1(function ($) { 2Drupal.behaviors.lang_dropdown = { 3 attach: function (context, settings) { 4 var settings = settings || Drupal.settings; 5 6 if (settings.lang_dropdown) { 7 var flags = settings.lang_dropdown.jsWidget.languageicons; 8 if (flags) { 9 $.each(flags, function(index, value) { 10 $('select.lang-dropdown-select-element option[value="' + index + '"]').attr('title', value); 11 }); 12 } 13 var msddSettings = settings.lang_dropdown.jsWidget; 14 15 $('select.lang-dropdown-select-element').msDropDown({ 16 visibleRows: msddSettings.visibleRows, 17 rowHeight: msddSettings.rowHeight, 18 animStyle: msddSettings.animStyle, 19 mainCSS: msddSettings.mainCSS 20 }); 21 } 22 23 try { 24 $('select.lang-dropdown-select-element').change(function() { 25 var lang = this.options[this.selectedIndex].value; 26 var href = $(this).parents('form').find('input[name="' + lang + '"]').val(); 27 window.location.href = href; 28 }); 29 } catch (e) { 30 if (console) { console.log(e); } 31 } 32 33 $('form#lang-dropdown-form').after('<div style="clear:both;"></div>'); 34 } 35}; 36})(jQuery); 37; 38/** 39 * @file 40 * Some basic behaviors and utility functions for Views. 41 */ 42(function ($) { 43 44 Drupal.Views = {}; 45 46 /** 47 * JQuery UI tabs, Views integration component. 48 */ 49 Drupal.behaviors.viewsTabs = { 50 attach: function (context) { 51 if ($.viewsUi && $.viewsUi.tabs) { 52 $('#views-tabset').once('views-processed').viewsTabs({ 53 selectedClass: 'active' 54 }); 55 } 56 57 $('a.views-remove-link').once('views-processed').click(function(event) { 58 var id = $(this).attr('id').replace('views-remove-link-', ''); 59 $('#views-row-' + id).hide(); 60 $('#views-removed-' + id).attr('checked', true); 61 event.preventDefault(); 62 }); 63 /** 64 * Here is to handle display deletion 65 * (checking in the hidden checkbox and hiding out the row). 66 */ 67 $('a.display-remove-link') 68 .addClass('display-processed') 69 .click(function() { 70 var id = $(this).attr('id').replace('display-remove-link-', ''); 71 $('#display-row-' + id).hide(); 72 $('#display-removed-' + id).attr('checked', true); 73 return false; 74 }); 75 } 76 }; 77 78 /** 79 * Helper function to parse a querystring. 80 */ 81 Drupal.Views.parseQueryString = function (query) { 82 var args = {}; 83 var pos = query.indexOf('?'); 84 if (pos != -1) { 85 query = query.substring(pos + 1); 86 } 87 var pairs = query.split('&'); 88 for (var i in pairs) { 89 if (typeof(pairs[i]) == 'string') { 90 var pair = pairs[i].split('='); 91 // Ignore the 'q' path argument, if present. 92 if (pair[0] != 'q' && pair[1]) { 93 args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] = decodeURIComponent(pair[1].replace(/\+/g, ' ')); 94 } 95 } 96 } 97 return args; 98 }; 99 100 /** 101 * Helper function to return a view's arguments based on a path. 102 */ 103 Drupal.Views.parseViewArgs = function (href, viewPath) { 104 105 // Provide language prefix. 106 if (Drupal.settings.pathPrefix) { 107 var viewPath = Drupal.settings.pathPrefix + viewPath; 108 } 109 var returnObj = {}; 110 var path = Drupal.Views.getPath(href); 111 // Ensure we have a correct path. 112 if (viewPath && path.substring(0, viewPath.length + 1) == viewPath + '/') { 113 var args = decodeURIComponent(path.substring(viewPath.length + 1, path.length)); 114 returnObj.view_args = args; 115 returnObj.view_path = path; 116 } 117 return returnObj; 118 }; 119 120 /** 121 * Strip off the protocol plus domain from an href. 122 */ 123 Drupal.Views.pathPortion = function (href) { 124 // Remove e.g. http://example.com if present. 125 var protocol = window.location.protocol; 126 if (href.substring(0, protocol.length) == protocol) { 127 // 2 is the length of the '//' that normally follows the protocol. 128 href = href.substring(href.indexOf('/', protocol.length + 2)); 129 } 130 return href; 131 }; 132 133 /** 134 * Return the Drupal path portion of an href. 135 */ 136 Drupal.Views.getPath = function (href) { 137 href = Drupal.Views.pathPortion(href); 138 href = href.substring(Drupal.settings.basePath.length, href.length); 139 // 3 is the length of the '?q=' added to the url without clean urls. 140 if (href.substring(0, 3) == '?q=') { 141 href = href.substring(3, href.length); 142 } 143 var chars = ['#', '?', '&']; 144 for (var i in chars) { 145 if (href.indexOf(chars[i]) > -1) { 146 href = href.substr(0, href.indexOf(chars[i])); 147 } 148 } 149 return href; 150 }; 151 152})(jQuery); 153; 154(function ($) { 155 156/** 157 * A progressbar object. Initialized with the given id. Must be inserted into 158 * the DOM afterwards through progressBar.element. 159 * 160 * method is the function which will perform the HTTP request to get the 161 * progress bar state. Either "GET" or "POST". 162 * 163 * e.g. pb = new progressBar('myProgressBar'); 164 * some_element.appendChild(pb.element); 165 */ 166Drupal.progressBar = function (id, updateCallback, method, errorCallback) { 167 var pb = this; 168 this.id = id; 169 this.method = method || 'GET'; 170 this.updateCallback = updateCallback; 171 this.errorCallback = errorCallback; 172
173 // The WAI-ARIA setting aria-live="polite" will announce changes after users 174 // have completed their current activity and not interrupt the screen reader. 175 this.element = $('<div class="progress-wrapper" aria-live="polite"></div>'); 176 this.element.html('<div id ="' + id + '" class="progress progress-striped active">' + 177 '<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">' + 178 '<div class="percentage sr-only"></div>' + 179 '</div></div>' + 180 '</div><div class="percentage pull-right"></div>' + 181 '<div class="message"> </div>'); 182}; 183 184/** 185 * Set the percentage and status message for the progressbar. 186 */ 187Drupal.progressBar.prototype.setProgress = function (percentage, message) { 188 if (percentage >= 0 && percentage <= 100) { 189 $('div.progress-bar', this.element).css('width', percentage + '%'); 190 $('div.progress-bar', this.element).attr('aria-valuenow', percentage); 191 $('div.percentage', this.element).html(percentage + '%'); 192 } 193 $('div.message', this.element).html(message); 194 if (this.updateCallback) { 195 this.updateCallback(percentage, message, this); 196 } 197}; 198 199/** 200 * Start monitoring progress via Ajax. 201 */ 202Drupal.progressBar.prototype.startMonitoring = function (uri, delay) { 203 this.delay = delay; 204 this.uri = uri; 205 this.sendPing(); 206}; 207 208/** 209 * Stop monitoring progress via Ajax. 210 */ 211Drupal.progressBar.prototype.stopMonitoring = function () { 212 clearTimeout(this.timer); 213 // This allows monitoring to be stopped from within the callback. 214 this.uri = null; 215}; 216 217/** 218 * Request progress data from server. 219 */ 220Drupal.progressBar.prototype.sendPing = function () { 221 if (this.timer) { 222 clearTimeout(this.timer); 223 } 224 if (this.uri) { 225 var pb = this; 226 // When doing a post request, you need non-null data. Otherwise a 227 // HTTP 411 or HTTP 406 (with Apache mod_security) error may result. 228 $.ajax({ 229 type: this.method, 230 url: this.uri, 231 data: '', 232 dataType: 'json', 233 success: function (progress) { 234 // Display errors. 235 if (progress.status == 0) { 236 pb.displayError(progress.data); 237 return; 238 } 239 // Update display. 240 pb.setProgress(progress.percentage, progress.message); 241 // Schedule next timer. 242 pb.timer = setTimeout(function () { pb.sendPing(); }, pb.delay); 243 }, 244 error: function (xmlhttp) { 245 pb.displayError(Drupal.ajaxError(xmlhttp, pb.uri)); 246 } 247 }); 248 } 249}; 250 251/** 252 * Display errors on the page. 253 */ 254Drupal.progressBar.prototype.displayError = function (string) { 255 var error = $('<div class="alert alert-block alert-error"><a class="close" data-dismiss="alert" href="#">×</a><h4>Error message</h4></div>').append(string); 256 $(this.element).before(error).hide(); 257 258 if (this.errorCallback) { 259 this.errorCallback(this); 260 } 261}; 262 263})(jQuery); 264; 265/** 266 * @file 267 * Handles AJAX fetching of views, including filter submission and response. 268 */ 269(function ($) { 270 271 /** 272 * Attaches the AJAX behavior to exposed filter forms and key views links. 273 */ 274 Drupal.behaviors.ViewsAjaxView = {}; 275 Drupal.behaviors.ViewsAjaxView.attach = function() { 276 if (Drupal.settings && Drupal.settings.views && Drupal.settings.views.ajaxViews) { 277 $.each(Drupal.settings.views.ajaxViews, function(i, settings) { 278 Drupal.views.instances[i] = new Drupal.views.ajaxView(settings); 279 }); 280 } 281 }; 282 283 Drupal.views = {}; 284 Drupal.views.instances = {}; 285 286 /** 287 * Javascript object for a certain view. 288 */ 289 Drupal.views.ajaxView = function(settings) { 290 var selector = '.view-dom-id-' + settings.view_dom_id; 291 this.$view = $(selector); 292 293 // Retrieve the path to use for views' ajax. 294 var ajax_path = Drupal.settings.views.ajax_path; 295 296 // If there are multiple views this might've ended up showing up multiple 297 // times. 298 if (ajax_path.constructor.toString().indexOf("Array") != -1) { 299 ajax_path = ajax_path[0]; 300 } 301 302 // Check if there are any GET parameters to send to views. 303 var queryString = window.location.search || ''; 304 if (queryString !== '') { 305 // Remove the question mark and Drupal path component if any. 306 var queryString = queryString.slice(1).replace(/q=[^&]+&?|&?render=[^&]+/, ''); 307 if (queryString !== '') { 308 // If there is a '?' in ajax_path, clean url are on and & should be 309 // used to add parameters. 310 queryString = ((/\?/.test(ajax_path)) ? '&' : '?') + queryString; 311 } 312 } 313 314 this.element_settings = { 315 url: ajax_path + queryString, 316 submit: settings, 317 setClick: true, 318 event: 'click', 319 selector: selector, 320 progress: { 321 type: 'throbber' 322 } 323 }; 324 325 this.settings = settings; 326
327 // Add the ajax to exposed forms. 328 this.$exposed_form = $('#views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-')); 329 this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this)); 330 331 // Store Drupal.ajax objects here for all pager links. 332 this.links = []; 333 334 // Add the ajax to pagers. 335 this.$view 336 // Don't attach to nested views. Doing so would attach multiple behaviors 337 // to a given element. 338 .filter(jQuery.proxy(this.filterNestedViews, this)) 339 .once(jQuery.proxy(this.attachPagerAjax, this)); 340 341 // Add a trigger to update this view specifically. In order to trigger a 342 // refresh use the following code. 343 // 344 // @code 345 // jQuery('.view-name').trigger('RefreshView'); 346 // @endcode 347 // Add a trigger to update this view specifically. 348 var self_settings = this.element_settings; 349 self_settings.event = 'RefreshView'; 350 this.refreshViewAjax = new Drupal.ajax(this.selector, this.$view, self_settings); 351 }; 352 353 Drupal.views.ajaxView.prototype.attachExposedFormAjax = function() { 354 var button = $('input[type=submit], button[type=submit], input[type=image]', this.$exposed_form); 355 button = button[0]; 356 357 // Call the autocomplete submit before doing AJAX. 358 $(button).click(function () { 359 if (Drupal.autocompleteSubmit) { 360 Drupal.autocompleteSubmit(); 361 } 362 }); 363 364 this.exposedFormAjax = new Drupal.ajax($(button).attr('id'), button, this.element_settings); 365 }; 366 367 Drupal.views.ajaxView.prototype.filterNestedViews = function() { 368 // If there is at least one parent with a view class, this view 369 // is nested (e.g., an attachment). Bail. 370 return !this.$view.parents('.view').length; 371 }; 372 373 /** 374 * Attach the ajax behavior to each link. 375 */ 376 Drupal.views.ajaxView.prototype.attachPagerAjax = function() { 377 this.$view.find('ul.pager > li > a, th.views-field a, .attachment .views-summary a') 378 .each(jQuery.proxy(this.attachPagerLinkAjax, this)); 379 }; 380 381 /** 382 * Attach the ajax behavior to a singe link. 383 */ 384 Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function(id, link) { 385 var $link = $(link); 386 var viewData = {}; 387 var href = $link.attr('href'); 388 // Construct an object using the settings defaults and then overriding 389 // with data specific to the link. 390 $.extend( 391 viewData, 392 this.settings, 393 Drupal.Views.parseQueryString(href), 394 // Extract argument data from the URL. 395 Drupal.Views.parseViewArgs(href, this.settings.view_base_path) 396 ); 397 398 // For anchor tags, these will go to the target of the anchor rather 399 // than the usual location. 400 $.extend(viewData, Drupal.Views.parseViewArgs(href, this.settings.view_base_path)); 401 402 this.element_settings.submit = viewData; 403 this.pagerAjax = new Drupal.ajax(false, $link, this.element_settings); 404 this.links.push(this.pagerAjax); 405 }; 406 407 Drupal.ajax.prototype.commands.viewsScrollTop = function (ajax, response, status) { 408 // Scroll to the top of the view. This will allow users 409 // to browse newly loaded content after e.g. clicking a pager 410 // link. 411 var offset = $(response.selector).offset(); 412 // We can't guarantee that the scrollable object should be 413 // the body, as the view could be embedded in something 414 // more complex such as a modal popup. Recurse up the DOM 415 // and scroll the first element that has a non-zero top. 416 var scrollTarget = response.selector; 417 while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) { 418 scrollTarget = $(scrollTarget).parent(); 419 } 420 // Only scroll upward. 421 if (offset.top - 10 < $(scrollTarget).scrollTop()) { 422 $(scrollTarget).animate({scrollTop: (offset.top - 10)}, 500); 423 } 424 }; 425 426})(jQuery); 427; 428(function($) { 429 Drupal.behaviors.chosen = { 430 attach: function(context, settings) { 431 settings.chosen = settings.chosen || Drupal.settings.chosen; 432 433 // Prepare selector and add unwantend selectors. 434 var selector = settings.chosen.selector; 435 436 // Function to prepare all the options together for the chosen() call. 437 var getElementOptions = function (element) { 438 var options = $.extend({}, settings.chosen.options); 439 440 // The width default option is considered the minimum width, so this 441 // must be evaluated for every option. 442 if (settings.chosen.minimum_width > 0) { 443 if ($(element).width() < settings.chosen.minimum_width) { 444 options.width = settings.chosen.minimum_width + 'px'; 445 } 446 else { 447 options.width = $(element).width() + 'px'; 448 } 449 } 450 451 // Some field widgets have cardinality, so we must respect that. 452 // @see chosen_pre_render_select() 453 if ($(element).attr('multiple') && $(element).data('cardinality')) { 454 options.max_selected_options = $(element).data('cardinality'); 455 } 456 457 return options; 458 }; 459 460 // Process elements that have opted-in for Chosen. 461 // @todo Remove support for the deprecated chosen-widget class. 462 $('select.chosen-enable, select.chosen-widget', context).once('chosen', function() { 463 options = getElementOptions(this); 464 $(this).chosen(options); 465 }); 466 467 $(selector, context) 468 // Disabled on: 469 // - Field UI 470 // - WYSIWYG elements 471 // - Tabledrag weights 472 // - Elements that have opted-out of Chosen 473 // - Elements already processed by Chosen 474 .not('#field-ui-field-overview-form select, #field-ui-display-overview-form select, .wysiwyg, .draggable select[name$="[weight]"], .draggable select[name$="[position]"], .chosen-disable, .chosen-processed') 475 .filter(function() { 476 // Filter out select widgets that do not meet the minimum number of 477 // options. 478 var minOptions = $(this).attr('multiple') ? settings.chosen.minimum_multiple : settings.chosen.minimum_single; 479 if (!minOptions) { 480 // Zero value means no minimum. 481 return true; 482 } 483 else { 484 return $(this).find('option').length >= minOptions; 485 } 486 }) 487 .once('chosen', function() { 488 options = getElementOptions(this); 489 $(this).chosen(options); 490 }); 491 } 492 }; 493})(jQuery); 494; 495/** 496* hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+ 497* <http://cherne.net/brian/resources/jquery.hoverIntent.html> 498* 499* @param f onMouseOver function || An object with configuration options 500* @param g onMouseOut function || Nothing (use configuration options object) 501* @author Brian Cherne brian(at)cherne(dot)net 502*/ 503(function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))<cfg.sensitivity){$(ob).unbind("mousemove",track);ob.hoverIntent_s=1;return cfg.over.apply(ob,[ev])}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=0;return cfg.out.apply(ob,[ev])};var handleHover=function(e){var ev=jQuery.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t)}if(e.type=="mouseenter"){pX=ev.pageX;pY=ev.pageY;$(ob).bind("mousemove",track);if(ob.hoverIntent_s!=1){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}}else{$(ob).unbind("mousemove",track);if(ob.hoverIntent_s==1){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob)},cfg.timeout)}}};return this.bind('mouseenter',handleHover).bind('mouseleave',handleHover)}})(jQuery);; 504/* 505 * sf-Touchscreen v1.3b - Provides touchscreen compatibility for the jQuery Superfish plugin. 506 * 507 * Developer's note: 508 * Built as a part of the Superfish project for Drupal (http://drupal.org/project/superfish) 509 * Found any bug? have any cool ideas? contact me right away! http://drupal.org/user/619294/contact 510 * 511 * jQuery version: 1.3.x or higher. 512 * 513 * Dual licensed under the MIT and GPL licenses: 514 * http://www.opensource.org/licenses/mit-license.php 515 * http://www.gnu.org/licenses/gpl.html 516 */ 517 518(function($){ 519 $.fn.sftouchscreen = function(options){ 520 options = $.extend({ 521 mode: 'inactive', 522 breakpoint: 768, 523 breakpointUnit: 'px', 524 useragent: '', 525 behaviour: 2, 526 disableHover: false 527 }, options); 528 529 function activate(menu){ 530 var eventHandler = (('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) ? ['click touchstart','mouseup touchend'] : ['click','mouseup']; 531 // Select hyperlinks from parent menu items. 532 menu.find('li:has(ul)').children('a,span.nolink').each(function(){ 533 var item = $(this), 534 parent = item.closest('li'); 535 if (options.disableHover){ 536 parent.unbind('mouseenter mouseleave'); 537 } 538 if (options.behaviour == 2){ 539 if (parent.children('a.menuparent,span.nolink.menuparent').length > 0 && parent.children('ul').children('.sf-clone-parent').length == 0){ 540 var 541 // Cloning the hyperlink of the parent menu item. 542 cloneLink = parent.children('a.menuparent,span.nolink.menuparent').clone(), 543 // Wrapping the hyerplinks in <li>. 544 cloneLink = $('<li class="sf-clone-parent" />').html(cloneLink); 545 // Removing unnecessary stuff. 546 cloneLink.find('.sf-sub-indicator').remove(), 547 // Adding a helper class and attaching them to the sub-menus. 548 parent.children('ul').addClass('sf-has-clone-parent').prepend(clone
548Link); 549 } 550 } 551 // No .toggle() here as it's not possible to reset it. 552 item.bind(eventHandler[0], function(event){ 553 // Already clicked? 554 if (item.hasClass('sf-clicked')){ 555 // Depending on the preferred behaviour, either proceed to the URL. 556 if (options.behaviour == 0){ 557 window.location = item.attr('href'); 558 } 559 // or collapse the sub-menu. 560 else if (options.behaviour == 1 || options.behaviour == 2){ 561 event.preventDefault(); 562 item.removeClass('sf-clicked'); 563 parent.hideSuperfishUl().find('a,span.nolink').removeClass('sf-clicked'); 564 } 565 } 566 // Prevent the default action otherwise. 567 else { 568 event.preventDefault(); 569 item.addClass('sf-clicked'); 570 parent.showSuperfishUl().siblings('li:has(ul)').hideSuperfishUl().find('.sf-clicked').removeClass('sf-clicked'); 571 } 572 }); 573 }); 574 575 $(document).bind(eventHandler[1], function(event){ 576 if (menu.not(event.target) && menu.has(event.target).length === 0){ 577 menu.find('.sf-clicked').removeClass('sf-clicked'); 578 menu.find('li:has(ul)').hideSuperfishUl(); 579 } 580 }); 581 } 582 // Return original object to support chaining. 583 // This is not necessary actually because of the way the module uses these plugins. 584 for (var b = 0; b < this.length; b++) { 585 var menu = $(this).eq(b), 586 mode = options.mode; 587 // The rest is crystal clear, isn't it? :) 588 if (mode == 'always_active'){ 589 activate(menu); 590 } 591 else if (mode == 'window_width'){ 592 var breakpoint = (options.breakpointUnit == 'em') ? (options.breakpoint * parseFloat($('body').css('font-size'))) : options.breakpoint, 593 windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, 594 timer; 595 if ((typeof Modernizr.mq === 'function' && Modernizr.mq('(max-width:' + (breakpoint - 1) + 'px)')) || (typeof Modernizr.mq === 'undefined' && windowWidth < breakpoint)){ 596 activate(menu); 597 } 598 $(window).resize(function(){ 599 clearTimeout(timer); 600 timer = setTimeout(function(){ 601 var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 602 if ((typeof Modernizr.mq === 'function' && Modernizr.mq('(max-width:' + (breakpoint - 1) + 'px)')) || (typeof Modernizr.mq === 'undefined' && windowWidth < breakpoint)){ 603 activate(menu); 604 } 605 }, 50); 606 }); 607 } 608 else if (mode == 'useragent_custom'){ 609 if (options.useragent != ''){ 610 var ua = RegExp(options.useragent, 'i'); 611 if (navigator.userAgent.match(ua)){ 612 activate(menu); 613 } 614 } 615 } 616 else if (mode == 'useragent_predefined' && navigator.userAgent.match(/(android|bb\d+|meego)|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i)){ 617 activate(menu); 618 } 619 } 620 return this; 621 } 622})(jQuery);; 623/* 624 * sf-Smallscreen v1.2b - Provides small-screen compatibility for the jQuery Superfish plugin. 625 * 626 * Developer's note: 627 * Built as a part of the Superfish project for Drupal (http://drupal.org/project/superfish) 628 * Found any bug? have any cool ideas? contact me right away! http://drupal.org/user/619294/contact 629 * 630 * jQuery version: 1.3.x or higher. 631 * 632 * Dual licensed under the MIT and GPL licenses: 633 * http://www.opensource.org/licenses/mit-license.php 634 * http://www.gnu.org/licenses/gpl.html 635 */ 636 637(function($){ 638 $.fn.sfsmallscreen = function(options){ 639 options = $.extend({ 640 mode: 'inactive', 641 type: 'accordion', 642 breakpoint: 768, 643 breakpointUnit: 'px', 644 useragent: '', 645 title: '', 646 addSelected: false, 647 menuClasses: false, 648 hyperlinkClasses: false, 649 excludeClass_menu: '', 650 excludeClass_hyperlink: '', 651 includeClass_menu: '', 652 includeClass_hyperlink: '', 653 accordionButton: 1, 654 expandText: 'Expand', 655 collapseText: 'Collapse' 656 }, options); 657 658 // We need to clean up the menu from anything unnecessary. 659 function refine(menu){ 660 var
661 refined = menu.clone(), 662 // Things that should not be in the small-screen menus. 663 rm = refined.find('span.sf-sub-indicator, span.sf-description'), 664 // This is a helper class for those who need to add extra markup that shouldn't exist 665 // in the small-screen versions. 666 rh = refined.find('.sf-smallscreen-remove'), 667 // Mega-menus has to be removed too. 668 mm = refined.find('ul.sf-megamenu'); 669 for (var a = 0; a < rh.length; a++){ 670 rh.eq(a).replaceWith(rh.eq(a).html()); 671 } 672 for (var b = 0; b < rm.length; b++){ 673 rm.eq(b).remove(); 674 } 675 if (mm.length > 0){ 676 mm.removeClass('sf-megamenu'); 677 var ol = refined.find('div.sf-megamenu-column > ol'); 678 for (var o = 0; o < ol.length; o++){ 679 ol.eq(o).replaceWith('<ul>' + ol.eq(o).html() + '</ul>'); 680 } 681 var elements = ['div.sf-megamenu-column','.sf-megamenu-wrapper > ol','li.sf-megamenu-wrapper']; 682 for (var i = 0; i < elements.length; i++){ 683 obj = refined.find(elements[i]); 684 for (var t = 0; t < obj.length; t++){ 685 obj.eq(t).replaceWith(obj.eq(t).html()); 686 } 687 } 688 refined.find('.sf-megamenu-column').removeClass('sf-megamenu-column'); 689 } 690 refined.add(refined.find('*')).css({width:''}); 691 return refined; 692 } 693 694 // Creating <option> elements out of the menu. 695 function toSelect(menu, level){ 696 var 697 items = '', 698 childLI = $(menu).children('li'); 699 for (var a = 0; a < childLI.length; a++){ 700 var list = childLI.eq(a), parent = list.children('a, span'); 701 for (var b = 0; b < parent.length; b++){ 702 var 703 item = parent.eq(b), 704 path = item.is('a') ? item.attr('href') : '', 705 // Class names modification. 706 itemClone = item.clone(), 707 classes = (options.hyperlinkClasses) ? ((options.excludeClass_hyperlink && itemClone.hasClass(options.excludeClass_hyperlink)) ? itemClone.removeClass(options.excludeClass_hyperlink).attr('class') : itemClone.attr('class')) : '', 708 classes = (options.includeClass_hyperlink && !itemClone.hasClass(options.includeClass_hyperlink)) ? ((options.hyperlinkClasses) ? itemClone.addClass(options.includeClass_hyperlink).attr('class') : options.includeClass_hyperlink) : classes; 709 // Retaining the active class if requested. 710 if (options.addSelected && item.hasClass('active')){ 711 classes += ' active'; 712 } 713 // <option> has to be disabled if the item is not a link. 714 disable = item.is('span') || item.attr('href')=='#' ? ' disabled="disabled"' : '', 715 // Crystal clear. 716 subIndicator = 1 < level ? Array(level).join('-') + ' ' : ''; 717 // Preparing the <option> element. 718 items += '<option value="' + path + '" class="' + classes + '"' + disable + '>' + subIndicator + $.trim(item.text()) +'</option>', 719 childUL = list.find('> ul'); 720 // Using the function for the sub-menu of this item. 721 for (var u = 0; u < childUL.length; u++){ 722 items += toSelect(childUL.eq(u), level + 1); 723 } 724 } 725 } 726 return items; 727 } 728 729 // Create the new version, hide the original. 730 function convert(menu){ 731 var menuID = menu.attr('id'), 732 // Creating a refined version of the menu. 733 refinedMenu = refine(menu); 734 // Currently the plugin provides two reactions to small screens. 735 // Converting the menu to a <select>
735 element, and converting to an accordion version of the menu. 736 if (options.type == 'accordion'){ 737 var 738 toggleID = menuID + '-toggle', 739 accordionID = menuID + '-accordion'; 740 // Making sure the accordion does not exist. 741 if ($('#' + accordionID).length == 0){ 742 var 743 // Getting the style class. 744 styleClass = menu.attr('class').split(' ').filter(function(item){ 745 return item.indexOf('sf-style-') > -1 ? item : ''; 746 }), 747 // Creating the accordion. 748 accordion = $(refinedMenu).attr('id', accordionID); 749 // Removing unnecessary classes. 750 accordion.removeClass('sf-horizontal sf-vertical sf-navbar sf-shadow sf-js-enabled'); 751 // Adding necessary classes. 752 accordion.addClass('sf-accordion sf-hidden'); 753 // Removing style attributes and any unnecessary class. 754 accordion.children('li').removeAttr('style').removeClass('sfHover'); 755 // Doing the same and making sure all the sub-menus are off-screen (hidden). 756 accordion.find('ul').removeAttr('style').not('.sf-hidden').addClass('sf-hidden'); 757 // Creating the accordion toggle switch. 758 var toggle = '<div class="sf-accordion-toggle ' + styleClass + '"><a href="#" id="' + toggleID + '"><span>' + options.title + '</span></a></div>'; 759 760 // Adding Expand\Collapse buttons if requested. 761 if (options.accordionButton == 2){ 762 var parent = accordion.find('li.menuparent'); 763 for (var i = 0; i < parent.length; i++){ 764 parent.eq(i).prepend('<a href="#" class="sf-accordion-button">' + options.expandText + '</a>'); 765 } 766 } 767 // Inserting the according and hiding the original menu. 768 menu.before(toggle).before(accordion).hide(); 769 770 var 771 accordionElement = $('#' + accordionID), 772 // Deciding what should be used as accordion buttons. 773 buttonElement = (options.accordionButton < 2) ? 'a.menuparent,span.nolink.menuparent' : 'a.sf-accordion-button', 774 button = accordionElement.find(buttonElement); 775 776 // Attaching a click event to the toggle switch. 777 $('#' + toggleID).bind('click', function(e){ 778 // Preventing the click. 779 e.preventDefault(); 780 // Adding the sf-expanded class. 781 $(this).toggleClass('sf-expanded'); 782 783 if (accordionElement.hasClass('sf-expanded')){ 784 // If the accordion is already expanded: 785 // Hiding its expanded sub-menus and then the accordion itself as well. 786 accordionElement.add(accordionElement.find('li.sf-expanded')).removeClass('sf-expanded') 787 .end().find('ul').hide() 788 // This is a bit tricky, it's the same trick that has been in use in the main plugin for sometime. 789 // Basically we'll add a class that keeps the sub-menu off-screen and still visible, 790 // and make it invisible and removing the class one moment before showing or hiding it. 791 // This helps screen reader software access all the menu items. 792 .end().hide().addClass('sf-hidden').show(); 793 // Changing the caption of any existing accordion buttons to 'Expand'. 794 if (options.accordionButton == 2){ 795 accordionElement.find('a.sf-accordion-button').text(options.expandText); 796 } 797 } 798 else { 799 // But if it's collapsed, 800 accordionElement.addClass('sf-expanded').hide().removeClass('sf-hidden').show(); 801 } 802 }); 803 804 // Attaching a click event to the buttons. 805 button.bind('click', function(e){ 806 // Making sure the buttons does not exist already. 807 if ($(this).closest('li').children('ul').length > 0){ 808 e.preventDefault(); 809 // Selecting the parent menu items. 810 var parent = $(this).closest('li'); 811 // Creating and inserting Expand\Collapse buttons to the parent menu items, 812 // of course only if not already happened.
813 if (options.accordionButton == 1 && parent.children('a.menuparent,span.nolink.menuparent').length > 0 && parent.children('ul').children('li.sf-clone-parent').length == 0){ 814 var 815 // Cloning the hyperlink of the parent menu item. 816 cloneLink = parent.children('a.menuparent,span.nolink.menuparent').clone(), 817 // Wrapping the hyerplinks in <li>. 818 cloneLink = $('<li class="sf-clone-parent" />').html(cloneLink); 819 // Adding a helper class and attaching them to the sub-menus. 820 parent.children('ul').addClass('sf-has-clone-parent').prepend(cloneLink); 821 } 822 // Once the button is clicked, collapse the sub-menu if it's expanded. 823 if (parent.hasClass('sf-expanded')){ 824 parent.children('ul').slideUp('fast', function(){ 825 // Doing the accessibility trick after hiding the sub-menu. 826 $(this).closest('li').removeClass('sf-expanded').end().addClass('sf-hidden').show(); 827 }); 828 // Changing the caption of the inserted Collapse link to 'Expand', if any is inserted. 829 if (options.accordionButton == 2 && parent.children('.sf-accordion-button').length > 0){ 830 parent.children('.sf-accordion-button').text(options.expandText); 831 } 832 } 833 // Otherwise, expand the sub-menu. 834 else { 835 // Doing the accessibility trick and then showing the sub-menu. 836 parent.children('ul').hide().removeClass('sf-hidden').slideDown('fast') 837 // Changing the caption of the inserted Expand link to 'Collape', if any is inserted. 838 .end().addClass('sf-expanded').children('a.sf-accordion-button').text(options.collapseText) 839 // Hiding any expanded sub-menu of the same level. 840 .end().siblings('li.sf-expanded').children('ul') 841 .slideUp('fast', function(){ 842 // Doing the accessibility trick after hiding it. 843 $(this).closest('li').removeClass('sf-expanded').end().addClass('sf-hidden').show(); 844 }) 845 // Assuming Expand\Collapse buttons do exist, resetting captions, in those hidden sub-menus. 846 .parent().children('a.sf-accordion-button').text(options.expandText); 847 } 848 } 849 }); 850 } 851 } 852 else { 853 var 854 // Class names modification. 855 menuClone = menu.clone(), classes = (options.menuClasses) ? ((options.excludeClass_menu && menuClone.hasClass(options.excludeClass_menu)) ? menuClone.removeClass(options.excludeClass_menu).attr('class') : menuClone.attr('class')) : '', 856 classes = (options.includeClass_menu && !menuClone.hasClass(options.includeClass_menu)) ? ((options.menuClasses) ? menuClone.addClass(options.includeClass_menu).attr('class') : options.includeClass_menu) : classes, 857 classes = (classes) ? ' class="' + classes + '"' : ''; 858 859 // Making sure the <select> element does not exist already. 860 if ($('#' + menuID + '-select').length == 0){ 861 // Creating the <option> elements. 862 var newMenu = toSelect(refinedMenu, 1), 863 // Creating the <select> element and assigning an ID and class name. 864 selectList = $('<select class="' + classes + '" id="' + menuID + '-select"/>') 865 // Attaching the title and the items to the <select> element. 866 .html('<option>' + options.title + '</option>' + newMenu) 867 // Attaching an event then. 868 .change(function(){ 869 // Except for the first option that is the menu title and not a real menu item. 870 if ($('option:selected', this).index()){ 871 window.location = selectList.val(); 872 } 873 }); 874 // Applying the addSelected option to it. 875 if (options.addSelected){ 876 selectList.find('.active').attr('selected', !0); 877 } 878 // Finally inserting the <select> element into the document then hiding the original menu. 879 menu.before(selectList).hide(); 880 } 881 } 882 } 883 884 // Turn everything back to normal. 885 function turnBack(menu){ 886 var 887 id = '#' + menu.attr('id'); 888 // Removing the small screen version. 889 $(id + '-' + options.type).remove(); 890 // Removing the accordion toggle switch as well. 891 if (options.type == 'accordion'){ 892 $(id + '-toggle').parent('div').remove(); 893 } 894 // Crystal clear! 895 $(id).show(); 896 } 897
898 // Return original object to support chaining. 899 // Although this is unnecessary because of the way the module uses these plugins. 900 for (var s = 0; s < this.length; s++){ 901 var 902 menu = $(this).eq(s), 903 mode = options.mode; 904 // The rest is crystal clear, isn't it? :) 905 if (mode == 'always_active'){ 906 convert(menu); 907 } 908 else if (mode == 'window_width'){ 909 var breakpoint = (options.breakpointUnit == 'em') ? (options.breakpoint * parseFloat($('body').css('font-size'))) : options.breakpoint, 910 windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, 911 timer; 912 if ((typeof Modernizr.mq === 'function' && Modernizr.mq('(max-width:' + (breakpoint - 1) + 'px)')) || (typeof Modernizr.mq === 'undefined' && windowWidth < breakpoint)){ 913 convert(menu); 914 } 915 $(window).resize(function(){ 916 clearTimeout(timer); 917 timer = setTimeout(function(){ 918 var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 919 if ((typeof Modernizr.mq === 'function' && Modernizr.mq('(max-width:' + (breakpoint - 1) + 'px)')) || (typeof Modernizr.mq === 'undefined' && windowWidth < breakpoint)){ 920 convert(menu); 921 } 922 else { 923 turnBack(menu); 924 } 925 }, 50); 926 }); 927 } 928 else if (mode == 'useragent_custom'){ 929 if (options.useragent != ''){ 930 var ua = RegExp(options.useragent, 'i'); 931 if (navigator.userAgent.match(ua)){ 932 convert(menu); 933 } 934 } 935 } 936 else if (mode == 'useragent_predefined' && navigator.userAgent.match(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i)){ 937 convert(menu); 938 } 939 } 940 return this; 941 } 942})(jQuery); 943; 944/* 945 * Supposition v0.2 - an optional enhancer for Superfish jQuery menu widget. 946 * 947 * Copyright (c) 2008 Joel Birch - based mostly on work by Jesse Klaasse and credit goes largely to him. 948 * Special thanks to Karl Swedberg for valuable input. 949 * 950 * Dual licensed under the MIT and GPL licenses: 951 * http://www.opensource.org/licenses/mit-license.php 952 * http://www.gnu.org/licenses/gpl.html 953 */ 954/* 955 * This is not the original jQuery Supposition plugin. 956 * Please refer to the README for more information. 957 */ 958 959(function($){ 960 $.fn.supposition = function(){ 961 var $w = $(window), /*do this once instead of every onBeforeShow call*/ 962 _offset = function(dir) { 963 return window[dir == 'y' ? 'pageYOffset' : 'pageXOffset'] 964 || document.documentElement && document.documentElement[dir=='y' ? 'scrollTop' : 'scrollLeft'] 965 || document.body[dir=='y' ? 'scrollTop' : 'scrollLeft']; 966 }, 967 onHide = function(){ 968 this.css({bottom:''}); 969 }, 970 onBeforeShow = function(){ 971 this.each(function(){ 972 var $u = $(this); 973 $u.css('display','block'); 974 var $mul = $u.closest('.sf-menu'), 975 level = $u.parents('ul').length, 976 menuWidth = $u.width(), 977 menuParentWidth = $u.closest('li').outerWidth(true), 978 menuParentLeft = $u.closest('li').offset().left, 979 totalRight = $w.width() + _offset('x'), 980 menuRight = $u.offset().left + menuWidth, 981 exactMenuWidth = (menuRight > (menuParentWidth + menuParentLeft)) ? menuWidth - (menuRight - (menuParentWidth + menuParentLeft)) : menuWidth; 982 if ($u.parents('.sf-js-enabled').hasClass('rtl')) { 983 if (menuParentLeft < exactMenuWidth) { 984 if (($mul.hasClass('sf-horizontal') && level == 1) || ($mul.hasClass('sf-navbar') && level == 2)){ 985 $u.css({left:0,right:'auto'}); 986 } 987 else { 988 $u.css({left:menuParentWidth + 'px',right:'auto'}); 989 } 990 } 991 } 992 else { 993 if (menuRight > totalRight && menuParentLeft > menuWidth) { 994 if (($mul.hasClass('sf-horizontal') && level == 1) || ($mul.hasClass('sf-navbar') && level == 2)){ 995 $u.css({right:0,left:'auto'}); 996 } 997 else { 998 $u.css({right:menuParentWidth + 'px',left:'auto'}); 999 } 1000 } 1001 } 1002 var windowHeight = $w.height(), 1003 offsetTop = $u.offset().top, 1004 menuParentShadow = ($mul.hasClass('sf-shadow') && $u.css('padding-bottom').length > 0) ? parseInt($u.css('padding-bottom').slice(0,-2)) : 0, 1005 menuParentHeight = ($mul.hasClass('sf-vertical')) ? '-' + menuParentShadow : $u.parent().outerHeight(true) - menuParentShadow, 1006 menuHeight = $u.height(), 1007 baseline = windowHeight + _offset('y'); 1008 var expandUp = ((offsetTop + menuHeight > baseline) && (offsetTop > menuHeight)); 1009 if (expandUp) { 1010 $u.css({bottom:menuParentHeight + 'px',top:'auto'}); 1011 } 1012 $u.css('display','none'); 1013 }); 1014 }; 1015 1016 return this.each(function() { 1017 var o = $.fn.superfish.o[this.serial]; /* get this menu's options */ 1018 1019 /* if callbacks already set, store them */ 1020 var _onBeforeShow = o.onBeforeShow, 1021 _onHide = o.onHide; 1022 1023 $.extend($.fn.superfish.o[this.serial],{ 1024 onBeforeShow: function() { 1025 onBeforeShow.call(this); /* fire our Supposition callback */ 1026 _onBeforeShow.call(this); /* fire stored callbacks */ 1027 }, 1028 onHide: function() { 1029 onHide.call(this); /* fire our Supposition callback */ 1030 _onHide.call(this); /* fire stored callbacks */ 1031 } 1032 }); 1033 }); 1034 }; 1035})(jQuery);; 1036/* 1037 * Superfish v1.4.8 - jQuery menu widget 1038 * Copyright (c) 2008 Joel Birch 1039 * 1040 * Dual licensed under the MIT and GPL licenses: 1041 * http://www.opensource.org/licenses/mit-license.php 1042 * http://www.gnu.org/licenses/gpl.html 1043 * 1044 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt 1045 */ 1046/* 1047 * This is not the original jQuery Superfish plugin. 1048 * Please refer to the README for more information. 1049 */ 1050 1051(function($){ 1052 $.fn.superfish = function(op){ 1053 var sf = $.fn.superfish, 1054 c = sf.c, 1055 $arrow = $(['<span class="',c.arrowClass,'"> »</span>'].join('')), 1056 over = function(){ 1057 var $$ = $(this), menu = getMenu($$); 1058 clearTimeout(menu.sfTimer); 1059 $$.showSuperfishUl().siblings().hideSuperfishUl(); 1060 }, 1061 out = function(){ 1062 var $$ = $(this), menu = getMenu($$), o = sf.op; 1063 clearTimeout(menu.sfTimer); 1064 menu.sfTimer=setTimeout(function(){ 1065 if ($$.children('.sf-clicked').length == 0){ 1066 o.retainPath=($.inArray($$[0],o.$path)>-1);
1067 $$.hideSuperfishUl(); 1068 if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);} 1069 } 1070 },o.delay); 1071 }, 1072 getMenu = function($menu){ 1073 var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0]; 1074 sf.op = sf.o[menu.serial]; 1075 return menu; 1076 }, 1077 addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); }; 1078 1079 return this.each(function() { 1080 var s = this.serial = sf.o.length; 1081 var o = $.extend({},sf.defaults,op); 1082 o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels), 1083 p = o.$path; 1084 for (var l = 0; l < p.length; l++){ 1085 p.eq(l).addClass([o.hoverClass,c.bcClass].join(' ')).filter('li:has(ul)').removeClass(o.pathClass); 1086 } 1087 sf.o[s] = sf.op = o; 1088 1089 $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() { 1090 if (o.autoArrows) addArrow( $(this).children('a:first-child, span.nolink:first-child') ); 1091 }) 1092 .not('.'+c.bcClass) 1093 .hideSuperfishUl(); 1094 1095 var $a = $('a, span.nolink',this); 1096 $a.each(function(i){ 1097 var $li = $a.eq(i).parents('li'); 1098 $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);}); 1099 }); 1100 o.onInit.call(this); 1101 1102 }).each(function() { 1103 var menuClasses = [c.menuClass], 1104 addShadow = true; 1105 if ($.browser !== undefined){ 1106 if ($.browser.msie && $.browser.version < 7){ 1107 addShadow = false; 1108 } 1109 } 1110 if (sf.op.dropShadows && addShadow){ 1111 menuClasses.push(c.shadowClass); 1112 } 1113 $(this).addClass(menuClasses.join(' ')); 1114 }); 1115 }; 1116 1117 var sf = $.fn.superfish; 1118 sf.o = []; 1119 sf.op = {}; 1120 sf.IE7fix = function(){ 1121 var o = sf.op; 1122 if ($.browser !== undefined){ 1123 if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity != undefined) { 1124 this.toggleClass(sf.c.shadowClass+'-off'); 1125 } 1126 } 1127 }; 1128 sf.c = { 1129 bcClass: 'sf-breadcrumb', 1130 menuClass: 'sf-js-enabled', 1131 anchorClass: 'sf-with-ul', 1132 arrowClass: 'sf-sub-indicator', 1133 shadowClass: 'sf-shadow' 1134 }; 1135 sf.defaults = { 1136 hoverClass: 'sfHover', 1137 pathClass: 'overideThisToUse', 1138 pathLevels: 1, 1139 delay: 800, 1140 animation: {opacity:'show'}, 1141 speed: 'fast', 1142 autoArrows: true, 1143 dropShadows: true, 1144 disableHI: false, // true disables hoverIntent detection 1145 onInit: function(){}, // callback functions 1146 onBeforeShow: function(){}, 1147 onShow: function(){}, 1148 onHide: function(){} 1149 }; 1150 $.fn.extend({ 1151 hideSuperfishUl : function(){ 1152 var o = sf.op, 1153 not = (o.retainPath===true) ? o.$path : ''; 1154 o.retainPath = false; 1155 var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass) 1156 .children('ul').addClass('sf-hidden'); 1157 o.onHide.call($ul); 1158 return this; 1159 }, 1160 showSuperfishUl : function(){ 1161 var o = sf.op, 1162 sh = sf.c.shadowClass+'-off', 1163 $ul = this.addClass(o.hoverClass) 1164 .children('ul.sf-hidden').hide().removeClass('sf-hidden'); 1165 sf.IE7fix.call($ul); 1166 o.onBeforeShow.call($ul); 1167 $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); }); 1168 return this; 1169 } 1170 }); 1171})(jQuery);; 1172/* 1173 * Supersubs v0.4b - jQuery plugin 1174 * Copyright (c) 2013 Joel Birch 1175 * 1176 * Dual licensed under the MIT and GPL licenses: 1177 * http://www.opensource.org/licenses/mit-license.php 1178 * http://www.gnu.org/licenses/gpl.html 1179 * 1180 * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of 1181 * their longest list item children. If you use this, please expect bugs and report them 1182 * to the jQuery Google Group with the word 'Superfish' in the subject line. 1183 * 1184 */ 1185/* 1186 * This is not the original jQuery Supersubs plugin. 1187 * Please refer to the README for more information. 1188 */ 1189 1190(function($){ // $ will refer to jQuery within this closure 1191 $.fn.supersubs = function(options){ 1192 var opts = $.extend({}, $.fn.supersubs.defaults, options);
1193 // return original object to support chaining 1194 // Although this is unnecessary due to the way the module uses these plugins. 1195 for (var a = 0; a < this.length; a++) { 1196 // cache selections 1197 var $$ = $(this).eq(a), 1198 // support metadata 1199 o = $.meta ? $.extend({}, opts, $$.data()) : opts; 1200 // Jump one level if it's a "NavBar" 1201 if ($$.hasClass('sf-navbar')) { 1202 $$ = $$.children('li').children('ul'); 1203 } 1204 // cache all ul elements 1205 var $ULs = $$.find('ul'), 1206 // get the font size of menu. 1207 // .css('fontSize') returns various results cross-browser, so measure an em dash instead 1208 fontsize = $('<li id="menu-fontsize">—</li>'), 1209 size = fontsize.attr('style','padding:0;position:absolute;top:-99999em;width:auto;') 1210 .appendTo($$)[0].clientWidth; //clientWidth is faster than width() 1211 // remove em dash 1212 fontsize.remove(); 1213 1214 // loop through each ul in menu 1215 for (var b = 0; b < $ULs.length; b++) { 1216 var 1217 // cache this ul 1218 $ul = $ULs.eq(b); 1219 // If a multi-column sub-menu, and only if correctly configured. 1220 if (o.megamenu && $ul.hasClass('sf-megamenu') && $ul.find('.sf-megamenu-column').length > 0){ 1221 // Look through each column. 1222 var $column = $ul.find('div.sf-megamenu-column > ol'), 1223 // Overall width. 1224 mwWidth = 0; 1225 for (var d = 0; d < $column.length; d++){ 1226 resize($column.eq(d)); 1227 // New column width, in pixels. 1228 var colWidth = $column.width(); 1229 // Just a trick to convert em unit to px. 1230 $column.css({width:colWidth}) 1231 // Making column parents the same size. 1232 .parents('.sf-megamenu-column').css({width:colWidth}); 1233 // Overall width. 1234 mwWidth += parseInt(colWidth); 1235 } 1236 // Resizing the columns container too. 1237 $ul.add($ul.find('li.sf-megamenu-wrapper, li.sf-megamenu-wrapper > ol')).css({width:mwWidth}); 1238 } 1239 else { 1240 resize($ul); 1241 } 1242 } 1243 } 1244 function resize($ul){ 1245 var 1246 // get all (li) children of this ul 1247 $LIs = $ul.children(), 1248 // get all anchor grand-children 1249 $As = $LIs.children('a'); 1250 // force content to one line and save current float property 1251 $LIs.css('white-space','nowrap'); 1252 // remove width restrictions and floats so elements remain vertically stacked 1253 $ul.add($LIs).add($As).css({float:'none',width:'auto'}); 1254 // this ul will now be shrink-wrapped to longest li due to position:absolute 1255 // so save its width as ems. 1256 var emWidth = $ul.get(0).clientWidth / size; 1257 // add more width to ensure lines don't turn over at certain sizes in various browsers 1258 emWidth += o.extraWidth; 1259 // restrict to at least minWidth and at most maxWidth 1260 if (emWidth > o.maxWidth) {emWidth = o.maxWidth;} 1261 else if (emWidth < o.minWidth) {emWidth = o.minWidth;} 1262 emWidth += 'em'; 1263 // set ul to width in ems 1264 $ul.css({width:emWidth}); 1265 // restore li floats to avoid IE bugs 1266 // set li width to full width of this ul 1267 // revert white-space to normal 1268 $LIs.add($As).css({float:'',width:'',whiteSpace:''}); 1269 // update offset position of descendant ul to reflect new width of parent. 1270 // set it to 100% in case it isn't already set to this in the CSS 1271 for (var c = 0; c < $LIs.length; c++) { 1272 var $childUl = $LIs.eq(c).children('ul'); 1273 var offsetDirection = $childUl.css('left') !== undefined ? 'left' : 'right'; 1274 $childUl.css(offsetDirection,'100%'); 1275 } 1276 } 1277 return this; 1278 }; 1279 // expose defaults 1280 $.fn.supersubs.defaults = { 1281 megamenu: true, // define width for multi-column sub-menus and their columns. 1282 minWidth: 12, // requires em unit. 1283 maxWidth: 27, // requires em unit. 1284 extraWidth: 1 // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values 1285 }; 1286})(jQuery); // plugin code ends 1287; 1288/** 1289 * @file 1290 * The Superfish Drupal Behavior to apply the Superfish jQuery plugin to lists. 1291 */ 1292 1293(function ($) { 1294 Drupal.behaviors.superfish = { 1295 attach: function (context, settings) { 1296 // Take a look at each list to apply Superfish to. 1297 $.each(settings.superfish || {}, function(index, options) { 1298 // Process all Superfish lists. 1299 $('#superfish-' + options.id, context).once('superfish', function() { 1300 var list = $(this); 1301 1302 // Check if we are to apply the Supersubs plug-in to it. 1303 if (options.plugins || false) { 1304 if (options.plugins.supersubs || false) { 1305 list.supersubs(options.plugins.supersubs); 1306 } 1307 } 1308 1309 // Apply Superfish to the list. 1310 list.superfish(options.sf); 1311 1312 // Check if we are to apply any other plug-in to it. 1313 if (options.plugins || false) { 1314 if (options.plugins.touchscreen || false) { 1315 list.sftouchscreen(options.plugins.touchscreen); 1316 } 1317 if (options.plugins.smallscreen || false) { 1318 list.sfsmallscreen(options.plugins.smallscreen); 1319 } 1320 if (options.plugins.automaticwidth || false) { 1321 list.sfautomaticwidth(); 1322 } 1323 if (options.plugins.supposition || false) { 1324 list.supposition(); 1325 } 1326 if (options.plugins.bgiframe || false) { 1327 list.find('ul').bgIframe({opacity:false}); 1328 } 1329 } 1330 }); 1331 }); 1332 } 1333 }; 1334})(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.