Sbisson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/236870

Change subject: [WIP] Topic Summary Widget
......................................................................

[WIP] Topic Summary Widget

Bug: T111102
Change-Id: I1a011260bf1b2060dd3e1f941c89535d2d87e3da
---
M Resources.php
M handlebars/compiled/flow_block_topiclist.handlebars.php
M handlebars/compiled/flow_post.handlebars.php
M handlebars/flow_moderation_actions_list.partial.handlebars
M modules/engine/components/board/base/flow-board-api-events.js
M modules/engine/components/board/base/flow-boardandhistory-base.js
M modules/flow-initialize.js
M modules/flow/dm/api/mw.flow.dm.APIHandler.js
M modules/flow/ui/widgets/mw.flow.ui.EditPostWidget.js
A modules/flow/ui/widgets/mw.flow.ui.EditTopicSummaryWidget.js
M tests/browser/features/step_definitions/resolve_reopen_steps.rb
A tests/browser/features/summarize.feature
M tests/browser/features/support/pages/abstract_flow_page.rb
13 files changed, 372 insertions(+), 170 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow 
refs/changes/70/236870/1

diff --git a/Resources.php b/Resources.php
index ddea094..d9d1085 100644
--- a/Resources.php
+++ b/Resources.php
@@ -388,6 +388,7 @@
                        'flow/ui/widgets/mw.flow.ui.NavigationWidget.js',
                        'flow/ui/widgets/mw.flow.ui.ReplyWidget.js',
                        'flow/ui/widgets/mw.flow.ui.EditPostWidget.js',
+                       'flow/ui/widgets/mw.flow.ui.EditTopicSummaryWidget.js',
                        'flow/ui/widgets/mw.flow.ui.SidebarExpandWidget.js',
                        'flow/ui/widgets/mw.flow.ui.NewTopicWidget.js',
 
