DeferSource = { put: function(element, property, value) { var putObj = {}; putObj[property] = value; element.dataset.defer = JSON.stringify(Object.assign(DeferSource.list(element), putObj)); }, set: function(element, values) { element.dataset.defer = JSON.stringify(values); }, add: function(element, value) { this.set( element, $.extend(JSON.parse(element.dataset.defer), value) ); }, remove: function(element, property) { if(this.has(element, property)) { var values = this.list(element); delete values[property]; this.set(element, values); } }, get: function(element, property) { return this.list(element)[property]; }, has: function(element, property) { return this.list(element).hasOwnProperty(property); }, list: function(element) { if(!element.dataset.defer) { return {}; } return JSON.parse(element.dataset.defer); }, activate: function(element, property) { if(property && this.has(element, property)) { element[property] = this.get(element, property); this.remove(element, property); } else { for (property in this.list(element)){ if (this.list(element).hasOwnProperty(property)) { this.activate(element, property); } } } }, deactivate: function(element, property) { if(property && element[property]) { var add = {}; add[property] = element[property]; this.add(element, add); element.removeAttribute(property); } } }; function onStyleChange(element, callback) { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if(mutation.attributeName === "style") { callback(); } }); }); return { "start": function() { observer.observe(element, { attributes: true, attributeFilter: ["style"], childList: false }); }, "stop": function() { observer.disconnect(); } }; } function isIPhone() { return (navigator.userAgent.includes("Mobile/") && navigator.userAgent.includes("AppleWebKit/")); } function addListenerMulti(el, s, fn, options) { s.split(" ").forEach(function(e){ el.addEventListener(e,fn, options,false); }); } function isElementInEventPath(el, event) { if(undefined !== event.path) { return event.path.includes(el); } else { var pathElement = event.target ? event.target : event.srcElement; while(pathElement) { if(el === pathElement) { return true; } pathElement = pathElement.parentNode; } return false; } } function onElementHover(element, onHoverCallback, onHoverEndCallback) { var elementIsHovered = false; addListenerMulti(element, "mouseenter touchstart", function(event) { elementIsHovered = true; onHoverCallback(); document.addEventListener("touchstart", touchscreenClickedOut); event.preventDefault(); event.stopPropagation(); }); function touchscreenClickedOut(event) { if(elementIsHovered && !isElementInEventPath(element, event)) { hoverStopped(event); } } element.addEventListener("mouseleave", hoverStopped); function hoverStopped(event) { if(elementIsHovered) { elementIsHovered = false; onHoverEndCallback(event); document.removeEventListener("touchstart", touchscreenClickedOut); } } } function forAllElements(selector, callback) { var elements = selector; if("string" === typeof selector) { elements = document.querySelectorAll(selector); } if(elements) { [].forEach.call(elements, callback); } } function getEventXY(event) { var coords = {x:undefined,y:undefined}; if(undefined !== event.pageX) { coords.x = event.pageX; coords.y = event.pageY; } else if("undefined" !== typeof event.originalEvent && "undefined" !== typeof event.originalEvent.changedTouches && "undefined" !== typeof event.originalEvent.changedTouches[0] && "undefined" !== typeof event.originalEvent.changedTouches[0].pageX) { coords.x = event.originalEvent.changedTouches[0].pageX; coords.y = event.originalEvent.changedTouches[0].pageY; } return coords; } function clickWithoutMovement(element, callback, preventDefault=true) { var currentMousePosition = {}; var dragTolerance = Math.min(screen.width, screen.height)*0.01953125; $(element).on('touchstart mousedown', function (downEvent) { currentMousePosition = getEventXY(downEvent); var endEvent = ("touchstart" === downEvent.type ? "touchend": "mouseup"); var triggered = false; $(element).one(endEvent, function handler(upEvent) { if(!triggered) { triggered = true; var newMousePosition = getEventXY(upEvent); if (Math.abs(newMousePosition.x - currentMousePosition.x) < dragTolerance && Math.abs(newMousePosition.y - currentMousePosition.y) < dragTolerance) { callback(upEvent); } } if(preventDefault) { upEvent.preventDefault(); } }); if(preventDefault) { downEvent.preventDefault(); } }); } function pauseVideoElement(element) { if("IFRAME" === element.nodeName) { if (element.src.includes("youtube.com/embed")) { element.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*'); } } else if("VIDEO" === element.nodeName) { element.pause(); } } // Prevent touch and scroll events from reaching the parent element. function stopTouchAndScrollEventPropagation(element) { var eventList = [ 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'wheel', 'mousewheel' //Additional events , 'pointerover', 'pointerenter', 'pointerdown', 'gotpointercapture', 'pointermove', 'touchmove', 'pointercancel', 'lostpointercapture', 'pointerout', 'pointerleave', 'pointerup' ]; for (var i = 0; i < eventList.length; i++) { element.addEventListener(eventList[i], stopPropagation); } } function enableTouchAndScrollEventPropagation(element) { var eventList = [ 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'wheel', 'mousewheel' //Additional events , 'pointerover', 'pointerenter', 'pointerdown', 'gotpointercapture', 'pointermove', 'touchmove', 'pointercancel', 'lostpointercapture', 'pointerout', 'pointerleave', 'pointerup' ]; for (var i = 0; i < eventList.length; i++) { element.removeEventListener(eventList[i], stopPropagation); } } function stopPropagation(e) { e.stopPropagation(); } function classInstancesTracking(ClassFunction) { ClassFunction.create = function(params) { var classObject = Object.create(ClassFunction.prototype); ClassFunction.apply(classObject, arguments); ClassFunction.instances.push(classObject); return classObject; }; ClassFunction.prototype.destroy = function () { var i = 0; while (ClassFunction.instances[i] !== this) { i++; } ClassFunction.instances.splice(i, 1); }; ClassFunction.instances = []; ClassFunction.findByValue = function(property, value) { return ClassFunction.instances.find(function(el, i) { return (value === el[property]); }); }; } function supportsVideoType(type) { //Safari doesn't support transparency if("webm" === type && /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { return false; } var video; // Allow user to create shortcuts, i.e. just "webm" var formats = { ogg: 'video/ogg; codecs="theora"', h264: 'video/mp4; codecs="avc1.42E01E"', webm: 'video/webm; codecs="vp8, vorbis"', vp9: 'video/webm; codecs="vp9"', hls: 'application/x-mpegURL; codecs="avc1.42E01E"' }; if(!video) { video = document.createElement('video') } return ("probably" === video.canPlayType(formats[type] || type)); } function animateCss(element, animationName, callback) { var animationEnd = (function(el) { var animations = { animation: 'animationend', OAnimation: 'oAnimationEnd', MozAnimation: 'mozAnimationEnd', WebkitAnimation: 'webkitAnimationEnd', }; for (var t in animations) { if (el.style[t] !== undefined) { return animations[t]; } } })(document.createElement('div')); $(element).addClass('animated ' + animationName).one(animationEnd, function() { $(element).removeClass('animated ' + animationName); if (typeof callback === 'function') callback(); }); return this; } //Add Find and Includes to IE // https://tc39.github.io/ecma262/#sec-array.prototype.find if (!Array.prototype.find) { Object.defineProperty(Array.prototype, 'find', { value: function(predicate) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If IsCallable(predicate) is false, throw a TypeError exception. if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. var thisArg = arguments[1]; // 5. Let k be 0. var k = 0; // 6. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kValue be ? Get(O, Pk). // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). // d. If testResult is true, return kValue. var kValue = o[k]; if (predicate.call(thisArg, kValue, k, o)) { return kValue; } // e. Increase k by 1. k++; } // 7. Return undefined. return undefined; } }); } if (!String.prototype.includes) { String.prototype.includes = function(search, start) { if (typeof start !== 'number') { start = 0; } if (start + search.length > this.length) { return false; } else { return this.indexOf(search, start) !== -1; } }; } //End of add find and includes to IE //IE workaround for action bar custom event (function () { function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent( 'CustomEvent' ); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; })(); //End of IE action bar workaround //Detect any safari (including firefox and chrome on ios), currently used to workaround not being able to change cues on guides function isAnySafari() { return( navigator.vendor && navigator.vendor.indexOf('Apple') > -1); } //IE workaround show all interactive elements over panorama function isIE() { var ua = window.navigator.userAgent; var msie = ua.indexOf('MSIE '); // IE 10 or older var trident = ua.indexOf('Trident/'); //IE 11 return (msie > 0 || trident > 0); } if(isIE()) { var sheet = (function() { // Create the