(function ($) { /** * Attaches sticky table headers. */ Drupal.behaviors.tableHeader = { attach: function (context, settings) { if (!$.support.positionFixed) { return; } $('table.sticky-enabled', context).once('tableheader', function () { $(this).data("drupal-tableheader", new Drupal.tableHeader(this)); }); } }; /** * Constructor for the tableHeader object. Provides sticky table headers. * * @param table * DOM object for the table to add a sticky header to. */ Drupal.tableHeader = function (table) { var self = this; this.originalTable = $(table); this.originalHeader = $(table).children('thead'); this.originalHeaderCells = this.originalHeader.find('> tr > th'); this.displayWeight = null; // React to columns change to avoid making checks in the scroll callback. this.originalTable.bind('columnschange', function (e, display) { // This will force header size to be calculated on scroll. self.widthCalculated = (self.displayWeight !== null && self.displayWeight === display); self.displayWeight = display; }); // Clone the table header so it inherits original jQuery properties. Hide // the table to avoid a flash of the header clone upon page load. this.stickyTable = $('') .insertBefore(this.originalTable) .css({ position: 'fixed', top: '0px' }); this.stickyHeader = this.originalHeader.clone(true) .hide() .appendTo(this.stickyTable); this.stickyHeaderCells = this.stickyHeader.find('> tr > th'); this.originalTable.addClass('sticky-table'); $(window) .bind('scroll.drupal-tableheader', $.proxy(this, 'eventhandlerRecalculateStickyHeader')) .bind('resize.drupal-tableheader', { calculateWidth: true }, $.proxy(this, 'eventhandlerRecalculateStickyHeader')) // Make sure the anchor being scrolled into view is not hidden beneath the // sticky table header. Adjust the scrollTop if it does. .bind('drupalDisplaceAnchor.drupal-tableheader', function () { window.scrollBy(0, -self.stickyTable.outerHeight()); }) // Make sure the element being focused is not hidden beneath the sticky // table header. Adjust the scrollTop if it does. .bind('drupalDisplaceFocus.drupal-tableheader', function (event) { if (self.stickyVisible && event.clientY < (self.stickyOffsetTop + self.stickyTable.outerHeight()) && event.$target.closest('sticky-header').length === 0) { window.scrollBy(0, -self.stickyTable.outerHeight()); } }) .triggerHandler('resize.drupal-tableheader'); // We hid the header to avoid it showing up erroneously on page load; // we need to unhide it now so that it will show up when expected. this.stickyHeader.show(); }; /** * Event handler: recalculates position of the sticky table header. * * @param event * Event being triggered. */ Drupal.tableHeader.prototype.eventhandlerRecalculateStickyHeader = function (event) { var self = this; var calculateWidth = event.data && event.data.calculateWidth; // Reset top position of sticky table headers to the current top offset. this.stickyOffsetTop = Drupal.settings.tableHeaderOffset ? eval(Drupal.settings.tableHeaderOffset + '()') : 0; this.stickyTable.css('top', this.stickyOffsetTop + 'px'); // Save positioning data. var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight; if (calculateWidth || this.viewHeight !== viewHeight) { this.viewHeight = viewHeight; this.vPosition = this.originalTable.offset().top - 4 - this.stickyOffsetTop; this.hPosition = this.originalTable.offset().left; this.vLength = this.originalTable[0].clientHeight - 100; calculateWidth = true; } // Track horizontal positioning relative to the viewport and set visibility. var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft; var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - this.vPosition; this.stickyVisible = vOffset > 0 && vOffset < this.vLength; this.stickyTable.css({ left: (-hScroll + this.hPosition) + 'px', visibility: this.stickyVisible ? 'visible' : 'hidden' }); // Only perform expensive calculations if the sticky header is actually // visible or when forced. if (this.stickyVisible && (calculateWidth || !this.widthCalculated)) { this.widthCalculated = true; var $that = null; var $stickyCell = null; var display = null; var cellWidth = null; // Resize header and its cell widths. // Only apply width to visible table cells. This prevents the header from // displaying incorrectly when the sticky header is no longer visible. for (var i = 0, il = this.originalHeaderCells.length; i < il; i += 1) { $that = $(this.originalHeaderCells[i]); $stickyCell = this.stickyHeaderCells.eq($that.index()); display = $that.css('display'); if (display !== 'none') { cellWidth = $that.css('width'); // Exception for IE7. if (cellWidth === 'auto') { cellWidth = $that[0].clientWidth + 'px'; } $stickyCell.css({'width': cellWidth, 'display': display}); } else { $stickyCell.css('display', 'none'); } } this.stickyTable.css('width', this.originalTable.outerWidth()); } }; })(jQuery); ; (function($) { Drupal.behaviors.CToolsJumpMenu = { attach: function(context) { $('.ctools-jump-menu-hide') .once('ctools-jump-menu') .hide(); $('.ctools-jump-menu-change') .once('ctools-jump-menu') .change(function() { var loc = $(this).val(); var urlArray = loc.split('::'); if (urlArray[1]) { location.href = urlArray[1]; } else { location.href = loc; } return false; }); $('.ctools-jump-menu-button') .once('ctools-jump-menu') .click(function() { // Instead of submitting the form, just perform the redirect. // Find our sibling value. var $select = $(this).parents('form').find('.ctools-jump-menu-select'); var loc = $select.val(); var urlArray = loc.split('::'); if (urlArray[1]) { location.href = urlArray[1]; } else { location.href = loc; } return false; }); } } })(jQuery); ; (function ($) { Drupal.googleanalytics = {}; $(document).ready(function() { // Attach mousedown, keyup, touchstart events to document only and catch // clicks on all elements. $(document.body).bind("mousedown keyup touchstart", function(event) { // Catch the closest surrounding link of a clicked element. $(event.target).closest("a,area").each(function() { // Is the clicked URL internal? if (Drupal.googleanalytics.isInternal(this.href)) { // Skip 'click' tracking, if custom tracking events are bound. if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { // Do nothing here. The custom event will handle all tracking. //console.info("Click on .colorbox item has been detected."); } // Is download tracking activated and the file extension configured for download tracking? else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { // Download link clicked. ga("send", { "hitType": "event", "eventCategory": "Downloads", "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), "transport": "beacon" }); } else if (Drupal.googleanalytics.isInternalSpecial(this.href)) { // Keep the internal URL for Google Analytics website overlay intact. ga("send", { "hitType": "pageview", "page": Drupal.googleanalytics.getPageUrl(this.href), "transport": "beacon" }); } } else { if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) { // Mailto link clicked. ga("send", { "hitType": "event", "eventCategory": "Mails", "eventAction": "Click", "eventLabel": this.href.substring(7), "transport": "beacon" }); } else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { // External link clicked / No top-level cross domain clicked. ga("send", { "hitType": "event", "eventCategory": "Outbound links", "eventAction": "Click", "eventLabel": this.href, "transport": "beacon" }); } } } }); }); // Track hash changes as unique pageviews, if this option has been enabled. if (Drupal.settings.googleanalytics.trackUrlFragments) { window.onhashchange = function() { ga("send", { "hitType": "pageview", "page": location.pathname + location.search + location.hash }); }; } // Colorbox: This event triggers when the transition has completed and the // newly loaded content has been revealed. if (Drupal.settings.googleanalytics.trackColorbox) { $(document).bind("cbox_complete", function () { var href = $.colorbox.element().attr("href"); if (href) { ga("send", { "hitType": "pageview", "page": Drupal.googleanalytics.getPageUrl(href) }); } }); } }); /** * Check whether the hostname is part of the cross domains or not. * * @param string hostname * The hostname of the clicked URL. * @param array crossDomains * All cross domain hostnames as JS array. * * @return boolean */ Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) { /** * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is * `null` or `undefined`, http://bugs.jquery.com/ticket/10076, * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174 * * @todo: Remove/Refactor in D8 */ if (!crossDomains) { return false; } else { return $.inArray(hostname, crossDomains) > -1 ? true : false; } }; /** * Check whether this is a download URL or not. * * @param string url * The web url to check. * * @return boolean */ Drupal.googleanalytics.isDownload = function (url) { var isDownload = new RegExp("\\.(" + Drupal.settings.googleanalytics.trackDownloadExtensions + ")([\?#].*)?$", "i"); return isDownload.test(url); }; /** * Check whether this is an absolute internal URL or not. * * @param string url * The web url to check. * * @return boolean */ Drupal.googleanalytics.isInternal = function (url) { var isInternal = new RegExp("^(https?):\/\/" + window.location.host, "i"); return isInternal.test(url); }; /** * Check whether this is a special URL or not. * * URL types: * - gotwo.module /go/* links. * * @param string url * The web url to check. * * @return boolean */ Drupal.googleanalytics.isInternalSpecial = function (url) { var isInternalSpecial = new RegExp("(\/go\/.*)$", "i"); return isInternalSpecial.test(url); }; /** * Extract the relative internal URL from an absolute internal URL. * * Examples: * - http://mydomain.com/node/1 -> /node/1 * - http://example.com/foo/bar -> http://example.com/foo/bar * * @param string url * The web url to check. * * @return string * Internal website URL */ Drupal.googleanalytics.getPageUrl = function (url) { var extractInternalUrl = new RegExp("^(https?):\/\/" + window.location.host, "i"); return url.replace(extractInternalUrl, ''); }; /** * Extract the download file extension from the URL. * * @param string url * The web url to check. * * @return string * The file extension of the passed url. e.g. "zip", "txt" */ Drupal.googleanalytics.getDownloadExtension = function (url) { var extractDownloadextension = new RegExp("\\.(" + Drupal.settings.googleanalytics.trackDownloadExtensions + ")([\?#].*)?$", "i"); var extension = extractDownloadextension.exec(url); return (extension === null) ? '' : extension[1]; }; })(jQuery); ;