Jiabao has uploaded a new change for review.
https://gerrit.wikimedia.org/r/85638
Change subject: MathJax Live Preview III
......................................................................
MathJax Live Preview III
Change-Id: I623eef48e40d480cc98766cf7daf75dacd0bde19
---
M modules/ve-mw/ce/nodes/ve.ce.MWMathNode.js
M modules/ve-mw/dm/nodes/ve.dm.MWMathNode.js
M modules/ve-mw/ui/inspectors/ve.ui.MWMathInspector.js
3 files changed, 234 insertions(+), 25 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor
refs/changes/38/85638/1
diff --git a/modules/ve-mw/ce/nodes/ve.ce.MWMathNode.js
b/modules/ve-mw/ce/nodes/ve.ce.MWMathNode.js
index 0c19877..a54878d 100644
--- a/modules/ve-mw/ce/nodes/ve.ce.MWMathNode.js
+++ b/modules/ve-mw/ce/nodes/ve.ce.MWMathNode.js
@@ -5,51 +5,130 @@
* @license The MIT License (MIT); see LICENSE.txt
*/
-/*global MathJax */
+/*global mw, MathJax */
/**
* ContentEditable MediaWiki math node.
*
* @class
- * @extends ve.ce.MWExtensionNode
+ * @extends ve.ce.LeafNode
+ * @mixins ve.ce.FocusableNode
+ * @mixins ve.ce.ProtectedNode
+ * @mixins ve.ce.GeneratedContentNode
*
* @constructor
* @param {ve.dm.MWMathNode} model Model to observe
* @param {Object} [config] Config options
*/
ve.ce.MWMathNode = function VeCeMWMathNode( model, config ) {
- // Parent constructor
- ve.ce.MWExtensionNode.call( this, model, config );
- // DOM changes
+ // Parent constructor
+ ve.ce.LeafNode.call( this, model, config );
+
+ // Mixin constructors
+ ve.ce.FocusableNode.call( this );
+ ve.ce.ProtectedNode.call( this );
+ ve.ce.GeneratedContentNode.call( this );
+
+ // Events
+ this.$.on( 'click', ve.bind( this.onClick, this ) );
+
+ // DOM Changes
this.$.addClass( 've-ce-mwMathNode' );
};
/* Inheritance */
-ve.inheritClass( ve.ce.MWMathNode, ve.ce.MWExtensionNode );
+ve.inheritClass( ve.ce.MWMathNode, ve.ce.LeafNode );
+
+ve.mixinClass( ve.ce.MWMathNode, ve.ce.FocusableNode );
+ve.mixinClass( ve.ce.MWMathNode, ve.ce.ProtectedNode );
+ve.mixinClass( ve.ce.MWMathNode, ve.ce.GeneratedContentNode );
/* Static Properties */
ve.ce.MWMathNode.static.name = 'mwMath';
+ve.ce.MWMathNode.static.tagName = 'span';
+
/* Methods */
/** */
+ve.ce.MWMathNode.prototype.generateContents = function ( config ) {
+ var xhr, promise, deferred = $.Deferred(),
+ wikitext = this.model.getAttribute( 'mw' ).body.extsrc;
+
+ if (config) {
+ wikitext = config.wikitext;
+ }
+ xhr = $.ajax( {
+ 'url': mw.util.wikiScript( 'api' ),
+ 'data': {
+ 'action': 'visualeditor',
+ 'paction': 'parsefragment',
+ 'page': mw.config.get( 'wgRelevantPageName' ),
+ 'wikitext': '<math>' + wikitext + '</math>',
+ 'token': mw.user.tokens.get( 'editToken' ),
+ 'format': 'json'
+ },
+ 'dataType': 'json',
+ 'type': 'POST',
+ // Wait up to 100 seconds before giving up
+ 'timeout': 100000,
+ 'cache': 'false',
+ 'success': ve.bind( this.onParseSuccess, this, deferred ),
+ 'error': ve.bind( this.onParseError, this, deferred )
+ } );
+ promise = deferred.promise();
+ promise.abort = function () {
+ xhr.abort();
+ };
+ return promise;
+};
+
+/**
+ * Handle a successful response from the parser for the wikitext fragment.
+ *
+ * @param {jQuery.Deferred} deferred The Deferred object created by
generateContents
+ * @param {Object} response Response data
+ */
ve.ce.MWMathNode.prototype.onParseSuccess = function ( deferred, response ) {
- var data = response.visualeditor, contentNodes = $( data.content
).get();
- // HACK: unwrap paragraph from PHP parser
+ var data = response.visualeditor, contentNodes = $( data.content
).get();//, self = this;
contentNodes = Array.prototype.slice.apply( contentNodes[0].childNodes
);
deferred.resolve( contentNodes );
- if ( $( contentNodes ).is( 'span.tex' ) ) {
- // MathJax
- MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub ] );
- } else {
- // Rerender after image load
- this.$.find( 'img' ).on( 'load', ve.bind( function () {
- this.emit( 'rerender' );
- }, this ) );
- }
+
+ MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, this.$[0] ] );
+};
+
+
+/**
+ * Handle an unsuccessful response from the parser for the wikitext fragment.
+ *
+ * @param {jQuery.Deferred} deferred The promise object created by
generateContents
+ * @param {Object} response Response data
+ */
+ve.ce.MWMathNode.prototype.onParseError = function ( deferred ) {
+ deferred.reject();
+};
+
+/**
+ * Handle the mouse click.
+ *
+ * @method
+ * @param {jQuery.Event} e Click event
+ */
+ve.ce.MWMathNode.prototype.onClick = function ( e ) {
+ var surfaceModel = this.getRoot().getSurface().getModel(),
+ selectionRange = surfaceModel.getSelection(),
+ nodeRange = this.model.getOuterRange();
+
+ surfaceModel.getFragment(
+ e.shiftKey ?
+ ve.Range.newCoveringRange(
+ [ selectionRange, nodeRange ],
selectionRange.from > nodeRange.from
+ ) :
+ nodeRange
+ ).select();
};
/* Registration */
diff --git a/modules/ve-mw/dm/nodes/ve.dm.MWMathNode.js
b/modules/ve-mw/dm/nodes/ve.dm.MWMathNode.js
index 622f13a..7588df9 100644
--- a/modules/ve-mw/dm/nodes/ve.dm.MWMathNode.js
+++ b/modules/ve-mw/dm/nodes/ve.dm.MWMathNode.js
@@ -9,26 +9,83 @@
* DataModel MediaWiki math node.
*
* @class
- * @extends ve.dm.MWExtensionNode
+ * @extends ve.dm.LeafNode
+ * @mixins ve.dm.GeneratedContentNode
*
* @constructor
*/
ve.dm.MWMathNode = function VeDmMWMathNode( length, element ) {
// Parent constructor
- ve.dm.MWExtensionNode.call( this, 0, element );
+ ve.dm.LeafNode.call( this, 0, element );
+
+ // Mixin constructors
+ ve.dm.GeneratedContentNode.call( this );
};
/* Inheritance */
-ve.inheritClass( ve.dm.MWMathNode, ve.dm.MWExtensionNode );
+ve.inheritClass( ve.dm.MWMathNode, ve.dm.LeafNode );
+
+ve.mixinClass( ve.dm.MWMathNode, ve.dm.GeneratedContentNode );
/* Static members */
ve.dm.MWMathNode.static.name = 'mwMath';
-ve.dm.MWMathNode.static.tagName = 'img';
+ve.dm.MWMathNode.static.enableAboutGrouping = true;
-ve.dm.MWMathNode.static.extensionName = 'math';
+ve.dm.MWMathNode.static.matchTagNames = null;
+
+ve.dm.MWMathNode.static.matchRdfaTypes = [ 'mw:Extension/math' ];
+
+ve.dm.MWMathNode.static.isContent = true;
+
+ve.dm.MWMathNode.static.toDataElement = function ( domElements, converter ) {
+ var dataElement, index,
+ mwDataJSON = domElements[0].getAttribute( 'data-mw' ),
+ mwData = mwDataJSON ? JSON.parse( mwDataJSON ) : {};
+
+ dataElement = {
+ 'type': 'mwMath',
+ 'attributes': {
+ 'mw': mwData,
+ 'originalDomElements': [ domElements[0] ],
+ 'originalMw': mwDataJSON
+ }
+ };
+
+ index = this.storeDomElements( dataElement, domElements,
converter.getStore() );
+ dataElement.attributes.originalIndex = index;
+ return dataElement;
+};
+
+ve.dm.MWMathNode.static.toDomElements = function ( dataElement, doc, converter
) {
+ var el,
+ index = converter.getStore().indexOfHash( ve.getHash(
this.getHashObject( dataElement ) ) ),
+ originalMw = dataElement.attributes.originalMw;
+
+ // If the transclusion is unchanged just send back the
+ // original DOM elements so selser can skip over it
+ if (
+ index === dataElement.attributes.originalIndex ||
+ ( originalMw && ve.compare( dataElement.attributes.mw,
JSON.parse( originalMw ) ) )
+ ) {
+ // The object in the store is also used for CE rendering so
return a copy
+ return ve.copyDomElements(
dataElement.attributes.originalDomElements, doc );
+ } else {
+ el = doc.createElement( 'img' );
+ el.setAttribute( 'typeof', 'mw:Extension/Math' );
+ el.setAttribute( 'data-mw', JSON.stringify(
dataElement.attributes.mw ) );
+ return [ el ];
+ }
+};
+
+ve.dm.MWMathNode.static.getHashObject = function ( dataElement ) {
+ return {
+ type: dataElement.type,
+ mw: dataElement.attributes.mw
+ };
+};
/* Registration */
diff --git a/modules/ve-mw/ui/inspectors/ve.ui.MWMathInspector.js
b/modules/ve-mw/ui/inspectors/ve.ui.MWMathInspector.js
index 177177f..af73629 100644
--- a/modules/ve-mw/ui/inspectors/ve.ui.MWMathInspector.js
+++ b/modules/ve-mw/ui/inspectors/ve.ui.MWMathInspector.js
@@ -36,14 +36,87 @@
ve.ui.MWMathInspector.static.nodeModel = ve.dm.MWMathNode;
+ve.ui.MWMathInspector.static.TextInputWidget = ve.ui.TextInputWidget;
+
/* Methods */
-/** */
+/**
+ * Handle frame ready events.
+ *
+ * @method
+ */
ve.ui.MWMathInspector.prototype.initialize = function () {
// Parent method
- ve.ui.MWExtensionInspector.prototype.initialize.call( this );
+ ve.ui.Inspector.prototype.initialize.call( this );
- this.input.$.addClass( 've-ui-mwMathInspector-input' );
+ this.input = new this.constructor.static.TextInputWidget( {
+ '$$': this.frame.$$, 'overlay': this.surface.$localOverlay
+ } );
+
+ this.changed = false;
+
+ this.input.on( 'change', ve.bind( this.livePreview, this ) );
+
+ // Initialization
+ this.$form.append( this.input.$ );
+};
+
+ve.ui.MWMathInspector.prototype.livePreview = function () {
+
+ var newsrc = this.input.getValue(),
+ mw = this.mathNode.getModel().getAttribute( 'mw' );
+
+ if ( mw.body.extsrc !== newsrc ) {
+ this.mathNode.forceUpdate({ 'wikitext': newsrc });
+ }
+};
+
+/**
+ * Handle the inspector being opened.
+ */
+ve.ui.MWMathInspector.prototype.onOpen = function () {
+
+ // Parent method
+ ve.ui.Inspector.prototype.onOpen.call( this );
+
+ this.mathNode = this.surface.getView().getFocusedNode();
+
+ var src = this.mathNode.getModel().getAttribute( 'mw' ).body.extsrc;
+
+ // Wait for animation to complete
+ setTimeout( ve.bind( function () {
+ // Setup input text
+ this.input.setValue( src );
+ this.input.$input.focus().select();
+ }, this ), 200 );
+};
+
+/**
+ * Handle the inspector being closed.
+ *
+ * @param {string} action Action that caused the window to be closed
+ */
+ve.ui.MWMathInspector.prototype.onClose = function ( action ) {
+
+ var newsrc = this.input.getValue(),
+ surfaceModel = this.surface.getModel(),
+ mw = this.mathNode.getModel().getAttribute( 'mw' );
+
+ // Parent method
+ ve.ui.Inspector.prototype.onClose.call( this, action );
+
+ // If change is called with no change it will unrender the mathnode
+ // If the input box is empty when closed it errors if change is called
in the onParseSuccess function
+ if ( newsrc !== '' ) {
+ if ( mw.body.extsrc !== newsrc ) {
+ mw.body.extsrc = this.input.getValue();
+ surfaceModel.change(
+ ve.dm.Transaction.newFromAttributeChanges(
+ surfaceModel.getDocument(),
this.mathNode.getOuterRange().start, { 'mw': mw }
+ )
+ );
+ }
+ }
};
/* Registration */
--
To view, visit https://gerrit.wikimedia.org/r/85638
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I623eef48e40d480cc98766cf7daf75dacd0bde19
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Jiabao <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits