From: Timo Tijhof Date: Sun, 13 Jan 2013 00:47:00 +0000 (+0100) Subject: Initial JSDuck implementation X-Git-Tag: 1.31.0-rc.0~20594^2 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/categories/modifier.php?a=commitdiff_plain;h=dfb8390a428f3aa0b6991aac99afdc223f2b43b1;p=lhc%2Fweb%2Fwiklou.git Initial JSDuck implementation * 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 --- diff --git a/.gitignore b/.gitignore index 004ecf4f4d..6f08ff28a8 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ sublime-* # MediaWiki install & usage cache +docs/js images/[0-9a-f] images/archive images/deleted diff --git a/maintenance/Makefile b/maintenance/Makefile index 30b568dcab..2555475102 100644 --- a/maintenance/Makefile +++ b/maintenance/Makefile @@ -8,7 +8,9 @@ test: 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 diff --git a/maintenance/jsduck/MetaTags.rb b/maintenance/jsduck/MetaTags.rb new file mode 100644 index 0000000000..84e4021339 --- /dev/null +++ b/maintenance/jsduck/MetaTags.rb @@ -0,0 +1,53 @@ +# 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 '

Context

' + 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 << '

Related

' + doc << [ + '', + ] + doc + end + + def render_long_see(tag) + if tag =~ /\A([^\s]+)( .*)?\Z/m + name = $1 + doc = $2 ? ': ' + $2 : '' + return [ + '
  • ', + format("{@link #{name}} #{doc}"), + '
  • ' + ] + end + end +end diff --git a/maintenance/jsduck/categories.json b/maintenance/jsduck/categories.json new file mode 100644 index 0000000000..4a8ba8c3bb --- /dev/null +++ b/maintenance/jsduck/categories.json @@ -0,0 +1,54 @@ +[ + { + "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"] + } + ] + } +] diff --git a/maintenance/jsduck/config.json b/maintenance/jsduck/config.json new file mode 100644 index 0000000000..c4705d8f8d --- /dev/null +++ b/maintenance/jsduck/config.json @@ -0,0 +1,18 @@ +{ + "--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 diff --git a/maintenance/jsduck/eg-iframe.html b/maintenance/jsduck/eg-iframe.html new file mode 100644 index 0000000000..f53b40445e --- /dev/null +++ b/maintenance/jsduck/eg-iframe.html @@ -0,0 +1,20 @@ + + + + + MediaWiki Examples + + + + diff --git a/maintenance/jsduck/external.js b/maintenance/jsduck/external.js new file mode 100644 index 0000000000..8ab102f4c3 --- /dev/null +++ b/maintenance/jsduck/external.js @@ -0,0 +1,26 @@ +/** + * @class jQuery + */ + +/** + * @method ajax + * @return {jqXHR} + */ + +/** + * @class jQuery.Event + */ + +/** + * @class jQuery.Promise + */ + +/** + * @class jQuery.Deferred + * @mixins jQuery.Promise + */ + +/** + * @class jQuery.jqXHR + * @alternateClassName jqXHR + */ diff --git a/maintenance/mwjsduck-gen b/maintenance/mwjsduck-gen new file mode 100755 index 0000000000..fbd428f131 --- /dev/null +++ b/maintenance/mwjsduck-gen @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +jsduck --config=$(cd $(dirname $0)/..; pwd)/maintenance/jsduck/config.json && echo 'JSDuck execution finished.' diff --git a/resources/jquery/jquery.localize.js b/resources/jquery/jquery.localize.js index 3e786ec2ee..d9a2b199f3 100644 --- a/resources/jquery/jquery.localize.js +++ b/resources/jquery/jquery.localize.js @@ -1,9 +1,31 @@ /** - * 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 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 elements or elements + * Call on a selection of HTML which contains `` elements or elements * with title-msg="message-key", alt-msg="message-key" or placeholder-msg="message-key" attributes. - * elements will be replaced with localized text, *-msg attributes will be replaced + * `` 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: @@ -77,34 +99,12 @@ * Appends something like this to the body... *

    You may not get there all in one piece.

    * - */ -( 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 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, @@ -162,4 +162,9 @@ $.fn.localize = function ( options ) { // Let IE know about the msg tag before it's used... document.createElement( 'msg' ); +/** + * @class jQuery + * @mixins jQuery.plugin.localize + */ + }( jQuery, mediaWiki ) ); diff --git a/resources/mediawiki.api/mediawiki.api.category.js b/resources/mediawiki.api/mediawiki.api.category.js index cc6f704f55..4de52911c1 100644 --- a/resources/mediawiki.api/mediawiki.api.category.js +++ b/resources/mediawiki.api/mediawiki.api.category.js @@ -1,104 +1,130 @@ /** - * 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 ) ); diff --git a/resources/mediawiki.api/mediawiki.api.edit.js b/resources/mediawiki.api/mediawiki.api.edit.js index 49af93758e..3c775ad0e6 100644 --- a/resources/mediawiki.api/mediawiki.api.edit.js +++ b/resources/mediawiki.api/mediawiki.api.edit.js @@ -1,5 +1,5 @@ /** - * Additional mw.Api methods to assist with API calls related to editing wiki pages. + * @class mw.Api.plugin.edit */ ( function ( mw, $ ) { @@ -13,10 +13,10 @@ * 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, @@ -48,67 +48,74 @@ }, /** - * 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 ) ); diff --git a/resources/mediawiki.api/mediawiki.api.js b/resources/mediawiki.api/mediawiki.api.js index a184e3ca96..cf7443f3b3 100644 --- a/resources/mediawiki.api/mediawiki.api.js +++ b/resources/mediawiki.api/mediawiki.api.js @@ -1,15 +1,9 @@ -/** - * 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 @@ -30,22 +24,23 @@ /** * 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 - * - * var api = new mw.Api(); - * api.get( { - * action: 'query', - * meta: 'userinfo' - * }, { - * ok: function () { console.log( arguments ); } - * } ); - * + * 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 ) { @@ -69,13 +64,12 @@ /** * 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' ) { @@ -87,8 +81,8 @@ /** * 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 ) { @@ -99,10 +93,11 @@ /** * 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 ) { @@ -114,11 +109,9 @@ /** * 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, @@ -187,7 +180,9 @@ }; /** - * @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. */ @@ -237,7 +232,9 @@ ]; /** - * @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. */ diff --git a/resources/mediawiki.api/mediawiki.api.parse.js b/resources/mediawiki.api/mediawiki.api.parse.js index e8d1b3e6cb..ea0388c103 100644 --- a/resources/mediawiki.api/mediawiki.api.parse.js +++ b/resources/mediawiki.api/mediawiki.api.parse.js @@ -1,42 +1,43 @@ /** - * 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 ) ); diff --git a/resources/mediawiki.api/mediawiki.api.titleblacklist.js b/resources/mediawiki.api/mediawiki.api.titleblacklist.js index 1f7e275aa8..8c46717abd 100644 --- a/resources/mediawiki.api/mediawiki.api.titleblacklist.js +++ b/resources/mediawiki.api/mediawiki.api.titleblacklist.js @@ -1,33 +1,39 @@ /** - * 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, @@ -35,18 +41,28 @@ 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 ) ); diff --git a/resources/mediawiki.api/mediawiki.api.watch.js b/resources/mediawiki.api/mediawiki.api.watch.js index 6cbccbfc39..c86a90a781 100644 --- a/resources/mediawiki.api/mediawiki.api.watch.js +++ b/resources/mediawiki.api/mediawiki.api.watch.js @@ -1,56 +1,72 @@ /** - * 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 ) ); diff --git a/resources/mediawiki/mediawiki.Title.js b/resources/mediawiki/mediawiki.Title.js index dad6021906..b86a14baeb 100644 --- a/resources/mediawiki/mediawiki.Title.js +++ b/resources/mediawiki/mediawiki.Title.js @@ -1,6 +1,4 @@ -/** - * mediaWiki.Title - * +/*! * @author Neil Kandalgaonkar, 2010 * @author Timo Tijhof, 2011 * @since 1.18 @@ -12,13 +10,12 @@ /* 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 @@ -35,17 +32,16 @@ } 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 ) { @@ -55,8 +51,9 @@ var /** * 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 ) { @@ -68,13 +65,15 @@ var /** * Sanitize name. + * @ignore */ fixName = function ( s ) { return clean( $.trim( s ) ); }, /** - * Sanitize name. + * Sanitize extension. + * @ignore */ fixExt = function ( s ) { return clean( s ); @@ -82,6 +81,7 @@ var /** * Sanitize namespace id. + * @ignore * @param id {Number} Namespace id. * @return {Number|Boolean} The id as-is or boolean false if invalid. */ @@ -99,8 +99,8 @@ var /** * 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. */ @@ -125,8 +125,9 @@ var /** * 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 ) { @@ -153,8 +154,9 @@ var /** * 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 ) { @@ -179,8 +181,9 @@ var /** * 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; @@ -198,20 +201,27 @@ var }; /** - * @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]; @@ -231,7 +241,7 @@ var /** * Get the namespace number. - * @return {Number} + * @return {number} */ getNamespaceId: function (){ return this.ns; @@ -240,7 +250,7 @@ var /** * 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 ? '' : ':'); @@ -248,7 +258,7 @@ var /** * The name, like "Foo_bar" - * @return {String} + * @return {string} */ getName: function () { if ( $.inArray( this.ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) { @@ -260,7 +270,7 @@ var /** * The name, like "Foo bar" - * @return {String} + * @return {string} */ getNameText: function () { return text( this.getName() ); @@ -269,6 +279,7 @@ var /** * 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(); @@ -276,7 +287,7 @@ var /** * Get full name in text form, like "File:Foo bar.jpg". - * @return {String} + * @return {string} */ getPrefixedText: function () { return text( this.getPrefixedDb() ); @@ -284,7 +295,7 @@ var /** * The main title (without namespace), like "Foo_bar.jpg" - * @return {String} + * @return {string} */ getMain: function () { return this.getName() + this.getDotExtension(); @@ -292,7 +303,7 @@ var /** * The "text" form, like "Foo bar.jpg" - * @return {String} + * @return {string} */ getMainText: function () { return text( this.getMain() ); @@ -300,7 +311,7 @@ var /** * Get the extension (returns null if there was none) - * @return {String|null} extension + * @return {string|null} */ getExtension: function () { return this.ext; @@ -308,7 +319,7 @@ var /** * Convenience method: return string like ".jpg", or "" if no extension - * @return {String} + * @return {string} */ getDotExtension: function () { return this.ext === null ? '' : '.' + this.ext; @@ -316,7 +327,8 @@ var /** * Return the URL to this title - * @return {String} + * @see mw.util#wikiGetlink + * @return {string} */ getUrl: function () { return mw.util.wikiGetlink( this.toString() ); @@ -324,7 +336,8 @@ var /** * 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 ); diff --git a/resources/mediawiki/mediawiki.js b/resources/mediawiki/mediawiki.js index b0abc9e6f6..73d5635f19 100644 --- a/resources/mediawiki/mediawiki.js +++ b/resources/mediawiki/mediawiki.js @@ -13,14 +13,13 @@ var mw = ( function ( $, undefined ) { /* 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 : {}; @@ -39,7 +38,7 @@ var mw = ( function ( $, undefined ) { * 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; @@ -98,7 +97,7 @@ var mw = ( function ( $, undefined ) { * 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; @@ -116,15 +115,14 @@ var mw = ( function ( $, undefined ) { }; /** - * 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'; @@ -152,8 +150,8 @@ var mw = ( function ( $, undefined ) { /** * 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; @@ -166,7 +164,7 @@ var mw = ( function ( $, undefined ) { /** * 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 if key does not exist. + * @return {string} Message as a string in the current form or `` if key does not exist. */ toString: function () { var text; @@ -233,13 +231,19 @@ var mw = ( function ( $, undefined ) { /** * 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 */ @@ -249,77 +253,72 @@ var mw = ( function ( $, undefined ) { */ 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 () { @@ -338,29 +337,32 @@ var mw = ( function ( $, undefined ) { * 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 = [], @@ -392,10 +394,11 @@ var mw = ( function ( $, undefined ) { /** * 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 . - * @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 ``. + * @return {HTMLElement} Node reference to the created `