diff --git a/handlebars/compiled/flow_block_topiclist.handlebars.php 
b/handlebars/compiled/flow_block_topiclist.handlebars.php
index ea7fbb2..319860b 100644
--- a/handlebars/compiled/flow_block_topiclist.handlebars.php
+++ b/handlebars/compiled/flow_block_topiclist.handlebars.php
@@ -148,10 +148,7 @@
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['links']['topic-history']['url']) && 
is_array($in['links']['topic-history'])) ? $in['links']['topic-history']['url'] 
: null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic-history']['title']) 
&& is_array($in['links']['topic-history'])) ? 
$in['links']['topic-history']['title'] : null), ENT_QUOTES, 
'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) && 
is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-clock"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-history'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['links']['topic']) && is_array($in['links'])) ? 
$in['links']['topic'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-quiet"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['links']['topic']['url']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic']['title']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-link"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-view'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['summarize']) && is_array($in['actions'])) ? 
$in['actions']['summarize'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="activateSummarizeTopic"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic']['title']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-link"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-view'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['summarize']) && is_array($in['actions'])) ? 
$in['actions']['summarize'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-summarize-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['summarize']['url']) && 
is_array($in['actions']['summarize'])) ? $in['actions']['summarize']['url'] : 
null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['summarize']['title']) && 
is_array($in['actions']['summarize'])) ? $in['actions']['summarize']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before mw-ui-icon-stripeToC 
mw-ui-icon-stripeToC-progressive-hover"></span> ' : '').''.((LCRun3::ifvar($cx, 
((isset($in['summary']['revision']['content']['content']) && 
is_array($in['summary']['revision']['content'])) ? 
$in['summary']['revision']['content']['content'] : null))) ? ''.LCRun3::ch($cx, 
'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-resummarize-topic'),array()), 'raw')),array()), 
'encq').'' : ''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-summarize-topic'),array()), 'raw')),array()), 
'encq').'').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) 
? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : 
'').'';}).''.LCRun3::hbch($cx, 'ifCond', 
array(array(((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'===','post'),array()), $in, false, function($cx, 
$in)use($sp){return ''.((LCRun3::ifvar($cx, ((isset($in['actions']['edit']) && 
is_array($in['actions'])) ? $in['actions']['edit'] : null))) ? '<li>
 '.$sp.'                                <a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-edit-post-link"
@@ -208,19 +205,9 @@
 '.$sp.'                                   data-role="unlock"
 '.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['unlock']['url']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').'';}, 
function($cx, $in)use($sp){return ''.((LCRun3::ifvar($cx, 
((isset($in['actions']['lock']) && is_array($in['actions'])) ? 
$in['actions']['lock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="lockAndSummarizeTopic"
-'.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
-'.$sp.'                                   data-flow-api-method="POST"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').'';}, 
function($cx, $in)use($sp){return ''.((LCRun3::ifvar($cx, 
((isset($in['actions']['lock']) && is_array($in['actions'])) ? 
$in['actions']['lock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-resolve-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['lock']['url']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['lock']['title']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-check mw-ui-icon-check-progressive-hover"></span> 
' : '').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-lock-topic'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['unlock']) && is_array($in['actions'])) ? 
$in['actions']['unlock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="lockAndSummarizeTopic"
-'.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
-'.$sp.'                                   data-flow-api-method="POST"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['lock']['title']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-check mw-ui-icon-check-progressive-hover"></span> 
' : '').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-lock-topic'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['unlock']) && is_array($in['actions'])) ? 
$in['actions']['unlock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-reopen-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['unlock']['url']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : 
'').'';}).'</section>
 ';},'flow_topic_titlebar' => function ($cx, $in, $sp) {return ''.$sp.'<div 
class="flow-topic-titlebar">
diff --git a/handlebars/compiled/flow_post.handlebars.php 
b/handlebars/compiled/flow_post.handlebars.php
index 2dad062..173bb84 100644
--- a/handlebars/compiled/flow_post.handlebars.php
+++ b/handlebars/compiled/flow_post.handlebars.php
@@ -88,10 +88,7 @@
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['links']['topic-history']['url']) && 
is_array($in['links']['topic-history'])) ? $in['links']['topic-history']['url'] 
: null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic-history']['title']) 
&& is_array($in['links']['topic-history'])) ? 
$in['links']['topic-history']['title'] : null), ENT_QUOTES, 
'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) && 
is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-clock"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-history'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['links']['topic']) && is_array($in['links'])) ? 
$in['links']['topic'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-quiet"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['links']['topic']['url']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic']['title']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-link"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-view'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['summarize']) && is_array($in['actions'])) ? 
$in['actions']['summarize'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="activateSummarizeTopic"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['links']['topic']['title']) && 
is_array($in['links']['topic'])) ? $in['links']['topic']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-link"></span> ' : '').''.LCRun3::ch($cx, 'l10n', 
array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-view'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['summarize']) && is_array($in['actions'])) ? 
$in['actions']['summarize'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-summarize-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['summarize']['url']) && 
is_array($in['actions']['summarize'])) ? $in['actions']['summarize']['url'] : 
null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['summarize']['title']) && 
is_array($in['actions']['summarize'])) ? $in['actions']['summarize']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before mw-ui-icon-stripeToC 
mw-ui-icon-stripeToC-progressive-hover"></span> ' : '').''.((LCRun3::ifvar($cx, 
((isset($in['summary']['revision']['content']['content']) && 
is_array($in['summary']['revision']['content'])) ? 
$in['summary']['revision']['content']['content'] : null))) ? ''.LCRun3::ch($cx, 
'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-resummarize-topic'),array()), 'raw')),array()), 
'encq').'' : ''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-topic-action-summarize-topic'),array()), 'raw')),array()), 
'encq').'').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) 
? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : 
'').'';}).''.LCRun3::hbch($cx, 'ifCond', 
array(array(((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'===','post'),array()), $in, false, function($cx, 
$in)use($sp){return ''.((LCRun3::ifvar($cx, ((isset($in['actions']['edit']) && 
is_array($in['actions'])) ? $in['actions']['edit'] : null))) ? '<li>
 '.$sp.'                                <a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-edit-post-link"
@@ -148,19 +145,9 @@
 '.$sp.'                                   data-role="unlock"
 '.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['unlock']['url']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').'';}, 
function($cx, $in)use($sp){return ''.((LCRun3::ifvar($cx, 
((isset($in['actions']['lock']) && is_array($in['actions'])) ? 
$in['actions']['lock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="lockAndSummarizeTopic"
-'.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
-'.$sp.'                                   data-flow-api-method="POST"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').'';}, 
function($cx, $in)use($sp){return ''.((LCRun3::ifvar($cx, 
((isset($in['actions']['lock']) && is_array($in['actions'])) ? 
$in['actions']['lock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-resolve-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['lock']['url']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['lock']['title']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-check mw-ui-icon-check-progressive-hover"></span> 
' : '').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-lock-topic'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['unlock']) && is_array($in['actions'])) ? 
$in['actions']['unlock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-'.$sp.'                                   
data-flow-interactive-handler="apiRequest"
-'.$sp.'                                   
data-flow-api-handler="lockAndSummarizeTopic"
-'.$sp.'                                   
data-flow-id="'.htmlentities((string)((isset($in['postId']) && is_array($in)) ? 
$in['postId'] : null), ENT_QUOTES, 'UTF-8').'"
-'.$sp.'                                   data-flow-api-target="< 
.flow-topic-titlebar .flow-topic-summary-container"
-'.$sp.'                                   data-flow-api-method="POST"
+'.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['lock']['title']) && 
is_array($in['actions']['lock'])) ? $in['actions']['lock']['title'] : null), 
ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, ((isset($in['moderationIcons']) 
&& is_array($in)) ? $in['moderationIcons'] : null))) ? '<span class="mw-ui-icon 
mw-ui-icon-before mw-ui-icon-check mw-ui-icon-check-progressive-hover"></span> 
' : '').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-lock-topic'),array()), 'raw')),array()), 
'encq').'</a>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : '').''.((LCRun3::ifvar($cx, 
((isset($in['actions']['unlock']) && is_array($in['actions'])) ? 
$in['actions']['unlock'] : null))) ? 
'<li>'.htmlentities((string)((isset($in['noop']) && is_array($in)) ? 
$in['noop'] : null), ENT_QUOTES, 'UTF-8').'<a 
class="'.htmlentities((string)((isset($in['moderationMwUiClass']) && 
is_array($in)) ? $in['moderationMwUiClass'] : null), ENT_QUOTES, 'UTF-8').' 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-reopen-topic-link"
 '.$sp.'                                   
