Merge changes I51e74b32,Ibaa14d20

* changes:
  Refactor Transclusion and Meta dialogs to use BookletLayout
  Update OOJS UI to v0.1.0-pre (592e1d6401)
This commit is contained in:
jenkins-bot 2013-12-06 00:48:41 +00:00 committed by Gerrit Code Review
commit 674236cab4
19 changed files with 1856 additions and 1253 deletions

View file

@ -134,6 +134,10 @@
{
"name": "Dialogs",
"classes": ["ve.ui.*Dialog"]
},
{
"name": "Pages",
"classes": ["ve.ui.*Page"]
}
]
},

View file

@ -474,12 +474,21 @@ $wgResourceModules += array(
've-mw/ui/widgets/ve.ui.MWReferenceResultWidget.js',
've-mw/ui/widgets/ve.ui.MWTitleInputWidget.js',
've-mw/ui/pages/ve.ui.MWCategoriesPage.js',
've-mw/ui/pages/ve.ui.MWLanguagesPage.js',
've-mw/ui/pages/ve.ui.MWTemplatePage.js',
've-mw/ui/pages/ve.ui.MWTemplateParameterPage.js',
've-mw/ui/pages/ve.ui.MWTemplatePlaceholderPage.js',
've-mw/ui/pages/ve.ui.MWTransclusionContentPage.js',
've-mw/ui/dialogs/ve.ui.MWSaveDialog.js',
've-mw/ui/dialogs/ve.ui.MWMetaDialog.js',
've-mw/ui/dialogs/ve.ui.MWBetaWelcomeDialog.js',
've-mw/ui/dialogs/ve.ui.MWMediaInsertDialog.js',
've-mw/ui/dialogs/ve.ui.MWMediaEditDialog.js',
've-mw/ui/dialogs/ve.ui.MWTransclusionDialog.js',
've-mw/ui/dialogs/ve.ui.MWTemplateDialog.js',
've-mw/ui/dialogs/ve.ui.MWAdvancedTransclusionDialog.js',
've-mw/ui/dialogs/ve.ui.MWReferenceListDialog.js',
've-mw/ui/dialogs/ve.ui.MWReferenceDialog.js',

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,12 @@
/*!
* OOJS UI v0.1.0-pre-svg (e5ef1e5b28)
* OOJS UI v0.1.0-pre-svg (592e1d6401)
* https://www.mediawiki.org/wiki/OOJS
*
* Copyright 2011-2013 OOJS Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
* Date: Mon Nov 25 2013 10:40:32 GMT+0000 (GMT)
* Date: Thu Dec 05 2013 16:06:17 GMT-0800 (PST)
*/
/*csslint vendor-prefix:false */
@ -199,46 +199,6 @@
margin: 0.25em 0.25em;
}
/* OO.ui.PagedLayout */
.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout {
padding: 1.5em;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout-scrollable {
overflow-y: auto;
}
.oo-ui-pagedLayout-pagesPanel .oo-ui-panelLayout-padded {
padding: 2em;
}
/* OO.ui.PagedOutlineLayout */
.oo-ui-pagedOutlineLayout-outlinePanel {
border-right: solid 1px #ddd;
}
.oo-ui-pagedOutlineLayout-outlinePanel-editable .oo-ui-outlineWidget {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 3em;
overflow-y: auto;
}
.oo-ui-pagedOutlineLayout-outlinePanel .oo-ui-outlineControlsWidget {
position: absolute;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
}
/* OO.ui.LabeledElement */
.oo-ui-labeledElement-label {
@ -289,10 +249,14 @@
.oo-ui-fieldsetLayout {
border: none;
margin: 0 0 1.75em 0;
margin: 0;
padding: 0;
}
.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
margin-top: 2em;
}
.oo-ui-fieldsetLayout-labeled {
margin-top: -0.75em;
}
@ -307,6 +271,60 @@
background-position: left center;
background-repeat: no-repeat;
}
/* OO.ui.BookletLayout */
.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
padding: 1.5em;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable {
overflow-y: auto;
}
.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded {
padding: 2em;
}
.oo-ui-bookletLayout-outlinePanel {
border-right: solid 1px #ddd;
}
.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 3em;
overflow-y: auto;
}
.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
position: absolute;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
}
.oo-ui-stackLayout > .oo-ui-panelLayout {
display: none;
}
.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
display: block;
position: relative;
margin-bottom: 1em;
box-shadow: 0 0 0.5em rgba(0,0,0,0.25);
}
.oo-ui-stackLayout-continuous > .oo-ui-panelLayout:last-child {
margin-bottom: 0;
}
/* OO.ui.PopupTool */
.oo-ui-popupTool .oo-ui-popupWidget {
@ -1094,6 +1112,21 @@ a.oo-ui-buttonWidget-button {
background-repeat: no-repeat;
}
/* OO.ui.CheckboxWidget */
.oo-ui-checkboxWidget .oo-ui-labeledElement-label {
display: inline-block;
vertical-align: middle;
padding-left: 0.5em;
}
.oo-ui-checkboxWidget input {
vertical-align: middle;
}
.oo-ui-checkboxWidget.oo-ui-widget-disabled .oo-ui-labeledElement-label {
opacity: 0.5;
}
/* OO.ui.MenuWidget */
.oo-ui-menuWidget {
@ -1259,6 +1292,10 @@ a.oo-ui-buttonWidget-button {
transition: background-color 200ms;
}
.oo-ui-toggleWidget.oo-ui-widget-disabled {
opacity: 0.5;
}
.oo-ui-toggleWidget-slide {
position: absolute;
top: 0;
@ -1316,7 +1353,7 @@ a.oo-ui-buttonWidget-button {
background-image: linear-gradient(top, #ffffff 0%, #f0f0f0 100%);
}
.oo-ui-toggleWidget:hover,
.oo-ui-toggleWidget:not(.oo-ui-widget-disabled):hover,
.oo-ui-toggleWidget-dragging,
.oo-ui-toggleWidget:hover .oo-ui-toggleWidget-grip,
.oo-ui-toggleWidget-dragging .oo-ui-toggleWidget-grip {

View file

@ -18,15 +18,13 @@
* @param {Object} target Template target
* @param {string} target.wt Original wikitext of target
* @param {string} [target.href] Hypertext reference to target
* @param {string} [origin] Origin of part, e.g. 'data' or 'user'
*/
ve.dm.MWTemplateModel = function VeDmMWTemplateModel( transclusion, target, origin ) {
ve.dm.MWTemplateModel = function VeDmMWTemplateModel( transclusion, target ) {
// Parent constructor
ve.dm.MWTransclusionPartModel.call( this, transclusion );
// Properties
this.target = target;
this.origin = origin;
// TODO: Either here or in uses of this constructor we need to validate the title
this.title = ( target.href && target.href.replace( /^(\.\.?\/)*/, '' ) ) || null;
@ -106,26 +104,15 @@ ve.dm.MWTemplateModel.newFromName = function ( transclusion, name ) {
/**
* Get template target.
*
* @method
* @returns {Object} Template target
*/
ve.dm.MWTemplateModel.prototype.getTarget = function () {
return this.target;
};
/**
* Get template origin, e.g. 'user' or 'data'.
*
* @returns {string} Origin
*/
ve.dm.MWTemplateModel.prototype.getOrigin = function () {
return this.origin;
};
/**
* Get template title.
*
* @method
* @returns {string|null} Template title, if available
*/
ve.dm.MWTemplateModel.prototype.getTitle = function () {
@ -135,7 +122,6 @@ ve.dm.MWTemplateModel.prototype.getTitle = function () {
/**
* Get template specification.
*
* @method
* @returns {ve.dm.MWTemplateSpecModel} Template specification
*/
ve.dm.MWTemplateModel.prototype.getSpec = function () {
@ -145,7 +131,6 @@ ve.dm.MWTemplateModel.prototype.getSpec = function () {
/**
* Get all params.
*
* @method
* @returns {Object.<string,ve.dm.MWTemplateParameterModel>} Parameters keyed by name
*/
ve.dm.MWTemplateModel.prototype.getParameters = function () {
@ -155,7 +140,6 @@ ve.dm.MWTemplateModel.prototype.getParameters = function () {
/**
* Get a parameter.
*
* @method
* @param {string} name Parameter name
* @returns {ve.dm.MWTemplateParameterModel} Parameter
*/
@ -166,7 +150,6 @@ ve.dm.MWTemplateModel.prototype.getParameter = function ( name ) {
/**
* Check if a parameter exists.
*
* @method
* @param {string} name Parameter name
* @returns {boolean} Parameter exists
*/
@ -203,7 +186,6 @@ ve.dm.MWTemplateModel.prototype.hasParameter = function ( name ) {
* Numeric names, whether strings or real numbers, are placed at the begining, followed by
* alphabetically sorted names.
*
* @method
* @returns {string[]} List of parameter names
*/
ve.dm.MWTemplateModel.prototype.getParameterNames = function () {
@ -233,7 +215,6 @@ ve.dm.MWTemplateModel.prototype.getParameterNames = function () {
/**
* Add a parameter to template.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} param Parameter to add
* @fires add
*/
@ -248,7 +229,6 @@ ve.dm.MWTemplateModel.prototype.addParameter = function ( param ) {
/**
* Remove parameter from template.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} param Parameter to remove
* @fires remove
*/
@ -261,9 +241,25 @@ ve.dm.MWTemplateModel.prototype.removeParameter = function ( param ) {
};
/**
* Set original data, to be used as a base for serialization.
* Add all non-existing required parameters, if any.
*
* @method
*/
ve.dm.MWTemplateModel.prototype.addRequiredParameters = function () {
var i, len,
spec = this.getSpec(),
names = spec.getParameterNames();
for ( i = 0, len = names.length; i < len; i++ ) {
if ( !this.params[name] && spec.isParameterRequired( names[i] ) ) {
this.addParameter( new ve.dm.MWTemplateParameterModel( this, names[i] ) );
}
}
};
/**
* Set original data, to be used as a base for serialization.
*
* @returns {Object} Template data
*/
ve.dm.MWTemplateModel.prototype.setOriginalData = function ( data ) {

View file

@ -37,13 +37,9 @@ OO.mixinClass( ve.dm.MWTransclusionModel, OO.EventEmitter );
/* Events */
/**
* @event add
* @param {ve.dm.MWTransclusionPartModel} part Added part
*/
/**
* @event remove
* @param {ve.dm.MWTransclusionPartModel} part Removed part
* @event replace
* @param {ve.dm.MWTransclusionPartModel|null} removed Removed part
* @param {ve.dm.MWTransclusionPartModel|null} added Added part
*/
/* Methods */
@ -51,12 +47,12 @@ OO.mixinClass( ve.dm.MWTransclusionModel, OO.EventEmitter );
/**
* Load from transclusion data, and fetch spec from server.
*
* @method
* @param {Object} data Transclusion data
* @returns {jQuery.Promise} Promise, resolved when spec is loaded
*/
ve.dm.MWTransclusionModel.prototype.load = function ( data ) {
var i, len, part;
var i, len, part, deferred,
promises = [];
// Convert single part format to multi-part format
// Parsoid doesn't use this format any more, but we accept it for backwards compatibility
@ -68,48 +64,66 @@ ve.dm.MWTransclusionModel.prototype.load = function ( data ) {
for ( i = 0, len = data.parts.length; i < len; i++ ) {
part = data.parts[i];
if ( part.template ) {
this.queue.push(
{ 'part': ve.dm.MWTemplateModel.newFromData( this, part.template ) }
);
deferred = $.Deferred();
promises.push( deferred.promise() );
this.queue.push( {
'add': ve.dm.MWTemplateModel.newFromData( this, part.template ),
'deferred': deferred
} );
} else if ( typeof part === 'string' ) {
this.queue.push(
{ 'part': new ve.dm.MWTransclusionContentModel( this, part, 'data' ) }
);
deferred = $.Deferred();
promises.push( deferred.promise() );
this.queue.push( {
'add': new ve.dm.MWTransclusionContentModel( this, part, 'data' ),
'deferred': deferred
} );
}
}
setTimeout( ve.bind( this.fetch, this ) );
}
return $.when.apply( $, promises );
};
/**
* Process one or more queue items.
*
* @method
* @param {Object[]} queue List of objects containing parts to add and optionally indexes to add
* them at, if no index is given parts will be added at the end
* @fires add For each item added
* @fires replace For each item added
*/
ve.dm.MWTransclusionModel.prototype.process = function ( queue ) {
var i, len, item, title, index;
var i, len, item, title, index,
remove = 0;
for ( i = 0, len = queue.length; i < len; i++ ) {
item = queue[i];
if ( item.part instanceof ve.dm.MWTemplateModel ) {
title = item.part.getTitle();
if ( item.add instanceof ve.dm.MWTemplateModel ) {
title = item.add.getTitle();
if ( hasOwn.call( specCache, title ) && specCache[title] ) {
item.part.getSpec().extend( specCache[title] );
item.add.getSpec().extend( specCache[title] );
}
}
// Auto-remove if already existing
index = ve.indexOf( item.part, this.parts );
index = ve.indexOf( item.add, this.parts );
if ( index !== -1 ) {
this.parts.splice( index, 1 );
this.emit( 'remove', item.part );
this.emit( 'replace', item.add, null );
}
// Add at index, or end if none was given
index = item.index === undefined ? this.parts.length : item.index;
this.parts.splice( index, 0, item.part );
this.emit( 'add', item.part );
if ( item.index !== undefined ) {
index = item.index;
} else if ( item.remove ) {
index = ve.indexOf( item.remove, this.parts );
if ( index !== -1 ) {
remove = 1;
}
}
if ( index === undefined || index === -1 ) {
index = this.parts.length;
}
this.parts.splice( index, remove, item.add );
this.emit( 'replace', item.remove || null, item.add );
// Resolve promises
if ( item.deferred ) {
item.deferred.resolve();
@ -134,8 +148,8 @@ ve.dm.MWTransclusionModel.prototype.fetch = function () {
// Get unique list of template titles that aren't already loaded
for ( i = 0, len = queue.length; i < len; i++ ) {
item = queue[i];
if ( item.part instanceof ve.dm.MWTemplateModel ) {
title = item.part.getTitle();
if ( item.add instanceof ve.dm.MWTemplateModel ) {
title = item.add.getTitle();
if (
// Skip titles that don't have a resolvable href
title &&
@ -227,7 +241,6 @@ ve.dm.MWTransclusionModel.prototype.abortRequests = function () {
/**
* Get plain object representation of template transclusion.
*
* @method
* @returns {Object|null} Plain object representation, or null if empty
*/
ve.dm.MWTransclusionModel.prototype.getPlainObject = function () {
@ -254,19 +267,45 @@ ve.dm.MWTransclusionModel.prototype.getPlainObject = function () {
*
* This is used to give parts unique IDs, and returns a different value each time it's called.
*
* @method
* @returns {number} Unique ID
*/
ve.dm.MWTransclusionModel.prototype.getUniquePartId = function () {
return this.uid++;
};
/**
* Replace part.
*
* Replace asynchonously.
*
* @param {ve.dm.MWTransclusionPartModel} remove Part to remove
* @param {ve.dm.MWTransclusionPartModel} add Part to add
* @throws {Error} If part to remove is not valid
* @throws {Error} If part to add is not valid
* @returns {jQuery.Promise} Promise, resolved when part is added
*/
ve.dm.MWTransclusionModel.prototype.replacePart = function ( remove, add ) {
var deferred = $.Deferred();
if (
!( remove instanceof ve.dm.MWTransclusionPartModel ) ||
!( add instanceof ve.dm.MWTransclusionPartModel )
) {
throw new Error( 'Invalid transclusion part' );
}
this.queue.push( { 'remove': remove, 'add': add, 'deferred': deferred } );
// Fetch on next yield to process items in the queue together, subsequent calls to fetch will
// have no effect because the queue will be clear
setTimeout( ve.bind( this.fetch, this ) );
return deferred.promise();
};
/**
* Add part.
*
* Added asynchronously, but order is preserved.
*
* @method
* @param {ve.dm.MWTransclusionPartModel} part Part to add
* @param {number} [index] Specific index to add content at, defaults to the end
* @throws {Error} If part is not valid
@ -277,7 +316,7 @@ ve.dm.MWTransclusionModel.prototype.addPart = function ( part, index ) {
if ( !( part instanceof ve.dm.MWTransclusionPartModel ) ) {
throw new Error( 'Invalid transclusion part' );
}
this.queue.push( { 'part': part, 'index': index, 'deferred': deferred } );
this.queue.push( { 'add': part, 'index': index, 'deferred': deferred } );
// Fetch on next yield to process items in the queue together, subsequent calls to fetch will
// have no effect because the queue will be clear
@ -289,22 +328,20 @@ ve.dm.MWTransclusionModel.prototype.addPart = function ( part, index ) {
/**
* Remove a part.
*
* @method
* @param {ve.dm.MWTransclusionPartModel} part Part to remove
* @fires remove
* @fires replace
*/
ve.dm.MWTransclusionModel.prototype.removePart = function ( part ) {
var index = ve.indexOf( part, this.parts );
if ( index !== -1 ) {
this.parts.splice( index, 1 );
this.emit( 'remove', part );
this.emit( 'replace', part, null );
}
};
/**
* Get all parts.
*
* @method
* @returns {ve.dm.MWTransclusionPartModel[]} Parts in transclusion
*/
ve.dm.MWTransclusionModel.prototype.getParts = function () {
@ -316,7 +353,6 @@ ve.dm.MWTransclusionModel.prototype.getParts = function () {
*
* Matching is performed against the first section of the `id`, delimited by a '/'.
*
* @method
* @param {string} id Part ID
* @returns {ve.dm.MWTransclusionPartModel|null} Part with matching ID, if found
*/
@ -334,4 +370,36 @@ ve.dm.MWTransclusionModel.prototype.getPartFromId = function ( id ) {
return null;
};
/**
* Get the index of a part or parameter.
*
* Indexes are linear depth-first addresses in the transclusion tree.
*
* @param {ve.dm.MWTransclusionPartModel|ve.dm.MWTemplateParameterModel} model Part or parameter
* @returns {number} Page index of model
*/
ve.dm.MWTransclusionModel.prototype.getIndex = function ( model ) {
var i, iLen, j, jLen, part, names,
parts = this.parts,
index = 0;
for ( i = 0, iLen = parts.length; i < iLen; i++ ) {
part = parts[i];
if ( part === model ) {
return index;
}
index++;
if ( part instanceof ve.dm.MWTemplateModel ) {
names = part.getParameterNames();
for ( j = 0, jLen = names.length; j < jLen; j++ ) {
if ( part.getParameter( names[j] ) === model ) {
return index;
}
index++;
}
}
}
return -1;
};
}() );

View file

@ -0,0 +1,131 @@
/*
* VisualEditor user interface MWAdvancedTransclusionDialog class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Dialog for inserting and editing MediaWiki transclusions.
*
* @class
* @extends ve.ui.MWTransclusionDialog
*
* @constructor
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.MWAdvancedTransclusionDialog = function VeUiMWAdvancedTransclusionDialog( windowSet, config ) {
// Parent constructor
ve.ui.MWTransclusionDialog.call( this, windowSet, config );
// Properties
this.node = null;
this.transclusion = null;
this.loaded = false;
};
/* Inheritance */
OO.inheritClass( ve.ui.MWAdvancedTransclusionDialog, ve.ui.MWTransclusionDialog );
/* Static Properties */
ve.ui.MWAdvancedTransclusionDialog.static.name = 'transclusion';
ve.ui.MWAdvancedTransclusionDialog.static.titleMessage = 'visualeditor-dialog-transclusion-title';
ve.ui.MWAdvancedTransclusionDialog.static.icon = 'template';
/* Methods */
/**
* Handle outline controls move events.
*
* @param {number} places Number of places to move the selected item
*/
ve.ui.MWAdvancedTransclusionDialog.prototype.onOutlineControlsMove = function ( places ) {
var part, index, name, promise,
parts = this.transclusion.getParts(),
item = this.bookletLayout.getOutline().getSelectedItem();
if ( item ) {
name = item.getData();
part = this.transclusion.getPartFromId( name );
index = ve.indexOf( part, parts );
// Auto-removes part from old location
promise = this.transclusion.addPart( part, index + places );
if ( this.loaded ) {
promise.done( ve.bind( this.setPageByName, this, part.getId() ) );
}
}
};
/**
* Handle outline controls add events.
*
* @param {string} type Type of item to add
*/
ve.ui.MWAdvancedTransclusionDialog.prototype.onOutlineControlsAdd = function ( type ) {
var part, parts, item, index, promise;
if ( type === 'content' ) {
part = new ve.dm.MWTransclusionContentModel( this.transclusion, '', 'user' );
} else if ( type === 'template' ) {
part = new ve.dm.MWTemplatePlaceholderModel( this.transclusion, 'user' );
}
if ( part ) {
parts = this.transclusion.getParts();
item = this.bookletLayout.getOutline().getSelectedItem();
index = item ?
ve.indexOf( this.transclusion.getPartFromId( item.getData() ), parts ) + 1 :
parts.length;
promise = this.transclusion.addPart( part, index );
if ( this.loaded ) {
promise.done( ve.bind( this.setPageByName, this, part.getId() ) );
}
}
};
/**
* @inheritdoc
*/
ve.ui.MWAdvancedTransclusionDialog.prototype.getBookletLayout = function () {
return new OO.ui.BookletLayout( {
'$': this.$,
'continuous': true,
'autoFocus': true,
'outlined': true,
'editable': true,
'adders': [
{
'name': 'template',
'icon': 'template',
'title': ve.msg( 'visualeditor-dialog-transclusion-add-template' )
},
{
'name': 'content',
'icon': 'source',
'title': ve.msg( 'visualeditor-dialog-transclusion-add-content' )
}
]
} );
};
/**
* @inheritdoc
*/
ve.ui.MWAdvancedTransclusionDialog.prototype.initialize = function () {
// Parent method
ve.ui.MWTransclusionDialog.prototype.initialize.call( this );
// Events
this.bookletLayout.getOutlineControls().connect( this, {
'move': 'onOutlineControlsMove',
'add': 'onOutlineControlsAdd'
} );
};
/* Registration */
ve.ui.dialogFactory.register( ve.ui.MWAdvancedTransclusionDialog );

View file

@ -5,8 +5,6 @@
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw*/
/**
* Dialog for editing MediaWiki page meta information.
*
@ -20,17 +18,6 @@
ve.ui.MWMetaDialog = function VeUiMWMetaDialog( windowSet, config ) {
// Parent constructor
ve.ui.MWDialog.call( this, windowSet, config );
// Properties
this.metaList = this.surface.getModel().metaList;
this.defaultSortKeyTouched = false;
this.fallbackDefaultSortKey = mw.config.get( 'wgTitle' );
// Events
this.metaList.connect( this, {
'insert': 'onMetaListInsert',
'remove': 'onMetaListRemove'
} );
};
/* Inheritance */
@ -47,341 +34,32 @@ ve.ui.MWMetaDialog.static.icon = 'settings';
/* Methods */
/**
* Handle language items being loaded.
*/
ve.ui.MWMetaDialog.prototype.onAllLanuageItemsSuccess = function ( deferred, response ) {
var i, iLen, languages = [], langlinks = response.query.pages[response.query.pageids[0]].langlinks;
if ( langlinks ) {
for ( i = 0, iLen = langlinks.length; i < iLen; i++ ) {
languages.push( {
'lang': langlinks[i].lang,
'title': langlinks[i]['*'],
'metaItem': null
} );
}
}
deferred.resolve( languages );
};
/**
* Handle language items failing to be loaded.
*
* TODO: This error function should probably not be empty.
*/
ve.ui.MWMetaDialog.prototype.onAllLanuageItemsError = function () {};
/**
* Handle category default sort change events.
*
* @param {string} value Default sort value
*/
ve.ui.MWMetaDialog.prototype.onDefaultSortChange = function ( value ) {
this.categoryWidget.setDefaultSortKey( value === '' ? this.fallbackDefaultSortKey : value );
this.defaultSortKeyTouched = true;
};
/**
* Inserts new category into meta list
*
* @param {Object} item
*/
ve.ui.MWMetaDialog.prototype.onNewCategory = function ( item ) {
// Insert new metaList item
this.insertMetaListItem( this.getCategoryItemForInsertion( item ) );
};
/**
* Removes and re-inserts updated category widget item
*
* @param {Object} item
*/
ve.ui.MWMetaDialog.prototype.onUpdateSortKey = function ( item ) {
// Replace meta item with updated one
item.metaItem.replaceWith( this.getCategoryItemForInsertion( item, item.metaItem.getElement() ) );
};
/**
* Bound to MetaList insert event for adding meta dialog components.
*
* @param {ve.dm.MetaItem} metaItem
*/
ve.ui.MWMetaDialog.prototype.onMetaListInsert = function ( metaItem ) {
// Responsible for adding UI components
if ( metaItem.element.type === 'mwCategory' ) {
this.categoryWidget.addItems(
[ this.getCategoryItemFromMetaListItem( metaItem ) ],
this.metaList.findItem( metaItem.getOffset(), metaItem.getIndex(), 'mwCategory' )
);
}
};
/**
* Bound to MetaList insert event for removing meta dialog components.
*
* @param {ve.dm.MetaItem} metaItem
*/
ve.ui.MWMetaDialog.prototype.onMetaListRemove = function ( metaItem ) {
var item;
if ( metaItem.element.type === 'mwCategory' ) {
item = this.getCategoryItemFromMetaListItem( metaItem );
this.categoryWidget.removeItems( [item.value] );
}
};
/**
* Get default sort key item.
*
* @returns {string} Default sort key item
*/
ve.ui.MWMetaDialog.prototype.getDefaultSortKeyItem = function () {
var items = this.metaList.getItemsInGroup( 'mwDefaultSort' );
return items.length ? items[0] : null;
};
/**
* Get array of category items from meta list
*
* @returns {Object[]} items
*/
ve.ui.MWMetaDialog.prototype.getCategoryItems = function () {
var i,
items = [],
categories = this.metaList.getItemsInGroup( 'mwCategory' );
// Loop through MwCategories and build out items
for ( i = 0; i < categories.length; i++ ) {
items.push( this.getCategoryItemFromMetaListItem( categories[i] ) );
}
return items;
};
/**
* Gets category item from meta list item
*
* @param {ve.dm.MWCategoryMetaItem} metaItem
* @returns {Object} item
*/
ve.ui.MWMetaDialog.prototype.getCategoryItemFromMetaListItem = function ( metaItem ) {
var title = mw.Title.newFromText( metaItem.element.attributes.category ),
value = title ? title.getMainText() : '';
return {
'name': metaItem.element.attributes.category,
'value': value,
// TODO: sortkey is lcase, make consistent throughout CategoryWidget
'sortKey': metaItem.element.attributes.sortkey,
'metaItem': metaItem
};
};
/**
* Get metaList like object to insert from item
*
* @param {Object} item category widget item
* @param {Object} [oldData] Metadata object that was previously associated with this item, if any
* @returns {Object} metaBase
*/
ve.ui.MWMetaDialog.prototype.getCategoryItemForInsertion = function ( item, oldData ) {
var newData = {
'attributes': { 'category': item.name, 'sortkey': item.sortKey || '' },
'type': 'mwCategory'
};
if ( oldData ) {
return ve.extendObject( {}, oldData, newData );
}
return newData;
};
/**
* Gets language item from meta list item
*
* @param {ve.dm.MWLanguageMetaItem} metaItem
* @returns {Object} item
*/
ve.ui.MWMetaDialog.prototype.getLanguageItemFromMetaListItem = function ( metaItem ) {
// TODO: get real values from metaItem once Parsoid actually provides them - bug 48970
return {
'lang': 'lang',
'title': 'title',
'metaItem': metaItem
};
};
/**
* Get array of language items from meta list
*
* @returns {Object[]} items
*/
ve.ui.MWMetaDialog.prototype.getLocalLanguageItems = function () {
var i,
items = [],
languages = this.metaList.getItemsInGroup( 'mwLanguage' ),
languageslength = languages.length;
// Loop through MWLanguages and build out items
for ( i = 0; i < languageslength; i++ ) {
items.push( this.getLanguageItemFromMetaListItem( languages[i] ) );
}
return items;
};
/**
* Get array of language items from meta list
*
* @returns {jQuery.Promise}
*/
ve.ui.MWMetaDialog.prototype.getAllLanguageItems = function () {
var deferred = $.Deferred();
// TODO: Detect paging token if results exceed limit
$.ajax( {
'url': mw.util.wikiScript( 'api' ),
'data': {
'action': 'query',
'prop': 'langlinks',
'lllimit': 500,
'titles': mw.config.get( 'wgTitle' ),
'indexpageids': 1,
'format': 'json'
},
'dataType': 'json',
'type': 'POST',
// Wait up to 100 seconds before giving up
'timeout': 100000,
'cache': 'false'
} )
.done( ve.bind( this.onAllLanuageItemsSuccess, this, deferred ) )
.fail( ve.bind( this.onAllLanuageItemsError, this, deferred ) );
return deferred.promise();
};
/**
* Inserts a meta list item
*
* @param {Object} metaBase meta list insert object
*/
ve.ui.MWMetaDialog.prototype.insertMetaListItem = function ( metaBase ) {
this.metaList.insertMeta( metaBase );
};
/**
* @inheritdoc
*/
ve.ui.MWMetaDialog.prototype.initialize = function () {
var languagePromise;
// Parent method
ve.ui.MWDialog.prototype.initialize.call( this );
// Properties
this.pagedOutlineLayout = new OO.ui.PagedOutlineLayout( { '$': this.$ } );
this.categoriesFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-categories-data-label' ),
'icon': 'tag'
} );
this.categoryOptionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-categories-options' ),
'icon': 'settings'
} );
this.categoryWidget = new ve.ui.MWCategoryWidget( {
'$': this.$, '$overlay': this.$overlay
} );
this.defaultSortInput = new OO.ui.TextInputWidget( {
'$': this.$, 'placeholder': this.fallbackDefaultSortKey
} );
this.defaultSortLabel = new OO.ui.InputLabelWidget( {
'$': this.$,
'input': this.defaultSortInput,
'label': ve.msg( 'visualeditor-dialog-meta-categories-defaultsort-label' )
} );
this.languagesFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-languages-label' ),
'icon': 'language'
} );
this.bookletLayout = new OO.ui.BookletLayout( { '$': this.$, 'outlined': true } );
this.applyButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-action-apply' ),
'flags': ['primary']
} );
this.categoriesPage = new ve.ui.MWCategoriesPage( this.surface, 'categories', {
'$': this.$, '$overlay': this.$overlay
} );
this.languagesPage = new ve.ui.MWLanguagesPage( 'languages', { '$': this.$ } );
// Events
this.categoryWidget.connect( this, {
'newCategory': 'onNewCategory',
'updateSortkey': 'onUpdateSortKey'
} );
this.defaultSortInput.connect( this, {
'change': 'onDefaultSortChange'
} );
this.applyButton.connect( this, { 'click': [ 'close', { 'action': 'apply' } ] } );
// Initialization
this.categoryWidget.addItems( this.getCategoryItems() );
this.$body.append( this.pagedOutlineLayout.$element );
this.$body.append( this.bookletLayout.$element );
this.$foot.append( this.applyButton.$element );
this.pagedOutlineLayout.addPage( 'categories', {
'$content': [ this.categoriesFieldset.$element, this.categoryOptionsFieldset.$element ],
'label': ve.msg( 'visualeditor-dialog-meta-categories-section' ),
'icon': 'tag'
} ).addPage( 'languages', {
'$content': this.languagesFieldset.$element,
'label': ve.msg( 'visualeditor-dialog-meta-languages-section' ),
'icon': 'language'
} );
this.categoriesFieldset.$element.append( this.categoryWidget.$element );
this.categoryOptionsFieldset.$element.append(
this.defaultSortLabel.$element,
this.defaultSortInput.$element
);
this.languagesFieldset.$element.append(
this.$( '<span>' )
.text( ve.msg( 'visualeditor-dialog-meta-languages-readonlynote' ) )
);
languagePromise = this.getAllLanguageItems();
languagePromise.done( ve.bind( function ( languages ) {
var i, $languagesTable = this.$( '<table>' ), languageslength = languages.length;
$languagesTable
.addClass( 've-ui-mwMetaDialog-languages-table' )
.append( this.$( '<tr>' )
.append(
this.$( '<th>' )
.append( ve.msg( 'visualeditor-dialog-meta-languages-code-label' ) )
)
.append(
this.$( '<th>' )
.append( ve.msg( 'visualeditor-dialog-meta-languages-link-label' ) )
)
);
for ( i = 0; i < languageslength; i++ ) {
languages[i].safelang = languages[i].lang;
languages[i].dir = 'auto';
if ( $.uls ) {
// site codes don't always represent official language codes
// using real language code instead of a dummy ('redirect' in ULS' terminology)
languages[i].safelang = $.uls.data.isRedirect( languages[i].lang ) || languages[i].lang;
languages[i].dir = $.uls.data.getDir( languages[i].safelang );
}
$languagesTable
.append( this.$( '<tr>' )
.append( this.$( '<td>' ).append( languages[i].lang ) )
.append( this.$( '<td>' ).append( languages[i].title )
.attr( 'lang', languages[i].safelang )
.attr( 'dir', languages[i].dir ) )
);
}
this.languagesFieldset.$element.append( $languagesTable );
}, this ) );
this.bookletLayout.addPages( [ this.categoriesPage, this.languagesPage ] );
};
/**
@ -394,49 +72,25 @@ ve.ui.MWMetaDialog.prototype.setup = function ( data ) {
// Data initialization
data = data || {};
var surfaceModel = this.surface.getModel(),
categoryWidget = this.categoryWidget,
defaultSortKeyItem = this.getDefaultSortKeyItem();
var surfaceModel = this.surface.getModel();
if ( data.page && this.pagedOutlineLayout.getPage( data.page ) ) {
this.pagedOutlineLayout.setPage( data.page );
if ( data.page && this.bookletLayout.getPage( data.page ) ) {
this.bookletLayout.setPage( data.page );
}
this.defaultSortInput.setValue(
defaultSortKeyItem ? defaultSortKeyItem.getAttribute( 'content' ) : ''
);
this.defaultSortKeyTouched = false;
// Force all previous transactions to be separate from this history state
surfaceModel.breakpoint();
surfaceModel.stopHistoryTracking();
// Update input position once visible
setTimeout( function () {
categoryWidget.fitInput();
} );
this.categoriesPage.setup( data );
};
/**
* @inheritdoc
*/
ve.ui.MWMetaDialog.prototype.teardown = function ( data ) {
// Data initialization
data = data || {};
var hasTransactions,
surfaceModel = this.surface.getModel(),
// Category sort key items
currentDefaultSortKeyItem = this.getDefaultSortKeyItem(),
newDefaultSortKey = this.defaultSortInput.getValue(),
newDefaultSortKeyData = {
'type': 'mwDefaultSort',
'attributes': { 'content': newDefaultSortKey }
};
// Place transactions made while dialog was open in a common history state
hasTransactions = surfaceModel.breakpoint();
var surfaceModel = this.surface.getModel(),
hasTransactions = surfaceModel.breakpoint();
// Undo everything done in the dialog and prevent redoing those changes
if ( data.action === 'cancel' && hasTransactions ) {
@ -444,28 +98,10 @@ ve.ui.MWMetaDialog.prototype.teardown = function ( data ) {
surfaceModel.truncateUndoStack();
}
// Alter the default sort key iff it's been touched & is actually different
if ( this.defaultSortKeyTouched ) {
if ( newDefaultSortKey === '' ) {
if ( currentDefaultSortKeyItem ) {
currentDefaultSortKeyItem.remove();
}
} else {
if ( !currentDefaultSortKeyItem ) {
this.metaList.insertMeta( newDefaultSortKeyData );
} else if ( currentDefaultSortKeyItem.getValue() !== newDefaultSortKey ) {
currentDefaultSortKeyItem.replaceWith(
ve.extendObject( true, {},
currentDefaultSortKeyItem.getElement(),
newDefaultSortKeyData
)
);
}
}
}
this.categoriesPage.teardown( data );
// Return to normal tracking behavior
surfaceModel.startHistoryTracking();
this.surface.getModel().startHistoryTracking();
// Parent method
ve.ui.MWDialog.prototype.teardown.call( this, data );

View file

@ -140,7 +140,7 @@ ve.ui.MWReferenceDialog.prototype.initialize = function () {
ve.ui.MWDialog.prototype.initialize.call( this );
// Properties
this.panels = new OO.ui.StackPanelLayout( { '$': this.$ } );
this.panels = new OO.ui.StackLayout( { '$': this.$ } );
this.editPanel = new OO.ui.PanelLayout( {
'$': this.$, 'scrollable': true, 'padded': true
} );
@ -187,14 +187,14 @@ ve.ui.MWReferenceDialog.prototype.initialize = function () {
this.backButton.$element.show();
this.insertButton.$element.hide();
this.selectButton.$element.hide();
this.panels.showItem( this.searchPanel );
this.panels.setItem( this.searchPanel );
this.search.getQuery().$input.focus().select();
} } );
this.backButton.connect( this, { 'click': function () {
this.backButton.$element.hide();
this.insertButton.$element.show();
this.selectButton.$element.show();
this.panels.showItem( this.editPanel );
this.panels.setItem( this.editPanel );
this.editPanel.$element.find( '.ve-ce-documentNode' ).focus();
} } );
this.search.connect( this, { 'select': 'onSearchSelect' } );
@ -234,7 +234,7 @@ ve.ui.MWReferenceDialog.prototype.setup = function ( data ) {
this.selectButton.$element.show();
}
this.backButton.$element.hide();
this.panels.showItem( this.editPanel );
this.panels.setItem( this.editPanel );
this.useReference( ref );
this.search.buildIndex();
this.selectButton.setDisabled( !this.search.getResults().getItems().length );

View file

@ -159,7 +159,7 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
}
// Show the target panel
this.panel.showItem( panelObj );
this.panel.setItem( panelObj );
mw.hook( 've.saveDialog.stateChanged' ).fire();
@ -344,7 +344,7 @@ ve.ui.MWSaveDialog.prototype.initialize = function () {
this.nochangesPanel.$element.append( this.$noChanges );
// Panel stack
this.panel = new OO.ui.StackPanelLayout( { '$': this.$, 'scrollable': true } );
this.panel = new OO.ui.StackLayout( { '$': this.$, 'scrollable': true } );
this.panel.$element.addClass( 've-ui-mwSaveDialog-panel' );
this.panel.addItems( [this.savePanel, this.reviewPanel, this.conflictPanel, this.nochangesPanel], 0 );

View file

@ -0,0 +1,56 @@
/*
* VisualEditor user interface MWTemplateDialog class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Dialog for editing MediaWiki templates.
*
* @class
* @extends ve.ui.MWTransclusionDialog
*
* @constructor
* @param {ve.ui.WindowSet} windowSet Window set this dialog is part of
* @param {Object} [config] Configuration options
*/
ve.ui.MWTemplateDialog = function VeUiMWTemplateDialog( windowSet, config ) {
// Parent constructor
ve.ui.MWTransclusionDialog.call( this, windowSet, config );
// Properties
this.node = null;
this.transclusion = null;
this.loaded = false;
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTemplateDialog, ve.ui.MWTransclusionDialog );
/* Static Properties */
ve.ui.MWTemplateDialog.static.name = 'transclusion';
ve.ui.MWTemplateDialog.static.titleMessage = 'visualeditor-dialog-transclusion-title';
ve.ui.MWTemplateDialog.static.icon = 'template';
/* Methods */
/**
* @inheritdoc
*/
ve.ui.MWTemplateDialog.prototype.getBookletLayout = function () {
return new OO.ui.BookletLayout( {
'$': this.$,
'continuous': true,
'autoFocus': true,
'outlined': true
} );
};
/* Registration */
ve.ui.dialogFactory.register( ve.ui.MWTemplateDialog );

View file

@ -1,4 +1,4 @@
/*!
/*
* VisualEditor user interface MWTransclusionDialog class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
@ -22,7 +22,7 @@ ve.ui.MWTransclusionDialog = function VeUiMWTransclusionDialog( windowSet, confi
// Properties
this.node = null;
this.transclusion = null;
this.pending = [];
this.loaded = false;
};
/* Inheritance */
@ -31,457 +31,105 @@ OO.inheritClass( ve.ui.MWTransclusionDialog, ve.ui.MWDialog );
/* Static Properties */
ve.ui.MWTransclusionDialog.static.name = 'transclusion';
ve.ui.MWTransclusionDialog.static.titleMessage = 'visualeditor-dialog-transclusion-title';
ve.ui.MWTransclusionDialog.static.icon = 'template';
/* Methods */
/**
* Handle add part events.
* Handle parts being replaced.
*
* @method
* @param {ve.dm.MWTransclusionPartModel} part Added part
* @param {ve.dm.MWTransclusionPartModel} removed Removed part
* @param {ve.dm.MWTransclusionPartModel} added Added part
*/
ve.ui.MWTransclusionDialog.prototype.onAddPart = function ( part ) {
var i, len, page, params, names, pending, item, spec;
ve.ui.MWTransclusionDialog.prototype.onReplacePart = function ( removed, added ) {
var i, len, page, name, names, params, selected,
removePages = [],
select = false;
if ( part instanceof ve.dm.MWTemplateModel ) {
page = this.getTemplatePage( part );
} else if ( part instanceof ve.dm.MWTransclusionContentModel ) {
page = this.getContentPage( part );
} else if ( part instanceof ve.dm.MWTemplatePlaceholderModel ) {
page = this.getPlaceholderPage( part );
}
if ( page ) {
page.index = this.getPageIndex( part );
this.pagedOutlineLayout.addPage( part.getId(), page );
// Add existing params to templates
if ( part instanceof ve.dm.MWTemplateModel ) {
names = part.getParameterNames();
params = part.getParameters();
for ( i = 0, len = names.length; i < len; i++ ) {
this.onAddParameter( params[names[i]] );
if ( removed ) {
// Remove parameter pages of removed templates
if ( removed instanceof ve.dm.MWTemplateModel ) {
params = removed.getParameters();
for ( name in params ) {
removePages.push( this.bookletLayout.getPage( params[name].getId() ) );
}
part.connect( this, { 'add': 'onAddParameter', 'remove': 'onRemoveParameter' } );
removed.disconnect( this );
}
}
// Add required params to user created templates
if ( part instanceof ve.dm.MWTemplateModel && part.getOrigin() === 'user' ) {
spec = part.getSpec();
names = spec.getParameterNames();
for ( i = 0, len = names.length; i < len; i++ ) {
// Only add required params
if ( spec.isParameterRequired( names[i] ) ) {
part.addParameter( new ve.dm.MWTemplateParameterModel( part, names[i] ) );
}
}
}
// Resolve pending placeholder
for ( i = 0, len = this.pending.length; i < len; i++ ) {
pending = this.pending[i];
if ( pending.part === part ) {
if ( this.outlined ) {
// Auto-select new part if placeholder is still selected
item = this.pagedOutlineLayout.getOutline().getSelectedItem();
if ( item.getData() === pending.placeholder.getId() ) {
this.setPageByName( part.getId() );
selected = this.bookletLayout.getOutline().getSelectedItem();
if ( selected && removed.getId() === selected.getData() ) {
select = true;
}
}
removePages.push( this.bookletLayout.getPage( removed.getId() ) );
this.bookletLayout.removePages( removePages );
}
if ( added ) {
if ( added instanceof ve.dm.MWTemplateModel ) {
page = new ve.ui.MWTemplatePage( added, added.getId(), { '$': this.$ } );
} else if ( added instanceof ve.dm.MWTransclusionContentModel ) {
page = new ve.ui.MWTransclusionContentPage( added, added.getId(), { '$': this.$ } );
} else if ( added instanceof ve.dm.MWTemplatePlaceholderModel ) {
page = new ve.ui.MWTemplatePlaceholderPage( added, added.getId(), { '$': this.$ } );
}
if ( page ) {
this.bookletLayout.addPages( [ page ], this.transclusion.getIndex( added ) );
if ( select && this.loaded ) {
this.setPageByName( added.getId() );
}
// Add existing params to templates (the template might be being moved)
if ( added instanceof ve.dm.MWTemplateModel ) {
names = added.getParameterNames();
params = added.getParameters();
for ( i = 0, len = names.length; i < len; i++ ) {
this.onAddParameter( params[names[i]] );
}
added.connect( this, { 'add': 'onAddParameter', 'remove': 'onRemoveParameter' } );
}
// Add required params to user created templates
if ( added instanceof ve.dm.MWTemplateModel && this.loaded ) {
added.addRequiredParameters();
}
// Cleanup
pending.placeholder.remove();
this.pending.splice( i, 1 );
break;
}
}
};
/**
* Handle remove part events.
*
* @method
* @param {ve.dm.MWTransclusionPartModel} part Removed part
*/
ve.ui.MWTransclusionDialog.prototype.onRemovePart = function ( part ) {
var name, params;
if ( part instanceof ve.dm.MWTemplateModel ) {
params = part.getParameters();
for ( name in params ) {
this.pagedOutlineLayout.removePage( params[name].getId() );
}
part.disconnect( this );
}
this.pagedOutlineLayout.removePage( part.getId() );
};
/**
* Handle add param events.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} param Added param
*/
ve.ui.MWTransclusionDialog.prototype.onAddParameter = function ( param ) {
var page = this.getParameterPage( param );
page.index = this.getPageIndex( param );
this.pagedOutlineLayout.addPage( param.getId(), page );
var page = new ve.ui.MWTemplateParameterPage( param, param.getId(), { '$': this.$ } );
this.bookletLayout.addPages( [ page ], this.transclusion.getIndex( param ) );
if ( this.loaded ) {
this.setPageByName( param.getId() );
}
};
/**
* Handle remove param events.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} param Removed param
*/
ve.ui.MWTransclusionDialog.prototype.onRemoveParameter = function ( param ) {
this.pagedOutlineLayout.removePage( param.getId() );
// Return to template page
this.setPageByName( param.getTemplate().getId() );
};
/**
* Handle outline controls move events.
*
* @method
* @param {number} places Number of places to move the selected item
*/
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsMove = function ( places ) {
var part, index, name,
parts = this.transclusion.getParts(),
item = this.pagedOutlineLayout.getOutline().getSelectedItem();
if ( item ) {
name = item.getData();
part = this.transclusion.getPartFromId( name );
index = ve.indexOf( part, parts );
// Auto-removes part from old location
this.transclusion.addPart( part, index + places )
.done( ve.bind( this.setPageByName, this, part.getId() ) );
this.bookletLayout.removePages( [ this.bookletLayout.getPage( param.getId() ) ] );
if ( this.loaded ) {
// Return to template page
this.setPageByName( param.getTemplate().getId() );
}
};
/**
* Handle outline controls add events.
* Get an outlined booklet layout widget.
*
* @method
* @param {string} type Type of item to add
* @return {OO.ui.BookletLayout} Configured widget
*/
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsAdd = function ( type ) {
var part;
if ( type === 'content' ) {
part = new ve.dm.MWTransclusionContentModel( this.transclusion, '', 'user' );
} else if ( type === 'template' ) {
part = new ve.dm.MWTemplatePlaceholderModel( this.transclusion, 'user' );
}
if ( part ) {
this.transclusion.addPart( part, this.getPartInsertionIndex() )
.done( ve.bind( this.setPageByName, this, part.getId() ) );
}
};
/**
* Get an index for part insertion.
*
* @method
* @returns {number} Index to insert new parts at
*/
ve.ui.MWTransclusionDialog.prototype.getPartInsertionIndex = function () {
var parts = this.transclusion.getParts(),
item = this.pagedOutlineLayout.getOutline().getSelectedItem();
if ( item ) {
return ve.indexOf( this.transclusion.getPartFromId( item.getData() ), parts ) + 1;
}
return parts.length;
};
/**
* Get the page index of an item.
*
* @method
* @param {ve.dm.MWTransclusionPartModel|ve.dm.MWTemplateParameterModel} item Part or parameter
* @returns {number} Page index of item
*/
ve.ui.MWTransclusionDialog.prototype.getPageIndex = function ( item ) {
// Build pages from parts
var i, iLen, j, jLen, part, names,
parts = this.transclusion.getParts(),
index = 0;
// Populate pages
for ( i = 0, iLen = parts.length; i < iLen; i++ ) {
part = parts[i];
if ( part === item ) {
return index;
}
index++;
if ( part instanceof ve.dm.MWTemplateModel ) {
names = part.getParameterNames();
for ( j = 0, jLen = names.length; j < jLen; j++ ) {
if ( part.getParameter( names[j] ) === item ) {
return index;
}
index++;
}
}
}
return -1;
};
/**
* Get page for transclusion content.
*
* @method
* @param {ve.dm.MWTransclusionContentModel} content Content model
*/
ve.ui.MWTransclusionDialog.prototype.getContentPage = function ( content ) {
var valueFieldset, textInput, optionsFieldset, removeButton;
valueFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-content' ),
'icon': 'source'
} );
textInput = new OO.ui.TextInputWidget( { '$': this.$, 'multiline': true } );
textInput.setValue( content.getValue() );
textInput.connect( this, { 'change': function () {
content.setValue( textInput.getValue() );
} } );
textInput.$element.addClass( 've-ui-mwTransclusionDialog-input' );
valueFieldset.$element.append( textInput.$element );
optionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-options' ),
'icon': 'settings'
} );
removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-content' ),
'flags': ['destructive']
} );
removeButton.connect( this, { 'click': function () {
content.remove();
} } );
optionsFieldset.$element.append( removeButton.$element );
return {
'label': ve.msg( 'visualeditor-dialog-transclusion-content' ),
'icon': 'source',
'$content': valueFieldset.$element.add( optionsFieldset.$element ),
'moveable': true
};
};
/**
* Get page for a template.
*
* @method
* @param {ve.dm.MWTemplateModel} template Template model
*/
ve.ui.MWTransclusionDialog.prototype.getTemplatePage = function ( template ) {
var infoFieldset, addParameterFieldset, addParameterSearch, optionsFieldset,
removeButton,
spec = template.getSpec(),
label = spec.getLabel(),
description = spec.getDescription();
function addParameter( name ) {
var param;
if ( name ) {
param = new ve.dm.MWTemplateParameterModel( template, name );
template.addParameter( param );
addParameterSearch.query.setValue();
this.setPageByName( param.getId() );
}
}
infoFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': label,
'icon': 'template'
} );
if ( description ) {
infoFieldset.$element.append( this.$( '<div>' ).text( description ) );
}
addParameterFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-add-param' ),
'icon': 'parameter'
} );
addParameterFieldset.$element.addClass( 've-ui-mwTransclusionDialog-addParameterFieldset' );
addParameterSearch = new ve.ui.MWParameterSearchWidget( template, { '$': this.$ } );
addParameterSearch.connect( this, { 'select': addParameter } );
addParameterFieldset.$element.append( addParameterSearch.$element );
optionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-options' ),
'icon': 'settings'
} );
removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-template' ),
'flags': ['destructive']
} );
removeButton.connect( this, { 'click': function () {
template.remove();
} } );
optionsFieldset.$element.append( removeButton.$element );
return {
'label': label,
'icon': 'template',
'$content': infoFieldset.$element.add( addParameterFieldset.$element ).add( optionsFieldset.$element ),
'moveable': true
};
};
/**
* Get page for a parameter.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} parameter Parameter model
*/
ve.ui.MWTransclusionDialog.prototype.getParameterPage = function ( parameter ) {
var valueFieldset, optionsFieldset, textInput, inputLabel, removeButton,
spec = parameter.getTemplate().getSpec(),
name = parameter.getName(),
label = spec.getParameterLabel( name ),
description = spec.getParameterDescription( name );
valueFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': label,
'icon': 'parameter'
} );
if ( description ) {
inputLabel = new OO.ui.InputLabelWidget( {
'$': this.$,
'input': textInput,
'label': description
} );
valueFieldset.$element.append( inputLabel.$element );
}
textInput = new OO.ui.TextInputWidget( { '$': this.$, 'multiline': true } );
textInput.setValue( parameter.getValue() );
textInput.connect( this, { 'change': function () {
parameter.setValue( textInput.getValue() );
} } );
textInput.$element.addClass( 've-ui-mwTransclusionDialog-input' );
valueFieldset.$element.append( textInput.$element );
optionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-options' ),
'icon': 'settings'
} );
removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-param' ),
'flags': ['destructive']
} );
removeButton.connect( this, { 'click': function () {
parameter.remove();
} } );
optionsFieldset.$element.append( removeButton.$element );
// TODO: Use spec.required
// TODO: Use spec.deprecation
// TODO: Use spec.default
// TODO: Use spec.type
return {
'label': label,
'icon': 'parameter',
'level': 1,
'$content': valueFieldset.$element.add( optionsFieldset.$element )
};
};
/**
* Get page for a parameter.
*
* @method
* @param {ve.dm.MWTemplateParameterModel} parameter Parameter model
*/
ve.ui.MWTransclusionDialog.prototype.getPlaceholderPage = function ( placeholder ) {
var addTemplateFieldset, addTemplateInput, addTemplateButton, optionsFieldset, removeButton,
label = ve.msg( 'visualeditor-dialog-transclusion-placeholder' );
function addTemplate() {
var parts = placeholder.getTransclusion().getParts(),
part = ve.dm.MWTemplateModel.newFromName(
this.transclusion, addTemplateInput.getValue()
);
this.transclusion.addPart( part, ve.indexOf( placeholder, parts ) );
this.pending.push( { 'part': part, 'placeholder': placeholder } );
addTemplateInput.pushPending();
addTemplateButton.setDisabled( true );
removeButton.setDisabled( true );
}
addTemplateFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': label,
'icon': 'template'
} );
addTemplateFieldset.$element.addClass( 've-ui-mwTransclusionDialog-addTemplateFieldset' );
addTemplateInput = new ve.ui.MWTitleInputWidget( {
'$': this.$, '$overlay': this.$overlay, 'namespace': 10
} );
addTemplateButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-add-template' ),
'flags': ['constructive'],
'disabled': true
} );
addTemplateInput.connect( this, {
'change': function () {
addTemplateButton.setDisabled( addTemplateInput.getValue() === '' );
},
'enter': addTemplate
} );
addTemplateButton.connect( this, { 'click': addTemplate } );
addTemplateFieldset.$element.append( addTemplateInput.$element, addTemplateButton.$element );
optionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-options' ),
'icon': 'settings'
} );
removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-template' ),
'flags': ['destructive']
} );
removeButton.connect( this, { 'click': function () {
placeholder.remove();
} } );
optionsFieldset.$element.append( removeButton.$element );
return {
'label': this.$( '<span>' )
.addClass( 've-ui-mwTransclusionDialog-placeholder-label' )
.text( label ),
'icon': 'template',
'$content': addTemplateFieldset.$element.add( optionsFieldset.$element )
};
ve.ui.MWTransclusionDialog.prototype.getBookletLayout = function () {
return new OO.ui.BookletLayout( { '$': this.$, 'continuous': true } );
};
/**
@ -489,13 +137,16 @@ ve.ui.MWTransclusionDialog.prototype.getPlaceholderPage = function ( placeholder
*
* Page names are always the ID of the part or param they represent.
*
* @method
* @param {string} name Page name
*/
ve.ui.MWTransclusionDialog.prototype.setPageByName = function ( name ) {
this.pagedOutlineLayout.getOutline().selectItem(
this.pagedOutlineLayout.getOutline().getItemFromData( name )
);
if ( this.outlined ) {
this.bookletLayout.getOutline().selectItem(
this.bookletLayout.getOutline().getItemFromData( name )
);
} else {
this.bookletLayout.setPage( name );
}
};
/**
@ -507,34 +158,17 @@ ve.ui.MWTransclusionDialog.prototype.initialize = function () {
// Properties
this.applyButton = new OO.ui.PushButtonWidget( {
'$': this.$, 'label': ve.msg( 'visualeditor-dialog-action-apply' ), 'flags': ['primary']
} );
this.pagedOutlineLayout = new OO.ui.PagedOutlineLayout( {
'$': this.$,
'editable': true,
'adders': [
{
'name': 'template',
'icon': 'template',
'title': ve.msg( 'visualeditor-dialog-transclusion-add-template' )
},
{
'name': 'content',
'icon': 'source',
'title': ve.msg( 'visualeditor-dialog-transclusion-add-content' )
}
]
'label': ve.msg( 'visualeditor-dialog-action-apply' ),
'flags': ['primary']
} );
this.bookletLayout = this.getBookletLayout();
// Events
this.pagedOutlineLayout.getOutlineControls().connect( this, {
'move': 'onOutlineControlsMove',
'add': 'onOutlineControlsAdd'
} );
this.applyButton.connect( this, { 'click': [ 'close', { 'action': 'apply' } ] } );
// Initialization
this.$body.append( this.pagedOutlineLayout.$element );
this.$body.append( this.bookletLayout.$element );
this.$foot.append( this.applyButton.$element );
};
@ -550,17 +184,21 @@ ve.ui.MWTransclusionDialog.prototype.setup = function ( data ) {
// Properties
this.transclusion = new ve.dm.MWTransclusionModel();
this.loaded = false;
// Events
this.transclusion.connect( this, { 'add': 'onAddPart', 'remove': 'onRemovePart' } );
this.transclusion.connect( this, { 'replace': 'onReplacePart' } );
// Initialization
if ( this.node instanceof ve.ce.MWTransclusionNode ) {
this.transclusion.load( ve.copy( this.node.getModel().getAttribute( 'mw' ) ) );
this.transclusion
.load( ve.copy( this.node.getModel().getAttribute( 'mw' ) ) )
.always( ve.bind( function () {
this.loaded = true;
}, this ) );
} else {
this.transclusion.addPart(
new ve.dm.MWTemplatePlaceholderModel( this.transclusion, 'user' )
);
this.loaded = true;
this.transclusion.addPart( new ve.dm.MWTemplatePlaceholderModel( this.transclusion ) );
}
};
@ -598,7 +236,7 @@ ve.ui.MWTransclusionDialog.prototype.teardown = function ( data ) {
this.transclusion.disconnect( this );
this.transclusion.abortRequests();
this.transclusion = null;
this.pagedOutlineLayout.clearPages();
this.bookletLayout.clearPages();
this.node = null;
this.content = null;
@ -606,6 +244,3 @@ ve.ui.MWTransclusionDialog.prototype.teardown = function ( data ) {
ve.ui.MWDialog.prototype.teardown.call( this, data );
};
/* Registration */
ve.ui.dialogFactory.register( ve.ui.MWTransclusionDialog );

View file

@ -0,0 +1,264 @@
/*!
* VisualEditor user interface MWCategoriesPage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw*/
/**
* MediaWiki meta dialog categories page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.ui.Surface} surface Surface being worked on
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
* @cfg {jQuery} [$overlay] Overlay to render category settings popups in
*/
ve.ui.MWCategoriesPage = function VeUiMWCategoriesPage( surface, name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'tag' } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.surface = surface;
this.metaList = this.surface.getModel().metaList;
this.defaultSortKeyTouched = false;
this.fallbackDefaultSortKey = mw.config.get( 'wgTitle' );
this.label = ve.msg( 'visualeditor-dialog-meta-categories-section' );
this.categoriesFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-categories-data-label' ),
'icon': 'tag'
} );
this.categoryOptionsFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-categories-options' ),
'icon': 'settings'
} );
this.categoryWidget = new ve.ui.MWCategoryWidget( {
'$': this.$, '$overlay': config.$overlay
} );
this.defaultSortInput = new OO.ui.TextInputWidget( {
'$': this.$, 'placeholder': this.fallbackDefaultSortKey
} );
this.defaultSortLabel = new OO.ui.InputLabelWidget( {
'$': this.$,
'input': this.defaultSortInput,
'label': ve.msg( 'visualeditor-dialog-meta-categories-defaultsort-label' )
} );
// Events
this.metaList.connect( this, {
'insert': 'onMetaListInsert',
'remove': 'onMetaListRemove'
} );
this.categoryWidget.connect( this, {
'newCategory': 'onNewCategory',
'updateSortkey': 'onUpdateSortKey'
} );
this.defaultSortInput.connect( this, {
'change': 'onDefaultSortChange'
} );
// Initialization
this.categoryWidget.addItems( this.getCategoryItems() );
this.categoriesFieldset.$element.append( this.categoryWidget.$element );
this.categoryOptionsFieldset.$element.append(
this.defaultSortLabel.$element,
this.defaultSortInput.$element
);
this.$element.append( this.categoriesFieldset.$element, this.categoryOptionsFieldset.$element );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWCategoriesPage, OO.ui.PageLayout );
/* Methods */
/**
* Handle category default sort change events.
*
* @param {string} value Default sort value
*/
ve.ui.MWCategoriesPage.prototype.onDefaultSortChange = function ( value ) {
this.categoryWidget.setDefaultSortKey( value === '' ? this.fallbackDefaultSortKey : value );
this.defaultSortKeyTouched = true;
};
/**
* Inserts new category into meta list
*
* @param {Object} item
*/
ve.ui.MWCategoriesPage.prototype.onNewCategory = function ( item ) {
// Insert new metaList item
this.insertMetaListItem( this.getCategoryItemForInsertion( item ) );
};
/**
* Removes and re-inserts updated category widget item
*
* @param {Object} item
*/
ve.ui.MWCategoriesPage.prototype.onUpdateSortKey = function ( item ) {
// Replace meta item with updated one
item.metaItem.replaceWith( this.getCategoryItemForInsertion( item, item.metaItem.getElement() ) );
};
/**
* Bound to MetaList insert event for adding meta dialog components.
*
* @param {Object} ve.dm.MetaItem
*/
ve.ui.MWCategoriesPage.prototype.onMetaListInsert = function ( metaItem ) {
// Responsible for adding UI components
if ( metaItem.element.type === 'mwCategory' ) {
this.categoryWidget.addItems(
[ this.getCategoryItemFromMetaListItem( metaItem ) ],
this.metaList.findItem( metaItem.getOffset(), metaItem.getIndex(), 'mwCategory' )
);
}
};
/**
* Bound to MetaList insert event for removing meta dialog components.
*
* @param {Object} ve.dm.MetaItem
*/
ve.ui.MWCategoriesPage.prototype.onMetaListRemove = function ( metaItem ) {
var item;
if ( metaItem.element.type === 'mwCategory' ) {
item = this.getCategoryItemFromMetaListItem( metaItem );
this.categoryWidget.removeItems( [item.value] );
}
};
/**
* Get default sort key item.
*
* @returns {string} Default sort key item
*/
ve.ui.MWCategoriesPage.prototype.getDefaultSortKeyItem = function () {
var items = this.metaList.getItemsInGroup( 'mwDefaultSort' );
return items.length ? items[0] : null;
};
/**
* Get array of category items from meta list
*
* @returns {Object[]} items
*/
ve.ui.MWCategoriesPage.prototype.getCategoryItems = function () {
var i,
items = [],
categories = this.metaList.getItemsInGroup( 'mwCategory' );
// Loop through MwCategories and build out items
for ( i = 0; i < categories.length; i++ ) {
items.push( this.getCategoryItemFromMetaListItem( categories[i] ) );
}
return items;
};
/**
* Gets category item from meta list item
*
* @param {Object} ve.dm.MWCategoryMetaItem
* @returns {Object} item
*/
ve.ui.MWCategoriesPage.prototype.getCategoryItemFromMetaListItem = function ( metaItem ) {
var title = mw.Title.newFromText( metaItem.element.attributes.category ),
value = title ? title.getMainText() : '';
return {
'name': metaItem.element.attributes.category,
'value': value,
// TODO: sortkey is lcase, make consistent throughout CategoryWidget
'sortKey': metaItem.element.attributes.sortkey,
'metaItem': metaItem
};
};
/**
* Get metaList like object to insert from item
*
* @param {Object} item category widget item
* @param {Object} [oldData] Metadata object that was previously associated with this item, if any
* @returns {Object} metaBase
*/
ve.ui.MWCategoriesPage.prototype.getCategoryItemForInsertion = function ( item, oldData ) {
var newData = {
'attributes': { 'category': item.name, 'sortkey': item.sortKey || '' },
'type': 'mwCategory'
};
if ( oldData ) {
return ve.extendObject( {}, oldData, newData );
}
return newData;
};
/**
* Inserts a meta list item
*
* @param {Object} metaBase meta list insert object
*/
ve.ui.MWCategoriesPage.prototype.insertMetaListItem = function ( metaBase ) {
this.metaList.insertMeta( metaBase );
};
/**
* Set up the page. This is called when the MWMetaDialog is set up.
*/
ve.ui.MWCategoriesPage.prototype.setup = function () {
var defaultSortKeyItem = this.getDefaultSortKeyItem();
this.defaultSortInput.setValue(
defaultSortKeyItem ? defaultSortKeyItem.getAttribute( 'content' ) : ''
);
this.defaultSortKeyTouched = false;
// Update input position once visible
setTimeout( ve.bind( function () {
this.categoryWidget.fitInput();
}, this ) );
};
/**
* Tear down the page. This is called when the MWMetaDialog is torn down.
*/
ve.ui.MWCategoriesPage.prototype.teardown = function () {
var currentDefaultSortKeyItem = this.getDefaultSortKeyItem(),
newDefaultSortKey = this.defaultSortInput.getValue(),
newDefaultSortKeyData = {
'type': 'mwDefaultSort',
'attributes': { 'content': newDefaultSortKey }
};
// Alter the default sort key iff it's been touched & is actually different
if ( this.defaultSortKeyTouched ) {
if ( newDefaultSortKey === '' ) {
if ( currentDefaultSortKeyItem ) {
currentDefaultSortKeyItem.remove();
}
} else {
if ( !currentDefaultSortKeyItem ) {
this.metaList.insertMeta( newDefaultSortKeyData );
} else if ( currentDefaultSortKeyItem.getAttribute( 'content' ) !== newDefaultSortKey ) {
currentDefaultSortKeyItem.replaceWith(
ve.extendObject( true, {},
currentDefaultSortKeyItem.getElement(),
newDefaultSortKeyData
) );
}
}
}
};

