/** * @file * Some basic behaviors and utility functions for Views. */ (function ($) { Drupal.Views = {}; /** * jQuery UI tabs, Views integration component */ Drupal.behaviors.viewsTabs = { attach: function (context) { if ($.viewsUi && $.viewsUi.tabs) { $('#views-tabset').once('views-processed').viewsTabs({ selectedClass: 'active' }); } $('a.views-remove-link').once('views-processed').click(function(event) { var id = $(this).attr('id').replace('views-remove-link-', ''); $('#views-row-' + id).hide(); $('#views-removed-' + id).attr('checked', true); event.preventDefault(); }); /** * Here is to handle display deletion * (checking in the hidden checkbox and hiding out the row) */ $('a.display-remove-link') .addClass('display-processed') .click(function() { var id = $(this).attr('id').replace('display-remove-link-', ''); $('#display-row-' + id).hide(); $('#display-removed-' + id).attr('checked', true); return false; }); } }; /** * Helper function to parse a querystring. */ Drupal.Views.parseQueryString = function (query) { var args = {}; var pos = query.indexOf('?'); if (pos != -1) { query = query.substring(pos + 1); } var pairs = query.split('&'); for(var i in pairs) { if (typeof(pairs[i]) == 'string') { var pair = pairs[i].split('='); // Ignore the 'q' path argument, if present. if (pair[0] != 'q' && pair[1]) { args[decodeURIComponent(pair[0].replace(/\+/g, ' '))] = decodeURIComponent(pair[1].replace(/\+/g, ' ')); } } } return args; }; /** * Helper function to return a view's arguments based on a path. */ Drupal.Views.parseViewArgs = function (href, viewPath) { var returnObj = {}; var path = Drupal.Views.getPath(href); // Ensure we have a correct path. if (viewPath && path.substring(0, viewPath.length + 1) == viewPath + '/') { var args = decodeURIComponent(path.substring(viewPath.length + 1, path.length)); returnObj.view_args = args; returnObj.view_path = path; } return returnObj; }; /** * Strip off the protocol plus domain from an href. */ Drupal.Views.pathPortion = function (href) { // Remove e.g. http://example.com if present. var protocol = window.location.protocol; if (href.substring(0, protocol.length) == protocol) { // 2 is the length of the '//' that normally follows the protocol href = href.substring(href.indexOf('/', protocol.length + 2)); } return href; }; /** * Return the Drupal path portion of an href. */ Drupal.Views.getPath = function (href) { href = Drupal.Views.pathPortion(href); href = href.substring(Drupal.settings.basePath.length, href.length); // 3 is the length of the '?q=' added to the url without clean urls. if (href.substring(0, 3) == '?q=') { href = href.substring(3, href.length); } var chars = ['#', '?', '&']; for (i in chars) { if (href.indexOf(chars[i]) > -1) { href = href.substr(0, href.indexOf(chars[i])); } } return href; }; })(jQuery); ; /** * @file * Handles AJAX fetching of views, including filter submission and response. */ (function ($) { /** * Attaches the AJAX behavior to Views exposed filter forms and key View links. */ Drupal.behaviors.ViewsAjaxView = {}; Drupal.behaviors.ViewsAjaxView.attach = function() { if (Drupal.settings && Drupal.settings.views && Drupal.settings.views.ajaxViews) { $.each(Drupal.settings.views.ajaxViews, function(i, settings) { Drupal.views.instances[i] = new Drupal.views.ajaxView(settings); }); } }; Drupal.views = {}; Drupal.views.instances = {}; /** * Javascript object for a certain view. */ Drupal.views.ajaxView = function(settings) { var selector = '.view-dom-id-' + settings.view_dom_id; this.$view = $(selector); // Retrieve the path to use for views' ajax. var ajax_path = Drupal.settings.views.ajax_path; // If there are multiple views this might've ended up showing up multiple times. if (ajax_path.constructor.toString().indexOf("Array") != -1) { ajax_path = ajax_path[0]; } // Check if there are any GET parameters to send to views. var queryString = window.location.search || ''; if (queryString !== '') { // Remove the question mark and Drupal path component if any. var queryString = queryString.slice(1).replace(/q=[^&]+&?|&?render=[^&]+/, ''); if (queryString !== '') { // If there is a '?' in ajax_path, clean url are on and & should be used to add parameters. queryString = ((/\?/.test(ajax_path)) ? '&' : '?') + queryString; } } this.element_settings = { url: ajax_path + queryString, submit: settings, setClick: true, event: 'click', selector: selector, progress: { type: 'throbber' } }; this.settings = settings; // Add the ajax to exposed forms. this.$exposed_form = $('#views-exposed-form-'+ settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-')); this.$exposed_form.once(jQuery.proxy(this.attachExposedFormAjax, this)); // Add the ajax to pagers. this.$view // Don't attach to nested views. Doing so would attach multiple behaviors // to a given element. .filter(jQuery.proxy(this.filterNestedViews, this)) .once(jQuery.proxy(this.attachPagerAjax, this)); // Add a trigger to update this view specifically. In order to trigger a // refresh use the following code. // // @code // jQuery('.view-name').trigger('RefreshView'); // @endcode // Add a trigger to update this view specifically. var self_settings = this.element_settings; self_settings.event = 'RefreshView'; this.refreshViewAjax = new Drupal.ajax(this.selector, this.$view, self_settings); }; Drupal.views.ajaxView.prototype.attachExposedFormAjax = function() { var button = $('input[type=submit], button[type=submit], input[type=image]', this.$exposed_form); button = button[0]; this.exposedFormAjax = new Drupal.ajax($(button).attr('id'), button, this.element_settings); }; Drupal.views.ajaxView.prototype.filterNestedViews= function() { // If there is at least one parent with a view class, this view // is nested (e.g., an attachment). Bail. return !this.$view.parents('.view').size(); }; /** * Attach the ajax behavior to each link. */ Drupal.views.ajaxView.prototype.attachPagerAjax = function() { this.$view.find('ul.pager > li > a, th.views-field a, .attachment .views-summary a') .each(jQuery.proxy(this.attachPagerLinkAjax, this)); }; /** * Attach the ajax behavior to a singe link. */ Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function(id, link) { var $link = $(link); var viewData = {}; var href = $link.attr('href'); // Construct an object using the settings defaults and then overriding // with data specific to the link. $.extend( viewData, this.settings, Drupal.Views.parseQueryString(href), // Extract argument data from the URL. Drupal.Views.parseViewArgs(href, this.settings.view_base_path) ); // For anchor tags, these will go to the target of the anchor rather // than the usual location. $.extend(viewData, Drupal.Views.parseViewArgs(href, this.settings.view_base_path)); this.element_settings.submit = viewData; this.pagerAjax = new Drupal.ajax(false, $link, this.element_settings); }; Drupal.ajax.prototype.commands.viewsScrollTop = function (ajax, response, status) { // Scroll to the top of the view. This will allow users // to browse newly loaded content after e.g. clicking a pager // link. var offset = $(response.selector).offset(); // We can't guarantee that the scrollable object should be // the body, as the view could be embedded in something // more complex such as a modal popup. Recurse up the DOM // and scroll the first element that has a non-zero top. var scrollTarget = response.selector; while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) { scrollTarget = $(scrollTarget).parent(); } // Only scroll upward if (offset.top - 10 < $(scrollTarget).scrollTop()) { $(scrollTarget).animate({scrollTop: (offset.top - 10)}, 500); } }; })(jQuery); ; Drupal.TBMegaMenu = Drupal.TBMegaMenu || {}; (function ($) { Drupal.TBMegaMenu.oldWindowWidth = 0; Drupal.TBMegaMenu.displayedMenuMobile = false; Drupal.TBMegaMenu.supportedScreens = [980]; Drupal.TBMegaMenu.menuResponsive = function () { var windowWidth = window.innerWidth ? window.innerWidth : $(window).width(); var navCollapse = $('.tb-megamenu').children('.nav-collapse'); if (windowWidth < Drupal.TBMegaMenu.supportedScreens[0]) { navCollapse.addClass('collapse'); if (Drupal.TBMegaMenu.displayedMenuMobile) { navCollapse.css({height: 'auto', overflow: 'visible'}); } else { navCollapse.css({height: 0, overflow: 'hidden'}); } } else { // If width of window is greater than 980 (supported screen). navCollapse.removeClass('collapse'); if (navCollapse.height() <= 0) { navCollapse.css({height: 'auto', overflow: 'visible'}); } } }; Drupal.behaviors.tbMegaMenuAction = { attach: function(context) { $('.tb-megamenu-button', context).once('menuIstance', function () { var This = this; $(This).click(function() { if(parseInt($(this).parent().children('.nav-collapse').height())) { $(this).parent().children('.nav-collapse').css({height: 0, overflow: 'hidden'}); Drupal.TBMegaMenu.displayedMenuMobile = false; } else { $(this).parent().children('.nav-collapse').css({height: 'auto', overflow: 'visible'}); Drupal.TBMegaMenu.displayedMenuMobile = true; } }); }); var isTouch = 'ontouchstart' in window && !(/hp-tablet/gi).test(navigator.appVersion); if(!isTouch){ $(document).ready(function($){ var mm_duration = 0; $('.tb-megamenu').each (function(){ if ($(this).data('duration')) { mm_duration = $(this).data('duration'); } }); var mm_timeout = mm_duration ? 100 + mm_duration : 500; $('.nav > li, li.mega').hover(function(event) { var $this = $(this); if ($this.hasClass ('mega')) { $this.addClass ('animating'); clearTimeout ($this.data('animatingTimeout')); $this.data('animatingTimeout', setTimeout(function(){$this.removeClass ('animating')}, mm_timeout)); clearTimeout ($this.data('hoverTimeout')); $this.data('hoverTimeout', setTimeout(function(){$this.addClass ('open')}, 100)); } else { clearTimeout ($this.data('hoverTimeout')); $this.data('hoverTimeout', setTimeout(function(){$this.addClass ('open')}, 100)); } }, function(event) { var $this = $(this); if ($this.hasClass ('mega')) { $this.addClass ('animating'); clearTimeout ($this.data('animatingTimeout')); $this.data('animatingTimeout', setTimeout(function(){$this.removeClass ('animating')}, mm_timeout)); clearTimeout ($this.data('hoverTimeout')); $this.data('hoverTimeout', setTimeout(function(){$this.removeClass ('open')}, 100)); } else { clearTimeout ($this.data('hoverTimeout')); $this.data('hoverTimeout', setTimeout(function(){$this.removeClass ('open')}, 100)); } }); }); } $(window).resize(function() { var windowWidth = window.innerWidth ? window.innerWidth : $(window).width(); if(windowWidth != Drupal.TBMegaMenu.oldWindowWidth){ Drupal.TBMegaMenu.oldWindowWidth = windowWidth; Drupal.TBMegaMenu.menuResponsive(); } }); }, } })(jQuery); ; Drupal.TBMegaMenu = Drupal.TBMegaMenu || {}; (function ($) { Drupal.TBMegaMenu.createTouchMenu = function(items) { items.children('a').each( function() { var $item = $(this); var tbitem = $(this).parent(); $item.click( function(event){ if ($item.hasClass('tb-megamenu-clicked')) { var $uri = $item.attr('href'); window.location.href = $uri; } else { event.preventDefault(); $item.addClass('tb-megamenu-clicked'); if(!tbitem.hasClass('open')){ tbitem.addClass('open'); } } }).closest('li').mouseleave( function(){ $item.removeClass('tb-megamenu-clicked'); tbitem.removeClass('open'); }); }); /* items.children('a').children('span.caret').each( function() { var $item = $(this).parent(); $item.click(function(event){ tbitem = $item.parent(); if ($item.hasClass('tb-megamenu-clicked')) { Drupal.TBMegaMenu.eventStopPropagation(event); if(tbitem.hasClass('open')){ tbitem.removeClass('open'); $item.removeClass('tb-megamenu-clicked'); } } else { Drupal.TBMegaMenu.eventStopPropagation(event); $item.addClass('tb-megamenu-clicked'); if(!tbitem.hasClass('open')){ tbitem.addClass('open'); $item.removeClass('tb-megamenu-clicked'); } } }); }); */ } Drupal.TBMegaMenu.eventStopPropagation = function(event) { if (event.stopPropagation) { event.stopPropagation(); } else if (window.event) { window.event.cancelBubble = true; } } Drupal.behaviors.tbMegaMenuTouchAction = { attach: function(context) { var isTouch = 'ontouchstart' in window && !(/hp-tablet/gi).test(navigator.appVersion); if(isTouch){ $('html').addClass('touch'); Drupal.TBMegaMenu.createTouchMenu($('.tb-megamenu ul.nav li.mega').has('.dropdown-menu')); } } } })(jQuery); ; (function ($) { Drupal.settings.views = Drupal.settings.views || {'ajax_path': '/views/ajax'}; Drupal.quicktabs = Drupal.quicktabs || {}; Drupal.quicktabs.getQTName = function (el) { return el.id.substring(el.id.indexOf('-') +1); } Drupal.behaviors.quicktabs = { attach: function (context, settings) { $.extend(true, Drupal.settings, settings); $('.quicktabs-wrapper', context).once(function(){ Drupal.quicktabs.prepare(this); }); } } // Setting up the inital behaviours Drupal.quicktabs.prepare = function(el) { // el.id format: "quicktabs-$name" var qt_name = Drupal.quicktabs.getQTName(el); var $ul = $(el).find('ul.quicktabs-tabs:first'); $("ul.quicktabs-tabs li a span#active-quicktabs-tab").remove(); $ul.find('li a').each(function(i, element){ element.myTabIndex = i; element.qt_name = qt_name; var tab = new Drupal.quicktabs.tab(element); var parent_li = $(element).parents('li').get(0); if ($(parent_li).hasClass('active')) { $(element).addClass('quicktabs-loaded'); $(element).append('' + Drupal.t('(active tab)') + ''); } $(element).once(function() {$(this).bind('click', {tab: tab}, Drupal.quicktabs.clickHandler);}); }); } Drupal.quicktabs.clickHandler = function(event) { var tab = event.data.tab; var element = this; // Set clicked tab to active. $(this).parents('li').siblings().removeClass('active'); $(this).parents('li').addClass('active'); $("ul.quicktabs-tabs li a span#active-quicktabs-tab").remove(); $(this).append('' + Drupal.t('(active tab)') + ''); // Hide all tabpages. tab.container.children().addClass('quicktabs-hide'); if (!tab.tabpage.hasClass("quicktabs-tabpage")) { tab = new Drupal.quicktabs.tab(element); } tab.tabpage.removeClass('quicktabs-hide'); $(element).trigger('switchtab'); return false; } // Constructor for an individual tab Drupal.quicktabs.tab = function (el) { this.element = el; this.tabIndex = el.myTabIndex; var qtKey = 'qt_' + el.qt_name; var i = 0; for (var key in Drupal.settings.quicktabs[qtKey].tabs) { if (i == this.tabIndex) { this.tabObj = Drupal.settings.quicktabs[qtKey].tabs[key]; this.tabKey = key; } i++; } this.tabpage_id = 'quicktabs-tabpage-' + el.qt_name + '-' + this.tabKey; this.container = $('#quicktabs-container-' + el.qt_name); this.tabpage = this.container.find('#' + this.tabpage_id); } if (Drupal.ajax) { /** * Handle an event that triggers an AJAX response. * * We unfortunately need to override this function, which originally comes from * misc/ajax.js, in order to be able to cache loaded tabs, i.e. once a tab * content has loaded it should not need to be loaded again. * * I have removed all comments that were in the original core function, so that * the only comments inside this function relate to the Quicktabs modification * of it. */ Drupal.ajax.prototype.eventResponse = function (element, event) { var ajax = this; if (ajax.ajaxing) { return false; } try { if (ajax.form) { if (ajax.setClick) { element.form.clk = element; } ajax.form.ajaxSubmit(ajax.options); } else { // Do not perform an ajax request for already loaded Quicktabs content. if (!$(element).hasClass('quicktabs-loaded')) { ajax.beforeSerialize(ajax.element, ajax.options); $.ajax(ajax.options); if ($(element).parents('ul').hasClass('quicktabs-tabs')) { $(element).addClass('quicktabs-loaded'); } } } } catch (e) { ajax.ajaxing = false; alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message); } return false; }; } })(jQuery); ;