mediawiki-extensions-Visual.../modules/ve/ui/ve.ui.ToolGroup.js
Trevor Parscal 332e31fb00 Toolbar API
Objectives:

* Make it possible to add items to toolbars without having to have all
  toolbars know about the items in advance
* Make it possible to specialize an existing tool and have it be used
  instead of the base implementation

Approach:

* Tools are named using a path-style category/id/ext system, making them
  selectable, the latter component being used to differentiate extended
  tools from their base classes, but is ignored during selection
* Toolbars have ToolGroups, which include or exclude tools by category or
  category/id, and order them by promoting and demoting selections of
  tools by category or category/id

Future:

* Add a way to place available but not yet placed tools in an "overflow"
  group
* Add a mode to ToolGroup to make the tools a multi-column drop-down style
  list with labels so tools with less obvious icons are easier to identify
  - and probably use this as the overflow group

Change-Id: I7625f861435a99ce3d7a2b1ece9731aaab1776f8
2013-08-20 16:08:26 -07:00

127 lines
3 KiB
JavaScript

/*!
* VisualEditor UserInterface ToolGroup class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* UserInterface tool group.
*
* @class
* @abstract
* @extends ve.ui.Widget
* @mixins ve.ui.GroupElement
*
* Patterns can be either:
* - All tools in a category: 'category'
* - A specific tool: 'category/name'
*
* @constructor
* @param {ve.ui.Toolbar} toolbar
* @param {Object} [config] Config options
* @cfg {string[]} [include=[]] Patterns of tools to automatically include
* @cfg {string[]} [exclude=[]] Patterns of tools to automatically exclude
* @cfg {string[]} [promote=[]] Patterns of tools to promote to the beginning
* @cfg {string[]} [demote=[]] Patterns of tools to demote to the end
*/
ve.ui.ToolGroup = function VeUiToolGroup( toolbar, config ) {
// Configuration initialization
config = config || {};
// Parent constructor
ve.ui.Widget.call( this, config );
// Mixin constructors
ve.ui.GroupElement.call( this, this.$ );
// Properties
this.toolbar = toolbar;
this.tools = {};
this.include = config.include || [];
this.exclude = config.exclude || [];
this.promote = config.promote || [];
this.demote = config.demote || [];
// Events
this.$.on( { 'mousedown': false } );
ve.ui.toolFactory.connect( this, { 'register': 'onToolFactoryRegister' } );
// Initialization
this.$.addClass( 've-ui-toolGroup' );
this.populateTools();
};
/* Inheritance */
ve.inheritClass( ve.ui.ToolGroup, ve.ui.Widget );
ve.mixinClass( ve.ui.ToolGroup, ve.ui.GroupElement );
/* Methods */
/**
* Handle tool registry register events.
*
* If a tool is registered after the group is created, this handler will ensure the tool is included
* as if it were present at the time of the group being created.
*
* @param {string} name Symbolic name of tool
*/
ve.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
this.populateTools();
};
/**
* Add and remove tools based on configuration.
*
* @method
*/
ve.ui.ToolGroup.prototype.populateTools = function () {
var i, len, name, tool,
names = {},
tools = [],
list = ve.ui.toolFactory.getTools(
this.include, this.exclude, this.promote, this.demote
);
// Build a list of needed tools
for ( i = 0, len = list.length; i < len; i++ ) {
name = list[i];
tool = this.tools[name];
if ( !tool ) {
// Auto-initialize tools on first use
tool = ve.ui.toolFactory.create( name, this.toolbar );
this.tools[name] = tool;
}
tools.push( tool );
names[name] = true;
}
// Remove tools that are no longer needed
for ( name in this.tools ) {
if ( !names[name] ) {
this.tools[name].destroy();
this.removeItem( this.tools[name] );
delete this.tools[name];
}
}
// Re-add tools (moving existing ones to new locations)
this.addItems( tools );
};
/**
* Destroy tool group.
*
* @method
*/
ve.ui.ToolGroup.prototype.destroy = function () {
var name;
this.clearItems();
ve.ui.toolFactory.disconnect( this );
for ( name in this.tools ) {
this.tools[name].destroy();
}
this.$.remove();
};