/**
* @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
*
* @version 0.5.1
* @codingstandard ftlabs-jsv2
* @copyright The Financial Times Limited [All Rights Reserved]
* @license MIT License (see LICENSE.txt)
*/
/*jslint browser:true, node:true*/
/*global define, Event, Node*/
/**
* Instantiate fast-clicking listeners on the specificed layer.
*
* @constructor
* @param {Element} layer The layer to listen on
*/
function FastClick(layer) {
'use strict';
var oldOnClick, self = this;
/**
* Whether a click is currently being tracked.
*
* @type boolean
*/
this.trackingClick = false;
/**
* Timestamp for when when click tracking started.
*
* @type number
*/
this.trackingClickStart = 0;
/**
* The element being tracked for a click.
*
* @type EventTarget
*/
this.targetElement = null;
/**
* X-coordinate of touch start event.
*
* @type number
*/
this.touchStartX = 0;
/**
* Y-coordinate of touch start event.
*
* @type number
*/
this.touchStartY = 0;
/**
* ID of the last touch, retrieved from Touch.identifier.
*
* @type number
*/
this.lastTouchIdentifier = 0;
/**
* The FastClick layer.
*
* @type Element
*/
this.layer = layer;
if (!layer || !layer.nodeType) {
throw new TypeError('Layer must be a document node');
}
/** @type function() */
this.onClick = function() { FastClick.prototype.onClick.apply(self, arguments); };
/** @type function() */
this.onTouchStart = function() { FastClick.prototype.onTouchStart.apply(self, arguments); };
/** @type function() */
this.onTouchMove = function() { FastClick.prototype.onTouchMove.apply(self, arguments); };
/** @type function() */
this.onTouchEnd = function() { FastClick.prototype.onTouchEnd.apply(self, arguments); };
/** @type function() */
this.onTouchCancel = function() { FastClick.prototype.onTouchCancel.apply(self, arguments); };
// Devices that don't support touch don't need FastClick
if (typeof window.ontouchstart === 'undefined') {
return;
}
// Set up event handlers as required
layer.addEventListener('click', this.onClick, true);
layer.addEventListener('touchstart', this.onTouchStart, false);
layer.addEventListener('touchmove', this.onTouchMove, false);
layer.addEventListener('touchend', this.onTouchEnd, false);
layer.addEventListener('touchcancel', this.onTouchCancel, false);
// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
// layer when they are cancelled.
if (!Event.prototype.stopImmediatePropagation) {
layer.removeEventListener = function(type, callback, capture) {
var rmv = Node.prototype.removeEventListener;
if (type === 'click') {
rmv.call(layer, type, callback.hijacked || callback, capture);
} else {
rmv.call(layer, type, callback, capture);
}
};
layer.addEventListener = function(type, callback, capture) {
var adv = Node.prototype.addEventListener;
if (type === 'click') {
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
if (!event.propagationStopped) {
callback(event);
}
}), capture);
} else {
adv.call(layer, type, callback, capture);
}
};
}
// If a handler is already declared in the element's onclick attribute, it will be fired before
// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
// adding it as listener.
if (typeof layer.onclick === 'function') {
// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
// - the old one won't work if passed to addEventListener directly.
oldOnClick = layer.onclick;
layer.addEventListener('click', function(event) {
oldOnClick(event);
}, false);
layer.onclick = null;
}
}
/**
* Android requires an exception for labels.
*
* @type boolean
*/
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
/**
* iOS requires an exception for alert confirm dialogs.
*
* @type boolean
*/
FastClick.prototype.deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
/**
* iOS 4 requires an exception for select elements.
*
* @type boolean
*/
FastClick.prototype.deviceIsIOS4 = FastClick.prototype.deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
/**
* Determine whether a given element requires a native click.
*
* @param {EventTarget|Element} target Target DOM element
* @returns {boolean} Returns true if the element needs a native click
*/
FastClick.prototype.needsClick = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
case 'label':
case 'video':
return true;
default:
return (/\bneedsclick\b/).test(target.className);
}
};
/**
* Determine whether a given element requires a call to focus to simulate click into element.
*
* @param {EventTarget|Element} target Target DOM element
* @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
*/
FastClick.prototype.needsFocus = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
case 'textarea':
case 'select':
return true;
case 'input':
switch (target.type) {
case 'button':
case 'checkbox':
case 'file':
case 'image':
case 'radio':
case 'submit':
return false;
}
return true;
default:
return (/\bneedsfocus\b/).test(target.className);
}
};
/**
* Send a click event to the specified element.
*
* @param {EventTarget|Element} targetElement
* @param {Event} event
*/
FastClick.prototype.sendClick = function(targetElement, event) {
'use strict';
var clickEvent, touch;
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
if (document.activeElement && document.activeElement !== targetElement) {
document.activeElement.blur();
}
touch = event.changedTouches[0];
// Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent);
};
/**
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.focus = function(targetElement) {
'use strict';
var length;
if (this.deviceIsIOS && targetElement.setSelectionRange) {
length = targetElement.value.length;
targetElement.setSelectionRange(length, length);
} else {
targetElement.focus();
}
};
/**
* Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
*
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.updateScrollParent = function(targetElement) {
'use strict';
var scrollParent, parentElement;
scrollParent = targetElement.fastClickScrollParent;
// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
// target element was moved to another parent.
if (!scrollParent || !scrollParent.contains(targetElement)) {
parentElement = targetElement;
do {
if (parentElement.scrollHeight > parentElement.offsetHeight) {
scrollParent = parentElement;
targetElement.fastClickScrollParent = parentElement;
break;
}
parentElement = parentElement.parentElement;
} while (parentElement);
}
// Always update the scroll top tracker if possible.
if (scrollParent) {
scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
}
};
/**
* @param {EventTarget} targetElement
* @returns {Element|EventTarget}
*/
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
'use strict';
// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
if (eventTarget.nodeType === Node.TEXT_NODE) {
return eventTarget.parentNode;
}
return eventTarget;
};
/**
* On touch start, record the position and scroll offset.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchStart = function(event) {
'use strict';
var targetElement, touch;
targetElement = this.getTargetElementFromEventTarget(event.target);
touch = event.targetTouches[0];
if (this.deviceIsIOS) {
// Only trusted events will deselect text on iOS (issue #49)
if (window.getSelection().rangeCount) {
return true;
}
if (!this.deviceIsIOS4) {
// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
// with the same identifier as the touch event that previously triggered the click that triggered the alert.
// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
if (touch.identifier === this.lastTouchIdentifier) {
event.preventDefault();
return false;
}
this.lastTouchIdentifier = touch.identifier;
// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
// 1) the user does a fling scroll on the scrollable layer
// 2) the user stops the fling scroll with another tap
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
this.updateScrollParent(targetElement);
}
}
this.trackingClick = true;
this.trackingClickStart = event.timeStamp;
this.targetElement = targetElement;
this.touchStartX = touch.pageX;
this.touchStartY = touch.pageY;
// Prevent phantom clicks on fast double-tap (issue #36)
if ((event.timeStamp - this.lastClickTime) < 200) {
event.preventDefault();
}
return true;
};
/**
* Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.touchHasMoved = function(event) {
'use strict';
var touch = event.targetTouches[0];
if (Math.abs(touch.pageX - this.touchStartX) > 10 || Math.abs(touch.pageY - this.touchStartY) > 10) {
return true;
}
return false;
};
/**
* Update the last position.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchMove = function(event) {
'use strict';
if (!this.trackingClick) {
return true;
}
// If the touch has moved, cancel the click tracking
if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
this.trackingClick = false;
this.targetElement = null;
}
return true;
};
/**
* Attempt to find the labelled control for the given label element.
*
* @param {EventTarget|HTMLLabelElement} labelElement
* @returns {Element|null}
*/
FastClick.prototype.findControl = function(labelElement) {
'use strict';
// Fast path for newer browsers supporting the HTML5 control attribute
if (labelElement.control !== undefined) {
return labelElement.control;
}
// All browsers under test that support touch events also support the HTML5 htmlFor attribute
if (labelElement.htmlFor) {
return document.getElementById(labelElement.htmlFor);
}
// If no for attribute exists, attempt to retrieve the first labellable descendant element
// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
};
/**
* On touch end, determine whether to send a click event at once.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchEnd = function(event) {
'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, targetElement = this.targetElement;
if (!this.trackingClick) {
return true;
}
// Prevent phantom clicks on fast double-tap (issue #36)
if ((event.timeStamp - this.lastClickTime) < 200) {
this.cancelNextClick = true;
return true;
}
this.lastClickTime = event.timeStamp;
trackingClickStart = this.trackingClickStart;
this.trackingClick = false;
this.trackingClickStart = 0;
targetTagName = targetElement.tagName.toLowerCase();
if (targetTagName === 'label') {
forElement = this.findControl(targetElement);
if (forElement) {
this.focus(targetElement);
if (this.deviceIsAndroid) {
return false;
}
targetElement = forElement;
}
} else if (this.needsFocus(targetElement)) {
// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
this.targetElement = null;
return false;
}
this.focus(targetElement);
// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
if (!this.deviceIsIOS4 || targetTagName !== 'select') {
this.targetElement = null;
event.preventDefault();
}
return false;
}
if (this.deviceIsIOS && !this.deviceIsIOS4) {
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
scrollParent = targetElement.fastClickScrollParent;
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
return true;
}
}
// Prevent the actual click from going though - unless the target node is marked as requiring
// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
if (!this.needsClick(targetElement)) {
event.preventDefault();
this.sendClick(targetElement, event);
}
return false;
};
/**
* On touch cancel, stop tracking the click.
*
* @returns {void}
*/
FastClick.prototype.onTouchCancel = function() {
'use strict';
this.trackingClick = false;
this.targetElement = null;
};
/**
* On actual clicks, determine whether this is a touch-generated click, a click action occurring
* naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
* an actual click which should be permitted.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onClick = function(event) {
'use strict';
var oldTargetElement;
// If a target element was never set (because a touch event was never fired) allow the click
if (!this.targetElement) {
return true;
}
if (event.forwardedTouchEvent) {
return true;
}
oldTargetElement = this.targetElement;
this.targetElement = null;
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
if (this.trackingClick) {
this.trackingClick = false;
return true;
}
// Programmatically generated events targeting a specific element should be permitted
if (!event.cancelable) {
return true;
}
// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
if (event.target.type === 'submit' && event.detail === 0) {
return true;
}
// Derive and check the target element to see whether the click needs to be permitted;
// unless explicitly enabled, prevent non-touch click events from triggering actions,
// to prevent ghost/doubleclicks.
if (!this.needsClick(oldTargetElement) || this.cancelNextClick) {
this.cancelNextClick = false;
// Prevent any user-added listeners declared on FastClick element from being fired.
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
event.propagationStopped = true;
}
// Cancel the event
event.stopPropagation();
event.preventDefault();
return false;
}
// If clicks are permitted, return true for the action to go through.
return true;
};
/**
* Remove all FastClick's event listeners.
*
* @returns {void}
*/
FastClick.prototype.destroy = function() {
'use strict';
var layer = this.layer;
layer.removeEventListener('click', this.onClick, true);
layer.removeEventListener('touchstart', this.onTouchStart, false);
layer.removeEventListener('touchmove', this.onTouchMove, false);
layer.removeEventListener('touchend', this.onTouchEnd, false);
layer.removeEventListener('touchcancel', this.onTouchCancel, false);
};
if (typeof define !== 'undefined' && define.amd) {
// AMD. Register as an anonymous module.
define(function() {
'use strict';
return FastClick;
});
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = function(layer) {
'use strict';
return new FastClick(layer);
};
module.exports.FastClick = FastClick;
}
// Avoid `console` errors in browsers that lack a console.
(function() {
var method;
var noop = function () {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());
// Place any jQuery/helper plugins in here.
/*! Backstretch - v2.0.3 - 2012-11-30
* http://srobbin.com/jquery-plugins/backstretch/
* Copyright (c) 2012 Scott Robbin; Licensed MIT */
(function(e,t,n){"use strict";e.fn.backstretch=function(r,s){return(r===n||r.length===0)&&e.error("No images were supplied for Backstretch"),e(t).scrollTop()===0&&t.scrollTo(0,0),this.each(function(){var t=e(this),n=t.data("backstretch");n&&(s=e.extend(n.options,s),n.destroy(!0)),n=new i(this,r,s),t.data("backstretch",n)})},e.backstretch=function(t,n){return e("body").backstretch(t,n).data("backstretch")},e.expr[":"].backstretch=function(t){return e(t).data("backstretch")!==n},e.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5e3,fade:0};var r={wrap:{left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"100%",width:"100%",zIndex:-999999},img:{position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"auto",maxWidth:"none",zIndex:-999999}},i=function(n,i,o){this.options=e.extend({},e.fn.backstretch.defaults,o||{}),this.images=e.isArray(i)?i:[i],e.each(this.images,function(){e("
")[0].src=this}),this.isBody=n===document.body,this.$container=e(n),this.$wrap=e('
').css(r.wrap).appendTo(this.$container),this.$root=this.isBody?s?e(t):e(document):this.$container;if(!this.isBody){var u=this.$container.css("position"),a=this.$container.css("zIndex");this.$container.css({position:u==="static"?"relative":u,zIndex:a==="auto"?0:a,background:"none"}),this.$wrap.css({zIndex:-999998})}this.$wrap.css({position:this.isBody&&s?"fixed":"absolute"}),this.index=0,this.show(this.index),e(t).on("resize.backstretch",e.proxy(this.resize,this)).on("orientationchange.backstretch",e.proxy(function(){this.isBody&&t.pageYOffset===0&&(t.scrollTo(0,1),this.resize())},this))};i.prototype={resize:function(){try{var e={left:0,top:0},n=this.isBody?this.$root.width():this.$root.innerWidth(),r=n,i=this.isBody?t.innerHeight?t.innerHeight:this.$root.height():this.$root.innerHeight(),s=r/this.$img.data("ratio"),o;s>=i?(o=(s-i)/2,this.options.centeredY&&(e.top="-"+o+"px")):(s=i,r=s*this.$img.data("ratio"),o=(r-n)/2,this.options.centeredX&&(e.left="-"+o+"px")),this.$wrap.css({width:n,height:i}).find("img:not(.deleteable)").css({width:r,height:s}).css(e)}catch(u){}return this},show:function(t){if(Math.abs(t)>this.images.length-1)return;this.index=t;var n=this,i=n.$wrap.find("img").addClass("deleteable"),s=e.Event("backstretch.show",{relatedTarget:n.$container[0]});return clearInterval(n.interval),n.$img=e("
").css(r.img).bind("load",function(t){var r=this.width||e(t.target).width(),o=this.height||e(t.target).height();e(this).data("ratio",r/o),e(this).fadeIn(n.options.speed||n.options.fade,function(){i.remove(),n.paused||n.cycle(),n.$container.trigger(s,n)}),n.resize()}).appendTo(n.$wrap),n.$img.attr("src",n.images[t]),n},next:function(){return this.show(this.index1&&(clearInterval(this.interval),this.interval=setInterval(e.proxy(function(){this.paused||this.next()},this),this.options.duration)),this},destroy:function(n){e(t).off("resize.backstretch orientationchange.backstretch"),clearInterval(this.interval),n||this.$wrap.remove(),this.$container.removeData("backstretch")}};var s=function(){var e=navigator.userAgent,n=navigator.platform,r=e.match(/AppleWebKit\/([0-9]+)/),i=!!r&&r[1],s=e.match(/Fennec\/([0-9]+)/),o=!!s&&s[1],u=e.match(/Opera Mobi\/([0-9]+)/),a=!!u&&u[1],f=e.match(/MSIE ([0-9]+)/),l=!!f&&f[1];return!((n.indexOf("iPhone")>-1||n.indexOf("iPad")>-1||n.indexOf("iPod")>-1)&&i&&i<534||t.operamini&&{}.toString.call(t.operamini)==="[object OperaMini]"||u&&a<7458||e.indexOf("Android")>-1&&i&&i<533||o&&o<6||"palmGetResource"in t&&i&&i<534||e.indexOf("MeeGo")>-1&&e.indexOf("NokiaBrowser/8.5.0")>-1||l&&l<=6)}()})(jQuery,window);
// jquery.event.move
//
// 1.3.1
//
// Stephen Band
//
// Triggers 'movestart', 'move' and 'moveend' events after
// mousemoves following a mousedown cross a distance threshold,
// similar to the native 'dragstart', 'drag' and 'dragend' events.
// Move events are throttled to animation frames. Move event objects
// have the properties:
//
// pageX:
// pageY: Page coordinates of pointer.
// startX:
// startY: Page coordinates of pointer at movestart.
// distX:
// distY: Distance the pointer has moved since movestart.
// deltaX:
// deltaY: Distance the finger has moved since last event.
// velocityX:
// velocityY: Average velocity over last few events.
(function (module) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], module);
} else {
// Browser globals
module(jQuery);
}
})(function(jQuery, undefined){
var // Number of pixels a pressed pointer travels before movestart
// event is fired.
threshold = 6,
add = jQuery.event.add,
remove = jQuery.event.remove,
// Just sugar, so we can have arguments in the same order as
// add and remove.
trigger = function(node, type, data) {
jQuery.event.trigger(type, data, node);
},
// Shim for requestAnimationFrame, falling back to timer. See:
// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
requestFrame = (function(){
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(fn, element){
return window.setTimeout(function(){
fn();
}, 25);
}
);
})(),
ignoreTags = {
textarea: true,
input: true,
select: true,
button: true
},
mouseevents = {
move: 'mousemove',
cancel: 'mouseup dragstart',
end: 'mouseup'
},
touchevents = {
move: 'touchmove',
cancel: 'touchend',
end: 'touchend'
};
// Constructors
function Timer(fn){
var callback = fn,
active = false,
running = false;
function trigger(time) {
if (active){
callback();
requestFrame(trigger);
running = true;
active = false;
}
else {
running = false;
}
}
this.kick = function(fn) {
active = true;
if (!running) { trigger(); }
};
this.end = function(fn) {
var cb = callback;
if (!fn) { return; }
// If the timer is not running, simply call the end callback.
if (!running) {
fn();
}
// If the timer is running, and has been kicked lately, then
// queue up the current callback and the end callback, otherwise
// just the end callback.
else {
callback = active ?
function(){ cb(); fn(); } :
fn ;
active = true;
}
};
}
// Functions
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
function preventDefault(e) {
e.preventDefault();
}
function preventIgnoreTags(e) {
// Don't prevent interaction with form elements.
if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }
e.preventDefault();
}
function isLeftButton(e) {
// Ignore mousedowns on any button other than the left (or primary)
// mouse button, or when a modifier key is pressed.
return (e.which === 1 && !e.ctrlKey && !e.altKey);
}
function identifiedTouch(touchList, id) {
var i, l;
if (touchList.identifiedTouch) {
return touchList.identifiedTouch(id);
}
// touchList.identifiedTouch() does not exist in
// webkit yet… we must do the search ourselves...
i = -1;
l = touchList.length;
while (++i < l) {
if (touchList[i].identifier === id) {
return touchList[i];
}
}
}
function changedTouch(e, event) {
var touch = identifiedTouch(e.changedTouches, event.identifier);
// This isn't the touch you're looking for.
if (!touch) { return; }
// Chrome Android (at least) includes touches that have not
// changed in e.changedTouches. That's a bit annoying. Check
// that this touch has changed.
if (touch.pageX === event.pageX && touch.pageY === event.pageY) { return; }
return touch;
}
// Handlers that decide when the first movestart is triggered
function mousedown(e){
var data;
if (!isLeftButton(e)) { return; }
data = {
target: e.target,
startX: e.pageX,
startY: e.pageY,
timeStamp: e.timeStamp
};
add(document, mouseevents.move, mousemove, data);
add(document, mouseevents.cancel, mouseend, data);
}
function mousemove(e){
var data = e.data;
checkThreshold(e, data, e, removeMouse);
}
function mouseend(e) {
removeMouse();
}
function removeMouse() {
remove(document, mouseevents.move, mousemove);
remove(document, mouseevents.cancel, removeMouse);
}
function touchstart(e) {
var touch, template;
// Don't get in the way of interaction with form elements.
if (ignoreTags[ e.target.tagName.toLowerCase() ]) { return; }
touch = e.changedTouches[0];
// iOS live updates the touch objects whereas Android gives us copies.
// That means we can't trust the touchstart object to stay the same,
// so we must copy the data. This object acts as a template for
// movestart, move and moveend event objects.
template = {
target: touch.target,
startX: touch.pageX,
startY: touch.pageY,
timeStamp: e.timeStamp,
identifier: touch.identifier
};
// Use the touch identifier as a namespace, so that we can later
// remove handlers pertaining only to this touch.
add(document, touchevents.move + '.' + touch.identifier, touchmove, template);
add(document, touchevents.cancel + '.' + touch.identifier, touchend, template);
}
function touchmove(e){
var data = e.data,
touch = changedTouch(e, data);
if (!touch) { return; }
checkThreshold(e, data, touch, removeTouch);
}
function touchend(e) {
var template = e.data,
touch = identifiedTouch(e.changedTouches, template.identifier);
if (!touch) { return; }
removeTouch(template.identifier);
}
function removeTouch(identifier) {
remove(document, '.' + identifier, touchmove);
remove(document, '.' + identifier, touchend);
}
// Logic for deciding when to trigger a movestart.
function checkThreshold(e, template, touch, fn) {
var distX = touch.pageX - template.startX,
distY = touch.pageY - template.startY;
// Do nothing if the threshold has not been crossed.
if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }
triggerStart(e, template, touch, distX, distY, fn);
}
function handled() {
// this._handled should return false once, and after return true.
this._handled = returnTrue;
return false;
}
function flagAsHandled(e) {
e._handled();
}
function triggerStart(e, template, touch, distX, distY, fn) {
var node = template.target,
touches, time;
touches = e.targetTouches;
time = e.timeStamp - template.timeStamp;
// Create a movestart object with some special properties that
// are passed only to the movestart handlers.
template.type = 'movestart';
template.distX = distX;
template.distY = distY;
template.deltaX = distX;
template.deltaY = distY;
template.pageX = touch.pageX;
template.pageY = touch.pageY;
template.velocityX = distX / time;
template.velocityY = distY / time;
template.targetTouches = touches;
template.finger = touches ?
touches.length :
1 ;
// The _handled method is fired to tell the default movestart
// handler that one of the move events is bound.
template._handled = handled;
// Pass the touchmove event so it can be prevented if or when
// movestart is handled.
template._preventTouchmoveDefault = function() {
e.preventDefault();
};
// Trigger the movestart event.
trigger(template.target, template);
// Unbind handlers that tracked the touch or mouse up till now.
fn(template.identifier);
}
// Handlers that control what happens following a movestart
function activeMousemove(e) {
var event = e.data.event,
timer = e.data.timer;
updateEvent(event, e, e.timeStamp, timer);
}
function activeMouseend(e) {
var event = e.data.event,
timer = e.data.timer;
removeActiveMouse();
endEvent(event, timer, function() {
// Unbind the click suppressor, waiting until after mouseup
// has been handled.
setTimeout(function(){
remove(event.target, 'click', returnFalse);
}, 0);
});
}
function removeActiveMouse(event) {
remove(document, mouseevents.move, activeMousemove);
remove(document, mouseevents.end, activeMouseend);
}
function activeTouchmove(e) {
var event = e.data.event,
timer = e.data.timer,
touch = changedTouch(e, event);
if (!touch) { return; }
// Stop the interface from gesturing
e.preventDefault();
event.targetTouches = e.targetTouches;
updateEvent(event, touch, e.timeStamp, timer);
}
function activeTouchend(e) {
var event = e.data.event,
timer = e.data.timer,
touch = identifiedTouch(e.changedTouches, event.identifier);
// This isn't the touch you're looking for.
if (!touch) { return; }
removeActiveTouch(event);
endEvent(event, timer);
}
function removeActiveTouch(event) {
remove(document, '.' + event.identifier, activeTouchmove);
remove(document, '.' + event.identifier, activeTouchend);
}
// Logic for triggering move and moveend events
function updateEvent(event, touch, timeStamp, timer) {
var time = timeStamp - event.timeStamp;
event.type = 'move';
event.distX = touch.pageX - event.startX;
event.distY = touch.pageY - event.startY;
event.deltaX = touch.pageX - event.pageX;
event.deltaY = touch.pageY - event.pageY;
// Average the velocity of the last few events using a decay
// curve to even out spurious jumps in values.
event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;
event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;
event.pageX = touch.pageX;
event.pageY = touch.pageY;
timer.kick();
}
function endEvent(event, timer, fn) {
timer.end(function(){
event.type = 'moveend';
trigger(event.target, event);
return fn && fn();
});
}
// jQuery special event definition
function setup(data, namespaces, eventHandle) {
// Stop the node from being dragged
//add(this, 'dragstart.move drag.move', preventDefault);
// Prevent text selection and touch interface scrolling
//add(this, 'mousedown.move', preventIgnoreTags);
// Tell movestart default handler that we've handled this
add(this, 'movestart.move', flagAsHandled);
// Don't bind to the DOM. For speed.
return true;
}
function teardown(namespaces) {
remove(this, 'dragstart drag', preventDefault);
remove(this, 'mousedown touchstart', preventIgnoreTags);
remove(this, 'movestart', flagAsHandled);
// Don't bind to the DOM. For speed.
return true;
}
function addMethod(handleObj) {
// We're not interested in preventing defaults for handlers that
// come from internal move or moveend bindings
if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {
return;
}
// Stop the node from being dragged
add(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid, preventDefault, undefined, handleObj.selector);
// Prevent text selection and touch interface scrolling
add(this, 'mousedown.' + handleObj.guid, preventIgnoreTags, undefined, handleObj.selector);
}
function removeMethod(handleObj) {
if (handleObj.namespace === "move" || handleObj.namespace === "moveend") {
return;
}
remove(this, 'dragstart.' + handleObj.guid + ' drag.' + handleObj.guid);
remove(this, 'mousedown.' + handleObj.guid);
}
jQuery.event.special.movestart = {
setup: setup,
teardown: teardown,
add: addMethod,
remove: removeMethod,
_default: function(e) {
var template, data;
// If no move events were bound to any ancestors of this
// target, high tail it out of here.
if (!e._handled()) { return; }
template = {
target: e.target,
startX: e.startX,
startY: e.startY,
pageX: e.pageX,
pageY: e.pageY,
distX: e.distX,
distY: e.distY,
deltaX: e.deltaX,
deltaY: e.deltaY,
velocityX: e.velocityX,
velocityY: e.velocityY,
timeStamp: e.timeStamp,
identifier: e.identifier,
targetTouches: e.targetTouches,
finger: e.finger
};
data = {
event: template,
timer: new Timer(function(time){
trigger(e.target, template);
})
};
if (e.identifier === undefined) {
// We're dealing with a mouse
// Stop clicks from propagating during a move
add(e.target, 'click', returnFalse);
add(document, mouseevents.move, activeMousemove, data);
add(document, mouseevents.end, activeMouseend, data);
}
else {
// We're dealing with a touch. Stop touchmove doing
// anything defaulty.
e._preventTouchmoveDefault();
add(document, touchevents.move + '.' + e.identifier, activeTouchmove, data);
add(document, touchevents.end + '.' + e.identifier, activeTouchend, data);
}
}
};
jQuery.event.special.move = {
setup: function() {
// Bind a noop to movestart. Why? It's the movestart
// setup that decides whether other move events are fired.
add(this, 'movestart.move', jQuery.noop);
},
teardown: function() {
remove(this, 'movestart.move', jQuery.noop);
}
};
jQuery.event.special.moveend = {
setup: function() {
// Bind a noop to movestart. Why? It's the movestart
// setup that decides whether other move events are fired.
add(this, 'movestart.moveend', jQuery.noop);
},
teardown: function() {
remove(this, 'movestart.moveend', jQuery.noop);
}
};
add(document, 'mousedown.move', mousedown);
add(document, 'touchstart.move', touchstart);
// Make jQuery copy touch event properties over to the jQuery event
// object, if they are not already listed. But only do the ones we
// really need. IE7/8 do not have Array#indexOf(), but nor do they
// have touch events, so let's assume we can ignore them.
if (typeof Array.prototype.indexOf === 'function') {
(function(jQuery, undefined){
var props = ["changedTouches", "targetTouches"],
l = props.length;
while (l--) {
if (jQuery.event.props.indexOf(props[l]) === -1) {
jQuery.event.props.push(props[l]);
}
}
})(jQuery);
};
});
// jQuery.event.swipe
// 0.5
// Stephen Band
// Dependencies
// jQuery.event.move 1.2
// One of swipeleft, swiperight, swipeup or swipedown is triggered on
// moveend, when the move has covered a threshold ratio of the dimension
// of the target node, or has gone really fast. Threshold and velocity
// sensitivity changed with:
//
// jQuery.event.special.swipe.settings.threshold
// jQuery.event.special.swipe.settings.sensitivity
(function (module) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], module);
} else {
// Browser globals
module(jQuery);
}
})(function(jQuery, undefined){
var add = jQuery.event.add,
remove = jQuery.event.remove,
// Just sugar, so we can have arguments in the same order as
// add and remove.
trigger = function(node, type, data) {
jQuery.event.trigger(type, data, node);
},
settings = {
// Ratio of distance over target finger must travel to be
// considered a swipe.
threshold: 0.4,
// Faster fingers can travel shorter distances to be considered
// swipes. 'sensitivity' controls how much. Bigger is shorter.
sensitivity: 6
};
function moveend(e) {
var w, h, event;
w = e.target.offsetWidth;
h = e.target.offsetHeight;
// Copy over some useful properties from the move event
event = {
distX: e.distX,
distY: e.distY,
velocityX: e.velocityX,
velocityY: e.velocityY,
finger: e.finger
};
// Find out which of the four directions was swiped
if (e.distX > e.distY) {
if (e.distX > -e.distY) {
if (e.distX/w > settings.threshold || e.velocityX * e.distX/w * settings.sensitivity > 1) {
event.type = 'swiperight';
trigger(e.currentTarget, event);
}
}
else {
if (-e.distY/h > settings.threshold || e.velocityY * e.distY/w * settings.sensitivity > 1) {
event.type = 'swipeup';
trigger(e.currentTarget, event);
}
}
}
else {
if (e.distX > -e.distY) {
if (e.distY/h > settings.threshold || e.velocityY * e.distY/w * settings.sensitivity > 1) {
event.type = 'swipedown';
trigger(e.currentTarget, event);
}
}
else {
if (-e.distX/w > settings.threshold || e.velocityX * e.distX/w * settings.sensitivity > 1) {
event.type = 'swipeleft';
trigger(e.currentTarget, event);
}
}
}
}
function getData(node) {
var data = jQuery.data(node, 'event_swipe');
if (!data) {
data = { count: 0 };
jQuery.data(node, 'event_swipe', data);
}
return data;
}
jQuery.event.special.swipe =
jQuery.event.special.swipeleft =
jQuery.event.special.swiperight =
jQuery.event.special.swipeup =
jQuery.event.special.swipedown = {
setup: function( data, namespaces, eventHandle ) {
var data = getData(this);
// If another swipe event is already setup, don't setup again.
if (data.count++ > 0) { return; }
add(this, 'moveend', moveend);
return true;
},
teardown: function() {
var data = getData(this);
// If another swipe event is still setup, don't teardown.
if (--data.count > 0) { return; }
remove(this, 'moveend', moveend);
return true;
},
settings: settings
};
});
(function(a){"use strict";a.fn.fitVids=function(b){var c={customSelector:null},d=document.createElement("div"),e=document.getElementsByTagName("base")[0]||document.getElementsByTagName("script")[0];return d.className="fit-vids-style",d.innerHTML="",e.parentNode.insertBefore(d,e),b&&a.extend(c,b),this.each(function(){var b=["iframe[src*='player.vimeo.com']","iframe[src*='www.youtube.com']","iframe[src*='www.youtube-nocookie.com']","iframe[src*='www.kickstarter.com']","object","embed"];c.customSelector&&b.push(c.customSelector);var d=a(this).find(b.join(","));d.each(function(){var b=a(this);if(!("embed"===this.tagName.toLowerCase()&&b.parent("object").length||b.parent(".fluid-width-video-wrapper").length)){var c="object"===this.tagName.toLowerCase()||b.attr("height")&&!isNaN(parseInt(b.attr("height"),10))?parseInt(b.attr("height"),10):b.height(),d=isNaN(parseInt(b.attr("width"),10))?b.width():parseInt(b.attr("width"),10),e=c/d;if(!b.attr("id")){var f="fitvid"+Math.floor(999999*Math.random());b.attr("id",f)}b.wrap('').parent(".fluid-width-video-wrapper").css("padding-top",100*e+"%"),b.removeAttr("height").removeAttr("width")}})})}})(jQuery);
/*
* jQuery Orbit Plugin 1.4.0
* www.ZURB.com/playground
* Copyright 2010, ZURB
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
(function ($) {
'use strict';
$.fn.findFirstImage = function () {
return this.first()
.find('img')
.andSelf().filter('img')
.first();
};
var ORBIT = {
defaults: {
animation: 'horizontal-push', // fade, horizontal-slide, vertical-slide, horizontal-push, vertical-push
animationSpeed: 600, // how fast animations are
timer: true, // display timer?
advanceSpeed: 4000, // if timer is enabled, time between transitions
pauseOnHover: false, // if you hover pauses the slider
startClockOnMouseOut: false, // if clock should start on MouseOut
startClockOnMouseOutAfter: 1000, // how long after MouseOut should the timer start again
directionalNav: true, // manual advancing directional navs
directionalNavRightText: 'Right', // text of right directional element for accessibility
directionalNavLeftText: 'Left', // text of left directional element for accessibility
captions: true, // do you want captions?
captionAnimation: 'fade', // fade, slideOpen, none
captionAnimationSpeed: 600, // if so how quickly should they animate in
resetTimerOnClick: false, // true resets the timer instead of pausing slideshow progress on manual navigation
bullets: false, // true or false to activate the bullet navigation
bulletThumbs: false, // thumbnails for the bullets
bulletThumbLocation: '', // relative path to thumbnails from this file
bulletThumbsHideOnSmall: true, // hide thumbs on small devices
afterSlideChange: $.noop, // callback to execute after slide changes
afterLoadComplete: $.noop, // callback to execute after everything has been loaded
fluid: true,
centerBullets: true, // center bullet nav with js, turn this off if you want to position the bullet nav manually
singleCycle: false, // cycles through orbit slides only once
slideNumber: false, // display slide numbers?
stackOnSmall: false // stack slides on small devices (i.e. phones)
},
activeSlide: 0,
numberSlides: 0,
orbitWidth: null,
orbitHeight: null,
locked: null,
timerRunning: null,
degrees: 0,
wrapperHTML: '',
timerHTML: '
',
captionHTML: '',
directionalNavHTML: '
',
bulletHTML: '',
slideNumberHTML: '',
init: function (element, options) {
var $imageSlides,
imagesLoadedCount = 0,
self = this;
// Bind functions to correct context
this.clickTimer = $.proxy(this.clickTimer, this);
this.addBullet = $.proxy(this.addBullet, this);
this.resetAndUnlock = $.proxy(this.resetAndUnlock, this);
this.stopClock = $.proxy(this.stopClock, this);
this.startTimerAfterMouseLeave = $.proxy(this.startTimerAfterMouseLeave, this);
this.clearClockMouseLeaveTimer = $.proxy(this.clearClockMouseLeaveTimer, this);
this.rotateTimer = $.proxy(this.rotateTimer, this);
this.options = $.extend({}, this.defaults, options);
if (this.options.timer === 'false') this.options.timer = false;
if (this.options.captions === 'false') this.options.captions = false;
if (this.options.directionalNav === 'false') this.options.directionalNav = false;
this.$element = $(element);
this.$wrapper = this.$element.wrap(this.wrapperHTML).parent();
this.$slides = this.$element.children('img, a, div, figure, li');
this.$element.on('movestart', function(e) {
// If the movestart is heading off in an upwards or downwards
// direction, prevent it so that the browser scrolls normally.
if ((e.distX > e.distY && e.distX < -e.distY) ||
(e.distX < e.distY && e.distX > -e.distY)) {
e.preventDefault();
}
});
this.$element.bind('orbit.next', function () {
self.shift('next');
});
this.$element.bind('orbit.prev', function () {
self.shift('prev');
});
this.$element.bind('swipeleft', function () {
$(this).trigger('orbit.next');
});
this.$element.bind('swiperight', function () {
$(this).trigger('orbit.prev');
});
this.$element.bind('orbit.goto', function (event, index) {
self.shift(index);
});
this.$element.bind('orbit.start', function (event, index) {
self.startClock();
});
this.$element.bind('orbit.stop', function (event, index) {
self.stopClock();
});
$imageSlides = this.$slides.filter('img');
if ($imageSlides.length === 0) {
this.loaded();
} else {
$imageSlides.bind('imageready', function () {
imagesLoadedCount += 1;
if (imagesLoadedCount === $imageSlides.length) {
self.loaded();
}
});
}
},
loaded: function () {
this.$element
.addClass('orbit')
.css({width: '1px', height: '1px'});
if (this.options.stackOnSmall) {
this.$element.addClass('orbit-stack-on-small');
}
this.$slides.addClass('orbit-slide').css({"opacity" : 0});
this.setDimentionsFromLargestSlide();
this.updateOptionsIfOnlyOneSlide();
this.setupFirstSlide();
this.notifySlideChange();
if (this.options.timer) {
this.setupTimer();
this.startClock();
}
if (this.options.captions) {
this.setupCaptions();
}
if (this.options.directionalNav) {
this.setupDirectionalNav();
}
if (this.options.bullets) {
this.setupBulletNav();
this.setActiveBullet();
}
this.options.afterLoadComplete.call(this);
Holder.run();
},
currentSlide: function () {
return this.$slides.eq(this.activeSlide);
},
notifySlideChange: function() {
if (this.options.slideNumber) {
var txt = (this.activeSlide+1) + ' of ' + this.$slides.length;
this.$element.trigger("orbit.change", {slideIndex: this.activeSlide, slideCount: this.$slides.length});
if (this.$counter === undefined) {
var $counter = $(this.slideNumberHTML).html(txt);
this.$counter = $counter;
this.$wrapper.append(this.$counter);
} else {
this.$counter.html(txt);
}
}
},
setDimentionsFromLargestSlide: function () {
//Collect all slides and set slider size of largest image
var self = this,
$fluidPlaceholder;
self.$element.add(self.$wrapper).width(this.$slides.first().outerWidth());
self.$element.add(self.$wrapper).height(this.$slides.first().height());
self.orbitWidth = this.$slides.first().outerWidth();
self.orbitHeight = this.$slides.first().height();
$fluidPlaceholder = this.$slides.first().findFirstImage().clone();
this.$slides.each(function () {
var slide = $(this),
slideWidth = slide.outerWidth(),
slideHeight = slide.height();
if (slideWidth > self.$element.outerWidth()) {
self.$element.add(self.$wrapper).width(slideWidth);
self.orbitWidth = self.$element.outerWidth();
}
if (slideHeight > self.$element.height()) {
self.$element.add(self.$wrapper).height(slideHeight);
self.orbitHeight = self.$element.height();
$fluidPlaceholder = $(this).findFirstImage().clone();
}
self.numberSlides += 1;
});
if (this.options.fluid) {
if (typeof this.options.fluid === "string") {
// $fluidPlaceholder = $("
").attr("src", "http://placehold.it/" + this.options.fluid);
$fluidPlaceholder = $("
").attr("data-src", "holder.js/" + this.options.fluid);
//var inner = $("").css({"display":"inline-block", "width":"2px", "height":"2px"});
//$fluidPlaceholder = $("").css({"float":"left"});
//$fluidPlaceholder.wrapInner(inner);
//$fluidPlaceholder = $("").css({"height":"1px", "width":"2px"});
//$fluidPlaceholder = $("");
}
self.$element.prepend($fluidPlaceholder);
$fluidPlaceholder.addClass('fluid-placeholder');
self.$element.add(self.$wrapper).css({width: 'inherit'});
self.$element.add(self.$wrapper).css({height: 'inherit'});
$(window).bind('resize', function () {
self.orbitWidth = self.$element.outerWidth();
self.orbitHeight = self.$element.height();
});
}
},
//Animation locking functions
lock: function () {
this.locked = true;
},
unlock: function () {
this.locked = false;
},
updateOptionsIfOnlyOneSlide: function () {
if(this.$slides.length === 1) {
this.options.directionalNav = false;
this.options.timer = false;
this.options.bullets = false;
}
},
setupFirstSlide: function () {
//Set initial front photo z-index and fades it in
var self = this;
this.$slides.first()
.css({"z-index" : 3, "opacity" : 1})
.fadeIn(function() {
//brings in all other slides IF css declares a display: none
self.$slides.css({"display":"block"})
});
},
startClock: function () {
var self = this;
if(!this.options.timer) {
return false;
}
if (this.$timer.is(':hidden')) {
this.clock = setInterval(function () {
self.$element.trigger('orbit.next');
}, this.options.advanceSpeed);
} else {
this.timerRunning = true;
this.$pause.removeClass('active');
this.clock = setInterval(this.rotateTimer, this.options.advanceSpeed / 180, false);
}
},
rotateTimer: function (reset) {
var degreeCSS = "rotate(" + this.degrees + "deg)";
this.degrees += 2;
this.$rotator.css({
"-webkit-transform": degreeCSS,
"-moz-transform": degreeCSS,
"-o-transform": degreeCSS,
"-ms-transform": degreeCSS
});
if (reset) {
this.degrees = 0;
this.$rotator.removeClass('move');
this.$mask.removeClass('move');
}
if(this.degrees > 180) {
this.$rotator.addClass('move');
this.$mask.addClass('move');
}
if(this.degrees > 360) {
this.$rotator.removeClass('move');
this.$mask.removeClass('move');
this.degrees = 0;
this.$element.trigger('orbit.next');
}
},
stopClock: function () {
if (!this.options.timer) {
return false;
} else {
this.timerRunning = false;
clearInterval(this.clock);
this.$pause.addClass('active');
}
},
setupTimer: function () {
this.$timer = $(this.timerHTML);
this.$wrapper.append(this.$timer);
this.$rotator = this.$timer.find('.rotator');
this.$mask = this.$timer.find('.mask');
this.$pause = this.$timer.find('.pause');
this.$timer.click(this.clickTimer);
if (this.options.startClockOnMouseOut) {
this.$wrapper.mouseleave(this.startTimerAfterMouseLeave);
this.$wrapper.mouseenter(this.clearClockMouseLeaveTimer);
}
if (this.options.pauseOnHover) {
this.$wrapper.mouseenter(this.stopClock);
}
},
startTimerAfterMouseLeave: function () {
var self = this;
this.outTimer = setTimeout(function() {
if(!self.timerRunning){
self.startClock();
}
}, this.options.startClockOnMouseOutAfter)
},
clearClockMouseLeaveTimer: function () {
clearTimeout(this.outTimer);
},
clickTimer: function () {
if(!this.timerRunning) {
this.startClock();
} else {
this.stopClock();
}
},
setupCaptions: function () {
this.$caption = $(this.captionHTML);
this.$wrapper.append(this.$caption);
this.setCaption();
},
setCaption: function () {
var captionLocation = this.currentSlide().attr('data-caption'),
captionHTML;
if (!this.options.captions) {
return false;
}
//Set HTML for the caption if it exists
if (captionLocation) {
//if caption text is blank, don't show captions
if ($.trim($(captionLocation).text()).length < 1){
return false;
}
// if location selector starts with '#', remove it so we don't see id="#selector"
if (captionLocation.charAt(0) == '#') {
captionLocation = captionLocation.substring(1, captionLocation.length);
}
captionHTML = $('#' + captionLocation).html(); //get HTML from the matching HTML entity
this.$caption
.attr('id', captionLocation) // Add ID caption TODO why is the id being set?
.html(captionHTML); // Change HTML in Caption
//Animations for Caption entrances
switch (this.options.captionAnimation) {
case 'none':
this.$caption.show();
break;
case 'fade':
this.$caption.fadeIn(this.options.captionAnimationSpeed);
break;
case 'slideOpen':
this.$caption.slideDown(this.options.captionAnimationSpeed);
break;
}
} else {
//Animations for Caption exits
switch (this.options.captionAnimation) {
case 'none':
this.$caption.hide();
break;
case 'fade':
this.$caption.fadeOut(this.options.captionAnimationSpeed);
break;
case 'slideOpen':
this.$caption.slideUp(this.options.captionAnimationSpeed);
break;
}
}
},
setupDirectionalNav: function () {
var self = this,
$directionalNav = $(this.directionalNavHTML);
$directionalNav.find('.right').html(this.options.directionalNavRightText);
$directionalNav.find('.left').html(this.options.directionalNavLeftText);
this.$wrapper.append($directionalNav);
this.$wrapper.find('.left').click(function () {
self.stopClock();
if (self.options.resetTimerOnClick) {
self.rotateTimer(true);
self.startClock();
}
self.$element.trigger('orbit.prev');
});
this.$wrapper.find('.right').click(function () {
self.stopClock();
if (self.options.resetTimerOnClick) {
self.rotateTimer(true);
self.startClock();
}
self.$element.trigger('orbit.next');
});
},
setupBulletNav: function () {
this.$bullets = $(this.bulletHTML);
this.$wrapper.append(this.$bullets);
this.$slides.each(this.addBullet);
this.$element.addClass('with-bullets');
if (this.options.centerBullets) this.$bullets.css('margin-left', -this.$bullets.outerWidth() / 2);
if (this.options.bulletThumbsHideOnSmall) this.$bullets.addClass('hide-for-small');
},
addBullet: function (index, slide) {
var position = index + 1,
$li = $('' + (position) + ''),
thumbName,
self = this;
if (this.options.bulletThumbs) {
thumbName = $(slide).attr('data-thumb');
if (thumbName) {
$li
.addClass('has-thumb')
.css({background: "url(" + this.options.bulletThumbLocation + thumbName + ") no-repeat"});;
}
}
this.$bullets.append($li);
$li.data('index', index);
$li.click(function () {
self.stopClock();
if (self.options.resetTimerOnClick) {
self.rotateTimer(true);
self.startClock();
}
self.$element.trigger('orbit.goto', [$li.data('index')])
});
},
setActiveBullet: function () {
if(!this.options.bullets) { return false; } else {
this.$bullets.find('li')
.removeClass('active')
.eq(this.activeSlide)
.addClass('active');
}
},
resetAndUnlock: function () {
this.$slides
.eq(this.prevActiveSlide)
.css({"z-index" : 1});
this.unlock();
this.options.afterSlideChange.call(this, this.$slides.eq(this.prevActiveSlide), this.$slides.eq(this.activeSlide));
},
shift: function (direction) {
var slideDirection = direction;
//remember previous activeSlide
this.prevActiveSlide = this.activeSlide;
//exit function if bullet clicked is same as the current image
if (this.prevActiveSlide == slideDirection) { return false; }
if (this.$slides.length == "1") { return false; }
if (!this.locked) {
this.lock();
//deduce the proper activeImage
if (direction == "next") {
this.activeSlide++;
if (this.activeSlide == this.numberSlides) {
this.activeSlide = 0;
}
} else if (direction == "prev") {
this.activeSlide--
if (this.activeSlide < 0) {
this.activeSlide = this.numberSlides - 1;
}
} else {
this.activeSlide = direction;
if (this.prevActiveSlide < this.activeSlide) {
slideDirection = "next";
} else if (this.prevActiveSlide > this.activeSlide) {
slideDirection = "prev"
}
}
//set to correct bullet
this.setActiveBullet();
this.notifySlideChange();
//set previous slide z-index to one below what new activeSlide will be
this.$slides
.eq(this.prevActiveSlide)
.css({"z-index" : 2});
//fade
if (this.options.animation == "fade") {
this.$slides
.eq(this.activeSlide)
.css({"opacity" : 0, "z-index" : 3})
.animate({"opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.animate({"opacity":0}, this.options.animationSpeed);
}
//horizontal-slide
if (this.options.animation == "horizontal-slide") {
if (slideDirection == "next") {
this.$slides
.eq(this.activeSlide)
.css({"left": this.orbitWidth, "z-index" : 3})
.css("opacity", 1)
.animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock);
}
if (slideDirection == "prev") {
this.$slides
.eq(this.activeSlide)
.css({"left": -this.orbitWidth, "z-index" : 3})
.css("opacity", 1)
.animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock);
}
this.$slides
.eq(this.prevActiveSlide)
.css("opacity", 0);
}
//vertical-slide
if (this.options.animation == "vertical-slide") {
if (slideDirection == "prev") {
this.$slides
.eq(this.activeSlide)
.css({"top": this.orbitHeight, "z-index" : 3})
.css("opacity", 1)
.animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.css("opacity", 0);
}
if (slideDirection == "next") {
this.$slides
.eq(this.activeSlide)
.css({"top": -this.orbitHeight, "z-index" : 3})
.css("opacity", 1)
.animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock);
}
this.$slides
.eq(this.prevActiveSlide)
.css("opacity", 0);
}
//horizontal-push
if (this.options.animation == "horizontal-push") {
if (slideDirection == "next") {
this.$slides
.eq(this.activeSlide)
.css({"left": this.orbitWidth, "z-index" : 3})
.animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.animate({"left" : -this.orbitWidth}, this.options.animationSpeed, "", function(){
$(this).css({"opacity" : 0});
});
}
if (slideDirection == "prev") {
this.$slides
.eq(this.activeSlide)
.css({"left": -this.orbitWidth, "z-index" : 3})
.animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.animate({"left" : this.orbitWidth}, this.options.animationSpeed, "", function(){
$(this).css({"opacity" : 0});
});
}
}
//vertical-push
if (this.options.animation == "vertical-push") {
if (slideDirection == "next") {
this.$slides
.eq(this.activeSlide)
.css({top: -this.orbitHeight, "z-index" : 3})
.css("opacity", 1)
.animate({top : 0, "opacity":1}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.css("opacity", 0)
.animate({top : this.orbitHeight}, this.options.animationSpeed, "");
}
if (slideDirection == "prev") {
this.$slides
.eq(this.activeSlide)
.css({top: this.orbitHeight, "z-index" : 3})
.css("opacity", 1)
.animate({top : 0}, this.options.animationSpeed, this.resetAndUnlock);
this.$slides
.eq(this.prevActiveSlide)
.css("opacity", 0)
.animate({top : -this.orbitHeight}, this.options.animationSpeed);
}
}
this.setCaption();
}
// if on last slide and singleCycle is true, don't loop through slides again
// .length is zero based so must minus 1 to match activeSlide index
if (this.activeSlide === this.$slides.length-1 && this.options.singleCycle) {
this.stopClock();
}
}
};
$.fn.orbit = function (options) {
return this.each(function () {
var orbit = $.extend({}, ORBIT);
orbit.init(this, options);
});
};
})(jQuery);
/*!
* jQuery imageready Plugin
* http://www.zurb.com/playground/
*
* Copyright 2011, ZURB
* Released under the MIT License
*/
(function ($) {
var options = {};
$.event.special.imageready = {
setup: function (data, namespaces, eventHandle) {
options = data || options;
},
add: function (handleObj) {
var $this = $(this),
src;
if ( this.nodeType === 1 && this.tagName.toLowerCase() === 'img' && this.src !== '' ) {
if (options.forceLoad) {
src = $this.attr('src');
$this.attr('src', '');
bindToLoad(this, handleObj.handler);
$this.attr('src', src);
} else if ( this.complete || this.readyState === 4 ) {
handleObj.handler.apply(this, arguments);
} else {
bindToLoad(this, handleObj.handler);
}
}
},
teardown: function (namespaces) {
$(this).unbind('.imageready');
}
};
function bindToLoad(element, callback) {
var $this = $(element);
$this.bind('load.imageready', function () {
callback.apply(element, arguments);
$this.unbind('load.imageready');
});
}
}(jQuery));
/*
Holder - 1.3 - client side image placeholders
(c) 2012 Ivan Malopinsky / http://imsky.co
Provided under the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
Commercial use requires attribution.
*/
var Holder = Holder || {};
(function (app, win) {
var preempted = false,
fallback = false,
canvas = document.createElement('canvas');
//http://javascript.nwbox.com/ContentLoaded by Diego Perini with modifications
function contentLoaded(n,t){var l="complete",s="readystatechange",u=!1,h=u,c=!0,i=n.document,a=i.documentElement,e=i.addEventListener?"addEventListener":"attachEvent",v=i.addEventListener?"removeEventListener":"detachEvent",f=i.addEventListener?"":"on",r=function(e){(e.type!=s||i.readyState==l)&&((e.type=="load"?n:i)[v](f+e.type,r,u),!h&&(h=!0)&&t.call(n,null))},o=function(){try{a.doScroll("left")}catch(n){setTimeout(o,50);return}r("poll")};if(i.readyState==l)t.call(n,"lazy");else{if(i.createEventObject&&a.doScroll){try{c=!n.frameElement}catch(y){}c&&o()}i[e](f+"DOMContentLoaded",r,u),i[e](f+s,r,u),n[e](f+"load",r,u)}};
//https://gist.github.com/991057 by Jed Schmidt with modifications
function selector(a){
a=a.match(/^(\W)?(.*)/);var b=document["getElement"+(a[1]?a[1]=="#"?"ById":"sByClassName":"sByTagName")](a[2]);
var ret=[]; b!=null&&(b.length?ret=b:b.length==0?ret=b:ret=[b]); return ret;
}
//shallow object property extend
function extend(a,b){var c={};for(var d in a)c[d]=a[d];for(var e in b)c[e]=b[e];return c}
function draw(ctx, dimensions, template) {
var dimension_arr = [dimensions.height, dimensions.width].sort();
var maxFactor = Math.round(dimension_arr[1] / 16),
minFactor = Math.round(dimension_arr[0] / 16);
var text_height = Math.max(template.size, maxFactor);
canvas.width = dimensions.width;
canvas.height = dimensions.height;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = template.background;
ctx.fillRect(0, 0, dimensions.width, dimensions.height);
ctx.fillStyle = template.foreground;
ctx.font = "bold " + text_height + "px sans-serif";
var text = template.text ? template.text : (dimensions.width + "x" + dimensions.height);
if (Math.round(ctx.measureText(text).width) / dimensions.width > 1) {
text_height = Math.max(minFactor, template.size);
}
ctx.font = "bold " + text_height + "px sans-serif";
ctx.fillText(text, (dimensions.width / 2), (dimensions.height / 2), dimensions.width);
return canvas.toDataURL("image/png");
}
if (!canvas.getContext) {
fallback = true;
} else {
if (canvas.toDataURL("image/png").indexOf("data:image/png") < 0) {
//Android doesn't support data URI
fallback = true;
} else {
var ctx = canvas.getContext("2d");
}
}
var settings = {
domain: "holder.js",
images: "img",
themes: {
"gray": {
background: "#eee",
foreground: "#aaa",
size: 12
},
"social": {
background: "#3a5a97",
foreground: "#fff",
size: 12
},
"industrial": {
background: "#434A52",
foreground: "#C2F200",
size: 12
}
}
};
app.flags = {
dimensions: {
regex: /([0-9]+)x([0-9]+)/,
output: function(val){
var exec = this.regex.exec(val);
return {
width: +exec[1],
height: +exec[2]
}
}
},
colors: {
regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i,
output: function(val){
var exec = this.regex.exec(val);
return {
size: settings.themes.gray.size,
foreground: "#" + exec[2],
background: "#" + exec[1]
}
}
},
text: {
regex: /text\:(.*)/,
output: function(val){
return this.regex.exec(val)[1];
}
}
}
for(var flag in app.flags){
app.flags[flag].match = function (val){
return val.match(this.regex)
}
}
app.add_theme = function (name, theme) {
name != null && theme != null && (settings.themes[name] = theme);
return app;
};
app.add_image = function (src, el) {
var node = selector(el);
if (node.length) {
for (var i = 0, l = node.length; i < l; i++) {
var img = document.createElement("img")
img.setAttribute("data-src", src);
node[i].appendChild(img);
}
}
return app;
};
app.run = function (o) {
var options = extend(settings, o),
images = selector(options.images),
preempted = true;
for (var l = images.length, i = 0; i < l; i++) {
var theme = settings.themes.gray;
var src = images[i].getAttribute("data-src") || images[i].getAttribute("src");
if (src && !! ~src.indexOf(options.domain)) {
var render = false,
dimensions = null,
text = null;
var flags = src.substr(src.indexOf(options.domain) + options.domain.length + 1).split("/");
for (sl = flags.length, j = 0; j < sl; j++) {
if (app.flags.dimensions.match(flags[j])) {
render = true;
dimensions = app.flags.dimensions.output(flags[j]);
} else if (app.flags.colors.match(flags[j])) {
theme = app.flags.colors.output(flags[j]);
} else if (options.themes[flags[j]]) {
//If a theme is specified, it will override custom colors
theme = options.themes[flags[j]];
} else if (app.flags.text.match(flags[j])) {
text = app.flags.text.output(flags[j]);
}
}
if (render) {
images[i].setAttribute("data-src", src);
var dimensions_caption = dimensions.width + "x" + dimensions.height;
images[i].setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
// Fallback
// images[i].style.width = dimensions.width + "px";
// images[i].style.height = dimensions.height + "px";
images[i].style.backgroundColor = theme.background;
var theme = (text ? extend(theme, {
text: text
}) : theme);
if (!fallback) {
images[i].setAttribute("src", draw(ctx, dimensions, theme));
}
}
}
}
return app;
};
contentLoaded(win, function () {
preempted || app.run()
})
})(Holder, window);
(function(c,q){var m="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";c.fn.imagesLoaded=function(f){function n(){var b=c(j),a=c(h);d&&(h.length?d.reject(e,b,a):d.resolve(e));c.isFunction(f)&&f.call(g,e,b,a)}function p(b){k(b.target,"error"===b.type)}function k(b,a){b.src===m||-1!==c.inArray(b,l)||(l.push(b),a?h.push(b):j.push(b),c.data(b,"imagesLoaded",{isBroken:a,src:b.src}),r&&d.notifyWith(c(b),[a,e,c(j),c(h)]),e.length===l.length&&(setTimeout(n),e.unbind(".imagesLoaded",
p)))}var g=this,d=c.isFunction(c.Deferred)?c.Deferred():0,r=c.isFunction(d.notify),e=g.find("img").add(g.filter("img")),l=[],j=[],h=[];c.isPlainObject(f)&&c.each(f,function(b,a){if("callback"===b)f=a;else if(d)d[b](a)});e.length?e.bind("load.imagesLoaded error.imagesLoaded",p).each(function(b,a){var d=a.src,e=c.data(a,"imagesLoaded");if(e&&e.src===d)k(a,e.isBroken);else if(a.complete&&a.naturalWidth!==q)k(a,0===a.naturalWidth||0===a.naturalHeight);else if(a.readyState||a.complete)a.src=m,a.src=d}):
n();return d?d.promise(g):g}})(jQuery);
/**
* @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
*
* @version 0.5.1
* @codingstandard ftlabs-jsv2
* @copyright The Financial Times Limited [All Rights Reserved]
* @license MIT License (see LICENSE.txt)
*/
/*jslint browser:true, node:true*/
/*global define, Event, Node*/
/**
* Instantiate fast-clicking listeners on the specificed layer.
*
* @constructor
* @param {Element} layer The layer to listen on
*/
function FastClick(layer) {
'use strict';
var oldOnClick, self = this;
/**
* Whether a click is currently being tracked.
*
* @type boolean
*/
this.trackingClick = false;
/**
* Timestamp for when when click tracking started.
*
* @type number
*/
this.trackingClickStart = 0;
/**
* The element being tracked for a click.
*
* @type EventTarget
*/
this.targetElement = null;
/**
* X-coordinate of touch start event.
*
* @type number
*/
this.touchStartX = 0;
/**
* Y-coordinate of touch start event.
*
* @type number
*/
this.touchStartY = 0;
/**
* ID of the last touch, retrieved from Touch.identifier.
*
* @type number
*/
this.lastTouchIdentifier = 0;
/**
* The FastClick layer.
*
* @type Element
*/
this.layer = layer;
if (!layer || !layer.nodeType) {
throw new TypeError('Layer must be a document node');
}
/** @type function() */
this.onClick = function() { FastClick.prototype.onClick.apply(self, arguments); };
/** @type function() */
this.onTouchStart = function() { FastClick.prototype.onTouchStart.apply(self, arguments); };
/** @type function() */
this.onTouchMove = function() { FastClick.prototype.onTouchMove.apply(self, arguments); };
/** @type function() */
this.onTouchEnd = function() { FastClick.prototype.onTouchEnd.apply(self, arguments); };
/** @type function() */
this.onTouchCancel = function() { FastClick.prototype.onTouchCancel.apply(self, arguments); };
// Devices that don't support touch don't need FastClick
if (typeof window.ontouchstart === 'undefined') {
return;
}
// Set up event handlers as required
layer.addEventListener('click', this.onClick, true);
layer.addEventListener('touchstart', this.onTouchStart, false);
layer.addEventListener('touchmove', this.onTouchMove, false);
layer.addEventListener('touchend', this.onTouchEnd, false);
layer.addEventListener('touchcancel', this.onTouchCancel, false);
// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
// layer when they are cancelled.
if (!Event.prototype.stopImmediatePropagation) {
layer.removeEventListener = function(type, callback, capture) {
var rmv = Node.prototype.removeEventListener;
if (type === 'click') {
rmv.call(layer, type, callback.hijacked || callback, capture);
} else {
rmv.call(layer, type, callback, capture);
}
};
layer.addEventListener = function(type, callback, capture) {
var adv = Node.prototype.addEventListener;
if (type === 'click') {
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
if (!event.propagationStopped) {
callback(event);
}
}), capture);
} else {
adv.call(layer, type, callback, capture);
}
};
}
// If a handler is already declared in the element's onclick attribute, it will be fired before
// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
// adding it as listener.
if (typeof layer.onclick === 'function') {
// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
// - the old one won't work if passed to addEventListener directly.
oldOnClick = layer.onclick;
layer.addEventListener('click', function(event) {
oldOnClick(event);
}, false);
layer.onclick = null;
}
}
/**
* Android requires an exception for labels.
*
* @type boolean
*/
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
/**
* iOS requires an exception for alert confirm dialogs.
*
* @type boolean
*/
FastClick.prototype.deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
/**
* iOS 4 requires an exception for select elements.
*
* @type boolean
*/
FastClick.prototype.deviceIsIOS4 = FastClick.prototype.deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
/**
* Determine whether a given element requires a native click.
*
* @param {EventTarget|Element} target Target DOM element
* @returns {boolean} Returns true if the element needs a native click
*/
FastClick.prototype.needsClick = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
case 'label':
case 'video':
return true;
default:
return (/\bneedsclick\b/).test(target.className);
}
};
/**
* Determine whether a given element requires a call to focus to simulate click into element.
*
* @param {EventTarget|Element} target Target DOM element
* @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
*/
FastClick.prototype.needsFocus = function(target) {
'use strict';
switch (target.nodeName.toLowerCase()) {
case 'textarea':
case 'select':
return true;
case 'input':
switch (target.type) {
case 'button':
case 'checkbox':
case 'file':
case 'image':
case 'radio':
case 'submit':
return false;
}
return true;
default:
return (/\bneedsfocus\b/).test(target.className);
}
};
/**
* Send a click event to the specified element.
*
* @param {EventTarget|Element} targetElement
* @param {Event} event
*/
FastClick.prototype.sendClick = function(targetElement, event) {
'use strict';
var clickEvent, touch;
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
if (document.activeElement && document.activeElement !== targetElement) {
document.activeElement.blur();
}
touch = event.changedTouches[0];
// Synthesise a click event, with an extra attribute so it can be tracked
clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
clickEvent.forwardedTouchEvent = true;
targetElement.dispatchEvent(clickEvent);
};
/**
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.focus = function(targetElement) {
'use strict';
var length;
if (this.deviceIsIOS && targetElement.setSelectionRange) {
length = targetElement.value.length;
targetElement.setSelectionRange(length, length);
} else {
targetElement.focus();
}
};
/**
* Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
*
* @param {EventTarget|Element} targetElement
*/
FastClick.prototype.updateScrollParent = function(targetElement) {
'use strict';
var scrollParent, parentElement;
scrollParent = targetElement.fastClickScrollParent;
// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
// target element was moved to another parent.
if (!scrollParent || !scrollParent.contains(targetElement)) {
parentElement = targetElement;
do {
if (parentElement.scrollHeight > parentElement.offsetHeight) {
scrollParent = parentElement;
targetElement.fastClickScrollParent = parentElement;
break;
}
parentElement = parentElement.parentElement;
} while (parentElement);
}
// Always update the scroll top tracker if possible.
if (scrollParent) {
scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
}
};
/**
* @param {EventTarget} targetElement
* @returns {Element|EventTarget}
*/
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
'use strict';
// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
if (eventTarget.nodeType === Node.TEXT_NODE) {
return eventTarget.parentNode;
}
return eventTarget;
};
/**
* On touch start, record the position and scroll offset.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchStart = function(event) {
'use strict';
var targetElement, touch;
targetElement = this.getTargetElementFromEventTarget(event.target);
touch = event.targetTouches[0];
if (this.deviceIsIOS) {
// Only trusted events will deselect text on iOS (issue #49)
if (window.getSelection().rangeCount) {
return true;
}
if (!this.deviceIsIOS4) {
// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
// with the same identifier as the touch event that previously triggered the click that triggered the alert.
// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
if (touch.identifier === this.lastTouchIdentifier) {
event.preventDefault();
return false;
}
this.lastTouchIdentifier = touch.identifier;
// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
// 1) the user does a fling scroll on the scrollable layer
// 2) the user stops the fling scroll with another tap
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
this.updateScrollParent(targetElement);
}
}
this.trackingClick = true;
this.trackingClickStart = event.timeStamp;
this.targetElement = targetElement;
this.touchStartX = touch.pageX;
this.touchStartY = touch.pageY;
// Prevent phantom clicks on fast double-tap (issue #36)
if ((event.timeStamp - this.lastClickTime) < 200) {
event.preventDefault();
}
return true;
};
/**
* Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.touchHasMoved = function(event) {
'use strict';
var touch = event.targetTouches[0];
if (Math.abs(touch.pageX - this.touchStartX) > 10 || Math.abs(touch.pageY - this.touchStartY) > 10) {
return true;
}
return false;
};
/**
* Update the last position.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchMove = function(event) {
'use strict';
if (!this.trackingClick) {
return true;
}
// If the touch has moved, cancel the click tracking
if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
this.trackingClick = false;
this.targetElement = null;
}
return true;
};
/**
* Attempt to find the labelled control for the given label element.
*
* @param {EventTarget|HTMLLabelElement} labelElement
* @returns {Element|null}
*/
FastClick.prototype.findControl = function(labelElement) {
'use strict';
// Fast path for newer browsers supporting the HTML5 control attribute
if (labelElement.control !== undefined) {
return labelElement.control;
}
// All browsers under test that support touch events also support the HTML5 htmlFor attribute
if (labelElement.htmlFor) {
return document.getElementById(labelElement.htmlFor);
}
// If no for attribute exists, attempt to retrieve the first labellable descendant element
// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
};
/**
* On touch end, determine whether to send a click event at once.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onTouchEnd = function(event) {
'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, targetElement = this.targetElement;
if (!this.trackingClick) {
return true;
}
// Prevent phantom clicks on fast double-tap (issue #36)
if ((event.timeStamp - this.lastClickTime) < 200) {
this.cancelNextClick = true;
return true;
}
this.lastClickTime = event.timeStamp;
trackingClickStart = this.trackingClickStart;
this.trackingClick = false;
this.trackingClickStart = 0;
targetTagName = targetElement.tagName.toLowerCase();
if (targetTagName === 'label') {
forElement = this.findControl(targetElement);
if (forElement) {
this.focus(targetElement);
if (this.deviceIsAndroid) {
return false;
}
targetElement = forElement;
}
} else if (this.needsFocus(targetElement)) {
// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
this.targetElement = null;
return false;
}
this.focus(targetElement);
// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
if (!this.deviceIsIOS4 || targetTagName !== 'select') {
this.targetElement = null;
event.preventDefault();
}
return false;
}
if (this.deviceIsIOS && !this.deviceIsIOS4) {
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
scrollParent = targetElement.fastClickScrollParent;
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
return true;
}
}
// Prevent the actual click from going though - unless the target node is marked as requiring
// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
if (!this.needsClick(targetElement)) {
event.preventDefault();
this.sendClick(targetElement, event);
}
return false;
};
/**
* On touch cancel, stop tracking the click.
*
* @returns {void}
*/
FastClick.prototype.onTouchCancel = function() {
'use strict';
this.trackingClick = false;
this.targetElement = null;
};
/**
* On actual clicks, determine whether this is a touch-generated click, a click action occurring
* naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
* an actual click which should be permitted.
*
* @param {Event} event
* @returns {boolean}
*/
FastClick.prototype.onClick = function(event) {
'use strict';
var oldTargetElement;
// If a target element was never set (because a touch event was never fired) allow the click
if (!this.targetElement) {
return true;
}
if (event.forwardedTouchEvent) {
return true;
}
oldTargetElement = this.targetElement;
this.targetElement = null;
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
if (this.trackingClick) {
this.trackingClick = false;
return true;
}
// Programmatically generated events targeting a specific element should be permitted
if (!event.cancelable) {
return true;
}
// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
if (event.target.type === 'submit' && event.detail === 0) {
return true;
}
// Derive and check the target element to see whether the click needs to be permitted;
// unless explicitly enabled, prevent non-touch click events from triggering actions,
// to prevent ghost/doubleclicks.
if (!this.needsClick(oldTargetElement) || this.cancelNextClick) {
this.cancelNextClick = false;
// Prevent any user-added listeners declared on FastClick element from being fired.
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
event.propagationStopped = true;
}
// Cancel the event
event.stopPropagation();
event.preventDefault();
return false;
}
// If clicks are permitted, return true for the action to go through.
return true;
};
/**
* Remove all FastClick's event listeners.
*
* @returns {void}
*/
FastClick.prototype.destroy = function() {
'use strict';
var layer = this.layer;
layer.removeEventListener('click', this.onClick, true);
layer.removeEventListener('touchstart', this.onTouchStart, false);
layer.removeEventListener('touchmove', this.onTouchMove, false);
layer.removeEventListener('touchend', this.onTouchEnd, false);
layer.removeEventListener('touchcancel', this.onTouchCancel, false);
};
if (typeof define !== 'undefined' && define.amd) {
// AMD. Register as an anonymous module.
define(function() {
'use strict';
return FastClick;
});
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = function(layer) {
'use strict';
return new FastClick(layer);
};
module.exports.FastClick = FastClick;
}
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.0.6
*
* Requires: 1.2.2+
*/
(function($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for ( var i=types.length; i; ) {
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i=types.length; i; ) {
this.addEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
this.removeEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);
/*
* jScrollPane - v2.0.0beta12 - 2012-09-27
* http://jscrollpane.kelvinluck.com/
*
* Copyright (c) 2010 Kelvin Luck
* Dual licensed under the MIT or GPL licenses.
*/
(function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('').css("padding",aH).append(D.children());al=b('').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('').append(b(''),b('').append(b('').append(b(''),b(''))),b('')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('').append(b(''),b('').append(b('').append(b(''),b(''))),b('')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB);
if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(atay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(AaS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQaS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQi){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL;aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae)
}else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(saO){aR=s-v+aK+ay.verticalGutter}}if(aR){M(aR,aJ)}aP=aC();aS=aP+aj;if(aUaS){aT=aU-aj+aL+ay.horizontalGutter}}if(aT){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aL,aM,aK,aI){var aJ=aa,s=I;Q.scrollBy(aK*ay.mouseWheelSpeed,-aI*ay.mouseWheelSpeed,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1));aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aNaL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault()
})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this);
/*
@name View.js — A simple, lightweight, jQuery photo viewer for the web
@category Lightbox, Image Viewer
@author Rogie King
@copyright 2011-2011 Rogie King
@version 1.02
@license By purchasing View.js, you agree to the following: View.js remain property of Rogie King. View.js may be used by the licensee in any personal or commercial projects. View.js may not be resold or redistributed. For example: packaged in an application where it could be downloaded for free, such as an open-source project or other application where View.js is bundled along with other files.View.js — A simple, lightweight, jQuery photo viewer for the web by Rogie King is licensed under a Creative Commons Attribution-NoDerivs 3.0 Unported License.
*/
function View(a,b){function v(){t();q();d=c.find("img");g("body").append(c);if(!View._cssified){n()}View._cssified=true;u();i.sync();i.close();if(b.preload){i.show(d.eq(0))}i._ie7=navigator.userAgent.indexOf("MSIE 7")>-1;g(window).resize(function(){i.sync()})}function u(){c.unbind("click.view").bind("click.view",m)}function t(){if(typeof a=="object"&&a.jquery){a.filter("a[href]").each(function(){if(s(this.href)||!b.validateUrls){h.push({src:this.href,caption:this.title})}g(this).unbind("click.view").bind("click.view",r)})}else if(g.isArray(a)){h=a}}function s(a){return/\.(jpeg|jpg|gif|png)(\?|#)?(.*)?$/ig.test(a)}function r(a){a.preventDefault();i.show(this.href);i.open()}function q(){if(g.isArray(h)){for(var a=0,b;b=h[a];++a){var c=null;var d=g('');if(typeof b=="object"&&b.src){c=b.src}else if(typeof b=="string"){c=b}var f=new Image;f.onload=function(){i.sync();g(this).css({visibility:"visible"}).parents("li").removeClass("loading")};g(f).css({visibility:"hidden"});g(f).attr("data-src",c);if(b.caption){d.addClass("has-caption").append(g('').text(b.caption))}if(a==0){d.addClass("first")}if(a==h.length-1){d.addClass("last")}e.append(d.append(g("").append(g("").append(f))))}}}function p(a){if(!a.src){g(a).attr("src",g(a).attr("data-src"))}}function o(a,b){p(a.find("img"));a.nextAll().slice(0,b).add(a.prevAll().slice(0,b)).find("img").each(function(a,b){p(b)})}function n(){var a=g("");g("head").prepend(a);var c=document.styleSheets[0];for(h in b.css){var d="";for(name in b.css[h]){d+=name+":"+b.css[h][name]+";"}var e=h.split(",");for(var f=0,h;h=e[f];++f){if(c.insertRule){c.insertRule(h+"{"+d+"}",c.cssRules.length)}else{c.addRule(h,d)}}}}function m(a){a.preventDefault();$t=g(a.target);if(e.find("li").length<=1){i.close()}if($t.is("img")){if($t.parents("li").is(".current")){i.next()}else{i.show($t)}}else if($t.is("li>div,li")){if($t.parents("li").is(".next")||$t.is(".next")){i.next()}else if($t.parents("li").is(".previous")||$t.is(".previous")){i.prev()}else{i.close()}}else{i.close()}}function l(a){g.each(b.keys,function(b,c){for(var d=0;d×').hide();e=c.find("ul");var b=g.extend({css:{"body.viewing":{overflow:"hidden"},".viewer *, .viewer":{margin:0,padding:0,border:0},".viewer":{"background-color":"#222",filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D8000000,endColorstr=#D8000000)","background-color":"rgba(0,0,0,0.85)",position:"fixed",right:0,top:0,left:0,bottom:0,display:"block",overflow:"hidden","z-index":Math.ceil((new Date).getTime()/1e7),height:"100%",width:"100%"},".viewer li.current + .loading":{"background-position":"0 center"},".viewer ul":{display:"block",height:"100%",width:"100%","white-space":"nowrap"},".viewer li":{height:"100%",width:"0%",overflow:"hidden",display:"none","float":"left","text-align":"center",position:"relative"},".viewer li.previous, .viewer li.next":{cursor:"pointer",display:"block"},".viewer li>div":{left:"10px",right:"10px",bottom:"10px",top:"10px",display:"block","text-align":"center",position:"absolute"},".viewer li.has-caption>div":{bottom:"5em"},".viewer li.loading>div":{background:"url(data:image/gif;base64,R0lGODlhDAAMAPIGAFxcXE5OTlZWVkpKSkZGRkJCQgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFHgAGACwAAAAADAAMAAADLmhaIRJFSQHEGFRMQKQhlVFwngIyWqk8lqpgrYs1rvGMXXnapASmPAsm5EHdJAkAIfkEBR4AAQAsBgABAAMABQAAAgaEbwISHAUAIfkEBR4AAQAsBgADAAUAAwAAAgOEj1kAIfkEBR4AAgAsBgAGAAUAAwAAAgYMDmInegUAIfkEBR4AAQAsBgAGAAMABQAAAgOEj1kAIfkEBR4AAgAsAwAGAAMABQAAAgaUchDAzQUAIfkEBR4AAQAsAQAGAAUAAwAAAgOEj1kAIfkEBR4AAgAsAQADAAUAAwAAAgYEImKnGwUAIfkEBR4AAQAsAwABAAMABQAAAgOEj1kAOw%3D%3D) center center no-repeat"},".viewer li.loading.next>div":{"background-position":"0 center"},".viewer li.loading.previous>div":{"background-position":"right center"},".viewer .close":{color:"#fff","text-decoration":"none","font-weight":"bold","font-size":"20px",position:"absolute",right:"15px",top:"15px",cursor:"pointer",display:"block",opacity:.6},".viewer .close:hover":{opacity:1},".viewer img":{"max-width":"100%","max-height":"100%",cursor:"pointer",position:"relative",height:"auto",width:"auto","vertical-align":"middle","-ms-interpolation-mode":"bicubic"},".viewer .caption":{color:"#aaa","text-shadow":"0 1px 2px rgba(0,0,0,0.8)","line-height":"5em",position:"absolute",bottom:"0",left:"0",right:"0",visibility:"hidden"},".viewer li.current .caption":{visibility:"visible"},".viewer li.previous":{width:"10%"},".viewer li.current":{width:"80%",display:"block"},".viewer li.first.current":{"margin-left":"10%"},".viewer li.last.current":{"margin-right":"10%"},".viewer li.next":{width:"10%"},".viewer li.previous>div":{left:"-50%",right:"50%"},".viewer li.next>div":{right:"-50%",left:"50%"},".viewer .next img, .viewer .previous img, .viewer .current img":{"-webkit-transform":"translateZ(0)"}},keys:{close:[27],prev:[37,188],next:[39,190]},loadAhead:1,preload:false,validateUrls:true},b);this.next=function(){this.show(f.next().find("img"))};this.prev=function(){this.show(f.prev().find("img"))};this.close=function(){c.hide();g(document).unbind("keyup.view");j.removeClass("viewing")};this.open=function(){c.show();g(document).bind("keyup.view",l);j.addClass("viewing");this.sync()};this.show=function(a){if(typeof a=="string"){a=k(a)}if(a.constructor==g&&a.length>0){c.find("li").removeClass("current next previous").removeAttr("title");f=$parent=a.parents("li").addClass("current");f.next().addClass("next").attr("title","Next");f.prev().addClass("previous").attr("title","Previous");this.sync();o(f,b.loadAhead)}};this.sync=function(){var a=e.find("li.current>div").height();var b=a+"px";e.find("li>div>span").each(function(){g(this).css({"line-height":b})});if(i._ie7){d.css({"max-height":b});d.each(function(){var b=g(this);b.css({top:(a-b.height())/2+"px"})})}};this.next=function(){i.show(f.next().find("img"))};this.prev=function(){i.show(f.prev().find("img"))};v()}View._version="1.02";(function(){var a=jQuery,b=document.getElementsByTagName("script");if(b[b.length-1].src.indexOf("?auto")>-1){a().ready(function(){var b=a("a.view[href]");var c={};b.each(function(){var b=this.rel;if(b){if(!c[b]){c[b]=[]}c[b].push(this)}else{new View(a(this))}});for(var d in c){new View(a(c[d]))}})}})()
$(document).ready(function() {
var switched = false;
var updateTables = function() {
if (($(window).width() < 767) && !switched ){
switched = true;
$("table.responsive").each(function(i, element) {
splitTable($(element));
});
return true;
}
else if (switched && ($(window).width() > 767)) {
switched = false;
$("table.responsive").each(function(i, element) {
unsplitTable($(element));
});
}
};
$(window).load(updateTables);
$(window).bind("resize", updateTables);
function splitTable(original)
{
original.wrap("");
var copy = original.clone();
copy.find("td:not(:first-child), th:not(:first-child)").css("display", "none");
copy.removeClass("responsive");
original.closest(".table-wrapper").append(copy);
copy.wrap("");
original.wrap("");
setCellHeights(original, copy);
}
function unsplitTable(original) {
original.closest(".table-wrapper").find(".pinned").remove();
original.unwrap();
original.unwrap();
}
function setCellHeights(original, copy) {
var tr = original.find('tr'),
tr_copy = copy.find('tr'),
heights = [];
tr.each(function (index) {
var self = $(this),
tx = self.find('th, td');
tx.each(function () {
var height = $(this).outerHeight(true);
heights[index] = heights[index] || 0;
if (height > heights[index]) heights[index] = height;
});
});
tr_copy.each(function (index) {
$(this).height(heights[index]);
});
}
});