mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 23:05:35 +00:00
f06952f2f3
Refactor: * ve.indexOf Renamed from ve.inArray. This was named after the jQuery method which in turn has a longer story about why it is so unfortunately named. It doesn't return a boolean, but an index. Hence the native method being called indexOf as well. * ve.bind Renamed from ve.proxy. I considered making it use Function.prototype.bind if available. As it performs better than $.proxy (which doesn't use to the native bind if available). However since bind needs to be bound itself in order to use it detached, it turns out with the "call()" and "bind()" it is slower than the $.proxy shim: http://jsperf.com/function-bind-shim-perf It would've been like this: ve.bind = Function.prototype.bind ? Function.prototype.call.bind( Function.prototype.bind ) : $.proxy; But instead sticking to ve.bind = $.proxy; * ve.extendObject Documented the parts of jQuery.extend that we use. This makes it easier to replace in the future. Documentation: * Added function documentation blocks. * Added annotations to functions that we will be able to remove in the future in favour of the native methods. With "@until + when/how". In this case "ES5". Meaning, whenever we drop support for browsers that don't support ES5. Although in the developer community ES5 is still fairly fresh, browsers have been aware for it long enough that thee moment we're able to drop it may be sooner than we think. The only blocker so far is IE8. The rest of the browsers have had it long enough that the traffic we need to support of non-IE supports it. Misc.: * Removed 'node: true' from .jshintrc since Parsoid is no longer in this repo and thus no more nodejs files. - This unraveled two lint errors: Usage of 'module' and 'console'. (both were considered 'safe globals' due to nodejs, but not in browser code). * Replaced usage (before renaming): - $.inArray -> ve.inArray - Function.prototype.bind -> ve.proxy - Array.isArray -> ve.isArray - [].indexOf -> ve.inArray - $.fn.bind/live/delegate/unbind/die/delegate -> $.fn.on/off Change-Id: Idcf1fa6a685b6ed3d7c99ffe17bd57a7bc586a2c
247 lines
6.7 KiB
JavaScript
247 lines
6.7 KiB
JavaScript
/*global mw */
|
|
|
|
/**
|
|
* VisualEditor MediaWiki initialization Target class.
|
|
*
|
|
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* MediaWiki target.
|
|
*
|
|
* @class
|
|
* @constructor
|
|
* @param {String} pageName Name of target page
|
|
*/
|
|
ve.init.mw.Target = function ( pageName ) {
|
|
// Inheritance
|
|
ve.EventEmitter.call( this );
|
|
|
|
// Properties
|
|
this.pageName = pageName;
|
|
this.editToken = mw.user.tokens.get( 'editToken' );
|
|
this.apiUrl = mw.util.wikiScript( 'api' );
|
|
this.modules = ['ext.visualEditor.core', 'ext.visualEditor.specialMessages'];
|
|
this.loading = false;
|
|
this.saving = false;
|
|
this.dom = null;
|
|
this.isMobileDevice = (
|
|
'ontouchstart' in window ||
|
|
( window.DocumentTouch && document instanceof window.DocumentTouch )
|
|
);
|
|
};
|
|
|
|
/* Static Methods */
|
|
|
|
/**
|
|
* Handle response to a successful load request.
|
|
*
|
|
* This method is called within the context of a target instance. If successful the DOM from the
|
|
* server will be parsed, stored in {this.dom} and then {ve.init.mw.Target.onReady} will be called once
|
|
* the modules are ready.
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {Object} response XHR Response object
|
|
* @param {String} status Text status message
|
|
* @emits loadError (null, message, null)
|
|
*/
|
|
ve.init.mw.Target.onLoad = function ( response, status ) {
|
|
var data = response['ve-parsoid'];
|
|
if ( !data ) {
|
|
this.loading = false;
|
|
this.emit( 'loadError', null, 'Invalid response from server', null );
|
|
} else if ( typeof data.result === 'error' ) {
|
|
this.loading = false;
|
|
this.emit( 'loadError', null, 'Server error', null );
|
|
} else if ( typeof data.parsed !== 'string' ) {
|
|
this.loading = false;
|
|
this.emit( 'loadError', null, 'No HTML content in response from server', null );
|
|
} else {
|
|
this.dom = $( '<div>' ).html( data.parsed )[0];
|
|
// Everything worked, the page was loaded, continue as soon as the module is ready
|
|
mw.loader.using( this.modules, ve.bind( ve.init.mw.Target.onReady, this ) );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle both DOM and modules being loaded and ready.
|
|
*
|
|
* This method is called within the context of a target instance. After the load event is emitted
|
|
* this.dom is cleared, allowing it to be garbage collected.
|
|
*
|
|
* @static
|
|
* @method
|
|
* @emits load (dom)
|
|
*/
|
|
ve.init.mw.Target.onReady = function () {
|
|
this.loading = false;
|
|
this.emit( 'load', this.dom );
|
|
// Release DOM data
|
|
this.dom = null;
|
|
};
|
|
|
|
/**
|
|
* Handle response to a successful load request.
|
|
*
|
|
* This method is called within the context of a target instance.
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {Object} response XHR Response object
|
|
* @param {String} status Text status message
|
|
* @param {Mixed} error Thrown exception or HTTP error string
|
|
* @emits loadError (response, text, exception)
|
|
*/
|
|
ve.init.mw.Target.onLoadError = function ( response, text, exception ) {
|
|
this.loading = false;
|
|
this.emit( 'loadError', response, text, exception );
|
|
};
|
|
|
|
/**
|
|
* Handle response to a successful save request.
|
|
*
|
|
* This method is called within the context of a target instance.
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {Object} response XHR Response object
|
|
* @param {String} status Text status message
|
|
* @emits save (html)
|
|
* @emits saveError (null, message, null)
|
|
*/
|
|
ve.init.mw.Target.onSave = function ( response, status ) {
|
|
this.saving = false;
|
|
var data = response['ve-parsoid'];
|
|
if ( !data ) {
|
|
this.emit( 'saveError', null, 'Invalid response from server', null );
|
|
} else if ( data.result !== 'success' ) {
|
|
this.emit( 'saveError', null, 'Unsuccessful request: ' + data.result, null );
|
|
} else if ( typeof data.content !== 'string' ) {
|
|
this.emit( 'saveError', null, 'Invalid HTML content in response from server', null );
|
|
} else {
|
|
this.emit( 'save', data.content );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle response to a successful save request.
|
|
*
|
|
* This method is called within the context of a target instance.
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {Object} data HTTP Response object
|
|
* @param {String} status Text status message
|
|
* @param {Mixed} error Thrown exception or HTTP error string
|
|
* @emits saveError (response, status, error)
|
|
*/
|
|
ve.init.mw.Target.onSaveError = function ( response, status, error ) {
|
|
this.saving = false;
|
|
this.emit( 'saveError', response, status, error );
|
|
};
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* Gets DOM from Parsoid API.
|
|
*
|
|
* This method performs an asynchronous action and uses a callback function to handle the result.
|
|
*
|
|
* @example
|
|
* target.loadDom(
|
|
* function ( error, dom ) {
|
|
* // Handle errors and do something with the loaded DOM
|
|
* }
|
|
* );
|
|
*
|
|
* @method
|
|
* @param {Function} callback Function to call when complete, accepts error and dom arguments
|
|
* @returns {Boolean} Loading is now in progress
|
|
*/
|
|
ve.init.mw.Target.prototype.load = function () {
|
|
// Prevent duplicate requests
|
|
if ( this.loading ) {
|
|
return false;
|
|
}
|
|
// Start loading the module immediately
|
|
mw.loader.load( this.modules );
|
|
// Load DOM
|
|
this.loading = true;
|
|
$.ajax( {
|
|
'url': this.apiUrl,
|
|
'data': {
|
|
'action': 've-parsoid',
|
|
'paction': 'parse',
|
|
'page': this.pageName,
|
|
'format': 'json'
|
|
},
|
|
'dataType': 'json',
|
|
'type': 'GET',
|
|
// Wait up to 10 seconds before giving up
|
|
'timeout': 10000,
|
|
'cache': 'false',
|
|
'success': ve.bind( ve.init.mw.Target.onLoad, this ),
|
|
'error': ve.bind( ve.init.mw.Target.onLoadError, this )
|
|
} );
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Posts DOM to Parsoid API.
|
|
*
|
|
* This method performs an asynchronous action and uses a callback function to handle the result.
|
|
*
|
|
* @example
|
|
* target.saveDom(
|
|
* dom,
|
|
* { 'summary': 'test', 'minor': true, 'watch': false },
|
|
* function ( error, html ) {
|
|
* // Handle errors and do something with the rendered HTML
|
|
* }
|
|
* );
|
|
*
|
|
* @method
|
|
* @param {HTMLElement} dom DOM to save
|
|
* @param {Object} options Saving options
|
|
* - {String} summary Edit summary
|
|
* - {Boolean} minor Edit is a minor edit
|
|
* - {Boolean} watch Watch this page
|
|
* @param {Function} callback Function to call when complete, accepts error and html arguments
|
|
* @returns {Boolean} Saving is now in progress
|
|
*/
|
|
ve.init.mw.Target.prototype.save = function ( dom, options ) {
|
|
// Prevent duplicate requests
|
|
if ( this.saving ) {
|
|
return false;
|
|
}
|
|
// Save DOM
|
|
this.saving = true;
|
|
$.ajax( {
|
|
'url': this.apiUrl,
|
|
'data': {
|
|
'format': 'json',
|
|
'action': 've-parsoid',
|
|
'paction': 'save',
|
|
'page': this.pageName,
|
|
'html': $( dom ).html(),
|
|
'token': this.editToken,
|
|
'summary': options.summary,
|
|
'minor': options.minor,
|
|
'watch': options.watch
|
|
},
|
|
'dataType': 'json',
|
|
'type': 'POST',
|
|
// Wait up to 10 seconds before giving up
|
|
'timeout': 10000,
|
|
'success': ve.bind( ve.init.mw.Target.onSave, this ),
|
|
'error': ve.bind( ve.init.mw.Target.onSaveError, this )
|
|
} );
|
|
return true;
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
ve.extendClass( ve.init.mw.Target, ve.EventEmitter );
|