View file

@ -0,0 +1,173 @@
/*!
* VisualEditor user interface MWLanguagesPage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/*global mw*/
/**
* MediaWiki meta dialog Languages page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
*/
ve.ui.MWLanguagesPage = function VeUiMWLanguagesPage( name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'language' } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.label = ve.msg( 'visualeditor-dialog-meta-languages-section' );
this.languagesFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-meta-languages-label' ),
'icon': 'language'
} );
// Initialization
this.languagesFieldset.$element.append(
this.$( '<span>' )
.text( ve.msg( 'visualeditor-dialog-meta-languages-readonlynote' ) )
);
this.$element.append( this.languagesFieldset.$element );
this.getAllLanguageItems().done( ve.bind( this.onLoadLanguageData, this ) );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWLanguagesPage, OO.ui.PageLayout );
/* Methods */
ve.ui.MWLanguagesPage.prototype.onLoadLanguageData = function ( languages ) {
var i, $languagesTable = this.$( '<table>' ), languageslength = languages.length;
$languagesTable
.addClass( 've-ui-MWLanguagesPage-languages-table' )
.append( this.$( '<tr>' )
.append(
this.$( '<th>' )
.append( ve.msg( 'visualeditor-dialog-meta-languages-code-label' ) )
)
.append(
this.$( '<th>' )
.append( ve.msg( 'visualeditor-dialog-meta-languages-link-label' ) )
)
);
for ( i = 0; i < languageslength; i++ ) {
languages[i].safelang = languages[i].lang;
languages[i].dir = 'auto';
if ( $.uls ) {
// site codes don't always represent official language codes
// using real language code instead of a dummy ('redirect' in ULS' terminology)
languages[i].safelang = $.uls.data.isRedirect( languages[i].lang ) || languages[i].lang;
languages[i].dir = $.uls.data.getDir( languages[i].safelang );
}
$languagesTable
.append( this.$( '<tr>' )
.append( this.$( '<td>' ).append( languages[i].lang ) )
.append( this.$( '<td>' ).append( languages[i].title )
.attr( 'lang', languages[i].safelang )
.attr( 'dir', languages[i].dir ) )
);
}
this.languagesFieldset.$element.append( $languagesTable );
};
/**
* Handle language items being loaded.
*/
ve.ui.MWLanguagesPage.prototype.onAllLanuageItemsSuccess = function ( deferred, response ) {
var i, iLen, languages = [], langlinks = response.query.pages[response.query.pageids[0]].langlinks;
if ( langlinks ) {
for ( i = 0, iLen = langlinks.length; i < iLen; i++ ) {
languages.push( {
'lang': langlinks[i].lang,
'title': langlinks[i]['*'],
'metaItem': null
} );
}
}
deferred.resolve( languages );
};
/**
* Gets language item from meta list item
*
* @param {Object} ve.dm.MWLanguageMetaItem
* @returns {Object} item
*/
ve.ui.MWLanguagesPage.prototype.getLanguageItemFromMetaListItem = function ( metaItem ) {
// TODO: get real values from metaItem once Parsoid actually provides them - bug 48970
return {
'lang': 'lang',
'title': 'title',
'metaItem': metaItem
};
};
/**
* Get array of language items from meta list
*
* @returns {Object[]} items
*/
ve.ui.MWLanguagesPage.prototype.getLocalLanguageItems = function () {
var i,
items = [],
languages = this.metaList.getItemsInGroup( 'mwLanguage' ),
languageslength = languages.length;
// Loop through MWLanguages and build out items
for ( i = 0; i < languageslength; i++ ) {
items.push( this.getLanguageItemFromMetaListItem( languages[i] ) );
}
return items;
};
/**
* Get array of language items from meta list
*
* @returns {jQuery.Promise}
*/
ve.ui.MWLanguagesPage.prototype.getAllLanguageItems = function () {
var deferred = $.Deferred();
// TODO: Detect paging token if results exceed limit
$.ajax( {
'url': mw.util.wikiScript( 'api' ),
'data': {
'action': 'query',
'prop': 'langlinks',
'lllimit': 500,
'titles': mw.config.get( 'wgTitle' ),
'indexpageids': 1,
'format': 'json'
},
'dataType': 'json',
'type': 'POST',
// Wait up to 100 seconds before giving up
'timeout': 100000,
'cache': 'false'
} )
.done( ve.bind( this.onAllLanuageItemsSuccess, this, deferred ) )
.fail( ve.bind( this.onAllLanuageItemsError, this, deferred ) );
return deferred.promise();
};
/**
* Handle language items failing to be loaded.
*
* TODO: This error function should probably not be empty.
*/
ve.ui.MWLanguagesPage.prototype.onAllLanuageItemsError = function () {};

