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