href="'.htmlentities((string)((isset($in['actions']['unlock']['url']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['url'] : null), 
ENT_QUOTES, 'UTF-8').'"
 '.$sp.'                                   
title="'.htmlentities((string)((isset($in['actions']['unlock']['title']) && 
is_array($in['actions']['unlock'])) ? $in['actions']['unlock']['title'] : 
null), ENT_QUOTES, 'UTF-8').'">'.((LCRun3::ifvar($cx, 
((isset($in['moderationIcons']) && is_array($in)) ? $in['moderationIcons'] : 
null))) ? '<span class="mw-ui-icon mw-ui-icon-before 
mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> ' : 
'').''.LCRun3::ch($cx, 'l10n', array(array(LCRun3::ch($cx, 'concat', 
array(array('flow-',((isset($in['moderationType']) && is_array($in)) ? 
$in['moderationType'] : null),'-action-unlock-topic'),array()), 
'raw')),array()), 'encq').'</a>'.htmlentities((string)((isset($in['noop']) && 
is_array($in)) ? $in['noop'] : null), ENT_QUOTES, 'UTF-8').'</li>' : 
'').'';}).'</section>
 ';},'flow_post_actions' => function ($cx, $in, $sp) {return ''.$sp.'<div 
class="flow-menu flow-menu-hoverable">
diff --git a/handlebars/flow_moderation_actions_list.partial.handlebars 
b/handlebars/flow_moderation_actions_list.partial.handlebars
index 845fba2..01a81b6 100644
--- a/handlebars/flow_moderation_actions_list.partial.handlebars
+++ b/handlebars/flow_moderation_actions_list.partial.handlebars
@@ -44,10 +44,7 @@
                {{~#if actions.summarize~}}
                        <li>
                                {{~noop~}}
-                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-                                  data-flow-interactive-handler="apiRequest"
-                                  
data-flow-api-handler="activateSummarizeTopic"
-                                  data-flow-api-target="< .flow-topic-titlebar 
.flow-topic-summary-container"
+                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-summarize-topic-link"
                                   href="{{actions.summarize.url}}"
                                   title="{{actions.summarize.title}}">
                                        {{~#if moderationIcons}}<span 
class="mw-ui-icon mw-ui-icon-before mw-ui-icon-stripeToC 
mw-ui-icon-stripeToC-progressive-hover"></span> {{/if~}}
@@ -238,12 +235,7 @@
                {{~#if actions.lock~}}
                        <li>
                                {{~noop~}}
-                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-                                  data-flow-interactive-handler="apiRequest"
-                                  data-flow-api-handler="lockAndSummarizeTopic"
-                                  data-flow-id="{{postId}}"
-                                  data-flow-api-target="< .flow-topic-titlebar 
.flow-topic-summary-container"
-                                  data-flow-api-method="POST"
+                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-resolve-topic-link"
                                   href="{{actions.lock.url}}"
                                   title="{{actions.lock.title}}">
                                        {{~#if moderationIcons}}<span 
class="mw-ui-icon mw-ui-icon-before mw-ui-icon-check 
mw-ui-icon-check-progressive-hover"></span> {{/if~}}
@@ -255,12 +247,7 @@
                {{~#if actions.unlock~}}
                        <li>
                                {{~noop~}}
-                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon"
-                                  data-flow-interactive-handler="apiRequest"
-                                  data-flow-api-handler="lockAndSummarizeTopic"
-                                  data-flow-id="{{postId}}"
-                                  data-flow-api-target="< .flow-topic-titlebar 
.flow-topic-summary-container"
-                                  data-flow-api-method="POST"
+                               <a class="{{moderationMwUiClass}} 
mw-ui-progressive mw-ui-quiet mw-ui-hovericon flow-ui-reopen-topic-link"
                                   href="{{actions.unlock.url}}"
                                   title="{{actions.unlock.title}}">
                                        {{~#if moderationIcons}}<span 
class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ongoingConversation 
mw-ui-icon-ongoingConversation-progressive-hover"></span> {{/if~}}
diff --git a/modules/engine/components/board/base/flow-board-api-events.js 
b/modules/engine/components/board/base/flow-board-api-events.js
index 38e3606..96ff172 100644
--- a/modules/engine/components/board/base/flow-board-api-events.js
+++ b/modules/engine/components/board/base/flow-board-api-events.js
@@ -507,51 +507,6 @@
        };
 
        /**
-        * Activate the editable summarize topic form with given api request
-        * @param {Object} info (status:done|fail, $target: jQuery)
-        * @param {Object} data
-        * @param {jqXHR} jqxhr
-        * @return {jQuery.Promise}
-        */
-       
FlowBoardComponentApiEventsMixin.UI.events.apiHandlers.activateSummarizeTopic = 
function ( info, data, jqxhr ) {
-               var flowBoard = mw.flow.getPrototypeMethod( 'board', 
'getInstanceByElement' )( $( this ) );
-
-               if ( info.status !== 'done' ) {
-                       // Error will be displayed by default, nothing else to 
wrap up
-                       return $.Deferred().resolve().promise();
-               }
-
-               return _activateSummarizeTopic(
-                       info.$target,
-                       flowBoard,
-                       data.flow[ 'view-topic-summary' ].result.topicsummary,
-                       'summarize'
-               );
-       };
-
-       /**
-        * After submit of the summarize topic edit form, process the new topic 
summary data.
-        * @param {Object} info
-        * @param {string} info.status "done" or "fail"
-        * @param {jQuery} info.$target
-        * @param {Object} data
-        * @param {jqXHR} jqxhr
-        * @return {jQuery.Promise}
-        */
-       FlowBoardComponentApiEventsMixin.UI.events.apiHandlers.summarizeTopic = 
function ( info, data, jqxhr ) {
-               if ( info.status !== 'done' ) {
-                       // Error will be displayed by default, nothing else to 
wrap up
-                       return $.Deferred().resolve().promise();
-               }
-
-               return _flowBoardComponentRefreshTopic(
-                       info.$target,
-                       data.flow['edit-topic-summary'].workflow,
-                       '.flow-topic-titlebar'
-               );
-       };
-
-       /**
         * Shows the form for editing a topic title, it's not already showing.
         *
         * @param {Object} info (status:done|fail, $target: jQuery)
@@ -715,6 +670,7 @@
                var $target = $targetElement.closest( '.flow-topic' ),
                        flowBoard = mw.flow.getPrototypeMethod( 'board', 
'getInstanceByElement' )( $targetElement );
 
+               $targetElement.addClass( 'flow-api-inprogress' );
                return flowBoard.Api.apiCall( {
                        action: 'flow',
                        submodule: 'view-topic',
@@ -749,36 +705,13 @@
 
                        flowBoard.emitWithReturn( 'removeError', $target );
                        flowBoard.emitWithReturn( 'showError', $target, 
errorMsg );
+               } ).always( function () {
+                       $targetElement.removeClass( 'flow-api-inprogress' );
                } );
        }
 
        // HACK expose this so flow-initialize.js can rerender topics when it 
needs to
        
FlowBoardComponentApiEventsMixin.prototype.flowBoardComponentRefreshTopic = 
_flowBoardComponentRefreshTopic;
-
-       function _activateSummarizeTopic( $target, flowBoard, topicSummary, 
action ) {
-               var $old = $target;
-
-               // Create the new flow_block_topicsummary_edit template
-               $target = $( 
flowBoard.constructor.static.TemplateEngine.processTemplateGetFragment(
-                       'flow_block_topicsummary_edit',
-                       $.extend( topicSummary, { action: action } )
-               ) ).children();
-
-               // On cancel, put the old topicsummary back
-               flowBoard.emitWithReturn( 'addFormCancelCallback', 
$target.find( 'form' ), function () {
-                       $target.before( $old ).remove();
-               } );
-
-               // Replace the old one
-               $old.before( $target ).detach();
-
-               flowBoard.emitWithReturn( 'makeContentInteractive', $target );
-
-               // Focus on first form field
-               $target.find( 'input, textarea' ).filter( ':visible:first' 
).focus();
-
-               return $.Deferred().resolve().promise();
-       }
 
        // Mixin to FlowBoardComponent
        mw.flow.mixinComponent( 'board', FlowBoardComponentApiEventsMixin );
diff --git a/modules/engine/components/board/base/flow-boardandhistory-base.js 
b/modules/engine/components/board/base/flow-boardandhistory-base.js
index 3bbe4ab..f2d86fb 100644
--- a/modules/engine/components/board/base/flow-boardandhistory-base.js
+++ b/modules/engine/components/board/base/flow-boardandhistory-base.js
@@ -124,25 +124,6 @@
                } );
        };
 
-       /**
-        * Adds a hardcoded moderation reason to the request when resolving and 
reopening a topic.
-        * @param {Event} event
-        * @param {Object} info
-        * @param {Object} queryMap
-        * @return {Object}
-        */
-       function addLockRestoreReason( event, info, queryMap ) {
-               var msgKey = queryMap.cotmoderationState === 'lock' ?
-                               'flow-rev-message-lock-topic-reason' :
-                               'flow-rev-message-restore-topic-reason',
-                       msg = mw.msg( msgKey );
-               return $.extend( {}, queryMap, {
-                       cotreason: msg
-               } );
-       }
-       
FlowBoardAndHistoryComponentBase.UI.events.apiPreHandlers.lockAndSummarizeTopic 
= addLockRestoreReason;
-       FlowBoardAndHistoryComponentBase.UI.events.apiPreHandlers.lockTopic = 
addLockRestoreReason;
-
        //
        // Interactive handlers
        //
diff --git a/modules/flow-initialize.js b/modules/flow-initialize.js
index 8d599b9..f140d86 100644
--- a/modules/flow-initialize.js
+++ b/modules/flow-initialize.js
@@ -213,15 +213,11 @@
                                        replyWidget.destroy();
                                        replyWidget.$element.remove();
 
-                                       $topic.addClass( 'flow-api-inprogress' 
);
                                        // HACK get the old system to rerender 
the topic
                                        return 
flowBoard.flowBoardComponentRefreshTopic(
                                                $topic,
                                                workflow
-                                       )
-                                       .always( function () {
-                                               $topic.removeClass( 
'flow-api-inprogress' );
-                                       } );
+                                       );
                                } );
                                replyWidget.$element.data( 'self', replyWidget 
);
 
@@ -269,15 +265,11 @@
                                                replyWidget.destroy();
                                                replyWidget.$element.remove();
 
-                                               $topic.addClass( 
'flow-api-inprogress' );
                                                // HACK get the old system to 
rerender the topic
                                                return 
flowBoard.flowBoardComponentRefreshTopic(
                                                        $topic,
                                                        workflow
-                                               )
-                                               .always( function () {
-                                                       $topic.removeClass( 
'flow-api-inprogress' );
-                                               } );
+                                               );
                                        } )
                                        .on( 'cancel', function () {
                                                replyWidget.destroy();
@@ -319,9 +311,7 @@
                                topicId = $topic.data( 'flow-id' ),
                                $post = $( this ).closest( '.flow-post' ),
                                $postMain = $post.find( '.flow-post-main' ),
-                               postId = $post.data( 'flow-id' ),
-                               $board = $( '.flow-board' ),
-                               flowBoard = mw.flow.getPrototypeMethod( 
'component', 'getInstanceByElement' )( $board );
+                               postId = $post.data( 'flow-id' );
 
                        editPostWidget = new mw.flow.ui.EditPostWidget( 
topicId, postId );
                        editPostWidget
@@ -329,15 +319,11 @@
                                        editPostWidget.destroy();
                                        editPostWidget.$element.remove();
 
-                                       $topic.addClass( 'flow-api-inprogress' 
);
                                        // HACK get the old system to rerender 
the topic
                                        return 
flowBoard.flowBoardComponentRefreshTopic(
                                                $topic,
                                                workflow
-                                       )
-                                               .always( function () {
-                                                       $topic.removeClass( 
'flow-api-inprogress' );
-                                               } );
+                                       );
                                } )
                                .on( 'cancel', function () {
                                        editPostWidget.$element.replaceWith( 
$postMain );
@@ -349,6 +335,82 @@
                        event.preventDefault();
                } );
 
+               function startEditTopicSummary( topicId, action ) {
+                       var $topic = $board.find( '#flow-topic-' + topicId ),
+                               $summaryContainer = $topic.find( 
'.flow-topic-summary-container' ),
+                               editTopicSummaryWidget,
+                               options = {};
+
+                       if ( action === 'resolve-topic' || action === 
'reopen-topic' ) {
+                               options = {
+                                       cancelMsgKey: 'flow-skip-summary'
+                               };
+                       }
+
+                       editTopicSummaryWidget = new 
mw.flow.ui.EditTopicSummaryWidget( topicId, options );
+                       editTopicSummaryWidget
+                               .on( 'saveContent', function ( workflow ) {
+                                       editTopicSummaryWidget.destroy();
+                                       
editTopicSummaryWidget.$element.remove();
+
+                                       // HACK get the old system to rerender 
the topic
+                                       return 
flowBoard.flowBoardComponentRefreshTopic(
+                                               $topic,
+                                               workflow
+                                       );
+                               } )
+                               .on( 'cancel', function () {
+                                       
editTopicSummaryWidget.$element.replaceWith( $summaryContainer );
+                                       editTopicSummaryWidget.destroy();
+                               } );
+
+                       $summaryContainer.replaceWith( 
editTopicSummaryWidget.$element );
+               }
+
+               $board.on( 'click', '.flow-ui-summarize-topic-link', function ( 
event ) {
+                       var $topic = $( this ).closest( '.flow-topic' ),
+                               topicId = $topic.data( 'flow-id' );
+                       startEditTopicSummary( topicId );
+                       event.preventDefault();
+               } );
+
+               $board.on( 'click', '.flow-ui-resolve-topic-link', function ( 
event ) {
+                       var $topic = $( this ).closest( '.flow-topic' ),
+                               topicId = $topic.data( 'flow-id' ),
+                               api = new mw.flow.dm.APIHandler();
+
+                       api.resolveTopic( topicId )
+                               .then( function( workflow ) {
+                                       return 
flowBoard.flowBoardComponentRefreshTopic(
+                                               $topic,
+                                               workflow
+                                       );
+                               } )
+                               .then( function() { startEditTopicSummary( 
topicId, 'resolve-topic' ); } );
+
+                       event.preventDefault();
+               } );
+
+               $board.on( 'click', '.flow-ui-reopen-topic-link', function ( 
event ) {
+                       var $topic = $( this ).closest( '.flow-topic' ),
+                               topicId = $topic.data( 'flow-id' ),
+                               api = new mw.flow.dm.APIHandler();
+
+                       api.reopenTopic( topicId )
+                               .then( function( workflow ) {
+                                       return 
flowBoard.flowBoardComponentRefreshTopic(
+                                               $topic,
+                                               workflow
+                                       );
+                               } )
+                               .then( function() {
+                                       console.log('after reopen', arguments);
+                                       startEditTopicSummary( topicId, 
'reopen-topic' );
+                               } );
+
+                       event.preventDefault();
+               } );
+
                // Fall back to mw.flow.data, which was used until September 
2015
                dataBlob = mw.config.get( 'wgFlowData' ) || ( mw.flow && 
mw.flow.data );
                if ( dataBlob && dataBlob.blocks ) {
diff --git a/modules/flow/dm/api/mw.flow.dm.APIHandler.js 
b/modules/flow/dm/api/mw.flow.dm.APIHandler.js
index 0011d32..f4255eb 100644
--- a/modules/flow/dm/api/mw.flow.dm.APIHandler.js
+++ b/modules/flow/dm/api/mw.flow.dm.APIHandler.js
@@ -126,6 +126,10 @@
                }
        };
 
+       mw.flow.dm.APIHandler.prototype.topicTitle = function ( topicId ) {
+               return ( new mw.Title( topicId, 2600 ) ).getPrefixedDb();
+       };
+
        /**
         * Send an edit request to the API to save a reply.
         *
@@ -235,9 +239,9 @@
         * @param {string} format
         * @return {jQuery.Promise} Promise that is resolved with the post 
revision data
         */
-       mw.flow.dm.APIHandler.prototype.getPost = function ( postId, format ) {
+       mw.flow.dm.APIHandler.prototype.getPost = function ( topicId, postId, 
format ) {
                var params = {
-                       page: this.page,
+                       page: this.topicTitle( topicId ),
                        vppostId: postId,
                        vpformat: format || 'html'
                };
@@ -257,10 +261,10 @@
         * @param {string} [captcha] CAPTCHA information
         * @return {jQuery.Promise} Promise that is resolved with the saved 
post revision id
         */
-       mw.flow.dm.APIHandler.prototype.savePost = function ( postId, content, 
format, captcha ) {
+       mw.flow.dm.APIHandler.prototype.savePost = function ( topicId, postId, 
content, format, captcha ) {
                var xhr,
                        params = {
-                               page: this.page,
+                               page: this.topicTitle( topicId ),
                                epcontent: content,
                                epformat: format,
                                epprev_revision: this.currentRevision,
@@ -277,4 +281,67 @@
                return xhr.promise( { abort: xhr.abort } );
        };
 
+       mw.flow.dm.APIHandler.prototype.getTopicSummary = function ( topicId, 
format ) {
+               var params = {
+                       page: this.topicTitle( topicId ),
+                       vtsformat: format || 'html'
+               };
+
+               return this.get( 'view-topic-summary', params )
+                       .then( function ( data ) {
+                               return data.topicsummary.revision;
+                       } );
+       };
+
+       mw.flow.dm.APIHandler.prototype.saveTopicSummary = function ( topicId, 
content, format, captcha ) {
+               var xhr,
+                       params = {
+                               page: this.topicTitle( topicId ),
+                               etssummary: content,
+                               etsformat: format,
+                               etsprev_revision: this.currentRevision
+                       };
+
+               this.addCaptcha( params, captcha );
+
+               xhr = this.postEdit( 'edit-topic-summary', params )
+                       .then( function ( data ) {
+                               return OO.getProp( data.flow, 
'edit-topic-summary', 'workflow' );
+                       } );
+
+               return xhr.promise( { abort: xhr.abort } );
+       };
+
+       /**
+        * Executes the 'lock-topic' moderation action against a topic. Can be 
used to resolve or reopen a topic.
+        *
+        * @param {string} topicId Id of the topic to moderate
+        * @param {string} moderationState Can be 'lock' or 'unlock'
+        * @param {string} reasonMsgKey Message key for the moderation reason
+        * @return {jQuery.Promise} Resolved with the workflow id
+        */
+       mw.flow.dm.APIHandler.prototype.lockTopic = function ( topicId, 
moderationState, reasonMsgKey ) {
+               var xhr,
+                       params = {
+                               page: this.topicTitle( topicId ),
+                               cotmoderationState: moderationState,
+                               cotreason: mw.msg( reasonMsgKey )
+                       };
+
+               xhr = this.postEdit( 'lock-topic', params )
+                       .then( function ( data ) {
+                               return OO.getProp( data.flow, 'lock-topic', 
'workflow' );
+                       } );
+
+               return xhr.promise( { abort: xhr.abort } );
+       };
+
+       mw.flow.dm.APIHandler.prototype.resolveTopic = function ( topicId ) {
+               return this.lockTopic( topicId, 'lock', 
'flow-rev-message-lock-topic-reason' );
+       };
+
+       mw.flow.dm.APIHandler.prototype.reopenTopic = function ( topicId ) {
+               return this.lockTopic( topicId, 'unlock', 
'flow-rev-message-restore-topic-reason' );
+       };
+
 }( jQuery ) );
diff --git a/modules/flow/ui/widgets/mw.flow.ui.EditPostWidget.js 
b/modules/flow/ui/widgets/mw.flow.ui.EditPostWidget.js
index 1352e85..656d35b 100644
--- a/modules/flow/ui/widgets/mw.flow.ui.EditPostWidget.js
+++ b/modules/flow/ui/widgets/mw.flow.ui.EditPostWidget.js
@@ -58,7 +58,7 @@
                var widget = this,
                        contentFormat = this.editor.getContentFormat();
 
-               this.api.getPost( postId, contentFormat ).then(
+               this.api.getPost( topicId, postId, contentFormat ).then(
                        function ( post ) {
                                var content = OO.getProp( post, 'content', 
'content' ),
                                        format = OO.getProp( post, 'content', 
'format' );
@@ -129,7 +129,7 @@
                this.error.toggle( false );
 
                this.editor.pushPending();
-               this.api.savePost( this.postId, content, format, captcha )
+               this.api.savePost( this.topicId, this.postId, content, format, 
captcha )
                        .then( function ( workflow ) {
                                widget.emit( 'saveContent', workflow, content, 
format );
                        } )
diff --git a/modules/flow/ui/widgets/mw.flow.ui.EditTopicSummaryWidget.js 
b/modules/flow/ui/widgets/mw.flow.ui.EditTopicSummaryWidget.js
new file mode 100644
index 0000000..123a233
--- /dev/null
+++ b/modules/flow/ui/widgets/mw.flow.ui.EditTopicSummaryWidget.js
@@ -0,0 +1,168 @@
+( function ( $ ) {
+       /**
+        * Flow edit topic summary widget
+        *
+        * @class
+        * @extends OO.ui.Widget
+        *
+        * @constructor
+        * @param {string} topicId The id of the topic that has the summary we 
want to edit
+        * @param {Object} [config] Configuration object
+        */
+       mw.flow.ui.EditTopicSummaryWidget = function 
mwFlowUiEditTopicSummaryWidget( topicId, config ) {
+               config = config || {};
+
+               this.topicId = topicId;
+
+               // Parent constructor
+               mw.flow.ui.EditTopicSummaryWidget.parent.call( this, config );
+
+               this.editor = new mw.flow.ui.EditorWidget( {
+                       saveMsgKey: 'flow-topic-action-update-topic-summary',
+                       classes: [ 'flow-ui-editTopicSummaryWidget-editor' ],
+                       placeholder: mw.msg( 'flow-edit-summary-placeholder' ),
+                       cancelMsgKey: config.cancelMsgKey
+               } );
+               this.editor.toggle( true );
+
+               this.anonWarning = new mw.flow.ui.AnonWarningWidget();
+               this.anonWarning.toggle( true );
+
+               this.error = new OO.ui.LabelWidget( {
+                       classes: [ 'flow-ui-editTopicSummaryWidget-error 
flow-errors errorbox' ]
+               } );
+               this.error.toggle( false );
+
+               this.api = new mw.flow.dm.APIHandler(
+                       'Topic:' + topicId
+               );
+
+               // Events
+               this.editor.connect( this, {
+                       saveContent: 'onEditorSaveContent',
+                       cancel: 'onEditorCancel'
+               } );
+
+               this.$element
+                       .addClass( 'flow-ui-editTopicSummaryWidget' )
+                       .append(
+                               this.anonWarning.$element,
+                               this.error.$element,
+                               this.editor.$element
+                       );
+
+               // Load the editor
+               this.editor.pushPending();
+               this.editor.activate();
+
+               // Get the post from the API
+               var widget = this,
+                       contentFormat = this.editor.getContentFormat();
+
+               this.api.getTopicSummary( topicId, contentFormat ).then(
+                       function ( topicSummary ) {
+                               var content = OO.getProp( topicSummary, 
'content', 'content' ),
+                                       format = OO.getProp( topicSummary, 
'content', 'format' );
+
+                               if ( content !== undefined && format !== 
undefined ) {
+                                       // Give it to the editor
+                                       widget.editor.setContent( content, 
format );
+
+                                       // Update revisionId in the API
+                                       widget.api.setCurrentRevision( 
topicSummary.revisionId );
+                               }
+
+                       },
+                       // Error fetching description
+                       function ( error ) {
+                               // Display error
+                               widget.error.setLabel( mw.msg( 
'flow-error-external', error ) );
+                               widget.error.toggle( true );
+                       }
+               ).always( function () {
+                       // Unset pending editor
+                       widget.editor.popPending();
+                       // Focus again: pending editors are disabled and can't 
be focused
+                       widget.editor.focus();
+               } );
+
+       };
+
+       /* Initialization */
+
+       OO.inheritClass( mw.flow.ui.EditTopicSummaryWidget, OO.ui.Widget );
+
+       /* Events */
+
+       /**
+        * Save the content of the reply
+        * @event saveContent
+        * @param {string} workflow The workflow this reply was saved under
+        * @param {string} content The content of the reply
+        * @param {string} contentFormat The format of the content of this reply
+        */
+
+       /* Methods */
+
+       /**
+        * Respond to editor cancel
+        */
+       mw.flow.ui.EditTopicSummaryWidget.prototype.onEditorCancel = function 
() {
+               this.emit( 'cancel' );
+       };
+
+       /**
+        * Respond to editor save
+        */
+       mw.flow.ui.EditTopicSummaryWidget.prototype.onEditorSaveContent = 
function ( content, format ) {
+               var widget = this,
+                       $captchaField, captcha;
+
+               $captchaField = this.error.$label.find( 
'[name="wpCaptchaWord"]' );
+               if ( $captchaField.length > 0 ) {
+                       captcha = {
+                               id: this.error.$label.find( 
'[name="wpCaptchaId"]' ).val(),
+                               answer: $captchaField.val()
+                       };
+               }
+
+               this.error.setLabel( '' );
+               this.error.toggle( false );
+
+               this.editor.pushPending();
+               this.api.saveTopicSummary( this.topicId, content, format, 
captcha )
+                       .then( function ( workflow ) {
+                               widget.emit( 'saveContent', workflow, content, 
format );
+                       } )
+                       .then( null, function ( errorCode, errorObj ) {
+                               if ( /spamfilter$/.test( errorCode ) && 
errorObj.error.spamfilter === 'flow-spam-confirmedit-form' ) {
+                                       widget.error.setLabel(
+                                               // CAPTCHA form
+                                               new OO.ui.HtmlSnippet( 
errorObj.error.info )
+                                       );
+                               } else {
+                                       widget.error.setLabel( errorObj.error 
&& errorObj.error.info || errorObj.exception );
+                               }
+
+                               widget.error.toggle( true );
+                       } )
+                       .always( function () {
+                               widget.editor.popPending();
+                       } );
+       };
+
+       /**
+        * Focus the reply widget on the editor
+        */
+       mw.flow.ui.EditTopicSummaryWidget.prototype.focus = function () {
+               this.editor.focus();
+       };
+
+       /**
+        * Destroy the widget
+        */
+       mw.flow.ui.EditTopicSummaryWidget.prototype.destroy = function () {
+               this.editor.destroy();
+       };
+
+}( jQuery ) );
diff --git a/tests/browser/features/step_definitions/resolve_reopen_steps.rb 
b/tests/browser/features/step_definitions/resolve_reopen_steps.rb
index 1b3235a..3f0c681 100644
--- a/tests/browser/features/step_definitions/resolve_reopen_steps.rb
+++ b/tests/browser/features/step_definitions/resolve_reopen_steps.rb
@@ -65,6 +65,14 @@
   end
 end
 
+When(/^I click the edit summary menu item$/) do
+  on(FlowPage) do |page|
+    menu = page.topic_actions_link_element
+    option = page.topic_edit_summary_button_element
+    page.select_menu_option menu, option
+  end
+end
+
 Then(/^the first topic is summarized as "(.*?)"$/) do |summary_text|
   on(FlowPage) do |page|
     expect(page.summary_content_element.when_present.text).to eq(summary_text)
@@ -88,6 +96,12 @@
   step 'I click the update summary button'
 end
 
+Given(/^I re-summarize the first topic as "(.*?)"$/) do |summary_text|
+  step 'I click the edit summary menu item'
+  step "I enter \"#{summary_text}\" as summary"
+  step 'I click the update summary button'
+end
+
 When(/^I summarize as "(.*?)"$/) do |summary_text|
   step "I enter \"#{summary_text}\" as summary"
   step 'I click the update summary button'
diff --git a/tests/browser/features/summarize.feature 
b/tests/browser/features/summarize.feature
new file mode 100644
index 0000000..1804900
--- /dev/null
+++ b/tests/browser/features/summarize.feature
@@ -0,0 +1,15 @@
+@chrome @firefox @internet_explorer_10
+@clean @login
[email protected]
+Feature: Summarize
+
+  Background:
+    Given there is a new topic
+    And I am logged in
+    And I am on Flow page
+
+  Scenario: Summarize a topic
+    When I summarize the first topic as "first summary version"
+    Then the first topic is summarized as "first summary version"
+    When I re-summarize the first topic as "second summary version"
+    Then the first topic is summarized as "second summary version"
diff --git a/tests/browser/features/support/pages/abstract_flow_page.rb 
b/tests/browser/features/support/pages/abstract_flow_page.rb
index 667bb99..fc7d296 100644
--- a/tests/browser/features/support/pages/abstract_flow_page.rb
+++ b/tests/browser/features/support/pages/abstract_flow_page.rb
@@ -124,6 +124,9 @@
   a(:topic_summarize_button) do |page|
     page.topic_actions_menu_element.link_element(text: "Summarize")
   end
+  a(:topic_edit_summary_button) do |page|
+    page.topic_actions_menu_element.link_element(text: "Edit the topic 
summary")
+  end
 
   ### Editing title of first topic
   text_field(:title_edit, css: ".flow-topic-titlebar form .mw-ui-input", 
index: 0)
@@ -145,17 +148,14 @@
   div(:summary_content) do |page|
     page.summary_element.div_element(css: '.flow-topic-summary-content')
   end
-  button(:skip_summary_button) do |page|
-    page.summary_element.button_element(text: 'Skip summary')
+  link(:skip_summary_button, text: 'Skip summary')
+  link(:cancel_summary_button) do |page|
+    page.summary_element.link_element(text: 'Cancel')
   end
-  button(:cancel_summary_button) do |page|
-    page.summary_element.button_element(text: 'Cancel')
-  end
-  button(:update_summary_button) do |page|
-    page.summary_element.button_element(text: 'Update summary')
-  end
+  link(:update_summary_button, text: 'Update summary')
   def edit_summary_element
-    visualeditor_or_textarea '.flow-edit-form'
+    edit_summary_widget = div_element(class: 'flow-ui-editTopicSummaryWidget')
+    visualeditor_or_textarea edit_summary_widget
   end
   span(:first_topic_resolved_mark) do |page|
     page.flow_first_topic_heading_element.span_element(css: 
'.mw-ui-icon-check')

-- 
To view, visit https://gerrit.wikimedia.org/r/236870
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1a011260bf1b2060dd3e1f941c89535d2d87e3da
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Sbisson <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to