View file

@ -0,0 +1,79 @@
/*!
* VisualEditor user interface MWTemplatePage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* MediaWiki transclusion dialog template page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.dm.MWTemplateModel} parameter Template
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
*/
ve.ui.MWTemplatePage = function VeUiMWTemplatePage( template, name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'template', 'moveable': true, 'level': 0 } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.template = template;
this.spec = this.template.getSpec();
this.label = this.spec.getLabel();
this.addParameterSearch = new ve.ui.MWParameterSearchWidget( this.template, { '$': this.$ } )
.connect( this, { 'select': 'onParameterSelect' } );
this.removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-template' ),
'flags': ['destructive'],
'classes': [ 've-ui-mwTransclusionDialog-removeButton' ]
} )
.connect( this, { 'click': 'onRemoveButtonClick' } );
this.infoFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': this.spec.getLabel(),
'icon': 'template',
'$content': this.$( '<div>' ).text( this.template.getSpec().getDescription() || '' )
} );
this.addParameterFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-add-param' ),
'icon': 'parameter',
'classes': [ 've-ui-mwTransclusionDialog-addParameterFieldset' ],
'$content': this.addParameterSearch.$element
} );
// Initialization
this.$element.append(
this.infoFieldset.$element,
this.addParameterFieldset.$element,
this.removeButton.$element
);
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTemplatePage, OO.ui.PageLayout );
/* Methods */
ve.ui.MWTemplatePage.prototype.onParameterSelect = function ( name ) {
var param;
if ( name ) {
param = new ve.dm.MWTemplateParameterModel( this.template, name );
this.template.addParameter( param );
this.addParameterSearch.query.setValue();
}
};
ve.ui.MWTemplatePage.prototype.onRemoveButtonClick = function () {
this.template.remove();
};

