* Adding configuration files for jsduck.
* Fixing our previously undocumented code documentation to comply
with jsduck specifications
.. for the following modules:
- mediawiki
- mediawiki.Title
- mediawiki.util
- mediawiki.notification
- mediawiki.api (and plugins thereof)
- jquery.localize
I've choose these to show as many different examples for
different types of modules and methods that we encounter
in our code base.
Hopefully with this as a start it will be easy for other people
to extend the documentation for most (if not, all) other modules
we have in MediaWiki core.
Change-Id: Ieb8c5d2d2cb4672f1d6abc3f865c6fb1470d8feb
# MediaWiki install & usage
cache
+docs/js
images/[0-9a-f]
images/archive
images/deleted
doc:
php mwdocgen.php --all
- @echo 'Doc generation done. Look at ./docs/html/'
+ ./mwjsduck-gen
+ @echo 'PHP documentation (by Doxygen) in ./docs/html/'
+ @echo 'JS documentation (by JSDuck) in ./docs/js/'
man:
php mwdocgen.php --all --generate-man
--- /dev/null
+# See also:
+# - https://github.com/senchalabs/jsduck/wiki/Tags
+# - https://github.com/senchalabs/jsduck/wiki/Custom-tags
+require 'jsduck/meta_tag'
+
+class ContextTag < JsDuck::MetaTag
+ def initialize
+ @name = 'context'
+ end
+
+ # @param tags All matches of this tag on one class.
+ def to_html(tags)
+ return '<h3 class="pa">Context</h3>' + render_long_context(tags.last)
+ end
+
+ def render_long_context(tag)
+ if tag =~ /\A([^\s]+)/m
+ name = $1
+ return format("`this` : {@link #{name}}")
+ end
+ end
+end
+
+class SeeTag < JsDuck::MetaTag
+ def initialize
+ @name = 'see'
+ @multiline = true
+ end
+
+ # @param tags All matches of this tag on one class.
+ def to_html(tags)
+ doc = []
+ doc << '<h3 class="pa">Related</h3>'
+ doc << [
+ '<ul>',
+ tags.map {|tag| render_long_see(tag) },
+ '</ul>',
+ ]
+ doc
+ end
+
+ def render_long_see(tag)
+ if tag =~ /\A([^\s]+)( .*)?\Z/m
+ name = $1
+ doc = $2 ? ': ' + $2 : ''
+ return [
+ '<li>',
+ format("{@link #{name}} #{doc}"),
+ '</li>'
+ ]
+ end
+ end
+end
--- /dev/null
+[
+ {
+ "name": "MediaWiki",
+ "groups": [
+ {
+ "name": "Base",
+ "classes": [
+ "mw",
+ "mw.Map",
+ "mw.Message",
+ "mw.loader",
+ "mw.html",
+ "mw.html.Cdata",
+ "mw.html.Raw"
+ ]
+ },
+ {
+ "name": "General",
+ "classes": [
+ "mw.Title",
+ "mw.notification",
+ "mw.util",
+ "mw.plugin.notify"
+ ]
+ },
+ {
+ "name": "API",
+ "classes": ["mw.Api*"]
+ }
+ ]
+ },
+ {
+ "name": "jQuery",
+ "groups": [
+ {
+ "name": "Core",
+ "classes": ["jQuery", "jQuery.Event", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR"]
+ },
+ {
+ "name": "Plugins",
+ "classes": ["jQuery.plugin.*"]
+ }
+ ]
+ },
+ {
+ "name": "Misc",
+ "groups": [
+ {
+ "name": "Native",
+ "classes": ["Array", "Boolean", "Date", "Function", "Number", "Object", "RegExp", "String"]
+ }
+ ]
+ }
+]
--- /dev/null
+{
+ "--title": "MediaWiki Code Documentation",
+ "--categories": "./categories.json",
+ "--meta-tags": "./MetaTags.rb",
+ "--warnings": ["-no_doc"],
+ "--builtin-classes": true,
+ "--output": "../../docs/js",
+ "--": [
+ "./external.js",
+ "../../resources/mediawiki/mediawiki.js",
+ "../../resources/mediawiki/mediawiki.util.js",
+ "../../resources/mediawiki/mediawiki.Title.js",
+ "../../resources/mediawiki/mediawiki.notify.js",
+ "../../resources/mediawiki/mediawiki.notification.js",
+ "../../resources/mediawiki.api",
+ "../../resources/jquery/jquery.localize.js"
+ ]
+}
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>MediaWiki Examples</title>
+ <script>
+ function loadInlineExample(code, options, callback) {
+ try {
+ document.body.innerHTML = '';
+ eval(code);
+ callback && callback(true);
+ } catch (e) {
+ document.body.innerHTML = document.createTextNode(e);
+ callback && callback(false, e);
+ }
+ }
+ </script>
+</head>
+<body></body>
+</html>
--- /dev/null
+/**
+ * @class jQuery
+ */
+
+/**
+ * @method ajax
+ * @return {jqXHR}
+ */
+
+/**
+ * @class jQuery.Event
+ */
+
+/**
+ * @class jQuery.Promise
+ */
+
+/**
+ * @class jQuery.Deferred
+ * @mixins jQuery.Promise
+ */
+
+/**
+ * @class jQuery.jqXHR
+ * @alternateClassName jqXHR
+ */
--- /dev/null
+#!/usr/bin/env sh
+jsduck --config=$(cd $(dirname $0)/..; pwd)/maintenance/jsduck/config.json && echo 'JSDuck execution finished.'
/**
- * Simple Placeholder-based Localization
+ * @class jQuery.plugin.localize
+ */
+( function ( $, mw ) {
+
+/**
+ * Gets a localized message, using parameters from options if present.
+ * @ignore
+ *
+ * @param {Object} options
+ * @param {string} key
+ * @returns {string} Localized message
+ */
+function msg( options, key ) {
+ var args = options.params[key] || [];
+ // Format: mw.msg( key [, p1, p2, ...] )
+ args.unshift( options.prefix + ( options.keys[key] || key ) );
+ return mw.msg.apply( mw, args );
+}
+
+/**
+ * Localizes a DOM selection by replacing <html:msg /> elements with localized text and adding
+ * localized title and alt attributes to elements with title-msg and alt-msg attributes
+ * respectively.
*
- * Call on a selection of HTML which contains <html:msg key="message-key" /> elements or elements
+ * Call on a selection of HTML which contains `<html:msg key="message-key" />` elements or elements
* with title-msg="message-key", alt-msg="message-key" or placeholder-msg="message-key" attributes.
- * <html:msg /> elements will be replaced with localized text, *-msg attributes will be replaced
+ * `<html:msg />` elements will be replaced with localized text, *-msg attributes will be replaced
* with attributes that do not have the "-msg" suffix and contain a localized message.
*
* Example:
* Appends something like this to the body...
* <p>You may not get there all in one piece.</p>
*
- */
-( function ( $, mw ) {
-
-/**
- * Gets a localized message, using parameters from options if present.
- *
- * @function
- * @param {String} key Message key to get localized message for
- * @returns {String} Localized message
- */
-function msg( options, key ) {
- var args = options.params[key] || [];
- // Format: mw.msg( key [, p1, p2, ...] )
- args.unshift( options.prefix + ( options.keys[key] || key ) );
- return mw.msg.apply( mw, args );
-}
-
-/**
- * Localizes a DOM selection by replacing <html:msg /> elements with localized text and adding
- * localized title and alt attributes to elements with title-msg and alt-msg attributes
- * respectively.
- *
* @method
* @param {Object} options Map of options to be used while localizing
- * @param {String} options.prefix String to prepend to all message keys
+ * @param {string} options.prefix String to prepend to all message keys
* @param {Object} options.keys Message key aliases, used for remapping keys to a template
* @param {Object} options.params Lists of parameters to use with certain message keys
- * @returns {jQuery} This selection
+ * @return {jQuery}
*/
$.fn.localize = function ( options ) {
var $target = this,
// Let IE know about the msg tag before it's used...
document.createElement( 'msg' );
+/**
+ * @class jQuery
+ * @mixins jQuery.plugin.localize
+ */
+
}( jQuery, mediaWiki ) );
/**
- * Additional mw.Api methods to assist with API calls related to categories.
+ * @class mw.Api.plugin.category
*/
( function ( mw, $ ) {
$.extend( mw.Api.prototype, {
/**
* Determine if a category exists.
- * @param title {mw.Title}
- * @param success {Function} callback to pass boolean of category's existence
- * @param err {Function} optional callback to run if api error
- * @return ajax call object
+ * @param {mw.Title} title
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {boolean} return.done.isCategory Whether the category exists.
*/
- isCategory: function ( title, success, err ) {
- var params, ok;
- params = {
- prop: 'categoryinfo',
- titles: title.toString()
- };
- ok = function ( data ) {
- var exists = false;
- if ( data.query && data.query.pages ) {
- $.each( data.query.pages, function ( id, page ) {
- if ( page.categoryinfo ) {
- exists = true;
- }
- } );
- }
- success( exists );
- };
+ isCategory: function ( title, ok, err ) {
+ var d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
- return this.get( params, { ok: ok, err: err } );
+ this.get( {
+ prop: 'categoryinfo',
+ titles: title.toString()
+ } )
+ .done( function ( data ) {
+ var exists = false;
+ if ( data.query && data.query.pages ) {
+ $.each( data.query.pages, function ( id, page ) {
+ if ( page.categoryinfo ) {
+ exists = true;
+ }
+ } );
+ }
+ d.resolve( exists );
+ })
+ .fail( d.reject );
+
+ return d.promise();
},
/**
* Get a list of categories that match a certain prefix.
* e.g. given "Foo", return "Food", "Foolish people", "Foosball tables" ...
- * @param prefix {String} prefix to match
- * @param success {Function} callback to pass matched categories to
- * @param err {Function} optional callback to run if api error
- * @return {jqXHR}
+ * @param {string} prefix Prefix to match.
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {String[]} return.done.categories Matched categories
*/
- getCategoriesByPrefix: function ( prefix, success, err ) {
+ getCategoriesByPrefix: function ( prefix, ok, err ) {
+ var d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
+
// Fetch with allpages to only get categories that have a corresponding description page.
- var params, ok;
- params = {
- 'list': 'allpages',
- 'apprefix': prefix,
- 'apnamespace': mw.config.get('wgNamespaceIds').category
- };
- ok = function ( data ) {
- var texts = [];
- if ( data.query && data.query.allpages ) {
- $.each( data.query.allpages, function ( i, category ) {
- texts.push( new mw.Title( category.title ).getNameText() );
- } );
- }
- success( texts );
- };
+ this.get( {
+ list: 'allpages',
+ apprefix: prefix,
+ apnamespace: mw.config.get('wgNamespaceIds').category
+ } )
+ .done( function ( data ) {
+ var texts = [];
+ if ( data.query && data.query.allpages ) {
+ $.each( data.query.allpages, function ( i, category ) {
+ texts.push( new mw.Title( category.title ).getNameText() );
+ } );
+ }
+ d.resolve( texts );
+ })
+ .fail( d.reject );
- return this.get( params, { ok: ok, err: err } );
+ return d.promise();
},
/**
* Get the categories that a particular page on the wiki belongs to
- * @param title {mw.Title}
- * @param success {Function} callback to pass categories to (or false, if title not found)
- * @param err {Function} optional callback to run if api error
- * @param async {Boolean} optional asynchronousness (default = true = async)
- * @return {jqXHR}
+ * @param {mw.Title} title
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @param {boolean} [async=true] Asynchronousness
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {boolean|mw.Title[]} return.done.categories List of category titles or false
+ * if title was not found.
*/
- getCategories: function ( title, success, err, async ) {
- var params, ok;
- params = {
- prop: 'categories',
- titles: title.toString()
- };
- if ( async === undefined ) {
- async = true;
- }
- ok = function ( data ) {
- var ret = false;
- if ( data.query && data.query.pages ) {
- $.each( data.query.pages, function ( id, page ) {
- if ( page.categories ) {
- if ( typeof ret !== 'object' ) {
- ret = [];
+ getCategories: function ( title, ok, err, async ) {
+ var d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
+
+ this.get( {
+ prop: 'categories',
+ titles: title.toString()
+ }, {
+ async: async === undefined ? true : async
+ } )
+ .done( function ( data ) {
+ var ret = false;
+ if ( data.query && data.query.pages ) {
+ $.each( data.query.pages, function ( id, page ) {
+ if ( page.categories ) {
+ if ( typeof ret !== 'object' ) {
+ ret = [];
+ }
+ $.each( page.categories, function ( i, cat ) {
+ ret.push( new mw.Title( cat.title ) );
+ } );
}
- $.each( page.categories, function ( i, cat ) {
- ret.push( new mw.Title( cat.title ) );
- } );
- }
- } );
- }
- success( ret );
- };
+ } );
+ }
+ d.resolve( ret );
+ })
+ .fail( d.reject );
- return this.get( params, { ok: ok, err: err, async: async } );
+ return d.promise();
}
} );
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.category
+ */
+
}( mediaWiki, jQuery ) );
/**
- * Additional mw.Api methods to assist with API calls related to editing wiki pages.
+ * @class mw.Api.plugin.edit
*/
( function ( mw, $ ) {
* If we have a cached token try using that, and if it fails, blank out the
* cached token and start over.
*
- * @param params {Object} API parameters
- * @param ok {Function} callback for success
- * @param err {Function} [optional] error callback
- * @return {jqXHR}
+ * @param {Object} params API parameters
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @return {jQuery.Promise} See #post
*/
postWithEditToken: function ( params, ok, err ) {
var useTokenToPost, getTokenIfBad,
},
/**
- * Api helper to grab an edit token
+ * Api helper to grab an edit token.
*
- * token callback has signature ( String token )
- * error callback has signature ( String code, Object results, XmlHttpRequest xhr, Exception exception )
- * Note that xhr and exception are only available for 'http_*' errors
- * code may be any http_* error code (see mw.Api), or 'token_missing'
- *
- * @param tokenCallback {Function} received token callback
- * @param err {Function} error callback
- * @return {jqXHR}
+ * @param {Function} [ok] Success callback
+ * @param {Function} [err] Error callback
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {string} return.done.token Received token.
*/
- getEditToken: function ( tokenCallback, err ) {
- var parameters = {
+ getEditToken: function ( ok, err ) {
+ var d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
+
+ this.get( {
action: 'tokens',
type: 'edit'
- },
- ok = function ( data ) {
+ }, {
+ // Due to the API assuming we're logged out if we pass the callback-parameter,
+ // we have to disable jQuery's callback system, and instead parse JSON string,
+ // by setting 'jsonp' to false.
+ // TODO: This concern seems genuine but no other module has it. Is it still
+ // needed and/or should we pass this by default?
+ jsonp: false
+ } )
+ .done( function ( data ) {
var token;
// If token type is not available for this user,
// key 'edittoken' is missing or can contain Boolean false
if ( data.tokens && data.tokens.edittoken ) {
token = data.tokens.edittoken;
cachedToken = token;
- tokenCallback( token );
+ d.resolve( token );
} else {
- err( 'token-missing', data );
+ d.reject( 'token-missing', data );
}
- },
- ajaxOptions = {
- ok: ok,
- err: err,
- // Due to the API assuming we're logged out if we pass the callback-parameter,
- // we have to disable jQuery's callback system, and instead parse JSON string,
- // by setting 'jsonp' to false.
- jsonp: false
- };
+ })
+ .fail( d.reject );
- return this.get( parameters, ajaxOptions );
+ return d.promise();
},
/**
* Create a new section of the page.
- * @param title {mw.Title|String} target page
- * @param header {String}
- * @param message {String} wikitext message
- * @param ok {Function} success handler
- * @param err {Function} error handler
- * @return {jqXHR}
+ * @see #postWithEditToken
+ * @param {mw.Title|String} title Target page
+ * @param {string} header
+ * @param {string} message wikitext message
+ * @param {Function} [ok] Success handler
+ * @param {Function} [err] Error handler
+ * @return {jQuery.Promise}
*/
newSection: function ( title, header, message, ok, err ) {
- var params = {
+ return this.postWithEditToken( {
action: 'edit',
section: 'new',
format: 'json',
title: title.toString(),
summary: header,
text: message
- };
- return this.postWithEditToken( params, ok, err );
+ }, ok, err );
}
} );
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.edit
+ */
+
}( mediaWiki, jQuery ) );
-/**
- * mw.Api objects represent the API of a particular MediaWiki server.
- */
( function ( mw, $ ) {
- /**
- * @var defaultOptions {Object}
- * We allow people to omit these default parameters from API requests
- * there is very customizable error handling here, on a per-call basis
- * wondering, would it be simpler to make it easy to clone the api object,
- * change error handling, and use that instead?
- */
+ // We allow people to omit these default parameters from API requests
+ // there is very customizable error handling here, on a per-call basis
+ // wondering, would it be simpler to make it easy to clone the api object,
+ // change error handling, and use that instead?
var defaultOptions = {
// Query parameters for API requests
/**
* Constructor to create an object to interact with the API of a particular MediaWiki server.
+ * mw.Api objects represent the API of a particular MediaWiki server.
+ *
+ * TODO: Share API objects with exact same config.
*
- * @todo Share API objects with exact same config.
- * @example
- * <code>
- * var api = new mw.Api();
- * api.get( {
- * action: 'query',
- * meta: 'userinfo'
- * }, {
- * ok: function () { console.log( arguments ); }
- * } );
- * </code>
+ * var api = new mw.Api();
+ * api.get( {
+ * action: 'query',
+ * meta: 'userinfo'
+ * } ).done ( function ( data ) {
+ * console.log( data );
+ * } );
+ *
+ * @class
*
* @constructor
- * @param options {Object} See defaultOptions documentation above. Ajax options can also be
- * overridden for each individual request to jQuery.ajax() later on.
+ * @param {Object} options See defaultOptions documentation above. Ajax options can also be
+ * overridden for each individual request to {@link jQuery#ajax} later on.
*/
mw.Api = function ( options ) {
/**
* Normalize the ajax options for compatibility and/or convenience methods.
*
- * @param {undefined|Object|Function} An object contaning one or more of options.ajax,
- * or just a success function (options.ajax.ok).
+ * @param {Object} [arg] An object contaning one or more of options.ajax.
* @return {Object} Normalized ajax options.
*/
normalizeAjaxOptions: function ( arg ) {
// Arg argument is usually empty
- // (before MW 1.20 it was often used to pass ok/err callbacks)
+ // (before MW 1.20 it was used to pass ok callbacks)
var opts = arg || {};
// Options can also be a success callback handler
if ( typeof arg === 'function' ) {
/**
* Perform API get request
*
- * @param {Object} request parameters
- * @param {Object|Function} [optional] ajax options
+ * @param {Object} parameters
+ * @param {Object|Function} [ajaxOptions]
* @return {jQuery.Promise}
*/
get: function ( parameters, ajaxOptions ) {
/**
* Perform API post request
- * @todo Post actions for nonlocal will need proxy
*
- * @param {Object} request parameters
- * @param {Object|Function} [optional] ajax options
+ * TODO: Post actions for non-local hostnames will need proxy.
+ *
+ * @param {Object} parameters
+ * @param {Object|Function} [ajaxOptions]
* @return {jQuery.Promise}
*/
post: function ( parameters, ajaxOptions ) {
/**
* Perform the API call.
*
- * @param {Object} request parameters
- * @param {Object} ajax options
- * @return {jQuery.Promise}
- * - done: API response data as first argument
- * - fail: errorcode as first arg, details (string or object) as second arg.
+ * @param {Object} parameters
+ * @param {Object} [ajaxOptions]
+ * @return {jQuery.Promise} Done: API response data. Fail: Error code
*/
ajax: function ( parameters, ajaxOptions ) {
var token,
};
/**
- * @var {Array} List of errors we might receive from the API.
+ * @static
+ * @property {Array}
+ * List of errors we might receive from the API.
* For now, this just documents our expectation that there should be similar messages
* available.
*/
];
/**
- * @var {Array} List of warnings we might receive from the API.
+ * @static
+ * @property {Array}
+ * List of warnings we might receive from the API.
* For now, this just documents our expectation that there should be similar messages
* available.
*/
/**
- * mw.Api methods for parsing wikitext.
+ * @class mw.Api.plugin.parse
*/
( function ( mw, $ ) {
$.extend( mw.Api.prototype, {
/**
- * Convinience method for 'action=parse'. Parses wikitext into HTML.
+ * Convinience method for 'action=parse'.
*
- * @param wikiText {String}
- * @param ok {Function} [optional] deprecated (success callback)
- * @param err {Function} [optional] deprecated (error callback)
+ * @param {string} wikitext
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {string} return.done.data Parsed HTML of `wikitext`.
*/
- parse: function ( wikiText, ok, err ) {
- var apiDeferred = $.Deferred();
-
+ parse: function ( wikitext, ok, err ) {
+ var d = $.Deferred();
// Backwards compatibility (< MW 1.20)
- if ( ok ) {
- apiDeferred.done( ok );
- }
- if ( err ) {
- apiDeferred.fail( err );
- }
+ d.done( ok );
+ d.fail( err );
this.get( {
action: 'parse',
- text: wikiText
+ text: wikitext
} )
.done( function ( data ) {
if ( data.parse && data.parse.text && data.parse.text['*'] ) {
- apiDeferred.resolve( data.parse.text['*'] );
+ d.resolve( data.parse.text['*'] );
}
} )
- .fail( apiDeferred.reject );
+ .fail( d.reject );
- // Return the promise
- return apiDeferred.promise();
+ return d.promise();
}
} );
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.parse
+ */
+
}( mediaWiki, jQuery ) );
/**
- * Additional mw.Api methods to assist with API calls to the API module of the TitleBlacklist extension.
+ * @class mw.Api.plugin.titleblacklist
*/
-
( function ( mw, $ ) {
$.extend( mw.Api.prototype, {
/**
- * Convinience method for 'action=titleblacklist'.
+ * Convinience method for `action=titleblacklist`.
* Note: This action is not provided by MediaWiki core, but as part of the TitleBlacklist extension.
*
- * @param title {mw.Title}
- * @param success {Function} Called on successfull request. First argument is false if title wasn't blacklisted,
- * object with 'reason', 'line' and 'message' properties if title was blacklisted.
- * @param err {Function} optional callback to run if api error
- * @return {jqXHR}
+ * @param {mw.Title|string} title
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {Object|boolean} return.done.result False if title wasn't blacklisted, an object with 'reason', 'line'
+ * and 'message' properties if title was blacklisted.
*/
- isBlacklisted: function ( title, success, err ) {
- var params = {
+ isBlacklisted: function ( title, ok, err ) {
+ var d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
+
+ this.get( {
action: 'titleblacklist',
tbaction: 'create',
tbtitle: title.toString()
- },
- ok = function ( data ) {
+ } )
+ .done( function ( data ) {
var result;
// this fails open (if nothing valid is returned by the api, allows the title)
// also fails open when the API is not present, which will be most of the time
// as this API module is part of the TitleBlacklist extension.
- if ( data.titleblacklist && data.titleblacklist.result && data.titleblacklist.result === 'blacklisted') {
+ if ( data.titleblacklist && data.titleblacklist.result && data.titleblacklist.result === 'blacklisted' ) {
if ( data.titleblacklist.reason ) {
result = {
reason: data.titleblacklist.reason,
message: data.titleblacklist.message
};
} else {
- mw.log('mw.Api.titleblacklist::isBlacklisted> no reason data for blacklisted title', 'debug');
- result = { reason: 'Blacklisted, but no reason supplied', line: 'Unknown', message: null };
+ mw.log( 'mw.Api.titleblacklist::isBlacklisted> no reason data for blacklisted title', 'debug' );
+ result = {
+ reason: 'Blacklisted, but no reason supplied',
+ line: 'Unknown',
+ message: null
+ };
}
- success( result );
+ d.resolve( result );
} else {
- success ( false );
+ d.resolve( false );
}
- };
+ } )
+ .fail( d.reject );
- return this.get( params, { ok: ok, err: err } );
+ return d.promise();
}
} );
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.titleblacklist
+ */
+
}( mediaWiki, jQuery ) );
/**
- * Additional mw.Api methods to assist with (un)watching wiki pages.
+ * @class mw.Api.plugin.watch
* @since 1.19
*/
( function ( mw, $ ) {
/**
- * @context {mw.Api}
+ * @private
+ * @context mw.Api
+ *
+ * @param {String|mw.Title} page Full page name or instance of mw.Title
+ * @param {Function} [ok] Success callback (deprecated)
+ * @param {Function} [err] Error callback (deprecated)
+ * @return {jQuery.Promise}
+ * @return {Function} return.done
+ * @return {Object} return.done.watch
+ * @return {string} return.done.watch.title Full pagename
+ * @return {boolean} return.done.watch.watched
+ * @return {string} return.done.watch.message Parsed HTML of the confirmational interface message
*/
- function doWatchInternal( page, success, err, addParams ) {
- var params = {
+ function doWatchInternal( page, ok, err, addParams ) {
+ var params, d = $.Deferred();
+ // Backwards compatibility (< MW 1.20)
+ d.done( ok );
+ d.fail( err );
+
+ params = {
action: 'watch',
title: String( page ),
token: mw.user.tokens.get( 'watchToken' ),
uselang: mw.config.get( 'wgUserLanguage' )
};
- function ok( data ) {
- success( data.watch );
- }
+
if ( addParams ) {
$.extend( params, addParams );
}
- return this.post( params, { ok: ok, err: err } );
+
+ this.post( params )
+ .done( function ( data ) {
+ d.resolve( data.watch );
+ } )
+ .fail( d.reject );
+
+ return d.promise();
}
$.extend( mw.Api.prototype, {
/**
- * Convenience method for 'action=watch'.
+ * Convenience method for `action=watch`.
*
- * @param page {String|mw.Title} Full page name or instance of mw.Title
- * @param success {Function} Callback to which the watch object will be passed.
- * Watch object contains properties 'title' (full pagename), 'watched' (boolean) and
- * 'message' (parsed HTML of the 'addedwatchtext' message).
- * @param err {Function} Error callback (optional)
- * @return {jqXHR}
+ * @inheritdoc #doWatchInternal
*/
- watch: function ( page, success, err ) {
- return doWatchInternal.call( this, page, success, err );
+ watch: function ( page, ok, err ) {
+ return doWatchInternal.call( this, page, ok, err );
},
/**
- * Convenience method for 'action=watch&unwatch=1'.
+ * Convenience method for `action=watch&unwatch=1`.
*
- * @param page {String|mw.Title} Full page name or instance of mw.Title
- * @param success {Function} Callback to which the watch object will be passed.
- * Watch object contains properties 'title' (full pagename), 'watched' (boolean) and
- * 'message' (parsed HTML of the 'removedwatchtext' message).
- * @param err {Function} Error callback (optional)
- * @return {jqXHR}
+ * @inheritdoc #doWatchInternal
*/
- unwatch: function ( page, success, err ) {
- return doWatchInternal.call( this, page, success, err, { unwatch: 1 } );
+ unwatch: function ( page, ok, err ) {
+ return doWatchInternal.call( this, page, ok, err, { unwatch: 1 } );
}
} );
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.watch
+ */
+
}( mediaWiki, jQuery ) );
-/**
- * mediaWiki.Title
- *
+/*!
* @author Neil Kandalgaonkar, 2010
* @author Timo Tijhof, 2011
* @since 1.18
/* Local space */
/**
- * Title
- * @constructor
+ * @class mw.Title
*
- * @param title {String} Title of the page. If no second argument given,
+ * @constructor
+ * @param {string} title Title of the page. If no second argument given,
* this will be searched for a namespace.
- * @param namespace {Number} (optional) Namespace id. If given, title will be taken as-is.
- * @return {Title} this
+ * @param {number} [namespace] Namespace id. If given, title will be taken as-is.
*/
function Title( title, namespace ) {
this.ns = 0; // integer namespace id
}
var
- /**
- * Public methods (defined later)
- */
+ /* Public methods (defined later) */
fn,
/**
* Strip some illegal chars: control chars, colon, less than, greater than,
* brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
* intact, like unicode bidi chars, but it's a good start..
- * @param s {String}
- * @return {String}
+ * @ignore
+ * @param {string} s
+ * @return {string}
*/
clean = function ( s ) {
if ( s !== undefined ) {
/**
* Convert db-key to readable text.
- * @param s {String}
- * @return {String}
+ * @ignore
+ * @param {string} s
+ * @return {string}
*/
text = function ( s ) {
if ( s !== null && s !== undefined ) {
/**
* Sanitize name.
+ * @ignore
*/
fixName = function ( s ) {
return clean( $.trim( s ) );
},
/**
- * Sanitize name.
+ * Sanitize extension.
+ * @ignore
*/
fixExt = function ( s ) {
return clean( s );
/**
* Sanitize namespace id.
+ * @ignore
* @param id {Number} Namespace id.
* @return {Number|Boolean} The id as-is or boolean false if invalid.
*/
/**
* Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
- *
- * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
+ * Example: On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
+ * @ignore
* @param ns {String} Namespace name (case insensitive, leading/trailing space ignored).
* @return {Number|Boolean} Namespace id or boolean false if unrecognized.
*/
/**
* Helper to extract namespace, name and extension from a string.
*
- * @param title {mw.Title}
- * @param raw {String}
+ * @ignore
+ * @param {mw.Title} title
+ * @param {string} raw
* @return {mw.Title}
*/
setAll = function ( title, s ) {
/**
* Helper to extract name and extension from a string.
*
- * @param title {mw.Title}
- * @param raw {String}
+ * @ignore
+ * @param {mw.Title} title
+ * @param {string} raw
* @return {mw.Title}
*/
setNameAndExtension = function ( title, raw ) {
/**
* Whether this title exists on the wiki.
- * @param title {mixed} prefixed db-key name (string) or instance of Title
- * @return {mixed} Boolean true/false if the information is available. Otherwise null.
+ * @static
+ * @param {Mixed} title prefixed db-key name (string) or instance of Title
+ * @return {Mixed} Boolean true/false if the information is available. Otherwise null.
*/
Title.exists = function ( title ) {
var type = $.type( title ), obj = Title.exist.pages, match;
};
/**
- * @var Title.exist {Object}
+ * @static
+ * @property
*/
Title.exist = {
/**
- * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
+ * @static
+ * @property {Object} exist.pages Keyed by PrefixedDb title.
* Boolean true value indicates page does exist.
*/
pages: {},
/**
- * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
- * @example Declare titles nonexistent: Title.exist.set(['File:Foo_bar.jpg', ...], false);
- * @param titles {String|Array} Title(s) in strict prefixedDb title form.
- * @param state {Boolean} (optional) State of the given titles. Defaults to true.
- * @return {Boolean}
+ * Example to declare existing titles:
+ * Title.exist.set(['User:John_Doe', ...]);
+ * Eample to declare titles nonexistent:
+ * Title.exist.set(['File:Foo_bar.jpg', ...], false);
+ *
+ * @static
+ * @property exist.set
+ * @param {string|Array} titles Title(s) in strict prefixedDb title form.
+ * @param {boolean} [state] State of the given titles. Defaults to true.
+ * @return {boolean}
*/
set: function ( titles, state ) {
titles = $.isArray( titles ) ? titles : [titles];
/**
* Get the namespace number.
- * @return {Number}
+ * @return {number}
*/
getNamespaceId: function (){
return this.ns;
/**
* Get the namespace prefix (in the content-language).
* In NS_MAIN this is '', otherwise namespace name plus ':'
- * @return {String}
+ * @return {string}
*/
getNamespacePrefix: function (){
return mw.config.get( 'wgFormattedNamespaces' )[this.ns].replace( / /g, '_' ) + (this.ns === 0 ? '' : ':');
/**
* The name, like "Foo_bar"
- * @return {String}
+ * @return {string}
*/
getName: function () {
if ( $.inArray( this.ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
/**
* The name, like "Foo bar"
- * @return {String}
+ * @return {string}
*/
getNameText: function () {
return text( this.getName() );
/**
* Get full name in prefixed DB form, like File:Foo_bar.jpg,
* most useful for API calls, anything that must identify the "title".
+ * @return {string}
*/
getPrefixedDb: function () {
return this.getNamespacePrefix() + this.getMain();
/**
* Get full name in text form, like "File:Foo bar.jpg".
- * @return {String}
+ * @return {string}
*/
getPrefixedText: function () {
return text( this.getPrefixedDb() );
/**
* The main title (without namespace), like "Foo_bar.jpg"
- * @return {String}
+ * @return {string}
*/
getMain: function () {
return this.getName() + this.getDotExtension();
/**
* The "text" form, like "Foo bar.jpg"
- * @return {String}
+ * @return {string}
*/
getMainText: function () {
return text( this.getMain() );
/**
* Get the extension (returns null if there was none)
- * @return {String|null} extension
+ * @return {string|null}
*/
getExtension: function () {
return this.ext;
/**
* Convenience method: return string like ".jpg", or "" if no extension
- * @return {String}
+ * @return {string}
*/
getDotExtension: function () {
return this.ext === null ? '' : '.' + this.ext;
/**
* Return the URL to this title
- * @return {String}
+ * @see mw.util#wikiGetlink
+ * @return {string}
*/
getUrl: function () {
return mw.util.wikiGetlink( this.toString() );
/**
* Whether this title exists on the wiki.
- * @return {mixed} Boolean true/false if the information is available. Otherwise null.
+ * @see #static-method-exists
+ * @return {boolean|null} If the information is available. Otherwise null.
*/
exists: function () {
return Title.exists( this );
/* Object constructors */
/**
- * Map
- *
* Creates an object that can be read from or written to from prototype functions
* that allow both single and multiple variables at once.
+ * @class mw.Map
*
- * @param global boolean Whether to store the values in the global window
+ * @constructor
+ * @param {boolean} global Whether to store the values in the global window
* object or a exclusively in the object property 'values'.
- * @return Map
*/
function Map( global ) {
this.values = global === true ? window : {};
* If selection was an array, returns an object of key/values (value is null if not found),
* If selection was not passed or invalid, will return the 'values' object member (be careful as
* objects are always passed by reference in JavaScript!).
- * @return Values as a string or object, null if invalid/inexistant.
+ * @return {string|Object|null} Values as a string or object, null if invalid/inexistant.
*/
get: function ( selection, fallback ) {
var results, i;
* Checks if one or multiple keys exist.
*
* @param selection {mixed} String key or array of keys to check
- * @return {Boolean} Existence of key(s)
+ * @return {boolean} Existence of key(s)
*/
exists: function ( selection ) {
var s;
};
/**
- * Message
- *
* Object constructor for messages,
* similar to the Message class in MediaWiki PHP.
+ * @class mw.Message
*
- * @param map Map Instance of mw.Map
- * @param key String
- * @param parameters Array
- * @return Message
+ * @constructor
+ * @param {mw.Map} map Message storage
+ * @param {string} key
+ * @param {Array} [parameters]
*/
function Message( map, key, parameters ) {
this.format = 'plain';
/**
* Appends (does not replace) parameters for replacement to the .parameters property.
*
- * @param parameters Array
- * @return Message
+ * @param {Array} parameters
+ * @chainable
*/
params: function ( parameters ) {
var i;
/**
* Converts message object to it's string form based on the state of format.
*
- * @return string Message as a string in the current form or <key> if key does not exist.
+ * @return {string} Message as a string in the current form or `<key>` if key does not exist.
*/
toString: function () {
var text;
/**
* Checks if message exists
*
- * @return {string} String form of parsed message
+ * @see mw.Map#exists
+ * @return {boolean}
*/
exists: function () {
return this.map.exists( this.key );
}
};
+ /**
+ * @class mw
+ * @alternateClassName mediaWiki
+ * @singleton
+ */
return {
/* Public Members */
*/
log: function () { },
- /**
- * @var constructor Make the Map constructor publicly available.
- */
+ // Make the Map constructor publicly available.
Map: Map,
- /**
- * @var constructor Make the Message constructor publicly available.
- */
+ // Make the Message constructor publicly available.
Message: Message,
/**
* List of configuration values
*
* Dummy placeholder. Initiated in startUp module as a new instance of mw.Map().
- * If $wgLegacyJavaScriptGlobals is true, this Map will have its values
+ * If `$wgLegacyJavaScriptGlobals` is true, this Map will have its values
* in the global window object.
+ * @property
*/
config: null,
/**
- * @var object
- *
* Empty object that plugins can be installed in.
+ * @property
*/
libs: {},
/* Extension points */
+ /**
+ * @property
+ */
legacy: {},
/**
* Localization system
+ * @property {mw.Map}
*/
messages: new Map(),
/* Public Methods */
/**
- * Gets a message object, similar to wfMessage()
+ * Gets a message object, similar to wfMessage().
*
- * @param key string Key of message to get
- * @param parameter1 mixed First argument in a list of variadic arguments,
- * each a parameter for $N replacement in messages.
- * @return Message
+ * @param {string} key Key of message to get
+ * @param {Mixed...} parameters Parameters for the $N replacements in messages.
+ * @return {mw.Message}
*/
- message: function ( key, parameter1 ) {
- var parameters;
- // Support variadic arguments
- if ( parameter1 !== undefined ) {
- parameters = slice.call( arguments );
- parameters.shift();
- } else {
- parameters = [];
- }
+ message: function ( key ) {
+ // Variadic arguments
+ var parameters = slice.call( arguments, 1 );
return new Message( mw.messages, key, parameters );
},
/**
* Gets a message string, similar to wfMessage()
*
- * @param key string Key of message to get
- * @param parameters mixed First argument in a list of variadic arguments,
- * each a parameter for $N replacement in messages.
- * @return String.
+ * @see mw.Message#toString
+ * @param {string} key Key of message to get
+ * @param {Mixed...} parameters Parameters for the $N replacements in messages.
+ * @return {string}
*/
- msg: function ( /* key, parameter_1, parameter_2, .. */ ) {
+ msg: function ( /* key, parameters... */ ) {
return mw.message.apply( mw.message, arguments ).toString();
},
/**
* Client-side module loader which integrates with the MediaWiki ResourceLoader
+ * @class mw.loader
+ * @singleton
*/
loader: ( function () {
* mw.loader.implement.
*
* Format:
- * {
- * 'moduleName': {
- * 'version': ############## (unix timestamp),
- * 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
- * 'group': 'somegroup', (or) null,
- * 'source': 'local', 'someforeignwiki', (or) null
- * 'state': 'registered', 'loading', 'loaded', 'ready', 'error' or 'missing'
- * 'script': ...,
- * 'style': ...,
- * 'messages': { 'key': 'value' },
- * }
- * }
+ * {
+ * 'moduleName': {
+ * 'version': ############## (unix timestamp),
+ * 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
+ * 'group': 'somegroup', (or) null,
+ * 'source': 'local', 'someforeignwiki', (or) null
+ * 'state': 'registered', 'loading', 'loaded', 'ready', 'error' or 'missing'
+ * 'script': ...,
+ * 'style': ...,
+ * 'messages': { 'key': 'value' },
+ * }
+ * }
+ *
+ * @property
+ * @private
*/
var registry = {},
- /**
- * Mapping of sources, keyed by source-id, values are objects.
- * Format:
- * {
- * 'sourceId': {
- * 'loadScript': 'http://foo.bar/w/load.php'
- * }
- * }
- */
+ //
+ // Mapping of sources, keyed by source-id, values are objects.
+ // Format:
+ // {
+ // 'sourceId': {
+ // 'loadScript': 'http://foo.bar/w/load.php'
+ // }
+ // }
+ //
sources = {},
// List of modules which will be loaded as when ready
batch = [],
/**
* Create a new style tag and add it to the DOM.
*
- * @param text String: CSS text
- * @param nextnode mixed: [optional] An Element or jQuery object for an element where
- * the style tag should be inserted before. Otherwise appended to the <head>.
- * @return HTMLStyleElement
+ * @private
+ * @param {string} text CSS text
+ * @param {Mixed} [nextnode] An Element or jQuery object for an element where
+ * the style tag should be inserted before. Otherwise appended to the `<head>`.
+ * @return {HTMLElement} Node reference to the created `<style>` tag.
*/
function addStyleTag( text, nextnode ) {
var s = document.createElement( 'style' );
* Checks if certain cssText is safe to append to
* a stylesheet.
*
- * Right now it only makes sure that cssText containing @import
+ * Right now it only makes sure that cssText containing `@import`
* rules will end up in a new stylesheet (as those only work when
* placed at the start of a stylesheet; bug 35562).
* This could later be extended to take care of other bugs, such as
* the IE cssRules limit - not the same as the IE styleSheets limit).
+ * @private
+ * @param {jQuery} $style
+ * @param {string} cssText
+ * @return {boolean}
*/
function canExpandStylesheetWith( $style, cssText ) {
return cssText.indexOf( '@import' ) === -1;
function addEmbeddedCSS( cssText ) {
var $style, styleEl;
$style = getMarker().prev();
- // Re-use <style> tags if possible, this to try to stay
+ // Re-use `<style>` tags if possible, this to try to stay
// under the IE stylesheet limit (bug 31676).
// Also verify that the the element before Marker actually is one
// that came from ResourceLoader, and not a style tag that some
// other script inserted before our marker, or, more importantly,
- // it may not be a style tag at all (could be <meta> or <script>).
+ // it may not be a style tag at all (could be `<meta>` or `<script>`).
if (
$style.data( 'ResourceLoaderDynamicStyleTag' ) === true &&
canExpandStylesheetWith( $style, cssText )
/**
* Generates an ISO8601 "basic" string from a UNIX timestamp
+ * @private
*/
function formatVersionNumber( timestamp ) {
var d = new Date();
/**
* Resolves dependencies and detects circular references.
*
- * @param module String Name of the top-level module whose dependencies shall be
+ * @private
+ * @param {string} module Name of the top-level module whose dependencies shall be
* resolved and sorted.
- * @param resolved Array Returns a topological sort of the given module and its
+ * @param {Array} resolved Returns a topological sort of the given module and its
* dependencies, such that later modules depend on earlier modules. The array
* contains the module names. If the array contains already some module names,
* this function appends its result to the pre-existing array.
- * @param unresolved Object [optional] Hash used to track the current dependency
+ * @param {Object} [unresolved] Hash used to track the current dependency
* chain; used to report loops in the dependency graph.
- * @throws Error if any unregistered module or a dependency loop is encountered
+ * @throws {Error} If any unregistered module or a dependency loop is encountered
*/
function sortDependencies( module, resolved, unresolved ) {
var n, deps, len;
* Gets a list of module names that a module depends on in their proper dependency
* order.
*
- * @param module string module name or array of string module names
- * @return list of dependencies, including 'module'.
- * @throws Error if circular reference is detected
+ * @private
+ * @param {string} module Module name or array of string module names
+ * @return {Array} list of dependencies, including 'module'.
+ * @throws {Error} If circular reference is detected
*/
function resolve( module ) {
var m, resolved;
* One can also filter for 'unregistered', which will return the
* modules names that don't have a registry entry.
*
- * @param states string or array of strings of module states to filter by
- * @param modules array list of module names to filter (optional, by default the entire
+ * @private
+ * @param {string|string[]} states Module states to filter by
+ * @param {Array} modules List of module names to filter (optional, by default the entire
* registry is used)
- * @return array list of filtered module names
+ * @return {Array} List of filtered module names
*/
function filter( states, modules ) {
var list, module, s, m;
* Determine whether all dependencies are in state 'ready', which means we may
* execute the module or job now.
*
- * @param dependencies Array dependencies (module names) to be checked.
- *
- * @return Boolean true if all dependencies are in state 'ready', false otherwise
+ * @private
+ * @param {Array} dependencies Dependencies (module names) to be checked.
+ * @return {boolean} True if all dependencies are in state 'ready', false otherwise
*/
function allReady( dependencies ) {
return filter( 'ready', dependencies ).length === dependencies.length;
* Gets console references in each invocation, so that delayed debugging tools work
* fine. No need for optimization here, which would only result in losing logs.
*
- * @param msg String text for the log entry.
- * @param e Error [optional] to also log.
+ * @private
+ * @param {string} msg text for the log entry.
+ * @param {Error} [e]
*/
function log( msg, e ) {
var console = window.console;
* state up the dependency tree; otherwise, execute all jobs/modules that now have all their
* dependencies satisfied. On jobs depending on a failed module, run the error callback, if any.
*
- * @param module String name of module that entered one of the states 'ready', 'error', or 'missing'.
+ * @private
+ * @param {string} module Name of module that entered one of the states 'ready', 'error', or 'missing'.
*/
function handlePending( module ) {
var j, job, hasErrors, m, stateChange;
* Adds a script tag to the DOM, either using document.write or low-level DOM manipulation,
* depending on whether document-ready has occurred yet and whether we are in async mode.
*
- * @param src String: URL to script, will be used as the src attribute in the script tag
- * @param callback Function: Optional callback which will be run when the script is done
+ * @private
+ * @param {string} src URL to script, will be used as the src attribute in the script tag
+ * @param {Function} [callback] Callback which will be run when the script is done
*/
function addScript( src, callback, async ) {
/*jshint evil:true */
/**
* Executes a loaded module, making it ready to use
*
- * @param module string module name to execute
+ * @private
+ * @param {string} module Module name to execute
*/
function execute( module ) {
var key, value, media, i, urls, script, markModuleReady, nestedAddScript;
/**
* Define loop-function here for efficiency
* and to avoid re-using badly scoped variables.
+ * @ignore
*/
function addLink( media, url ) {
var el = document.createElement( 'link' );
* Adds a dependencies to the queue with optional callbacks to be run
* when the dependencies are ready or fail
*
- * @param dependencies string module name or array of string module names
- * @param ready function callback to execute when all dependencies are ready
- * @param error function callback to execute when any dependency fails
- * @param async (optional) If true, load modules asynchronously even if
- * document ready has not yet occurred
+ * @private
+ * @param {string|string[]} dependencies Module name or array of string module names
+ * @param {Function} ready Callback to execute when all dependencies are ready
+ * @param {Function} error Callback to execute when any dependency fails
+ * @param {boolean} [async] If true, load modules asynchronously even if
+ * document ready has not yet occurred.
*/
function request( dependencies, ready, error, async ) {
var n;
/**
* Converts a module map of the form { foo: [ 'bar', 'baz' ], bar: [ 'baz, 'quux' ] }
* to a query string of the form foo.bar,baz|bar.baz,quux
+ * @private
*/
function buildModulesString( moduleMap ) {
var arr = [], p, prefix;
/**
* Asynchronously append a script tag to the end of the body
* that invokes load.php
- * @param moduleMap {Object}: Module map, see buildModulesString()
- * @param currReqBase {Object}: Object with other parameters (other than 'modules') to use in the request
- * @param sourceLoadScript {String}: URL of load.php
- * @param async {Boolean}: If true, use an asynchrounous request even if document ready has not yet occurred
+ * @private
+ * @param {Object} moduleMap Module map, see #buildModulesString
+ * @param {Object} currReqBase Object with other parameters (other than 'modules') to use in the request
+ * @param {string} sourceLoadScript URL of load.php
+ * @param {boolean} async If true, use an asynchrounous request even if document ready has not yet occurred
*/
function doRequest( moduleMap, currReqBase, sourceLoadScript, async ) {
var request = $.extend(
/**
* Register a source.
*
- * @param id {String}: Short lowercase a-Z string representing a source, only used internally.
- * @param props {Object}: Object containing only the loadScript property which is a url to
- * the load.php location of the source.
- * @return {Boolean}
+ * @param {string} id Short lowercase a-Z string representing a source, only used internally.
+ * @param {Object} props Object containing only the loadScript property which is a url to
+ * the load.php location of the source.
+ * @return {boolean}
*/
addSource: function ( id, props ) {
var source;
*
* All arguments are required.
*
- * @param {String} module Name of module
+ * @param {string} module Name of module
* @param {Function|Array} script Function with module code or Array of URLs to
- * be used as the src attribute of a new <script> tag.
+ * be used as the src attribute of a new `<script>` tag.
* @param {Object} style Should follow one of the following patterns:
- * { "css": [css, ..] }
- * { "url": { <media>: [url, ..] } }
- * And for backwards compatibility (needs to be supported forever due to caching):
- * { <media>: css }
- * { <media>: [url, ..] }
+ * { "css": [css, ..] }
+ * { "url": { <media>: [url, ..] } }
+ * And for backwards compatibility (needs to be supported forever due to caching):
+ * { <media>: css }
+ * { <media>: [url, ..] }
*
- * The reason css strings are not concatenated anymore is bug 31676. We now check
- * whether it's safe to extend the stylesheet (see canExpandStylesheetWith).
+ * The reason css strings are not concatenated anymore is bug 31676. We now check
+ * whether it's safe to extend the stylesheet (see #canExpandStylesheetWith).
*
- * @param {Object} msgs List of key/value pairs to be passed through mw.messages.set
+ * @param {Object} msgs List of key/value pairs to be added to {@link mw#messages}.
*/
implement: function ( module, script, style, msgs ) {
// Validate input
};
}() ),
- /** HTML construction helper functions */
+ /**
+ * HTML construction helper functions
+ * @class mw.html
+ * @singleton
+ */
html: ( function () {
function escapeCallback( s ) {
switch ( s ) {
return {
/**
* Escape a string for HTML. Converts special characters to HTML entities.
- * @param s The string to escape
+ * @param {string} s The string to escape
*/
escape: function ( s ) {
return s.replace( /['"<>&]/g, escapeCallback );
/**
* Wrapper object for raw HTML passed to mw.html.element().
- * @constructor
+ * @class mw.html.Raw
*/
Raw: function ( value ) {
this.value = value;
/**
* Wrapper object for CDATA element contents passed to mw.html.element()
- * @constructor
+ * @class mw.html.Cdata
*/
Cdata: function ( value ) {
this.value = value;
-/**
- * Implements mediaWiki.notification library
- */
( function ( mw, $ ) {
'use strict';
var notification,
isPageReady = false,
- isInitialized = false,
preReadyNotifQueue = [],
- /**
- * @var {jQuery}
- * The #mw-notification-area div that all notifications are contained inside.
- */
+ // The #mw-notification-area div that all notifications are contained inside.
$area = null;
/**
* Creates a Notification object for 1 message.
- * Does not insert anything into the document (see .start()).
+ * Does not insert anything into the document (see #start).
+ *
+ * The "_" in the name is to avoid a bug (http://github.com/senchalabs/jsduck/issues/304)
+ * It is not part of the actual class name.
+ *
+ * @class mw.Notification_
+ * @alternateClassName mw.Notification
+ * @private
*
* @constructor
- * @see mw.notification.notify
*/
function Notification( message, options ) {
var $notification, $notificationTitle, $notificationContent;
*
* @param {Object} options An object containing options for the closing of the notification.
* These are typically only used internally.
+ *
* - speed: Use a close speed different than the default 'slow'.
* - placeholder: Set to false to disable the placeholder transition.
*/
/**
* Helper function, take a list of notification divs and call
- * a function on the Notification instance attached to them
+ * a function on the Notification instance attached to them.
*
* @param {jQuery} $notifications A jQuery object containing notification divs
* @param {string} fn The name of the function to call on the Notification instance
}
/**
- * Initialisation
- * (don't call before document ready)
+ * Initialisation.
+ * Must only be called once, and not before the document is ready.
+ * @ignore
*/
function init() {
- if ( !isInitialized ) {
- isInitialized = true;
- $area = $( '<div id="mw-notification-area"></div>' )
- // Pause auto-hide timers when the mouse is in the notification area.
- .on( {
- mouseenter: notification.pause,
- mouseleave: notification.resume
- } )
- // When clicking on a notification close it.
- .on( 'click', '.mw-notification', function () {
- var notif = $( this ).data( 'mw.notification' );
- if ( notif ) {
- notif.close();
- }
- } )
- // Stop click events from <a> tags from propogating to prevent clicking.
- // on links from hiding a notification.
- .on( 'click', 'a', function ( e ) {
- e.stopPropagation();
- } );
-
- // Prepend the notification area to the content area and save it's object.
- mw.util.$content.prepend( $area );
- }
+ $area = $( '<div id="mw-notification-area"></div>' )
+ // Pause auto-hide timers when the mouse is in the notification area.
+ .on( {
+ mouseenter: notification.pause,
+ mouseleave: notification.resume
+ } )
+ // When clicking on a notification close it.
+ .on( 'click', '.mw-notification', function () {
+ var notif = $( this ).data( 'mw.notification' );
+ if ( notif ) {
+ notif.close();
+ }
+ } )
+ // Stop click events from <a> tags from propogating to prevent clicking.
+ // on links from hiding a notification.
+ .on( 'click', 'a', function ( e ) {
+ e.stopPropagation();
+ } );
+
+ // Prepend the notification area to the content area and save it's object.
+ mw.util.$content.prepend( $area );
}
+ /**
+ * @class mw.notification
+ * @singleton
+ */
notification = {
/**
* Pause auto-hide timers for all notifications.
* Notifications will not auto-hide until resume is called.
+ * @see mw.Notification#pause
*/
pause: function () {
callEachNotification(
/**
* Resume any paused auto-hide timers from the beginning.
- * Only the first {autoHideLimit} timers will be resumed.
+ * Only the first #autoHideLimit timers will be resumed.
*/
resume: function () {
callEachNotification(
- // Only call resume on the first {autoHideLimit} notifications.
- // Exclude noautohide notifications to avoid bugs where {autoHideLimit}
- // { autoHide: false } notifications are at the start preventing any
+ // Only call resume on the first #autoHideLimit notifications.
+ // Exclude noautohide notifications to avoid bugs where #autoHideLimit
+ // `{ autoHide: false }` notifications are at the start preventing any
// auto-hide notifications from being autohidden.
$area.children( '.mw-notification-autohide' ).slice( 0, notification.autoHideLimit ),
'resume'
/**
* Display a notification message to the user.
*
- * @param {mixed} message The DOM-element, jQuery object, mw.Message instance,
- * or plaintext string to be used as the message.
+ * @param {HTMLElement|jQuery|mw.Message|string} message
* @param {Object} options The options to use for the notification.
- * See mw.notification.defaults for details.
+ * See #defaults for details.
*/
notify: function ( message, options ) {
var notif;
},
/**
- * @var {Object}
- * The defaults for mw.notification.notify's options parameter
- * autoHide:
- * A boolean indicating whether the notifification should automatically
- * be hidden after shown. Or if it should persist.
+ * @property {Object}
+ * The defaults for #notify options parameter.
+ *
+ * - autoHide:
+ * A boolean indicating whether the notifification should automatically
+ * be hidden after shown. Or if it should persist.
*
- * tag:
- * An optional string. When a notification is tagged only one message
- * with that tag will be displayed. Trying to display a new notification
- * with the same tag as one already being displayed will cause the other
- * notification to be closed and this new notification to open up inside
- * the same place as the previous notification.
+ * - tag:
+ * An optional string. When a notification is tagged only one message
+ * with that tag will be displayed. Trying to display a new notification
+ * with the same tag as one already being displayed will cause the other
+ * notification to be closed and this new notification to open up inside
+ * the same place as the previous notification.
*
- * title:
- * An optional title for the notification. Will be displayed above the
- * content. Usually in bold.
+ * - title:
+ * An optional title for the notification. Will be displayed above the
+ * content. Usually in bold.
*/
defaults: {
autoHide: true,
},
/**
- * @var {number}
+ * @property {number}
* Number of seconds to wait before auto-hiding notifications.
*/
autoHideSeconds: 5,
/**
- * @var {number}
+ * @property {number}
* Maximum number of notifications to count down auto-hide timers for.
- * Only the first {autoHideLimit} notifications being displayed will
+ * Only the first #autoHideLimit notifications being displayed will
* auto-hide. Any notifications further down in the list will only start
* counting down to auto-hide after the first few messages have closed.
*
* This basically represents the number of notifications the user should
- * be able to process in {autoHideSeconds} time.
+ * be able to process in #autoHideSeconds time.
*/
autoHideLimit: 3
};
/**
- * Implements mediaWiki.notify function
+ * @class mw.plugin.notify
*/
( function ( mw ) {
'use strict';
/**
- * @see mw.notification.notify
+ * @see mw.notification#notify
+ * @param message
+ * @param options
*/
mw.notify = function ( message, options ) {
// Don't bother loading the whole notification system if we never use it.
} );
};
-}( mediaWiki ) );
\ No newline at end of file
+ /**
+ * @class mw
+ * @mixins mw.plugin.notify
+ */
+
+}( mediaWiki ) );
-/**
- * Implements mediaWiki.util library
- */
( function ( mw, $ ) {
'use strict';
- // Local cache and alias
+ /**
+ * Utility library
+ * @class mw.util
+ * @singleton
+ */
var util = {
/**
/**
* Encode the string like PHP's rawurlencode
*
- * @param str string String to be encoded
+ * @param {string} str String to be encoded.
*/
rawurlencode: function ( str ) {
str = String( str );
* We want / and : to be included as literal characters in our title URLs
* as they otherwise fatally break the title
*
- * @param str string String to be encoded
+ * @param {string} str String to be encoded.
*/
wikiUrlencode: function ( str ) {
return util.rawurlencode( str )
},
/**
- * Get the link to a page name (relative to wgServer)
+ * Get the link to a page name (relative to `wgServer`),
*
- * @param str String: Page name to get the link for.
- * @return String: Location for a page with name of 'str' or boolean false on error.
+ * @param {string} str Page name to get the link for.
+ * @return {string} Location for a page with name of `str` or boolean false on error.
*/
wikiGetlink: function ( str ) {
return mw.config.get( 'wgArticlePath' ).replace( '$1',
/**
* Get address to a script in the wiki root.
- * For index.php use mw.config.get( 'wgScript' )
+ * For index.php use `mw.config.get( 'wgScript' )`.
*
* @since 1.18
* @param str string Name of script (eg. 'api'), defaults to 'index'
/**
* Append a new style block to the head and return the CSSStyleSheet object.
- * Use .ownerNode to access the <style> element, or use mw.loader.addStyleTag.
+ * Use .ownerNode to access the `<style>` element, or use mw.loader#addStyleTag.
* This function returns the styleSheet object for convience (due to cross-browsers
* difference as to where it is located).
- * @example
- * <code>
- * var sheet = mw.util.addCSS('.foobar { display: none; }');
- * $(foo).click(function () {
- * // Toggle the sheet on and off
- * sheet.disabled = !sheet.disabled;
- * });
- * </code>
*
- * @param text string CSS to be appended
- * @return CSSStyleSheet (use .ownerNode to get to the <style> element)
+ * var sheet = mw.util.addCSS('.foobar { display: none; }');
+ * $(foo).click(function () {
+ * // Toggle the sheet on and off
+ * sheet.disabled = !sheet.disabled;
+ * });
+ *
+ * @param {string} text CSS to be appended
+ * @return {CSSStyleSheet} Use .ownerNode to get to the `<style>` element.
*/
addCSS: function ( text ) {
var s = mw.loader.addStyleTag( text );
/**
* Hide/show the table of contents element
*
- * @param $toggleLink jQuery A jQuery object of the toggle link.
- * @param callback function Function to be called after the toggle is
- * completed (including the animation) (optional)
- * @return mixed Boolean visibility of the toc (true if it's visible)
+ * @param {jQuery} $toggleLink A jQuery object of the toggle link.
+ * @param {Function} [callback] Function to be called after the toggle is
+ * completed (including the animation).
+ * @return {Mixed} Boolean visibility of the toc (true if it's visible)
* or Null if there was no table of contents.
*/
toggleToc: function ( $toggleLink, callback ) {
* Grab the URL parameter value for the given parameter.
* Returns null if not found.
*
- * @param param string The parameter name.
- * @param url string URL to search through (optional)
- * @return mixed Parameter value or null.
+ * @param {string} param The parameter name.
+ * @param {string} [url] URL to search through.
+ * @return {Mixed} Parameter value or null.
*/
getParamValue: function ( param, url ) {
if ( url === undefined ) {
},
/**
- * @var string
+ * @property {string}
* Access key prefix. Will be re-defined based on browser/operating system
- * detection in mw.util.init().
+ * detection in mw.util#init.
*/
tooltipAccessKeyPrefix: 'alt-',
/**
- * @var RegExp
+ * @property {RegExp}
* Regex to match accesskey tooltips.
*/
tooltipAccessKeyRegexp: /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/,
* otherwise, all the nodes that will probably have accesskeys by
* default are updated.
*
- * @param $nodes {Array|jQuery} [optional] A jQuery object, or array
- * of elements to update.
+ * @param {Array|jQuery} [$nodes] A jQuery object, or array of nodes to update.
*/
updateTooltipAccessKeys: function ( $nodes ) {
if ( !$nodes ) {
},
/*
- * @var jQuery
- * A jQuery object that refers to the content area element
- * Populated by init().
+ * @property {jQuery}
+ * A jQuery object that refers to the content area element.
+ * Populated by #init.
*/
$content: null,
*
* By default the new link will be added to the end of the list. To
* add the link before a given existing item, pass the DOM node
- * (document.getElementById( 'foobar' )) or the jQuery-selector
- * ( '#foobar' ) of that item.
+ * (e.g. `document.getElementById( 'foobar' )`) or a jQuery-selector
+ * (e.g. `'#foobar'`) for that item.
*
- * @example mw.util.addPortletLink(
- * 'p-tb', 'http://mediawiki.org/',
- * 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print'
- * )
+ * mw.util.addPortletLink(
+ * 'p-tb', 'http://mediawiki.org/',
+ * 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print'
+ * );
*
- * @param portlet string ID of the target portlet ( 'p-cactions' or 'p-personal' etc.)
- * @param href string Link URL
- * @param text string Link text
- * @param id string ID of the new item, should be unique and preferably have
- * the appropriate prefix ( 'ca-', 'pt-', 'n-' or 't-' )
- * @param tooltip string Text to show when hovering over the link, without accesskey suffix
- * @param accesskey string Access key to activate this link (one character, try
- * to avoid conflicts. Use $( '[accesskey=x]' ).get() in the console to
- * see if 'x' is already used.
- * @param nextnode mixed DOM Node or jQuery-selector string of the item that the new
- * item should be added before, should be another item in the same
- * list, it will be ignored otherwise
+ * @param {string} portlet ID of the target portlet ( 'p-cactions' or 'p-personal' etc.)
+ * @param {string} href Link URL
+ * @param {string} text Link text
+ * @param {string} [id] ID of the new item, should be unique and preferably have
+ * the appropriate prefix ( 'ca-', 'pt-', 'n-' or 't-' )
+ * @param {string} [tooltip] Text to show when hovering over the link, without accesskey suffix
+ * @param {string} [accesskey] Access key to activate this link (one character, try
+ * to avoid conflicts. Use `$( '[accesskey=x]' ).get()` in the console to
+ * see if 'x' is already used.
+ * @param {HTMLElement|jQuery|string} [nextnode] Element or jQuery-selector string to the item that
+ * the new item should be added before, should be another item in the same
+ * list, it will be ignored otherwise
*
- * @return mixed The DOM Node of the added item (a ListItem or Anchor element,
+ * @return {HTMLElement|null} The added element (a ListItem or Anchor element,
* depending on the skin) or null if no element was added to the document.
*/
addPortletLink: function ( portlet, href, text, id, tooltip, accesskey, nextnode ) {
* something, replacing any previous message.
* Calling with no arguments, with an empty string or null will hide the message
*
- * @param message {mixed} The DOM-element, jQuery object or HTML-string to be put inside the message box.
+ * @param {Mixed} message The DOM-element, jQuery object or HTML-string to be put inside the message box.
* to allow CSS/JS to hide different boxes. null = no class used.
- * @depreceated Use mw.notify
+ * @deprecated Use mw#notify
*/
jsMessage: function ( message ) {
if ( !arguments.length || message === '' || message === null ) {
* according to HTML5 specification. Please note the specification
* does not validate a domain with one character.
*
- * @todo FIXME: should be moved to or replaced by a JavaScript validation module.
+ * FIXME: should be moved to or replaced by a validation module.
*
- * @param mailtxt string E-mail address to be validated.
- * @return mixed Null if mailtxt was an empty string, otherwise true/false
- * is determined by validation.
+ * @param {string} mailtxt E-mail address to be validated.
+ * @return {boolean|null} Null if `mailtxt` was an empty string, otherwise true/false
+ * as determined by validation.
*/
validateEmail: function ( mailtxt ) {
var rfc5322Atext, rfc1034LdhStr, html5EmailRegexp;
return null;
}
- /**
- * HTML5 defines a string as valid e-mail address if it matches
- * the ABNF:
- * 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str )
- * With:
- * - atext : defined in RFC 5322 section 3.2.3
- * - ldh-str : defined in RFC 1034 section 3.5
- *
- * (see STD 68 / RFC 5234 http://tools.ietf.org/html/std68):
- */
-
- /**
- * First, define the RFC 5322 'atext' which is pretty easy:
- * atext = ALPHA / DIGIT / ; Printable US-ASCII
- "!" / "#" / ; characters not including
- "$" / "%" / ; specials. Used for atoms.
- "&" / "'" /
- "*" / "+" /
- "-" / "/" /
- "=" / "?" /
- "^" / "_" /
- "`" / "{" /
- "|" / "}" /
- "~"
- */
+ // HTML5 defines a string as valid e-mail address if it matches
+ // the ABNF:
+ // 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str )
+ // With:
+ // - atext : defined in RFC 5322 section 3.2.3
+ // - ldh-str : defined in RFC 1034 section 3.5
+ //
+ // (see STD 68 / RFC 5234 http://tools.ietf.org/html/std68)
+ // First, define the RFC 5322 'atext' which is pretty easy:
+ // atext = ALPHA / DIGIT / ; Printable US-ASCII
+ // "!" / "#" / ; characters not including
+ // "$" / "%" / ; specials. Used for atoms.
+ // "&" / "'" /
+ // "*" / "+" /
+ // "-" / "/" /
+ // "=" / "?" /
+ // "^" / "_" /
+ // "`" / "{" /
+ // "|" / "}" /
+ // "~"
rfc5322Atext = 'a-z0-9!#$%&\'*+\\-/=?^_`{|}~';
- /**
- * Next define the RFC 1034 'ldh-str'
- * <domain> ::= <subdomain> | " "
- * <subdomain> ::= <label> | <subdomain> "." <label>
- * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
- * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
- * <let-dig-hyp> ::= <let-dig> | "-"
- * <let-dig> ::= <letter> | <digit>
- */
+ // Next define the RFC 1034 'ldh-str'
+ // <domain> ::= <subdomain> | " "
+ // <subdomain> ::= <label> | <subdomain> "." <label>
+ // <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+ // <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ // <let-dig-hyp> ::= <let-dig> | "-"
+ // <let-dig> ::= <letter> | <digit>
rfc1034LdhStr = 'a-z0-9\\-';
html5EmailRegexp = new RegExp(
/**
* Note: borrows from IP::isIPv4
*
- * @param address string
- * @param allowBlock boolean
- * @return boolean
+ * @param {string} address
+ * @param {boolean} allowBlock
+ * @return {boolean}
*/
isIPv4Address: function ( address, allowBlock ) {
if ( typeof address !== 'string' ) {
/**
* Note: borrows from IP::isIPv6
*
- * @param address string
- * @param allowBlock boolean
- * @return boolean
+ * @param {string} address
+ * @param {boolean} allowBlock
+ * @return {boolean}
*/
isIPv6Address: function ( address, allowBlock ) {
if ( typeof address !== 'string' ) {