2017-01-11 21:50:35 +00:00
|
|
|
/*!
|
|
|
|
* VisualEditor user interface MWLatexDialog class.
|
|
|
|
*
|
|
|
|
* @copyright 2015 VisualEditor Team and others; see AUTHORS.txt
|
2018-04-13 14:04:06 +00:00
|
|
|
* @license MIT
|
2017-01-11 21:50:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Abstract dialog for inserting and editing different formulas
|
|
|
|
* provided by the Math extension.
|
|
|
|
*
|
|
|
|
* @abstract
|
|
|
|
* @class
|
|
|
|
* @extends ve.ui.MWExtensionPreviewDialog
|
|
|
|
*
|
|
|
|
* @constructor
|
|
|
|
* @param {Object} [config] Configuration options
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog = function VeUiMWLatexDialog( config ) {
|
|
|
|
// Parent constructor
|
|
|
|
ve.ui.MWLatexDialog.super.call( this, config );
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Inheritance */
|
|
|
|
|
|
|
|
OO.inheritClass( ve.ui.MWLatexDialog, ve.ui.MWExtensionPreviewDialog );
|
|
|
|
|
|
|
|
/* Static properties */
|
|
|
|
|
|
|
|
ve.ui.MWLatexDialog.static.size = 'larger';
|
|
|
|
|
|
|
|
ve.ui.MWLatexDialog.static.dir = 'ltr';
|
|
|
|
|
|
|
|
ve.ui.MWLatexDialog.static.symbolsModule = null;
|
|
|
|
|
|
|
|
/* Methods */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.initialize = function () {
|
2024-02-13 00:31:24 +00:00
|
|
|
const dialog = this;
|
2017-01-11 21:50:35 +00:00
|
|
|
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWLatexDialog.super.prototype.initialize.call( this );
|
|
|
|
|
2017-05-17 09:31:57 +00:00
|
|
|
// Layout for the formula inserter (formula tab panel) and options form (options tab panel)
|
2018-11-12 16:15:00 +00:00
|
|
|
this.indexLayout = new OO.ui.IndexLayout();
|
2017-01-11 21:50:35 +00:00
|
|
|
|
2024-02-13 00:31:24 +00:00
|
|
|
const formulaTabPanel = new OO.ui.TabPanelLayout( 'formula', {
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexdialog-card-formula' ),
|
2022-08-30 15:21:11 +00:00
|
|
|
padded: true,
|
|
|
|
classes: [ 'latex-dialog-formula-panel' ]
|
2017-01-11 21:50:35 +00:00
|
|
|
} );
|
2024-02-13 00:31:24 +00:00
|
|
|
const optionsTabPanel = new OO.ui.TabPanelLayout( 'options', {
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexdialog-card-options' ),
|
2022-08-30 15:21:11 +00:00
|
|
|
padded: true,
|
|
|
|
classes: [ 'latex-dialog-options-panel' ]
|
2017-01-11 21:50:35 +00:00
|
|
|
} );
|
|
|
|
|
2017-05-17 09:31:57 +00:00
|
|
|
this.indexLayout.addTabPanels( [
|
|
|
|
formulaTabPanel,
|
|
|
|
optionsTabPanel
|
2017-01-11 21:50:35 +00:00
|
|
|
] );
|
|
|
|
|
|
|
|
// Layout for symbol picker (menu) and input and preview (content)
|
|
|
|
this.menuLayout = new OO.ui.MenuLayout( {
|
|
|
|
menuPosition: 'bottom',
|
|
|
|
classes: [ 've-ui-mwLatexDialog-menuLayout' ]
|
|
|
|
} );
|
|
|
|
|
|
|
|
this.previewElement.$element.addClass(
|
|
|
|
've-ui-mwLatexDialog-preview'
|
|
|
|
);
|
|
|
|
|
|
|
|
this.input = new ve.ui.MWAceEditorWidget( {
|
|
|
|
rows: 1, // This will be recalculated later in onWindowManagerResize
|
|
|
|
autocomplete: 'live',
|
|
|
|
autocompleteWordList: this.constructor.static.autocompleteWordList
|
|
|
|
} ).setLanguage( 'latex' );
|
|
|
|
|
|
|
|
this.input.togglePrintMargin( false );
|
|
|
|
|
|
|
|
this.displaySelect = new OO.ui.ButtonSelectWidget( {
|
|
|
|
items: [
|
|
|
|
new OO.ui.ButtonOptionWidget( {
|
|
|
|
data: 'default',
|
2019-01-23 22:36:14 +00:00
|
|
|
icon: 'mathematicsDisplayDefault',
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-display-default' )
|
|
|
|
} ),
|
|
|
|
new OO.ui.ButtonOptionWidget( {
|
|
|
|
data: 'inline',
|
2019-01-23 22:36:14 +00:00
|
|
|
icon: 'mathematicsDisplayInline',
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-display-inline' )
|
|
|
|
} ),
|
|
|
|
new OO.ui.ButtonOptionWidget( {
|
|
|
|
data: 'block',
|
2019-01-23 22:36:14 +00:00
|
|
|
icon: 'mathematicsDisplayBlock',
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-display-block' )
|
|
|
|
} )
|
|
|
|
]
|
|
|
|
} );
|
|
|
|
|
|
|
|
this.idInput = new OO.ui.TextInputWidget();
|
2022-07-20 15:51:31 +00:00
|
|
|
this.qidInput = new mw.widgets.MathWbEntitySelector();
|
2017-01-11 21:50:35 +00:00
|
|
|
|
2024-02-13 00:31:24 +00:00
|
|
|
const inputField = new OO.ui.FieldLayout( this.input, {
|
2017-01-11 21:50:35 +00:00
|
|
|
align: 'top',
|
2022-08-30 15:21:11 +00:00
|
|
|
classes: [ 'latex-dialog-formula-field' ],
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexdialog-card-formula' )
|
|
|
|
} );
|
2024-02-13 00:31:24 +00:00
|
|
|
const displayField = new OO.ui.FieldLayout( this.displaySelect, {
|
2017-01-11 21:50:35 +00:00
|
|
|
align: 'top',
|
2022-08-30 15:21:11 +00:00
|
|
|
classes: [ 'latex-dialog-display-field' ],
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-display' )
|
|
|
|
} );
|
2024-02-13 00:31:24 +00:00
|
|
|
const idField = new OO.ui.FieldLayout( this.idInput, {
|
2017-01-11 21:50:35 +00:00
|
|
|
align: 'top',
|
2022-08-30 15:21:11 +00:00
|
|
|
classes: [ 'latex-dialog-id-field' ],
|
2017-01-11 21:50:35 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-id' )
|
|
|
|
} );
|
2024-02-13 00:31:24 +00:00
|
|
|
const qidField = new OO.ui.FieldLayout( this.qidInput, {
|
2022-05-24 16:03:46 +00:00
|
|
|
align: 'top',
|
2022-08-30 15:21:11 +00:00
|
|
|
classes: [ 'latex-dialog-qid-field' ],
|
2022-05-24 16:03:46 +00:00
|
|
|
label: ve.msg( 'math-visualeditor-mwlatexinspector-qid' )
|
|
|
|
} );
|
2017-01-11 21:50:35 +00:00
|
|
|
|
2024-02-13 00:31:24 +00:00
|
|
|
const formulaPanel = new OO.ui.PanelLayout( {
|
2018-11-12 16:15:00 +00:00
|
|
|
scrollable: true,
|
2017-01-11 21:50:35 +00:00
|
|
|
padded: true
|
|
|
|
} );
|
|
|
|
|
|
|
|
// Layout for the symbol picker
|
|
|
|
this.bookletLayout = new OO.ui.BookletLayout( {
|
|
|
|
classes: [ 've-ui-mwLatexDialog-symbols' ],
|
|
|
|
menuPosition: 'before',
|
|
|
|
outlined: true,
|
|
|
|
continuous: true
|
|
|
|
} );
|
|
|
|
this.pages = [];
|
2022-11-22 17:37:36 +00:00
|
|
|
this.symbolsPromise = mw.loader.using( this.constructor.static.symbolsModule ).done( function ( require ) {
|
2024-02-13 00:31:24 +00:00
|
|
|
const symbols = require( dialog.constructor.static.symbolsModule );
|
|
|
|
for ( const category in symbols ) {
|
2017-01-11 21:50:35 +00:00
|
|
|
dialog.pages.push(
|
2019-11-01 21:56:31 +00:00
|
|
|
new ve.ui.MWLatexPage(
|
|
|
|
// eslint-disable-next-line mediawiki/msg-doc
|
|
|
|
ve.msg( category ),
|
|
|
|
{
|
|
|
|
// eslint-disable-next-line mediawiki/msg-doc
|
|
|
|
label: ve.msg( category ),
|
|
|
|
symbols: symbols[ category ]
|
|
|
|
}
|
|
|
|
)
|
2017-01-11 21:50:35 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
dialog.bookletLayout.addPages( dialog.pages );
|
|
|
|
dialog.bookletLayout.$element.on(
|
|
|
|
'click',
|
|
|
|
'.ve-ui-mwLatexPage-symbol',
|
|
|
|
dialog.onListClick.bind( dialog )
|
|
|
|
);
|
|
|
|
|
|
|
|
// Append everything
|
2018-11-12 16:15:00 +00:00
|
|
|
formulaPanel.$element.append(
|
|
|
|
dialog.previewElement.$element,
|
|
|
|
inputField.$element
|
2017-01-11 21:50:35 +00:00
|
|
|
);
|
2018-11-12 16:15:00 +00:00
|
|
|
dialog.menuLayout.setMenuPanel( dialog.bookletLayout );
|
|
|
|
dialog.menuLayout.setContentPanel( formulaPanel );
|
2017-01-11 21:50:35 +00:00
|
|
|
|
2017-05-17 09:31:57 +00:00
|
|
|
formulaTabPanel.$element.append(
|
2017-01-11 21:50:35 +00:00
|
|
|
dialog.menuLayout.$element
|
|
|
|
);
|
2017-05-17 09:31:57 +00:00
|
|
|
optionsTabPanel.$element.append(
|
2017-01-11 21:50:35 +00:00
|
|
|
displayField.$element,
|
2022-05-24 16:03:46 +00:00
|
|
|
idField.$element,
|
|
|
|
qidField.$element
|
2017-01-11 21:50:35 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
dialog.$body
|
|
|
|
.addClass( 've-ui-mwLatexDialog-content' )
|
|
|
|
.append( dialog.indexLayout.$element );
|
|
|
|
} );
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.getSetupProcess = function ( data ) {
|
|
|
|
return ve.ui.MWLatexDialog.super.prototype.getSetupProcess.call( this, data )
|
|
|
|
.next( function () {
|
2024-02-13 00:31:24 +00:00
|
|
|
const attributes = this.selectedNode && this.selectedNode.getAttribute( 'mw' ).attrs,
|
2017-01-11 21:50:35 +00:00
|
|
|
display = attributes && attributes.display || 'default',
|
2019-02-19 14:58:41 +00:00
|
|
|
id = attributes && attributes.id || '',
|
2022-05-24 16:03:46 +00:00
|
|
|
qid = attributes && attributes.qid || '',
|
2019-02-19 14:58:41 +00:00
|
|
|
isReadOnly = this.isReadOnly();
|
2017-01-11 21:50:35 +00:00
|
|
|
|
|
|
|
// Populate form
|
2019-02-19 14:58:41 +00:00
|
|
|
// TODO: This widget is not readable when disabled
|
|
|
|
this.displaySelect.selectItemByData( display ).setDisabled( isReadOnly );
|
2019-04-16 11:04:58 +00:00
|
|
|
this.idInput.setValue( id ).setReadOnly( isReadOnly );
|
2022-05-24 16:03:46 +00:00
|
|
|
this.qidInput.setValue( qid ).setReadOnly( isReadOnly );
|
2017-01-11 21:50:35 +00:00
|
|
|
|
|
|
|
// Add event handlers
|
|
|
|
this.input.on( 'change', this.onChangeHandler );
|
|
|
|
this.displaySelect.on( 'choose', this.onChangeHandler );
|
|
|
|
this.idInput.on( 'change', this.onChangeHandler );
|
2022-05-24 16:03:46 +00:00
|
|
|
this.qidInput.on( 'change', this.onChangeHandler );
|
2017-01-11 21:50:35 +00:00
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.getReadyProcess = function ( data ) {
|
2022-08-30 15:21:11 +00:00
|
|
|
mw.hook( 've.ui.MwLatexDialogReadyProcess' ).fire();
|
2017-01-11 21:50:35 +00:00
|
|
|
return ve.ui.MWLatexDialog.super.prototype.getReadyProcess.call( this, data )
|
|
|
|
.next( function () {
|
|
|
|
return this.symbolsPromise;
|
|
|
|
}, this )
|
|
|
|
.next( function () {
|
|
|
|
// Resize the input once the dialog has been appended
|
|
|
|
this.input.adjustSize( true ).focus().moveCursorToEnd();
|
|
|
|
this.getManager().connect( this, { resize: 'onWindowManagerResize' } );
|
|
|
|
this.onWindowManagerResize();
|
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.getTeardownProcess = function ( data ) {
|
|
|
|
return ve.ui.MWLatexDialog.super.prototype.getTeardownProcess.call( this, data )
|
|
|
|
.first( function () {
|
|
|
|
this.input.off( 'change', this.onChangeHandler );
|
|
|
|
this.displaySelect.off( 'choose', this.onChangeHandler );
|
|
|
|
this.idInput.off( 'change', this.onChangeHandler );
|
2022-05-24 16:03:46 +00:00
|
|
|
this.qidInput.off( 'change', this.onChangeHandler );
|
2017-01-11 21:50:35 +00:00
|
|
|
this.getManager().disconnect( this );
|
2018-11-12 16:15:00 +00:00
|
|
|
this.indexLayout.setTabPanel( 'formula' );
|
|
|
|
this.indexLayout.resetScroll();
|
|
|
|
this.menuLayout.resetScroll();
|
|
|
|
this.bookletLayout.resetScroll();
|
2017-01-11 21:50:35 +00:00
|
|
|
}, this );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.updateMwData = function ( mwData ) {
|
|
|
|
// Parent method
|
|
|
|
ve.ui.MWLatexDialog.super.prototype.updateMwData.call( this, mwData );
|
|
|
|
|
|
|
|
// Get data from dialog
|
2024-02-13 00:31:24 +00:00
|
|
|
const display = this.displaySelect.findSelectedItem().getData();
|
|
|
|
const id = this.idInput.getValue();
|
|
|
|
const qid = this.qidInput.getValue();
|
2017-01-11 21:50:35 +00:00
|
|
|
|
|
|
|
// Update attributes
|
|
|
|
mwData.attrs.display = display !== 'default' ? display : undefined;
|
|
|
|
mwData.attrs.id = id || undefined;
|
2022-05-24 16:03:46 +00:00
|
|
|
mwData.attrs.qid = qid || undefined;
|
2017-01-11 21:50:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.getBodyHeight = function () {
|
|
|
|
return 600;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle the window resize event
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.onWindowManagerResize = function () {
|
2024-02-13 00:31:24 +00:00
|
|
|
const dialog = this;
|
2018-01-11 14:07:29 +00:00
|
|
|
this.input.loadingPromise.always( function () {
|
2017-01-11 21:50:35 +00:00
|
|
|
// Toggle short mode as necessary
|
|
|
|
// NB a change of mode triggers a transition...
|
|
|
|
dialog.menuLayout.$element.toggleClass(
|
|
|
|
've-ui-mwLatexDialog-menuLayout-short', dialog.menuLayout.$element.height() < 450
|
|
|
|
);
|
|
|
|
|
|
|
|
// ...So wait for the possible menuLayout transition to finish
|
|
|
|
setTimeout( function () {
|
|
|
|
// Give the input the right number of rows to fit the space
|
2024-02-13 00:31:24 +00:00
|
|
|
const availableSpace = dialog.menuLayout.$content.height() - dialog.input.$element.position().top;
|
2018-06-07 23:11:59 +00:00
|
|
|
// TODO: Compute this line height from the skin
|
2024-02-13 00:31:24 +00:00
|
|
|
const singleLineHeight = 21;
|
|
|
|
const border = 1;
|
|
|
|
const padding = 3;
|
|
|
|
const borderAndPadding = 2 * ( border + padding );
|
|
|
|
const maxInputHeight = availableSpace - borderAndPadding;
|
|
|
|
const minRows = Math.floor( maxInputHeight / singleLineHeight );
|
2018-01-11 14:07:29 +00:00
|
|
|
dialog.input.loadingPromise.done( function () {
|
|
|
|
dialog.input.setMinRows( minRows );
|
|
|
|
} ).fail( function () {
|
|
|
|
dialog.input.$input.attr( 'rows', minRows );
|
|
|
|
} );
|
2017-01-11 21:50:35 +00:00
|
|
|
}, OO.ui.theme.getDialogTransitionDuration() );
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle the click event on the list
|
|
|
|
*
|
|
|
|
* @param {jQuery.Event} e Mouse click event
|
|
|
|
*/
|
|
|
|
ve.ui.MWLatexDialog.prototype.onListClick = function ( e ) {
|
2019-02-19 14:58:41 +00:00
|
|
|
if ( this.isReadOnly() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-13 00:31:24 +00:00
|
|
|
const symbol = $( e.target ).data( 'symbol' ),
|
2021-10-05 16:04:47 +00:00
|
|
|
encapsulate = symbol.encapsulate;
|
|
|
|
|
2017-01-11 21:50:35 +00:00
|
|
|
if ( encapsulate ) {
|
2024-02-13 00:31:24 +00:00
|
|
|
const range = this.input.getRange();
|
2017-01-11 21:50:35 +00:00
|
|
|
if ( range.from === range.to ) {
|
|
|
|
this.input.insertContent( encapsulate.placeholder );
|
|
|
|
this.input.selectRange( range.from, range.from + encapsulate.placeholder.length );
|
|
|
|
}
|
|
|
|
this.input.encapsulateContent( encapsulate.pre, encapsulate.post );
|
|
|
|
} else {
|
2024-02-13 00:31:24 +00:00
|
|
|
const insert = symbol.insert;
|
2017-01-11 21:50:35 +00:00
|
|
|
this.input.insertContent( insert );
|
|
|
|
}
|
|
|
|
};
|