PageSourceSearch

https://www.columbiaortho.org/sites/default/files/js/js_cQ8Jiw8JvHVXsNV2g-L7yMVwg24KGufO80ReAcoFRUA.js

js columbiaortho.org collected 2026-10-03 21:01:27 UTC 54,542 bytes, 1,467 lines download raw bytes

1(function ($) {
2
3  Drupal.behaviors.esi = {
4    attach: function (context, settings) {
5      var contextualize_urls = (typeof Drupal.settings.ESI !== 'undefined') && Drupal.settings.ESI.contextualize_URLs;
6      if (contextualize_urls) {
7        $().esiTags().DrupalESIContextualizeURL().handleESI();
8      }
9      else {
10        $().esiTags().handleESI();
11      }
12    }
13  };
14
15  // Add the ESI context from the cookie to the ESI URL.
16  $.fn.DrupalESIContextualizeURL = function() {
17    // Regex to find the ESI context from an ESI src URL.
18    var esi_context_regexp = /\/CACHE%3D([^\/]+)$/;
19
20    $(this).each(function() {
21      src = $(this).attr('src');
22      
23      // Get the context key from the ESI src attribute.
24      // Contexts are provided in the last element: e.g. /CACHE=FOO.
25      if (match = $(this).attr('src').match(esi_context_regexp)) {
26        context_key = match[1];
27        context_val = esi_get_user_context(context_key);
28        new_src = src.replace(esi_context_regexp, '/CACHE=' + context_val);
29        $(this).attr('src', new_src);
30      }
31    });
32    return this;
33  }
34
35  // Attach to ajax request, find block that was created and
36  // attachBehaviours to it.
37  $( document ).ajaxSuccess(function( event, request, settings ) {
38    if (event.target.nodeName.toLowerCase() == 'esi:include') {
39      var returned = $('<div></div>').html($.trim(request.responseText)).contents();
40      if (returned[0] !== undefined) {
41        var elem = $('#' + returned[0].id);
42        if (elem !== undefined) {
43          Drupal.attachBehaviors(elem[0], Drupal.settings);
44        }
45      }
46    }
47  });
48
49})(jQuery);
50
51/**
52 * Get the value of a particular context.
53 */
54function esi_get_user_context(context_key) {
55  // Transform a context string (e.g. 'USER') into the actual cookie name.
56  cookie_name = Drupal.settings.ESI.cookie_prefix + context_key + Drupal.settings.ESI.cookie_suffix;
57  return esi_get_value_from_cookie(cookie_name);
58}
59
60/**
61 * Get the value of a named cookie.
62 */
63function esi_get_value_from_cookie(cookie_name) {
64  var all_cookies = document.cookie.split(';');
65  for (var i=0; i < all_cookies.length; i++) {
66    if (all_cookies[i].indexOf(cookie_name) === 1) {
67      var values = all_cookies[i].split('=');
68      return values[1];
69    }
70  }
71  return '';
72}
73;
74/**
75 * jQuery ESI Plugin v1.0
76 * http://github.com/manarth/jquery_esi
77 *
78 * Dual licensed under the MIT and GPL licenses:
79 *   http://www.opensource.org/licenses/mit-license.php
80 *   http://www.gnu.org/licenses/gpl.html
81 *
82 * Usage:
83 * $().esiTags().handleESI();
84 */
85
86(function ($) {
87
88  // Fetch all ESI tags.
89  $.fn.esiTags = function() {
90    // Initialise a jQuery collection to return.
91    esi_tags = $();
92
93    // The handler can be called as $().esiTags, or $('foo').esiTags().
94    // Ensure we have an iterable collection in either instance.
95    if (this.length == 0) {
96      collection = $('html');
97    }
98    else {
99      collection = this;
100    }
101
102    collection.each(function() {
103      // Retrieve the base DOM element, in order to access the DOM method
104      // getElementsByTagName.
105      base_element = $(this).get(0);
106      // Discover the <esi:include> tags.
107      jQuery.each(base_element.getElementsByTagName('esi:include'), function(i, val) {
108        // Some DOMs fail to recognise that the ESI include tag is self-
109        // closing, so they treat following tags as child nodes.
110        if ($(this).children().length > 0) {
111          // Move the child nodes to become siblings.
112          children = $(this).children().detach();
113          $(this).after(children);
114        }
115        esi_tags = esi_tags.add($(this));
116      });
117      // Discover the <esi:remove> tags.
118      jQuery.each(base_element.getElementsByTagName('esi:remove'), function(i, val) {
119        // ESI remove tags are not self-closing, so no special treatment for
120        // child nodes is needed.
121        esi_tags = esi_tags.add($(this));
122      });
123    });
124    return esi_tags;
125  };
126
127  // Move child nodes to siblings.
128  $.fn.handleESIChildren = function() {
129    $(this).each(function() {
130    });
131    return this;
132  }
133
134  // Handle ESI tags.
135  // Delegates to either .handleESIInclude() or .handleESIRemove() as needed.
136  $.fn.handleESI = function() {
137    $(this).each(function() {
138      switch (this.nodeName.toLowerCase()) {
139        case 'esi:include':
140          $(this).handleESIInclude();
141          break;
142      
143        case 'esi:remove':
144          $(this).handleESIRemove();
145          break;
146      }
147    });
148
149    return this;
150  }
151
152  // Handle a single ESI Include tag.
153  $.fn.handleESIInclude = function() {
154    src = $(this).attr('src');
155    jQuery.ajax({
156      context: this,
157      headers: {
158        'X-ESI-REFERER-ORIGINAL' : document.referrer
159      },
160      url: src,
161      success: function(data, textStatus, jqXHR) {
162        esiElement = $(this);
163        esiElement.replaceWith(data);
164      }
165    });
166  }
167
168  // Handle a single ESI Remove tag.
169  $.fn.handleESIRemove = function() {
170    $(this).replaceWith('');
171  }
172
173})(jQuery);
174;
175(function($,Drupal,drupalSettings){"use strict";function doSlick(i,elm){var t=$("> .slick__slider",elm).length?$("> .slick__slider",elm):$(elm);var a=$("> .slick__arrow",elm);var o=t.data("slick")?$.extend({},drupalSettings.slick,t.data("slick")):drupalSettings.slick;var r=$.type(o.responsive)==="array"&&o.responsive.length?o.responsive:false;var d=o.appendDots;var b;var isBlazy=o.lazyLoad==="blazy"&&Drupal.blazy;var unSlick=t.hasClass("unslick");if(!unSlick){o.appendDots=d===".slick__arrow"?a:d||$(t)}if(r){for(b in r){if(r.hasOwnProperty(b)&&r[b].settings!=="unslick"){r[b].settings=$.extend({},drupalSettings.slick,globals(o),r[b].settings)}}}t.data("slick",o);o=t.data("slick");function beforeSlick(){if(o.randomize&&!t.hasClass("slick-initiliazed")){randomize()}if(!unSlick){t.on("init.sl",function(e,slick){if(d===".slick__arrow"){$(slick.$dots).insertAfter(slick.$prevArrow)}var $src=t.find(".slick-cloned.slick-active .b-lazy:not(.b-loaded)");if(isBlazy&&$src.length){Drupal.blazy.init.load($src)}})}if(isBlazy){t.on("beforeChange.sl",function(){preloadBlazy(true)})}else{$(".media--loading",t).closest(".slide__content").addClass("is-loading")}t.on("setPosition.sl",function(e,slick){setPosition(slick)})}function preloadBlazy(ahead){if(t.find(".b-lazy:not(.b-loaded)").length){var $src=t.find(ahead?".slide:not(.slick-cloned) .b-lazy:not(.b-loaded)":".slick-active .b-lazy:not(.b-loaded)");if($src.length){Drupal.blazy.init.load($src)}}}function afterChange(){if(isBlazy){preloadBlazy(false)}}function afterSlick(){t.parent().on("click.sl",".slick-down",function(e){e.preventDefault();var b=$(this);$("html, body").stop().animate({scrollTop:$(b.data("target")).offset().top-(b.data("offset")||0)},800,"easeOutQuad"in $.easing&&o.easing?o.easing:"swing")});if(o.mouseWheel){t.on("mousewheel.sl",function(e,delta){e.preventDefault();return t.slick(delta<0?"slickNext":"slickPrev")})}if(!isBlazy){t.on("lazyLoaded lazyLoadError",function(e,slick,img){setBackgroun
175d(img)})}t.on("afterChange.sl",afterChange)}function setBackground(img){var $img=$(img);var $bg=$img.closest(".media--background");var p=$img.closest(".slide")||$img.closest(".unslick");$img.parentsUntil(p).removeClass(function(index,css){return(css.match(/(\S+)loading/g)||[]).join(" ")});if($bg.length&&$bg.find("> img").length){$bg.css("background-image","url("+$img.attr("src")+")");$bg.find("> img").remove();$bg.removeAttr("data-lazy")}}function randomize(){t.children().sort(function(){return.5-Math.random()}).each(function(){t.append(this)})}function setPosition(slick){var less=slick.slideCount<=slick.options.slidesToShow;var hide=less||slick.options.arrows===false;if(t.attr("id")===slick.$slider.attr("id")){if(!slick.options.centerPadding||slick.options.centerPadding==="0"){slick.$list.css("padding","")}if(less&&slick.$slideTrack.width()<=slick.$slider.width()){slick.$slideTrack.css({left:"",transform:""})}a[hide?"addClass":"removeClass"]("element-invisible")}}function globals(o){return unSlick?{}:{slide:o.slide,lazyLoad:o.lazyLoad,dotsClass:o.dotsClass,rtl:o.rtl,customPaging:function(slick,i){var container=slick.$slides.eq(i).find("[data-thumb]")||null;var img='<img alt="'+Drupal.t(container.find("img").attr("alt"))+'" src="'+container.data("thumb")+'">';var dotsThumb=container.length&&o.dotsClass.indexOf("thumbnail")>0?'<div class="slick-dots__thumbnail">'+img+"</div>":"";var paging=slick.defaults.customPaging(slick,i);return dotsThumb?paging.add(dotsThumb):paging}}}beforeSlick();t.slick(globals(o));afterSlick();if(t.hasClass("unslick")){t.slick("unslick")}$(elm).addClass("slick--initialized")}Drupal.behaviors.slick={attach:function(context){$(".slick",context).once("slick",doSlick)}}})(jQuery,Drupal,Drupal.settings);
176;
177
178(function($) {
179
180/**
181 * Drupal FieldGroup object.
182 */
183Drupal.FieldGroup = Drupal.FieldGroup || {};
184Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {};
185Drupal.FieldGroup.groupWithfocus = null;
186
187Drupal.FieldGroup.setGroupWithfocus = function(element) {
188  element.css({display: 'block'});
189  Drupal.FieldGroup.groupWithfocus = element;
190}
191
192/**
193 * Implements Drupal.FieldGroup.processHook().
194 */
195Drupal.FieldGroup.Effects.processFieldset = {
196  execute: function (context, settings, type) {
197    if (type == 'form') {
198      // Add required fields mark to any fieldsets containing required fields
199      $('fieldset.fieldset', context).once('fieldgroup-effects', function(i) {
200        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
201          $('legend span.fieldset-legend', $(this)).eq(0).append(' ').append($('.form-required').eq(0).clone());
202        }
203        if ($('.error', $(this)).length) {
204          $('legend span.fieldset-legend', $(this)).eq(0).addClass('error');
205          Drupal.FieldGroup.setGroupWithfocus($(this));
206        }
207      });
208    }
209  }
210}
211
212/**
213 * Implements Drupal.FieldGroup.processHook().
214 */
215Drupal.FieldGroup.Effects.processAccordion = {
216  execute: function (context, settings, type) {
217    $('div.field-group-accordion-wrapper', context).once('fieldgroup-effects', function () {
218      var wrapper = $(this);
219
220      // Get the index to set active.
221      var active_index = false;
222      wrapper.find('.accordion-item').each(function(i) {
223        if ($(this).hasClass('field-group-accordion-active')) {
224          active_index = i;
225        }
226      });
227
228      wrapper.accordion({
229        heightStyle: "content", // jQuery UI >= v1.9
230        autoHeight: false,      // jQuery UI < v1.9
231        active: active_index,
232        collapsible: true,
233        changestart: function(event, ui) {
234          if ($(this).hasClass('effect-none')) {
235            ui.options.animated = false;
236          }
237          else {
238            ui.options.animated = 'slide';
239          }
240        }
241      });
242
243      if (type == 'form') {
244
245        var $firstErrorItem = false;
246
247        // Add required fields mark to any element containing required fields
248        wrapper.find('div.field-group-accordion-item').each(function(i) {
249
250          if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
251            $('h3.ui-accordion-header a').eq(i).append(' ').append($('.form-required').eq(0).clone());
252          }
253          if ($('.error', $(this)).length) {
254            // Save first error item, for focussing it.
255            if (!$firstErrorItem) {
256              $firstErrorItem = $(this).parent().accordion("option", "active", i);
257            }
258            $('h3.ui-accordion-header').eq(i).addClass('error');
259          }
260        });
261
262        // Save first error item, for focussing it.
263        if (!$firstErrorItem) {
264          $('.ui-accordion-content-active', $firstErrorItem).css({height: 'auto', width: 'auto', display: 'block'});
265        }
266
267      }
268    });
269  }
270}
271
272/**
273 * Implements Drupal.FieldGroup.processHook().
274 */
275Drupal.FieldGroup.Effects.processHtabs = {
276  execute: function (context, settings, type) {
277    if (type == 'form') {
278      // Add required fields mark to any element containing required fields
279      $('fieldset.horizontal-tabs-pane', context).once('fieldgroup-effects', function(i) {
280        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
281          $(this).data('horizontalTab').link.find('strong:first').after($('.form-required').eq(0).clone()).after(' ');
282        }
283        if ($('.error', $(this)).length) {
284          $(this).data('horizontalTab').link.parent().addClass('error');
285          Drupal.FieldGroup.setGroupWithfocus($(this));
286          $(this).data('horizontalTab').focus();
287        }
288      });
289    }
290  }
291}
292
293/**
294 * Implements Drupal.FieldGroup.processHook().
295 */
296Drupal.FieldGroup.Effects.processTabs = {
297  execute: function (context, settings, type) {
298    if (type == 'form') {
299
300      var errorFocussed = false;
301
302      // Add required fields mark to any fieldsets containing required fields
303      $('fieldset.vertical-tabs-pane', context).once('fieldgroup-effects', function(i) {
304        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
305          $(this).data('verticalTab').link.find('strong:first').after($('.form-required').eq(0).clone()).after(' ');
306        }
307        if ($('.error', $(this)).length) {
308          $(this).data('verticalTab').link.parent().addClass('error');
309          // Focus the first tab with error.
310          if (!errorFocussed) {
311            Drupal.FieldGroup.setGroupWithfocus($(this));
312            $(this).data('verticalTab').focus();
313            errorFocussed = true;
314          }
315        }
316      });
317    }
318  }
319}
320
321/**
322 * Implements Drupal.FieldGroup.processHook().
323 *
324 * TODO clean this up meaning check if this is really
325 *      necessary.
326 */
327Drupal.FieldGroup.Effects.processDiv = {
328  execute: function (context, settings, type) {
329
330    $('div.collapsible', context).once('fieldgroup-effects', function() {
331      var $wrapper = $(this);
332
333      // Turn the legend into a clickable link, but retain span.field-group-format-toggler
334      // for CSS positioning.
335
336      var $toggler = $('span.field-group-format-toggler:first', $wrapper);
337      var $link = $('<a class="field-group-format-title" href="#"></a>');
338      $link.prepend($toggler.contents());
339
340      // Add required field markers if needed
341      if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
342        $link.append(' ').append($('.form-required').eq(0).clone());
343      }
344
345      $link.appendTo($toggler);
346
347      // .wrapInner() does not retain bound events.
348      $link.click(function () {
349        var wrapper = $wrapper.get(0);
350        // Don't animate multiple times.
351        if (!wrapper.animating) {
352          wrapper.animating = true;
353          var speed = $wrapper.hasClass('speed-fast') ? 300 : 1000;
354          if ($wrapper.hasClass('effect-none') && $wrapper.hasClass('speed-none')) {
355            $('> .field-group-format-wrapper', wrapper).toggle();
356            wrapper.animating = false;
357          }
358          else if ($wrapper.hasClass('effect-blind')) {
359            $('> .field-group-format-wrapper', wrapper).toggle('blind', {}, speed);
360            wrapper.animating = false;
361          }
362          else {
363            $('> .field-group-format-wrapper', wrapper).toggle(speed, function() {
364              wrapper.animating = false;
365            });
366          }
367        }
368        $wrapper.toggleClass('collapsed');
369        return false;
370      });
371
372    });
373  }
374};
375
376/**
377 * Behaviors.
378 */
379Drupal.behaviors.fieldGroup = {
380  attach: function (context, settings) {
381    settings.field_group = settings.field_group || Drupal.settings.field_group;
382    if (settings.field_group == undefined) {
383      return;
384    }
385
386    // Execute all of them.
387    $.each(Drupal.FieldGroup.Effects, function (func) {
388      // We check for a wrapper function in Drupal.field_group as
389      // alternative for dynamic string function calls.
390      var type = func.toLowerCase().replace("process", "");
391      if (settings.field_group[type] != undefined && $.isFunction(this.execute)) {
392        this.execute(context, settings, settings.field_group[type]);
393      }
394    });
395
396    // Fixes css for fieldgroups under vertical tabs.
397    $('.fieldset-wrapper .fieldset > legend').css({display: 'block'});
398    $('.vertical-tabs fieldset.fieldset').addClass('default-fallback');
399
400    // Add a new ID to each fieldset.
401    $('.group-wrapper .horizontal-tabs-panes > fieldset', context).once('group-wrapper-panes-processed', function() {
402      // Tats bad, but we have to keep the actual id to prevent layouts to break.
403      var fieldgroupID = 'field_group-' + $(this).attr('id');
404      $(this).attr('id', fieldgroupID);
405    });
406    // Set the hash in url to remember last userselection.
407    $('.group-wrapper ul li').once('group-wrapper-ul-processed', function() {
408      var fieldGroupNavigationListIndex = $(this).index();
409      $(this).children('a').click(function() {
410        var fieldset = $('.group-wrapper fieldset').get(fieldGroupNavigationListIndex);
411        // Grab the first id, holding the wanted hashurl.
412        var hashUrl = $(fieldset).attr('id').replace(/^field_group-/, '').split(' ')[0];
413        window.location.hash = hashUrl;
414      });
415    });
416
417  }
418};
419
420})(jQuery);
421;
422/**
423 * @file
424 */
425
426(function ($) {
427
428  'use strict';
429
430  Drupal.extlink = Drupal.extlink || {};
431
432  Drupal.extlink.attach = function (context, settings) {
433    if (!settings.hasOwnProperty('extlink')) {
434      return;
435    }
436
437    // Strip the host name down, removing ports, subdomains, or www.
438    var pattern = /^(([^\/:]+?\.)*)([^\.:]{1,})((\.[a-z0-9]{1,253})*)(:[0-9]{1,5})?$/;
439    var host = window.location.host.replace(pattern, '$2$3$6');
440    var subdomain = window.location.host.replace(host, '');
441
442    // Determine what subdomains are considered internal.
443    var subdomains;
444    if (settings.extlink.extSubdomains) {
445      subdomains = '([^/]*\\.)?';
446    }
447    else if (subdomain === 'www.' || subdomain === '') {
448      subdomains = '(www\\.)?';
449    }
450    else {
451      subdomains = subdomain.replace('.', '\\.');
452    }
453
454    // Build regular expressions that define an internal link.
455    var internal_link = new RegExp('^https?://([^@]*@)?' + subdomains + host, 'i');
456
457    // Extra internal link matching.
458    var extInclude = false;
459    if (settings.extlink.extInclude) {
460      extInclude = new RegExp(settings.extlink.extInclude.replace(/\\/, '\\'), 'i');
461    }
462
463    // Extra external link matching.
464    var extExclude = false;
465    if (settings.extlink.extExclude) {
466      extExclude = new RegExp(settings.extlink.extExclude.replace(/\\/, '\\'), 'i');
467    }
468
469    // Extra external link CSS selector exclusion.
470    var extCssExclude = false;
471    if (settings.extlink.extCssExclude) {
472      extCssExclude = settings.extlink.extCssExclude;
473    }
474
475    // Extra external link CSS selector explicit.
476    var extCssExplicit = false;
477    if (settings.extlink.extCssExplicit) {
478      extCssExplicit = settings.extlink.extCssExplicit;
479    }
480
481    // Define the jQuery method (either 'append' or 'prepend') of placing the icon, defaults to 'append'.
482    var extIconPlacement = settings.extlink.extIconPlacement || 'append';
483
484    // Find all links which are NOT internal and begin with http as opposed
485    // to ftp://, javascript:, etc. other kinds of links.
486    // When operating on the 'this' variable, the host has been appended to
487    // all links by the browser, even local ones.
488    // In jQuery 1.1 and higher, we'd use a filter method here, but it is not
489    // available in jQuery 1.0 (Drupal 5 default).
490    var external_links = [];
491    var mailto_links = [];
492    $('a:not([data-extlink]), area:not([data-extlink])', context).each(function (el) {
493      try {
494        var url = '';
495        if (typeof this.href == 'string') {
496          url = this.href.toLowerCase();
497        }
498        // Handle SVG links (xlink:href).
499        else if (typeof this.href == 'object') {
500          url = this.href.baseVal;
501        }
502        if (url.indexOf('http') === 0
503          && ((!url.match(internal_link) && !(extExclude && url.match(extExclude))) || (extInclude && url.match(extInclude)))
504          && !(extCssExclude && $(this).is(extCssExclude))
505          && !(extCssExclude && $(this).parents(extCssExclude).length > 0)
506          && !(extCssExplicit && $(this).parents(extCssExplicit).length < 1)) {
507          external_links.push(this);
508        }
509        // Do not include area tags with begin with mailto: (this prohibits
510        // icons from being added to image-maps).
511        else if (this.tagName !== 'AREA'
512          && url.indexOf('mailto:') === 0
513          && !(extCssExclude && $(this).parents(extCssExclude).length > 0)
514          && !(extCssExplicit && $(this).parents(extCssExplicit).length < 1)) {
515          mailto_links.push(this);
516        }
517      }
518      // IE7 throws errors often when dealing with irregular links, such as:
519      // <a href="node/10"></a> Empty tags.
520      // <a href="http://user:[email protected]">example</a> User:pass syntax.
521      catch (error) {
522        return false;
523      }
524    });
525
526    if (settings.extlink.extClass) {
527      Drupal.extlink.applyClassAndSpan(external_links, settings.extlink.extClass, extIconPlacement);
528    }
529
530    if (settings.extlink.mailtoClass) {
531      Drupal.extlink.applyClassAndSpan(mailto_links, settings.extlink.mailtoClass, extIconPlacement);
532    }
533
534    if (settings.extlink.extTarget) {
535      // Apply the target attribute to all links.
536      $(external_links).attr('target', settings.extlink.extTarget);
537      // Add rel attributes noopener and noreferrer.
538      $(external_links).attr('rel', function (i, val) {
539        // If no rel attribute is present, create one with the values noopener and noreferrer.
540        if (val == null) {
541          return 'noopener noreferrer';
542        }
543        // Check to see if rel contains noopener or noreferrer. Add what doesn't exist.
544        if (val.indexOf('noopener') > -1 || val.indexOf('noreferrer') > -1) {
545          if (val.indexOf('noopener') === -1) {
546            return val + ' noopener';
547          }
548          if (val.indexOf('noreferrer') === -1) {
549            return val + ' noreferrer';
550          }
551          // Both noopener and noreferrer exist. Nothing needs to be added.
552          else {
553            return val;
554          }
555        }
556        // Else, append noopener and noreferrer to val.
557        else {
558          return val + ' noopener noreferrer';
559        }
560      });
561    }
562
563    Drupal.extlink = Drupal.extlink || {};
564
565    // Set up default click function for the external links popup. This should be
566    // overridden by modules wanting to alter the popup.
567    Drupal.extlink.popupClickHandler = Drupal.extlink.popupClickHandler || function () {
568      if (settings.extlink.extAlert) {
569        return confirm(settings.extlink.extAlertText);
570      }
571    };
572
573    $(external_links).click(function (e) {
574      return Drupal.extlink.popupClickHandler(e, this);
575    });
576  };
577
578  /**
579   * Apply a class and a trailing <span> to all links not containing images.
580   *
581   * @param {object[]} links
582   *   An array of DOM elements representing the links.
583   * @param {string} class_name
584   *   The class to apply to the links.
585   * @param {string} icon_placement
586   *   'append' or 'prepend' the icon to the link.
587   */
588  Drupal.extlink.applyClassAndSpan = function (links, class_name, icon_placement) {
589    var $links_to_process;
590    if (Drupal.settings.extlink.extImgClass) {
591      $links_to_process = $(links);
592    }
593    else {
594      var links_with_images = $(links).find('img').parents('a');
595      $links_to_process = $(links).not(links_with_images);
596    }
597    // Add data-extlink attribute.
598    $links_to_process.attr('data-extlink', '');
599    var i;
600    var length = $links_to_process.length;
601    for (i = 0; i < length; i++) {
602      var $link = $($links_to_process[i]);
603      if ($link.css('display') === 'inline' || $link.css('display') === 'inline-block' || $link.css('display') === 'block') {
604        if (Drupal.settings.extlink.extUseFontAwesome) {
605          if (class_name === Drupal.settings.extlink.mailtoClass) {
606            $link[icon_placement]('<span class="fa-' + class_name + ' extlink"><span class="fa fa-envelope-o" title="' + Drupal.settings.extlink.mailtoLabel + '"></span><span class="element-invisible">' + Drupal.settings.extlink.mailtoLabel + '</span></span>');
607          }
608          else {
609            $link[icon_placement]('<span class="fa-' + class_name + ' extlink"><span class="fa fa-external-link" title="' + Drupal.settings.extlink.extLabel + '"></span><span class="element-invisible">' + Drupal.settings.extlink.extLabel + '</span></span>');
610          }
611        }
612        else {
613          if (class_name === Drupal.settings.extlink.mailtoClass) {
614            $link[icon_placement]('<span class="' + class_name + '"><span class="element-invisible">' + Drupal.settings.extlink.mailtoLabel + '</span></span>');
615          }
616          else {
617            $link[icon_placement]('<span class="' + class_name + '"><span class="element-invisible">' + Drupal.settings.extlink.extLabel + '</span></span>');
618          }
619        }
620      }
621    }
622  };
623
624  Drupal.behaviors.extlink = Drupal.behaviors.extlink || {};
625  Drupal.behaviors.extlink.attach = function (context, settings) {
626    // Backwards compatibility, for the benefit of modules overriding extlink
627    // functionality by defining an "extlinkAttach" global function.
628    if (typeof extlinkAttach === 'function') {
629      extlinkAttach(context);
630    }
631    else {
632      Drupal.extlink.attach(context, settings);
633    }
634  };
635
636})(jQuery);
637;
638(function ($) {
639
640/**
641 * A progressbar object. Initialized with the given id. Must be inserted into
642 * the DOM afterwards through progressBar.element.
643 *
644 * method is the function which will perform the HTTP request to get the
645 * progress bar state. Either "GET" or "POST".
646 *
647 * e.g. pb = new progressBar('myProgressBar');
648 *      some_element.appendChild(pb.element);
649 */
650Drupal.progressBar = function (id, updateCallback, method, errorCallback) {
651  var pb = this;
652  this.id = id;
653  this.method = method || 'GET';
654  this.updateCallback = updateCallback;
655  this.errorCallback = errorCallback;
656
657  // The WAI-ARIA setting aria-live="polite" will announce changes after users
658  // have completed their current activity and not interrupt the screen reader.
659  this.element = $('<div class="progress" aria-live="polite"></div>').attr('id', id);
660  this.element.html('<div class="bar"><div class="filled"></div></div>' +
661                    '<div class="percentage"></div>' +
662                    '<div class="message">&nbsp;</div>');
663};
664
665/**
666 * Set the percentage and status message for the progressbar.
667 */
668Drupal.progressBar.prototype.setProgress = function (percentage, message) {
669  if (percentage >= 0 && percentage <= 100) {
670    $('div.filled', this.element).css('width', percentage + '%');
671    $('div.percentage', this.element).html(percentage + '%');
672  }
673  $('div.message', this.element).html(message);
674  if (this.updateCallback) {
675    this.updateCallback(percentage, message, this);
676  }
677};
678
679/**
680 * Start monitoring progress via Ajax.
681 */
682Drupal.progressBar.prototype.startMonitoring = function (uri, delay) {
683  this.delay = delay;
684  this.uri = uri;
685  this.sendPing();
686};
687
688/**
689 * Stop monitoring progress via Ajax.
690 */
691Drupal.progressBar.prototype.stopMonitoring = function () {
692  clearTimeout(this.timer);
693  // This allows monitoring to be stopped from within the callback.
694  this.uri = null;
695};
696
697/**
698 * Request progress data from server.
699 */
700Drupal.progressBar.prototype.sendPing = function () {
701  if (this.timer) {
702    clearTimeout(this.timer);
703  }
704  if (this.uri) {
705    var pb = this;
706    // When doing a post request, you need non-null data. Otherwise a
707    // HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
708    $.ajax({
709      type: this.method,
710      url: this.uri,
711      data: '',
712      dataType: 'json',
713      success: function (progress) {
714        // Display errors.
715        if (progress.status == 0) {
716          pb.displayError(progress.data);
717          return;
718        }
719        // Update display.
720        pb.setProgress(progress.percentage, progress.message);
721        // Schedule next timer.
722        pb.timer = setTimeout(function () { pb.sendPing(); }, pb.delay);
723      },
724      error: function (xmlhttp) {
725        pb.displayError(Drupal.ajaxError(xmlhttp, pb.uri));
726      }
727    });
728  }
729};
730
731/**
732 * Display errors on the page.
733 */
734Drupal.progressBar.prototype.displayError = function (string) {
735  var error = $('<div class="messages error"></div>').html(string);
736  $(this.element).before(error).hide();
737
738  if (this.errorCallback) {
739    this.errorCallback(this);
740  }
741};
742
743})(jQuery);
744;
745/**
746 * @file
747 *
748 * Implement a modal form.
749 *
750 * @see modal.inc for documentation.
751 *
752 * This javascript relies on the CTools ajax responder.
753 */
754
755(function ($) {
756  // Make sure our objects are defined.
757  Drupal.CTools = Drupal.CTools || {};
758  Drupal.CTools.Modal = Drupal.CTools.Modal || {};
759
760  /**
761   * Display the modal
762   *
763   * @todo -- document the settings.
764   */
765  Drupal.CTools.Modal.show = function(choice) {
766    var opts = {};
767
768    if (choice && typeof choice == 'string' && Drupal.settings[choice]) {
769      // This notation guarantees we are actually copying it.
770      $.extend(true, opts, Drupal.settings[choice]);
771    }
772    else if (choice) {
773      $.extend(true, opts, choice);
774    }
775
776    var defaults = {
777      modalTheme: 'CToolsModalDialog',
778      throbberTheme: 'CToolsModalThrobber',
779      animation: 'show',
780      animationSpeed: 'fast',
781      modalSize: {
782        type: 'scale',
783        width: .8,
784        height: .8,
785        addWidth: 0,
786        addHeight: 0,
787        // How much to remove from the inner content to make space for the
788        // theming.
789        contentRight: 25,
790        contentBottom: 45
791      },
792      modalOptions: {
793        opacity: .55,
794        background: '#fff'
795      },
796      modalClass: 'default'
797    };
798
799    var settings = {};
800    $.extend(true, settings, defaults, Drupal.settings.CToolsModal, opts);
801
802    if (Drupal.CTools.Modal.currentSettings && Drupal.CTools.Modal.currentSettings != settings) {
803      Drupal.CTools.Modal.modal.remove();
804      Drupal.CTools.Modal.modal = null;
805    }
806
807    Drupal.CTools.Modal.currentSettings = settings;
808
809    var resize = function(e) {
810      // When creating the modal, it actually exists only in a theoretical
811      // place that is not in the DOM. But once the modal exists, it is in the
812      // DOM so the context must be set appropriately.
813      var context = e ? document : Drupal.CTools.Modal.modal;
814
815      if (Drupal.CTools.Modal.currentSettings.modalSize.type == 'scale') {
816        var width = $(window).width() * Drupal.CTools.Modal.currentSettings.modalSize.width;
817        var height = $(window).height() * Drupal.CTools.Modal.currentSettings.modalSize.height;
818      }
819      else {
820        var width = Drupal.CTools.Modal.currentSettings.modalSize.width;
821        var height = Drupal.CTools.Modal.currentSettings.modalSize.height;
822      }
823
824      // Use the additionol pixels for creating the width and height.
825      $('div.ctools-modal-content', context).css({
826        'width': width + Drupal.CTools.Modal.currentSettings.modalSize.addWidth + 'px',
827        'height': height + Drupal.CTools.Modal.currentSettings.modalSize.addHeight + 'px'
828      });
829      $('div.ctools-modal-content .modal-content', context).css({
830        'width': (width - Drupal.CTools.Modal.currentSettings.modalSize.contentRight) + 'px',
831        'height': (height - Drupal.CTools.Modal.currentSettings.modalSize.contentBottom) + 'px'
832      });
833    };
834
835    if (!Drupal.CTools.Modal.modal) {
836      Drupal.CTools.Modal.modal = $(Drupal.theme(settings.modalTheme));
837      if (settings.modalSize.type == 'scale') {
838        $(window).bind('resize', resize);
839      }
840    }
841
842    resize();
843
844    $('span.modal-title', Drupal.CTools.Modal.modal).html(Drupal.CTools.Modal.currentSettings.loadingText);
845    Drupal.CTools.Modal.modalContent(Drupal.CTools.Modal.modal, settings.modalOptions, settings.animation, settings.animationSpeed, settings.modalClass);
846    $('#modalContent .modal-content').html(Drupal.theme(settings.throbberTheme)).addClass('ctools-modal-loading');
847
848    // Position autocomplete results based on the scroll position of the modal.
849    $('#modalContent .modal-content').delegate('input.form-autocomplete', 'keyup', function() {
850      $('#autocomplete').css('top', $(this).position().top + $(this).outerHeight() + $(this).offsetParent().filter('#modal-content').scrollTop());
851    });
852  };
853
854  /**
855   * Hide the modal
856   */
857  Drupal.CTools.Modal.dismiss = function() {
858    if (Drupal.CTools.Modal.modal) {
859      Drupal.CTools.Modal.unmodalContent(Drupal.CTools.Modal.modal);
860    }
861  };
862
863  /**
864   * Provide the HTML to create the modal dialog.
865   */
866  Drupal.theme.prototype.CToolsModalDialog = function () {
867    var html = '';
868    html += '<div id="ctools-modal">';
869    html += '  <div class="ctools-modal-content">'; // panels-modal-content
870    html += '    <div class="modal-header">';
871    html += '      <a class="close" href="#">';
872    html +=          Drupal.CTools.Modal.currentSettings.closeText + Drupal.CTools.Modal.currentSettings.closeImage;
873    html += '      </a>';
874    html += '      <span id="modal-title" class="modal-title">&nbsp;</span>';
875    html += '    </div>';
876    html += '    <div id="modal-content" class="modal-content">';
877    html += '    </div>';
878    html += '  </div>';
879    html += '</div>';
880
881    return html;
882  };
883
884  /**
885   * Provide the HTML to create the throbber.
886   */
887  Drupal.theme.prototype.CToolsModalThrobber = function () {
888    var html = '';
889    html += '<div id="modal-throbber">';
890    html += '  <div class="modal-throbber-wrapper">';
891    html +=      Drupal.CTools.Modal.currentSettings.throbber;
892    html += '  </div>';
893    html += '</div>';
894
895    return html;
896  };
897
898  /**
899   * Figure out what settings string to use to display a modal.
900   */
901  Drupal.CTools.Modal.getSettings = function (object) {
902    var match = $(object).attr('class').match(/ctools-modal-(\S+)/);
903    if (match) {
904      return match[1];
905    }
906  };
907
908  /**
909   * Click function for modals that can be cached.
910   */
911  Drupal.CTools.Modal.clickAjaxCacheLink = function () {
912    Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(this));
913    return Drupal.CTools.AJAX.clickAJAXCacheLink.apply(this);
914  };
915
916  /**
917   * Handler to prepare the modal for the response
918   */
919  Drupal.CTools.Modal.clickAjaxLink = function () {
920    Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(this));
921    return false;
922  };
923
924  /**
925   * Submit responder to do an AJAX submit on all modal forms.
926   */
927  Drupal.CTools.Modal.submitAjaxForm = function(e) {
928    var $form = $(this);
929    var url = $form.attr('action');
930
931    setTimeout(function() { Drupal.CTools.AJAX.ajaxSubmit($form, url); }, 1);
932    return false;
933  };
934
935  /**
936   * Bind links that will open modals to the appropriate function.
937   */
938  Drupal.behaviors.ZZCToolsModal = {
939    attach: function(context) {
940      // Bind links
941      // Note that doing so in this order means that the two classes can be
942      // used together safely.
943      /*
944       * @todo remimplement the warm caching feature
945       $('a.ctools-use-modal-cache', context).once('ctools-use-modal', function() {
946         $(this).click(Drupal.CTools.Modal.clickAjaxCacheLink);
947         Drupal.CTools.AJAX.warmCache.apply(this);
948       });
949        */
950
951      $('area.ctools-use-modal, a.ctools-use-modal', context).once('ctools-use-modal', function() {
952        var $this = $(this);
953        $this.click(Drupal.CTools.Modal.clickAjaxLink);
954        // Create a drupal ajax object
955        var element_settings = {};
956        if ($this.attr('href')) {
957          element_settings.url = $this.attr('href');
958          element_settings.event = 'click';
959          element_settings.progress = { type: 'throbber' };
960        }
961        var base = $this.attr('href');
962        Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
963      });
964
965      // Bind buttons
966      $('input.ctools-use-modal, button.ctools-use-modal', context).once('ctools-use-modal', function() {
967        var $this = $(this);
968        $this.click(Drupal.CTools.Modal.clickAjaxLink);
969        var button = this;
970        var element_settings = {};
971
972        // AJAX submits specified in this manner automatically submit to the
973        // normal form action.
974        element_settings.url = Drupal.CTools.Modal.findURL(this);
975        if (element_settings.url == '') {
976          element_settings.url = $(this).closest('form').attr('action');
977        }
978        element_settings.event = 'click';
979        element_settings.setClick = true;
980
981        var base = $this.attr('id');
982        Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
983
984        // Make sure changes to settings are reflected in the URL.
985        $('.' + $(button).attr('id') + '-url').change(function() {
986          Drupal.ajax[base].options.url = Drupal.CTools.Modal.findURL(button);
987        });
988      });
989
990      // Bind our custom event to the form submit
991      $('#modal-content form', context).once('ctools-use-modal', function() {
992        var $this = $(this);
993        var element_settings = {};
994
995        element_settings.url = $this.attr('action');
996        element_settings.event = 'submit';
997        element_settings.progress = { 'type': 'throbber' };
998        var base = $this.attr('id');
999
1000        Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
1001        Drupal.ajax[base].form = $this;
1002
1003        $('input[type=submit], button', this).click(function(event) {
1004          Drupal.ajax[base].element = this;
1005          this.form.clk = this;
1006          // Stop autocomplete from submitting.
1007          if (Drupal.autocompleteSubmit && !Drupal.autocompleteSubmit()) {
1008            return false;
1009          }
1010          // An empty event means we were triggered via .click() and
1011          // in jquery 1.4 this won't trigger a submit.
1012          // We also have to check jQuery version to prevent
1013          // IE8 + jQuery 1.4.4 to break on other events
1014          // bound to the submit button.
1015          if (jQuery.fn.jquery.substr(0, 3) === '1.4' && typeof event.bubbles === "undefined") {
1016            $(this.form).trigger('submit');
1017            return false;
1018          }
1019        });
1020      });
1021
1022      // Bind a click handler to allow elements with the 'ctools-close-modal'
1023      // class to close the modal.
1024      $('.ctools-close-modal', context).once('ctools-close-modal')
1025        .click(function() {
1026          Drupal.CTools.Modal.dismiss();
1027          return false;
1028        });
1029    }
1030  };
1031
1032  // The following are implementations of AJAX responder commands.
1033
1034  /**
1035   * AJAX responder command to place HTML within the modal.
1036   */
1037  Drupal.CTools.Modal.modal_display = function(ajax, response, status) {
1038    var settings = response.settings || ajax.settings || Drupal.settings;
1039    // If the modal does not exist yet, create it.
1040    if ($('#modalContent').length == 0) {
1041      Drupal.CTools.Modal.show(Drupal.CTools.Modal.getSettings(ajax.element));
1042    }
1043    // If the modal exists run detachBehaviors before removing existing content.
1044    else {
1045      Drupal.detachBehaviors($('#modalContent'), settings, 'unload');
1046    }
1047    $('#modal-title').html(response.title);
1048    // Simulate an actual page load by scrolling to the top after adding the
1049    // content. This is helpful for allowing users to see error messages at the
1050    // top of a form, etc.
1051    $('#modal-content').html(response.output).scrollTop(0);
1052    $(document).trigger('CToolsAttachBehaviors', $('#modalContent'));
1053
1054    // Attach behaviors within a modal dialog.
1055    Drupal.attachBehaviors($('#modalContent'), settings);
1056
1057    if ($('#modal-content').hasClass('ctools-modal-loading')) {
1058      $('#modal-content').removeClass('ctools-modal-loading');
1059    }
1060    else {
1061      // If the modal was already shown, and we are simply replacing its
1062      // content, then focus on the first focusable element in the modal.
1063      // (When first showing the modal, focus will be placed on the close
1064      // button by the show() function called above.)
1065      $('#modal-content :focusable:first').focus();
1066    }
1067
1068    // Force all attached animations to finish, and trigger a window resize
1069    // event to center te modal after the ajax content has been added.
1070    $('#modalContent').stop(true, true);
1071    $(window).resize();
1072  };
1073
1074  /**
1075   * AJAX responder command to dismiss the modal.
1076   */
1077  Drupal.CTools.Modal.modal_dismiss = function(command) {
1078    Drupal.CTools.Modal.dismiss();
1079    $('link.ctools-temporary-css').remove();
1080  };
1081
1082  /**
1083   * Display loading
1084   */
1085  //Drupal.CTools.AJAX.commands.modal_loading = function(command) {
1086  Drupal.CTools.Modal.modal_loading = function(command) {
1087    Drupal.CTools.Modal.modal_display({
1088      output: Drupal.theme(Drupal.CTools.Modal.currentSettings.throbberTheme),
1089      title: Drupal.CTools.Modal.currentSettings.loadingText
1090    });
1091  };
1092
1093  /**
1094   * Find a URL for an AJAX button.
1095   *
1096   * The URL for this gadget will be composed of the values of items by
1097   * taking the ID of this item and adding -url and looking for that
1098   * class. They need to be in the form in order since we will
1099   * concat them all together using '/'.
1100   */
1101  Drupal.CTools.Modal.findURL = function(item) {
1102    var url = '';
1103    var url_class = '.' + $(item).attr('id') + '-url';
1104    $(url_class).each(
1105      function() {
1106        var $this = $(this);
1107        if (url && $this.val()) {
1108          url += '/';
1109        }
1110        url += $this.val();
1111      });
1112    return url;
1113  };
1114
1115
1116  /**
1117   * modalContent
1118   * @param content string to display in the content box
1119   * @param css obj of css attributes
1120   * @param animation (fadeIn, slideDown, show)
1121   * @param speed (valid animation speeds slow, medium, fast or # in ms)
1122   * @param modalClass class added to div#modalContent
1123   */
1124  Drupal.CTools.Modal.modalContent = function(content, css, animation, speed, modalClass) {
1125    // If our animation isn't set, make it just show/pop
1126    if (!animation) {
1127      animation = 'show';
1128    }
1129    else {
1130      // If our animation isn't "fadeIn" or "slideDown" then it always is show
1131      if (animation != 'fadeIn' && animation != 'slideDown') {
1132        animation = 'show';
1133      }
1134    }
1135
1136    if (!speed && 0 !== speed) {
1137      speed = 'fast';
1138    }
1139
1140    // Build our base attributes and allow them to be overriden
1141    css = jQuery.extend({
1142      position: 'absolute',
1143      left: '0px',
1144      margin: '0px',
1145      background: '#000',
1146      opacity: '.55'
1147    }, css);
1148
1149    // Add opacity handling for IE.
1150    css.filter = 'alpha(opacity=' + (100 * css.opacity) + ')';
1151    content.hide();
1152
1153    // If we already have modalContent, remove it.
1154    if ($('#modalBackdrop').length) $('#modalBackdrop').remove();
1155    if ($('#modalContent').length) $('#modalContent').remove();
1156
1157    // position code lifted from http://www.quirksmode.org/viewport/compatibility.html
1158    if (self.pageYOffset) { // all except Explorer
1159    var wt = self.pageYOffset;
1160    } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
1161      var wt = document.documentElement.scrollTop;
1162    } else if (document.body) { // all other Explorers
1163      var wt = document.body.scrollTop;
1164    }
1165
1166    // Get our dimensions
1167
1168    // Get the docHeight and (ugly hack) add 50 pixels to make sure we dont have a *visible* border below our div
1169    var docHeight = $(document).height() + 50;
1170    var docWidth = $(document).width();
1171    var winHeight = $(window).height();
1172    var winWidth = $(window).width();
1173    if( docHeight < winHeight ) docHeight = winHeight;
1174
1175    // Create our divs
1176    $('body').append('<div id="modalBackdrop" class="backdrop-' + modalClass + '" style="z-index: 1000; display: none;"></div><div id="modalContent" class="modal-' + modalClass + '" style="z-index: 1001; position: absolute;">' + $(content).html() + '</div>');
1177
1178    // Get a list of the tabbable elements in the modal content.
1179    var getTabbableElements = function () {
1180      var tabbableElements = $('#modalContent :tabbable'),
1181          radioButtons = tabbableElements.filter('input[type="radio"]');
1182
1183      // The list of tabbable elements from jQuery is *almost* right. The
1184      // exception is with groups of radio buttons. The list from jQuery will
1185      // include all radio buttons, when in fact, only the selected radio button
1186      // is tabbable, and if no radio buttons in a group are selected, then only
1187      // the first is tabbable.
1188      if (radioButtons.length > 0) {
1189        // First, build up an index of which groups have an item selected or not.
1190        var anySelected = {};
1191        radioButtons.each(function () {
1192          var name = this.name;
1193
1194          if (typeof anySelected[name] === 'undefined') {
1195            anySelected[name] = radioButtons.filter('input[name="' + name + '"]:checked').length !== 0;
1196          }
1197        });
1198
1199        // Next filter out the radio buttons that aren't really tabbable.
1200        var found = {};
1201        tabbableElements = tabbableElements.filter(function () {
1202          var keep = true;
1203
1204          if (this.type == 'radio') {
1205            if (anySelected[this.name]) {
1206              // Only keep the selected one.
1207              keep = this.checked;
1208            }
1209            else {
1210              // Only keep the first one.
1211              if (found[this.name]) {
1212                keep = false;
1213              }
1214              found[this.name] = true;
1215            }
1216          }
1217
1218          return keep;
1219        });
1220      }
1221
1222      return tabbableElements.get();
1223    };
1224
1225    // Keyboard and focus event handler ensures only modal elements gain focus.
1226    modalEventHandler = function( event ) {
1227      target = null;
1228      if ( event ) { //Mozilla
1229        target = event.target;
1230      } else { //IE
1231        event = window.event;
1232        target = event.srcElement;
1233      }
1234
1235      var parents = $(target).parents().get();
1236      for (var i = 0; i < parents.length; ++i) {
1237        var position = $(parents[i]).css('position');
1238        if (position == 'absolute' || position == 'fixed') {
1239          return true;
1240        }
1241      }
1242
1243      if ($(target).is('#modalContent, body') || $(target).filter('*:visible').parents('#modalContent').length) {
1244        // Allow the event only if target is a visible child node
1245        // of #modalContent.
1246        return true;
1247      }
1248      else {
1249        getTabbableElements()[0].focus();
1250      }
1251
1252      event.preventDefault();
1253    };
1254    $('body').bind( 'focus', modalEventHandler );
1255    $('body').bind( 'keypress', modalEventHandler );
1256
1257    // Keypress handler Ensures you can only TAB to elements within the modal.
1258    // Based on the psuedo-code from WAI-ARIA 1.0 Authoring Practices section
1259    // 3.3.1 "Trapping Focus".
1260    modalTabTrapHandler = function (evt) {
1261      // We only care about the TAB key.
1262      if (evt.which != 9) {
1263        return true;
1264      }
1265
1266      var tabbableElements = getTabbableElements(),
1267          firstTabbableElement = tabbableElements[0],
1268          lastTabbableElement = tabbableElements[tabbableElements.length - 1],
1269          singleTabbableElement = firstTabbableElement == lastTabbableElement,
1270          node = evt.target;
1271
1272      // If this is the first element and the user wants to go backwards, then
1273      // jump to the last element.
1274      if (node == firstTabbableElement && evt.shiftKey) {
1275        if (!singleTabbableElement) {
1276          lastTabbableElement.focus();
1277        }
1278        return false;
1279      }
1280      // If this is the last element and the user wants to go forwards, then
1281      // jump to the first element.
1282      else if (node == lastTabbableElement && !evt.shiftKey) {
1283        if (!singleTabbableElement) {
1284          firstTabbableElement.focus();
1285        }
1286        return false;
1287      }
1288      // If this element isn't in the dialog at all, then jump to the first
1289      // or last element to get the user into the game.
1290      else if ($.inArray(node, tabbableElements) == -1) {
1291        // Make sure the node isn't in another modal (ie. WYSIWYG modal).
1292        var parents = $(node).parents().get();
1293        for (var i = 0; i < parents.length; ++i) {
1294          var position = $(parents[i]).css('position');
1295          if (position == 'absolute' || position == 'fixed') {
1296            return true;
1297          }
1298        }
1299
1300        if (evt.shiftKey) {
1301          lastTabbableElement.focus();
1302        }
1303        else {
1304          firstTabbableElement.focus();
1305        }
1306      }
1307    };
1308    $('body').bind('keydown', modalTabTrapHandler);
1309
1310    // Create our content div, get the dimensions, and hide it
1311    var modalContent = $('#modalContent').css('top','-1000px');
1312    var $modalHeader = modalContent.find('.modal-header');
1313    var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
1314    var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
1315    $('#modalBackdrop').css(css).css('top', 0).css('height', docHeight + 'px').css('width', docWidth + 'px').show();
1316    modalContent.css({top: mdcTop + 'px', left: mdcLeft + 'px'}).hide()[animation](speed);
1317
1318    // Bind a click for closing the modalContent
1319    modalContentClose = function(){close(); return false;};
1320    $('.close', $modalHeader).bind('click', modalContentClose);
1321
1322    // Bind a keypress on escape for closing the modalContent
1323    modalEventEscapeCloseHandler = function(event) {
1324      if (event.keyCode == 27) {
1325        close();
1326        return false;
1327      }
1328    };
1329
1330    $(document).bind('keydown', modalEventEscapeCloseHandler);
1331
1332    // Per WAI-ARIA 1.0 Authoring Practices, initial focus should be on the
1333    // close button, but we should save the original focus to restore it after
1334    // the dialog is closed.
1335    var oldFocus = document.activeElement;
1336    $('.close', $modalHeader).focus();
1337
1338    // Close the open modal content and backdrop
1339    function close() {
1340      // Unbind the events
1341      $(window).unbind('resize',  modalContentResize);
1342      $('body').unbind( 'focus', modalEventHandler);
1343      $('body').unbind( 'keypress', modalEventHandler );
1344      $('body').unbind( 'keydown', modalTabTrapHandler );
1345      $('.close', $modalHeader).unbind('click', modalContentClose);
1346      $(document).unbind('keydown', modalEventEscapeCloseHandler);
1347      $(document).trigger('CToolsCloseModalBehaviors', $('#modalContent'));
1348      $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
1349
1350      // Closing animation.
1351      switch (animation) {
1352        case 'fadeIn':
1353          modalContent.fadeOut(speed, modalContentRemove);
1354          break;
1355
1356        case 'slideDown':
1357          modalContent.slideUp(speed, modalContentRemove);
1358          break;
1359
1360        case 'show':
1361          modalContent.hide(speed, modalContentRemove);
1362          break;
1363      }
1364    }
1365
1366    // Remove the content.
1367    modalContentRemove = function () {
1368      $('#modalContent').remove();
1369      $('#modalBackdrop').remove();
1370
1371      // Restore focus to where it was before opening the dialog.
1372      $(oldFocus).focus();
1373    };
1374
1375    // Move and resize the modalBackdrop and modalContent on window resize.
1376    modalContentResize = function () {
1377      // Reset the backdrop height/width to get accurate document size.
1378      $('#modalBackdrop').css('height', '').css('width', '');
1379
1380      // Position code lifted from:
1381      // http://www.quirksmode.org/viewport/compatibility.html
1382      if (self.pageYOffset) { // all except Explorer
1383        var wt = self.pageYOffset;
1384      } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
1385        var wt = document.documentElement.scrollTop;
1386      } else if (document.body) { // all other Explorers
1387        var wt = document.body.scrollTop;
1388      }
1389
1390      // Get our heights
1391      var docHeight = $(document).height();
1392      var docWidth = $(document).width();
1393      var winHeight = $(window).height();
1394      var winWidth = $(window).width();
1395      if( docHeight < winHeight ) docHeight = winHeight;
1396
1397      // Get where we should move content to
1398      var modalContent = $('#modalContent');
1399      var mdcTop = wt + Math.max((winHeight / 2) - (modalContent.outerHeight() / 2), 0);
1400      var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
1401
1402      // Apply the changes
1403      $('#modalBackdrop').css('height', docHeight + 'px').css('width', docWidth + 'px').show();
1404      modalContent.css('top', mdcTop + 'px').css('left', mdcLeft + 'px').show();
1405    };
1406    $(window).bind('resize', modalContentResize);
1407  };
1408
1409  /**
1410   * unmodalContent
1411   * @param content (The jQuery object to remove)
1412   * @param animation (fadeOut, slideUp, show)
1413   * @param speed (valid animation speeds slow, medium, fast or # in ms)
1414   */
1415  Drupal.CTools.Modal.unmodalContent = function(content, animation, speed)
1416  {
1417    // If our animation isn't set, make it just show/pop
1418    if (!animation) { var animation = 'show'; } else {
1419      // If our animation isn't "fade" then it always is show
1420      if (( animation != 'fadeOut' ) && ( animation != 'slideUp')) animation = 'show';
1421    }
1422    // Set a speed if we dont have one
1423    if ( !speed ) var speed = 'fast';
1424
1425    // Unbind the events we bound
1426    $(window).unbind('resize', modalContentResize);
1427    $('body').unbind('focus', modalEventHandler);
1428    $('body').unbind('keypress', modalEventHandler);
1429    $('body').unbind( 'keydown', modalTabTrapHandler );
1430    var $modalContent = $('#modalContent');
1431    var $modalHeader = $modalContent.find('.modal-header');
1432    $('.close', $modalHeader).unbind('click', modalContentClose);
1433    $(document).unbind('keydown', modalEventEscapeCloseHandler);
1434    $(document).trigger('CToolsDetachBehaviors', $modalContent);
1435
1436    // jQuery magic loop through the instances and run the animations or removal.
1437    content.each(function(){
1438      if ( animation == 'fade' ) {
1439        $('#modalContent').fadeOut(speed, function() {
1440          $('#modalBackdrop').fadeOut(speed, function() {
1441            $(this).remove();
1442          });
1443          $(this).remove();
1444        });
1445      } else {
1446        if ( animation == 'slide' ) {
1447          $('#modalContent').slideUp(speed,function() {
1448            $('#modalBackdrop').slideUp(speed, function() {
1449              $(this).remove();
1450            });
1451            $(this).remove();
1452          });
1453        } else {
1454          $('#modalContent').remove();
1455          $('#modalBackdrop').remove();
1456        }
1457      }
1458    });
1459  };
1460
1461$(function() {
1462  Drupal.ajax.prototype.commands.modal_display = Drupal.CTools.Modal.modal_display;
1463  Drupal.ajax.prototype.commands.modal_dismiss = Drupal.CTools.Modal.modal_dismiss;
1464});
1465
1466})(jQuery);
1467;

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.