mediawiki-extensions-Visual.../modules/ve-mw/ui/dialogs/ve.ui.MWTransclusionDialog.js

716 lines
23 KiB
JavaScript
Raw Normal View History

/*!
* VisualEditor user interface MWTransclusionDialog class.
*
* @copyright 2011-2020 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Dialog for inserting and editing MediaWiki transclusions, i.e. a sequence of one or more template
* invocations that strictly belong to each other (e.g. because they are unbalanced), possibly
* mixed with raw wikitext snippets.
*
* Note the base class {@see ve.ui.MWTemplateDialog} alone does not allow to manage more than a
* single template invocation. Most of the code for this feature set is exclusive to this subclass.
*
* @class
* @extends ve.ui.MWTemplateDialog
*
* @constructor
* @param {Object} [config] Configuration options
*/
ve.ui.MWTransclusionDialog = function VeUiMWTransclusionDialog( config ) {
var veConfig = mw.config.get( 'wgVisualEditorConfig' );
// Parent constructor
ve.ui.MWTransclusionDialog.super.call( this, config );
The great directory split of 2013 Move all MW-specific files into the ve-mw directory, in preparation for moving them out into a separate repo. All MW-specific files were moved into a parallel directory structure in modules/ve-mw . Files with both generic and MW-specific things were split up. Files in ve/init/mw/ were moved to ve-mw/init/ rather than ve-mw/init/mw ; they're still named ve.init.mw.* but we should change that. Some of the test files for core classes had MW-specific test cases, so those were split up and the test runner was duplicated; we should refactor our tests to use data providers so we can add cases more easily. Split files: * ve.ce.Node.css * ve.ce.ContentBranchNode.test.js (MWEntityNode) * ve.ce.Document.test.js (some core test cases genericized) * ve.dm.InternalList.test.js (uses mwReference test document) * ve.dm.SurfaceFragment.test.js, ve.ui.FormatAction.test.js ** Made core tests use heading instead of mwHeading ** Updated core tests because normal headings don't break out of lists ** Moved test runners into ve.test.utils.js * ve.ui.Icons-*.css * ve.ui.Dialog.css (MW parts into ve.ui.MWDialog.css) * ve.ui.Tool.css * ve.ui.Widget.css (move ve-ui-rtl and ve-ui-ltr to ve.ui.css) ve.dm.Converter.test.js: Moved runner functions into ve.test.utils.js ve.dm.example.js: * Refactored createExampleDocument so mwExample can use it * Removed wgExtensionAssetsPath detection, moved into mw-preload.js * Genericized withMeta example document (original version copied to mwExample) * Moved references example document to mwExample ve.dm.mwExample.js: * Move withMeta and references example documents from ve.dm.example.js * Add createExampleDocument function ve-mw/test/index.php: Runner for MW-specific tests only ve-mw/test/mw-preload.js: Sets VE_TESTDIR for Special:JavaScriptTest only ve.ui.Window.js: * Remove magic path interpolation in addLocalStyleSheets() * Pass full(er) paths to addLocalStyleSheets(), here and in subclasses ve.ui.MWDialog.js: Subclass of Dialog that adds MW versions of stylesheets ve.ui.MW*Dialog.js: * Subclass MWDialog rather than Dialog * Load both core and MW versions of stylesheets that have both ve.ui.PagedDialog.js: Converted to a mixin rather than an abstract base class * Don't inherit ve.ui.Dialog * Rather than overriding initialize(), provide initializePages() which the host class is supposed to call from its initialize() * Rename onOutlineSelect to onPageOutlineSelect ve.ui.MWMetaDialog.js, ve.ui.MWTransclusionDialog.js: * Use PagedDialog as a mixin rather than a base class, inherit MWDialog bullet-icon.png: Unused, deleted Stuff we should do later: * Refactor tests to use data providers * Write utility function for SVG compat check * Separate omnibus CSS files such as ve.ui.Widget.css * Separate omnibus RL modules * Use icon classes in ViewPageTarget Change-Id: I1b28f8ba7f2d2513e5c634927a854686fb9dd5a5
2013-07-03 01:30:10 +00:00
// Properties
this.isSidebarExpanded = null;
this.useNewSidebar = veConfig.transclusionDialogNewSidebar;
if ( this.useNewSidebar ) {
this.$element.addClass( 've-ui-mwTransclusionDialog-newSidebar' );
}
this.hotkeyTriggers = {};
this.$element.on( 'keydown', this.onKeyDown.bind( this ) );
};
/* Inheritance */
OO.inheritClass( ve.ui.MWTransclusionDialog, ve.ui.MWTemplateDialog );
The great directory split of 2013 Move all MW-specific files into the ve-mw directory, in preparation for moving them out into a separate repo. All MW-specific files were moved into a parallel directory structure in modules/ve-mw . Files with both generic and MW-specific things were split up. Files in ve/init/mw/ were moved to ve-mw/init/ rather than ve-mw/init/mw ; they're still named ve.init.mw.* but we should change that. Some of the test files for core classes had MW-specific test cases, so those were split up and the test runner was duplicated; we should refactor our tests to use data providers so we can add cases more easily. Split files: * ve.ce.Node.css * ve.ce.ContentBranchNode.test.js (MWEntityNode) * ve.ce.Document.test.js (some core test cases genericized) * ve.dm.InternalList.test.js (uses mwReference test document) * ve.dm.SurfaceFragment.test.js, ve.ui.FormatAction.test.js ** Made core tests use heading instead of mwHeading ** Updated core tests because normal headings don't break out of lists ** Moved test runners into ve.test.utils.js * ve.ui.Icons-*.css * ve.ui.Dialog.css (MW parts into ve.ui.MWDialog.css) * ve.ui.Tool.css * ve.ui.Widget.css (move ve-ui-rtl and ve-ui-ltr to ve.ui.css) ve.dm.Converter.test.js: Moved runner functions into ve.test.utils.js ve.dm.example.js: * Refactored createExampleDocument so mwExample can use it * Removed wgExtensionAssetsPath detection, moved into mw-preload.js * Genericized withMeta example document (original version copied to mwExample) * Moved references example document to mwExample ve.dm.mwExample.js: * Move withMeta and references example documents from ve.dm.example.js * Add createExampleDocument function ve-mw/test/index.php: Runner for MW-specific tests only ve-mw/test/mw-preload.js: Sets VE_TESTDIR for Special:JavaScriptTest only ve.ui.Window.js: * Remove magic path interpolation in addLocalStyleSheets() * Pass full(er) paths to addLocalStyleSheets(), here and in subclasses ve.ui.MWDialog.js: Subclass of Dialog that adds MW versions of stylesheets ve.ui.MW*Dialog.js: * Subclass MWDialog rather than Dialog * Load both core and MW versions of stylesheets that have both ve.ui.PagedDialog.js: Converted to a mixin rather than an abstract base class * Don't inherit ve.ui.Dialog * Rather than overriding initialize(), provide initializePages() which the host class is supposed to call from its initialize() * Rename onOutlineSelect to onPageOutlineSelect ve.ui.MWMetaDialog.js, ve.ui.MWTransclusionDialog.js: * Use PagedDialog as a mixin rather than a base class, inherit MWDialog bullet-icon.png: Unused, deleted Stuff we should do later: * Refactor tests to use data providers * Write utility function for SVG compat check * Separate omnibus CSS files such as ve.ui.Widget.css * Separate omnibus RL modules * Use icon classes in ViewPageTarget Change-Id: I1b28f8ba7f2d2513e5c634927a854686fb9dd5a5
2013-07-03 01:30:10 +00:00
/* Static Properties */
ve.ui.MWTransclusionDialog.static.name = 'transclusion';
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
ve.ui.MWTransclusionDialog.static.actions = ve.ui.MWTemplateDialog.static.actions.concat( [
{
action: 'mode',
modes: [ 'edit', 'insert' ],
// HACK: Will be set later, but we want measurements to be accurate in the mean time, this
// will not be needed when T93290 is resolved
label: $( document.createTextNode( '\u00a0' ) )
},
{
action: 'back',
label: OO.ui.deferMsg( 'visualeditor-dialog-action-goback' ),
modes: [ 'edit', 'insert' ],
flags: [ 'safe', 'back' ]
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
}
] );
/** @inheritdoc */
ve.ui.MWTransclusionDialog.static.bookletLayoutConfig = ve.extendObject(
{},
ve.ui.MWTemplateDialog.static.bookletLayoutConfig,
{ outlined: true, editable: true }
);
ve.ui.MWTransclusionDialog.static.smallScreenMaxWidth = 540;
/* Static Methods */
/**
* @return {boolean}
*/
ve.ui.MWTransclusionDialog.static.isSmallScreen = function () {
return $( window ).width() <= ve.ui.MWTransclusionDialog.static.smallScreenMaxWidth;
};
/* Methods */
/**
* Handle outline controls move events.
*
* @private
* @param {number} places Number of places to move the selected item
*/
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsMove = function ( places ) {
var part = this.transclusionModel.getPartFromId( this.findSelectedItemId() );
if ( !part ) {
return;
}
var newPlace = this.transclusionModel.getParts().indexOf( part ) + places;
if ( newPlace < 0 || newPlace >= this.transclusionModel.getParts().length ) {
return;
}
// Move part to new location, and if dialog is loaded switch to new part page
var promise = this.transclusionModel.addPart( part, newPlace );
if ( this.loaded && !this.preventReselection ) {
promise.done( this.focusPart.bind( this, part.getId() ) );
}
};
/**
* Handle outline controls remove events.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.onOutlineControlsRemove = function () {
var controls = this.bookletLayout.getOutlineControls();
// T301914: Safe-guard for when a keyboard shortcut triggers this, instead of the actual button
if ( !controls.isVisible() ||
!controls.removeButton.isVisible() ||
controls.removeButton.isDisabled()
) {
return;
}
var itemId = this.findSelectedItemId(),
part = this.transclusionModel.getPartFromId( itemId );
// Check if the part is the actual template, or one of its parameters
// TODO: This applies to the old sidebar only and can be removed later
if ( part instanceof ve.dm.MWTemplateModel && itemId !== part.getId() ) {
var param = part.getParameterFromId( itemId );
if ( param ) {
param.remove();
}
} else if ( part instanceof ve.dm.MWTransclusionPartModel ) {
this.transclusionModel.removePart( part );
}
};
/**
* Create a new template part at the end of the transclusion.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.addTemplatePlaceholder = function () {
this.addPart( new ve.dm.MWTemplatePlaceholderModel( this.transclusionModel ) );
};
/**
* Handle add content button click events.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.addContent = function () {
this.addPart( new ve.dm.MWTransclusionContentModel( this.transclusionModel ) );
};
/**
* Handle add parameter button click events.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.addParameter = function () {
var part = this.transclusionModel.getPartFromId( this.findSelectedItemId() );
if ( !( part instanceof ve.dm.MWTemplateModel ) ) {
return;
}
// TODO: Use a distinct class for placeholder model rather than
// these magical "empty" constants.
var placeholderParameter = new ve.dm.MWParameterModel( part );
part.addParameter( placeholderParameter );
this.focusPart( placeholderParameter.getId() );
this.autoExpandSidebar();
};
/**
* Handle booklet layout page set events.
*
* @private
* @param {OO.ui.PageLayout} page Active page
*/
ve.ui.MWTransclusionDialog.prototype.onBookletLayoutSetPage = function ( page ) {
var isLastPlaceholder = page instanceof ve.ui.MWTemplatePlaceholderPage &&
this.transclusionModel.isSingleTemplate(),
acceptsNewParameters = page instanceof ve.ui.MWTemplatePage ||
page instanceof ve.ui.MWParameterPage;
this.addParameterButton.setDisabled( !acceptsNewParameters || this.isReadOnly() );
this.bookletLayout.getOutlineControls().removeButton.toggle( !isLastPlaceholder );
this.sidebar.setSelectionByPageName( page.getName() );
};
/**
* @inheritdoc
*/
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
ve.ui.MWTransclusionDialog.prototype.onReplacePart = function ( removed, added ) {
ve.ui.MWTransclusionDialog.super.prototype.onReplacePart.call( this, removed, added );
var parts = this.transclusionModel.getParts();
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
if ( parts.length === 0 ) {
this.addParameterButton.setDisabled( true );
this.addPart( new ve.dm.MWTemplatePlaceholderModel( this.transclusionModel ) );
} else if ( parts.length > 1 ) {
this.bookletLayout.getOutlineControls().toggle( true );
this.$element.removeClass( 've-ui-mwTransclusionDialog-single-transclusion' );
}
// multipart message
if ( this.useNewSidebar ) {
this.bookletLayout.stackLayout.$element.prepend( this.multipartMessage.$element );
this.multipartMessage.toggle( parts.length > 1 );
}
this.autoExpandSidebar();
this.updateModeActionState();
this.updateActionSet();
};
/**
* @private
*/
ve.ui.MWTransclusionDialog.prototype.setupHotkeyTriggers = function () {
// Lower-case modifier and key names as specified in {@see ve.ui.Trigger}
var isMac = ve.getSystemPlatform() === 'mac',
meta = isMac ? 'meta+' : 'ctrl+';
var hotkeys = {
addTemplate: meta + 'd',
addWikitext: meta + 'shift+y',
addParameter: meta + 'shift+d',
moveUp: meta + 'shift+up',
moveDown: meta + 'shift+down',
remove: meta + 'delete',
removeBackspace: meta + 'backspace'
};
var notInTextFields = /^(?!INPUT|TEXTAREA)/i;
this.connectHotKeyBinding( hotkeys.addTemplate, this.addTemplatePlaceholder.bind( this ) );
this.connectHotKeyBinding( hotkeys.addWikitext, this.addContent.bind( this ) );
this.connectHotKeyBinding( hotkeys.addParameter, this.addParameter.bind( this ) );
this.connectHotKeyBinding( hotkeys.moveUp, this.onOutlineControlsMove.bind( this, -1 ), notInTextFields );
this.connectHotKeyBinding( hotkeys.moveDown, this.onOutlineControlsMove.bind( this, 1 ), notInTextFields );
this.connectHotKeyBinding( hotkeys.remove, this.onOutlineControlsRemove.bind( this ), notInTextFields );
if ( isMac ) {
this.connectHotKeyBinding( hotkeys.removeBackspace, this.onOutlineControlsRemove.bind( this ), notInTextFields );
}
this.addHotkeyToTitle( this.addTemplateButton, hotkeys.addTemplate );
this.addHotkeyToTitle( this.addContentButton, hotkeys.addWikitext );
this.addHotkeyToTitle( this.addParameterButton, hotkeys.addParameter );
var controls = this.bookletLayout.getOutlineControls();
this.addHotkeyToTitle( controls.upButton, hotkeys.moveUp );
this.addHotkeyToTitle( controls.downButton, hotkeys.moveDown );
this.addHotkeyToTitle( controls.removeButton, hotkeys.remove );
};
/**
* @private
* @param {string} hotkey
* @param {Function} handler
* @param {RegExp} [validTypes]
*/
ve.ui.MWTransclusionDialog.prototype.connectHotKeyBinding = function ( hotkey, handler, validTypes ) {
this.hotkeyTriggers[ hotkey ] = {
handler: handler,
validTypes: validTypes
};
};
/**
* @private
* @param {OO.ui.mixin.TitledElement} element
* @param {string} hotkey
*/
ve.ui.MWTransclusionDialog.prototype.addHotkeyToTitle = function ( element, hotkey ) {
// Separated with a space as in {@see OO.ui.Tool.updateTitle}
element.setTitle( element.getTitle() + ' ' + new ve.ui.Trigger( hotkey ).getMessage() );
};
/**
* Handles key down events.
*
* @protected
* @param {jQuery.Event} e Key down event
*/
ve.ui.MWTransclusionDialog.prototype.onKeyDown = function ( e ) {
var hotkey = new ve.ui.Trigger( e ).toString(),
trigger = this.hotkeyTriggers[ hotkey ];
if ( trigger && ( !trigger.validTypes || trigger.validTypes.test( e.target.nodeName ) ) ) {
trigger.handler();
e.preventDefault();
e.stopPropagation();
}
};
/**
* @return {string|undefined} Any id, including slash-delimited template parameter ids
*/
ve.ui.MWTransclusionDialog.prototype.findSelectedItemId = function () {
if ( this.sidebar ) {
// TODO: This can't return parameter ids any more when the old sidebar is gone
return this.sidebar.findSelectedPartId();
}
var item = this.bookletLayout.getOutline().findSelectedItem();
return item && item.getData();
};
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.getPageFromPart = function ( part ) {
var page = ve.ui.MWTransclusionDialog.super.prototype.getPageFromPart.call( this, part );
if ( !page && part instanceof ve.dm.MWTransclusionContentModel ) {
return new ve.ui.MWTransclusionContentPage( part, part.getId(), { $overlay: this.$overlay, isReadOnly: this.isReadOnly() } );
}
return page;
};
/**
* Automatically expand or collapse the sidebar according to default logic.
*
* @protected
*/
ve.ui.MWTransclusionDialog.prototype.autoExpandSidebar = function () {
var expandSidebar;
var isSmallScreen = this.constructor.static.isSmallScreen();
var showOtherActions = isSmallScreen ||
this.actions.getOthers().some( function ( action ) {
// Check for unknown actions, show the toolbar if any are available.
return action.action !== 'mode';
} );
this.actions.forEach( { actions: [ 'mode' ] }, function ( action ) {
action.toggle( isSmallScreen );
} );
this.$otherActions.toggleClass( 'oo-ui-element-hidden', !showOtherActions );
if ( isSmallScreen && this.transclusionModel.isEmpty() ) {
expandSidebar = false;
} else if ( isSmallScreen &&
// eslint-disable-next-line no-jquery/no-class-state
this.$content.hasClass( 've-ui-mwTransclusionDialog-small-screen' )
) {
// We did this already. If the sidebar is visible or not is now the user's decision.
return;
} else {
expandSidebar = !isSmallScreen;
}
this.$content.toggleClass( 've-ui-mwTransclusionDialog-small-screen', isSmallScreen );
this.toggleSidebar( expandSidebar );
};
/**
* Set if the sidebar is visible (which means the dialog is expanded), or collapsed.
*
* @param {boolean} expandSidebar
* @private
*/
ve.ui.MWTransclusionDialog.prototype.toggleSidebar = function ( expandSidebar ) {
if ( this.isSidebarExpanded === expandSidebar ) {
return;
}
this.isSidebarExpanded = expandSidebar;
this.$content
.toggleClass( 've-ui-mwTransclusionDialog-collapsed', !expandSidebar )
.toggleClass( 've-ui-mwTransclusionDialog-expanded', expandSidebar );
var dialogSizeSidebarExpanded = 'larger';
var dialogSizeSidebarCollapsed = this.useNewSidebar ? dialogSizeSidebarExpanded : 'medium';
this.ignoreNextWindowResizeEvent = true;
this.setSize( expandSidebar ? dialogSizeSidebarExpanded : dialogSizeSidebarCollapsed );
this.bookletLayout.toggleOutline( expandSidebar );
this.updateTitle();
this.updateModeActionState();
// HACK blur any active input so that its dropdown will be hidden and won't end
// up being mispositioned
this.$content.find( 'input:focus' ).trigger( 'blur' );
if ( this.loaded && this.constructor.static.isSmallScreen() ) {
var dialog = this;
// Updates the page sizes when the menu is toggled using the button. This needs
// to happen after the animation when the panel is visible.
setTimeout( function () {
dialog.bookletLayout.stackLayout.getItems().forEach( function ( page ) {
if ( page instanceof ve.ui.MWParameterPage ) {
page.updateSize();
}
} );
}, OO.ui.theme.getDialogTransitionDuration() );
// Reapply selection and scrolling when switching between panes.
// FIXME: decouple from descendants
var selectedPage = this.bookletLayout.stackLayout.getCurrentItem();
if ( selectedPage ) {
var name = selectedPage.getName();
// Align whichever panel is becoming visible, after animation completes.
// TODO: Should hook onto an animation promise—but is this possible when pure CSS?
setTimeout( function () {
if ( expandSidebar ) {
dialog.sidebar.setSelectionByPageName( name );
} else {
selectedPage.scrollElementIntoView();
// TODO: Find a reliable way to refocus.
// dialog.focusPart( name );
}
}, OO.ui.theme.getDialogTransitionDuration() );
}
}
};
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.updateTitle = function () {
if ( !this.transclusionModel.isSingleTemplate() ) {
this.title.setLabel( ve.msg( 'visualeditor-dialog-transclusion-title-edit-transclusion' ) );
} else {
// Parent method
ve.ui.MWTransclusionDialog.super.prototype.updateTitle.call( this );
}
};
/**
* Update the state of the 'mode' action
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.updateModeActionState = function () {
var isExpanded = this.isSidebarExpanded,
label = ve.msg( isExpanded ?
'visualeditor-dialog-transclusion-collapse-options' :
'visualeditor-dialog-transclusion-expand-options' );
this.actions.forEach( { actions: [ 'mode' ] }, function ( action ) {
action.setLabel( label );
action.$button.attr( 'aria-expanded', isExpanded ? 1 : 0 );
} );
// Old sidebar: Only a single template can be collapsed, except it's still the initial
// placeholder.
// New sidebar: The button is only visible on very narrow screens, {@see autoExpandSidebar}.
// It's always needed, except in the initial placeholder state.
var isInitialState = !isExpanded && this.transclusionModel.isEmpty(),
canCollapse = !isInitialState;
this.actions.setAbilities( { mode: canCollapse } );
};
/**
* Add a part to the transclusion.
*
* @param {ve.dm.MWTransclusionPartModel} part Part to add
*/
ve.ui.MWTransclusionDialog.prototype.addPart = function ( part ) {
var parts = this.transclusionModel.getParts(),
selectedPart = this.transclusionModel.getPartFromId( this.findSelectedItemId() );
// Insert after selected part, or at the end if nothing is selected
var index = selectedPart ? parts.indexOf( selectedPart ) + 1 : parts.length;
// Add the part, and if dialog is loaded switch to part page
var promise = this.transclusionModel.addPart( part, index );
if ( this.loaded && !this.preventReselection ) {
promise.done( this.focusPart.bind( this, part.getId() ) );
}
};
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.getActionProcess = function ( action ) {
var willLoseProgress = this.getMode() === 'insert' ?
// A new template with no parameters is not considered valuable.
this.transclusionModel.containsValuableData() :
// The user has changed a parameter, and is not on the template search page.
( this.altered && !this.transclusionModel.isEmpty() );
switch ( action ) {
case 'back':
return new OO.ui.Process( function () {
if ( willLoseProgress ) {
ve.ui.MWConfirmationDialog.static.confirm(
'visualeditor-dialog-transclusion-back-confirmation-prompt',
this.resetDialog.bind( this )
);
} else {
this.resetDialog();
}
}, this );
case 'mode':
return new OO.ui.Process( function () {
this.toggleSidebar( !this.isSidebarExpanded );
}, this );
case '':
// close action
if ( willLoseProgress ) {
return new OO.ui.Process( function () {
ve.ui.MWConfirmationDialog.static.confirm(
'visualeditor-dialog-transclusion-close-confirmation-prompt',
this.close.bind( this ) );
}, this );
}
}
return ve.ui.MWTransclusionDialog.super.prototype.getActionProcess.call( this, action );
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
};
/**
* Update the widgets in the dialog's action bar.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.updateActionSet = function () {
var backButton = this.actions.get( { flags: [ 'back' ] } ).pop(),
saveButton = this.actions.get( { actions: [ 'done' ] } ).pop();
if ( saveButton && this.getMode() === 'edit' ) {
saveButton.setLabel( ve.msg( 'visualeditor-dialog-transclusion-action-save' ) );
}
var closeButton = this.actions.get( { flags: [ 'close' ] } ).pop(),
canGoBack = this.getMode() === 'insert' && this.canGoBack && !this.transclusionModel.isEmpty();
closeButton.toggle( !canGoBack );
backButton.toggle( canGoBack );
};
/**
* Revert the dialog back to its initial state.
*
* @private
*/
ve.ui.MWTransclusionDialog.prototype.resetDialog = function () {
var target = this;
this.transclusionModel.reset();
this.sidebar.clear();
this.bookletLayout.clearPages();
this.transclusionModel
.addPart( new ve.dm.MWTemplatePlaceholderModel( this.transclusionModel ), 0 )
.done( function () {
target.autoExpandSidebar();
} );
};
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.initialize = function () {
// Parent method
ve.ui.MWTransclusionDialog.super.prototype.initialize.call( this );
// Properties
this.addTemplateButton = new OO.ui.ButtonWidget( {
framed: false,
icon: 'puzzle',
title: ve.msg( 'visualeditor-dialog-transclusion-add-template' )
} );
this.addContentButton = new OO.ui.ButtonWidget( {
framed: false,
icon: 'wikiText',
title: ve.msg( this.useNewSidebar ?
'visualeditor-dialog-transclusion-add-wikitext' :
'visualeditor-dialog-transclusion-add-content' )
} );
this.addParameterButton = new OO.ui.ButtonWidget( {
framed: false,
icon: 'parameter',
title: ve.msg( 'visualeditor-dialog-transclusion-add-param' )
} );
this.bookletLayout.getOutlineControls().addItems( [ this.addTemplateButton, this.addContentButton ] );
if ( !this.useNewSidebar ) {
this.bookletLayout.getOutlineControls().addItems( [ this.addParameterButton ] );
}
this.setupHotkeyTriggers();
// multipart message gets attached in onReplacePart()
this.multipartMessage = new OO.ui.MessageWidget( {
label: mw.message( 'visualeditor-dialog-transclusion-multipart-message' ).parseDom(),
classes: [ 've-ui-mwTransclusionDialog-multipart-message' ]
} );
ve.targetLinksToNewWindow( this.multipartMessage.$element[ 0 ] );
var helpPopup = new ve.ui.MWFloatingHelpElement( {
label: mw.message( 'visualeditor-dialog-transclusion-help-title' ).text(),
title: mw.message( 'visualeditor-dialog-transclusion-help-title' ).text(),
$message: new OO.ui.FieldsetLayout( {
items: [
new OO.ui.LabelWidget( {
label: mw.message( 'visualeditor-dialog-transclusion-help-message' ).text()
} ),
this.getMessageButton( 'visualeditor-dialog-transclusion-help-page-help', 'helpNotice' ),
this.getMessageButton( 'visualeditor-dialog-transclusion-help-page-shortcuts', 'keyboard' )
],
classes: [ 've-ui-mwTransclusionDialog-floatingHelpElement-fieldsetLayout' ]
} ).$element
} );
helpPopup.$element.addClass( 've-ui-mwTransclusionDialog-floatingHelpElement' );
helpPopup.$element.appendTo( this.$body );
// Events
this.getManager().connect( this, { resize: ve.debounce( this.onWindowResize.bind( this ) ) } );
this.bookletLayout.connect( this, { set: 'onBookletLayoutSetPage' } );
this.bookletLayout.$menu.find( '[ role="listbox" ]' ).first()
.attr( 'aria-label', ve.msg( 'visualeditor-dialog-transclusion-templates-menu-aria-label' ) );
this.addTemplateButton.connect( this, { click: 'addTemplatePlaceholder' } );
this.addContentButton.connect( this, { click: 'addContent' } );
this.addParameterButton.connect( this, { click: 'addParameter' } );
this.bookletLayout.getOutlineControls().connect( this, {
move: 'onOutlineControlsMove',
remove: 'onOutlineControlsRemove'
} );
};
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.getSetupProcess = function ( data ) {
this.onTearDownCallback = data && data.onTearDownCallback;
return ve.ui.MWTransclusionDialog.super.prototype.getSetupProcess.call( this, data )
Update VE core submodule to master (f2277ea) New changes: 56de6f5 Localisation updates from https://translatewiki.net. f8bda64 Widgetise demo menu 6ac48d8 Localisation updates from https://translatewiki.net. 365e131 builderloader: Omit value for boolean "disabled" attribute per HTML5 706e4b3 Prevent double counting of DM nodes in getNodeAndOffset b141a7d Update OOjs UI to v0.1.0-pre (d2451ac748) c5b3921 Localisation updates from https://translatewiki.net. 1606983 Update reference to ConfirmationDialog to use MessageDialog Deletions: * Styles for ve.ui.MWBetaWelcomeDialog - not needed anymore because OO.ui.MessageDialog provides them * Styles for ve.ui.MWGalleryInspector - not needed anymore because ve.ui.MWExtensionInspector provides part of them and the rest are being replaced by programatic sizing Modifications: * ve.ui.MWLinkTargetInputWidget - Added support for validation and href getter * Split message between tool and dialog title for ve.ui.MWEditModeTool and ve.ui.MWWikitextSwitchConfirmDialog General changes: * Updated inheritance. * Added manager param to constructors of dialogs and inspectors. * Updated use of show/hide with toggle. * Added meaningful descriptions of dialog and inspector classes. * Configured dialog and inspector sizes statically. * Configured dialog action buttons statically. * Interfaced with OO.ui.ActionSet to control action buttons. * Moved applyChanges code into getActionProcess methods. * Always using .next in setup/ready process getters and .first in hold/teardown process getters. Change-Id: Ia74732e6e32c0808eee021f0a26225b9e6c3f971
2014-07-14 21:32:49 +00:00
.next( function () {
var isReadOnly = this.isReadOnly();
this.addTemplateButton.setDisabled( isReadOnly );
this.addContentButton.setDisabled( isReadOnly );
this.addParameterButton.setDisabled( isReadOnly );
this.bookletLayout.getOutlineControls().setAbilities( {
move: !isReadOnly,
remove: !isReadOnly
} );
if ( this.useNewSidebar ) {
this.bookletLayout.getOutlineControls().toggle( !this.transclusionModel.isSingleTemplate() );
this.$element.toggleClass(
've-ui-mwTransclusionDialog-single-transclusion',
this.transclusionModel.isSingleTemplate()
);
}
this.updateModeActionState();
this.autoExpandSidebar();
}, this );
};
/** @inheritdoc */
ve.ui.MWTransclusionDialog.prototype.getTeardownProcess = function () {
if ( this.onTearDownCallback ) {
this.onTearDownCallback();
}
return ve.ui.MWTransclusionDialog.super.prototype.getTeardownProcess.apply( this, arguments );
};
/**
* @private
*/
ve.ui.MWTransclusionDialog.prototype.onWindowResize = function () {
if ( this.transclusionModel && !this.ignoreNextWindowResizeEvent ) {
this.autoExpandSidebar();
this.bookletLayout.stackLayout.getItems().forEach( function ( page ) {
if ( page instanceof ve.ui.MWParameterPage ) {
page.updateSize();
}
} );
}
this.ignoreNextWindowResizeEvent = false;
};
/**
* @inheritdoc
*/
ve.ui.MWTransclusionDialog.prototype.getSizeProperties = function () {
return ve.extendObject(
{ height: '90%' },
ve.ui.MWTransclusionDialog.super.prototype.getSizeProperties.call( this )
);
};
/**
* Converts a message link into an OO.ui.ButtonWidget with an icon.
*
* @private
* @param {string} message i18n message key
* @param {string} icon icon name
* @return {OO.ui.ButtonWidget}
*/
ve.ui.MWTemplateDialog.prototype.getMessageButton = function ( message, icon ) {
// Messages that can be used here:
// * visualeditor-dialog-transclusion-help-page-help
// * visualeditor-dialog-transclusion-help-page-shortcuts
var $link = mw.message( message ).parseDom(),
button = new OO.ui.ButtonWidget( {
label: $link.text(),
href: $link.attr( 'href' ),
target: '_blank',
flags: 'progressive',
icon: icon,
framed: false
} );
button.$button.attr( 'role', 'link' );
return button;
};
/* Registration */
ve.ui.windowFactory.register( ve.ui.MWTransclusionDialog );