mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-24 10:48:42 +00:00
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:
commit
674236cab4
|
@ -134,6 +134,10 @@
|
|||
{
|
||||
"name": "Dialogs",
|
||||
"classes": ["ve.ui.*Dialog"]
|
||||
},
|
||||
{
|
||||
"name": "Pages",
|
||||
"classes": ["ve.ui.*Page"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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
|
@ -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 {
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}() );
|
||||
|
|
131
modules/ve-mw/ui/dialogs/ve.ui.MWAdvancedTransclusionDialog.js
Normal file
131
modules/ve-mw/ui/dialogs/ve.ui.MWAdvancedTransclusionDialog.js
Normal 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 );
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
56
modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js
Normal file
56
modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js
Normal 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 );
|
|
@ -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 );
|
||||
|
|
264
modules/ve-mw/ui/pages/ve.ui.MWCategoriesPage.js
Normal file
264
modules/ve-mw/ui/pages/ve.ui.MWCategoriesPage.js
Normal 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
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
173
modules/ve-mw/ui/pages/ve.ui.MWLanguagesPage.js
Normal file
173
modules/ve-mw/ui/pages/ve.ui.MWLanguagesPage.js
Normal 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 () {};
|
79
modules/ve-mw/ui/pages/ve.ui.MWTemplatePage.js
Normal file
79
modules/ve-mw/ui/pages/ve.ui.MWTemplatePage.js
Normal 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();
|
||||
};
|
77
modules/ve-mw/ui/pages/ve.ui.MWTemplateParameterPage.js
Normal file
77
modules/ve-mw/ui/pages/ve.ui.MWTemplateParameterPage.js
Normal 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();
|
||||
};
|
87
modules/ve-mw/ui/pages/ve.ui.MWTemplatePlaceholderPage.js
Normal file
87
modules/ve-mw/ui/pages/ve.ui.MWTemplatePlaceholderPage.js
Normal 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();
|
||||
};
|
67
modules/ve-mw/ui/pages/ve.ui.MWTransclusionContentPage.js
Normal file
67
modules/ve-mw/ui/pages/ve.ui.MWTransclusionContentPage.js
Normal 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();
|
||||
};
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue