mediawiki-extensions-Visual.../modules/ve/ui/widgets/ve.ui.MWCategoryWidget.js
Trevor Parscal 718db58fd5 Category editing
Modifications:

VisualEditor.php
* Added links to new widgets

VisualEditor.i18n.php
* Added placeholder text for category input

ve.ui.Widget.css
* Added styles for new widgets

New:

ve.ui.MWMetaDialog.js
* Create category widget with categories from dm.
* Listen to metaList for insert and remove events
** insert / remove bound methods to be improved upon additional meta groups
* Add listeners to mwCategoryWidget for new categories and updates

ve.ui.MWCategoryWidget.js
* Top-level category editing widget

ve.ui.MWCategoryItemWidget.js
* Items within a category widget

ve.ui.MWCategoryInputWidget.js
* Input for new categories, handles menu and API requests

ve.ui.MWCategoryPopupWidget.js
* Mini-inspector for a category item

Bug: 39597
Change-Id: I5eafaa484a1924a566d3a1ee1d869293089d0ecf
2013-04-30 17:50:31 +00:00

212 lines
5.1 KiB
JavaScript

/*!
* VisualEditor UserInterface MWCategoryWidget class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Creates an ve.ui.MWCategoryWidget object.
*
* @class
* @abstract
* @extends ve.ui.Widget
*
* @constructor
* @param {Object} [config] Config options
*/
ve.ui.MWCategoryWidget = function VeUiMWCategoryWidget( config ) {
// Config intialization
config = config || {};
// Parent constructor
ve.ui.Widget.call( this, config );
// Properties
this.categories = {};
this.$categories = this.$$( '<div>' );
this.popupState = false;
this.savedPopupState = false;
this.popup = new ve.ui.MWCategoryPopupWidget( {
'$$': this.$$, 'align': 'right', '$overlay': config.$overlay
} );
this.categoryInput = new ve.ui.MWCategoryInputWidget( this, {
'$$': this.$$, '$overlay': config.$overlay, '$container': this.$
} );
// Events
this.categoryInput.$input.on( 'keydown', ve.bind( this.onLookupInputKeyDown, this ) );
this.categoryInput.lookupMenu.addListenerMethod( this, 'select', 'onLookupMenuItemSelect' );
this.popup.addListenerMethods( this, {
'removeCategory': 'onRemoveCategory',
'updateSortkey': 'onUpdateSortkey',
'hide': 'onPopupHide'
} );
// Initialization
this.$.addClass( 've-ui-mwCategoryListWidget' )
.append(
this.$categories,
this.categoryInput.$,
this.$$( '<div>' ).css( 'clear', 'both' )
);
};
/* Inheritance */
ve.inheritClass( ve.ui.MWCategoryWidget, ve.ui.Widget );
/* Events */
/**
* @event newCategory
* @param {Object} item category group item
*/
/**
* @event updateSortkey
* * @param {Object} item category group item
*/
/* Methods */
/**
* Handle input key down event.
*
* @method
* @param {jQuery.Event} e Input key down event
*/
ve.ui.MWCategoryWidget.prototype.onLookupInputKeyDown = function ( e ) {
if ( this.categoryInput.getValue() !== '' && e.which === 13 ) {
this.emit(
'newCategory',
this.categoryInput.getCategoryItemFromValue( this.categoryInput.getValue() )
);
this.categoryInput.setValue( '' );
}
};
/**
* Handle menu item select event.
*
* @method
* @param {ve.ui.MenuItemWidget} item Selected item
*/
ve.ui.MWCategoryWidget.prototype.onLookupMenuItemSelect = function ( item ) {
if ( item && item.getData() !== '' ) {
this.emit( 'newCategory', this.categoryInput.getCategoryItemFromValue( item.getData() ) );
this.categoryInput.setValue( '' );
}
};
/**
* Calls metaItem remove method
*
* @param {String} name category name
*/
ve.ui.MWCategoryWidget.prototype.onRemoveCategory = function ( name ) {
this.categories[name].metaItem.remove();
};
/**
* Update sortkey value, emit upsteSortkey event
*
* @param {String} name
* @param {String} value
*/
ve.ui.MWCategoryWidget.prototype.onUpdateSortkey = function ( name, value ) {
this.categories[name].sortKey = value;
this.emit( 'updateSortkey', this.categories[name] );
};
/**
* Sets popup state when popup is hidden
*/
ve.ui.MWCategoryWidget.prototype.onPopupHide = function () {
this.popupState = false;
};
/**
* Saves current popup state
*/
ve.ui.MWCategoryWidget.prototype.onSavePopupState = function () {
this.savedPopupState = this.popupState;
};
/**
* Toggles popup menu per category item
* @param {Object} item
*/
ve.ui.MWCategoryWidget.prototype.onTogglePoupupMenu = function ( item ) {
// Close open popup.
if ( this.savedPopupState === false || item.value !== this.popup.category ) {
this.popup.openPopup( item );
} else {
// Handle toggle
this.popup.closePopup();
}
};
/**
* Get list of category names.
*
* @method
* @param {string[]} List of category names
*/
ve.ui.MWCategoryWidget.prototype.getCategories = function () {
return ve.getObjectKeys( this.categories );
};
/**
* Adds category items.
*
* @method
* @param {Object[]} items [description]
* @chainable
*/
ve.ui.MWCategoryWidget.prototype.addItems = function ( items ) {
var i, len, item, categoryGroupItem,
existingCategoryGroupItem = null;
for ( i = 0, len = items.length; i < len; i++ ) {
item = items[i];
// Filter out categories derived from aliens.
// TODO: Remove the block below once aliens no longer add items to metalist.
if( 'html/0/about' in item.metaItem.element.attributes ) {
return this;
}
categoryGroupItem = new ve.ui.MWCategoryItemWidget( { '$$': this.$$, 'item': item } );
// Bind category item events.
categoryGroupItem.addListenerMethods( this, {
'savePopupState': 'onSavePopupState',
'togglePopupMenu': 'onTogglePoupupMenu'
} );
if ( item.value in this.categories ) {
existingCategoryGroupItem = this.categories[item.value];
this.categories[item.value].metaItem.remove();
}
this.categories[item.value] = categoryGroupItem;
if ( existingCategoryGroupItem ) {
categoryGroupItem.sortKey = existingCategoryGroupItem.sortKey;
}
this.$categories.append( categoryGroupItem.$ );
}
return this;
};
/**
* Remove category items.
*
* @method
* @param {string[]} names Names of categories to remove
*/
ve.ui.MWCategoryWidget.prototype.removeItems = function ( names ) {
var i, len;
for ( i = 0, len = names.length; i < len; i++ ) {
this.categories[names[i]].$.remove();
delete this.categories[names[i]];
}
};