View file

@ -0,0 +1,77 @@
/*!
* VisualEditor user interface MWTemplateParameterPage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* MediaWiki transclusion dialog template page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.dm.MWTemplateParameterModel} parameter Template parameter
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
*/
ve.ui.MWTemplateParameterPage = function VeUiMWTemplateParameter( parameter, name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'parameter', 'moveable': false, 'level': 1 } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.parameter = parameter;
this.spec = parameter.getTemplate().getSpec();
this.label = this.spec.getParameterLabel( this.parameter.getName() );
this.textInput = new OO.ui.TextInputWidget( {
'$': this.$,
'multiline': true,
'classes': [ 've-ui-mwTransclusionDialog-input' ]
} )
.setValue( this.parameter.getValue() )
.connect( this, { 'change': 'onTextInputChange' } );
this.inputLabel = new OO.ui.InputLabelWidget( {
'$': this.$,
'input': this.textInput,
'label': this.spec.getParameterDescription( this.parameter.getName() ) || ''
} );
this.removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-param' ),
'flags': ['destructive'],
'classes': [ 've-ui-mwTransclusionDialog-removeButton' ]
} )
.connect( this, { 'click': 'onRemoveButtonClick' } );
this.valueFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': this.spec.getParameterLabel( this.parameter.getName() ),
'icon': 'parameter',
'$content': this.inputLabel.$element.add( this.textInput.$element )
} );
// TODO: Use spec.required
// TODO: Use spec.deprecation
// TODO: Use spec.default
// TODO: Use spec.type
// Initialization
this.$element.append( this.valueFieldset.$element, this.removeButton.$element );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTemplateParameterPage, OO.ui.PageLayout );
/* Methods */
ve.ui.MWTemplateParameterPage.prototype.onTextInputChange = function () {
this.parameter.setValue( this.textInput.getValue() );
};
ve.ui.MWTemplateParameterPage.prototype.onRemoveButtonClick = function () {
this.parameter.remove();
};

