mediawiki-extensions-Cite/modules/ve-cite/ve.ui.MWReferenceDialog.js
WMDE-Fisch 60eb760dd8 [refactor] Don't setup the edit panel when re-using a ref
In the setup process the dialog is loaded and initialized. For the
case where the user opens this dialog to directly re-use a
reference, it does not make sense to fill out the form or create
the internal ref model. The edit panel is not used then.

This method might also be an entry point to create a new sub-ref
when triggered from e.g. Citoid. Switching to the re-use panel
still would not require to setup the edit panel.

I'm also moving a setup for the abilities, that's only relevant
in the edit case.

Bug: T375156
Change-Id: I061b88abc6cfd702a53208bac76be7a2ed6812c2
2024-10-06 17:34:39 +02:00

283 lines
7.9 KiB
JavaScript

'use strict';
/*!
* VisualEditor UserInterface MediaWiki MWReferenceDialog class.
*
* @copyright 2011-2018 VisualEditor Team's Cite sub-team and others; see AUTHORS.txt
* @license MIT
*/
/**
* Dialog for inserting, editing and re-using MediaWiki references.
*
* @constructor
* @extends ve.ui.NodeDialog
* @param {Object} [config] Configuration options
*/
ve.ui.MWReferenceDialog = function VeUiMWReferenceDialog( config ) {
// Parent constructor
ve.ui.MWReferenceDialog.super.call( this, config );
// Properties
this.reuseReference = false;
};
/* Inheritance */
OO.inheritClass( ve.ui.MWReferenceDialog, ve.ui.NodeDialog );
/* Static Properties */
ve.ui.MWReferenceDialog.static.name = 'reference';
ve.ui.MWReferenceDialog.static.title =
OO.ui.deferMsg( 'cite-ve-dialog-reference-title' );
ve.ui.MWReferenceDialog.static.actions = [
{
action: 'done',
label: OO.ui.deferMsg( 'visualeditor-dialog-action-apply' ),
flags: [ 'progressive', 'primary' ],
modes: 'edit'
},
{
action: 'insert',
label: OO.ui.deferMsg( 'visualeditor-dialog-action-insert' ),
flags: [ 'progressive', 'primary' ],
modes: 'insert'
},
{
label: OO.ui.deferMsg( 'visualeditor-dialog-action-cancel' ),
flags: [ 'safe', 'close' ],
modes: [ 'readonly', 'insert', 'edit', 'insert-select' ]
}
];
ve.ui.MWReferenceDialog.static.modelClasses = [ ve.dm.MWReferenceNode ];
/* Methods */
/**
* Handle ve.ui.MWReferenceEditPanel#change events
*
* @param {Object} change
* @param {boolean} [change.isModified] If changes to the original content or values have been made
* @param {boolean} [change.hasContent] If there's non empty content set
*/
ve.ui.MWReferenceDialog.prototype.onEditPanelInputChange = function ( change ) {
this.actions.setAbilities( {
done: change.isModified,
insert: change.hasContent
} );
if ( !this.trackedInputChange ) {
ve.track( 'activity.' + this.constructor.static.name, { action: 'input' } );
this.trackedInputChange = true;
}
};
/**
* Handle search results ref reuse events.
*
* @param {ve.dm.MWReferenceModel} ref
*/
ve.ui.MWReferenceDialog.prototype.onReuseSearchResultsReuse = function ( ref ) {
if ( this.selectedNode instanceof ve.dm.MWReferenceNode ) {
this.getFragment().removeContent();
this.selectedNode = null;
}
this.insertReference( ref );
ve.track( 'activity.' + this.constructor.static.name, { action: 'reuse-choose' } );
this.close( { action: 'insert' } );
};
/**
* Handle search results popup menu extends events.
*
* @param {ve.dm.MWReferenceModel} originalRef
*/
ve.ui.MWReferenceDialog.prototype.onReuseSearchResultsExtends = function ( originalRef ) {
const newRef = new ve.dm.MWReferenceModel( this.getFragment().getDocument() );
newRef.extendsRef = originalRef.getListKey();
newRef.group = originalRef.getGroup();
this.getManager()
.openWindow( 'setExtendsContent', {
originalRef: originalRef,
newRef: newRef,
internalList: this.getFragment().getDocument().getInternalList()
} )
.closing.then( ( data ) => {
if ( data && data.action && data.action === 'insert' ) {
newRef.insertInternalItem( this.getFragment().getSurface() );
newRef.insertReferenceNode( this.getFragment() );
this.close( { action: 'extends-choose' } );
}
} );
};
/**
* @override
*/
ve.ui.MWReferenceDialog.prototype.getReadyProcess = function ( data ) {
return ve.ui.MWReferenceDialog.super.prototype.getReadyProcess.call( this, data )
.next( () => {
if ( this.reuseReference ) {
this.reuseSearch.getQuery().focus().select();
} else {
this.editPanel.focus();
}
} );
};
/**
* @override
*/
ve.ui.MWReferenceDialog.prototype.getBodyHeight = function () {
// Clamp value to between 300 and 400px height, preferring the actual height if available
return Math.min(
400,
Math.max(
300,
Math.ceil( this.panels.getCurrentItem().$element[ 0 ].scrollHeight )
)
);
};
/**
* @override
*/
ve.ui.MWReferenceDialog.prototype.initialize = function () {
// Parent method
ve.ui.MWReferenceDialog.super.prototype.initialize.call( this );
// Properties
this.panels = new OO.ui.StackLayout();
this.editPanel = new ve.ui.MWReferenceEditPanel( { $overlay: this.$overlay } );
this.reuseSearchPanel = new OO.ui.PanelLayout();
this.reuseSearch = new ve.ui.MWReferenceSearchWidget( { $overlay: this.$overlay } );
// Events
this.reuseSearch.connect( this, {
reuse: 'onReuseSearchResultsReuse',
extends: 'onReuseSearchResultsExtends'
} );
this.editPanel.connect( this, { change: 'onEditPanelInputChange' } );
// Initialization
this.$content.addClass( 've-ui-mwReferenceDialog' );
this.panels.addItems( [ this.editPanel, this.reuseSearchPanel ] );
this.reuseSearchPanel.$element.append( this.reuseSearch.$element );
this.$body.append( this.panels.$element );
};
/**
* Switches dialog to use existing reference mode.
*/
ve.ui.MWReferenceDialog.prototype.openReusePanel = function () {
this.actions.setMode( 'insert-select' );
this.reuseSearch.buildIndex();
this.panels.setItem( this.reuseSearchPanel );
// https://phabricator.wikimedia.org/T362347
ve.track( 'activity.' + this.constructor.static.name, { action: 'dialog-open-reuse' } );
};
/**
* Insert a reference at the end of the selection, could also be a reuse of an exising reference
*
* @private
* @param {ve.dm.MWReferenceModel} ref
*/
ve.ui.MWReferenceDialog.prototype.insertReference = function ( ref ) {
const surfaceModel = this.getFragment().getSurface();
if ( !ref.findInternalItem( surfaceModel ) ) {
ref.insertInternalItem( surfaceModel );
}
// Collapse returns a new fragment, so update this.fragment
this.fragment = this.getFragment().collapseToEnd();
ref.insertReferenceNode( this.getFragment() );
};
/**
* @override
*/
ve.ui.MWReferenceDialog.prototype.getActionProcess = function ( action ) {
if ( action === 'insert' || action === 'done' ) {
return new OO.ui.Process( () => {
const ref = this.editPanel.getReferenceFromEditing();
if ( !( this.selectedNode instanceof ve.dm.MWReferenceNode ) ) {
this.insertReference( ref );
}
ref.updateInternalItem( this.getFragment().getSurface() );
this.close( { action: action } );
} );
}
return ve.ui.MWReferenceDialog.super.prototype.getActionProcess.call( this, action );
};
/**
* @override
* @param {Object} [data] Setup data
* @param {boolean} [data.reuseReference=false] Open the dialog in "use existing reference" mode
*/
ve.ui.MWReferenceDialog.prototype.getSetupProcess = function ( data ) {
data = data || {};
return ve.ui.MWReferenceDialog.super.prototype.getSetupProcess.call( this, data )
.next( () => {
this.reuseReference = !!data.reuseReference;
if ( this.reuseReference ) {
this.reuseSearch.setInternalList( this.getFragment().getDocument().getInternalList() );
this.openReusePanel();
} else {
this.panels.setItem( this.editPanel );
const docRefs = ve.dm.MWDocumentReferences.static.refsForDoc(
this.getFragment().getDocument()
);
this.editPanel.setDocumentReferences( docRefs );
let ref;
if ( this.selectedNode instanceof ve.dm.MWReferenceNode ) {
// edit an existing reference
ref = ve.dm.MWReferenceModel.static.newFromReferenceNode( this.selectedNode );
if ( ref.extendsRef ) {
this.title.setLabel( ve.msg( 'cite-ve-dialog-reference-title-edit-details' ) );
}
this.actions.setAbilities( { done: false } );
} else {
// create a new reference
ref = new ve.dm.MWReferenceModel( this.getFragment().getDocument() );
this.actions.setAbilities( { insert: false } );
}
this.editPanel.setReferenceForEditing( ref );
this.editPanel.setReadOnly( this.isReadOnly() );
}
this.trackedInputChange = false;
} );
};
/**
* @override
*/
ve.ui.MWReferenceDialog.prototype.getTeardownProcess = function ( data ) {
return ve.ui.MWReferenceDialog.super.prototype.getTeardownProcess.call( this, data )
.first( () => {
this.editPanel.clear();
this.reuseSearch.clearSearch();
} );
};
/* Registration */
ve.ui.windowFactory.register( ve.ui.MWReferenceDialog );