added mw.util.getWikilink and ported enableCheckboxShiftClick to jQuery
[lhc/web/wiklou.git] / resources / mediawiki / mediawiki.util.js
1 /*jslint white: true, browser: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true */
2 /*
3 * Utilities
4 */
5
6 (function ($, mw) {
7
8 mediaWiki.util = {
9
10 /* Initialisation */
11 'initialised' : false,
12 'init' : function () {
13 if (this.initialised === false) {
14 this.initialised = true;
15
16
17 // Set tooltipAccessKeyPrefix
18 if (is_opera) {
19 this.tooltipAccessKeyPrefix = 'shift-esc-';
20 } else if (is_chrome) {
21 this.tooltipAccessKeyPrefix = is_chrome_mac ? 'ctrl-option-' : 'alt-';
22 } else if (!is_safari_win && is_safari && webkit_version > 526) {
23 this.tooltipAccessKeyPrefix = 'ctrl-alt-';
24 } else if (!is_safari_win &&
25 (is_safari || clientPC.indexOf('mac') !== -1 || clientPC.indexOf('konqueror') !== -1)) {
26 this.tooltipAccessKeyPrefix = 'ctrl-';
27 } else if (is_ff2) {
28 this.tooltipAccessKeyPrefix = 'alt-shift-';
29 }
30
31 // Setup CheckboxShiftClick
32 $.fn.enableCheckboxShiftClick = function () {
33 var prevCheckbox = null;
34 var $box = this;
35 $box.click(function (e) {
36 if (prevCheckbox !== null && e.shiftKey) {
37 $box.slice(
38 Math.min($box.index(prevCheckbox), $box.index(e.target)),
39 Math.max($box.index(prevCheckbox), $box.index(e.target)) + 1
40 ).attr({checked: e.target.checked ? 'checked' : ''});
41 }
42 prevCheckbox = e.target;
43 });
44 return $box;
45 };
46
47 // Any initialisation after the DOM is ready
48 $(function () {
49 $('input[type=checkbox]:not(.noshiftselect)').enableCheckboxShiftClick();
50 });
51
52
53 return true;
54 }
55 return false;
56 },
57
58 /* Main body */
59
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 },
70
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 },
81
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 },
90
91
92 /**
93 * Grabs the url parameter value for the given parameter
94 * Returns null if not found
95 *
96 * @param String param paramter name
97 * @param String url url to search through (optional)
98 */
99 'getParamValue' : function (param, url) {
100 url = url ? url : document.location.href;
101 var re = new RegExp('[^#]*[&?]' + param + '=([^&#]*)'); // Get last match, stop at hash
102 var m = re.exec(url);
103 if (m && m.length > 1) {
104 return decodeURIComponent(m[1]);
105 }
106 return null;
107 },
108
109 /**
110 * Converts special characters to their HTML entities
111 *
112 * @param String str text to escape
113 * @param Bool quotes if true escapes single and double quotes aswell (by default false)
114 */
115 'htmlEscape' : function (str, quotes) {
116 str = $('<div/>').text(str).html();
117 if (typeof quotes === 'undefined') {
118 quotes = false;
119 }
120 if (quotes === true) {
121 str = str.replace(/'/g, '&#039;').replace(/"/g, '&quot;');
122 }
123 return str;
124 },
125
126 /**
127 * Converts HTML entities back to text
128 *
129 * @param String str text to unescape
130 */
131 'htmlUnescape' : function (str) {
132 return $('<div/>').html(str).text();
133 },
134
135 // Access key prefix
136 // will be re-defined based on browser/operating system detection in mw.util.init()
137 'tooltipAccessKeyPrefix' : 'alt-',
138
139 // Regex to match accesskey tooltips
140 'tooltipAccessKeyRegexp': /\[(ctrl-)?(alt-)?(shift-)?(esc-)?(.)\]$/,
141
142 /**
143 * Add the appropriate prefix to the accesskey shown in the tooltip.
144 * If the nodeList parameter is given, only those nodes are updated;
145 * otherwise, all the nodes that will probably have accesskeys by
146 * default are updated.
147 *
148 * @param Mixed nodeList jQuery object, or array of elements
149 */
150 'updateTooltipAccessKeys' : function (nodeList) {
151 var $nodes;
152 if (nodeList instanceof jQuery) {
153 $nodes = nodeList;
154 } else if (nodeList) {
155 $nodes = $(nodeList);
156 } else {
157 // Rather than scanning all links, just
158 $('#column-one a, #mw-head a, #mw-panel a, #p-logo a');
159
160 // these are rare enough that no such optimization is needed
161 this.updateTooltipAccessKeys($('input'));
162 this.updateTooltipAccessKeys($('label'));
163 return;
164 }
165
166 $nodes.each(function (i) {
167 var tip = $(this).attr('title');
168 if (!!tip && mw.util.tooltipAccessKeyRegexp.exec(tip)) {
169 tip = tip.replace(mw.util.tooltipAccessKeyRegexp, '[' + mw.util.tooltipAccessKeyPrefix + "$5]");
170 $(this).attr('title', tip);
171 }
172 });
173 },
174
175
176 /**
177 * Add a link to a portlet menu on the page, such as:
178 *
179 * p-cactions (Content actions), p-personal (Personal tools), p-navigation (Navigation), p-tb (Toolbox)
180 *
181 * The first three paramters are required, others are optionals. Though
182 * providing an id and tooltip is recommended.
183 *
184 * By default the new link will be added to the end of the list. To add the link before a given existing item,
185 * pass the DOM node (document.getElementById('foobar') or the jQuery-selector ('#foobar') of that item.
186 *
187 * @example mw.util.addPortletLink('p-tb', 'http://mediawiki.org/', 'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org ', 'm', '#t-print')
188 *
189 * @param String portlet id of the target portlet ('p-cactions' or 'p-personal' etc.)
190 * @param String href link URL
191 * @param String text link text (will be automatically lowercased by CSS for p-cactions in Monobook)
192 * @param String id id of the new item, should be unique and preferably have the appropriate prefix ('ca-', 'pt-', 'n-' or 't-')
193 * @param String tooltip text to show when hovering over the link, without accesskey suffix
194 * @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.
195 * @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
196 *
197 * @return Node the DOM node of the new item (a LI element) or null
198 */
199 'addPortletLink' : function (portlet, href, text, id, tooltip, accesskey, nextnode) {
200 var $portlet = $('#' + portlet);
201 if ($portlet.length === 0) {
202 return null;
203 }
204 var $ul = $portlet.find('ul').eq(0);
205 if ($ul.length === 0) {
206 if ($portlet.find('div').length === 0) {
207 $portlet.append('<ul />');
208 } else {
209 $portlet.find('div').eq(-1).append('<ul />');
210 }
211 $ul = $portlet.find('ul').eq(0);
212 }
213 if ($ul.length === 0) {
214 return null;
215 }
216
217 // unhide portlet if it was hidden before
218 $portlet.removeClass('emptyPortlet');
219
220 var $link = $('<a />').attr('href', href).text(text);
221 var $item = $link.wrap('<li><span /></li>').parent().parent();
222
223 if (id) {
224 $item.attr('id', id);
225 }
226 if (accesskey) {
227 $link.attr('accesskey', accesskey);
228 tooltip += ' [' + accesskey + ']';
229 }
230 if (tooltip) {
231 $link.attr('title', tooltip);
232 }
233 if (accesskey && tooltip) {
234 this.updateTooltipAccessKeys($link);
235 }
236
237 // Append using DOM-element passing
238 if (nextnode && nextnode.parentNode == $ul.get(0)) {
239 $(nextnode).before($item);
240 } else {
241 // If the jQuery selector isn't found within the <ul>, just append it at the end
242 if ($ul.find(nextnode).length === 0) {
243 $ul.append($item);
244 } else {
245 // Append using jQuery CSS selector
246 $ul.find(nextnode).eq(0).before($item);
247 }
248 }
249
250 return $item.get(0);
251 }
252
253 };
254
255 })(jQuery, mediaWiki);
256
257 mediaWiki.util.init();