/**
* @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);
;