View file

@ -0,0 +1,87 @@
/*!
* VisualEditor user interface MWTemplatePlaceholderPage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* MediaWiki transclusion dialog placeholder page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.dm.MWTemplatePlaceholderModel} placeholder Template placeholder
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
*/
ve.ui.MWTemplatePlaceholderPage = function VeUiMWTemplatePlaceholder( placeholder, name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'template', 'moveable': true, 'level': 0 } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.placeholder = placeholder;
this.label = this.$( '<span>' )
.addClass( 've-ui-mwTransclusionDialog-placeholder-label' )
.text( ve.msg( 'visualeditor-dialog-transclusion-placeholder' ) );
this.addTemplateInput = new ve.ui.MWTitleInputWidget( {
'$': this.$, '$overlay': this.$overlay, 'namespace': 10
} )
.connect( this, {
'change': 'onTemplateInputChange',
'enter': 'onAddTemplate'
} );
this.addTemplateButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-add-template' ),
'flags': ['constructive'],
'disabled': true
} )
.connect( this, { 'click': 'onAddTemplate' } );
this.removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-template' ),
'flags': ['destructive'],
'classes': [ 've-ui-mwTransclusionDialog-removeButton' ]
} )
.connect( this, { 'click': 'onRemoveButtonClick' } );
this.addTemplateFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-placeholder' ),
'icon': 'template',
'classes': [ 've-ui-mwTransclusionDialog-addTemplateFieldset' ],
'$content': this.addTemplateInput.$element.add( this.addTemplateButton.$element )
} );
// Initialization
this.$element.append( this.addTemplateFieldset.$element, this.removeButton.$element );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTemplatePlaceholderPage, OO.ui.PageLayout );
/* Methods */
ve.ui.MWTemplatePlaceholderPage.prototype.onAddTemplate = function () {
var transclusion = this.placeholder.getTransclusion(),
parts = this.placeholder.getTransclusion().getParts(),
part = ve.dm.MWTemplateModel.newFromName( transclusion, this.addTemplateInput.getValue() );
transclusion.replacePart( this.placeholder, part, ve.indexOf( this.placeholder, parts ) );
this.addTemplateInput.pushPending();
this.addTemplateButton.setDisabled( true );
this.removeButton.setDisabled( true );
};
ve.ui.MWTemplatePlaceholderPage.prototype.onTemplateInputChange = function ( value ) {
this.addTemplateButton.setDisabled( value === '' );
};
ve.ui.MWTemplatePlaceholderPage.prototype.onRemoveButtonClick = function () {
this.placeholder.remove();
};

