%PDF- %PDF-
Direktori : /home/bitrix/www/!_land/responsive/ |
Current File : /home/bitrix/www/!_land/responsive/responsive.js |
/* ==|== Responsive ============================================================= Author: James South twitter : http://twitter.com/James_M_South github : https://github.com/ResponsiveBP/Responsive Copyright (c), James South. Licensed under the MIT License. ============================================================================== */ /*! Responsive v4.1.1 | MIT License | responsivebp.com */ /* * Responsive Core */ /*global jQuery*/ /*jshint forin:false, expr:true*/ (function ($, w, d) { "use strict"; $.pseudoUnique = function (length) { /// <summary>Returns a pseudo unique alpha-numeric string of the given length.</summary> /// <param name="length" type="Number">The length of the string to return. Defaults to 8.</param> /// <returns type="String">The pseudo unique alpha-numeric string.</returns> var len = length || 8, text = "", possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", max = possible.length; if (len > max) { len = max; } for (var i = 0; i < len; i += 1) { text += possible.charAt(Math.floor(Math.random() * max)); } return text; }; $.support.rtl = (function () { /// <summary>Returns a value indicating whether the current page is setup for right-to-left languages.</summary> /// <returns type="Boolean"> /// True if right-to-left language support is set up; otherwise false. ///</returns> return $("html[dir=rtl]").length ? true : false; }()); $.support.currentGrid = (function () { /// <summary>Returns a value indicating what grid range the current browser width is within.</summary> /// <returns type="Object"> /// An object containing two properties. /// 1: grid - The current applied grid; either xxs, xs, s, m, or l. /// 2: index - The index of the current grid in the range. /// 3: range - The available grid range. ///</returns> return function () { var $div = $("<div/>").addClass("grid-state-indicator").prependTo("body"); // These numbers match values in the css var grids = ["xxs", "xs", "s", "m", "l"], key = parseInt($div.width(), 10); $div.remove(); return { grid: grids[key], index: key, range: grids }; }; }()); $.support.scrollbarWidth = (function () { /// <summary>Returns a value indicating the width of the browser scrollbar.</summary> /// <returns type="Number">The width in pixels.</returns> return function () { var width = 0; if (d.body.clientWidth < w.innerWidth) { var $div = $("<div/>").addClass("scrollbar-measure").prependTo("body"); width = $div[0].offsetWidth - $div[0].clientWidth; $div.remove(); } return width; }; }()); $.toggleBodyLock = function () { /// <summary> /// Toggles a locked state on the body which toggles both scrollbar visibility and padding on the body. /// </summary> var $html = $("html"), $body = $("body"), bodyPad; // Remove. if ($html.attr("data-lock") !== undefined) { bodyPad = $body.data("bodyPad"); $body.css("padding-right", bodyPad || "") .removeData("bodyPad"); $html.removeAttr("data-lock") .trigger($.Event("unlock.r.bodylock")); return; } // Add bodyPad = parseInt($body.css("padding-right") || 0); var scrollWidth = $.support.scrollbarWidth(); if (scrollWidth) { $body.css("padding-right", bodyPad + scrollWidth); if (bodyPad) { $body.data("bodyPad", bodyPad); } $html.attr("data-lock", "") .trigger($.Event("lock.r.bodylock", { padding: bodyPad + scrollWidth })); } }; $.support.transition = (function () { /// <summary>Returns a value indicating whether the browser supports CSS transitions.</summary> /// <returns type="Boolean">True if the current browser supports css transitions.</returns> var transitionEnd = function () { /// <summary>Gets transition end event for the current browser.</summary> /// <returns type="Object">The transition end event for the current browser.</returns> var div = d.createElement("div"), transEndEventNames = { "transition": "transitionend", "WebkitTransition": "webkitTransitionEnd", "MozTransition": "transitionend", "OTransition": "oTransitionEnd otransitionend" }; var names = Object.keys(transEndEventNames), len = names.length; for (var i = 0; i < len; i++) { if (div.style[names[i]] !== undefined) { return { end: transEndEventNames[names[i]] }; } } return false; }; return transitionEnd(); }()); $.fn.redraw = function () { /// <summary>Forces the browser to redraw by measuring the given target.</summary> /// <returns type="jQuery">The jQuery object for chaining.</returns> var redraw; return this.each(function () { redraw = this.offsetWidth; }); }; (function () { var getDuration = function ($element) { var rtransition = /\d+(.\d+)?/; return (rtransition.test($element.css("transition-duration")) ? $element.css("transition-duration").match(rtransition)[0] : 0) * 1000; }; $.fn.ensureTransitionEnd = function (duration) { /// <summary> /// Ensures that the transition end callback is triggered. /// http://blog.alexmaccaw.com/css-transitions ///</summary> if (!$.support.transition) { return this; } var called = false, $this = $(this), callback = function () { if (!called) { $this.trigger($.support.transition.end); } }; if (!duration) { duration = getDuration($this); } $this.one($.support.transition.end, function () { called = true; }); w.setTimeout(callback, duration); return this; }; $.fn.onTransitionEnd = function (callback) { /// <summary>Performs the given callback at the end of a css transition.</summary> /// <param name="callback" type="Function">The function to call on transition end.</param> /// <returns type="jQuery">The jQuery object for chaining.</returns> var supportTransition = $.support.transition; return this.each(function () { if (!$.isFunction(callback)) { return; } var $this = $(this), duration = getDuration($this), error = duration / 10, start = new Date(), args = arguments; $this.redraw(); supportTransition ? $this.one(supportTransition.end, function () { // Prevent events firing too early. var end = new Date(); if (end.getMilliseconds() - start.getMilliseconds() <= error) { w.setTimeout(function () { callback.apply(this, args); }.bind(this), duration); return; } callback.apply(this, args); }) : callback.apply(this, args); }); }; }()); $.support.touchEvents = (function () { return ("ontouchstart" in w) || (w.DocumentTouch && d instanceof w.DocumentTouch); }()); $.support.pointerEvents = (function () { return (w.PointerEvent || w.MSPointerEvent); }()); (function () { var supportTouch = $.support.touchEvents, supportPointer = $.support.pointerEvents; var pointerStart = ["pointerdown", "MSPointerDown"], pointerMove = ["pointermove", "MSPointerMove"], pointerEnd = ["pointerup", "pointerout", "pointercancel", "pointerleave", "MSPointerUp", "MSPointerOut", "MSPointerCancel", "MSPointerLeave"]; var touchStart = "touchstart", touchMove = "touchmove", touchEnd = ["touchend", "touchleave", "touchcancel"]; var mouseStart = "mousedown", mouseMove = "mousemove", mouseEnd = ["mouseup", "mouseleave"]; var getEvents = function (ns) { var estart, emove, eend; // Keep the events separate since support could be crazy. if (supportTouch) { estart = touchStart + ns; emove = touchMove + ns; eend = (touchEnd.join(ns + " ")) + ns; } else if (supportPointer) { estart = (pointerStart.join(ns + " ")) + ns; emove = (pointerMove.join(ns + " ")) + ns; eend = (pointerEnd.join(ns + " ")) + ns; } else { estart = mouseStart + ns; emove = mouseMove + ns; eend = (mouseEnd.join(ns + " ")) + ns; } return { start: estart, move: emove, end: eend }; }; var addSwipe = function ($elem, handler) { /// <summary>Adds swiping functionality to the given element.</summary> /// <param name="$elem" type="Object"> /// The jQuery object representing the given node(s). /// </param> /// <returns type="jQuery">The jQuery object for chaining.</returns> var ns = handler.namespace ? "." + handler.namespace : "", eswipestart = "swipestart", eswipemove = "swipemove", eswipeend = "swipeend", etouch = getEvents(ns); // Set the touchAction variable for move. var touchAction = handler.data && handler.data.touchAction || "none", sensitivity = handler.data && handler.data.sensitivity || 5; if (supportPointer) { // Enable extended touch events on supported browsers before any touch events. $elem.css({ "-ms-touch-action": "" + touchAction + "", "touch-action": "" + touchAction + "" }); } return $elem.each(function () { var $this = $(this); var start = {}, delta = {}, onMove = function (event) { // Normalize the variables. var isMouse = event.type === "mousemove", isPointer = event.type !== "touchmove" && !isMouse, original = event.originalEvent, moveEvent; // Only left click allowed. if (isMouse && event.which !== 1) { return; } // One touch allowed. if (original.touches && original.touches.length > 1) { return; } // Ensure swiping with one touch and not pinching. if (event.scale && event.scale !== 1) { return; } var dx = (isMouse ? original.pageX : isPointer ? original.clientX : original.touches[0].pageX) - start.x, dy = (isMouse ? original.pageY : isPointer ? original.clientY : original.touches[0].pageY) - start.y; var doSwipe, percentX = Math.abs(parseFloat((dx / $this.width()) * 100)) || 100, percentY = Math.abs(parseFloat((dy / $this.height()) * 100)) || 100; // Work out whether to do a scroll based on the sensitivity limit. switch (touchAction) { case "pan-x": if (Math.abs(dy) > Math.abs(dx)) { event.preventDefault(); } doSwipe = Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > sensitivity && percentY < 100; break; case "pan-y": if (Math.abs(dx) > Math.abs(dy)) { event.preventDefault(); } doSwipe = Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > sensitivity && percentX < 100; break; default: event.preventDefault(); doSwipe = Math.abs(dy) > sensitivity || Math.abs(dx) > sensitivity && percentX < 100 && percentY < 100; break; } event.stopPropagation(); if (!doSwipe) { return; } moveEvent = $.Event(eswipemove, { delta: { x: dx, y: dy } }); $this.trigger(moveEvent); if (moveEvent.isDefaultPrevented()) { return; } // Measure change in x and y. delta = { x: dx, y: dy }; }, onEnd = function () { // Measure duration var duration = +new Date() - start.time, endEvent; // Determine if slide attempt triggers slide. if (Math.abs(delta.x) > 1 || Math.abs(delta.y) > 1) { // Set the direction and return it. var horizontal = delta.x < 0 ? "left" : "right", vertical = delta.y < 0 ? "up" : "down", direction = Math.abs(delta.x) > Math.abs(delta.y) ? horizontal : vertical; endEvent = $.Event(eswipeend, { delta: delta, direction: direction, duration: duration }); $this.trigger(endEvent); } // Disable the touch events till next time. $this.off(etouch.move).off(etouch.end); }; $this.off(etouch.start).on(etouch.start, function (event) { // Normalize the variables. var isMouse = event.type === "mousedown", isPointer = event.type !== "touchstart" && !isMouse, original = event.originalEvent; if ((isPointer || isMouse) && $(event.target).is("img")) { event.preventDefault(); } event.stopPropagation(); // Measure start values. start = { // Get initial touch coordinates. x: isMouse ? original.pageX : isPointer ? original.clientX : original.touches[0].pageX, y: isMouse ? original.pageY : isPointer ? original.clientY : original.touches[0].pageY, // Store time to determine touch duration. time: +new Date() }; var startEvent = $.Event(eswipestart, { start: start }); $this.trigger(startEvent); if (startEvent.isDefaultPrevented()) { return; } // Reset delta and end measurements. delta = { x: 0, y: 0 }; // Attach touchmove and touchend listeners. $this.on(etouch.move, onMove) .on(etouch.end, onEnd); }); }); }; var removeSwipe = function ($elem, handler) { /// <summary>Removes swiping functionality from the given element.</summary> var ns = handler.namespace ? "." + handler.namespace : "", etouch = getEvents(ns); return $elem.each(function () { // Disable extended touch events on ie. // Unbind events. $(this).css({ "-ms-touch-action": "", "touch-action": "" }) .off(etouch.start).off(etouch.move).off(etouch.end); }); }; // Create special events so we can use on/off. $.event.special.swipe = { add: function (handler) { addSwipe($(this), handler); }, remove: function (handler) { removeSwipe($(this), handler); } }; }()); $.extend($.expr[":"], { attrStart: function (el, i, props) { /// <summary>Custom selector extension to allow attribute starts with selection.</summary> /// <param name="el" type="DOM">The element to test against.</param> /// <param name="i" type="Number">The index of the element in the stack.</param> /// <param name="props" type="Object">Metadata for the element.</param> /// <returns type="Boolean">True if the element is a match; otherwise, false.</returns> var hasAttribute = false; $.each(el.attributes, function () { if (this.name.indexOf(props[3]) === 0) { hasAttribute = true; return false; // Exit the iteration. } return true; }); return hasAttribute; } }); $.getDataOptions = function ($elem, filter) { /// <summary>Creates an object containing options populated from an elements data attributes.</summary> /// <param name="$elem" type="jQuery">The object representing the DOM element.</param> /// <param name="filter" type="String">The prefix with filter to identify the data attribute.</param> /// <returns type="Object">The extended object.</returns> var options = {}; $.each($elem.data(), function (key, val) { if (key.indexOf(filter) === 0 && key.length > filter.length) { // Build a key with the correct format. var length = filter.length, newKey = key.charAt(length).toLowerCase() + key.substring(length + 1); options[newKey] = val; } }); return Object.keys(options).length ? options : $elem.data(); }; $.debounce = function (func, wait, immediate) { /// <summary> /// Returns a function, that, as long as it continues to be invoked, will not /// be triggered. The function will be called after it stops being called for /// N milliseconds. If `immediate` is passed, trigger the function on the /// leading edge, instead of the trailing. ///</summary> /// <param name="func" type="Function"> /// The function to debounce. /// </param> /// <param name="wait" type="Number"> /// The number of milliseconds to delay. /// </param> /// <param name="wait" type="immediate"> /// Specify execution on the leading edge of the timeout. /// </param> /// <returns type="jQuery">The function.</returns> var timeout; return function () { var context = this, args = arguments; w.clearTimeout(timeout); timeout = w.setTimeout(function () { timeout = null; if (!immediate) { func.apply(context, args); } }, wait); if (immediate && !timeout) { func.apply(context, args); } }; }; (function (old) { /// <summary>Override the core html method in the jQuery object to fire a domchanged event whenever it is called.</summary> /// <param name="old" type="Function"> /// The jQuery function being overridden. /// </param> /// <returns type="jQuery">The jQuery object for chaining.</returns> var echanged = $.Event("domchanged"), $d = $(d); $.fn.html = function () { // Execute the original html() method using the augmented arguments collection. var result = old.apply(this, arguments); if (arguments.length) { $d.trigger(echanged); } return result; }; })($.fn.html); } (jQuery, window, document)); /* * Responsive AutoSize */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_AUTOSIZE) { return; } // General variables and methods. var eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eresize = ["resize" + ns, "orientationchange" + ns].join(" "), einput = "input", ekeyup = "keyup", esize = "size" + ns, esized = "sized" + ns; (function (oldVal) { /// <summary>Override the core val method in the jQuery object to fire an input event on autosize plugins whenever it is called.</summary> /// <param name="old" type="Function"> /// The jQuery function being overridden. /// </param> /// <returns type="jQuery">The jQuery object for chaining.</returns> $.fn.val = function () { // Execute the original val() method using the augmented arguments collection. var result = oldVal.apply(this, arguments); if (this.data("r.autosize") && arguments.length) { this.trigger($.Event(einput)); } return result; }; })($.fn.val); // AutoSize class definition var AutoSize = function (element, options) { this.$element = $(element); this.element = element, this.options = $.extend({}, this.defaults, options); this.sizing = null; this.difference = 0; this.height = this.$element.height(); // Initial setup. this.init(); // Bind events. Keyup is required for IE9. this.$element.on([einput, ekeyup].join(" "), $.debounce($.proxy(this.size, this), 100)); $(w).on(eresize, $.debounce($.proxy(this.size, this), 100)); }; AutoSize.prototype.init = function () { var height = this.$element.outerHeight(); this.difference = parseFloat(this.$element.css("paddingBottom")) + parseFloat(this.$element.css("paddingTop")); // Firefox: scrollHeight isn't full height on border-box if (this.element.scrollHeight + this.difference <= height) { this.difference = 0; } // Only set the height if textarea has value. if (this.element.value.replace(/\s/g, "").length > 0) { this.$element.height(this.element.scrollHeight); } }; AutoSize.prototype.size = function () { var self = this, $element = this.$element, element = this.element, sizeEvent = $.Event(esize); if (this.sizing) { return; } // Check and get the height $element.height("auto"); var scrollHeight = element.scrollHeight - this.difference, different = this.height !== scrollHeight; $element.height(this.height); // Trigger events if need be. if (different) { $element.trigger(sizeEvent); } if (this.sizing || sizeEvent.isDefaultPrevented()) { return; } this.sizing = true; $element.height(scrollHeight); if (different) { // Do our callback $element.onTransitionEnd(function() { self.sizing = false; self.height = scrollHeight; $element.trigger($.Event(esized)); }); return; } this.sizing = false; }; // No conflict. var old = $.fn.autoSize; // Plug-in definition $.fn.autoSize = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.autosize"), opts = typeof options === "object" ? $.extend({}, options) : null; if (!data) { // Check the data and reassign if not present. $this.data("r.autosize", (data = new AutoSize(this, opts))); } if (options === "size") { data.size(); } }); }; // Set the public constructor. $.fn.autoSize.Constructor = AutoSize; $.fn.autoSize.noConflict = function () { $.fn.autoSize = old; return this; }; // Data API var init = function () { $("textarea[data-autosize]").each(function () { var $this = $(this), loaded = $this.data("r.autosizeLoaded"); if (!loaded) { $this.data("r.autosizeLoaded", true); $this.addClass("autosize").autoSize($.getDataOptions($this, "autosize")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_AUTOSIZE = true; }(jQuery, window, ".r.autosize", ".data-api")); /* * Responsive Carousel */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_CAROUSEL) { return; } // General variables. var supportTransition = $.support.transition, rtl = $.support.rtl, emouseenter = "mouseenter", emouseleave = "mouseleave", ekeydown = "keydown", eclick = "click", eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eslide = "slide" + ns, eslid = "slid" + ns; var keys = { SPACE: 32, ENTER: 13, LEFT: 37, RIGHT: 39 }; // Carousel class definition var Carousel = function (element, options) { this.$element = $(element); this.defaults = { interval: 0, // Better for a11y mode: "slide", pause: "hover", wrap: true, keyboard: true, touch: true, lazyImages: true, lazyOnDemand: true, nextTrigger: null, nextHint: "Next (" + (rtl ? "Left" : "Right") + " Arrow)", previousTrigger: null, previousHint: "Previous (" + (rtl ? "Right" : "Left") + " Arrow)", indicators: null }; this.options = $.extend({}, this.defaults, options); this.paused = null; this.interval = null; this.sliding = null; this.$items = null; this.keyboardTriggered = null; this.translationDuration = null; this.$nextTrigger = this.options.nextTrigger ? $(this.options.nextTrigger) : this.$element.children("button.forward"); this.$previousTrigger = this.options.previousTrigger ? $(this.options.previousTrigger) : this.$element.children("button:not(.forward)"); this.$indicators = this.options.indicators ? $(this.options.indicators) : this.$element.find("> ol > li"); this.id = this.$element.attr("id") || "carousel-" + $.pseudoUnique(); var self = this, activeIndex = this.activeindex(); // Hide the previous button if no wrapping. if (!this.options.wrap) { if (activeIndex === 0) { this.$previousTrigger.attr({ "aria-hidden": true, "hidden": true }); } } // Hide both if one item. if (this.$items.length === 1) { this.$previousTrigger.attr({ "aria-hidden": true, "hidden": true }); this.$nextTrigger.attr({ "aria-hidden": true, "hidden": true }); } // Add the css class to support fade. this.options.mode === "fade" && this.$element.addClass("carousel-fade"); if (this.options.lazyImages && !this.options.lazyOnDemand) { $(w).on("load", $.proxy(this.lazyimages), this); } // Add a11y features. this.$element.attr({ "role": "listbox", "aria-live": "polite", "id": this.id }); this.$element.children("figure").each(function (index) { var active = index === activeIndex; $(this).attr({ "role": "option", "aria-selected": active, "tabindex": active ? 0 : -1 }); }); // Find and add a11y to controls. var $controls = this.$nextTrigger.add(this.$previousTrigger); $controls.each(function () { var $this = $(this).attr({ "tabindex": 0, "aria-controls": self.id }); !$this.is("button") ? $this.attr({ "role": "button" }) : $this.attr({ "type": "button" }); if (!$this.find(".visuallyhidden").length) { $("<span/>").addClass("visuallyhidden") .html(this === self.$nextTrigger.get(0) ? self.options.nextHint : self.options.previousHint) .appendTo($this); } }); // Find and a11y indicators. this.$indicators.attr({ "role": "button", "aria-controls": self.id }).eq(activeIndex).addClass("active"); // Bind events // Not namespaced as we want to keep behaviour when not using data api. if (this.options.pause === "hover") { // Bind the mouse enter/leave events. if (!$.support.touchEvents && !$.support.pointerEvents) { this.$element.on(emouseenter, $.proxy(this.pause, this)) .on(emouseleave, $.proxy(this.cycle, this)); } } if (this.options.touch) { // You always have to pass the third parameter if setting data. this.$element.on("swipe.carousel", { touchAction: "pan-y" }, true) .on("swipemove.carousel", $.proxy(this.swipemove, this)) .on("swipeend.carousel", $.proxy(this.swipeend, this)); } if (this.options.keyboard) { this.$element.on(ekeydown, $.proxy(this.keydown, this)); } $(document).on(this.options.keyboard ? [eclick, ekeydown].join(" ") : eclick, "[aria-controls=" + this.id + "]", $.proxy(this.click, this)); }; Carousel.prototype.activeindex = function () { var $activeItem = this.$element.find(".carousel-active"); this.$items = $activeItem.parent().children("figure"); return this.$items.index($activeItem); }; Carousel.prototype.cycle = function (event) { if (!event) { // Flag false when there's no event. this.paused = false; } if (this.interval) { w.clearInterval(this.interval); } if (this.options.interval && !this.paused) { // Cycle to the next item on the set interval this.interval = w.setInterval($.proxy(this.next, this), this.options.interval); } // Return the carousel for chaining. return this; }; Carousel.prototype.to = function (position) { var activePosition = this.activeindex(), self = this; if (position > (this.$items.length - 1) || position < 0) { return false; } if (this.sliding) { // Fire the slid event. return this.$element.one(eslid, function () { // Reset the position. self.to(position); }); } if (activePosition === position) { return this.pause().cycle(); } return this.slide(position > activePosition ? "next" : "prev", $(this.$items[position])); }; Carousel.prototype.pause = function (event) { if (!event) { // Mark as paused this.paused = true; } // Ensure that transition end is triggered. if (this.$element.find(".next, .prev").length && $.support.transition) { this.$element.trigger($.support.transition.end); this.cycle(true); } // Clear the interval and return the carousel for chaining. this.interval = w.clearInterval(this.interval); return this; }; Carousel.prototype.next = function () { if (this.sliding) { return false; } return this.slide("next"); }; Carousel.prototype.prev = function () { if (this.sliding) { return false; } return this.slide("prev"); }; Carousel.prototype.slide = function (type, next) { var $activeItem = this.$element.children("figure.carousel-active"), $nextItem = next || $activeItem[type]("figure"), isCycling = this.interval, isNext = type === "next", direction = isNext ? "left" : "right", fallback = isNext ? "first" : "last", self = this, slideEvent, slidEvent; if (isCycling) { // Pause if cycling. this.pause(); } // Work out which item to slide to. if (!$nextItem.length) { if (!this.options.wrap) { return false; } $nextItem = this.$element.children("figure")[fallback](); } if ($nextItem.hasClass("carousel-active")) { return (this.sliding = false); } // Trigger the slide event with positional data. slideEvent = $.Event(eslide, { relatedTarget: $nextItem[0], direction: direction }); this.$element.trigger(slideEvent); if (slideEvent.isDefaultPrevented()) { return false; } if (this.options.lazyImages && this.options.lazyOnDemand) { // Load the next image. this.lazyimages.call($nextItem); } // Good to go? Then let's slide. this.sliding = true; if (isCycling) { this.pause(); } this.$element.one(eslid, function () { // Hide the correct trigger if necessary. if (!self.options.wrap) { var activePosition = self.activeindex(); if (self.$items && activePosition === self.$items.length - 1) { self.$nextTrigger.attr({ "aria-hidden": true, "hidden": true }); self.$previousTrigger.removeAttr("aria-hidden").removeAttr("hidden"); if (self.keyboardTriggered) { self.$previousTrigger.focus(); self.keyboardTriggered = false; } } else if (self.$items && activePosition === 0) { self.$previousTrigger.attr({ "aria-hidden": true, "hidden": true }); self.$nextTrigger.show().removeAttr("aria-hidden").removeAttr("hidden"); if (self.keyboardTriggered) { self.$nextTrigger.focus(); self.keyboardTriggered = false; } } else { self.$nextTrigger.removeAttr("aria-hidden").removeAttr("hidden"); self.$previousTrigger.removeAttr("aria-hidden").removeAttr("hidden"); self.keyboardTriggered = false; } } // Highlight the correct indicator. self.$indicators.removeClass("active") .eq(self.activeindex()).addClass("active"); }); var complete = function () { if (self.$items) { // Clear the transition properties if set. self.$items.removeClass("swiping").css({ "transition-duration": "" }); } $activeItem.removeClass(["carousel-active", direction].join(" ")) .attr({ "aria-selected": false, "tabIndex": -1 }); $nextItem.removeClass([type, direction].join(" ")).addClass("carousel-active") .attr({ "aria-selected": true, "tabIndex": 0 }); self.sliding = false; slidEvent = $.Event(eslid, { relatedTarget: $nextItem[0], direction: direction }); self.$element.trigger(slidEvent); }; // Force reflow. $nextItem.addClass(type).redraw(); // Do the slide. $activeItem.addClass(direction); $nextItem.addClass(direction); // Clear the added css. if (this.$items) { this.$items.each(function () { $(this).removeClass("swipe swipe-next").css({ "left": "", "right": "", "opacity": "" }); }); } // We use ensure here as IOS7 can sometimes not fire // the event if a scroll is accidentally triggered. $activeItem.onTransitionEnd(complete).ensureTransitionEnd(); // Restart the cycle. if (isCycling) { this.cycle(); } return this; }; Carousel.prototype.keydown = function (event) { if (/input|textarea/i.test(event.target.tagName)) { return; } var which = event && event.which; if (which === keys.LEFT || which === keys.RIGHT) { this.keyboardTriggered = true; event.preventDefault(); event.stopPropagation(); // Seek out the correct direction indicator, shift, and focus. switch (which) { case keys.LEFT: if (rtl) { this.next(); this.$nextTrigger.focus(); } else { this.prev(); this.$previousTrigger.focus(); } break; case keys.RIGHT: if (rtl) { this.prev(); this.$previousTrigger.focus(); } else { this.next(); this.$nextTrigger.focus(); } break; } } }; Carousel.prototype.click = function (event) { if (!event) { return; } var which = event.which; if (which && which !== 1) { if (which === keys.SPACE || which === keys.ENTER) { this.keyboardTriggered = true; } else { return; } } event.preventDefault(); event.stopPropagation(); var $this = $(event.target); if ($this.hasClass("forward")) { this.next(); } else if ($this.is("button")) { this.prev(); } else { this.to($this.index()); } }; Carousel.prototype.swipemove = function (event) { if (this.sliding) { return; } this.pause(); // Left is next. var isNext = event.delta.x < 0, type = isNext ? (rtl ? "prev" : "next") : (rtl ? "next" : "prev"), fallback = isNext ? (rtl ? "last" : "first") : (rtl ? "first" : "last"), activePosition = this.activeindex(), $activeItem = this.$items.eq(activePosition), $nextItem = $activeItem[type]("figure"); if (this.$items.length === 1) { return; } if (!$nextItem.length) { if (!this.options.wrap) { return; } $nextItem = this.$element.children("figure")[fallback](); } this.$items.not($activeItem).not($nextItem).removeClass("swipe swiping swipe-next").css({ "left": "", "right": "", "opacity": "" }); if ($nextItem.hasClass("carousel-active")) { return; } if (this.options.lazyImages && this.options.lazyOnDemand) { // Load the next image. this.lazyimages.call($nextItem); } // Get the distance swiped as a percentage. var width = $activeItem.width(), percent = parseFloat((event.delta.x / width) * 100), diff = isNext ? 100 : -100; if (rtl) { percent *= -1; } // This is crazy complicated. Basically swipe behaviour change direction in rtl // So you need to handle that. this.$element.addClass("no-transition"); if (this.options.mode === "slide") { if (rtl) { $activeItem.addClass("swiping").css({ "right": percent + "%" }); $nextItem.addClass("swipe swipe-next").css({ "right": (percent - diff) + "%" }); } else { $activeItem.addClass("swiping").css({ "left": percent + "%" }); $nextItem.addClass("swipe swipe-next").css({ "left": (percent + diff) + "%" }); } } else { $activeItem.addClass("swipe").css({ "opacity": 1 - Math.abs((percent / 100)) }); $nextItem.addClass("swipe swipe-next"); } }; Carousel.prototype.swipeend = function (event) { if (this.sliding || !this.$element.hasClass("no-transition")) { return; } var direction = event.direction, method = "next"; if (direction === "right") { method = "prev"; } // Re-enable the transitions. this.$element.removeClass("no-transition"); if (supportTransition) { // Trim the animation duration based on the current position. var activePosition = this.activeindex(), $activeItem = this.$items.eq(activePosition); if (!this.translationDuration) { this.translationDuration = parseFloat($activeItem.css("transition-duration")); } // Get the distance and turn it into a percentage // to calculate the duration. Whichever is lowest is used. var width = $activeItem.width(), percentageTravelled = (Math.abs(event.delta.x) / width) * 100, swipeDuration = (((event.duration / 1000) * 100) / percentageTravelled), newDuration = (((100 - percentageTravelled) / 100) * (Math.min(this.translationDuration, swipeDuration))); // Set the new temporary duration. this.$items.each(function () { $(this).css({ "transition-duration": newDuration + "s" }); }); } this.cycle(); this.slide(method, $(this.$items.filter(".swipe-next"))); }; Carousel.prototype.lazyimages = function () { if (!this.data("lazyLoaded")) { this.find("img[data-src]").each(function () { if (this.src.length === 0) { this.src = this.getAttribute("data-src"); } }); this.data("lazyLoaded", true); } }; // No conflict. var old = $.fn.carousel; // Plug-in definition $.fn.carousel = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.carousel"), opts = typeof options === "object" ? options : null; if (!data) { // Check the data and reassign if not present. $this.data("r.carousel", (data = new Carousel(this, opts))); } if (typeof options === "number") { // Cycle to the given number. data.to(options); } else if (typeof options === "string" && /(cycle|pause|next|prev)/.test(options) || (options = opts && opts.slide)) { data[options](); } else if (data.options.interval) { data.pause().cycle(); } }); }; // Set the public constructor. $.fn.carousel.Constructor = Carousel; $.fn.carousel.noConflict = function () { $.fn.carousel = old; return this; }; // Data API var init = function () { $(".carousel").each(function () { var $this = $(this), loaded = $this.data("r.carouselLoaded"); if (!loaded) { $this.data("r.carouselLoaded", true); $this.carousel($.getDataOptions($this, "carousel")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_CAROUSEL = true; }(jQuery, window, ".r.carousel", ".data-api")); /* * Responsive Conditional */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_CONDITIONAL) { return; } // General variables and methods. var eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eresize = ["resize" + ns, "orientationchange" + ns].join(" "), eload = "load" + ns, eloaded = "loaded" + ns, eerror = "error" + ns; // AutoSize class definition var Conditional = function (element, options) { this.$element = $(element); this.defaults = { xxs: null, xs: null, s: null, m: null, l: null, fallback: null, errorHint: "<p>An error has occured.</p>" }; this.cache = {}; this.options = $.extend({}, this.defaults, options); this.currentGrid = null; this.currentTarget = null; this.loading = null; // Bind events. $(w).on(eresize, $.debounce($.proxy(this.resize, this), 50)); // First Run this.resize(); }; Conditional.prototype.resize = function () { var current = $.support.currentGrid(), grid = current.grid, range = current.range; // Check to see if we need to cache the current content. if (!this.options.fallback) { for (var level in range) { if (range.hasOwnProperty(level)) { var name = range[level]; if (!this.options[name]) { this.options[name] = "fallback"; this.cache[name] = this.$element.html(); } } } } if (this.currentGrid !== grid) { this.currentGrid = grid; var self = this, target = this.options[grid] || this.options.fallback; if (target && target !== this.currentTarget) { this.currentTarget = target; var loadEvent = $.Event(eload); this.$element.trigger(loadEvent); if (this.loading || loadEvent.isDefaultPrevented()) { return; } this.loading = true; // First check the cache. if (this.cache[this.currentGrid]) { this.$element.empty().html(this.cache[this.currentGrid]); this.loading = false; this.$element.trigger($.Event(eloaded, { relatedTarget: self.$element[0], loadTarget: target, grid: this.currentGrid })); } else { this.$element.empty().load(target, null, function (responseText, textStatus) { // Handle errors. if (textStatus === "error") { self.$element.trigger($.Event(eerror, { relatedTarget: self.$element[0], loadTarget: target, grid: self.currentGrid })); self.$element.html(self.options.errorHint); self.loading = false; return; } var selector, off = target.indexOf(" "); if (off >= 0) { selector = $.trim(target.slice(off)); } // Cache the result so no further requests are made. This uses the internal `parseHTML` // method so be aware that could one day change. self.cache[grid] = selector ? $("<div>").append($.parseHTML(responseText)).find(selector).wrap("<div>").parent().html() : responseText; self.loading = false; self.$element.trigger($.Event(eloaded, { relatedTarget: self.$element[0], loadTarget: target, grid: self.currentGrid })); }); } } } }; // No conflict. var old = $.fn.conditional; // Plug-in definition $.fn.conditional = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.conditional"), opts = typeof options === "object" ? $.extend({}, options) : null; if (!data) { // Check the data and reassign if not present. $this.data("r.conditional", (data = new Conditional(this, opts))); } if (options === "resize") { data.resize(); } }); }; // Set the public constructor. $.fn.conditional.Constructor = Conditional; $.fn.conditional.noConflict = function () { $.fn.conditional = old; return this; }; // Data API var init = function () { $(":attrStart(data-conditional)").each(function () { var $this = $(this), loaded = $this.data("r.conditionalLoaded"); if (!loaded) { $this.data("r.conditionalLoaded", true); $this.conditional($.getDataOptions($this, "conditional")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_CONDITIONAL = true; }(jQuery, window, ".r.conditional", ".data-api")); /* * Responsive Dismiss */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_DISMISS) { return; } // General variables. var eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eclick = "click", edismiss = "dismiss" + ns, edismissed = "dismissed" + ns; // Dismiss class definition var Dismiss = function (element, options) { this.defaults = { closeHint: "Click to close" }; this.options = $.extend({}, this.defaults, options); this.$element = $(element).attr({ "type": "button" }); this.$target = this.$element.closest(options.target); this.dismissing = null; // A11y goodness. if (this.$element.is("button")) { $(element).attr({ "type": "button" }); } if (this.$target.hasClass("alert")) { this.$target.attr({ "role": "alert" }); } if (!this.$element.find(".visuallyhidden").length) { $("<span/>").addClass("visuallyhidden") .html(this.options.closeHint) .appendTo(this.$element); } // Bind events this.$element.on(eclick, $.proxy(this.click, this)); }; Dismiss.prototype.close = function () { var dismissEvent = $.Event(edismiss), $target = this.$target, self = this, complete = function () { self.dismissing = false; $target.removeClass("fade-out").attr({ "aria-hidden": true, "hidden": true, "tabindex": -1 }); self.$element.trigger($.Event(edismissed)); }; this.$element.trigger(dismissEvent); if (this.dismissing || dismissEvent.isDefaultPrevented()) { return; } this.dismissing = true; $target.addClass("fade-in fade-out") .redraw() .removeClass("fade-in"); // Do our callback this.$target.onTransitionEnd(complete); }; Dismiss.prototype.click = function (event) { event.preventDefault(); this.close(); }; // No conflict. var old = $.fn.dismiss; // Plug-in definition $.fn.dismiss = function (options) { return this.each(function () { var $this = $(this), data = $this.data("dismiss"); if (!data) { // Check the data and reassign if not present. $this.data("dismiss", (data = new Dismiss(this, options))); } // Close the element. if (options === "close") { data.close(); } }); }; // Set the public constructor. $.fn.dismiss.Constructor = Dismiss; $.fn.dismiss.noConflict = function () { $.fn.dismiss = old; return this; }; // Data API var init = function () { $("button[data-dismiss-target]").each(function () { var $this = $(this), loaded = $this.data("r.dismissLoaded"); if (!loaded) { $this.data("r.dismissLoaded", true); $this.dismiss($.getDataOptions($this, "dismiss")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_DISMISS = true; }(jQuery, window, ".r.dismiss", ".data-api")); /* * Responsive Dropdown */ /*jshint expr:true*/ /*global jQuery*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_DROPDOWN) { return; } // General variables. var supportTransition = w.getComputedStyle && $.support.transition, rtl = $.support.rtl, eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eclick = "click", ekeydown = "keydown", eshow = "show" + ns, eshown = "shown" + ns, ehide = "hide" + ns, ehidden = "hidden" + ns; var keys = { SPACE: 32, LEFT: 37, RIGHT: 39 }; // The Dropdown class definition var Dropdown = function (element, options) { this.$element = $(element); this.$target = $(options.target); this.defaults = { dimension: "height" }; this.options = $.extend({}, this.defaults, options); this.$parent = null; this.transitioning = null; this.endSize = null; if (this.options.parent) { this.$parent = this.$target.closest(this.options.parent); } // Add accessibility features. if (this.$parent) { this.$parent.attr({ "role": "tablist", "aria-multiselectable": "true" }) .find("div:not(.collapse,.accordion-body)").attr("role", "presentation"); } else { $(".accordion").find("div:not(.collapse,.accordion-body)").addBack().attr("role", "presentation"); } var id = this.$element.attr("id") || "dropdown-" + $.pseudoUnique(), paneId = this.$target.attr("id") || "dropdown-" + $.pseudoUnique(), active = !this.$target.hasClass("collapse"); this.$element.attr({ "id": id, "role": "tab", "aria-controls": paneId, "aria-selected": active, "aria-expanded": active, "tabindex": 0 }); this.$target.attr({ "id": paneId, "role": "tabpanel", "aria-labelledby": id, "aria-hidden": !active, "hidden": !active, "tabindex": active ? 0 : -1 }); // Bind events. this.$element.on(eclick, $.proxy(this.click, this)); this.$element.on(ekeydown, $.proxy(this.keydown, this)); }; Dropdown.prototype.show = function () { if (this.transitioning || this.$target.hasClass("expand")) { return; } this.transitioning = true; var self = this, dimension = this.options.dimension, size, $actives = []; if (this.$parent) { // Get all the related open panes. $actives = this.$parent.find(" > [role=presentation] > [role=presentation]").children("[role=tab]"); $actives = $.grep($actives, function (a) { var data = $(a).data("r.dropdown"), $target = data && data.$target; return $target && $target.hasClass("dropdown-group") && !$target.hasClass("collapse") && data.$parent && data.$parent[0] === self.$parent[0]; }); } // Set the height/width to zero then to the height/width // so animation can take place. this.$target[dimension](0); if (supportTransition) { // Calculate the height/width. this.$target[dimension]("auto").attr({ "aria-hidden": false, "hidden": false }); this.$target.find("[tabindex]:not(.collapse)").attr({ "aria-hidden": false, "hidden": false }); size = w.getComputedStyle(this.$target[0])[dimension]; // Reset to zero and force repaint. this.$target[dimension](0).redraw(); } this.$target[dimension](size || ""); this.transition("removeClass", $.Event(eshow), eshown); if ($actives && $actives.length) { $.each($actives, function () { $(this).dropdown("hide"); }); } }; Dropdown.prototype.hide = function () { if (this.transitioning || this.$target.hasClass("collapse")) { return; } this.transitioning = true; // Reset the height/width and then reduce to zero. var dimension = this.options.dimension, size; if (supportTransition) { // Set the height to auto, calculate the height/width and reset. size = w.getComputedStyle(this.$target[0])[dimension]; // Reset the size and force repaint. this.$target[dimension](size).redraw(); // Force reflow ; } this.$target.removeClass("expand"); this.$target[dimension](0); this.transition("addClass", $.Event(ehide), ehidden); }; Dropdown.prototype.toggle = function () { if (this.transitioning) { return; } // Run the correct command based on the presence of the class "collapse". this[this.$target.hasClass("collapse") ? "show" : "hide"](); }; Dropdown.prototype.transition = function (method, startEvent, completeEvent) { var self = this, doShow = method === "removeClass", complete = function () { // The event to expose. var eventToTrigger = $.Event(completeEvent); // Ensure the height/width is set to auto. self.$target.removeClass("trans")[self.options.dimension](""); // Set the correct aria attributes. self.$target.attr({ "aria-hidden": !doShow, "hidden": !doShow, "tabindex": doShow ? 0 : -1 }); var $tab = $("#" + self.$target.attr("aria-labelledby")).attr({ "aria-selected": doShow, "aria-expanded": doShow }); if (doShow) { $tab.focus(); } // Toggle any children. self.$target.find("[tabindex]:not(.collapse)").attr({ "aria-hidden": !doShow, "hidden": !doShow, "tabindex": doShow ? 0 : -1 }); self.transitioning = false; self.$element.trigger(eventToTrigger); }; this.$element.trigger(startEvent); if (startEvent.isDefaultPrevented()) { return; } // Remove or add the expand classes. this.$target[method]("collapse"); this.$target[startEvent.type === "show" ? "addClass" : "removeClass"]("trans expand"); this.$target.onTransitionEnd(complete); }; Dropdown.prototype.click = function (event) { event.preventDefault(); event.stopPropagation(); this.toggle(); }; Dropdown.prototype.keydown = function (event) { if (/input|textarea/i.test(event.target.tagName)) { return; } var which = event.which; if (which === keys.SPACE || which === keys.LEFT || which === keys.RIGHT) { event.preventDefault(); event.stopPropagation(); var $this = $(event.target); if (which === keys.SPACE) { this.toggle(); return; } var $parent = this.options.parent ? $this.closest("[role=tablist]") : $this.closest(".accordion"), $items = $parent.find(" > [role=presentation] > [role=presentation]").children("[role=tab]"), index = $items.index($items.filter(":focus")), length = $items.length; if (which === keys.LEFT) { rtl ? index += 1 : index -= 1; } else if (which === keys.RIGHT) { rtl ? index -= 1 : index += 1; } // Ensure that the index stays within bounds. if (index === length) { index = 0; } if (index < 0) { index = length - 1; } $($items.eq(index)).data("r.dropdown").show(); } }; // No conflict. var old = $.fn.dropdown; // Plug-in definition $.fn.dropdown = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.dropdown"), opts = typeof options === "object" ? $.extend({}, options) : null; if (!data) { // Check the data and reassign if not present. $this.data("r.dropdown", (data = new Dropdown(this, opts))); } // Run the appropriate function if a string is passed. if (typeof options === "string" && /(show|hide|toggle)/.test(options)) { data[options](); } }); }; // Set the public constructor. $.fn.dropdown.Constructor = Dropdown; $.fn.dropdown.noConflict = function () { $.fn.dropdown = old; return this; }; // Data API var init = function () { $(":attrStart(data-dropdown)").each(function () { var $this = $(this), loaded = $this.data("r.dropdownLoaded"); if (!loaded) { $this.data("r.dropdownLoaded", true); $this.dropdown($.getDataOptions($this, "dropdown")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_DROPDOWN = true; }(jQuery, window, ".r.dropdown", ".data-api")); /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_MODAL) { return; } var $window = $(w), $body = $("body"), $overlay = $("<div/>").attr({ "role": "document" }).addClass("modal-overlay modal-loader fade-out"), $modal = $("<div/>").addClass("modal fade-out").appendTo($overlay), $header = $("<div/>").addClass("modal-header fade-out"), $footer = $("<div/>").addClass("modal-footer fade-out"), $close = $("<button/>").attr({ "type": "button" }).addClass("modal-close fade-out"), $prev = $("<button/>").attr({ "type": "button" }).addClass("modal-direction prev fade-out"), $next = $("<button/>").attr({ "type": "button" }).addClass("modal-direction next fade-out"), $placeholder = $("<div/>").addClass("modal-placeholder"), // Events eready = "ready" + ns + da, echanged = "domchanged" + ns + da, eresize = ["resize" + ns, "orientationchange" + ns].join(" "), eclick = "click" + ns, ekeydown = "keydown" + ns, efocusin = "focusin" + ns, eshow = "show" + ns, eshown = "shown" + ns, ehide = "hide" + ns, ehidden = "hidden" + ns, eerror = "error" + ns, rtl = $.support.rtl, currentGrid = $.support.currentGrid(), keys = { ESCAPE: 27, LEFT: 37, RIGHT: 39 }, lastScroll = 0, protocol = w.location.protocol.indexOf("http") === 0 ? w.location.protocol : "http:", // Regular expression. rexternalHost = new RegExp("//" + w.location.host + "($|/)"), rimage = /(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|ti(ff|f)|webp|svg)((\?|#).*)?$)/i, // Taken from jQuery. rhash = /^#.*$/, // Altered to only match beginning. rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/; var Modal = function (element, options) { this.$element = $(element); this.defaults = { modal: null, external: false, group: null, image: false, immediate: false, iframe: false, iframeScroll: true, keyboard: true, touch: true, next: ">", nextHint: "Next (" + (rtl ? "Left" : "Right") + " Arrow)", previous: "<", previousHint: "Previous (" + (rtl ? "Right" : "Left") + " Arrow)", closeHint: "Close (Esc)", errorHint: "<p>An error has occured.</p>", mobileTarget: null, mobileViewportWidth: "xs", fitViewport: true }; this.options = $.extend({}, this.defaults, options); this.title = null; this.description = null; this.isShown = null; this.$group = null; // Make a list of grouped modal targets. if (this.options.group) { this.$group = $(this.options.group); } // Bind events. // Ensure script works if loaded at the top of the page. if ($body.length === 0) { $body = $("body"); } this.$element.on(eclick, this.click.bind(this)); var onResize = $.debounce(this.resize.bind(this), 15); $(w).off(eresize).on(eresize, onResize); if (this.options.immediate) { this.show(); } }; Modal.prototype.click = function (event) { event.preventDefault(); // Check to see if there is a current instance running // so we can cater for nested triggers. var $current = $modal.data("currentModal"); if ($current && $current[0] !== this.$element[0]) { var complete = function () { // Timeout > time required to fix flash error for IE9. w.setTimeout(function () { this.show(true); }.bind(this), 150); }.bind(this); $current.data("r.modal").toggleModal(true, true); $modal.onTransitionEnd(complete); return; } this.show(); }; Modal.prototype.show = function (noOverlay) { if (this.isShown) { return; } var showEvent = $.Event(eshow); this.$element.trigger(showEvent); if (showEvent.isDefaultPrevented()) { return; } this.isShown = true; // If the trigger has a mobile target and the viewport is smaller than the mobile limit // then redirect to that page instead. if (this.options.mobileTarget) { var width = this.options.mobileViewportWidth; // Handle numeric width. if (typeof width === "number" && width >= $window.width()) { w.location.href = this.options.mobileTarget; return; } // Handle specific range. if (typeof width === "string") { var index = $.inArray(width, currentGrid.range); if (currentGrid.index <= index && index > -1) { w.location.href = this.options.mobileTarget; return; } } } if (!noOverlay) { this.overlay(); return; } this.toggleModal(); }; Modal.prototype.hide = function () { // Destroy the modal this.toggleModal(true); }; Modal.prototype.overlay = function () { // Add the overlay to the body if not done already. if (!$(".modal-overlay").length) { $body.append($overlay); } // Fade out. if ($overlay.hasClass("fade-in")) { var complete = function () { $modal.removeData("currentModal").removeAttr("tabindex"); $.toggleBodyLock(); $overlay.attr("hidden", " "); $window.scrollTop(lastScroll); }.bind(this); $overlay.removeClass("fade-in").onTransitionEnd(complete); return; } // Fade in and fire modal. if ($("html").attr("data-lock") === undefined) { lastScroll = $window.scrollTop(); $.toggleBodyLock(); } $overlay.removeAttr("hidden") .redraw() .addClass("fade-in") .onTransitionEnd(function () { this.toggleModal(); }.bind(this)); }; Modal.prototype.toggleModal = function (destroy, nested) { var complete; if (!destroy) { complete = function () { var $autofocus = $modal.find("[autofocus]"); $body.attr({ "tabindex": -1 }); $modal.data("currentModal", this.$element).attr({ "tabindex": 0 }); $autofocus.length ? $autofocus.focus() : $modal.focus(); // Ensure that focus is maintained within the modal. $(document).off(efocusin).on(efocusin, this.focus.bind(this)); // Bind the keyboard and touch actions. if (this.options.keyboard) { $(document).off(ekeydown).on(ekeydown, this.keydown.bind(this)); } if (this.options.group) { if (this.options.touch) { $modal.off("swipe.modal").on("swipe.modal", true) .off("swipeend.modal").on("swipeend.modal", this.swipeend.bind(this)); } } $overlay.off(eclick).on(eclick, this.overlayclick.bind(this)); this.$element.trigger($.Event(eshown)); }.bind(this); // Create the modal contents. this.create(); $modal.onTransitionEnd(complete) .off(eclick).on(eclick, this.modalclick.bind(this)); return; } // We're destroying the current modal. if (!this.isShown) { return; } var hideEvent = $.Event(ehide); this.$element.trigger(hideEvent); if (hideEvent.isDefaultPrevented()) { return; } this.isShown = false; $overlay.removeClass("modal-loader"); $.each([$header, $footer, $close, $next, $prev, $modal], function () { this.removeClass("fade-in"); }); complete = function () { // Launch the next/pre grouped item. if (this.$sibling && this.$sibling.data("r.modal")) { this.destroy(true); this.$element.trigger($.Event(ehidden)); // Timeout > time required to fix flash error for IE9. w.setTimeout(function () { this.$sibling.data("r.modal").show(true); this.$sibling = null; }.bind(this), 150); return; } if (nested) { this.destroy(true); this.$element.trigger($.Event(ehidden)); return; } this.destroy(); this.$element.trigger($.Event(ehidden)); }.bind(this); // Destroy modal contents. $modal.onTransitionEnd(complete); }; Modal.prototype.create = function () { $overlay.addClass("modal-loader"); var isExternalUrl = function (url) { // Handle different host types. // Split the url into it's various parts. var locationParts = rurl.exec(url) || rurl.exec(protocol + url); if (locationParts === undefined || rhash.test(url)) { return false; } // Target is a local protocol. if (!locationParts || !locationParts[2] || rlocalProtocol.test(locationParts[1])) { return false; } // If the regex doesn't match return true . return !rexternalHost.test(locationParts[2]); }; var complete = function () { this.resize(); $.each([$header, $footer, $close, $next, $prev, $modal], function () { this.addClass("fade-in"); }); $modal.redraw(); $overlay.removeClass("modal-loader"); }.bind(this); var title = this.options.title, description = this.options.description, modal = this.options.modal, target = this.options.target, notHash = !rhash.test(this.options.target), external = isExternalUrl(target), local = !notHash && !external, $group = this.$group, nextText = this.options.next + "<span class=\"visuallyhidden\">" + this.options.nextHint + "</span>", prevText = this.options.previous + "<span class=\"visuallyhidden\">" + this.options.previousHint + "</span>", iframeScroll = this.options.iframeScroll, image = this.options.image || rimage.test(target), iframe = this.options.iframe || notHash && external ? !image : false, $iframeWrap = $("<div/>").addClass(iframeScroll ? "media media-scroll" : "media"), $content = $("<div/>").addClass("modal-content"); if ($group) { // Test to see if the grouped target have data. var $filtered = $group.filter(function () { return $(this).data("r.modal"); }); if ($filtered.length) { // Need to show next/prev. $next.html(nextText).prependTo($modal); $prev.html(prevText).prependTo($modal); } } // 1: Build the header if (title || !modal) { if (title) { var id = "modal-label-" + $.pseudoUnique(); $header.html("<div class=\"container\"><h2 id=\"" + id + "\">" + title + "</h2></div>") .appendTo($overlay.attr({ "aria-labelledby": id })); } if (!modal) { $close.html("x <span class=\"visuallyhidden\">" + this.options.closeHint + "</span>").appendTo($overlay); } } // 2: Build the footer if (description) { // Add footer text if necessary $footer.html("<div class=\"container\">" + description + "</div>") .appendTo($overlay); } // 3: Build the content if (local) { var $target = $(target); this.isLocalHidden = $target.is(":hidden"); $modal.addClass(this.options.fitViewport ? "container" : ""); $placeholder.detach().insertAfter($target); $target.detach().appendTo($content).removeClass("hidden").attr({ "aria-hidden": false, "hidden": false }); $content.appendTo($modal); // Fade in. complete(); } else { if (iframe) { $modal.addClass("modal-iframe"); // Normalize the src. var src = (isExternalUrl(target) && target.indexOf("http") !== 0) ? protocol + target : target, getMediaProvider = function (url) { var providers = { youtube: /youtu(be\.com|be\.googleapis\.com|\.be)/i, vimeo: /vimeo/i, vine: /vine/i, instagram: /instagram|instagr\.am/i, getty: /embed\.gettyimages\.com/i }; for (var p in providers) { if (providers.hasOwnProperty(p) && providers[p].test(url)) { return [p, "scaled"].join(" "); } } return false; }; // Have to add inline styles for older browsers. $("<iframe/>").attr({ "scrolling": iframeScroll ? "yes" : "no", "allowTransparency": true, "frameborder": 0, "hspace": 0, "vspace": 0, "webkitallowfullscreen": "", "mozallowfullscreen": "", "allowfullscreen": "" }).one("load error", function () { // Fade in. Can be slow but ensures concurrency. complete(); }).appendTo($iframeWrap).attr("src", src); // Test and add additional media classes. var mediaClasses = getMediaProvider(target) || ""; if (!mediaClasses) { $modal.addClass("iframe-full"); } $iframeWrap.addClass(mediaClasses).appendTo($modal); } else { if (image) { $modal.addClass("modal-image"); $("<img/>").one("load error", function () { // Fade in. complete(); }).appendTo($modal).attr("src", target); } else { $modal.addClass("modal-ajax"); $modal.addClass(this.options.fitViewport ? "container" : ""); // Standard ajax load. $content.load(target, null, function (responseText, textStatus) { if (textStatus === "error") { this.$element.trigger($.Event(eerror, { relatedTarget: $content[0] })); $content.html(this.options.errorHint); } $content.appendTo($modal); // Fade in. complete(); }.bind(this)); } } } }; Modal.prototype.destroy = function (noOverlay) { // Clean up the next/prev. $next.detach(); $prev.detach(); // Clean up the header/footer. $header.empty().detach(); $footer.empty().detach(); $close.detach(); // Remove label. $overlay.removeAttr("aria-labelledby"); if (!this.options.external && !$modal.is(".modal-iframe, .modal-ajax, .modal-image")) { // Put that kid back where it came from or so help me. $(this.options.target).addClass(this.isLocalHidden ? "hidden" : "") .attr({ "aria-hidden": this.isLocalHidden ? true : false, "hidden": this.isLocalHidden ? true : false }) .detach().insertAfter($placeholder); $placeholder.detach().insertAfter($overlay); } // Fix __flash__removeCallback' is undefined error in IE9. $modal.find("iframe").attr("src", ""); w.setTimeout(function () { $modal.removeClass("modal-iframe iframe-full modal-ajax modal-image container").css({ "max-height": "", "max-width": "" }).empty(); }.bind(this), 100); if (!noOverlay) { this.overlay(); } }; Modal.prototype.overlayclick = function (event) { if (this.options.modal) { return; } var closeTarget = $close[0], eventTarget = event.target; if (eventTarget === $modal[0] || $.contains($modal[0], eventTarget)) { return; } if (eventTarget === closeTarget) { this.hide(); return; } if (eventTarget === $overlay[0] || ($.contains($overlay[0], eventTarget))) { this.hide(); } }; Modal.prototype.modalclick = function (event) { var next = $next[0], prev = $prev[0], eventTarget = event.target; if (eventTarget === next || eventTarget === prev) { event.preventDefault(); event.stopPropagation(); this[eventTarget === next ? "next" : "prev"](); return; } if (this.options.modal) { if (eventTarget === $modal.find(this.options.modal)[0]) { event.preventDefault(); event.stopPropagation(); this.hide(); } } }; Modal.prototype.focus = function (event) { if (event.target !== $overlay[0] && !$.contains($overlay[0], event.target)) { var $newTarget = $modal.find("a, area, button, input, object, select, textarea, [tabindex]").first(); $newTarget.length ? $newTarget.focus() : $modal.focus(); return false; } return true; }; Modal.prototype.keydown = function (event) { if (this.options.modal) { return; } // Bind the escape key. if (event.which === keys.ESCAPE) { this.hide(); return; } // Bind the next/prev keys. if (this.options.group) { if (/input|textarea/i.test(event.target.tagName)) { return; } // Bind the left arrow key. if (event.which === keys.LEFT) { rtl ? this.next() : this.prev(); } // Bind the right arrow key. if (event.which === keys.RIGHT) { rtl ? this.prev() : this.next(); } } }; Modal.prototype.swipeend = function (event) { if (rtl) { this[(event.direction === "right") ? "prev" : "next"](); return; } this[(event.direction === "right") ? "next" : "prev"](); }; Modal.prototype.resize = function () { // Resize the modal var windowHeight = $window.height(), headerHeight = $header.length && $header.height() || 0, closeHeight = $close.length && $close.outerHeight() || 0, topHeight = closeHeight > headerHeight ? closeHeight : headerHeight, footerHeight = $footer.length && $footer.height() || 0, maxHeight = (windowHeight - (topHeight + footerHeight)) * 0.95; $(".modal-overlay").css({ "padding-top": topHeight, "padding-bottom": footerHeight }); if ($modal.hasClass("modal-image")) { $modal.children("img").css("max-height", maxHeight); } else if ($modal.hasClass("modal-iframe")) { // Calculate the ratio. var $iframe = $modal.find(".media > iframe"), iframeWidth = $iframe.width(), iframeHeight = $iframe.height(), ratio = iframeWidth / iframeHeight, maxWidth = maxHeight * ratio; // Set both to ensure there is no overflow. if ($iframe.parent().hasClass("scaled")) { $modal.css({ "max-height": maxHeight, "max-width": maxWidth }); } } else { var $content = $modal.children(".modal-content"); $.each([$modal, $content], function () { this.css({ "max-height": maxHeight }); }); } // Reassign the current grid. currentGrid = $.support.currentGrid(); }; Modal.prototype.direction = function (course) { if (!this.isShown) { return; } if (this.options.group) { var index = this.$group.index(this.$element), length = this.$group.length, position = course === "next" ? index + 1 : index - 1; if (course === "next") { if (position >= length || position < 0) { position = 0; } } else { if (position >= length) { position = 0; } if (position < 0) { position = length - 1; } } // Assign the sibling and destroy the current modal. this.$sibling = $(this.$group[position]); this.hide(); } }; Modal.prototype.next = function () { this.direction("next"); }; Modal.prototype.prev = function () { this.direction("prev"); }; // No conflict. var old = $.fn.modal; // Plug-in definition $.fn.modal = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.modal"), opts = typeof options === "object" ? $.extend({}, options) : {}; if (!opts.target) { opts.target = $this.attr("href"); } if (!data) { // Check the data and reassign if not present. $this.data("r.modal", (data = new Modal(this, opts))); } // Run the appropriate function if a string is passed. if (typeof options === "string" && /(show|hide|next|prev)/.test(options)) { data[options](); } }); }; // Set the public constructor. $.fn.modal.Constructor = Modal; $.fn.modal.noConflict = function () { $.fn.modal = old; return this; }; // Data API var init = function () { $(":attrStart(data-modal)").each(function () { var $this = $(this), loaded = $this.data("r.modalLoaded"); if (!loaded) { $this.data("r.modalLoaded", true); $this.modal($.getDataOptions($this, "modal")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged, eshown].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_MODAL = true; }(jQuery, window, ".r.modal", ".data-api")); /* * Responsive Navigation */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_NAVIGATION) { return; } // General variables and methods. var $window = $(w), eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), emodalShow = "show.r.modal" + da, eclick = "click" + ns, efocusin = "focusin" + ns, ekeydown = "keydown" + ns, eshow = "show" + ns, eshown = "shown" + ns, ehide = "hide" + ns, ehidden = "hidden" + ns; var keys = { SPACE: 32, ESCAPE: 27 }; // The Navigation class definition var Navigation = function (element) { this.$element = $(element).addClass("navigation"); this.defaults= { start: "xxs", end: "l" }; this.$button = this.$element.children().first(); this.transitioning = false; this.lastScroll = 0; if (!this.$button.length) { this.$button = $("<button/>").text("Menu").prependTo(this.$element); } var id = this.$element.attr("id") || "navigation-" + $.pseudoUnique(); this.$element.attr({ "id": id, "role": "navigation" }); this.$button.attr({ "aria-controls": id, "aria-expanded": false }); // Clone and add the nav to the body so it is accessible. this.$clone = this.$element.clone().removeAttr("id data-navigation") .removeClass("canvas-navigation") .addClass("visuallyhidden"); this.$clone.children("button").first().remove(); this.$clone.appendTo("body"); // Bind events. this.$button.on(eclick, this.click.bind(this)); $(document).on(efocusin, this.focus.bind(this)).on(emodalShow, function () { this.hide(true); }.bind(this)); }; Navigation.prototype.toggle = function () { this[this.$element.hasClass("open") ? "hide" : "show"](); }; Navigation.prototype.show = function () { if (this.transitioning) { return; } this.transitioning = true; var showEvent = $.Event(eshow), shownEvent = $.Event(eshown); this.$element.trigger(showEvent); if (showEvent.isDefaultPrevented()) { return; } var complete = function () { this.transitioning = false; this.$button.attr({ "aria-expanded": true }); $(document).on(ekeydown, this.keydown.bind(this)); this.$element.trigger(shownEvent); }.bind(this); this.lastScroll = $window.scrollTop(); $.toggleBodyLock(); // Do our callback this.$element.addClass("open visible").onTransitionEnd(complete); }; Navigation.prototype.hide = function (noLock) { if (this.transitioning) { return; } this.transitioning = true; var hideEvent = $.Event(ehide), hiddenEvent = $.Event(ehidden); this.$element.trigger(hideEvent); if (hideEvent.isDefaultPrevented()) { return; } var complete = function () { this.$element.removeClass("visible"); this.$button.attr({ "aria-expanded": false }); this.transitioning = false; // Unbind the handlers $(document).off(ekeydown); this.$element.trigger(hiddenEvent); }.bind(this); if (!noLock) { $.toggleBodyLock(); $window.scrollTop(this.lastScroll); } // Do our callback this.$element.removeClass("open") .onTransitionEnd(complete) .ensureTransitionEnd(); }; Navigation.prototype.click = function () { this.toggle(); }; Navigation.prototype.keydown = function (event) { if (event.which === keys.ESCAPE && this.$element.hasClass("open")) { this.hide(); } }; Navigation.prototype.focus = function (event) { // Ensure that focus is maintained within the menu. if (this.$element.hasClass("open")) { if (!event.shiftKey && event.target !== this.$element[0] && !$.contains(this.$element[0], event.target)) { this.$button.focus(); return false; } } else { // Ensure that focus is moved from the clone to the menu. if (!event.shiftKey && (event.target === this.$clone[0] || $.contains(this.$clone[0], event.target))) { this.$button.focus().click(); return false; } } return true; }; // No conflict. var old = $.fn.navigation; // Plug-in definition $.fn.navigation = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.navigation"); if (!data) { // Check the data and reassign if not present. $this.data("r.navigation", (data = new Navigation(this))); } // Run the appropriate function is a string is passed. if (typeof options === "string" && /(show|hide)/.test(options)) { data[options](); } }); }; // Set the public constructor. $.fn.navigation.Constructor = Navigation; $.fn.navigation.noConflict = function () { $.fn.navigation = old; return this; }; // Data API var init = function () { $("nav[data-navigation]").each(function () { var $this = $(this), loaded = $this.data("r.navigationLoaded"); if (!loaded) { $this.data("r.navigationLoaded", true); $this.navigation(); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_NAVIGATION = true; }(jQuery, window, ".r.navigation", ".data-api")); /* * Responsive Tables */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_TABLE) { return; } // General variables and methods. var eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eadd = "add" + ns, eadded = "added" + ns; // Table class definition. var Table = function (element) { this.$element = $(element).addClass("table-list"); this.$thead = this.$element.find("thead"); this.$tfoot = this.$element.find("tfoot"); this.$tbody = this.$element.find("tbody"); this.$headerColumns = this.$thead.find("th"); this.$footerColumns = this.$tfoot.find("th"); this.$bodyRows = this.$tbody.find("tr"); this.isAdded = null; this.add(); }; Table.prototype.add = function () { if (this.isAdded) { return; } var self = this, addEvent = $.Event(eadd), complete = function () { self.$element.trigger($.Event(eadded)); }; this.$element.trigger(addEvent); if (addEvent.isDefaultPrevented()) { return; } this.isAdded = true; $.each(this.$bodyRows, function () { $(this).find("th, td").each(function (index) { var $this = $(this), theadAttribute = $(self.$headerColumns[index]).text(); $this.attr("data-thead", theadAttribute); if (self.$tfoot.length) { var tfootAttribute = $(self.$footerColumns[index]).text(); $this.attr("data-tfoot", tfootAttribute); } }); }); this.$element.redraw().addClass("fade-in"); // Do our callback this.$element.onTransitionEnd(complete); }; // No conflict. var old = $.fn.tablelist; // Plug-in definition $.fn.tablelist = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.tablelist"), opts = typeof options === "object" ? options : null; if (!data) { // Check the data and reassign if not present. $this.data("r.tablelist", (data = new Table(this, opts))); } // Run the appropriate function is a string is passed. if (typeof options === "string") { data[options](); } }); }; // Set the public constructor. $.fn.tablelist.Constructor = Table; $.fn.tablelist.noConflict = function () { $.fn.tablelist = old; return this; }; // Data API var init = function () { $("table[data-table-list]").each(function () { var $this = $(this), loaded = $this.data("r.tableLoaded"); if (!loaded) { $this.data("r.tableLoaded", true); $this.tablelist($.getDataOptions($this, {}, "tablelist", "r")); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_TABLE = true; }(jQuery, window, ".r.tablelist", ".data-api")); /* * Responsive tabs */ /*global jQuery*/ /*jshint expr:true*/ (function ($, w, ns, da) { "use strict"; if (w.RESPONSIVE_TABS) { return; } // General variables. var rtl = $.support.rtl, eready = "ready" + ns + da, echanged = ["domchanged" + ns + da, "shown.r.modal" + da].join(" "), eclick = "click", ekeydown = "keydown", eshow = "show" + ns, eshown = "shown" + ns; var keys = { SPACE: 32, LEFT: 37, RIGHT: 39 }; // Tabs class definition var Tabs = function (element) { this.$element = $(element); this.tabbing = null; // Add accessibility features. var $tablist = this.$element.children("ul:first").attr("role", "tablist"), $triggers = $tablist.children().attr("role", "presentation"), $panes = this.$element.children(":not(ul)"), id = $.pseudoUnique(), activeIndex = $tablist.find("[aria-selected=true]").parent().index(), hasActive = activeIndex > -1; $triggers.each(function (index) { var $this = $(this), $tab = $this.children("a"), isActive = (hasActive && index === activeIndex) || (!hasActive && index === 0); $tab.attr({ "role": "tab", "id": "tab-" + id + "-" + index, "aria-controls": "pane-" + id + "-" + index, "aria-selected": isActive ? true : false, "tabindex": 0 }); $panes.eq(index).attr({ "role": "tabpanel", "id": "pane-" + id + "-" + index, "aria-labelledby": "tab-" + id + "-" + index, "tabindex": isActive ? 0 : -1 }); }); // Bind events. $(this.$element).on(eclick, "ul[role=tablist] > li > [role=tab]", $.proxy(this.click, this)) .on(ekeydown, "ul[role=tablist] > li > [role=tab]", $.proxy(this.keydown, this)); }; Tabs.prototype.show = function (position) { var $activeItem = this.$element.children("ul").find("[aria-selected=true]"), $children = $activeItem.closest("ul").children(), activePosition = $activeItem.parent().index(), self = this; if (position > ($children.length - 1) || position < 0) { return false; } if (activePosition === position) { return false; } // Call the function with the callback return this.tab(activePosition, position, function ($item) { var complete = function () { self.tabbing = false; $item.siblings().addBack().removeClass("fade-out fade-in"); self.$element.trigger($.Event(eshown, { relatedTarget: $item[0] })); }; // Do our callback $item.onTransitionEnd(complete); }); }; Tabs.prototype.tab = function (activePosition, postion, callback) { var showEvent = $.Event(eshow), $element = this.$element, $childTabs = $element.children("ul").children("li"), $childPanes = $element.children(":not(ul)"), $nextTab = $childTabs.eq(postion), $currentPane = $childPanes.eq(activePosition), $nextPane = $childPanes.eq(postion); $element.trigger(showEvent); if (this.tabbing || showEvent.isDefaultPrevented()) { return; } this.tabbing = true; $childTabs.children("a").attr({ "aria-selected": false }); $nextTab.children("a").attr({ "aria-selected": true }).focus(); // Do some class shuffling to allow the transition. $currentPane.addClass("fade-out fade-in"); $nextPane.attr({ "tabIndex": 0 }).addClass("fade-out"); $childPanes.filter(".fade-in").attr({ "tabIndex": -1 }).removeClass("fade-in"); // Force redraw. $nextPane.redraw().addClass("fade-in"); // Do the callback callback.call(this, $nextPane); }; Tabs.prototype.click = function (event) { event.preventDefault(); event.stopPropagation(); var $this = $(event.target), $li = $this.parent(), index = $li.index(); this.show(index); }; Tabs.prototype.keydown = function (event) { var which = event.which; // Ignore anything but left and right. if (which === keys.SPACE || which === keys.LEFT || which === keys.RIGHT) { event.preventDefault(); event.stopPropagation(); var $this = $(event.target), $li = $this.parent(), $all = $li.siblings().addBack(), length = $all.length, index = $li.index(); if (which === keys.SPACE) { this.show(index); return; } // Select the correct index. index = which === keys.LEFT ? (rtl ? index + 1 : index - 1) : (rtl ? index - 1 : index + 1); // Ensure that the index stays within bounds. if (index === length) { index = 0; } if (index < 0) { index = length - 1; } this.show(index); } }; // No conflict. var old = $.fn.tabs; // Plug-in definition $.fn.tabs = function (options) { return this.each(function () { var $this = $(this), data = $this.data("r.tabs"); if (!data) { // Check the data and reassign if not present. $this.data("r.tabs", (data = new Tabs(this))); } // Show the given number. if (typeof options === "number") { data.show(options); } }); }; // Set the public constructor. $.fn.tabs.Constructor = Tabs; $.fn.tabs.noConflict = function () { $.fn.tabs = old; return this; }; // Data API var init = function () { $("[data-tabs]").each(function () { var $this = $(this), loaded = $this.data("r.tabsLoaded"); if (!loaded) { $this.data("r.tabsLoaded", true); $this.tabs(); } }); }, debouncedInit = $.debounce(init, 500); $(document).on([eready, echanged].join(" "), function (event) { event.type === "ready" ? init() : debouncedInit(); }); w.RESPONSIVE_TABS = true; }(jQuery, window, ".r.tabs", ".data-api"));