1/** 2 * @file 3 * Simple responsification of menus. 4 */ 5(function ($) { 6 /** 7 * Handle clicks & toggling the menu. 8 */ 9 var toggler_click = function() { 10 $(this).parent().toggleClass('responsive-toggled'); 11 }; 12 /** 13 * Unbind other mouse events on the menu items. 14 * 15 * @todo 16 * Not sure if it works 100%. 17 * Doesn't restore binds when out-of-responsive (if window dragging). 18 */ 19 function remove_mouse_events(menuElement) { 20 // Determine jQuery version and what disable options we have. 21 var jqVersion = $.fn.jquery; 22 if (jqVersion < 1.7) { 23 $(menuElement).die('mouseover mouseout mouseenter mouseleave'); 24 $(menuElement + ' li').die('mouseover mouseout mouseenter mouseleave'); 25 $(menuElement + ' li a').die('mouseover mouseout mouseenter mouseleave'); 26 } 27 else { 28 $(menuElement).off('hover'); 29 $(menuElement + ' li').off('hover'); 30 $(menuElement + ' li a').off('hover'); 31 } 32 $(menuElement).unbind('mouseover mouseout mouseenter mouseleave'); 33 $(menuElement + ' li').unbind('mouseover mouseout mouseenter mouseleave'); 34 $(menuElement + ' li a').unbind('mouseover mouseout mouseenter mouseleave'); 35 } 36 37 /** 38 * Store classes & IDs for restoring later (if window dragging). 39 */ 40 function store_classes_ids(menuElement) { 41 if (!$(menuElement).attr('id')) { 42 $(menuElement).attr('id', 'rm-no-id-main'); 43 } 44 if (!$(menuElement).attr('class')) { 45 $(menuElement).attr('class', 'rm-no-class'); 46 } 47 $(menuElement).data('removeattr', true) 48 .data('rmids', $(menuElement).attr('id')) 49 .data('rmclasses', $(menuElement).attr('class')); 50 // Handle ULs if selector is parent div. 51 var incr = 0; 52 $(menuElement).find('ul').each(function() { 53 incr++; 54 // Prevent error if there is no id. 55 if (!$(this).attr('id')) { 56 $(this).attr('id', 'rm-no-id-' + incr); 57 } 58 // Prevent error if there is no class. 59 if (!$(this).attr('class')) { 60 $(this).attr('class', 'rm-no-class'); 61 } 62 $(this).data('removeattr', true) 63 .data('rmids', $(this).attr('id')) 64 .data('rmclasses', $(this).attr('class')); 65 }); 66 // Finally, add our class to the parent. 67 $(menuElement).addClass('responsive-menus-simple'); 68 } 69 70 /** 71 * Remove classes & IDs from original menu for easier theming. 72 */ 73 function remove_classes_ids(menuElement) { 74 // Handle ULs if selector is parent div. 75 $(menuElement).find('ul').each(function() { 76 $(this).attr('class', 'rm-removed').attr('id', 'rm-removed'); 77 }); 78 // Remove classes/IDs. 79 $(menuElement).attr('class', 'responsive-menus-simple').attr('id', 'rm-removed'); 80 } 81 82 // Iterate through selectors, check window sizes, add some classes. 83 Drupal.behaviors.responsive_menus = { 84 attach: function (context, settings) { 85 settings.responsive_menus = settings.responsive_menus || {}; 86 $('body').once('responsive-menus-load', function() { 87 // Only doing this themes that don't include a viewport attribute. 88 // e.g. Bartik for testing out-of-the-box... yeah, stupid. 89 if (!$('meta[name=viewport]').length > 0) { 90 $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0">'); 91 } 92 // Window width with legacy browsers. 93 var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 94 $.each(settings.responsive_menus, function(ind, iteration) { 95 if (iteration.responsive_menus_style != 'responsive_menus_simple') { 96 return true; 97 } 98 if (!iteration.selectors.length) { 99 return true; 100 } 101 var $media_unit = iteration.media_unit || 'px'; 102 if ($media_unit === 'em') { 103 var $base_font_size = parseFloat($('body').css('font-size')); 104 var $media_size = iteration.media_size * $base_font_size || 768; 105 } 106 else { 107 var $media_size = iteration.media_size || 768; 108 } 109 110 // Handle clicks & toggling. 111 var toggler_class = ''; 112 var toggler_text = iteration.toggler_text; 113 // Iterate through our selectors. 114 $.each(iteration.selectors, function(index, value) { 115 // Stop if there is no menu element. 116 if ($(value).length < 1) { 117 return true; 118 } 119 // Handle nested menus. Make sure we get the first, but not children. 120 if ($(value).length > 1) { 121 $(value).each(function(val_index) { 122 if (!$(this).parents('ul').length) { 123 if (!$(this).hasClass('responsive-menus-simple')) { 124 toggler_class = 'responsive-menus-' + ind + '-' + index + '-' + val_index; 125 // Store classes & IDs before removing. 126 if (iteration.remove_attributes) { 127 store_classes_ids(this); 128 } 129 $(this).wrap('<div data-mediasize="' + $media_size + '" class="responsive-menus ' + toggler_class + '" />'); 130 $('.' + toggler_class).prepend('<span class="toggler">' + toggler_text + '</span>'); 131 $('.' + toggler_class + ' .toggler').bind('click', toggler_click);
132 // Unbind other mouse events. 133 if (iteration.disable_mouse_events) { 134 //$(this).data('disablemouse', true); 135 remove_mouse_events(this); 136 } 137 // Use absolute positioning. 138 if (iteration.absolute) { 139 $('.' + toggler_class).addClass('absolute'); 140 } 141 // Handle first size check. 142 if (windowWidth <= $media_size) { 143 // Remove attributes setting. 144 if (iteration.remove_attributes) { 145 remove_classes_ids(this); 146 } 147 $('.' + toggler_class).addClass('responsified'); 148 } 149 } 150 } 151 }); 152 } 153 else { 154 // Single level menus. 155 if (!$(value).hasClass('responsive-menus-simple')) { 156 toggler_class = 'responsive-menus-' + ind + '-' + index; 157 // Store classes & IDs before removing. 158 if (iteration.remove_attributes) { 159 store_classes_ids(value); 160 } 161 $(value).wrap('<div data-mediasize="' + $media_size + '" class="responsive-menus ' + toggler_class + '" />'); 162 $('.' + toggler_class).prepend('<span class="toggler">' + toggler_text + '</span>'); 163 $('.' + toggler_class + ' .toggler').bind('click', toggler_click); 164 // Unbind other mouse events. 165 if (iteration.disable_mouse_events) { 166 // @todo For rebinding mouse events. 167 /*if ($(value + ' li a').data('events')) { 168 $(value).data('tmpevents', $(value + ' li a').data('events')); 169 }*/ 170 remove_mouse_events(value); 171 } 172 // Use absolute positioning. 173 if (iteration.absolute) { 174 $('.' + toggler_class).addClass('absolute'); 175 } 176 // Handle first size check. 177 if (windowWidth <= $media_size) { 178 // Remove attributes setting. 179 if (iteration.remove_attributes) { 180 remove_classes_ids(value); 181 } 182 $('.' + toggler_class).addClass('responsified'); 183 } 184 } 185 } 186 }); 187 }); 188 // Handle window resizing. 189 $(window).resize(function() {
190 // Window width with legacy browsers. 191 windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 192 $('.responsive-menus').each(function(menuIndex, menuValue) { 193 var mediasize = $(this).data('mediasize') || 768; 194 // Prevent menu from going off the screen. This only happens in 195 // non-responsive themes (like Bartik default), but it looks bad. 196 if ($(this).width() > windowWidth) { 197 $(this).data('nonresponsive', true); 198 $(this).width(windowWidth); 199 } 200 var menuElement = $(this).find('.responsive-menus-simple'); 201 if (windowWidth >= mediasize) { 202 if (menuElement.data('removeattr')) { 203 menuElement.addClass(menuElement.data('rmclasses')); 204 menuElement.attr('id', menuElement.data('rmids')); 205 menuElement.find('ul').each(function() { 206 $(this).addClass($(this).data('rmclasses')); 207 $(this).attr('id', $(this).data('rmids')); 208 }); 209 } 210 $(this).removeClass('responsified'); 211 } 212 if (windowWidth <= mediasize) { 213 // Now fix repercussions for handling non-responsive themes above. 214 // Stretch width back out w/ the screen. 215 if ($(this).data('nonresponsive') && $(this).width() < windowWidth) { 216 $(this).width(windowWidth); 217 } 218 if (menuElement.data('removeattr')) { 219 remove_classes_ids(menuElement); 220 } 221 $(this).addClass('responsified'); 222 } 223 }); 224 }); 225 }); 226 } 227 }; 228 229}(jQuery)); 230 231;/*})'"*/ 232;/*})'"*/ 233(function ($) { 234 235Drupal.googleanalytics = {}; 236 237$(document).ready(function() { 238 239 // Attach mousedown, keyup, touchstart events to document only and catch 240 // clicks on all elements. 241 $(document.body).bind("mousedown keyup touchstart", function(event) { 242 243 // Catch the closest surrounding link of a clicked element. 244 $(event.target).closest("a,area").each(function() { 245 246 // Is the clicked URL internal? 247 if (Drupal.googleanalytics.isInternal(this.href)) { 248 // Skip 'click' tracking, if custom tracking events are bound. 249 if ($(this).is('.colorbox') && (Drupal.settings.googleanalytics.trackColorbox)) { 250 // Do nothing here. The custom event will handle all tracking. 251 //console.info("Click on .colorbox item has been detected."); 252 } 253 // Is download tracking activated and the file extension configured for download tracking? 254 else if (Drupal.settings.googleanalytics.trackDownload && Drupal.googleanalytics.isDownload(this.href)) { 255 // Download link clicked. 256 ga("send", { 257 "hitType": "event", 258 "eventCategory": "Downloads", 259 "eventAction": Drupal.googleanalytics.getDownloadExtension(this.href).toUpperCase(), 260 "eventLabel": Drupal.googleanalytics.getPageUrl(this.href), 261 "transport": "beacon" 262 }); 263 } 264 else if (Drupal.googleanalytics.isInternalSpecial(this.href)) { 265 // Keep the internal URL for Google Analytics website overlay intact. 266 ga("send", { 267 "hitType": "pageview", 268 "page": Drupal.googleanalytics.getPageUrl(this.href), 269 "transport": "beacon" 270 }); 271 } 272 } 273 else { 274 if (Drupal.settings.googleanalytics.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) { 275 // Mailto link clicked. 276 ga("send", { 277 "hitType": "event", 278 "eventCategory": "Mails", 279 "eventAction": "Click", 280 "eventLabel": this.href.substring(7), 281 "transport": "beacon" 282 }); 283 } 284 else if (Drupal.settings.googleanalytics.trackOutbound && this.href.match(/^\w+:\/\//i)) { 285 if (Drupal.settings.googleanalytics.trackDomainMode !== 2 || (Drupal.settings.googleanalytics.trackDomainMode === 2 && !Drupal.googleanalytics.isCrossDomain(this.hostname, Drupal.settings.googleanalytics.trackCrossDomains))) { 286 // External link clicked / No top-level cross domain clicked. 287 ga("send", { 288 "hitType": "event", 289 "eventCategory": "Outbound links", 290 "eventAction": "Click", 291 "eventLabel": this.href, 292 "transport": "beacon" 293 }); 294 } 295 } 296 } 297 }); 298 }); 299 300 // Track hash changes as unique pageviews, if this option has been enabled. 301 if (Drupal.settings.googleanalytics.trackUrlFragments) { 302 window.onhashchange = function() { 303 ga("send", { 304 "hitType": "pageview", 305 "page": location.pathname + location.search + location.hash 306 }); 307 }; 308 } 309 310 // Colorbox: This event triggers when the transition has completed and the 311 // newly loaded content has been revealed. 312 if (Drupal.settings.googleanalytics.trackColorbox) { 313 $(document).bind("cbox_complete", function () {
314 var href = $.colorbox.element().attr("href"); 315 if (href) { 316 ga("send", { 317 "hitType": "pageview", 318 "page": Drupal.googleanalytics.getPageUrl(href) 319 }); 320 } 321 }); 322 } 323 324}); 325 326/** 327 * Check whether the hostname is part of the cross domains or not. 328 * 329 * @param string hostname 330 * The hostname of the clicked URL. 331 * @param array crossDomains 332 * All cross domain hostnames as JS array. 333 * 334 * @return boolean 335 */ 336Drupal.googleanalytics.isCrossDomain = function (hostname, crossDomains) { 337 /** 338 * jQuery < 1.6.3 bug: $.inArray crushes IE6 and Chrome if second argument is 339 * `null` or `undefined`, https://bugs.jquery.com/ticket/10076, 340 * https://github.com/jquery/jquery/commit/a839af034db2bd934e4d4fa6758a3fed8de74174 341 * 342 * @todo: Remove/Refactor in D8 343 */ 344 if (!crossDomains) { 345 return false; 346 } 347 else { 348 return $.inArray(hostname, crossDomains) > -1 ? true : false; 349 } 350}; 351 352/** 353 * Check whether this is a download URL or not. 354 * 355 * @param string url 356 * The web url to check. 357 * 358 * @return boolean 359 */ 360Drupal.googleanalytics.isDownload = function (url) { 361 var isDownload = new RegExp("\\.(" + Drupal.settings.googleanalytics.trackDownloadExtensions + ")([\?#].*)?$", "i"); 362 return isDownload.test(url); 363}; 364 365/** 366 * Check whether this is an absolute internal URL or not. 367 * 368 * @param string url 369 * The web url to check. 370 * 371 * @return boolean 372 */ 373Drupal.googleanalytics.isInternal = function (url) { 374 var isInternal = new RegExp("^(https?):\/\/" + window.location.host, "i"); 375 return isInternal.test(url); 376}; 377 378/** 379 * Check whether this is a special URL or not. 380 * 381 * URL types: 382 * - gotwo.module /go/* links. 383 * 384 * @param string url 385 * The web url to check. 386 * 387 * @return boolean 388 */ 389Drupal.googleanalytics.isInternalSpecial = function (url) { 390 var isInternalSpecial = new RegExp("(\/go\/.*)$", "i"); 391 return isInternalSpecial.test(url); 392}; 393 394/** 395 * Extract the relative internal URL from an absolute internal URL. 396 * 397 * Examples: 398 * - https://mydomain.com/node/1 -> /node/1 399 * - https://example.com/foo/bar -> https://example.com/foo/bar 400 * 401 * @param string url 402 * The web url to check. 403 * 404 * @return string 405 * Internal website URL 406 */ 407Drupal.googleanalytics.getPageUrl = function (url) { 408 var extractInternalUrl = new RegExp("^(https?):\/\/" + window.location.host, "i"); 409 return url.replace(extractInternalUrl, ''); 410}; 411 412/** 413 * Extract the download file extension from the URL. 414 * 415 * @param string url 416 * The web url to check. 417 * 418 * @return string 419 * The file extension of the passed url. e.g. "zip", "txt" 420 */ 421Drupal.googleanalytics.getDownloadExtension = function (url) { 422 var extractDownloadextension = new RegExp("\\.(" + Drupal.settings.googleanalytics.trackDownloadExtensions + ")([\?#].*)?$", "i"); 423 var extension = extractDownloadextension.exec(url); 424 return (extension === null) ? '' : extension[1]; 425}; 426 427})(jQuery); 428 429;/*})'"*/ 430;/*})'"*/
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.