jenkins-bot has submitted this change and it was merged.
Change subject: Add categories to the sidebar
......................................................................
Add categories to the sidebar
Add categories to the board data model and have a categories widget
that synchronizes with the model to present the current categories
in the board.
Bug: T92874
Bug: T111110
Change-Id: Ib9b766f9125e1e0c95798db46bf29ca7e0ac0408
---
M Resources.php
M handlebars/compiled/flow_block_header.handlebars.php
M handlebars/compiled/flow_block_topiclist.handlebars.php
M handlebars/flow_block_header.handlebars
A handlebars/flow_header_categories.partial.handlebars
M includes/View.php
M modules/flow-initialize.js
M modules/flow/dm/api/mw.flow.dm.APIHandler.js
M modules/flow/dm/mw.flow.dm.Board.js
A modules/flow/dm/mw.flow.dm.Categories.js
A modules/flow/dm/mw.flow.dm.CategoryItem.js
M modules/flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js
A modules/flow/ui/widgets/mw.flow.ui.CategoriesWidget.js
A modules/flow/ui/widgets/mw.flow.ui.CategoryItemWidget.js
M modules/styles/board/header.less
A modules/styles/flow/widgets/mw.flow.ui.CategoriesWidget.less
A modules/styles/flow/widgets/mw.flow.ui.CategoryItemWidget.less
17 files changed, 441 insertions(+), 8 deletions(-)
Approvals:
Catrope: Looks good to me, approved
Mooeypoo: Looks good to me, approved
jenkins-bot: Verified
diff --git a/Resources.php b/Resources.php
index 19e2fc7..bee4a05 100644
--- a/Resources.php
+++ b/Resources.php
@@ -58,6 +58,7 @@
'handlebars/flow_form_cancel_button.partial.handlebars',
'handlebars/flow_header_title.partial.handlebars',
'handlebars/flow_header_detail.partial.handlebars',
+ 'handlebars/flow_header_categories.partial.handlebars',
'handlebars/flow_header_footer.partial.handlebars',
// HACK: Get rid of this when the description uses js
ooui widgets
'handlebars/flow_header_detail_oldsystem.partial.handlebars',
@@ -373,6 +374,8 @@
'flow/dm/mw.flow.dm.Post.js',
'flow/dm/mw.flow.dm.Topic.js',
'flow/dm/mw.flow.dm.Board.js',
+ 'flow/dm/mw.flow.dm.CategoryItem.js',
+ 'flow/dm/mw.flow.dm.Categories.js',
),
'dependencies' => array(
'oojs'
@@ -402,6 +405,8 @@
'flow/ui/widgets/editor/mw.flow.ui.EditorWidget.js',
'flow/ui/widgets/editor/mw.flow.ui.SwitchToVeTool.js',
'flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js',
+ 'flow/ui/widgets/mw.flow.ui.CategoryItemWidget.js',
+ 'flow/ui/widgets/mw.flow.ui.CategoriesWidget.js',
),
'styles' => array(
'styles/flow/mw.flow.ui.Overlay.less',
@@ -416,7 +421,9 @@
'styles/flow/widgets/editor/mw.flow.ui.EditorControlsWidget.less',
'styles/flow/widgets/editor/mw.flow.ui.EditorSwitcherWidget.less',
'styles/flow/widgets/editor/mw.flow.ui.EditorWidget.less',
-
'styles/flow/widgets/editor/editors/mw.flow.ui.WikitextEditorWidget.less'
+
'styles/flow/widgets/editor/editors/mw.flow.ui.WikitextEditorWidget.less',
+
'styles/flow/widgets/mw.flow.ui.CategoryItemWidget.less',
+ 'styles/flow/widgets/mw.flow.ui.CategoriesWidget.less',
),
'messages' => array(
'flow-error-parsoid-failure',
@@ -426,6 +433,9 @@
'flow-dialog-cancelconfirm-keep',
'flow-dialog-cancelconfirm-discard',
'flow-wikitext-switch-editor-tooltip',
+ 'red-link-title',
+ 'pagecategories',
+ 'colon-separator'
),
'dependencies' => array (
'oojs-ui',
diff --git a/handlebars/compiled/flow_block_header.handlebars.php
b/handlebars/compiled/flow_block_header.handlebars.php
index 7995af2..9291a9a 100644
--- a/handlebars/compiled/flow_block_header.handlebars.php
+++ b/handlebars/compiled/flow_block_header.handlebars.php
@@ -62,7 +62,12 @@
'.$sp.' <span class="mw-ui-icon mw-ui-icon-before
mw-ui-icon-speechBubbles pull-right expand-button"
'.$sp.' title="'.LCRun3::ch($cx, 'l10n',
array(array('flow-board-expand-description'),array()), 'encq').'"></span>
'.$sp.'</a>
-';},'flow_header_footer' => function ($cx, $in, $sp) {return ''.$sp.'<div
class="flow-board-header-footer">
+';},'flow_header_categories' => function ($cx, $in, $sp) {return
''.$sp.''.((LCRun3::ifvar($cx, ((isset($cx['sp_vars']['root']['categories']) &&
is_array($cx['sp_vars']['root'])) ? $cx['sp_vars']['root']['categories'] :
null))) ? '<div class="flow-board-header-category-view-nojs">
+'.$sp.' <ul class="flow-board-header-category-list">
+'.$sp.''.LCRun3::sec($cx, ((isset($cx['sp_vars']['root']['categories']) &&
is_array($cx['sp_vars']['root'])) ? $cx['sp_vars']['root']['categories'] :
null), $in, true, function($cx, $in)use($sp){return ' <li
class="flow-board-header-category-item">'.LCRun3::ch($cx, 'html',
array(array($in),array()), 'encq').'</li>
+'.$sp.'';}).' </ul>
+'.$sp.'</div>
+'.$sp.'' : '').'';},'flow_header_footer' => function ($cx, $in, $sp) {return
''.$sp.'<div class="flow-board-header-footer">
'.$sp.' <hr />
'.$sp.' <p>
'.$sp.' '.LCRun3::ch($cx, 'html',
array(array(((isset($in['copyrightMessage']) && is_array($in)) ?
$in['copyrightMessage'] : null)),array()), 'encq').'
@@ -76,7 +81,7 @@
);
return '<div class="flow-board-header flow-load-interactive"
data-flow-load-handler="loadSideRail">
-'.LCRun3::p($cx, 'flow_header_title', array(array($in),array()), '
').''.LCRun3::p($cx, 'flow_errors', array(array($in),array()), '
').''.((LCRun3::ifvar($cx, ((isset($in['oldSystem']) && is_array($in)) ?
$in['oldSystem'] : null))) ? ''.LCRun3::p($cx, 'flow_header_detail_oldsystem',
array(array($in),array()), ' ').'' : ''.LCRun3::p($cx,
'flow_header_detail', array(array($in),array()), '
').'').''.LCRun3::p($cx, 'flow_header_footer', array(array($in),array()), '
').'</div>
+'.LCRun3::p($cx, 'flow_header_title', array(array($in),array()), '
').''.LCRun3::p($cx, 'flow_errors', array(array($in),array()), '
').''.((LCRun3::ifvar($cx, ((isset($in['oldSystem']) && is_array($in)) ?
$in['oldSystem'] : null))) ? ''.LCRun3::p($cx, 'flow_header_detail_oldsystem',
array(array($in),array()), ' ').'' : ''.LCRun3::p($cx,
'flow_header_detail', array(array($in),array()), '
').'').''.LCRun3::p($cx, 'flow_header_categories', array(array($in),array()), '
').''.LCRun3::p($cx, 'flow_header_footer', array(array($in),array()), '
').'</div>
';
}
?>
\ No newline at end of file
diff --git a/handlebars/compiled/flow_block_topiclist.handlebars.php
b/handlebars/compiled/flow_block_topiclist.handlebars.php
index 8f16d4f..a6ce538 100644
--- a/handlebars/compiled/flow_block_topiclist.handlebars.php
+++ b/handlebars/compiled/flow_block_topiclist.handlebars.php
@@ -302,4 +302,4 @@
</div>
';
}
-?>
+?>
\ No newline at end of file
diff --git a/handlebars/flow_block_header.handlebars
b/handlebars/flow_block_header.handlebars
index 5dd11cb..b226890 100644
--- a/handlebars/flow_block_header.handlebars
+++ b/handlebars/flow_block_header.handlebars
@@ -6,5 +6,6 @@
{{else}}
{{> flow_header_detail}}
{{/if}}
+ {{> flow_header_categories}}
{{> flow_header_footer}}
</div>
diff --git a/handlebars/flow_header_categories.partial.handlebars
b/handlebars/flow_header_categories.partial.handlebars
new file mode 100644
index 0000000..0e3798f
--- /dev/null
+++ b/handlebars/flow_header_categories.partial.handlebars
@@ -0,0 +1,9 @@
+{{#if @root.categories}}
+<div class="flow-board-header-category-view-nojs">
+ <ul class="flow-board-header-category-list">
+ {{#each @root.categories}}
+ <li class="flow-board-header-category-item">{{html this}}</li>
+ {{/each}}
+ </ul>
+</div>
+{{/if}}
diff --git a/includes/View.php b/includes/View.php
index 1571904..80e7a44 100644
--- a/includes/View.php
+++ b/includes/View.php
@@ -151,10 +151,24 @@
$workflow = $loader->getWorkflow();
$title = $workflow->getArticleTitle();
$user = $this->getUser();
+ $categories = array_keys( $title->getParentCategories() );
+ $categoryObject = array();
+ $linkedCategories = array();
+
+ // Transform the raw category names into links
+ foreach ( $categories as $value ) {
+ $categoryTitle = Title::newFromText( $value );
+ $categoryObject[ $value ] = array(
+ 'name' => $value,
+ 'exists' => $categoryTitle->exists()
+ );
+ $linkedCategories[] = \Linker::link( $categoryTitle,
htmlspecialchars( $categoryTitle->getText() ) );
+ }
// @todo This and API should use same code
$apiResponse = array(
'title' => $title->getPrefixedText(),
+ 'categories' => $categoryObject,
'workflow' => $workflow->isNew() ? '' :
$workflow->getId()->getAlphadecimal(),
'blocks' => array(),
'isWatched' => $user->isWatched( $title ),
@@ -179,6 +193,7 @@
'title'
=> $apiResponse['title'],
'block-action-template' => $block->getTemplate( $action ),
'editToken' => $editToken,
+
'categories' => $linkedCategories
);
if ( $block->getName() == 'topiclist' ) {
$topicListBlock = $block;
diff --git a/modules/flow-initialize.js b/modules/flow-initialize.js
index 4cda684..f790d16 100644
--- a/modules/flow-initialize.js
+++ b/modules/flow-initialize.js
@@ -127,9 +127,15 @@
// Board description widget
descriptionWidget = new mw.flow.ui.BoardDescriptionWidget(
dmBoard, {
- $existing: $( '.flow-ui-boardDescriptionWidget-content'
).contents()
+ $existing: $( '.flow-ui-boardDescriptionWidget-content'
).contents(),
+ $categories: $( '.flow-board-header-category-view-nojs'
).contents()
} );
$( '.flow-ui-boardDescriptionWidget' ).replaceWith(
descriptionWidget.$element );
+ // The category widget is inside the board description widget.
+ // Remove it here
+ $( '.flow-board-header-category-view-nojs' ).detach();
+ // HACK: Remove the MW page categories
+ $( '.catlinks' ).detach();
// HACK: These event handlers should be in the prospective
widgets
// they will move once we have Board UI and Topic UI widgets
diff --git a/modules/flow/dm/api/mw.flow.dm.APIHandler.js
b/modules/flow/dm/api/mw.flow.dm.APIHandler.js
index 3ac598e..13dc453 100644
--- a/modules/flow/dm/api/mw.flow.dm.APIHandler.js
+++ b/modules/flow/dm/api/mw.flow.dm.APIHandler.js
@@ -77,6 +77,27 @@
};
/**
+ * Get page categories. This will recursively continue to fetch results
+ * until all page categories are fetched.
+ *
+ * @return {jQuery.Promise} Promise that is resolved when the API
request
+ * is done, with the API result.
+ */
+ mw.flow.dm.APIHandler.prototype.getCategories = function () {
+ var params = {
+ action: 'query',
+ titles: this.page,
+ generator: 'categories',
+ gcllimit: 'max'
+ };
+
+ return ( new mw.Api() ).get( params )
+ .then( function ( response ) {
+ return OO.getProp( response, 'query', 'pages' );
+ } );
+ };
+
+ /**
* Send a request to get topic list
*
* @param {string} orderType Sort order type, 'newest' or 'updated'
diff --git a/modules/flow/dm/mw.flow.dm.Board.js
b/modules/flow/dm/mw.flow.dm.Board.js
index 7784861..fec6d2c 100644
--- a/modules/flow/dm/mw.flow.dm.Board.js
+++ b/modules/flow/dm/mw.flow.dm.Board.js
@@ -23,6 +23,8 @@
// Mixin constructor
mw.flow.dm.List.call( this, config );
+ this.categories = new mw.flow.dm.Categories();
+
// TODO: Fill this stuff in properly
this.setId( data.id );
this.pageTitle = data.pageTitle;
@@ -30,7 +32,13 @@
this.sort = data.defaultSort || 'newest';
this.description = new mw.flow.dm.BoardDescription();
+ // Events
this.aggregate( { contentChange: 'topicContentChange' } );
+ this.categories.connect( this, {
+ add: [ 'emit', 'addCategories' ],
+ remove: [ 'emit', 'removeCategories' ],
+ clear: [ 'emit', 'clearCategories' ]
+ } );
};
/* Initialization */
@@ -81,6 +89,65 @@
};
/**
+ * Add raw categories from the initial board api response
+ * @param {Object} categories Categories object
+ */
+ mw.flow.dm.Board.prototype.setCategoriesFromObject = function (
categories ) {
+ var cat,
+ categoryDMs = [];
+
+ // Add
+ for ( cat in categories ) {
+ categoryDMs.push( new mw.flow.dm.CategoryItem( cat, {
+ exists: !!categories[ cat ].exists
+ } ) );
+ }
+ this.addCategories( categoryDMs );
+ };
+
+ /**
+ * Add categories to the board
+ *
+ * @param {mw.flow.dm.CategoryItem[]} categories An array of category
items
+ */
+ mw.flow.dm.Board.prototype.addCategories = function ( categories ) {
+ this.categories.addItems( categories );
+ };
+
+ /**
+ * Get board categories
+ *
+ * @return {mw.flow.dm.Categories} An array of category items
+ */
+ mw.flow.dm.Board.prototype.getCategories = function () {
+ return this.categories;
+ };
+
+ /**
+ * Remove board categories
+ *
+ * @param {mw.flow.dm.CategoryItem[]} categories An array of category
items
+ */
+ mw.flow.dm.Board.prototype.removeCategories = function ( categories ) {
+ this.categories.removeItems( categories );
+ };
+
+ /**
+ * Clear the categories of this board
+ */
+ mw.flow.dm.Board.prototype.clearCategories = function () {
+ this.categories.clearItems();
+ };
+
+ /**
+ * Check whether the board has any categories
+ * @return {boolean} Board has categories
+ */
+ mw.flow.dm.Board.prototype.hasCategories = function () {
+ return !!this.categories.getItemCount();
+ };
+
+ /**
* Check if the board is in a deleted page
*
* @return {boolean} Board is in a deleted page
diff --git a/modules/flow/dm/mw.flow.dm.Categories.js
b/modules/flow/dm/mw.flow.dm.Categories.js
new file mode 100644
index 0000000..b002788
--- /dev/null
+++ b/modules/flow/dm/mw.flow.dm.Categories.js
@@ -0,0 +1,26 @@
+( function ( $ ) {
+ /**
+ * Flow Board
+ *
+ * @class
+ * @mixins mw.flow.dm.List
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+ mw.flow.dm.Categories = function mwFlowDmCategories( config ) {
+ config = config || {};
+
+ // Mixin constructor
+ OO.EventEmitter.call( this, config );
+
+ // Mixin constructor
+ mw.flow.dm.List.call( this, config );
+ };
+
+ /* Initialization */
+
+ OO.mixinClass( mw.flow.dm.Categories, OO.EventEmitter );
+ OO.mixinClass( mw.flow.dm.Categories, mw.flow.dm.List );
+}( jQuery ) );
diff --git a/modules/flow/dm/mw.flow.dm.CategoryItem.js
b/modules/flow/dm/mw.flow.dm.CategoryItem.js
new file mode 100644
index 0000000..fa4372a
--- /dev/null
+++ b/modules/flow/dm/mw.flow.dm.CategoryItem.js
@@ -0,0 +1,43 @@
+( function ( $ ) {
+ /**
+ * Flow Board
+ *
+ * @class
+ * @extends mw.flow.dm.Item
+ *
+ * @constructor
+ * @param {string} name Category name
+ * @param {Object} [config] Configuration options
+ */
+ mw.flow.dm.CategoryItem = function mwFlowDmCategoryItem( name, config )
{
+ config = config || {};
+
+ // Parent constructor
+ mw.flow.dm.CategoryItem.parent.call( this, config );
+
+ this.setId( name );
+ this.setExists( !!config.exists );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.flow.dm.CategoryItem, mw.flow.dm.Item );
+
+ /**
+ * Set exist status for this category in this wiki.
+ *
+ * @param {boolean} exists Category page exists in this wiki
+ */
+ mw.flow.dm.CategoryItem.prototype.setExists = function ( exists ) {
+ this.categoryExists = exists;
+ };
+
+ /**
+ * Set exist status for this category in this wiki.
+ *
+ * @return {boolean} Category page exists in this wiki
+ */
+ mw.flow.dm.CategoryItem.prototype.exists = function () {
+ return this.categoryExists;
+ };
+}( jQuery ) );
diff --git a/modules/flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js
b/modules/flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js
index 87a14aa..3b10728 100644
--- a/modules/flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js
+++ b/modules/flow/ui/widgets/mw.flow.ui.BoardDescriptionWidget.js
@@ -18,7 +18,8 @@
// Parent constructor
mw.flow.ui.BoardDescriptionWidget.parent.call( this, config );
- this.attachModel( boardModel.getDescription() );
+ this.board = boardModel;
+ this.attachModel( this.board.getDescription() );
// Since the content is already displayed, we will "steal" the
already created
// node to avoid having to render it twice.
@@ -34,7 +35,7 @@
.append( $content );
this.api = new mw.flow.dm.APIHandler(
- boardModel.getPageTitle().getPrefixedDb(),
+ this.board.getPageTitle().getPrefixedDb(),
{
currentRevision: this.model.getRevisionId()
}
@@ -66,12 +67,18 @@
this.button.toggle( false );
}
+ this.categoriesWidget = new mw.flow.ui.CategoriesWidget(
this.board );
+ if ( config.$categories ) {
+ this.addCategoriesFromDom( config.$categories );
+ }
+
// Events
this.button.connect( this, { click: 'onEditButtonClick' } );
this.editor.connect( this, {
saveContent: 'onEditorSaveContent',
cancel: 'onEditorCancel'
} );
+
// Initialize
this.$element
.append(
@@ -79,7 +86,8 @@
this.anonWarning.$element,
this.button.$element,
this.$content,
- this.editor.$element
+ this.editor.$element,
+ this.categoriesWidget.$element
)
.addClass( 'flow-ui-boardDescriptionWidget' );
};
@@ -112,6 +120,7 @@
// Hide the edit button, any errors, and the content
this.button.toggle( false );
this.error.toggle( false );
+ this.categoriesWidget.toggle( false );
this.$content.addClass( 'oo-ui-element-hidden' );
this.editor.toggle( true );
@@ -219,9 +228,48 @@
widget.error.toggle( true );
} )
+ // Get the new categories
+ .then( this.api.getCategories.bind( this.api ) )
+ .then( function ( catObject ) {
+ var cat, title,
+ categories = {};
+
+ for ( cat in catObject ) {
+ title = mw.Title.newFromText(
catObject[ cat ].title );
+ categories[ title.getName() ] = {
exists: catObject[ cat ].missing === undefined };
+ }
+ // Update the board data model
+ widget.board.clearCategories();
+ widget.board.setCategoriesFromObject(
categories );
+ } )
+ // Remove the editor and show content
+ .then( function () {
+ widget.showContent( true );
+ } )
+ // Always pop pending for the editor
.always( function () {
widget.editor.popPending();
} );
+ };
+
+ /**
+ * Add categories from a jQuery object. This is so that we can feed
categories from the
+ * nojs rendering of the page without having the widget to ask the API
for the categories
+ * when it just loads.
+ *
+ * @param {jQuery} $categoriesWrapper Categories div wrapper
+ */
+ mw.flow.ui.BoardDescriptionWidget.prototype.addCategoriesFromDom =
function ( $categoriesWrapper ) {
+ var categories = {};
+
+ $categoriesWrapper.find( '.flow-board-header-category-item a'
).each( function () {
+ categories[ $( this ).text() ] = {
+ exists: !$( this ).hasClass( 'new' )
+ };
+ } );
+
+ this.board.setCategoriesFromObject( categories );
+ this.categoriesWidget.toggle( this.board.hasCategories() );
};
/**
@@ -242,6 +290,7 @@
// Display the edit button and the content
this.button.toggle( true );
this.$content.removeClass( 'oo-ui-element-hidden' );
+ this.categoriesWidget.toggle( this.board.hasCategories() );
};
/**
diff --git a/modules/flow/ui/widgets/mw.flow.ui.CategoriesWidget.js
b/modules/flow/ui/widgets/mw.flow.ui.CategoriesWidget.js
new file mode 100644
index 0000000..ab2ea21
--- /dev/null
+++ b/modules/flow/ui/widgets/mw.flow.ui.CategoriesWidget.js
@@ -0,0 +1,100 @@
+( function ( $ ) {
+ /**
+ * Flow board categories widget
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.GroupElement
+ *
+ * @constructor
+ * @param {mw.flow.dm.Board} model Board model
+ * @param {Object} [config]
+ *
+ */
+ mw.flow.ui.CategoriesWidget = function mwFlowUiCategoriesWidget( model,
config ) {
+ config = config || {};
+
+ // Parent constructor
+ mw.flow.ui.CategoriesWidget.parent.call( this, config );
+
+ // Mixin constructor
+ OO.ui.mixin.GroupElement.call( this, config );
+
+ this.model = model;
+ this.model.connect( this, {
+ addCategories: 'onModelAddCategories',
+ removeCategories: 'onModelRemoveCategories',
+ clearCategories: 'onModelClearCategories'
+ } );
+
+ this.categoriesLabel = new OO.ui.LabelWidget();
+ this.updateCategoriesLabel();
+
+ // Initialize
+ this.$element
+ .append(
+ $( '<div>' )
+ .addClass(
'flow-board-header-category-title' )
+ .append( this.categoriesLabel.$element
),
+ this.$group
+ .addClass(
'flow-board-header-category-list' )
+ )
+ .addClass( 'flow-ui-categoriesWidget
flow-board-header-category-view' );
+ };
+
+ /* Initialization */
+
+ OO.inheritClass( mw.flow.ui.CategoriesWidget, OO.ui.Widget );
+ OO.mixinClass( mw.flow.ui.CategoriesWidget, OO.ui.mixin.GroupElement );
+
+ /**
+ * Respond to a change of categories in the board model
+ *
+ * @param {mw.flow.dm.CategoryItem[]} categories Added categories
+ */
+ mw.flow.ui.CategoriesWidget.prototype.onModelAddCategories = function (
categories ) {
+ var i, len,
+ widgets = [];
+
+ for ( i = 0, len = categories.length; i < len; i++ ) {
+ widgets.push( new mw.flow.ui.CategoryItemWidget(
categories[ i ] ) );
+ }
+
+ this.addItems( widgets );
+ this.updateCategoriesLabel();
+ };
+
+ /**
+ * Respond to removing categories from the model
+ *
+ * @param {mw.flow.dm.CategoryItem[]} categories Removed categories
+ */
+ mw.flow.ui.CategoriesWidget.prototype.onModelRemoveCategories =
function ( categories ) {
+ var i, len,
+ widgets = [];
+
+ for ( i = 0, len = categories.length; i < len; i++ ) {
+ widgets.push( this.getItemFromData( categories[ i
].getId() ) );
+ }
+
+ this.removeItems( widgets );
+ this.updateCategoriesLabel();
+ };
+
+ /**
+ * Respond to clearing all categories from the model
+ */
+ mw.flow.ui.CategoriesWidget.prototype.onModelClearCategories = function
() {
+ this.clearItems();
+ };
+
+ /**
+ * Update the category label according to the number of available items
+ */
+ mw.flow.ui.CategoriesWidget.prototype.updateCategoriesLabel = function
() {
+ this.categoriesLabel.setLabel(
+ mw.msg( 'pagecategories', this.model.getItemCount() ) +
+ mw.msg( 'colon-separator' )
+ );
+ };
+}( jQuery ) );
diff --git a/modules/flow/ui/widgets/mw.flow.ui.CategoryItemWidget.js
b/modules/flow/ui/widgets/mw.flow.ui.CategoryItemWidget.js
new file mode 100644
index 0000000..2ad0c2e
--- /dev/null
+++ b/modules/flow/ui/widgets/mw.flow.ui.CategoryItemWidget.js
@@ -0,0 +1,49 @@
+( function ( $ ) {
+ /**
+ * Flow board categories widget
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixin OO.ui.mixin.GroupElement
+ *
+ * @constructor
+ * @param {mw.flow.dm.CategoryItem} categoryModel Category item model
+ * @param {Object} [config]
+ * @cfg {boolean} [exists] Category page exists on this wiki
+ */
+ mw.flow.ui.CategoryItemWidget = function mwFlowUiCategoryItemWidget(
categoryModel, config ) {
+ var prefixedCleanName, $link;
+
+ config = config || {};
+
+ // Parent constructor
+ mw.flow.ui.CategoryItemWidget.parent.call( this, config );
+
+ this.model = categoryModel;
+ this.name = this.model.getId();
+ this.title = mw.Title.newFromText( this.name, mw.config.get(
'wgNamespaceIds' ).category );
+ this.exists = this.model.exists();
+ prefixedCleanName = this.title && this.title.getPrefixedText()
|| this.name;
+
+ $link = $( '<a>' )
+ .attr( 'href', mw.util.getUrl( this.title &&
this.title.getPrefixedDb() || this.name ) )
+ .attr( 'title', this.exists ? prefixedCleanName :
mw.msg( 'red-link-title', prefixedCleanName ) )
+ .text( this.name )
+ .toggleClass( 'new', !this.exists );
+
+ this.$element
+ .addClass( 'flow-ui-categoryItemWidget
flow-board-header-category-item' )
+ .append( $link );
+ };
+
+ OO.inheritClass( mw.flow.ui.CategoryItemWidget, OO.ui.Widget );
+
+ /**
+ * Get the category data
+ *
+ * @return {string} Category name
+ */
+ mw.flow.ui.CategoryItemWidget.prototype.getData = function () {
+ return this.name;
+ };
+}( jQuery ) );
diff --git a/modules/styles/board/header.less b/modules/styles/board/header.less
index 586df78..c621d1b 100644
--- a/modules/styles/board/header.less
+++ b/modules/styles/board/header.less
@@ -48,6 +48,25 @@
display: none;
}
+.flow-board-header-category-view-nojs,
+.flow-board-header-category-view {
+ background: white;
+ padding: 0.5em;
+
+ .flow-board-header-category-list { //ul
+ list-style-type: none;
+ list-style-image: none;
+
+ .flow-board-header-category-item {
+ display: inline-block;
+ }
+
+ .flow-board-header-category-item +
.flow-board-header-category-item:before {
+ content: " | ";
+ }
+ }
+}
+
.side-rail-toggle-button {
visibility: hidden;
position: absolute;
diff --git a/modules/styles/flow/widgets/mw.flow.ui.CategoriesWidget.less
b/modules/styles/flow/widgets/mw.flow.ui.CategoriesWidget.less
new file mode 100644
index 0000000..9dab103
--- /dev/null
+++ b/modules/styles/flow/widgets/mw.flow.ui.CategoriesWidget.less
@@ -0,0 +1,10 @@
+.flow-ui-categoriesWidget {
+ .flow-board-header-category-list {
+ margin: 0.3em 0 0 0.3em;
+ display: inline;
+ }
+
+ .flow-board-header-category-title {
+ display: inline;
+ }
+}
diff --git a/modules/styles/flow/widgets/mw.flow.ui.CategoryItemWidget.less
b/modules/styles/flow/widgets/mw.flow.ui.CategoryItemWidget.less
new file mode 100644
index 0000000..00d164f
--- /dev/null
+++ b/modules/styles/flow/widgets/mw.flow.ui.CategoryItemWidget.less
@@ -0,0 +1,3 @@
+.flow-ui-categoryItemWidget {
+ padding-right: 0.2em;
+}
--
To view, visit https://gerrit.wikimedia.org/r/230017
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ib9b766f9125e1e0c95798db46bf29ca7e0ac0408
Gerrit-PatchSet: 25
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Matthias Mullie <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Sbisson <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits