mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-12-01 11:27:26 +00:00
ab2c7e3ce6
An early version of WikiEditor added a workaround for a reported bug with IE 8 where textarea scroll and selection state was lost when the contents were modified. This doesn't seem to be needed on modern versions of IE such as 11 and above and the newer 'Edge' HTML engine mode in Windows 10. Actually, I can't reproduce it in Windows 7 or XP with IE 8 either from the original bugs, but just in case it's needed on some particular version that we don't know about I've only added a check for modern IEs, which is already in use on other old-IE workarounds in the module. Bug: T88875 Change-Id: I25b667a8d8378c417441adee5d97571c71a1c8c7
599 lines
22 KiB
JavaScript
599 lines
22 KiB
JavaScript
/**
|
|
* This plugin provides a way to build a wiki-text editing user interface around a textarea.
|
|
*
|
|
* @example To intialize without any modules:
|
|
* $( 'div#edittoolbar' ).wikiEditor();
|
|
*
|
|
* @example To initialize with one or more modules, or to add modules after it's already been initialized:
|
|
* $( 'textarea#wpTextbox1' ).wikiEditor( 'addModule', 'toolbar', { ... config ... } );
|
|
*
|
|
*/
|
|
/*jshint onevar:false, boss:true */
|
|
( function ( $, mw ) {
|
|
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
/**
|
|
* Global static object for wikiEditor that provides generally useful functionality to all modules and contexts.
|
|
*/
|
|
$.wikiEditor = {
|
|
/**
|
|
* For each module that is loaded, static code shared by all instances is loaded into this object organized by
|
|
* module name. The existance of a module in this object only indicates the module is available. To check if a
|
|
* module is in use by a specific context check the context.modules object.
|
|
*/
|
|
modules: {},
|
|
|
|
/**
|
|
* A context can be extended, such as adding iframe support, on a per-wikiEditor instance basis.
|
|
*/
|
|
extensions: {},
|
|
|
|
/**
|
|
* In some cases like with the iframe's HTML file, it's convienent to have a lookup table of all instances of the
|
|
* WikiEditor. Each context contains an instance field which contains a key that corrosponds to a reference to the
|
|
* textarea which the WikiEditor was build around. This way, by passing a simple integer you can provide a way back
|
|
* to a specific context.
|
|
*/
|
|
instances: [],
|
|
|
|
/**
|
|
* For each browser name, an array of conditions that must be met are supplied in [operaton, value]-form where
|
|
* operation is a string containing a JavaScript compatible binary operator and value is either a number to be
|
|
* compared with $.browser.versionNumber or a string to be compared with $.browser.version. If a browser is not
|
|
* specifically mentioned, we just assume things will work.
|
|
*/
|
|
browsers: {
|
|
// Left-to-right languages
|
|
ltr: {
|
|
// The toolbar layout is broken in IE6
|
|
msie: [['>=', 7]],
|
|
// Layout issues in FF < 2
|
|
firefox: [['>=', 2]],
|
|
// Text selection bugs galore
|
|
opera: [['>=', 9.6]],
|
|
// jQuery minimums
|
|
safari: [['>=', 3]],
|
|
chrome: [['>=', 3]],
|
|
netscape: [['>=', 9]],
|
|
blackberry: false,
|
|
ipod: [['>=', 6]],
|
|
iphone: [['>=', 6]]
|
|
},
|
|
// Right-to-left languages
|
|
rtl: {
|
|
// The toolbar layout is broken in IE 7 in RTL mode, and IE6 in any mode
|
|
msie: [['>=', 8]],
|
|
// Layout issues in FF < 2
|
|
firefox: [['>=', 2]],
|
|
// Text selection bugs galore
|
|
opera: [['>=', 9.6]],
|
|
// jQuery minimums
|
|
safari: [['>=', 3]],
|
|
chrome: [['>=', 3]],
|
|
netscape: [['>=', 9]],
|
|
blackberry: false,
|
|
ipod: [['>=', 6]],
|
|
iphone: [['>=', 6]]
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Path to images - this is a bit messy, and it would need to change if this code (and images) gets moved into the
|
|
* core - or anywhere for that matter...
|
|
*/
|
|
imgPath: mw.config.get( 'wgExtensionAssetsPath' ) + '/WikiEditor/modules/images/',
|
|
|
|
/**
|
|
* Checks the current browser against the browsers object to determine if the browser has been black-listed or not.
|
|
* Because these rules are often very complex, the object contains configurable operators and can check against
|
|
* either the browser version number or string. This process also involves checking if the current browser is amung
|
|
* those which we have configured as compatible or not. If the browser was not configured as comptible we just go on
|
|
* assuming things will work - the argument here is to prevent the need to update the code when a new browser comes
|
|
* to market. The assumption here is that any new browser will be built on an existing engine or be otherwise so
|
|
* similar to another existing browser that things actually do work as expected. The merrits of this argument, which
|
|
* is essentially to blacklist rather than whitelist are debateable, but at this point we've decided it's the more
|
|
* "open-web" way to go.
|
|
* @param module Module object, defaults to $.wikiEditor
|
|
*/
|
|
isSupported: function ( module ) {
|
|
// Fallback to the wikiEditor browser map if no special map is provided in the module
|
|
var mod = module && 'browsers' in module ? module : $.wikiEditor;
|
|
// Check for and make use of cached value and early opportunities to bail
|
|
if ( typeof mod.supported !== 'undefined' ) {
|
|
// Cache hit
|
|
return mod.supported;
|
|
}
|
|
// Run a browser support test and then cache and return the result
|
|
return mod.supported = $.client.test( mod.browsers );
|
|
},
|
|
|
|
/**
|
|
* Checks if a module has a specific requirement
|
|
* @param module Module object
|
|
* @param requirement String identifying requirement
|
|
*/
|
|
isRequired: function ( module, requirement ) {
|
|
if ( typeof module.req !== 'undefined' ) {
|
|
for ( var req in module.req ) {
|
|
if ( module.req[req] === requirement ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Provides a way to extract messages from objects. Wraps a mediaWiki.message( ... ).plain() call.
|
|
*
|
|
* @param object Object to extract messages from
|
|
* @param property String of name of property which contains the message. This should be the base name of the
|
|
* property, which means that in the case of the object { this: 'that', fooMsg: 'bar' }, passing property as 'this'
|
|
* would return the raw text 'that', while passing property as 'foo' would return the internationalized message
|
|
* with the key 'bar'.
|
|
*/
|
|
autoMsg: function ( object, property ) {
|
|
var i, p;
|
|
// Accept array of possible properties, of which the first one found will be used
|
|
if ( typeof property === 'object' ) {
|
|
for ( i in property ) {
|
|
if ( property[i] in object || property[i] + 'Msg' in object ) {
|
|
property = property[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( property in object ) {
|
|
return object[property];
|
|
} else if ( property + 'Msg' in object ) {
|
|
p = object[property + 'Msg'];
|
|
if ( $.isArray( p ) && p.length >= 2 ) {
|
|
return mw.message.apply( mw.message, p ).plain();
|
|
} else {
|
|
return mw.message( p ).plain();
|
|
}
|
|
} else {
|
|
return '';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Provides a way to extract a property of an object in a certain language, falling back on the property keyed as
|
|
* 'default' or 'default-rtl'. If such key doesn't exist, the object itself is considered the actual value, which
|
|
* should ideally be the case so that you may use a string or object of any number of strings keyed by language
|
|
* with a default.
|
|
*
|
|
* @param object Object to extract property from
|
|
* @param lang Language code, defaults to wgUserLanguage
|
|
*/
|
|
autoLang: function ( object, lang ) {
|
|
var defaultKey = $( 'body' ).hasClass( 'rtl' ) ? 'default-rtl' : 'default';
|
|
lang = lang || mw.config.get( 'wgUserLanguage' );
|
|
return hasOwn.call( object, lang ) ? object[lang] : ( object[defaultKey] || object['default'] || object );
|
|
},
|
|
|
|
/**
|
|
* Provides a way to extract the path of an icon in a certain language, automatically appending a version number for
|
|
* caching purposes and prepending an image path when icon paths are relative.
|
|
*
|
|
* @param icon Icon object from e.g. toolbar config
|
|
* @param path Default icon path, defaults to $.wikiEditor.imgPath
|
|
* @param lang Language code, defaults to wgUserLanguage
|
|
*/
|
|
autoIcon: function ( icon, path, lang ) {
|
|
var src = $.wikiEditor.autoLang( icon, lang );
|
|
path = path || $.wikiEditor.imgPath;
|
|
// Prepend path if src is not absolute
|
|
if ( src.substr( 0, 7 ) !== 'http://' && src.substr( 0, 8 ) !== 'https://' && src[0] !== '/' ) {
|
|
src = path + src;
|
|
}
|
|
return src + '?' + mw.loader.getVersion( 'jquery.wikiEditor' );
|
|
},
|
|
|
|
/**
|
|
* Get the sprite offset for a language if available, icon for a language if available, or the default offset or icon,
|
|
* in that order of preference.
|
|
* @param icon Icon object, see autoIcon()
|
|
* @param offset Offset object
|
|
* @param path Icon path, see autoIcon()
|
|
* @param lang Language code, defaults to wgUserLanguage
|
|
*/
|
|
autoIconOrOffset: function ( icon, offset, path, lang ) {
|
|
lang = lang || mw.config.get( 'wgUserLanguage' );
|
|
if ( typeof offset === 'object' && hasOwn.call( offset, lang ) ) {
|
|
return offset[lang];
|
|
} else if ( typeof icon === 'object' && hasOwn.call( icon, lang ) ) {
|
|
return $.wikiEditor.autoIcon( icon, undefined, lang );
|
|
} else {
|
|
return $.wikiEditor.autoLang( offset, lang );
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* jQuery plugin that provides a way to initialize a wikiEditor instance on a textarea.
|
|
*/
|
|
$.fn.wikiEditor = function () {
|
|
|
|
// Skip any further work when running in browsers that are unsupported
|
|
if ( !$.wikiEditor.isSupported() ) {
|
|
return $( this );
|
|
}
|
|
|
|
// Save browser profile for detailed tests.
|
|
var profile = $.client.profile();
|
|
|
|
/* Initialization */
|
|
|
|
// The wikiEditor context is stored in the element's data, so when this function gets called again we can pick up right
|
|
// where we left off
|
|
var context = $( this ).data( 'wikiEditor-context' );
|
|
// On first call, we need to set things up, but on all following calls we can skip right to the API handling
|
|
if ( !context || typeof context === 'undefined' ) {
|
|
|
|
// Star filling the context with useful data - any jQuery selections, as usual should be named with a preceding $
|
|
context = {
|
|
// Reference to the textarea element which the wikiEditor is being built around
|
|
'$textarea': $( this ),
|
|
// Container for any number of mutually exclusive views that are accessible by tabs
|
|
'views': {},
|
|
// Container for any number of module-specific data - only including data for modules in use on this context
|
|
'modules': {},
|
|
// General place to shouve bits of data into
|
|
'data': {},
|
|
// Unique numeric ID of this instance used both for looking up and differentiating instances of wikiEditor
|
|
'instance': $.wikiEditor.instances.push( $( this ) ) - 1,
|
|
// Saved selection state for old IE (<=10)
|
|
'savedSelection': null,
|
|
// List of extensions active on this context
|
|
'extensions': []
|
|
};
|
|
|
|
/**
|
|
* Externally Accessible API
|
|
*
|
|
* These are available using calls to $( selection ).wikiEditor( call, data ) where selection is a jQuery selection
|
|
* of the textarea that the wikiEditor instance was built around.
|
|
*/
|
|
|
|
context.api = {
|
|
/**
|
|
* Activates a module on a specific context with optional configuration data.
|
|
*
|
|
* @param data Either a string of the name of a module to add without any additional configuration parameters,
|
|
* or an object with members keyed with module names and valued with configuration objects.
|
|
*/
|
|
'addModule': function ( context, data ) {
|
|
var module, call,
|
|
modules = {};
|
|
if ( typeof data === 'string' ) {
|
|
modules[data] = {};
|
|
} else if ( typeof data === 'object' ) {
|
|
modules = data;
|
|
}
|
|
for ( module in modules ) {
|
|
// Check for the existance of an available / supported module with a matching name and a create function
|
|
if ( typeof module === 'string' && typeof $.wikiEditor.modules[module] !== 'undefined' &&
|
|
$.wikiEditor.isSupported( $.wikiEditor.modules[module] ) )
|
|
{
|
|
// Extend the context's core API with this module's own API calls
|
|
if ( 'api' in $.wikiEditor.modules[module] ) {
|
|
for ( call in $.wikiEditor.modules[module].api ) {
|
|
// Modules may not overwrite existing API functions - first come, first serve
|
|
if ( !( call in context.api ) ) {
|
|
context.api[call] = $.wikiEditor.modules[module].api[call];
|
|
}
|
|
}
|
|
}
|
|
// Activate the module on this context
|
|
if ( 'fn' in $.wikiEditor.modules[module] && 'create' in $.wikiEditor.modules[module].fn ) {
|
|
// Add a place for the module to put it's own stuff
|
|
context.modules[module] = {};
|
|
// Tell the module to create itself on the context
|
|
$.wikiEditor.modules[module].fn.create( context, modules[module] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Event Handlers
|
|
*
|
|
* These act as filters returning false if the event should be ignored or returning true if it should be passed
|
|
* on to all modules. This is also where we can attach some extra information to the events.
|
|
*/
|
|
|
|
context.evt = {
|
|
/* Empty until extensions add some; see jquery.wikiEditor.iframe.js for examples. */
|
|
};
|
|
|
|
/* Internal Functions */
|
|
|
|
context.fn = {
|
|
/**
|
|
* Executes core event filters as well as event handlers provided by modules.
|
|
*/
|
|
trigger: function ( name, event ) {
|
|
// Workaround for a scrolling bug in IE8 (bug 61908)
|
|
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
|
|
context.$textarea.css( 'width', context.$textarea.parent().width() );
|
|
}
|
|
|
|
// Event is an optional argument, but from here on out, at least the type field should be dependable
|
|
if ( typeof event === 'undefined' ) {
|
|
event = { 'type': 'custom' };
|
|
}
|
|
// Ensure there's a place for extra information to live
|
|
if ( typeof event.data === 'undefined' ) {
|
|
event.data = {};
|
|
}
|
|
|
|
// Allow filtering to occur
|
|
if ( name in context.evt ) {
|
|
if ( !context.evt[name]( event ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
var returnFromModules = null; //they return null by default
|
|
// Pass the event around to all modules activated on this context
|
|
|
|
for ( var module in context.modules ) {
|
|
if (
|
|
module in $.wikiEditor.modules &&
|
|
'evt' in $.wikiEditor.modules[module] &&
|
|
name in $.wikiEditor.modules[module].evt
|
|
) {
|
|
var ret = $.wikiEditor.modules[module].evt[name]( context, event );
|
|
if ( ret !== null ) {
|
|
//if 1 returns false, the end result is false
|
|
if ( returnFromModules === null ) {
|
|
returnFromModules = ret;
|
|
} else {
|
|
returnFromModules = returnFromModules && ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( returnFromModules !== null ) {
|
|
return returnFromModules;
|
|
} else {
|
|
return true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Adds a button to the UI
|
|
*/
|
|
addButton: function ( options ) {
|
|
// Ensure that buttons and tabs are visible
|
|
context.$controls.show();
|
|
context.$buttons.show();
|
|
return $( '<button>' )
|
|
.text( $.wikiEditor.autoMsg( options, 'caption' ) )
|
|
.click( options.action )
|
|
.appendTo( context.$buttons );
|
|
},
|
|
|
|
/**
|
|
* Adds a view to the UI, which is accessed using a set of tabs. Views are mutually exclusive and by default a
|
|
* wikitext view will be present. Only when more than one view exists will the tabs will be visible.
|
|
*/
|
|
addView: function ( options ) {
|
|
// Adds a tab
|
|
function addTab( options ) {
|
|
// Ensure that buttons and tabs are visible
|
|
context.$controls.show();
|
|
context.$tabs.show();
|
|
// Return the newly appended tab
|
|
return $( '<div>' )
|
|
.attr( 'rel', 'wikiEditor-ui-view-' + options.name )
|
|
.addClass( context.view === options.name ? 'current' : null )
|
|
.append( $( '<a>' )
|
|
.attr( 'href', '#' )
|
|
.mousedown( function () {
|
|
// No dragging!
|
|
return false;
|
|
} )
|
|
.click( function ( event ) {
|
|
context.$ui.find( '.wikiEditor-ui-view' ).hide();
|
|
context.$ui.find( '.' + $( this ).parent().attr( 'rel' ) ).show();
|
|
context.$tabs.find( 'div' ).removeClass( 'current' );
|
|
$( this ).parent().addClass( 'current' );
|
|
$( this ).blur();
|
|
if ( 'init' in options && typeof options.init === 'function' ) {
|
|
options.init( context );
|
|
}
|
|
event.preventDefault();
|
|
return false;
|
|
} )
|
|
.text( $.wikiEditor.autoMsg( options, 'title' ) )
|
|
)
|
|
.appendTo( context.$tabs );
|
|
}
|
|
// Automatically add the previously not-needed wikitext tab
|
|
if ( !context.$tabs.children().length ) {
|
|
addTab( { 'name': 'wikitext', 'titleMsg': 'wikieditor-wikitext-tab' } );
|
|
}
|
|
// Add the tab for the view we were actually asked to add
|
|
addTab( options );
|
|
// Return newly appended view
|
|
return $( '<div>' )
|
|
.addClass( 'wikiEditor-ui-view wikiEditor-ui-view-' + options.name )
|
|
.hide()
|
|
.appendTo( context.$ui );
|
|
},
|
|
|
|
/**
|
|
* Save scrollTop and cursor position for old IE (<=10)
|
|
* Related to old IE 8 issues that are no longer reproducible
|
|
*/
|
|
saveCursorAndScrollTop: function () {
|
|
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
|
|
var IHateIE8 = {
|
|
'scrollTop': context.$textarea.scrollTop(),
|
|
'pos': context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } )
|
|
};
|
|
context.$textarea.data( 'IHateIE8', IHateIE8 );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Restore scrollTo and cursor position for IE (<=10)
|
|
* Related to old IE 8 issues that are no longer reproducible
|
|
*/
|
|
restoreCursorAndScrollTop: function () {
|
|
if ( profile.name === 'msie' && document.selection && document.selection.createRange ) {
|
|
var IHateIE8 = context.$textarea.data( 'IHateIE' );
|
|
if ( IHateIE8 ) {
|
|
context.$textarea.scrollTop( IHateIE8.scrollTop );
|
|
context.$textarea.textSelection( 'setSelection', { start: IHateIE8.pos[0], end: IHateIE8.pos[1] } );
|
|
context.$textarea.data( 'IHateIE8', null );
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Save text selection for old IE (<=10)
|
|
*/
|
|
saveSelection: function () {
|
|
if ( $.client.profile().name === 'msie' && document.selection && document.selection.createRange ) {
|
|
context.$textarea.focus();
|
|
context.savedSelection = document.selection.createRange();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Restore text selection for old IE (<=10)
|
|
*/
|
|
restoreSelection: function () {
|
|
if ( $.client.profile().name === 'msie' && context.savedSelection !== null ) {
|
|
context.$textarea.focus();
|
|
context.savedSelection.select();
|
|
context.savedSelection = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Workaround for a scrolling bug in IE8 (bug 61908)
|
|
*/
|
|
if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
|
|
context.$textarea.css( 'height', context.$textarea.height() );
|
|
context.$textarea.css( 'width', context.$textarea.parent().width() );
|
|
}
|
|
|
|
/**
|
|
* Base UI Construction
|
|
*
|
|
* The UI is built from several containers, the outer-most being a div classed as "wikiEditor-ui". These containers
|
|
* provide a certain amount of "free" layout, but in some situations procedural layout is needed, which is performed
|
|
* as a response to the "resize" event.
|
|
*/
|
|
|
|
// Assemble a temporary div to place over the wikiEditor while it's being constructed
|
|
/* Disabling our loading div for now
|
|
var $loader = $( '<div>' )
|
|
.addClass( 'wikiEditor-ui-loading' )
|
|
.append( $( '<span>' + mediaWiki.msg( 'wikieditor-loading' ) + '</span>' )
|
|
.css( 'marginTop', context.$textarea.height() / 2 ) );
|
|
*/
|
|
/* Preserving cursor and focus state, which will get lost due to wrapAll */
|
|
var hasFocus = context.$textarea.is( ':focus' ),
|
|
cursorPos = context.$textarea.textSelection( 'getCaretPosition', { startAndEnd: true } );
|
|
// Encapsulate the textarea with some containers for layout
|
|
context.$textarea
|
|
/* Disabling our loading div for now
|
|
.after( $loader )
|
|
.add( $loader )
|
|
*/
|
|
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui' ) )
|
|
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-view wikiEditor-ui-view-wikitext' ) )
|
|
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-left' ) )
|
|
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-bottom' ) )
|
|
.wrapAll( $( '<div>' ).addClass( 'wikiEditor-ui-text' ) );
|
|
// Restore scroll position after this wrapAll (tracked by mediawiki.action.edit)
|
|
context.$textarea.prop( 'scrollTop', $( '#wpScrolltop' ).val() );
|
|
// Restore focus and cursor if needed
|
|
if ( hasFocus ) {
|
|
context.$textarea.focus();
|
|
context.$textarea.textSelection( 'setSelection', { start: cursorPos[0], end: cursorPos[1] } );
|
|
}
|
|
|
|
// Get references to some of the newly created containers
|
|
context.$ui = context.$textarea.parent().parent().parent().parent().parent();
|
|
context.$wikitext = context.$textarea.parent().parent().parent().parent();
|
|
// Add in tab and button containers
|
|
context.$wikitext
|
|
.before(
|
|
$( '<div>' ).addClass( 'wikiEditor-ui-controls' )
|
|
.append( $( '<div>' ).addClass( 'wikiEditor-ui-tabs' ).hide() )
|
|
.append( $( '<div>' ).addClass( 'wikiEditor-ui-buttons' ) )
|
|
)
|
|
.before( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
|
|
// Get references to some of the newly created containers
|
|
context.$controls = context.$ui.find( '.wikiEditor-ui-buttons' ).hide();
|
|
context.$buttons = context.$ui.find( '.wikiEditor-ui-buttons' );
|
|
context.$tabs = context.$ui.find( '.wikiEditor-ui-tabs' );
|
|
// Clear all floating after the UI
|
|
context.$ui.after( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
|
|
// Attach a right container
|
|
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-right' ) );
|
|
context.$wikitext.append( $( '<div>' ).addClass( 'wikiEditor-ui-clear' ) );
|
|
// Attach a top container to the left pane
|
|
context.$wikitext.find( '.wikiEditor-ui-left' ).prepend( $( '<div>' ).addClass( 'wikiEditor-ui-top' ) );
|
|
// Setup the intial view
|
|
context.view = 'wikitext';
|
|
// Trigger the "resize" event anytime the window is resized
|
|
$( window ).resize( function ( event ) {
|
|
context.fn.trigger( 'resize', event );
|
|
} );
|
|
}
|
|
|
|
/* API Execution */
|
|
|
|
// Since javascript gives arguments as an object, we need to convert them so they can be used more easily
|
|
var args = $.makeArray( arguments );
|
|
|
|
// Dynamically setup core extensions for modules that are required
|
|
if ( args[0] === 'addModule' && typeof args[1] !== 'undefined' ) {
|
|
var modules = args[1];
|
|
if ( typeof modules !== 'object' ) {
|
|
modules = {};
|
|
modules[args[1]] = '';
|
|
}
|
|
for ( var module in modules ) {
|
|
// Only allow modules which are supported (and thus actually being turned on) affect the decision to extend
|
|
if ( module in $.wikiEditor.modules && $.wikiEditor.isSupported( $.wikiEditor.modules[module] ) ) {
|
|
// Activate all required core extensions on context
|
|
for ( var e in $.wikiEditor.extensions ) {
|
|
if (
|
|
$.wikiEditor.isRequired( $.wikiEditor.modules[module], e ) &&
|
|
$.inArray( e, context.extensions ) === -1
|
|
) {
|
|
context.extensions[context.extensions.length] = e;
|
|
$.wikiEditor.extensions[e]( context );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// There would need to be some arguments if the API is being called
|
|
if ( args.length > 0 ) {
|
|
// Handle API calls
|
|
var call = args.shift();
|
|
if ( call in context.api ) {
|
|
context.api[call]( context, typeof args[0] === 'undefined' ? {} : args[0] );
|
|
}
|
|
}
|
|
|
|
// Store the context for next time, and support chaining
|
|
return $( this ).data( 'wikiEditor-context', context );
|
|
|
|
};
|
|
|
|
}( jQuery, mediaWiki ) );
|