1 | |
---|
2 | /** |
---|
3 | * Override jQuery.fn.init to guard against XSS attacks. |
---|
4 | * |
---|
5 | * See http://bugs.jquery.com/ticket/9521 |
---|
6 | */ |
---|
7 | (function () { |
---|
8 | var jquery_init = jQuery.fn.init; |
---|
9 | jQuery.fn.init = function (selector, context, rootjQuery) { |
---|
10 | // If the string contains a "#" before a "<", treat it as invalid HTML. |
---|
11 | if (selector && typeof selector === 'string') { |
---|
12 | var hash_position = selector.indexOf('#'); |
---|
13 | if (hash_position >= 0) { |
---|
14 | var bracket_position = selector.indexOf('<'); |
---|
15 | if (bracket_position > hash_position) { |
---|
16 | throw 'Syntax error, unrecognized expression: ' + selector; |
---|
17 | } |
---|
18 | } |
---|
19 | } |
---|
20 | return jquery_init.call(this, selector, context, rootjQuery); |
---|
21 | }; |
---|
22 | jQuery.fn.init.prototype = jquery_init.prototype; |
---|
23 | })(); |
---|
24 | |
---|
25 | var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} }; |
---|
26 | |
---|
27 | /** |
---|
28 | * Set the variable that indicates if JavaScript behaviors should be applied |
---|
29 | */ |
---|
30 | Drupal.jsEnabled = document.getElementsByTagName && document.createElement && document.createTextNode && document.documentElement && document.getElementById; |
---|
31 | |
---|
32 | /** |
---|
33 | * Attach all registered behaviors to a page element. |
---|
34 | * |
---|
35 | * Behaviors are event-triggered actions that attach to page elements, enhancing |
---|
36 | * default non-Javascript UIs. Behaviors are registered in the Drupal.behaviors |
---|
37 | * object as follows: |
---|
38 | * @code |
---|
39 | * Drupal.behaviors.behaviorName = function () { |
---|
40 | * ... |
---|
41 | * }; |
---|
42 | * @endcode |
---|
43 | * |
---|
44 | * Drupal.attachBehaviors is added below to the jQuery ready event and so |
---|
45 | * runs on initial page load. Developers implementing AHAH/AJAX in their |
---|
46 | * solutions should also call this function after new page content has been |
---|
47 | * loaded, feeding in an element to be processed, in order to attach all |
---|
48 | * behaviors to the new content. |
---|
49 | * |
---|
50 | * Behaviors should use a class in the form behaviorName-processed to ensure |
---|
51 | * the behavior is attached only once to a given element. (Doing so enables |
---|
52 | * the reprocessing of given elements, which may be needed on occasion despite |
---|
53 | * the ability to limit behavior attachment to a particular element.) |
---|
54 | * |
---|
55 | * @param context |
---|
56 | * An element to attach behaviors to. If none is given, the document element |
---|
57 | * is used. |
---|
58 | */ |
---|
59 | Drupal.attachBehaviors = function(context) { |
---|
60 | context = context || document; |
---|
61 | if (Drupal.jsEnabled) { |
---|
62 | // Execute all of them. |
---|
63 | jQuery.each(Drupal.behaviors, function() { |
---|
64 | this(context); |
---|
65 | }); |
---|
66 | } |
---|
67 | }; |
---|
68 | |
---|
69 | /** |
---|
70 | * Encode special characters in a plain-text string for display as HTML. |
---|
71 | */ |
---|
72 | Drupal.checkPlain = function(str) { |
---|
73 | str = String(str); |
---|
74 | var replace = { '&': '&', '"': '"', '<': '<', '>': '>' }; |
---|
75 | for (var character in replace) { |
---|
76 | var regex = new RegExp(character, 'g'); |
---|
77 | str = str.replace(regex, replace[character]); |
---|
78 | } |
---|
79 | return str; |
---|
80 | }; |
---|
81 | |
---|
82 | /** |
---|
83 | * Translate strings to the page language or a given language. |
---|
84 | * |
---|
85 | * See the documentation of the server-side t() function for further details. |
---|
86 | * |
---|
87 | * @param str |
---|
88 | * A string containing the English string to translate. |
---|
89 | * @param args |
---|
90 | * An object of replacements pairs to make after translation. Incidences |
---|
91 | * of any key in this array are replaced with the corresponding value. |
---|
92 | * Based on the first character of the key, the value is escaped and/or themed: |
---|
93 | * - !variable: inserted as is |
---|
94 | * - @variable: escape plain text to HTML (Drupal.checkPlain) |
---|
95 | * - %variable: escape text and theme as a placeholder for user-submitted |
---|
96 | * content (checkPlain + Drupal.theme('placeholder')) |
---|
97 | * @return |
---|
98 | * The translated string. |
---|
99 | */ |
---|
100 | Drupal.t = function(str, args) { |
---|
101 | // Fetch the localized version of the string. |
---|
102 | if (Drupal.locale.strings && Drupal.locale.strings[str]) { |
---|
103 | str = Drupal.locale.strings[str]; |
---|
104 | } |
---|
105 | |
---|
106 | if (args) { |
---|
107 | // Transform arguments before inserting them |
---|
108 | for (var key in args) { |
---|
109 | switch (key.charAt(0)) { |
---|
110 | // Escaped only |
---|
111 | case '@': |
---|
112 | args[key] = Drupal.checkPlain(args[key]); |
---|
113 | break; |
---|
114 | // Pass-through |
---|
115 | case '!': |
---|
116 | break; |
---|
117 | // Escaped and placeholder |
---|
118 | case '%': |
---|
119 | default: |
---|
120 | args[key] = Drupal.theme('placeholder', args[key]); |
---|
121 | break; |
---|
122 | } |
---|
123 | str = str.replace(key, args[key]); |
---|
124 | } |
---|
125 | } |
---|
126 | return str; |
---|
127 | }; |
---|
128 | |
---|
129 | /** |
---|
130 | * Format a string containing a count of items. |
---|
131 | * |
---|
132 | * This function ensures that the string is pluralized correctly. Since Drupal.t() is |
---|
133 | * called by this function, make sure not to pass already-localized strings to it. |
---|
134 | * |
---|
135 | * See the documentation of the server-side format_plural() function for further details. |
---|
136 | * |
---|
137 | * @param count |
---|
138 | * The item count to display. |
---|
139 | * @param singular |
---|
140 | * The string for the singular case. Please make sure it is clear this is |
---|
141 | * singular, to ease translation (e.g. use "1 new comment" instead of "1 new"). |
---|
142 | * Do not use @count in the singular string. |
---|
143 | * @param plural |
---|
144 | * The string for the plural case. Please make sure it is clear this is plural, |
---|
145 | * to ease translation. Use @count in place of the item count, as in "@count |
---|
146 | * new comments". |
---|
147 | * @param args |
---|
148 | * An object of replacements pairs to make after translation. Incidences |
---|
149 | * of any key in this array are replaced with the corresponding value. |
---|
150 | * Based on the first character of the key, the value is escaped and/or themed: |
---|
151 | * - !variable: inserted as is |
---|
152 | * - @variable: escape plain text to HTML (Drupal.checkPlain) |
---|
153 | * - %variable: escape text and theme as a placeholder for user-submitted |
---|
154 | * content (checkPlain + Drupal.theme('placeholder')) |
---|
155 | * Note that you do not need to include @count in this array. |
---|
156 | * This replacement is done automatically for the plural case. |
---|
157 | * @return |
---|
158 | * A translated string. |
---|
159 | */ |
---|
160 | Drupal.formatPlural = function(count, singular, plural, args) { |
---|
161 | var args = args || {}; |
---|
162 | args['@count'] = count; |
---|
163 | // Determine the index of the plural form. |
---|
164 | var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1); |
---|
165 | |
---|
166 | if (index == 0) { |
---|
167 | return Drupal.t(singular, args); |
---|
168 | } |
---|
169 | else if (index == 1) { |
---|
170 | return Drupal.t(plural, args); |
---|
171 | } |
---|
172 | else { |
---|
173 | args['@count['+ index +']'] = args['@count']; |
---|
174 | delete args['@count']; |
---|
175 | return Drupal.t(plural.replace('@count', '@count['+ index +']'), args); |
---|
176 | } |
---|
177 | }; |
---|
178 | |
---|
179 | /** |
---|
180 | * Generate the themed representation of a Drupal object. |
---|
181 | * |
---|
182 | * All requests for themed output must go through this function. It examines |
---|
183 | * the request and routes it to the appropriate theme function. If the current |
---|
184 | * theme does not provide an override function, the generic theme function is |
---|
185 | * called. |
---|
186 | * |
---|
187 | * For example, to retrieve the HTML that is output by theme_placeholder(text), |
---|
188 | * call Drupal.theme('placeholder', text). |
---|
189 | * |
---|
190 | * @param func |
---|
191 | * The name of the theme function to call. |
---|
192 | * @param ... |
---|
193 | * Additional arguments to pass along to the theme function. |
---|
194 | * @return |
---|
195 | * Any data the theme function returns. This could be a plain HTML string, |
---|
196 | * but also a complex object. |
---|
197 | */ |
---|
198 | Drupal.theme = function(func) { |
---|
199 | for (var i = 1, args = []; i < arguments.length; i++) { |
---|
200 | args.push(arguments[i]); |
---|
201 | } |
---|
202 | |
---|
203 | return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args); |
---|
204 | }; |
---|
205 | |
---|
206 | /** |
---|
207 | * Parse a JSON response. |
---|
208 | * |
---|
209 | * The result is either the JSON object, or an object with 'status' 0 and 'data' an error message. |
---|
210 | */ |
---|
211 | Drupal.parseJson = function (data) { |
---|
212 | if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) { |
---|
213 | return { status: 0, data: data.length ? data : Drupal.t('Unspecified error') }; |
---|
214 | } |
---|
215 | return eval('(' + data + ');'); |
---|
216 | }; |
---|
217 | |
---|
218 | /** |
---|
219 | * Freeze the current body height (as minimum height). Used to prevent |
---|
220 | * unnecessary upwards scrolling when doing DOM manipulations. |
---|
221 | */ |
---|
222 | Drupal.freezeHeight = function () { |
---|
223 | Drupal.unfreezeHeight(); |
---|
224 | var div = document.createElement('div'); |
---|
225 | $(div).css({ |
---|
226 | position: 'absolute', |
---|
227 | top: '0px', |
---|
228 | left: '0px', |
---|
229 | width: '1px', |
---|
230 | height: $('body').css('height') |
---|
231 | }).attr('id', 'freeze-height'); |
---|
232 | $('body').append(div); |
---|
233 | }; |
---|
234 | |
---|
235 | /** |
---|
236 | * Unfreeze the body height |
---|
237 | */ |
---|
238 | Drupal.unfreezeHeight = function () { |
---|
239 | $('#freeze-height').remove(); |
---|
240 | }; |
---|
241 | |
---|
242 | /** |
---|
243 | * Wrapper around encodeURIComponent() which avoids Apache quirks (equivalent of |
---|
244 | * drupal_urlencode() in PHP). This function should only be used on paths, not |
---|
245 | * on query string arguments. |
---|
246 | */ |
---|
247 | Drupal.encodeURIComponent = function (item, uri) { |
---|
248 | uri = uri || location.href; |
---|
249 | item = encodeURIComponent(item).replace(/%2F/g, '/'); |
---|
250 | return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F'); |
---|
251 | }; |
---|
252 | |
---|
253 | /** |
---|
254 | * Get the text selection in a textarea. |
---|
255 | */ |
---|
256 | Drupal.getSelection = function (element) { |
---|
257 | if (typeof(element.selectionStart) != 'number' && document.selection) { |
---|
258 | // The current selection |
---|
259 | var range1 = document.selection.createRange(); |
---|
260 | var range2 = range1.duplicate(); |
---|
261 | // Select all text. |
---|
262 | range2.moveToElementText(element); |
---|
263 | // Now move 'dummy' end point to end point of original range. |
---|
264 | range2.setEndPoint('EndToEnd', range1); |
---|
265 | // Now we can calculate start and end points. |
---|
266 | var start = range2.text.length - range1.text.length; |
---|
267 | var end = start + range1.text.length; |
---|
268 | return { 'start': start, 'end': end }; |
---|
269 | } |
---|
270 | return { 'start': element.selectionStart, 'end': element.selectionEnd }; |
---|
271 | }; |
---|
272 | |
---|
273 | /** |
---|
274 | * Build an error message from ahah response. |
---|
275 | */ |
---|
276 | Drupal.ahahError = function(xmlhttp, uri) { |
---|
277 | if (xmlhttp.status == 200) { |
---|
278 | if (jQuery.trim($(xmlhttp.responseText).text())) { |
---|
279 | var message = Drupal.t("An error occurred. \n@uri\n@text", {'@uri': uri, '@text': xmlhttp.responseText }); |
---|
280 | } |
---|
281 | else { |
---|
282 | var message = Drupal.t("An error occurred. \n@uri\n(no information available).", {'@uri': uri, '@text': xmlhttp.responseText }); |
---|
283 | } |
---|
284 | } |
---|
285 | else { |
---|
286 | var message = Drupal.t("An HTTP error @status occurred. \n@uri", {'@uri': uri, '@status': xmlhttp.status }); |
---|
287 | } |
---|
288 | return message; |
---|
289 | } |
---|
290 | |
---|
291 | // Global Killswitch on the <html> element |
---|
292 | if (Drupal.jsEnabled) { |
---|
293 | // Global Killswitch on the <html> element |
---|
294 | $(document.documentElement).addClass('js'); |
---|
295 | // 'js enabled' cookie |
---|
296 | document.cookie = 'has_js=1; path=/'; |
---|
297 | // Attach all behaviors. |
---|
298 | $(document).ready(function() { |
---|
299 | Drupal.attachBehaviors(this); |
---|
300 | }); |
---|
301 | } |
---|
302 | |
---|
303 | /** |
---|
304 | * The default themes. |
---|
305 | */ |
---|
306 | Drupal.theme.prototype = { |
---|
307 | |
---|
308 | /** |
---|
309 | * Formats text for emphasized display in a placeholder inside a sentence. |
---|
310 | * |
---|
311 | * @param str |
---|
312 | * The text to format (plain-text). |
---|
313 | * @return |
---|
314 | * The formatted text (html). |
---|
315 | */ |
---|
316 | placeholder: function(str) { |
---|
317 | return '<em>' + Drupal.checkPlain(str) + '</em>'; |
---|
318 | } |
---|
319 | }; |
---|