1 2var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} }; 3 4// Allow other JavaScript libraries to use $. 5jQuery.noConflict(); 6 7(function ($) { 8 9/** 10 * Override jQuery.fn.init to guard against XSS attacks. 11 * 12 * See http://bugs.jquery.com/ticket/9521 13 */ 14var jquery_init = $.fn.init; 15$.fn.init = function (selector, context, rootjQuery) { 16 // If the string contains a "#" before a "<", treat it as invalid HTML. 17 if (selector && typeof selector === 'string') { 18 var hash_position = selector.indexOf('#'); 19 if (hash_position >= 0) { 20 var bracket_position = selector.indexOf('<'); 21 if (bracket_position > hash_position) { 22 throw 'Syntax error, unrecognized expression: ' + selector; 23 } 24 } 25 } 26 return jquery_init.call(this, selector, context, rootjQuery); 27}; 28$.fn.init.prototype = jquery_init.prototype; 29 30/** 31 * Attach all registered behaviors to a page element. 32 * 33 * Behaviors are event-triggered actions that attach to page elements, enhancing 34 * default non-JavaScript UIs. Behaviors are registered in the Drupal.behaviors 35 * object using the method 'attach' and optionally also 'detach' as follows: 36 * @code 37 * Drupal.behaviors.behaviorName = { 38 * attach: function (context, settings) { 39 * ... 40 * }, 41 * detach: function (context, settings, trigger) { 42 * ... 43 * } 44 * }; 45 * @endcode 46 * 47 * Drupal.attachBehaviors is added below to the jQuery ready event and so 48 * runs on initial page load. Developers implementing AHAH/Ajax in their 49 * solutions should also call this function after new page content has been 50 * loaded, feeding in an element to be processed, in order to attach all 51 * behaviors to the new content. 52 * 53 * Behaviors should use 54 * @code 55 * $(selector).once('behavior-name', function () { 56 * ... 57 * }); 58 * @endcode 59 * to ensure the behavior is attached only once to a given element. (Doing so 60 * enables the reprocessing of given elements, which may be needed on occasion 61 * despite the ability to limit behavior attachment to a particular element.) 62 * 63 * @param context 64 * An element to attach behaviors to. If none is given, the document element 65 * is used. 66 * @param settings 67 * An object containing settings for the current context. If none given, the 68 * global Drupal.settings object is used. 69 */ 70Drupal.attachBehaviors = function (context, settings) { 71 context = context || document; 72 settings = settings || Drupal.settings; 73 // Execute all of them. 74 $.each(Drupal.behaviors, function () { 75 if ($.isFunction(this.attach)) { 76 this.attach(context, settings); 77 } 78 }); 79}; 80 81/** 82 * Detach registered behaviors from a page element. 83 * 84 * Developers implementing AHAH/Ajax in their solutions should call this 85 * function before page content is about to be removed, feeding in an element 86 * to be processed, in order to allow special behaviors to detach from the 87 * content. 88 * 89 * Such implementations should look for the class name that was added in their 90 * corresponding Drupal.behaviors.behaviorName.attach implementation, i.e. 91 * behaviorName-processed, to ensure the behavior is detached only from 92 * previously processed elements. 93 * 94 * @param context 95 * An element to detach behaviors from. If none is given, the document element 96 * is used. 97 * @param settings 98 * An object containing settings for the current context. If none given, the 99 * global Drupal.settings object is used. 100 * @param trigger 101 * A string containing what's causing the behaviors to be detached. The 102 * possible triggers are: 103 * - unload: (default) The context element is being removed from the DOM. 104 * - move: The element is about to be moved within the DOM (for example, 105 * during a tabledrag row swap). After the move is completed, 106 * Drupal.attachBehaviors() is called, so that the behavior can undo 107 * whatever it did in response to the move. Many behaviors won't need to 108 * do anything simply in response to the element being moved, but because 109 * IFRAME elements reload their "src" when being moved within the DOM, 110 * behaviors bound to IFRAME elements (like WYSIWYG editors) may need to 111 * take some action. 112 * - serialize: When an Ajax form is submitted, this is called with the 113 * form as the context. This provides every behavior within the form an 114 * opportunity to ensure that the field elements have correct content 115 * in them before the form is serialized. The canonical use-case is so 116 * that WYSIWYG editors can update the hidden textarea to which they are 117 * bound. 118 * 119 * @see Drupal.attachBehaviors 120 */ 121Drupal.detachBehaviors = function (context, settings, trigger) { 122 context = context || document; 123 settings = settings || Drupal.settings; 124 trigger = trigger || 'unload'; 125 // Execute all of them. 126 $.each(Drupal.behaviors, function () { 127 if ($.isFunction(this.detach)) { 128 this.detach(context, settings, trigger); 129 } 130 }); 131}; 132 133/** 134 * Encode special characters in a plain-text string for display as HTML. 135 * 136 * @ingroup sanitization 137 */ 138Drupal.checkPlain = function (str) { 139 var character, regex, 140 replace = { '&': '&', '"': '"', '<': '<', '>': '>' }; 141 str = String(str); 142 for (character in replace) { 143 if (replace.hasOwnProperty(character)) { 144 regex = new RegExp(character, 'g'); 145 str = str.replace(regex, replace[character]); 146 } 147 } 148 return str; 149}; 150 151/** 152 * Replace placeholders with sanitized values in a string. 153 * 154 * @param str 155 * A string with placeholders. 156 * @param args 157 * An object of replacements pairs to make. Incidences of any key in this 158 * array are replaced with the corresponding value. Based on the first 159 * character of the key, the value is escaped and/or themed: 160 * - !variable: inserted as is 161 * - @variable: escape plain text to HTML (Drupal.checkPlain) 162 * - %variable: escape text and theme as a placeholder for user-submitted 163 * content (checkPlain + Drupal.theme('placeholder')) 164 * 165 * @see Drupal.t() 166 * @ingroup sanitization 167 */ 168Drupal.formatString = function(str, args) { 169 // Transform arguments before inserting them. 170 for (var key in args) { 171 switch (key.charAt(0)) { 172 // Escaped only. 173 case '@': 174 args[key] = Drupal.checkPlain(args[key]); 175 break; 176 // Pass-through. 177 case '!': 178 break; 179 // Escaped and placeholder. 180 case '%': 181 default: 182 args[key] = Drupal.theme('placeholder', args[key]); 183 break; 184 } 185 str = str.replace(key, args[key]); 186 } 187 return str; 188}; 189 190/** 191 * Translate strings to the page language or a given language. 192 * 193 * See the documentation of the server-side t() function for further details. 194 * 195 * @param str 196 * A string containing the English string to translate. 197 * @param args 198 * An object of replacements pairs to make after translation. Incidences 199 * of any key in this array are replaced with the corresponding value. 200 * See Drupal.formatString(). 201 * 202 * @param options 203 * - 'context' (defaults to the empty context): The context the source string 204 * belongs to. 205 * 206 * @return 207 * The translated string. 208 */ 209Drupal.t = function (str, args, options) { 210 options = options || {}; 211 options.context = options.context || ''; 212 213 // Fetch the localized version of the string. 214 if (Drupal.locale.strings && Drupal.locale.strings[options.context] && Drupal.locale.strings[options.context][str]) { 215 str = Drupal.locale.strings[options.context][str]; 216 } 217 218 if (args) { 219 str = Drupal.formatString(str, args); 220 } 221 return str; 222}; 223 224/** 225 * Format a string containing a count of items. 226 * 227 * This function ensures that the string is pluralized correctly. Since Drupal.t() is 228 * called by this function, make sure not to pass already-localized strings to it. 229 * 230 * See the documentation of the server-side format_plural() function for further details. 231 * 232 * @param count 233 * The item count to display. 234 * @param singular 235 * The string for the singular case. Please make sure it is clear this is 236 * singular, to ease translation (e.g. use "1 new comment" instead of "1 new"). 237 * Do not use @count in the singular string. 238 * @param plural 239 * The string for the plural case. Please make sure it is clear this is plural, 240 * to ease translation. Use @count in place of the item count, as in "@count 241 * new comments". 242 * @param args 243 * An object of replacements pairs to make after translation. Incidences 244 * of any key in this array are replaced with the corresponding value. 245 * See Drupal.formatString(). 246 * Note that you do not need to include @count in this array. 247 * This replacement is done automatically for the plural case. 248 * @param options 249 * The options to pass to the Drupal.t() function. 250 * @return 251 * A translated string. 252 */ 253Drupal.formatPlural = function (count, singular, plural, args, options) { 254 var args = args || {}; 255 args['@count'] = count; 256 // Determine the index of the plural form. 257 var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1); 258 259 if (index == 0) { 260 return Drupal.t(singular, args, options); 261 } 262 else if (index == 1) { 263 return Drupal.t(plural, args, options); 264 } 265 else { 266 args['@count[' + index + ']'] = args['@count']; 267 delete args['@count']; 268 return Drupal.t(plural.replace('@count', '@count[' + index + ']'), args, options); 269 } 270}; 271 272/** 273 * Returns the passed in URL as an absolute URL. 274 * 275 * @param url 276 * The URL string to be normalized to an absolute URL. 277 * 278 * @return 279 * The normalized, absolute URL. 280 * 281 * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js 282 * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript 283 * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53 284 */ 285Drupal.absoluteUrl = function (url) { 286 var urlParsingNode = document.createElement('a'); 287 288 // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8 289 // strings may throw an exception. 290 try { 291 url = decodeURIComponent(url); 292 } catch (e) {} 293 294 urlParsingNode.setAttribute('href', url); 295
296 // IE <= 7 normalizes the URL when assigned to the anchor node similar to 297 // the other browsers. 298 return urlParsingNode.cloneNode(false).href; 299}; 300 301/** 302 * Returns true if the URL is within Drupal's base path. 303 * 304 * @param url 305 * The URL string to be tested. 306 * 307 * @return 308 * Boolean true if local. 309 * 310 * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58 311 */ 312Drupal.urlIsLocal = function (url) { 313 // Always use browser-derived absolute URLs in the comparison, to avoid 314 // attempts to break out of the base path using directory traversal. 315 var absoluteUrl = Drupal.absoluteUrl(url); 316 var protocol = location.protocol; 317 318 // Consider URLs that match this site's base URL but use HTTPS instead of HTTP 319 // as local as well. 320 if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) { 321 protocol = 'https:'; 322 } 323 var baseUrl = protocol + '//' + location.host + Drupal.settings.basePath.slice(0, -1); 324 325 // Decoding non-UTF-8 strings may throw an exception. 326 try { 327 absoluteUrl = decodeURIComponent(absoluteUrl); 328 } catch (e) {} 329 try { 330 baseUrl = decodeURIComponent(baseUrl); 331 } catch (e) {} 332 333 // The given URL matches the site's base URL, or has a path under the site's 334 // base URL. 335 return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0; 336}; 337 338/** 339 * Generate the themed representation of a Drupal object. 340 * 341 * All requests for themed output must go through this function. It examines 342 * the request and routes it to the appropriate theme function. If the current 343 * theme does not provide an override function, the generic theme function is 344 * called. 345 * 346 * For example, to retrieve the HTML for text that should be emphasized and 347 * displayed as a placeholder inside a sentence, call 348 * Drupal.theme('placeholder', text). 349 * 350 * @param func 351 * The name of the theme function to call. 352 * @param ... 353 * Additional arguments to pass along to the theme function. 354 * @return 355 * Any data the theme function returns. This could be a plain HTML string, 356 * but also a complex object. 357 */ 358Drupal.theme = function (func) { 359 var args = Array.prototype.slice.apply(arguments, [1]); 360 361 return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args); 362}; 363 364/** 365 * Freeze the current body height (as minimum height). Used to prevent 366 * unnecessary upwards scrolling when doing DOM manipulations. 367 */ 368Drupal.freezeHeight = function () { 369 Drupal.unfreezeHeight(); 370 $('<div id="freeze-height"></div>').css({ 371 position: 'absolute', 372 top: '0px', 373 left: '0px', 374 width: '1px', 375 height: $('body').css('height') 376 }).appendTo('body'); 377}; 378 379/** 380 * Unfreeze the body height. 381 */ 382Drupal.unfreezeHeight = function () { 383 $('#freeze-height').remove(); 384}; 385 386/** 387 * Encodes a Drupal path for use in a URL. 388 * 389 * For aesthetic reasons slashes are not escaped. 390 */ 391Drupal.encodePath = function (item, uri) { 392 uri = uri || location.href; 393 return encodeURIComponent(item).replace(/%2F/g, '/'); 394}; 395 396/** 397 * Get the text selection in a textarea. 398 */ 399Drupal.getSelection = function (element) { 400 if (typeof element.selectionStart != 'number' && document.selection) { 401 // The current selection. 402 var range1 = document.selection.createRange(); 403 var range2 = range1.duplicate(); 404 // Select all text. 405 range2.moveToElementText(element); 406 // Now move 'dummy' end point to end point of original range. 407 range2.setEndPoint('EndToEnd', range1); 408 // Now we can calculate start and end points. 409 var start = range2.text.length - range1.text.length; 410 var end = start + range1.text.length; 411 return { 'start': start, 'end': end }; 412 } 413 return { 'start': element.selectionStart, 'end': element.selectionEnd }; 414}; 415 416/** 417 * Build an error message from an Ajax response. 418 */ 419Drupal.ajaxError = function (xmlhttp, uri, customMessage) { 420 var statusCode, statusText, pathText, responseText, readyStateText, message; 421 if (xmlhttp.status) { 422 statusCode = "\n" + Drupal.t("An AJAX HTTP error occurred.") + "\n" + Drupal.t("HTTP Result Code: !status", {'!status': xmlhttp.status}); 423 } 424 else { 425 statusCode = "\n" + Drupal.t("An AJAX HTTP request terminated abnormally."); 426 } 427 statusCode += "\n" + Drupal.t("Debugging information follows."); 428 pathText = "\n" + Drupal.t("Path: !uri", {'!uri': uri} ); 429 statusText = ''; 430 // In some cases, when statusCode == 0, xmlhttp.statusText may not be defined. 431 // Unfortunately, testing for it with typeof, etc, doesn't seem to catch that 432 // and the test causes an exception. So we need to catch the exception here. 433 try { 434 statusText = "\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)}); 435 } 436 catch (e) {} 437 438 responseText = ''; 439 // Again, we don't have a way to know for sure whether accessing 440 // xmlhttp.responseText is going to throw an exception. So we'll catch it. 441 try { 442 responseText = "\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText) } ); 443 } catch (e) {} 444 445 // Make the responseText more readable by stripping HTML tags and newlines. 446 responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi,""); 447 responseText = responseText.replace(/[\n]+\s+/g,"\n"); 448 449 // We don't need readyState except for status == 0. 450 readyStateText = xmlhttp.status == 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : ""; 451 452 // Additional message beyond what the xmlhttp object provides. 453 customMessage = customMessage ? ("\n" + Drupal.t("CustomMessage: !customMessage", {'!customMessage': customMessage})) : ""; 454 455 message = statusCode + pathText + statusText + customMessage + responseText + readyStateText; 456 return message; 457}; 458 459// Class indicating that JS is enabled; used for styling purpose. 460$('html').addClass('js'); 461 462// 'js enabled' cookie. 463document.cookie = 'has_js=1; path=/'; 464 465/** 466 * Additions to jQuery.support. 467 */ 468$(function () { 469 /** 470 * Boolean indicating whether or not position:fixed is supported. 471 */ 472 if (jQuery.support.positionFixed === undefined) { 473 var el = $('<div style="position:fixed; top:10px" />').appendTo(document.body); 474 jQuery.support.positionFixed = el[0].offsetTop === 10; 475 el.remove(); 476 } 477}); 478 479//Attach all behaviors. 480$(function () { 481 Drupal.attachBehaviors(document, Drupal.settings); 482}); 483 484/** 485 * The default themes. 486 */ 487Drupal.theme.prototype = { 488 489 /** 490 * Formats text for emphasized display in a placeholder inside a sentence. 491 * 492 * @param str 493 * The text to format (plain-text). 494 * @return 495 * The formatted text (html). 496 */ 497 placeholder: function (str) { 498 return '<em class="placeholder">' + Drupal.checkPlain(str) + '</em>'; 499 } 500}; 501 502})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.