/[drupal]/drupal/misc/drupal.js
ViewVC logotype

Contents of /drupal/misc/drupal.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.60 - (show annotations) (download) (as text)
Tue Nov 3 05:34:37 2009 UTC (3 weeks, 3 days ago) by webchick
Branch: MAIN
CVS Tags: DRUPAL-7-0-UNSTABLE-10, HEAD
Changes since 1.59: +27 -5 lines
File MIME type: text/javascript
#561726 by effulgentsia, TwoD, and sun: Make ajax.js and tabledrag.js implement Drupal.detachBehaviors().
1 // $Id: drupal.js,v 1.59 2009/10/27 04:12:39 webchick Exp $
2
3 var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
4
5 // Allow other JavaScript libraries to use $.
6 jQuery.noConflict();
7
8 // Indicate when other scripts use $ with out wrapping their code.
9 if ($ === undefined) {
10 $ = function () {
11 alert('Please wrap your JavaScript code in (function ($) { ... })(jQuery); to be compatible. See http://docs.jquery.com/Using_jQuery_with_Other_Libraries.');
12 };
13 }
14
15 (function ($) {
16
17 /**
18 * Attach all registered behaviors to a page element.
19 *
20 * Behaviors are event-triggered actions that attach to page elements, enhancing
21 * default non-Javascript UIs. Behaviors are registered in the Drupal.behaviors
22 * object using the method 'attach' and optionally also 'detach' as follows:
23 * @code
24 * Drupal.behaviors.behaviorName = {
25 * attach: function (context, settings) {
26 * ...
27 * },
28 * detach: function (context, settings, trigger) {
29 * ...
30 * }
31 * };
32 * @endcode
33 *
34 * Drupal.attachBehaviors is added below to the jQuery ready event and so
35 * runs on initial page load. Developers implementing AHAH/AJAX in their
36 * solutions should also call this function after new page content has been
37 * loaded, feeding in an element to be processed, in order to attach all
38 * behaviors to the new content.
39 *
40 * Behaviors should use
41 * @code
42 * $(selector).once('behavior-name', function () {
43 * ...
44 * });
45 * @endcode
46 * to ensure the behavior is attached only once to a given element. (Doing so
47 * enables the reprocessing of given elements, which may be needed on occasion
48 * despite the ability to limit behavior attachment to a particular element.)
49 *
50 * @param context
51 * An element to attach behaviors to. If none is given, the document element
52 * is used.
53 * @param settings
54 * An object containing settings for the current context. If none given, the
55 * global Drupal.settings object is used.
56 */
57 Drupal.attachBehaviors = function (context, settings) {
58 context = context || document;
59 settings = settings || Drupal.settings;
60 // Execute all of them.
61 $.each(Drupal.behaviors, function () {
62 if ($.isFunction(this.attach)) {
63 this.attach(context, settings);
64 }
65 });
66 };
67
68 /**
69 * Detach registered behaviors from a page element.
70 *
71 * Developers implementing AHAH/AJAX in their solutions should call this
72 * function before page content is about to be removed, feeding in an element
73 * to be processed, in order to allow special behaviors to detach from the
74 * content.
75 *
76 * Such implementations should look for the class name that was added in their
77 * corresponding Drupal.behaviors.behaviorName.attach implementation, i.e.
78 * behaviorName-processed, to ensure the behavior is detached only from
79 * previously processed elements.
80 *
81 * @param context
82 * An element to detach behaviors from. If none is given, the document element
83 * is used.
84 * @param settings
85 * An object containing settings for the current context. If none given, the
86 * global Drupal.settings object is used.
87 * @param trigger
88 * A string containing what's causing the behaviors to be detached. The
89 * possible triggers are:
90 * - unload: (default) The context element is being removed from the DOM.
91 * - move: The element is about to be moved within the DOM (for example,
92 * during a tabledrag row swap). After the move is completed,
93 * Drupal.attachBehaviors() is called, so that the behavior can undo
94 * whatever it did in response to the move. Many behaviors won't need to
95 * do anything simply in response to the element being moved, but because
96 * IFRAME elements reload their "src" when being moved within the DOM,
97 * behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
98 * take some action.
99 * - serialize: When an AJAX form is submitted, this is called with the
100 * form as the context. This provides every behavior within the form an
101 * opportunity to ensure that the field elements have correct content
102 * in them before the form is serialized. The canonical use-case is so
103 * that WYSIWYG editors can update the hidden textarea to which they are
104 * bound.
105 *
106 * @see Drupal.attachBehaviors
107 */
108 Drupal.detachBehaviors = function (context, settings, trigger) {
109 context = context || document;
110 settings = settings || Drupal.settings;
111 trigger = trigger || 'unload';
112 // Execute all of them.
113 $.each(Drupal.behaviors, function () {
114 if ($.isFunction(this.detach)) {
115 this.detach(context, settings, trigger);
116 }
117 });
118 };
119
120 /**
121 * Encode special characters in a plain-text string for display as HTML.
122 */
123 Drupal.checkPlain = function (str) {
124 str = String(str);
125 var replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
126 for (var character in replace) {
127 var regex = new RegExp(character, 'g');
128 str = str.replace(regex, replace[character]);
129 }
130 return str;
131 };
132
133 /**
134 * Translate strings to the page language or a given language.
135 *
136 * See the documentation of the server-side t() function for further details.
137 *
138 * @param str
139 * A string containing the English string to translate.
140 * @param args
141 * An object of replacements pairs to make after translation. Incidences
142 * of any key in this array are replaced with the corresponding value.
143 * Based on the first character of the key, the value is escaped and/or themed:
144 * - !variable: inserted as is
145 * - @variable: escape plain text to HTML (Drupal.checkPlain)
146 * - %variable: escape text and theme as a placeholder for user-submitted
147 * content (checkPlain + Drupal.theme('placeholder'))
148 * @return
149 * The translated string.
150 */
151 Drupal.t = function (str, args) {
152 // Fetch the localized version of the string.
153 if (Drupal.locale.strings && Drupal.locale.strings[str]) {
154 str = Drupal.locale.strings[str];
155 }
156
157 if (args) {
158 // Transform arguments before inserting them.
159 for (var key in args) {
160 switch (key.charAt(0)) {
161 // Escaped only.
162 case '@':
163 args[key] = Drupal.checkPlain(args[key]);
164 break;
165 // Pass-through.
166 case '!':
167 break;
168 // Escaped and placeholder.
169 case '%':
170 default:
171 args[key] = Drupal.theme('placeholder', args[key]);
172 break;
173 }
174 str = str.replace(key, args[key]);
175 }
176 }
177 return str;
178 };
179
180 /**
181 * Format a string containing a count of items.
182 *
183 * This function ensures that the string is pluralized correctly. Since Drupal.t() is
184 * called by this function, make sure not to pass already-localized strings to it.
185 *
186 * See the documentation of the server-side format_plural() function for further details.
187 *
188 * @param count
189 * The item count to display.
190 * @param singular
191 * The string for the singular case. Please make sure it is clear this is
192 * singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
193 * Do not use @count in the singular string.
194 * @param plural
195 * The string for the plural case. Please make sure it is clear this is plural,
196 * to ease translation. Use @count in place of the item count, as in "@count
197 * new comments".
198 * @param args
199 * An object of replacements pairs to make after translation. Incidences
200 * of any key in this array are replaced with the corresponding value.
201 * Based on the first character of the key, the value is escaped and/or themed:
202 * - !variable: inserted as is
203 * - @variable: escape plain text to HTML (Drupal.checkPlain)
204 * - %variable: escape text and theme as a placeholder for user-submitted
205 * content (checkPlain + Drupal.theme('placeholder'))
206 * Note that you do not need to include @count in this array.
207 * This replacement is done automatically for the plural case.
208 * @return
209 * A translated string.
210 */
211 Drupal.formatPlural = function (count, singular, plural, args) {
212 var args = args || {};
213 args['@count'] = count;
214 // Determine the index of the plural form.
215 var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
216
217 if (index == 0) {
218 return Drupal.t(singular, args);
219 }
220 else if (index == 1) {
221 return Drupal.t(plural, args);
222 }
223 else {
224 args['@count[' + index + ']'] = args['@count'];
225 delete args['@count'];
226 return Drupal.t(plural.replace('@count', '@count[' + index + ']'));
227 }
228 };
229
230 /**
231 * Generate the themed representation of a Drupal object.
232 *
233 * All requests for themed output must go through this function. It examines
234 * the request and routes it to the appropriate theme function. If the current
235 * theme does not provide an override function, the generic theme function is
236 * called.
237 *
238 * For example, to retrieve the HTML that is output by theme_placeholder(text),
239 * call Drupal.theme('placeholder', text).
240 *
241 * @param func
242 * The name of the theme function to call.
243 * @param ...
244 * Additional arguments to pass along to the theme function.
245 * @return
246 * Any data the theme function returns. This could be a plain HTML string,
247 * but also a complex object.
248 */
249 Drupal.theme = function (func) {
250 for (var i = 1, args = []; i < arguments.length; i++) {
251 args.push(arguments[i]);
252 }
253
254 return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
255 };
256
257 /**
258 * Parse a JSON response.
259 *
260 * The result is either the JSON object, or an object with 'status' 0 and 'data' an error message.
261 */
262 Drupal.parseJson = function (data) {
263 if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) {
264 return { status: 0, data: data.length ? data : Drupal.t('Unspecified error') };
265 }
266 return eval('(' + data + ');');
267 };
268
269 /**
270 * Freeze the current body height (as minimum height). Used to prevent
271 * unnecessary upwards scrolling when doing DOM manipulations.
272 */
273 Drupal.freezeHeight = function () {
274 Drupal.unfreezeHeight();
275 $('<div id="freeze-height"></div>').css({
276 position: 'absolute',
277 top: '0px',
278 left: '0px',
279 width: '1px',
280 height: $('body').css('height')
281 }).appendTo('body');
282 };
283
284 /**
285 * Unfreeze the body height.
286 */
287 Drupal.unfreezeHeight = function () {
288 $('#freeze-height').remove();
289 };
290
291 /**
292 * Wrapper around encodeURIComponent() which avoids Apache quirks (equivalent of
293 * drupal_encode_path() in PHP). This function should only be used on paths, not
294 * on query string arguments.
295 */
296 Drupal.encodePath = function (item, uri) {
297 uri = uri || location.href;
298 item = encodeURIComponent(item).replace(/%2F/g, '/');
299 return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F');
300 };
301
302 /**
303 * Get the text selection in a textarea.
304 */
305 Drupal.getSelection = function (element) {
306 if (typeof element.selectionStart != 'number' && document.selection) {
307 // The current selection.
308 var range1 = document.selection.createRange();
309 var range2 = range1.duplicate();
310 // Select all text.
311 range2.moveToElementText(element);
312 // Now move 'dummy' end point to end point of original range.
313 range2.setEndPoint('EndToEnd', range1);
314 // Now we can calculate start and end points.
315 var start = range2.text.length - range1.text.length;
316 var end = start + range1.text.length;
317 return { 'start': start, 'end': end };
318 }
319 return { 'start': element.selectionStart, 'end': element.selectionEnd };
320 };
321
322 /**
323 * Build an error message from an AJAX response.
324 */
325 Drupal.ajaxError = function (xmlhttp, uri) {
326 if (xmlhttp.status == 200 || (xmlhttp.status == 500 && xmlhttp.statusText == 'Service unavailable (with message)')) {
327 if ($.trim(xmlhttp.responseText)) {
328 var message = Drupal.t("An error occurred. \nPath: @uri\nMessage: !text", { '@uri': uri, '!text': xmlhttp.responseText });
329 }
330 else {
331 var message = Drupal.t("An error occurred. \nPath: @uri\n(no information available).", {'@uri': uri });
332 }
333 }
334 else {
335 var message = Drupal.t("An HTTP error @status occurred. \nPath: @uri", { '@uri': uri, '@status': xmlhttp.status });
336 }
337 return message.replace(/\n/g, '<br />');
338 };
339
340 // Class indicating that JS is enabled; used for styling purpose.
341 $('html').addClass('js');
342
343 // 'js enabled' cookie.
344 document.cookie = 'has_js=1; path=/';
345
346 // Attach all behaviors.
347 $(function () {
348 Drupal.attachBehaviors(document, Drupal.settings);
349 });
350
351 /**
352 * The default themes.
353 */
354 Drupal.theme.prototype = {
355
356 /**
357 * Formats text for emphasized display in a placeholder inside a sentence.
358 *
359 * @param str
360 * The text to format (plain-text).
361 * @return
362 * The formatted text (html).
363 */
364 placeholder: function (str) {
365 return '<em>' + Drupal.checkPlain(str) + '</em>';
366 }
367 };
368
369 /**
370 * Return whether the given variable is an object.
371 *
372 * The HEAD version of jQuery (http://code.jquery.com/jquery-nightly.js)
373 * includes an isObject() function, so when that gets released and incorporated
374 * into Drupal, this can be removed.
375 */
376 $.extend({isObject: function(value) {
377 return (value !== null && typeof value === 'object');
378 }});
379
380 })(jQuery);

  ViewVC Help
Powered by ViewVC 1.1.2