moved jQuery.fn.enableCheckboxShiftClick to it's own file and renamed to jQuery.fn...
[mediawiki.git] / resources / mediawiki.util / mediawiki.util.js
blob2c8f973fea3ea5ab718d745c76950810f391826a
1 /*
2  * Utilities
3  */
5 (function ($, mw) {
7         mediaWiki.util = {
9                 /* Initialisation */
10                 'initialised' : false,
11                 'init' : function () {
12                         if (this.initialised === false) {
13                                 this.initialised = true;
15                                 // Set tooltipAccessKeyPrefix
16                                 if (is_opera) {
17                                         this.tooltipAccessKeyPrefix = 'shift-esc-';
18                                 } else if (is_chrome) {
19                                         this.tooltipAccessKeyPrefix = is_chrome_mac ? 'ctrl-option-' : 'alt-';
20                                 } else if (!is_safari_win && is_safari && webkit_version > 526) {
21                                         this.tooltipAccessKeyPrefix = 'ctrl-alt-';
22                                 } else if (!is_safari_win &&
23                                         (is_safari || clientPC.indexOf('mac') !== -1 || clientPC.indexOf('konqueror') !== -1)) {
24                                         this.tooltipAccessKeyPrefix = 'ctrl-';
25                                 } else if (is_ff2) {
26                                         this.tooltipAccessKeyPrefix = 'alt-shift-';
27                                 }
29                                 // Prototype enhancements
30                                 if (typeof String.prototype.ucFirst === 'undefined') {
31                                         String.prototype.ucFirst = function () {
32                                                 return this.substr(0, 1).toUpperCase() + this.substr(1, this.length);
33                                         };
34                                 }
36                                 // Any initialisation after the DOM is ready
37                                 $(function () {
38                                 
39                                         // Enable CheckboxShiftClick
40                                         $('input[type=checkbox]:not(.noshiftselect)').checkboxShiftClick();
41                                         
42                                         // Fill bodyContant var
43                                         if ($('#bodyContent').length) {
44                                                 mw.util.$content = $('#bodyContent');
45                                         } else if ($('#article').length) {
46                                                 mw.util.$content = $('#article');
47                                         } else {
48                                                 mw.util.$content = $('#content');
49                                         }
50                                 });
53                                 return true;
54                         }
55                         return false;
56                 },
58                 /* Main body */
60                 /**
61                 * Encodes the string like PHP's rawurlencode
62                 *
63                 * @param String str             string to be encoded
64                 */
65                 'rawurlencode' : function (str) {
66                         str = (str + '').toString();
67                         return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28')
68                                 .replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/~/g, '%7E');
69                 },
71                 /**
72                 * Encode pagetitles for use in a URL
73                 * We want / and : to be included as literal characters in our title URLs
74                 * as they otherwise fatally break the title
75                 *
76                 * @param String str             string to be encoded
77                 */
78                 'wikiUrlencode' : function (str) {
79                         return this.rawurlencode(str).replace(/%20/g, '_').replace(/%3A/g, ':').replace(/%2F/g, '/');
80                 },
82                 /**
83                 * Get the full url to a pagename
84                 *
85                 * @param String str             pagename to link to
86                 */
87                 'getWikilink' : function (str) {
88                         return wgServer + wgArticlePath.replace('$1', this.wikiUrlencode(str));
89                 },
91                 /**
92                 * Check is a variable is empty. Support for strings, booleans, arrays and objects.
93                 * String "0" is considered empty. String containing only whitespace (ie. "  ") is considered not empty.
94                 *
95                 * @param Mixed v        the variable to check for empty ness
96                 */
97                 'isEmpty' : function (v) {
98                         var key;
99                         if (v === "" || v === 0 || v === "0" || v === null || v === false || typeof v === 'undefined') {
100                                 return true;
101                         }
102                         if (v.length === 0) {
103                                 return true;
104                         }
105                         if (typeof v === 'object') {
106                                 for (key in v) {
107                                         return false;
108                                 }
109                                 return true;
110                         }
111                         return false;
112                 },
115                 /**
116                 * Grabs the url parameter value for the given parameter
117                 * Returns null if not found
118                 *
119                 * @param String param   paramter name
120                 * @param String url             url to search through (optional)
121                 */
122                 'getParamValue' : function (param, url) {
123                         url = url ? url : document.location.href;
124                         var re = new RegExp('[^#]*[&?]' + param + '=([^&#]*)'); // Get last match, stop at hash
125                         var m = re.exec(url);
126                         if (m && m.length > 1) {
127                                 return decodeURIComponent(m[1]);
128                         }
129                         return null;
130                 },
132                 /**
133                 * Converts special characters to their HTML entities
134                 *
135                 * @param String                 str text to escape
136                 * @param Bool                   quotes if true escapes single and double quotes aswell (by default false)
137                 */
138                 'htmlEscape' : function (str, quotes) {
139                         str = $('<div/>').text(str).html();
140                         if (typeof quotes === 'undefined') {
141                                 quotes = false;
142                         }
143                         if (quotes === true) {
144                                 str = str.replace(/'/g, '&#039;').replace(/"/g, '&quot;');
145                         }
146                         return str;
147                 },
149                 /**
150                 * Converts HTML entities back to text
151                 *
152                 * @param String str             text to unescape
153                 */
154                 'htmlUnescape' : function (str) {
155                         return $('<div/>').html(str).text();
156                 },
158                 // Access key prefix
159                 // will be re-defined based on browser/operating system detection in mw.util.init()
160                 'tooltipAccessKeyPrefix' : 'alt-',
162                 // Regex to match accesskey tooltips
163                 'tooltipAccessKeyRegexp': /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/,
165                 /**
166                  * Add the appropriate prefix to the accesskey shown in the tooltip.
167                  * If the nodeList parameter is given, only those nodes are updated;
168                  * otherwise, all the nodes that will probably have accesskeys by
169                  * default are updated.
170                  *
171                  * @param Mixed nodeList        jQuery object, or array of elements
172                  */
173                 'updateTooltipAccessKeys' : function (nodeList) {
174                         var $nodes;
175                         if (nodeList instanceof jQuery) {
176                                 $nodes = nodeList;
177                         } else if (nodeList) {
178                                 $nodes = $(nodeList);
179                         } else {
180                                 // Rather than scanning all links, just
181                                 $('#column-one a, #mw-head a, #mw-panel a, #p-logo a');
183                                 // these are rare enough that no such optimization is needed
184                                 this.updateTooltipAccessKeys($('input'));
185                                 this.updateTooltipAccessKeys($('label'));
186                                 return;
187                         }
189                         $nodes.each(function (i) {
190                                 var tip = $(this).attr('title');
191                                 if (!!tip && mw.util.tooltipAccessKeyRegexp.exec(tip)) {
192                                         tip = tip.replace(mw.util.tooltipAccessKeyRegexp, '[' + mw.util.tooltipAccessKeyPrefix + "$5]");
193                                         $(this).attr('title', tip);
194                                 }
195                         });
196                 },
197                 
198                 // jQuery object that refers to the page-content element
199                 // Populated by init()
200                 '$content' : null,
203                 /**
204                  * Add a link to a portlet menu on the page, such as:
205                  *
206                  * p-cactions (Content actions), p-personal (Personal tools), p-navigation (Navigation), p-tb (Toolbox)
207                  *
208                  * The first three paramters are required, others are optionals. Though
209                  * providing an id and tooltip is recommended.
210                  *
211                  * By default the new link will be added to the end of the list. To add the link before a given existing item,
212                  * pass the DOM node (document.getElementById('foobar') or the jQuery-selector ('#foobar') of that item.
213                  *
214                  * @example mw.util.addPortletLink('p-tb', 'http://mediawiki.org/', 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print')
215                  *
216                  * @param String portlet        id of the target portlet ('p-cactions' or 'p-personal' etc.)
217                  * @param String href           link URL
218                  * @param String text           link text (will be automatically lowercased by CSS for p-cactions in Monobook)
219                  * @param String id                     id of the new item, should be unique and preferably have the appropriate prefix ('ca-', 'pt-', 'n-' or 't-')
220                  * @param String tooltip        text to show when hovering over the link, without accesskey suffix
221                  * @param String accesskey      accesskey to activate this link (one character, try to avoid conflicts. Use $('[accesskey=x').get() in the console to see if 'x' is already used.
222                  * @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 will be ignored if not the so
223                  *
224                  * @return Node                         the DOM node of the new item (a LI element, or A element for older skins) or null
225                  */
226                 'addPortletLink' : function (portlet, href, text, id, tooltip, accesskey, nextnode) {
227                         var $link = $('<a />').attr('href', href).text(text);
228                         
229                         // Some skins don't have portlets
230                         // Just add it to the bottom of their 'sidebar' element ignoring the specified portlet target
231                         switch (skin) {
232                         case 'standard' :
233                         case 'cologneblue' :
234                                 $("#quickbar").append($link.after('<br />'));
235                                 return $link.get(0);
236                         case 'nostalgia' :
237                                 $("#searchform").before($link).before(' &#124; ');
238                                 return $link.get(0);
239                         default : // chick, modern, monobook, myskin, simple, vector...
240                                 
241                                 var $portlet = $('#' + portlet);
242                                 if ($portlet.length === 0) {
243                                         return null;
244                                 }
245                                 var $ul = $portlet.find('ul').eq(0);
246                                 if ($ul.length === 0) {
247                                         if ($portlet.find('div').length === 0) {
248                                                 $portlet.append('<ul />');
249                                         } else {
250                                                 $portlet.find('div').eq(-1).append('<ul />');
251                                         }
252                                         $ul = $portlet.find('ul').eq(0);
253                                 }
254                                 if ($ul.length === 0) {
255                                         return null;
256                                 }
257         
258                                 // unhide portlet if it was hidden before
259                                 $portlet.removeClass('emptyPortlet');
260                                 
261                                 var $item = $link.wrap('<li><span /></li>').parent().parent();
263                                 if (id) {
264                                         $item.attr('id', id);
265                                 }
266                                 if (accesskey) {
267                                         $link.attr('accesskey', accesskey);
268                                         tooltip += ' [' + accesskey + ']';
269                                 }
270                                 if (tooltip) {
271                                         $link.attr('title', tooltip);
272                                 }
273                                 if (accesskey && tooltip) {
274                                         this.updateTooltipAccessKeys($link);
275                                 }
276         
277                                 // Append using DOM-element passing
278                                 if (nextnode && nextnode.parentNode == $ul.get(0)) {
279                                         $(nextnode).before($item);
280                                 } else {
281                                         // If the jQuery selector isn't found within the <ul>, just append it at the end
282                                         if ($ul.find(nextnode).length === 0) {
283                                                 $ul.append($item);
284                                         } else {
285                                                 // Append using jQuery CSS selector
286                                                 $ul.find(nextnode).eq(0).before($item);
287                                         }
288                                 }
289         
290                                 return $item.get(0);
291                         }
292                 }
294         };
296         mediaWiki.util.init();
298 })(jQuery, mediaWiki);