View file

@ -0,0 +1,67 @@
/*!
* VisualEditor user interface MWTransclusionContentPage class.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* MediaWiki transclusion dialog content page.
*
* @class
* @extends OO.ui.PageLayout
*
* @constructor
* @param {ve.dm.MWTransclusionContentModel} content Transclusion content
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
*/
ve.ui.MWTransclusionContentPage = function VeUiMWTransclusionContent( content, name, config ) {
// Configuration initialization
config = ve.extendObject( config, { 'icon': 'source', 'moveable': true, 'level': 0 } );
// Parent constructor
OO.ui.PageLayout.call( this, name, config );
// Properties
this.content = content;
this.label = ve.msg( 'visualeditor-dialog-transclusion-content' );
this.textInput = new OO.ui.TextInputWidget( {
'$': this.$,
'multiline': true,
'classes': [ 've-ui-mwTransclusionDialog-input' ]
} )
.setValue( this.content.getValue() )
.connect( this, { 'change': 'onTextInputChange' } );
this.removeButton = new OO.ui.PushButtonWidget( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-remove-content' ),
'flags': [ 'destructive' ],
'classes': [ 've-ui-mwTransclusionDialog-removeButton' ]
} )
.connect( this, { 'click': 'onRemoveButtonClick' } );
this.valueFieldset = new OO.ui.FieldsetLayout( {
'$': this.$,
'label': ve.msg( 'visualeditor-dialog-transclusion-content' ),
'icon': 'source',
'$content': this.textInput.$element
} );
// Initialization
this.$element.append( this.valueFieldset.$element, this.removeButton.$element );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTransclusionContentPage, OO.ui.PageLayout );
/* Methods */
ve.ui.MWTransclusionContentPage.prototype.onTextInputChange = function () {
this.content.setValue( this.textInput.getValue() );
};
ve.ui.MWTransclusionContentPage.prototype.onRemoveButtonClick = function () {
this.content.remove();
};

View file

@ -27,6 +27,16 @@
font-style: italic;
}
.oo-ui-fieldsetLayout + .ve-ui-mwTransclusionDialog-addParameterFieldset {
margin-top: 0;
}
.ve-ui-mwTransclusionDialog-addParameterFieldset > legend.oo-ui-labeledElement-label {
font-size: 1.25em;
padding-left: 2em;
line-height: 2em;
}
.ve-ui-mwTransclusionDialog-addParameterFieldset .ve-ui-mwParameterSearchWidget {
position: relative;
overflow: hidden;
@ -39,6 +49,12 @@
padding-bottom: 5em;
}
.ve-ui-mwTransclusionDialog-removeButton {
position: absolute;
right: 1.5em;
top: 1em;
}
/* ve.ui.MWMetaDialog */
.ve-ui-mwMetaDialog-languages-table {