Index: trunk/phase3/includes/OutputPage.php |
— | — | @@ -1613,6 +1613,7 @@ |
1614 | 1614 | |
1615 | 1615 | // Add base resources |
1616 | 1616 | $this->addModules( array( 'mediawiki.legacy.wikibits' ) ); |
| 1617 | + $this->addModules( array( 'mediawiki.util' ) ); |
1617 | 1618 | |
1618 | 1619 | // Add various resources if required |
1619 | 1620 | if ( $wgUseAjax ) { |
Index: trunk/phase3/resources/Resources.php |
— | — | @@ -326,6 +326,9 @@ |
327 | 327 | 'scripts' => 'resources/mediawiki/mediawiki.views.history.js', |
328 | 328 | 'dependencies' => 'mediawiki.legacy.history', |
329 | 329 | ) ), |
| 330 | + 'mediawiki.util' => new ResourceLoaderFileModule( array( |
| 331 | + 'scripts' => 'resources/mediawiki/mediawiki.util.js', |
| 332 | + ) ), |
330 | 333 | |
331 | 334 | /* MediaWiki Legacy */ |
332 | 335 | |
Index: trunk/phase3/resources/mediawiki/mediawiki.util.js |
— | — | @@ -0,0 +1,228 @@ |
| 2 | +/*jslint white: true, browser: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true */ |
| 3 | +/* |
| 4 | + * Utilities |
| 5 | + */ |
| 6 | + |
| 7 | +(function ($, mw) { |
| 8 | + |
| 9 | + mediaWiki.util = { |
| 10 | + |
| 11 | + /* Initialisation */ |
| 12 | + 'initialised' : false, |
| 13 | + 'init' : function () { |
| 14 | + if (this.initialised === false){ |
| 15 | + this.initialised = true; |
| 16 | + |
| 17 | + |
| 18 | + // Set tooltipAccessKeyPrefix |
| 19 | + if ( is_opera ) { |
| 20 | + this.tooltipAccessKeyPrefix = 'shift-esc-'; |
| 21 | + } else if ( is_chrome ) { |
| 22 | + this.tooltipAccessKeyPrefix = is_chrome_mac ? 'ctrl-option-' : 'alt-'; |
| 23 | + } else if ( !is_safari_win && is_safari && webkit_version > 526 ) { |
| 24 | + this.tooltipAccessKeyPrefix = 'ctrl-alt-'; |
| 25 | + } else if ( !is_safari_win && ( is_safari |
| 26 | + || clientPC.indexOf('mac') != -1 |
| 27 | + || clientPC.indexOf('konqueror') != -1 ) ) { |
| 28 | + this.tooltipAccessKeyPrefix = 'ctrl-'; |
| 29 | + } else if ( is_ff2 ) { |
| 30 | + this.tooltipAccessKeyPrefix = 'alt-shift-'; |
| 31 | + } |
| 32 | + |
| 33 | + |
| 34 | + return true; |
| 35 | + } |
| 36 | + return false; |
| 37 | + }, |
| 38 | + |
| 39 | + /* Main body */ |
| 40 | + |
| 41 | + /** |
| 42 | + * Encodes the string like PHP's rawurlencode |
| 43 | + * |
| 44 | + * @param String str string to be encoded |
| 45 | + */ |
| 46 | + 'rawurlencode' : function (str) { |
| 47 | + str = (str + '').toString(); |
| 48 | + return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28') |
| 49 | + .replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/~/g, '%7E'); |
| 50 | + }, |
| 51 | + |
| 52 | + /** |
| 53 | + * Encode pagetitles for use in a URL |
| 54 | + * We want / and : to be included as literal characters in our title URLs |
| 55 | + * as they otherwise fatally break the title |
| 56 | + * |
| 57 | + * @param String str string to be encoded |
| 58 | + */ |
| 59 | + 'wikiUrlencode' : function (str) { |
| 60 | + return this.rawurlencode(str).replace(/%20/g, '_').replace(/%3A/g, ':').replace(/%2F/g, '/'); |
| 61 | + }, |
| 62 | + |
| 63 | + |
| 64 | + /** |
| 65 | + * Grabs the url parameter value for the given parameter |
| 66 | + * Returns null if not found |
| 67 | + * |
| 68 | + * @param String param paramter name |
| 69 | + * @param String url url to search through (optional) |
| 70 | + */ |
| 71 | + 'getParamValue' : function (param, url) { |
| 72 | + url = url ? url : document.location.href; |
| 73 | + var re = new RegExp('[^#]*[&?]' + param + '=([^&#]*)'); // Get last match, stop at hash |
| 74 | + var m = re.exec(url); |
| 75 | + if (m && m.length > 1) { |
| 76 | + return decodeURIComponent(m[1]); |
| 77 | + } |
| 78 | + return null; |
| 79 | + }, |
| 80 | + |
| 81 | + /** |
| 82 | + * Converts special characters to their HTML entities |
| 83 | + * |
| 84 | + * @param String str text to escape |
| 85 | + * @param Bool quotes if true escapes single and double quotes aswell (by default false) |
| 86 | + */ |
| 87 | + 'htmlEscape' : function (str, quotes) { |
| 88 | + str = $('<div/>').text(str).html(); |
| 89 | + if (typeof quotes === 'undefined') { |
| 90 | + quotes = false; |
| 91 | + } |
| 92 | + if (quotes === true) { |
| 93 | + str = str.replace(/'/g, ''').replace(/"/g, '"'); |
| 94 | + } |
| 95 | + return str; |
| 96 | + }, |
| 97 | + |
| 98 | + /** |
| 99 | + * Converts HTML entities back to text |
| 100 | + * |
| 101 | + * @param String str text to unescape |
| 102 | + */ |
| 103 | + 'htmlUnescape' : function (str) { |
| 104 | + return $('<div/>').html(str).text(); |
| 105 | + }, |
| 106 | + |
| 107 | + // Access key prefix |
| 108 | + // will be re-defined based on browser/operating system detection in mw.util.init() |
| 109 | + 'tooltipAccessKeyPrefix' : 'alt-', |
| 110 | + |
| 111 | + // Regex to match accesskey tooltips |
| 112 | + 'tooltipAccessKeyRegexp': /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/, |
| 113 | + |
| 114 | + /** |
| 115 | + * Add the appropriate prefix to the accesskey shown in the tooltip. |
| 116 | + * If the nodeList parameter is given, only those nodes are updated; |
| 117 | + * otherwise, all the nodes that will probably have accesskeys by |
| 118 | + * default are updated. |
| 119 | + * |
| 120 | + * @param Mixed nodeList jQuery object, or array of elements |
| 121 | + */ |
| 122 | + 'updateTooltipAccessKeys' : function (nodeList) { |
| 123 | + var $nodes; |
| 124 | + if (nodeList instanceof jQuery) { |
| 125 | + $nodes = nodeList; |
| 126 | + } else if (nodeList) { |
| 127 | + $nodes = $(nodeList); |
| 128 | + } else { |
| 129 | + // Rather than scanning all links, just |
| 130 | + $("#column-one a, #mw-head a, #mw-panel a, #p-logo a"); |
| 131 | + |
| 132 | + // these are rare enough that no such optimization is needed |
| 133 | + this.updateTooltipAccessKeys($('input')); |
| 134 | + this.updateTooltipAccessKeys($('label')); |
| 135 | + return; |
| 136 | + } |
| 137 | + |
| 138 | + $nodes.each(function (i) { |
| 139 | + var tip = $(this).attr('title'); |
| 140 | + if (!!tip && mw.util.tooltipAccessKeyRegexp.exec(tip)) { |
| 141 | + tip = tip.replace(mw.util.tooltipAccessKeyRegexp, '[' + tooltipAccessKeyPrefix + "$5]"); |
| 142 | + $(this).attr('title', tip); |
| 143 | + } |
| 144 | + }); |
| 145 | + }, |
| 146 | + |
| 147 | + |
| 148 | + /** |
| 149 | + * Add a link to a portlet menu on the page, such as: |
| 150 | + * |
| 151 | + * p-cactions (Content actions), p-personal (Personal tools), p-navigation (Navigation), p-tb (Toolbox) |
| 152 | + * |
| 153 | + * The first three paramters are required, others are optionals. Though |
| 154 | + * providing an id and tooltip is recommended. |
| 155 | + * |
| 156 | + * By default the new link will be added to the end of the list. To add the link before a given existing item, |
| 157 | + * pass the DOM node (document.getElementById('foobar') or the jQuery-selector ('#foobar') of that item. |
| 158 | + * |
| 159 | + * @example mw.util.addPortletLink('p-tb', 'http://mediawiki.org/', 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print') |
| 160 | + * |
| 161 | + * @param String portlet id of the target portlet ("p-cactions" or "p-personal" etc.) |
| 162 | + * @param String href link URL |
| 163 | + * @param String text link text (will be automatically lowercased by CSS for p-cactions in Monobook) |
| 164 | + * @param String id id of the new item, should be unique and preferably have the appropriate prefix ("ca-", "pt-", "n-" or "t-") |
| 165 | + * @param String tooltip text to show when hovering over the link, without accesskey suffix |
| 166 | + * @param String accesskey accesskey to activate this link (one character, try to avoid conflicts) |
| 167 | + * @param mixed nextnode DOM node or jQuery-selector of the item that the new item should be added before, should be another item in the same list |
| 168 | + * |
| 169 | + * @return Node the DOM node of the new item (a LI element) or null |
| 170 | + */ |
| 171 | + 'addPortletLink' : function (portlet, href, text, id, tooltip, accesskey, nextnode) { |
| 172 | + var $portlet = $('#' + portlet); |
| 173 | + if ($portlet.length === 0) { |
| 174 | + return null; |
| 175 | + } |
| 176 | + var $ul = $portlet.find('ul').eq(0); |
| 177 | + if ($ul.length === 0) { |
| 178 | + if ($portlet.find('div').length === 0) { |
| 179 | + $portlet.append('<ul />'); |
| 180 | + } else { |
| 181 | + $portlet.find('div').eq(-1).append('<ul />'); |
| 182 | + } |
| 183 | + $ul = $portlet.find('ul').eq(0); |
| 184 | + } |
| 185 | + if ($ul.length === 0) { |
| 186 | + return null; |
| 187 | + } |
| 188 | + |
| 189 | + // unhide portlet if it was hidden before |
| 190 | + $portlet.removeClass('emptyPortlet'); |
| 191 | + |
| 192 | + var $link = $('<a />').attr('href', href).text(text); |
| 193 | + var $item = $link.wrap('<li><span /></li>').parent().parent(); |
| 194 | + |
| 195 | + if (id) { |
| 196 | + $item.attr('id', id); |
| 197 | + } |
| 198 | + if (accesskey) { |
| 199 | + $link.attr('accesskey', accesskey); |
| 200 | + tooltip += ' [' + accesskey + ']'; |
| 201 | + } |
| 202 | + if (tooltip) { |
| 203 | + $link.attr('title', tooltip); |
| 204 | + } |
| 205 | + if (accesskey && tooltip) { |
| 206 | + this.updateTooltipAccessKeys($link); |
| 207 | + } |
| 208 | + |
| 209 | + // Append using DOM-element passing |
| 210 | + if (nextnode && nextnode.parentNode == $ul.get(0)) { |
| 211 | + $(nextnode).before($item); |
| 212 | + } else { |
| 213 | + // If the jQuery selector isn't found within the <ul>, just append it at the end |
| 214 | + if ($ul.find(nextnode).length === 0) { |
| 215 | + $ul.append($item); |
| 216 | + } else { |
| 217 | + // Append using jQuery CSS selector |
| 218 | + $ul.find(nextnode).eq(0).before($item); |
| 219 | + } |
| 220 | + } |
| 221 | + |
| 222 | + return $item.get(0); |
| 223 | + } |
| 224 | + |
| 225 | + }; |
| 226 | + |
| 227 | +})(jQuery, mediaWiki); |
| 228 | + |
| 229 | +mediaWiki.util.init(); |
\ No newline at end of file |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.util.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 230 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.js |
— | — | @@ -3,7 +3,7 @@ |
4 | 4 | */ |
5 | 5 | |
6 | 6 | // Make calling .indexOf() on an array work on older browsers |
7 | | -if ( typeof Array.prototype.indexOf === 'undefined' ) { |
| 7 | +if ( typeof Array.prototype.indexOf === 'undefined' ) { |
8 | 8 | Array.prototype.indexOf = function( needle ) { |
9 | 9 | for ( var i = 0; i < this.length; i++ ) { |
10 | 10 | if ( this[i] === needle ) { |
— | — | @@ -14,13 +14,13 @@ |
15 | 15 | }; |
16 | 16 | } |
17 | 17 | // Add array comparison functionality |
18 | | -if ( typeof Array.prototype.compare === 'undefined' ) { |
| 18 | +if ( typeof Array.prototype.compare === 'undefined' ) { |
19 | 19 | Array.prototype.compare = function( against ) { |
20 | 20 | if ( this.length != against.length ) { |
21 | 21 | return false; |
22 | 22 | } |
23 | 23 | for ( var i = 0; i < against.length; i++ ) { |
24 | | - if ( this[i].compare ) { |
| 24 | + if ( this[i].compare ) { |
25 | 25 | if ( !this[i].compare( against[i] ) ) { |
26 | 26 | return false; |
27 | 27 | } |
— | — | @@ -53,7 +53,7 @@ |
54 | 54 | this.prototypes = { |
55 | 55 | /* |
56 | 56 | * An object which allows single and multiple get/set/exists functionality on a list of key / value pairs |
57 | | - * |
| 57 | + * |
58 | 58 | * @param {boolean} global whether to get/set/exists values on the window object or a private object |
59 | 59 | * @param {function} parser function to perform extra processing; in the form of function( value, options ) |
60 | 60 | * @param {function} fallback function to format default fallback; in the form of function( key ) |
— | — | @@ -70,10 +70,10 @@ |
71 | 71 | |
72 | 72 | /** |
73 | 73 | * Gets one or more values |
74 | | - * |
| 74 | + * |
75 | 75 | * If called with no arguments, all values will be returned. If a parser is in use, no parsing will take |
76 | 76 | * place when calling with no arguments or calling with an array of names. |
77 | | - * |
| 77 | + * |
78 | 78 | * @param {mixed} selection string name of value to get, array of string names of values to get, or object |
79 | 79 | * of name/option pairs |
80 | 80 | * @param {object} options optional set of options which are also passed to a parser if in use; only used |
— | — | @@ -120,7 +120,7 @@ |
121 | 121 | |
122 | 122 | /** |
123 | 123 | * Sets one or multiple configuration values using a key and a value or an object of keys and values |
124 | | - * |
| 124 | + * |
125 | 125 | * @param {mixed} key string of name by which value will be made accessible, or object of name/value pairs |
126 | 126 | * @param {mixed} value optional value to set, only in use when key is a string |
127 | 127 | */ |
— | — | @@ -161,7 +161,7 @@ |
162 | 162 | |
163 | 163 | /* |
164 | 164 | * List of configuration values |
165 | | - * |
| 165 | + * |
166 | 166 | * In legacy mode the values this object wraps will be in the global space |
167 | 167 | */ |
168 | 168 | this.config = new this.prototypes.map( LEGACY_GLOBALS ); |
— | — | @@ -204,11 +204,11 @@ |
205 | 205 | var that = this; |
206 | 206 | /* |
207 | 207 | * Mapping of registered modules |
208 | | - * |
| 208 | + * |
209 | 209 | * The jquery module is pre-registered, because it must have already been provided for this object to have |
210 | 210 | * been built, and in debug mode jquery would have been provided through a unique loader request, making it |
211 | 211 | * impossible to hold back registration of jquery until after mediawiki. |
212 | | - * |
| 212 | + * |
213 | 213 | * Format: |
214 | 214 | * { |
215 | 215 | * 'moduleName': { |
— | — | @@ -258,7 +258,7 @@ |
259 | 259 | // Resolves dynamic loader function and replaces it with it's own results |
260 | 260 | if ( typeof registry[module].dependencies === 'function' ) { |
261 | 261 | registry[module].dependencies = registry[module].dependencies(); |
262 | | - // Ensures the module's dependencies are always in an array |
| 262 | + // Ensures the module's dependencies are always in an array |
263 | 263 | if ( typeof registry[module].dependencies !== 'object' ) { |
264 | 264 | registry[module].dependencies = [registry[module].dependencies]; |
265 | 265 | } |
— | — | @@ -280,7 +280,7 @@ |
281 | 281 | |
282 | 282 | /** |
283 | 283 | * Gets a list of modules names that a module dependencies in their proper dependency order |
284 | | - * |
| 284 | + * |
285 | 285 | * @param mixed string module name or array of string module names |
286 | 286 | * @return list of dependencies |
287 | 287 | * @throws Error if circular reference is detected |
— | — | @@ -311,7 +311,7 @@ |
312 | 312 | /** |
313 | 313 | * Narrows a list of module names down to those matching a specific state. Possible states are 'undefined', |
314 | 314 | * 'registered', 'loading', 'loaded', or 'ready' |
315 | | - * |
| 315 | + * |
316 | 316 | * @param mixed string or array of strings of module states to filter by |
317 | 317 | * @param array list of module names to filter (optional, all modules will be used by default) |
318 | 318 | * @return array list of filtered module names |
— | — | @@ -345,7 +345,7 @@ |
346 | 346 | |
347 | 347 | /** |
348 | 348 | * Executes a loaded module, making it ready to use |
349 | | - * |
| 349 | + * |
350 | 350 | * @param string module name to execute |
351 | 351 | */ |
352 | 352 | function execute( module ) { |
— | — | @@ -413,7 +413,7 @@ |
414 | 414 | |
415 | 415 | /** |
416 | 416 | * Adds a dependencies to the queue with optional callbacks to be run when the dependencies are ready or fail |
417 | | - * |
| 417 | + * |
418 | 418 | * @param mixed string moulde name or array of string module names |
419 | 419 | * @param function ready callback to execute when all dependencies are ready |
420 | 420 | * @param function error callback to execute when any dependency fails |
— | — | @@ -621,7 +621,7 @@ |
622 | 622 | |
623 | 623 | /** |
624 | 624 | * Executes a function as soon as one or more required modules are ready |
625 | | - * |
| 625 | + * |
626 | 626 | * @param mixed string or array of strings of modules names the callback dependencies to be ready before |
627 | 627 | * executing |
628 | 628 | * @param function callback to execute when all dependencies are ready (optional) |
— | — | @@ -658,7 +658,7 @@ |
659 | 659 | |
660 | 660 | /** |
661 | 661 | * Loads an external script or one or more modules for future use |
662 | | - * |
| 662 | + * |
663 | 663 | * @param {mixed} modules either the name of a module, array of modules, or a URL of an external script or style |
664 | 664 | * @param {string} type mime-type to use if calling with a URL of an external script or style; acceptable values |
665 | 665 | * are "text/css" and "text/javascript"; if no type is provided, text/javascript is assumed |
— | — | @@ -717,7 +717,7 @@ |
718 | 718 | |
719 | 719 | /** |
720 | 720 | * Changes the state of a module |
721 | | - * |
| 721 | + * |
722 | 722 | * @param mixed module string module name or object of module name/state pairs |
723 | 723 | * @param string state string state name |
724 | 724 | */ |
— | — | @@ -736,7 +736,7 @@ |
737 | 737 | |
738 | 738 | /** |
739 | 739 | * Gets the version of a module |
740 | | - * |
| 740 | + * |
741 | 741 | * @param string module name of module to get version for |
742 | 742 | */ |
743 | 743 | this.version = function( module ) { |
— | — | @@ -753,7 +753,6 @@ |
754 | 754 | |
755 | 755 | /* Extension points */ |
756 | 756 | |
757 | | - this.util = {}; |
758 | 757 | this.legacy = {}; |
759 | 758 | |
760 | 759 | } )( jQuery ); |
— | — | @@ -767,3 +766,4 @@ |
768 | 767 | |
769 | 768 | // Alias $j to jQuery for backwards compatibility |
770 | 769 | window.$j = jQuery; |
| 770 | +window.mw = mediaWiki; |
\ No newline at end of file |