/* Modernizr 2.8.3 (Custom Build) | MIT & BSD * Build: http://modernizr.com/download/#-geolocation-touch-cssclasses-teststyles-hasevent-prefixes */ ; window.Modernizr = (function( window, document, undefined ) { var version = '2.8.3', Modernizr = {}, enableClasses = true, docElement = document.documentElement, mod = 'modernizr', modElem = document.createElement(mod), mStyle = modElem.style, inputElem , toString = {}.toString, prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), tests = {}, inputs = {}, attrs = {}, classes = [], slice = classes.slice, featureName, injectElementWithStyles = function( rule, callback, nodes, testnames ) { var style, ret, node, docOverflow, div = document.createElement('div'), body = document.body, fakeBody = body || document.createElement('body'); if ( parseInt(nodes, 10) ) { while ( nodes-- ) { node = document.createElement('div'); node.id = testnames ? testnames[nodes] : mod + (nodes + 1); div.appendChild(node); } } style = ['­',''].join(''); div.id = mod; (body ? div : fakeBody).innerHTML += style; fakeBody.appendChild(div); if ( !body ) { fakeBody.style.background = ''; fakeBody.style.overflow = 'hidden'; docOverflow = docElement.style.overflow; docElement.style.overflow = 'hidden'; docElement.appendChild(fakeBody); } ret = callback(div, rule); if ( !body ) { fakeBody.parentNode.removeChild(fakeBody); docElement.style.overflow = docOverflow; } else { div.parentNode.removeChild(div); } return !!ret; }, isEventSupported = (function() { var TAGNAMES = { 'select': 'input', 'change': 'input', 'submit': 'form', 'reset': 'form', 'error': 'img', 'load': 'img', 'abort': 'img' }; function isEventSupported( eventName, element ) { element = element || document.createElement(TAGNAMES[eventName] || 'div'); eventName = 'on' + eventName; var isSupported = eventName in element; if ( !isSupported ) { if ( !element.setAttribute ) { element = document.createElement('div'); } if ( element.setAttribute && element.removeAttribute ) { element.setAttribute(eventName, ''); isSupported = is(element[eventName], 'function'); if ( !is(element[eventName], 'undefined') ) { element[eventName] = undefined; } element.removeAttribute(eventName); } } element = null; return isSupported; } return isEventSupported; })(), _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp; if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { hasOwnProp = function (object, property) { return _hasOwnProperty.call(object, property); }; } else { hasOwnProp = function (object, property) { return ((property in object) && is(object.constructor.prototype[property], 'undefined')); }; } if (!Function.prototype.bind) { Function.prototype.bind = function bind(that) { var target = this; if (typeof target != "function") { throw new TypeError(); } var args = slice.call(arguments, 1), bound = function () { if (this instanceof bound) { var F = function(){}; F.prototype = target.prototype; var self = new F(); var result = target.apply( self, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return self; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; return bound; }; } function setCss( str ) { mStyle.cssText = str; } function setCssAll( str1, str2 ) { return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); } function is( obj, type ) { return typeof obj === type; } function contains( str, substr ) { return !!~('' + str).indexOf(substr); } function testDOMProps( props, obj, elem ) { for ( var i in props ) { var item = obj[props[i]]; if ( item !== undefined) { if (elem === false) return props[i]; if (is(item, 'function')){ return item.bind(elem || obj); } return item; } } return false; } tests['touch'] = function() { var bool; if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { bool = true; } else { injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) { bool = node.offsetTop === 9; }); } return bool; }; tests['geolocation'] = function() { return 'geolocation' in navigator; }; for ( var feature in tests ) { if ( hasOwnProp(tests, feature) ) { featureName = feature.toLowerCase(); Modernizr[featureName] = tests[feature](); classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); } } Modernizr.addTest = function ( feature, test ) { if ( typeof feature == 'object' ) { for ( var key in feature ) { if ( hasOwnProp( feature, key ) ) { Modernizr.addTest( key, feature[ key ] ); } } } else { feature = feature.toLowerCase(); if ( Modernizr[feature] !== undefined ) { return Modernizr; } test = typeof test == 'function' ? test() : test; if (typeof enableClasses !== "undefined" && enableClasses) { docElement.className += ' ' + (test ? '' : 'no-') + feature; } Modernizr[feature] = test; } return Modernizr; }; setCss(''); modElem = inputElem = null; Modernizr._version = version; Modernizr._prefixes = prefixes; Modernizr.hasEvent = isEventSupported; Modernizr.testStyles = injectElementWithStyles; docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + (enableClasses ? ' js ' + classes.join(' ') : ''); return Modernizr; })(this, this.document); ; /** * Utilities; useful scripts * * @author Tijs Verkoyen * @author Thomas Deceuninck */ var utils = { debug: false }; /** * Functions related to arrays * * @author Tijs Verkoyen */ utils.array = { /** * Is the given value present in the array * * @return bool */ inArray: function(needle, array) { // loop values for(var i in array) { if(array[i] == needle) return true; } // fallback return false; } }; /** * Function related to cookies * * @author Tijs Verkoyen */ utils.cookies = { /** * Are cookies enabled? * * @return bool */ isEnabled: function() { // try to grab the property var cookiesEnabled = !!(navigator.cookieEnabled); // unknown property? if(typeof navigator.cookieEnabled == 'undefined' && !cookiesEnabled) { // try to set a cookie document.cookie = 'testcookie'; cookiesEnabled = ($.inArray('testcookie', document.cookie) != -1); } // return return cookiesEnabled; }, /** * Read a cookie * * @return mixed */ readCookie: function(name) { // get cookies var cookies = document.cookie.split(';'); name = name + '='; for(var i = 0; i < cookies.length; i++) { var cookie = cookies[i]; while(cookie.charAt(0) === ' ') cookie = cookie.substring(1, cookie.length); if(cookie.indexOf(name) === 0) return cookie.substring(name.length, cookie.length); } // fallback return null; }, setCookie: function(name, value, days) { if(typeof days == 'undefined') days = 7; var expireDate = new Date(); expireDate.setDate(expireDate.getDate() + days); document.cookie = name + '=' + escape(value) + ';expires=' + expireDate.toUTCString() + ';path=/'; } }; /** * Functions related to forms * * @author Tijs Verkoyen */ utils.form = { /** * Is a checkbox checked? * * @return bool * @param object element */ isChecked: function(element) { return ($('input[name="' + element.attr('name') + '"]:checked').length >= 1); }, /** * Is the value inside the element a valid email address * * @return bool * @param object element */ isEmail: function(element) { var regexp = /^[a-z0-9!#\$%&'*+-\/=?^_`{|}\.~]+@([a-z0-9]+([\-]+[a-z0-9]+)*\.)+[a-z]{2,7}$/i; return regexp.test(element.val()); }, /** * Is the element filled * * @return bool * @param object element */ isFilled: function(element) { return (utils.string.trim(element.val()) !== ''); }, /** * Is the value inside the element a valid number * * @return bool * @param object element */ isNumber: function(element) { return (!isNaN(element.val()) && element.val() !== ''); }, /** * Is the value inside the element a valid URL * * @return bool * @param object element */ isURL: function(element) { var regexp = /^((http|ftp|https):\/{2})?(([0-9a-zA-Z_-]+\.)+[0-9a-zA-Z]+)((:[0-9]+)?)((\/([~0-9a-zA-Z\#%@\.\/_-]+)?(\?[0-9a-zA-Z%@\/&=_-]+)?)?)$/i; return regexp.test(element.val()); } }; /** * Functions related to strings * * @author Tijs Verkoyen * @author Dieter Vanden Eynde * @author Matthias Mullie */ utils.string = { // data member div: false, /** * Fix a HTML5-chunk, so IE can render it * * @return string * @param string html */ html5: function(html) { var html5 = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '); // create div if needed if(utils.string.div === false) { utils.string.div = document.createElement('div'); utils.string.div.innerHTML = ''; if(utils.string.div.childNodes.length !== 1) { var fragment = document.createDocumentFragment(); var i = html5.length; while(i--) fragment.createElement(html5[i]); fragment.appendChild(utils.string.div); } } html = html.replace(/^\s\s*/, '').replace(/\s\s*$/, '') .replace(/)<[^<]*)*<\/script>/gi, ''); // fix for when in a table var inTable = html.match(/^<(tbody|tr|td|th|col|colgroup|thead|tfoot)[\s\/>]/i); if(inTable) utils.string.div.innerHTML = '' + html + '
'; else utils.string.div.innerHTML = html; var scope; if(inTable) scope = utils.string.div.getElementsByTagName(inTable[1])[0].parentNode; else scope = utils.string.div; var returnedFragment = document.createDocumentFragment(); var i = scope.childNodes.length; while(i--) returnedFragment.appendChild(scope.firstChild); return returnedFragment; }, /** * Encode the string as HTML * * @return string * @param string value */ htmlEncode: function(value) { return $('
').text(value).html(); }, /** * Decode the string as HTML * * @return string * @param string value */ htmlDecode: function(value) { return $('
').html(value).text(); }, /** * Replace all occurences of one string into a string * * @return string * @param string value * @param string needle * @param string replacement */ replaceAll: function(value, needle, replacement) { if(typeof value === 'undefined') return ''; return value.replace(new RegExp(needle, 'g'), replacement); }, /** * Sprintf replaces all arguments that occur in the string (%1$s, %2$s, ...) * * @return string * @param string value * @params string arguments */ sprintf: function(value) { if(arguments.length < 2) return value; else { // replace $ symbol first, because our RegExp won't except this symbol value = value.replace(/\$s/g, 'Ss'); // find all variables and replace them for(var i = 1; i < arguments.length; i++) { value = utils.string.replaceAll(value, '%' + i + 'Ss', arguments[i]); } } return value; }, /** * Strip HTML tags * * @return string */ stripTags: function(value) { return value.replace(/<[^>]*>/ig, ''); }, /** * Strip whitespace from the beginning and end of a string * * @return string * @param string value * @param string[optional] charList */ trim: function(value, charList) { if(typeof value === 'undefined') return ''; if(typeof charList === 'undefined') charList = ' '; var pattern = new RegExp('^[' + charList + ']*|[' + charList + ']*$', 'g'); return value.replace(pattern, ''); }, /** * PHP-like urlencode * * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent#Description * @return string * @param string value */ urlEncode: function(value) { return encodeURIComponent(value).replace(/\%20/g, '+').replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/\~/g, '%7E'); }, /** * PHP-like urlencode * * @see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent#Description * @return string * @param string value */ urlDecode: function(value) { return decodeURIComponent(value.replace(/\+/g, '%20').replace(/\%21/g, '!').replace(/\%27/g, "'").replace(/\%28/g, '(').replace(/\%29/g, ')').replace(/\%2A/g, '*').replace(/\%7E/g, '~')); }, /** * Urlise a string (cfr. SpoonFilter::urlise) * * @return string * @param string value */ urlise: function(value) { // reserved characters (RFC 3986) reservedCharacters = new Array( '/', '?', ':', '@', '#', '[', ']', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' ); // remove reserved characters for(var i in reservedCharacters) value = value.replace(reservedCharacters[i], ' '); // replace double quote, since this one might cause problems in html (e.g. ) value = utils.string.replaceAll(value, '"', ' '); // replace spaces by dashes value = utils.string.replaceAll(value, ' ', '-'); // only urlencode if not yet urlencoded if(utils.string.urlDecode(value) == value) { // to lowercase value = value.toLowerCase(); // urlencode value = utils.string.urlEncode(value); } // convert "--" to "-" value = value.replace(/-+/, '-'); // trim - signs return utils.string.trim(value, '-'); }, /** * Adds a capital letter to a string * * @return string * @param string $value */ ucfirst: function(value) { return value.charAt(0).toUpperCase() + value.slice(1); }, /** * Convert a HTML string to a XHTML string. * * @return string * @param string value */ xhtml: function(value) { // break tags should end with a slash value = value.replace(/
/g,'
'); value = value.replace(/
$/g,''); value = value.replace(/^
/g,''); // image tags should end with a slash value = value.replace(/(]+[^\/])>/gi,'$1 />'); // input tags should end with a slash value = value.replace(/(]+[^\/])>/gi,'$1 />'); // big no-no to value = value.replace(/]*>(.*?)<\/b[^>]*>/g,'$1'); value = value.replace(/]*>(.*?)<\/i[^>]*>/g,'$1'); value = value.replace(/]*>(.*?)<\/u[^>]*>/g,'$1'); // XHTML return value; } }; /** * Functions related to the current url * * @author Dieter Vanden Eynde * @author Tijs Verkoyen */ utils.url = { extractParamFromUri: function (uri, paramName) { if(!uri) return; uri = uri.split('#')[0]; var parts = uri.split('?'); if (parts.length == 1) return; var query = decodeURI(parts[1]); paramName += '='; var params = query.split('&'); for(var i=0, param; param = params[i]; ++i) { if(param.indexOf(paramName) === 0) return unescape(param.split('=')[1]); } }, /** * Get a GET parameter * * @return string * @param string name */ getGetValue: function(name) { // init return value var getValue = ''; // get GET chunks from url var hashes = window.location.search.slice(window.location.search.indexOf('?') + 1).split('&'); // find requested parameter $.each(hashes, function(index, value) { // split name/value up var chunks = value.split('='); // found the requested parameter if(chunks[0] == name) { // set for return getValue = chunks[1]; // break loop return false; } }); // cough up value return getValue; } }; /** * Frontend related objects * * @author Tijs Verkoyen * @author Thomas Deceuninck */ var jsFrontend = { debug: false, current: {}, // init, something like a constructor init: function() { jsFrontend.current.language = jsFrontend.data.get('FRONTEND_LANGUAGE'); // init stuff jsFrontend.initAjax(); jsFrontend.cookieBar.init(); // init controls jsFrontend.controls.init(); // init form jsFrontend.forms.init(); // init gravatar jsFrontend.gravatar.init(); // init search jsFrontend.search.init(); // init statistics jsFrontend.statistics.init(); // init twitter jsFrontend.twitter.init(); }, // init initAjax: function() { // set defaults for AJAX $.ajaxSetup( { url: '/frontend/ajax', cache: false, type: 'POST', dataType: 'json', timeout: 10000, data: { fork: { module: null, action: null, language: jsFrontend.current.language } } }); } }; /** * Controls related javascript * * @author Tijs Verkoyen */ jsFrontend.controls = { // init, something like a constructor init: function() { jsFrontend.controls.bindTargetBlank(); }, // bind target blank bindTargetBlank: function() { $('a.targetBlank').attr('target', '_blank'); } }; /** * Handles the cookieBar */ jsFrontend.cookieBar = { init: function() { // if there is no cookiebar we shouldn't do anything if($('#cookieBar').length === 0) return; $cookieBar = $('#cookieBar'); // @remark: as you can see we use PHP-serialized values so we can use them in PHP too. // hide the cookieBar if needed if(utils.cookies.readCookie('cookie_bar_hide') == 'b%3A1%3B') { $cookieBar.hide(); } $cookieBar.on('click', '#cookieBarAgree', function(e) { utils.cookies.setCookie('cookie_bar_agree', 'b:1;'); utils.cookies.setCookie('cookie_bar_hide', 'b:1;'); $cookieBar.hide(); }); $cookieBar.on('click', '#cookieBarDisagree', function(e) { utils.cookies.setCookie('cookie_bar_agree', 'b:0;'); utils.cookies.setCookie('cookie_bar_hide', 'b:1;'); $cookieBar.hide(); }); } }; /** * Data related methods * * @author Tijs Verkoyen */ jsFrontend.data = { initialized: false, data: {}, init: function() { // check if var is available if(typeof jsData == 'undefined') throw 'jsData is not available'; // populate jsFrontend.data.data = jsData; jsFrontend.data.initialized = true; }, exists: function(key) { return (typeof eval('jsFrontend.data.data.' + key) != 'undefined'); }, get: function(key) { // init if needed if(!jsFrontend.data.initialized) jsFrontend.data.init(); // return return eval('jsFrontend.data.data.' + key); } }; /** * Facebook related * * @author Tijs Verkoyen */ jsFrontend.facebook = { // will be called after Facebook is initialized afterInit: function() { // is GA available? if(typeof _gaq == 'object') { // subscribe and track like FB.Event.subscribe('edge.create', function(targetUrl) { _gaq.push(['_trackSocial', 'facebook', 'like', targetUrl]); }); // subscribe and track unlike FB.Event.subscribe('edge.remove', function(targetUrl) { _gaq.push(['_trackSocial', 'facebook', 'unlike', targetUrl]); }); // subscribe and track message FB.Event.subscribe('message.send', function(targetUrl) { _gaq.push(['_trackSocial', 'facebook', 'send', targetUrl]); }); } else if(typeof ga == 'object') { // subscribe and track like FB.Event.subscribe('edge.create', function(targetUrl) { ga('send', 'social', 'facebook', 'like', targetUrl); }); // subscribe and track unlike FB.Event.subscribe('edge.remove', function(targetUrl) { ga('send', 'social', 'facebook', 'unlike', targetUrl); }); // subscribe and track message FB.Event.subscribe('message.send', function(targetUrl) { ga('send', 'social', 'facebook', 'send', targetUrl); }); } } }; /** * Form related javascript * * @author Tijs Verkoyen */ jsFrontend.forms = { // init, something like a constructor init: function() { jsFrontend.forms.placeholders(); jsFrontend.forms.datefields(); jsFrontend.forms.filled(); }, // once text has been filled add another class to it (so it's possible to style it differently) filled: function() { $(document).on('blur', 'form input, form textarea, form select', function() { if($(this).val() === '') $(this).removeClass('filled'); else $(this).addClass('filled'); }); }, // initialize the date fields datefields: function() { // jQuery datapicker fallback for browsers that don't support the HTML5 date type var $inputDateType = $('input.inputDatefield'); if ($inputDateType.length) { // the browser does not support the HTML5 data type if ('date' !== $inputDateType.get(0).type) { $inputDateType.addClass('inputDatefieldNormal'); } } var $inputDatefields = $('.inputDatefieldNormal, .inputDatefieldFrom, .inputDatefieldTill, .inputDatefieldRange'); var $inputDatefieldNormal = $('.inputDatefieldNormal'); var $inputDatefieldFrom = $('.inputDatefieldFrom'); var $inputDatefieldTill = $('.inputDatefieldTill'); var $inputDatefieldRange = $('.inputDatefieldRange'); if($inputDatefields.length > 0) { var dayNames = [jsFrontend.locale.loc('DayLongSun'), jsFrontend.locale.loc('DayLongMon'), jsFrontend.locale.loc('DayLongTue'), jsFrontend.locale.loc('DayLongWed'), jsFrontend.locale.loc('DayLongThu'), jsFrontend.locale.loc('DayLongFri'), jsFrontend.locale.loc('DayLongSat')]; var dayNamesMin = [jsFrontend.locale.loc('DayShortSun'), jsFrontend.locale.loc('DayShortMon'), jsFrontend.locale.loc('DayShortTue'), jsFrontend.locale.loc('DayShortWed'), jsFrontend.locale.loc('DayShortThu'), jsFrontend.locale.loc('DayShortFri'), jsFrontend.locale.loc('DayShortSat')]; var dayNamesShort = [jsFrontend.locale.loc('DayShortSun'), jsFrontend.locale.loc('DayShortMon'), jsFrontend.locale.loc('DayShortTue'), jsFrontend.locale.loc('DayShortWed'), jsFrontend.locale.loc('DayShortThu'), jsFrontend.locale.loc('DayShortFri'), jsFrontend.locale.loc('DayShortSat')]; var monthNames = [jsFrontend.locale.loc('MonthLong1'), jsFrontend.locale.loc('MonthLong2'), jsFrontend.locale.loc('MonthLong3'), jsFrontend.locale.loc('MonthLong4'), jsFrontend.locale.loc('MonthLong5'), jsFrontend.locale.loc('MonthLong6'), jsFrontend.locale.loc('MonthLong7'), jsFrontend.locale.loc('MonthLong8'), jsFrontend.locale.loc('MonthLong9'), jsFrontend.locale.loc('MonthLong10'), jsFrontend.locale.loc('MonthLong11'), jsFrontend.locale.loc('MonthLong12')]; var monthNamesShort = [jsFrontend.locale.loc('MonthShort1'), jsFrontend.locale.loc('MonthShort2'), jsFrontend.locale.loc('MonthShort3'), jsFrontend.locale.loc('MonthShort4'), jsFrontend.locale.loc('MonthShort5'), jsFrontend.locale.loc('MonthShort6'), jsFrontend.locale.loc('MonthShort7'), jsFrontend.locale.loc('MonthShort8'), jsFrontend.locale.loc('MonthShort9'), jsFrontend.locale.loc('MonthShort10'), jsFrontend.locale.loc('MonthShort11'), jsFrontend.locale.loc('MonthShort12')]; $inputDatefieldNormal.each(function() { // Create a hidden clone (before datepicker init!), which will contain the actual value var clone = $(this).clone(); clone.insertAfter(this); clone.hide(); // Rename the original field, used to contain the display value $(this).attr('id', $(this).attr('id') + '-display'); $(this).attr('name', $(this).attr('name') + '-display'); }); $inputDatefields.datepicker({ dayNames: dayNames, dayNamesMin: dayNamesMin, dayNamesShort: dayNamesShort, hideIfNoPrevNext: true, monthNames: monthNames, monthNamesShort: monthNamesShort, nextText: jsFrontend.locale.lbl('Next'), prevText: jsFrontend.locale.lbl('Previous'), showAnim: 'slideDown' }); // the default, nothing special $inputDatefieldNormal.each(function() { // get data var data = $(this).data(); var phpDate = new Date($(this).val()); // Get date from php in YYYY-MM-DD format var value = $.datepicker.formatDate(data.mask, phpDate); // Convert the value to the data-mask to display it // Create the datepicker with the desired display format and alt field $(this).datepicker('option', { dateFormat: data.mask, firstDay: data.firstday, altField: "#" + $(this).attr('id').replace('-display', ''), altFormat: "yy-mm-dd" }).datepicker('setDate', value); }); // date fields that have a certain start date $inputDatefieldFrom.each(function() { // get data var data = $(this).data(); var value = $(this).val(); // set options $(this).datepicker('option', { dateFormat: data.mask, firstDay: data.firstday, minDate: new Date(parseInt(data.startdate.split('-')[0], 10), parseInt(data.startdate.split('-')[1], 10) - 1, parseInt(data.startdate.split('-')[2], 10)) }).datepicker('setDate', value); }); // date fields that have a certain enddate $inputDatefieldTill.each(function() { // get data var data = $(this).data(); var value = $(this).val(); // set options $(this).datepicker('option', { dateFormat: data.mask, firstDay: data.firstday, maxDate: new Date(parseInt(data.enddate.split('-')[0], 10), parseInt(data.enddate.split('-')[1], 10) -1, parseInt(data.enddate.split('-')[2], 10)) }).datepicker('setDate', value); }); // date fields that have a certain range $inputDatefieldRange.each(function() { // get data var data = $(this).data(); var value = $(this).val(); // set options $(this).datepicker('option', { dateFormat: data.mask, firstDay: data.firstday, minDate: new Date(parseInt(data.startdate.split('-')[0], 10), parseInt(data.startdate.split('-')[1], 10) - 1, parseInt(data.startdate.split('-')[2], 10), 0, 0, 0, 0), maxDate: new Date(parseInt(data.enddate.split('-')[0], 10), parseInt(data.enddate.split('-')[1], 10) - 1, parseInt(data.enddate.split('-')[2], 10), 23, 59, 59) }).datepicker('setDate', value); }); } }, // placeholder fallback for browsers that don't support placeholder placeholders: function() { // detect if placeholder-attribute is supported jQuery.support.placeholder = ('placeholder' in document.createElement('input')); if(!jQuery.support.placeholder) { // bind focus $('input[placeholder], textarea[placeholder]').on('focus', function() { // grab element var input = $(this); // only do something when the current value and the placeholder are the same if(input.val() == input.attr('placeholder')) { // clear input.val(''); // remove class input.removeClass('placeholder'); } }); $('input[placeholder], textarea[placeholder]').on('blur', function() { // grab element var input = $(this); // only do something when the input is empty or the value is the same as the placeholder if(input.val() === '' || input.val() === input.attr('placeholder')) { // set placeholder input.val(input.attr('placeholder')); // add class input.addClass('placeholder'); } }); // call blur to initialize $('input[placeholder], textarea[placeholder]').blur(); // hijack the form so placeholders aren't submitted as values $('input[placeholder], textarea[placeholder]').parents('form').submit(function() { // find elements with placeholders $(this).find('input[placeholder]').each(function() { // grab element var input = $(this); // if the value and the placeholder are the same reset the value if(input.val() == input.attr('placeholder')) input.val(''); }); }); } } }; /** * Gravatar related javascript * * @author Tijs Verkoyen */ jsFrontend.gravatar = { // init, something like a constructor init: function() { $('.replaceWithGravatar').each(function() { var element = $(this); var gravatarId = element.data('gravatarId'); var size = element.attr('height'); // valid gravatar id if(gravatarId !== '') { // build url var url = 'http://www.gravatar.com/avatar/' + gravatarId + '?r=g&d=404'; // add size if set before if(size !== '') url += '&s=' + size; // create new image var gravatar = new Image(); gravatar.src = url; // reset src gravatar.onload = function() { element.attr('src', url).addClass('gravatarLoaded'); }; } }); } }; /** * Locale * * @author Tijs Verkoyen */ jsFrontend.locale = { initialized: false, data: {}, // init, something like a constructor init: function() { $.ajax({ url: '/src/Frontend/Cache/Locale/' + jsFrontend.current.language + '.json', type: 'GET', dataType: 'json', async: false, success: function(data) { jsFrontend.locale.data = data; jsFrontend.locale.initialized = true; }, error: function(jqXHR, textStatus, errorThrown) { throw 'Regenerate your locale-files.'; } }); }, // get an item from the locale get: function(type, key) { // initialize if needed if(!jsFrontend.locale.initialized) jsFrontend.locale.init(); // validate if(typeof jsFrontend.locale.data[type][key] == 'undefined') return '{$' + type + key + '}'; return jsFrontend.locale.data[type][key]; }, // get an action act: function(key) { return jsFrontend.locale.get('act', key); }, // get an error err: function(key) { return jsFrontend.locale.get('err', key); }, // get a label lbl: function(key) { return jsFrontend.locale.get('lbl', key); }, // get localization loc: function(key) { return jsFrontend.locale.get('loc', key); }, // get a message msg: function(key) { return jsFrontend.locale.get('msg', key); } }; /** * Search controls * * @author Matthias Mullie */ jsFrontend.search = { // init, something like a constructor init: function() { // auto suggest (search widget) if($('input.autoSuggest').length > 0) jsFrontend.search.autosuggest(55); // autocomplete (search results page: autocomplete based on known search terms) if($('input.autoComplete').length > 0) jsFrontend.search.autocomplete(); // live suggest (search results page: live feed of matches) if($('input.liveSuggest').length > 0 && $('#searchContainer').length > 0) jsFrontend.search.livesuggest(); }, // autocomplete (search results page: autocomplete based on known search terms) autocomplete: function() { // grab element var $input = $('input.autoComplete'); // autocomplete (based on saved search terms) on results page $input.autocomplete( { minLength: 1, source: function(request, response) { // ajax call! $.ajax( { data: { fork: { module: 'Search', action: 'Autocomplete' }, term: request.term }, success: function(data, textStatus) { // init var var realData = []; // alert the user if(data.code != 200 && jsFrontend.debug) { alert(data.message); } if(data.code == 200) { for(var i in data.data) realData.push({ label: data.data[i].term, value: data.data[i].term, url: data.data[i].url }); } // set response response(realData); } }); }, select: function(e, ui) { window.location.href = ui.item.url; } }) // when we have been typing in the search textfield and we blur out of it, we're ready to save it .on('blur', function() { if($(this).val() !== '') { // ajax call! $.ajax( { data: { fork: { module: 'Search', action: 'Save' }, term: $(this).val() } }); } }); }, // auto suggest (search widget) autosuggest: function(length) { // set default values if(typeof length == 'undefined') length = 100; // grab element var $input = $('input.autoSuggest'); // search widget suggestions $input.autocomplete( { minLength: 1, source: function(request, response) { // ajax call! $.ajax( { data: { fork: { module: 'Search', action: 'Autosuggest' }, term: request.term, length: length }, success: function(data, textStatus) { // init var var realData = []; // alert the user if(data.code != 200 && jsFrontend.debug) { alert(data.message); } if(data.code == 200) { for(var i in data.data) realData.push({ label: data.data[i].title, value: data.data[i].title, url: data.data[i].full_url, desc: data.data[i].text }); } // set response response(realData); } }); }, select: function(e, ui) { window.location.href = ui.item.url; }, open: function(event, ui){ var autocomplete = $(".ui-autocomplete"); var position = autocomplete.offset().left - autocomplete.width() + $input.outerWidth(); autocomplete.css("left", position); } }) // when we have been typing in the search textfield and we blur out of it, we're ready to save it .on('blur', function() { if($(this).val() !== '') { // ajax call! $.ajax( { data: { fork: { module: 'Search', action: 'Save' }, term: $(this).val() } }); } }) // and also: alter the autocomplete style: add description! .data('ui-autocomplete')._renderItem = function(ul, item) { return $('
  • ') .data('item.autocomplete', item) .append('
    ' + item.label + '
    ' + item.desc + '
    ' ) .appendTo(ul); }; }, // livesuggest (search results page: live feed of matches) livesuggest: function() { // check if calls for live suggest are allowed var allowCall = true; // grab element var $input = $('input.liveSuggest'); // change in input = do the dance: live search results completion $input.on('keyup', function() { var $searchContainer = $('#searchContainer'); // make sure we're allowed to do the call (= previous call is no longer processing) if(allowCall) { // temporarily allow no more calls allowCall = false; // fade out $searchContainer.fadeTo(0, 0.5); // ajax call! $.ajax( { data: { fork: { module: 'Search', action: 'Livesuggest' }, term: $(this).val() }, success: function(data, textStatus) { // allow for new calls allowCall = true; // alert the user if(data.code != 200 && jsFrontend.debug) { alert(data.message); } if(data.code == 200) { // replace search results $searchContainer.html(utils.string.html5(data.data)); // fade in $searchContainer.fadeTo(0, 1); } }, error: function() { // allow for new calls allowCall = true; // replace search results $searchContainer.html(''); // fade in $searchContainer.fadeTo(0, 1); } }); } }); } }; /** * Google analytics related javascript * * @author Tijs Verkoyen */ jsFrontend.statistics = { // init, something like a constructor init: function() { jsFrontend.statistics.trackOutboundLinks(); }, // track all outbound links trackOutboundLinks: function() { // check if Google Analytics is available if(typeof _gaq === 'object' || typeof ga === 'object') { // create a new selector $.expr[':'].external = function(obj) { return (typeof obj.href != 'undefined') && !obj.href.match(/^mailto:/) && (obj.hostname != location.hostname); }; // bind on all links that don't have the class noTracking $(document).on('click', 'a:external:not(.noTracking)', function(e) { // only simulate direct links var hasTarget = (typeof $(this).attr('target') != 'undefined'); if(!hasTarget) e.preventDefault(); var link = $(this).attr('href'); // outbound link by default var type = 'Outbound Links'; var pageView = '/Outbound Links/' + link; // set mailto if(link.match(/^mailto:/)) { type = 'Mailto'; pageView = '/Mailto/' + link.substring(7); } // set anchor if(link.match(/^#/)) { type = 'Anchors'; pageView = '/Anchor/' + link.substring(1); } // track in Google Analytics if(typeof _gaq === 'object') { _gaq.push(['_trackEvent', type, pageView]); } else { ga('send', 'event', type, pageView); } // set time out if(!hasTarget) setTimeout(function() { document.location.href = link; }, 100); }); } } }; /** * Twitter related stuff * * @author Tijs Verkoyen */ jsFrontend.twitter = { init: function() { // if GA is integrated and a tweet button is used if(typeof twttr === 'object' && (typeof _gaq === 'object' || typeof ga === 'object')) { // bind event, so we can track the tweets twttr.events.on('tweet', function(e) { // valid event? if(e) { // init var var targetUrl = null; // get url if(e.target && e.target.nodeName == 'IFRAME') targetUrl = utils.url.extractParamFromUri(e.target.src, 'url'); // push to GA if(typeof _gaq === 'object') { _gaq.push(['_trackSocial', 'twitter', 'tweet', targetUrl]); } else { ga('send', 'social', 'twitter', 'tweet', targetUrl); } } }); } } }; $(jsFrontend.init); /* * debouncedresize: special jQuery event that happens once after a window resize * * latest version and complete README available on Github: * https://github.com/louisremi/jquery-smartresize * * Copyright 2012 @louis_remi * Licensed under the MIT license. * * This saved you an hour of work? * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON */ (function($) { var $event = $.event, $special, resizeTimeout; $special = $event.special.debouncedresize = { setup: function() { $( this ).on( "resize", $special.handler ); }, teardown: function() { $( this ).off( "resize", $special.handler ); }, handler: function( event, execAsap ) { // Save the context var context = this, args = arguments, dispatch = function() { // set correct event type event.type = "debouncedresize"; $event.dispatch.apply( context, args ); }; if ( resizeTimeout ) { clearTimeout( resizeTimeout ); } execAsap ? dispatch() : resizeTimeout = setTimeout( dispatch, $special.threshold ); }, threshold: 150 }; })(jQuery); /* equalHeights */ (function($) { $.fn.equalHeights = function() { // Variables var currentTallest = 0, currentRowStart = 0, rowDivs = new Array(), $el, topPosition = 0; // Store $(this) var $this = $(this); $this.each(function() { $el = $(this); $($el).height('auto'); topPostion = $el.position().top; if (currentRowStart != topPostion) { for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) { rowDivs[currentDiv].outerHeight(currentTallest); } rowDivs.length = 0; // empty the array currentRowStart = topPostion; currentTallest = $el.outerHeight(); rowDivs.push($el); } else { rowDivs.push($el); currentTallest = (currentTallest < $el.outerHeight()) ? ($el.outerHeight()) : (currentTallest); } for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) { rowDivs[currentDiv].outerHeight(currentTallest); } }); }; })(jQuery); /*! * fancyBox - jQuery Plugin * version: 2.1.5 (Fri, 14 Jun 2013) * requires jQuery v1.6 or later * * Examples at http://fancyapps.com/fancybox/ * License: www.fancyapps.com/fancybox/#license * * Copyright 2012 Janis Skarnelis - janis@fancyapps.com * */ ;(function (window, document, $, undefined) { "use strict"; var H = $("html"), W = $(window), D = $(document), F = $.fancybox = function () { F.open.apply( this, arguments ); }, IE = navigator.userAgent.match(/msie/i), didUpdate = null, isTouch = document.createTouch !== undefined, isQuery = function(obj) { return obj && obj.hasOwnProperty && obj instanceof $; }, isString = function(str) { return str && $.type(str) === "string"; }, isPercentage = function(str) { return isString(str) && str.indexOf('%') > 0; }, isScrollable = function(el) { return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight))); }, getScalar = function(orig, dim) { var value = parseInt(orig, 10) || 0; if (dim && isPercentage(orig)) { value = F.getViewport()[ dim ] / 100 * value; } return Math.ceil(value); }, getValue = function(value, dim) { return getScalar(value, dim) + 'px'; }; $.extend(F, { // The current version of fancyBox version: '2.1.5', defaults: { padding : 15, margin : 20, width : 800, height : 600, minWidth : 100, minHeight : 100, maxWidth : 9999, maxHeight : 9999, pixelRatio: 1, // Set to 2 for retina display support autoSize : true, autoHeight : false, autoWidth : false, autoResize : true, autoCenter : !isTouch, fitToView : true, aspectRatio : false, topRatio : 0.5, leftRatio : 0.5, scrolling : 'auto', // 'auto', 'yes' or 'no' wrapCSS : '', arrows : true, closeBtn : true, closeClick : false, nextClick : false, mouseWheel : true, autoPlay : false, playSpeed : 3000, preload : 3, modal : false, loop : true, ajax : { dataType : 'html', headers : { 'X-fancyBox': true } }, iframe : { scrolling : 'auto', preload : true }, swf : { wmode: 'transparent', allowfullscreen : 'true', allowscriptaccess : 'always' }, keys : { next : { 13 : 'left', // enter 34 : 'up', // page down 39 : 'left', // right arrow 40 : 'up' // down arrow }, prev : { 8 : 'right', // backspace 33 : 'down', // page up 37 : 'right', // left arrow 38 : 'down' // up arrow }, close : [27], // escape key play : [32], // space - start/stop slideshow toggle : [70] // letter "f" - toggle fullscreen }, direction : { next : 'left', prev : 'right' }, scrollOutside : true, // Override some properties index : 0, type : null, href : null, content : null, title : null, // HTML templates tpl: { wrap : '
    ', image : '', iframe : '', error : '

    The requested content cannot be loaded.
    Please try again later.

    ', closeBtn : '', next : '', prev : '', loading : '
    ' }, // Properties for each animation type // Opening fancyBox openEffect : 'fade', // 'elastic', 'fade' or 'none' openSpeed : 250, openEasing : 'swing', openOpacity : true, openMethod : 'zoomIn', // Closing fancyBox closeEffect : 'fade', // 'elastic', 'fade' or 'none' closeSpeed : 250, closeEasing : 'swing', closeOpacity : true, closeMethod : 'zoomOut', // Changing next gallery item nextEffect : 'elastic', // 'elastic', 'fade' or 'none' nextSpeed : 250, nextEasing : 'swing', nextMethod : 'changeIn', // Changing previous gallery item prevEffect : 'elastic', // 'elastic', 'fade' or 'none' prevSpeed : 250, prevEasing : 'swing', prevMethod : 'changeOut', // Enable default helpers helpers : { overlay : true, title : true }, // Callbacks onCancel : $.noop, // If canceling beforeLoad : $.noop, // Before loading afterLoad : $.noop, // After loading beforeShow : $.noop, // Before changing in current item afterShow : $.noop, // After opening beforeChange : $.noop, // Before changing gallery item beforeClose : $.noop, // Before closing afterClose : $.noop // After closing }, //Current state group : {}, // Selected group opts : {}, // Group options previous : null, // Previous element coming : null, // Element being loaded current : null, // Currently loaded element isActive : false, // Is activated isOpen : false, // Is currently open isOpened : false, // Have been fully opened at least once wrap : null, skin : null, outer : null, inner : null, player : { timer : null, isActive : false }, // Loaders ajaxLoad : null, imgPreload : null, // Some collections transitions : {}, helpers : {}, /* * Static methods */ open: function (group, opts) { if (!group) { return; } if (!$.isPlainObject(opts)) { opts = {}; } // Close if already active if (false === F.close(true)) { return; } // Normalize group if (!$.isArray(group)) { group = isQuery(group) ? $(group).get() : [group]; } // Recheck if the type of each element is `object` and set content type (image, ajax, etc) $.each(group, function(i, element) { var obj = {}, href, title, content, type, rez, hrefParts, selector; if ($.type(element) === "object") { // Check if is DOM element if (element.nodeType) { element = $(element); } if (isQuery(element)) { obj = { href : element.data('fancybox-href') || element.attr('href'), title : $('
    ').text( element.data('fancybox-title') || element.attr('title') || '' ).html(), isDom : true, element : element }; if ($.metadata) { $.extend(true, obj, element.metadata()); } } else { obj = element; } } href = opts.href || obj.href || (isString(element) ? element : null); title = opts.title !== undefined ? opts.title : obj.title || ''; content = opts.content || obj.content; type = content ? 'html' : (opts.type || obj.type); if (!type && obj.isDom) { type = element.data('fancybox-type'); if (!type) { rez = element.prop('class').match(/fancybox\.(\w+)/); type = rez ? rez[1] : null; } } if (isString(href)) { // Try to guess the content type if (!type) { if (F.isImage(href)) { type = 'image'; } else if (F.isSWF(href)) { type = 'swf'; } else if (href.charAt(0) === '#') { type = 'inline'; } else if (isString(element)) { type = 'html'; content = element; } } // Split url into two pieces with source url and content selector, e.g, // "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id" if (type === 'ajax') { hrefParts = href.split(/\s+/, 2); href = hrefParts.shift(); selector = hrefParts.shift(); } } if (!content) { if (type === 'inline') { if (href) { content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 } else if (obj.isDom) { content = element; } } else if (type === 'html') { content = href; } else if (!type && !href && obj.isDom) { type = 'inline'; content = element; } } $.extend(obj, { href : href, type : type, content : content, title : title, selector : selector }); group[ i ] = obj; }); // Extend the defaults F.opts = $.extend(true, {}, F.defaults, opts); // All options are merged recursive except keys if (opts.keys !== undefined) { F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; } F.group = group; return F._start(F.opts.index); }, // Cancel image loading or abort ajax request cancel: function () { var coming = F.coming; if (coming && false === F.trigger('onCancel')) { return; } F.hideLoading(); if (!coming) { return; } if (F.ajaxLoad) { F.ajaxLoad.abort(); } F.ajaxLoad = null; if (F.imgPreload) { F.imgPreload.onload = F.imgPreload.onerror = null; } if (coming.wrap) { coming.wrap.stop(true, true).trigger('onReset').remove(); } F.coming = null; // If the first item has been canceled, then clear everything if (!F.current) { F._afterZoomOut( coming ); } }, // Start closing animation if is open; remove immediately if opening/closing close: function (event) { F.cancel(); if (false === F.trigger('beforeClose')) { return; } F.unbindEvents(); if (!F.isActive) { return; } if (!F.isOpen || event === true) { $('.fancybox-wrap').stop(true).trigger('onReset').remove(); F._afterZoomOut(); } else { F.isOpen = F.isOpened = false; F.isClosing = true; $('.fancybox-item, .fancybox-nav').remove(); F.wrap.stop(true, true).removeClass('fancybox-opened'); F.transitions[ F.current.closeMethod ](); } }, // Manage slideshow: // $.fancybox.play(); - toggle slideshow // $.fancybox.play( true ); - start // $.fancybox.play( false ); - stop play: function ( action ) { var clear = function () { clearTimeout(F.player.timer); }, set = function () { clear(); if (F.current && F.player.isActive) { F.player.timer = setTimeout(F.next, F.current.playSpeed); } }, stop = function () { clear(); D.unbind('.player'); F.player.isActive = false; F.trigger('onPlayEnd'); }, start = function () { if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { F.player.isActive = true; D.bind({ 'onCancel.player beforeClose.player' : stop, 'onUpdate.player' : set, 'beforeLoad.player' : clear }); set(); F.trigger('onPlayStart'); } }; if (action === true || (!F.player.isActive && action !== false)) { start(); } else { stop(); } }, // Navigate to next gallery item next: function ( direction ) { var current = F.current; if (current) { if (!isString(direction)) { direction = current.direction.next; } F.jumpto(current.index + 1, direction, 'next'); } }, // Navigate to previous gallery item prev: function ( direction ) { var current = F.current; if (current) { if (!isString(direction)) { direction = current.direction.prev; } F.jumpto(current.index - 1, direction, 'prev'); } }, // Navigate to gallery item by index jumpto: function ( index, direction, router ) { var current = F.current; if (!current) { return; } index = getScalar(index); F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ]; F.router = router || 'jumpto'; if (current.loop) { if (index < 0) { index = current.group.length + (index % current.group.length); } index = index % current.group.length; } if (current.group[ index ] !== undefined) { F.cancel(); F._start(index); } }, // Center inside viewport and toggle position type to fixed or absolute if needed reposition: function (e, onlyAbsolute) { var current = F.current, wrap = current ? current.wrap : null, pos; if (wrap) { pos = F._getPosition(onlyAbsolute); if (e && e.type === 'scroll') { delete pos.position; wrap.stop(true, true).animate(pos, 200); } else { wrap.css(pos); current.pos = $.extend({}, current.dim, pos); } } }, update: function (e) { var type = (e && e.originalEvent && e.originalEvent.type), anyway = !type || type === 'orientationchange'; if (anyway) { clearTimeout(didUpdate); didUpdate = null; } if (!F.isOpen || didUpdate) { return; } didUpdate = setTimeout(function() { var current = F.current; if (!current || F.isClosing) { return; } F.wrap.removeClass('fancybox-tmp'); if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) { F._setDimension(); } if (!(type === 'scroll' && current.canShrink)) { F.reposition(e); } F.trigger('onUpdate'); didUpdate = null; }, (anyway && !isTouch ? 0 : 300)); }, // Shrink content to fit inside viewport or restore if resized toggle: function ( action ) { if (F.isOpen) { F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView; // Help browser to restore document dimensions if (isTouch) { F.wrap.removeAttr('style').addClass('fancybox-tmp'); F.trigger('onUpdate'); } F.update(); } }, hideLoading: function () { D.unbind('.loading'); $('#fancybox-loading').remove(); }, showLoading: function () { var el, viewport; F.hideLoading(); el = $(F.opts.tpl.loading).click(F.cancel).appendTo('body'); // If user will press the escape-button, the request will be canceled D.bind('keydown.loading', function(e) { if ((e.which || e.keyCode) === 27) { e.preventDefault(); F.cancel(); } }); if (!F.defaults.fixed) { viewport = F.getViewport(); el.css({ position : 'absolute', top : (viewport.h * 0.5) + viewport.y, left : (viewport.w * 0.5) + viewport.x }); } F.trigger('onLoading'); }, getViewport: function () { var locked = (F.current && F.current.locked) || false, rez = { x: W.scrollLeft(), y: W.scrollTop() }; if (locked && locked.length) { rez.w = locked[0].clientWidth; rez.h = locked[0].clientHeight; } else { // See http://bugs.jquery.com/ticket/6724 rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width(); rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height(); } return rez; }, // Unbind the keyboard / clicking actions unbindEvents: function () { if (F.wrap && isQuery(F.wrap)) { F.wrap.unbind('.fb'); } D.unbind('.fb'); W.unbind('.fb'); }, bindEvents: function () { var current = F.current, keys; if (!current) { return; } // Changing document height on iOS devices triggers a 'resize' event, // that can change document height... repeating infinitely W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update); keys = current.keys; if (keys) { D.bind('keydown.fb', function (e) { var code = e.which || e.keyCode, target = e.target || e.srcElement; // Skip esc key if loading, because showLoading will cancel preloading if (code === 27 && F.coming) { return false; } // Ignore key combinations and key events within form elements if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { $.each(keys, function(i, val) { if (current.group.length > 1 && val[ code ] !== undefined) { F[ i ]( val[ code ] ); e.preventDefault(); return false; } if ($.inArray(code, val) > -1) { F[ i ] (); e.preventDefault(); return false; } }); } }); } if ($.fn.mousewheel && current.mouseWheel) { F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) { var target = e.target || null, parent = $(target), canScroll = false; while (parent.length) { if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) { break; } canScroll = isScrollable( parent[0] ); parent = $(parent).parent(); } if (delta !== 0 && !canScroll) { if (F.group.length > 1 && !current.canShrink) { if (deltaY > 0 || deltaX > 0) { F.prev( deltaY > 0 ? 'down' : 'left' ); } else if (deltaY < 0 || deltaX < 0) { F.next( deltaY < 0 ? 'up' : 'right' ); } e.preventDefault(); } } }); } }, trigger: function (event, o) { var ret, obj = o || F.coming || F.current; if (obj) { if ($.isFunction( obj[event] )) { ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); } if (ret === false) { return false; } if (obj.helpers) { $.each(obj.helpers, function (helper, opts) { if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) { F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj); } }); } } D.trigger(event); }, isImage: function (str) { return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); }, isSWF: function (str) { return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); }, _start: function (index) { var coming = {}, obj, href, type, margin, padding; index = getScalar( index ); obj = F.group[ index ] || null; if (!obj) { return false; } coming = $.extend(true, {}, F.opts, obj); // Convert margin and padding properties to array - top, right, bottom, left margin = coming.margin; padding = coming.padding; if ($.type(margin) === 'number') { coming.margin = [margin, margin, margin, margin]; } if ($.type(padding) === 'number') { coming.padding = [padding, padding, padding, padding]; } // 'modal' propery is just a shortcut if (coming.modal) { $.extend(true, coming, { closeBtn : false, closeClick : false, nextClick : false, arrows : false, mouseWheel : false, keys : null, helpers: { overlay : { closeClick : false } } }); } // 'autoSize' property is a shortcut, too if (coming.autoSize) { coming.autoWidth = coming.autoHeight = true; } if (coming.width === 'auto') { coming.autoWidth = true; } if (coming.height === 'auto') { coming.autoHeight = true; } /* * Add reference to the group, so it`s possible to access from callbacks, example: * afterLoad : function() { * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); * } */ coming.group = F.group; coming.index = index; // Give a chance for callback or helpers to update coming item (type, title, etc) F.coming = coming; if (false === F.trigger('beforeLoad')) { F.coming = null; return; } type = coming.type; href = coming.href; if (!type) { F.coming = null; //If we can not determine content type then drop silently or display next/prev item if looping through gallery if (F.current && F.router && F.router !== 'jumpto') { F.current.index = index; return F[ F.router ]( F.direction ); } return false; } F.isActive = true; if (type === 'image' || type === 'swf') { coming.autoHeight = coming.autoWidth = false; coming.scrolling = 'visible'; } if (type === 'image') { coming.aspectRatio = true; } if (type === 'iframe' && isTouch) { coming.scrolling = 'scroll'; } // Build the neccessary markup coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' ); $.extend(coming, { skin : $('.fancybox-skin', coming.wrap), outer : $('.fancybox-outer', coming.wrap), inner : $('.fancybox-inner', coming.wrap) }); $.each(["Top", "Right", "Bottom", "Left"], function(i, v) { coming.skin.css('padding' + v, getValue(coming.padding[ i ])); }); F.trigger('onReady'); // Check before try to load; 'inline' and 'html' types need content, others - href if (type === 'inline' || type === 'html') { if (!coming.content || !coming.content.length) { return F._error( 'content' ); } } else if (!href) { return F._error( 'href' ); } if (type === 'image') { F._loadImage(); } else if (type === 'ajax') { F._loadAjax(); } else if (type === 'iframe') { F._loadIframe(); } else { F._afterLoad(); } }, _error: function ( type ) { $.extend(F.coming, { type : 'html', autoWidth : true, autoHeight : true, minWidth : 0, minHeight : 0, scrolling : 'no', hasError : type, content : F.coming.tpl.error }); F._afterLoad(); }, _loadImage: function () { // Reset preload image so it is later possible to check "complete" property var img = F.imgPreload = new Image(); img.onload = function () { this.onload = this.onerror = null; F.coming.width = this.width / F.opts.pixelRatio; F.coming.height = this.height / F.opts.pixelRatio; F._afterLoad(); }; img.onerror = function () { this.onload = this.onerror = null; F._error( 'image' ); }; img.src = F.coming.href; if (img.complete !== true) { F.showLoading(); } }, _loadAjax: function () { var coming = F.coming; F.showLoading(); F.ajaxLoad = $.ajax($.extend({}, coming.ajax, { url: coming.href, error: function (jqXHR, textStatus) { if (F.coming && textStatus !== 'abort') { F._error( 'ajax', jqXHR ); } else { F.hideLoading(); } }, success: function (data, textStatus) { if (textStatus === 'success') { coming.content = data; F._afterLoad(); } } })); }, _loadIframe: function() { var coming = F.coming, iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime())) .attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling) .attr('src', coming.href); // This helps IE $(coming.wrap).bind('onReset', function () { try { $(this).find('iframe').hide().attr('src', '//about:blank').end().empty(); } catch (e) {} }); if (coming.iframe.preload) { F.showLoading(); iframe.one('load', function() { $(this).data('ready', 1); // iOS will lose scrolling if we resize if (!isTouch) { $(this).bind('load.fb', F.update); } // Without this trick: // - iframe won't scroll on iOS devices // - IE7 sometimes displays empty iframe $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show(); F._afterLoad(); }); } coming.content = iframe.appendTo( coming.inner ); if (!coming.iframe.preload) { F._afterLoad(); } }, _preloadImages: function() { var group = F.group, current = F.current, len = group.length, cnt = current.preload ? Math.min(current.preload, len - 1) : 0, item, i; for (i = 1; i <= cnt; i += 1) { item = group[ (current.index + i ) % len ]; if (item.type === 'image' && item.href) { new Image().src = item.href; } } }, _afterLoad: function () { var coming = F.coming, previous = F.current, placeholder = 'fancybox-placeholder', current, content, type, scrolling, href, embed; F.hideLoading(); if (!coming || F.isActive === false) { return; } if (false === F.trigger('afterLoad', coming, previous)) { coming.wrap.stop(true).trigger('onReset').remove(); F.coming = null; return; } if (previous) { F.trigger('beforeChange', previous); previous.wrap.stop(true).removeClass('fancybox-opened') .find('.fancybox-item, .fancybox-nav') .remove(); } F.unbindEvents(); current = coming; content = coming.content; type = coming.type; scrolling = coming.scrolling; $.extend(F, { wrap : current.wrap, skin : current.skin, outer : current.outer, inner : current.inner, current : current, previous : previous }); href = current.href; switch (type) { case 'inline': case 'ajax': case 'html': if (current.selector) { content = $('
    ').html(content).find(current.selector); } else if (isQuery(content)) { if (!content.data(placeholder)) { content.data(placeholder, $('
    ').insertAfter( content ).hide() ); } content = content.show().detach(); current.wrap.bind('onReset', function () { if ($(this).find(content).length) { content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false); } }); } break; case 'image': content = current.tpl.image.replace(/\{href\}/g, href); break; case 'swf': content = ''; embed = ''; $.each(current.swf, function(name, val) { content += ''; embed += ' ' + name + '="' + val + '"'; }); content += ''; break; } if (!(isQuery(content) && content.parent().is(current.inner))) { current.inner.append( content ); } // Give a chance for helpers or callbacks to update elements F.trigger('beforeShow'); // Set scrolling before calculating dimensions current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); // Set initial dimensions and start position F._setDimension(); F.reposition(); F.isOpen = false; F.coming = null; F.bindEvents(); if (!F.isOpened) { $('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove(); } else if (previous.prevMethod) { F.transitions[ previous.prevMethod ](); } F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ](); F._preloadImages(); }, _setDimension: function () { var viewport = F.getViewport(), steps = 0, canShrink = false, canExpand = false, wrap = F.wrap, skin = F.skin, inner = F.inner, current = F.current, width = current.width, height = current.height, minWidth = current.minWidth, minHeight = current.minHeight, maxWidth = current.maxWidth, maxHeight = current.maxHeight, scrolling = current.scrolling, scrollOut = current.scrollOutside ? current.scrollbarWidth : 0, margin = current.margin, wMargin = getScalar(margin[1] + margin[3]), hMargin = getScalar(margin[0] + margin[2]), wPadding, hPadding, wSpace, hSpace, origWidth, origHeight, origMaxWidth, origMaxHeight, ratio, width_, height_, maxWidth_, maxHeight_, iframe, body; // Reset dimensions so we could re-check actual size wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp'); wPadding = getScalar(skin.outerWidth(true) - skin.width()); hPadding = getScalar(skin.outerHeight(true) - skin.height()); // Any space between content and viewport (margin, padding, border, title) wSpace = wMargin + wPadding; hSpace = hMargin + hPadding; origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width; origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height; if (current.type === 'iframe') { iframe = current.content; if (current.autoHeight && iframe.data('ready') === 1) { try { if (iframe[0].contentWindow.document.location) { inner.width( origWidth ).height(9999); body = iframe.contents().find('body'); if (scrollOut) { body.css('overflow-x', 'hidden'); } origHeight = body.outerHeight(true); } } catch (e) {} } } else if (current.autoWidth || current.autoHeight) { inner.addClass( 'fancybox-tmp' ); // Set width or height in case we need to calculate only one dimension if (!current.autoWidth) { inner.width( origWidth ); } if (!current.autoHeight) { inner.height( origHeight ); } if (current.autoWidth) { origWidth = inner.width(); } if (current.autoHeight) { origHeight = inner.height(); } inner.removeClass( 'fancybox-tmp' ); } width = getScalar( origWidth ); height = getScalar( origHeight ); ratio = origWidth / origHeight; // Calculations for the content minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth); maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth); minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight); maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight); // These will be used to determine if wrap can fit in the viewport origMaxWidth = maxWidth; origMaxHeight = maxHeight; if (current.fitToView) { maxWidth = Math.min(viewport.w - wSpace, maxWidth); maxHeight = Math.min(viewport.h - hSpace, maxHeight); } maxWidth_ = viewport.w - wMargin; maxHeight_ = viewport.h - hMargin; if (current.aspectRatio) { if (width > maxWidth) { width = maxWidth; height = getScalar(width / ratio); } if (height > maxHeight) { height = maxHeight; width = getScalar(height * ratio); } if (width < minWidth) { width = minWidth; height = getScalar(width / ratio); } if (height < minHeight) { height = minHeight; width = getScalar(height * ratio); } } else { width = Math.max(minWidth, Math.min(width, maxWidth)); if (current.autoHeight && current.type !== 'iframe') { inner.width( width ); height = inner.height(); } height = Math.max(minHeight, Math.min(height, maxHeight)); } // Try to fit inside viewport (including the title) if (current.fitToView) { inner.width( width ).height( height ); wrap.width( width + wPadding ); // Real wrap dimensions width_ = wrap.width(); height_ = wrap.height(); if (current.aspectRatio) { while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) { if (steps++ > 19) { break; } height = Math.max(minHeight, Math.min(maxHeight, height - 10)); width = getScalar(height * ratio); if (width < minWidth) { width = minWidth; height = getScalar(width / ratio); } if (width > maxWidth) { width = maxWidth; height = getScalar(width / ratio); } inner.width( width ).height( height ); wrap.width( width + wPadding ); width_ = wrap.width(); height_ = wrap.height(); } } else { width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_))); height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_))); } } if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) { width += scrollOut; } inner.width( width ).height( height ); wrap.width( width + wPadding ); width_ = wrap.width(); height_ = wrap.height(); canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight; canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight)); $.extend(current, { dim : { width : getValue( width_ ), height : getValue( height_ ) }, origWidth : origWidth, origHeight : origHeight, canShrink : canShrink, canExpand : canExpand, wPadding : wPadding, hPadding : hPadding, wrapSpace : height_ - skin.outerHeight(true), skinSpace : skin.height() - height }); if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) { inner.height('auto'); } }, _getPosition: function (onlyAbsolute) { var current = F.current, viewport = F.getViewport(), margin = current.margin, width = F.wrap.width() + margin[1] + margin[3], height = F.wrap.height() + margin[0] + margin[2], rez = { position: 'absolute', top : margin[0], left : margin[3] }; if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { rez.position = 'fixed'; } else if (!current.locked) { rez.top += viewport.y; rez.left += viewport.x; } rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * current.leftRatio))); return rez; }, _afterZoomIn: function () { var current = F.current; if (!current) { return; } F.isOpen = F.isOpened = true; F.wrap.css('overflow', 'visible').addClass('fancybox-opened').hide().show(0); F.update(); // Assign a click event if ( current.closeClick || (current.nextClick && F.group.length > 1) ) { F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { e.preventDefault(); F[ current.closeClick ? 'close' : 'next' ](); } }); } // Create a close button if (current.closeBtn) { $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) { e.preventDefault(); F.close(); }); } // Create navigation arrows if (current.arrows && F.group.length > 1) { if (current.loop || current.index > 0) { $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); } if (current.loop || current.index < F.group.length - 1) { $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); } } F.trigger('afterShow'); // Stop the slideshow if this is the last item if (!current.loop && current.index === current.group.length - 1) { F.play( false ); } else if (F.opts.autoPlay && !F.player.isActive) { F.opts.autoPlay = false; F.play(true); } }, _afterZoomOut: function ( obj ) { obj = obj || F.current; $('.fancybox-wrap').trigger('onReset').remove(); $.extend(F, { group : {}, opts : {}, router : false, current : null, isActive : false, isOpened : false, isOpen : false, isClosing : false, wrap : null, skin : null, outer : null, inner : null }); F.trigger('afterClose', obj); } }); /* * Default transitions */ F.transitions = { getOrigPosition: function () { var current = F.current, element = current.element, orig = current.orig, pos = {}, width = 50, height = 50, hPadding = current.hPadding, wPadding = current.wPadding, viewport = F.getViewport(); if (!orig && current.isDom && element.is(':visible')) { orig = element.find('img:first'); if (!orig.length) { orig = element; } } if (isQuery(orig)) { pos = orig.offset(); if (orig.is('img')) { width = orig.outerWidth(); height = orig.outerHeight(); } } else { pos.top = viewport.y + (viewport.h - height) * current.topRatio; pos.left = viewport.x + (viewport.w - width) * current.leftRatio; } if (F.wrap.css('position') === 'fixed' || current.locked) { pos.top -= viewport.y; pos.left -= viewport.x; } pos = { top : getValue(pos.top - hPadding * current.topRatio), left : getValue(pos.left - wPadding * current.leftRatio), width : getValue(width + wPadding), height : getValue(height + hPadding) }; return pos; }, step: function (now, fx) { var ratio, padding, value, prop = fx.prop, current = F.current, wrapSpace = current.wrapSpace, skinSpace = current.skinSpace; if (prop === 'width' || prop === 'height') { ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start); if (F.isClosing) { ratio = 1 - ratio; } padding = prop === 'width' ? current.wPadding : current.hPadding; value = now - padding; F.skin[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) ) ); F.inner[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) ); } }, zoomIn: function () { var current = F.current, startPos = current.pos, effect = current.openEffect, elastic = effect === 'elastic', endPos = $.extend({opacity : 1}, startPos); // Remove "position" property that breaks older IE delete endPos.position; if (elastic) { startPos = this.getOrigPosition(); if (current.openOpacity) { startPos.opacity = 0.1; } } else if (effect === 'fade') { startPos.opacity = 0.1; } F.wrap.css(startPos).animate(endPos, { duration : effect === 'none' ? 0 : current.openSpeed, easing : current.openEasing, step : elastic ? this.step : null, complete : F._afterZoomIn }); }, zoomOut: function () { var current = F.current, effect = current.closeEffect, elastic = effect === 'elastic', endPos = {opacity : 0.1}; if (elastic) { endPos = this.getOrigPosition(); if (current.closeOpacity) { endPos.opacity = 0.1; } } F.wrap.animate(endPos, { duration : effect === 'none' ? 0 : current.closeSpeed, easing : current.closeEasing, step : elastic ? this.step : null, complete : F._afterZoomOut }); }, changeIn: function () { var current = F.current, effect = current.nextEffect, startPos = current.pos, endPos = { opacity : 1 }, direction = F.direction, distance = 200, field; startPos.opacity = 0.1; if (effect === 'elastic') { field = direction === 'down' || direction === 'up' ? 'top' : 'left'; if (direction === 'down' || direction === 'right') { startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance); endPos[ field ] = '+=' + distance + 'px'; } else { startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance); endPos[ field ] = '-=' + distance + 'px'; } } // Workaround for http://bugs.jquery.com/ticket/12273 if (effect === 'none') { F._afterZoomIn(); } else { F.wrap.css(startPos).animate(endPos, { duration : current.nextSpeed, easing : current.nextEasing, complete : F._afterZoomIn }); } }, changeOut: function () { var previous = F.previous, effect = previous.prevEffect, endPos = { opacity : 0.1 }, direction = F.direction, distance = 200; if (effect === 'elastic') { endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px'; } previous.wrap.animate(endPos, { duration : effect === 'none' ? 0 : previous.prevSpeed, easing : previous.prevEasing, complete : function () { $(this).trigger('onReset').remove(); } }); } }; /* * Overlay helper */ F.helpers.overlay = { defaults : { closeClick : true, // if true, fancyBox will be closed when user clicks on the overlay speedOut : 200, // duration of fadeOut animation showEarly : true, // indicates if should be opened immediately or wait until the content is ready css : {}, // custom CSS properties locked : !isTouch, // if true, the content will be locked into overlay fixed : true // if false, the overlay CSS position property will not be set to "fixed" }, overlay : null, // current handle fixed : false, // indicates if the overlay has position "fixed" el : $('html'), // element that contains "the lock" // Public methods create : function(opts) { var parent; opts = $.extend({}, this.defaults, opts); if (this.overlay) { this.close(); } parent = F.coming ? F.coming.parent : opts.parent; this.overlay = $('
    ').appendTo( parent && parent.length ? parent : 'body' ); this.fixed = false; if (opts.fixed && F.defaults.fixed) { this.overlay.addClass('fancybox-overlay-fixed'); this.fixed = true; } }, open : function(opts) { var that = this; opts = $.extend({}, this.defaults, opts); if (this.overlay) { this.overlay.unbind('.overlay').width('auto').height('auto'); } else { this.create(opts); } if (!this.fixed) { W.bind('resize.overlay', $.proxy( this.update, this) ); this.update(); } if (opts.closeClick) { this.overlay.bind('click.overlay', function(e) { if ($(e.target).hasClass('fancybox-overlay')) { if (F.isActive) { F.close(); } else { that.close(); } return false; } }); } this.overlay.css( opts.css ).show(); }, close : function() { W.unbind('resize.overlay'); if (this.el.hasClass('fancybox-lock')) { $('.fancybox-margin').removeClass('fancybox-margin'); this.el.removeClass('fancybox-lock'); W.scrollTop( this.scrollV ).scrollLeft( this.scrollH ); } $('.fancybox-overlay').remove().hide(); $.extend(this, { overlay : null, fixed : false }); }, // Private, callbacks update : function () { var width = '100%', offsetWidth; // Reset width/height so it will not mess this.overlay.width(width).height('100%'); // jQuery does not return reliable result for IE if (IE) { offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); if (D.width() > offsetWidth) { width = D.width(); } } else if (D.width() > W.width()) { width = D.width(); } this.overlay.width(width).height(D.height()); }, // This is where we can manipulate DOM, because later it would cause iframes to reload onReady : function (opts, obj) { var overlay = this.overlay; $('.fancybox-overlay').stop(true, true); if (!overlay) { this.create(opts); } if (opts.locked && this.fixed && obj.fixed) { obj.locked = this.overlay.append( obj.wrap ); obj.fixed = false; } if (opts.showEarly === true) { this.beforeShow.apply(this, arguments); } }, beforeShow : function(opts, obj) { if (obj.locked && !this.el.hasClass('fancybox-lock')) { if (this.fixPosition !== false) { $('*').filter(function(){ return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") ); }).addClass('fancybox-margin'); } this.el.addClass('fancybox-margin'); this.scrollV = W.scrollTop(); this.scrollH = W.scrollLeft(); this.el.addClass('fancybox-lock'); W.scrollTop( this.scrollV ).scrollLeft( this.scrollH ); } this.open(opts); }, onUpdate : function() { if (!this.fixed) { this.update(); } }, afterClose: function (opts) { // Remove overlay if exists and fancyBox is not opening // (e.g., it is not being open using afterClose callback) if (this.overlay && !F.coming) { this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this )); } } }; /* * Title helper */ F.helpers.title = { defaults : { type : 'float', // 'float', 'inside', 'outside' or 'over', position : 'bottom' // 'top' or 'bottom' }, beforeShow: function (opts) { var current = F.current, text = current.title, type = opts.type, title, target; if ($.isFunction(text)) { text = text.call(current.element, current); } if (!isString(text) || $.trim(text) === '') { return; } title = $('
    ' + text + '
    '); switch (type) { case 'inside': target = F.skin; break; case 'outside': target = F.wrap; break; case 'over': target = F.inner; break; default: // 'float' target = F.skin; title.appendTo('body'); if (IE) { title.width( title.width() ); } title.wrapInner(''); //Increase bottom margin so this title will also fit into viewport F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) ); break; } title[ (opts.position === 'top' ? 'prependTo' : 'appendTo') ](target); } }; // jQuery plugin initialization $.fn.fancybox = function (options) { var index, that = $(this), selector = this.selector || '', run = function(e) { var what = $(this).blur(), idx = index, relType, relVal; if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) { relType = options.groupAttr || 'data-fancybox-group'; relVal = what.attr(relType); if (!relVal) { relType = 'rel'; relVal = what.get(0)[ relType ]; } if (relVal && relVal !== '' && relVal !== 'nofollow') { what = selector.length ? $(selector) : that; what = what.filter('[' + relType + '="' + relVal + '"]'); idx = what.index(this); } options.index = idx; // Stop an event from bubbling if everything is fine if (F.open(what, options) !== false) { e.preventDefault(); } } }; options = options || {}; index = options.index || 0; if (!selector || options.live === false) { that.unbind('click.fb-start').bind('click.fb-start', run); } else { D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run); } this.filter('[data-fancybox-start=1]').trigger('click'); return this; }; // Tests that need a body at doc ready D.ready(function() { var w1, w2; if ( $.scrollbarWidth === undefined ) { // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth $.scrollbarWidth = function() { var parent = $('
    ').appendTo('body'), child = parent.children(), width = child.innerWidth() - child.height( 99 ).innerWidth(); parent.remove(); return width; }; } if ( $.support.fixedPosition === undefined ) { $.support.fixedPosition = (function() { var elem = $('
    ').appendTo('body'), fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 ); elem.remove(); return fixed; }()); } $.extend(F.defaults, { scrollbarWidth : $.scrollbarWidth(), fixed : $.support.fixedPosition, parent : $('body') }); //Get real width of page scroll-bar w1 = $(window).width(); H.addClass('fancybox-lock-test'); w2 = $(window).width(); H.removeClass('fancybox-lock-test'); $("").appendTo("head"); }); }(window, document, jQuery)); /* * jQuery FlexSlider v2.5.0 * Copyright 2012 WooThemes * Contributing Author: Tyler Smith */ ; (function ($) { //FlexSlider: Object Instance $.flexslider = function(el, options) { var slider = $(el); // making variables public slider.vars = $.extend({}, $.flexslider.defaults, options); var namespace = slider.vars.namespace, msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture, touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch, // depricating this idea, as devices are being released with both of these events //eventType = (touch) ? "touchend" : "click", eventType = "click touchend MSPointerUp keyup", watchedEvent = "", watchedEventClearTimer, vertical = slider.vars.direction === "vertical", reverse = slider.vars.reverse, carousel = (slider.vars.itemWidth > 0), fade = slider.vars.animation === "fade", asNav = slider.vars.asNavFor !== "", methods = {}, focused = true; // Store a reference to the slider object $.data(el, "flexslider", slider); // Private slider methods methods = { init: function() { slider.animating = false; // Get current slide and make sure it is a number slider.currentSlide = parseInt( ( slider.vars.startAt ? slider.vars.startAt : 0), 10 ); if ( isNaN( slider.currentSlide ) ) { slider.currentSlide = 0; } slider.animatingTo = slider.currentSlide; slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last); slider.containerSelector = slider.vars.selector.substr(0,slider.vars.selector.search(' ')); slider.slides = $(slider.vars.selector, slider); slider.container = $(slider.containerSelector, slider); slider.count = slider.slides.length; // SYNC: slider.syncExists = $(slider.vars.sync).length > 0; // SLIDE: if (slider.vars.animation === "slide") { slider.vars.animation = "swing"; } slider.prop = (vertical) ? "top" : "marginLeft"; slider.args = {}; // SLIDESHOW: slider.manualPause = false; slider.stopped = false; //PAUSE WHEN INVISIBLE slider.started = false; slider.startTimeout = null; // TOUCH/USECSS: slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() { var obj = document.createElement('div'), props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; for (var i in props) { if ( obj.style[ props[i] ] !== undefined ) { slider.pfx = props[i].replace('Perspective','').toLowerCase(); slider.prop = "-" + slider.pfx + "-transform"; return true; } } return false; }()); slider.ensureAnimationEnd = ''; // CONTROLSCONTAINER: if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer); // MANUAL: if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls); // CUSTOM DIRECTION NAV: if (slider.vars.customDirectionNav !== "") slider.customDirectionNav = $(slider.vars.customDirectionNav).length === 2 && $(slider.vars.customDirectionNav); // RANDOMIZE: if (slider.vars.randomize) { slider.slides.sort(function() { return (Math.round(Math.random())-0.5); }); slider.container.empty().append(slider.slides); } slider.doMath(); // INIT slider.setup("init"); // CONTROLNAV: if (slider.vars.controlNav) { methods.controlNav.setup(); } // DIRECTIONNAV: if (slider.vars.directionNav) { methods.directionNav.setup(); } // KEYBOARD: if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) { $(document).bind('keyup', function(event) { var keycode = event.keyCode; if (!slider.animating && (keycode === 39 || keycode === 37)) { var target = (keycode === 39) ? slider.getTarget('next') : (keycode === 37) ? slider.getTarget('prev') : false; slider.flexAnimate(target, slider.vars.pauseOnAction); } }); } // MOUSEWHEEL: if (slider.vars.mousewheel) { slider.bind('mousewheel', function(event, delta, deltaX, deltaY) { event.preventDefault(); var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev'); slider.flexAnimate(target, slider.vars.pauseOnAction); }); } // PAUSEPLAY if (slider.vars.pausePlay) { methods.pausePlay.setup(); } //PAUSE WHEN INVISIBLE if (slider.vars.slideshow && slider.vars.pauseInvisible) { methods.pauseInvisible.init(); } // SLIDSESHOW if (slider.vars.slideshow) { if (slider.vars.pauseOnHover) { slider.hover(function() { if (!slider.manualPlay && !slider.manualPause) { slider.pause(); } }, function() { if (!slider.manualPause && !slider.manualPlay && !slider.stopped) { slider.play(); } }); } // initialize animation //If we're visible, or we don't use PageVisibility API if(!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) { (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play(); } } // ASNAV: if (asNav) { methods.asNav.setup(); } // TOUCH if (touch && slider.vars.touch) { methods.touch(); } // FADE&&SMOOTHHEIGHT || SLIDE: if (!fade || (fade && slider.vars.smoothHeight)) { $(window).bind("resize orientationchange focus", methods.resize); } slider.find("img").attr("draggable", "false"); // API: start() Callback setTimeout(function(){ slider.vars.start(slider); }, 200); }, asNav: { setup: function() { slider.asNav = true; slider.animatingTo = Math.floor(slider.currentSlide/slider.move); slider.currentItem = slider.currentSlide; slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide"); if(!msGesture){ slider.slides.on(eventType, function(e){ e.preventDefault(); var $slide = $(this), target = $slide.index(); var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container if( posFromLeft <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) { slider.flexAnimate(slider.getTarget("prev"), true); } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) { slider.direction = (slider.currentItem < target) ? "next" : "prev"; slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); } }); }else{ el._slider = slider; slider.slides.each(function (){ var that = this; that._gesture = new MSGesture(); that._gesture.target = that; that.addEventListener("MSPointerDown", function (e){ e.preventDefault(); if(e.currentTarget._gesture) { e.currentTarget._gesture.addPointer(e.pointerId); } }, false); that.addEventListener("MSGestureTap", function (e){ e.preventDefault(); var $slide = $(this), target = $slide.index(); if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) { slider.direction = (slider.currentItem < target) ? "next" : "prev"; slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); } }); }); } } }, controlNav: { setup: function() { if (!slider.manualControls) { methods.controlNav.setupPaging(); } else { // MANUALCONTROLS: methods.controlNav.setupManual(); } }, setupPaging: function() { var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging', j = 1, item, slide; slider.controlNavScaffold = $('
      '); if (slider.pagingCount > 1) { for (var i = 0; i < slider.pagingCount; i++) { slide = slider.slides.eq(i); item = (slider.vars.controlNav === "thumbnails") ? '' : '' + j + ''; if ( 'thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions ) { var captn = slide.attr( 'data-thumbcaption' ); if ( '' !== captn && undefined !== captn ) { item += '' + captn + ''; } } slider.controlNavScaffold.append('
    1. ' + item + '
    2. '); j++; } } // CONTROLSCONTAINER: (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold); methods.controlNav.set(); methods.controlNav.active(); slider.controlNavScaffold.delegate('a, img', eventType, function(event) { event.preventDefault(); if (watchedEvent === "" || watchedEvent === event.type) { var $this = $(this), target = slider.controlNav.index($this); if (!$this.hasClass(namespace + 'active')) { slider.direction = (target > slider.currentSlide) ? "next" : "prev"; slider.flexAnimate(target, slider.vars.pauseOnAction); } } // setup flags to prevent event duplication if (watchedEvent === "") { watchedEvent = event.type; } methods.setToClearWatchedEvent(); }); }, setupManual: function() { slider.controlNav = slider.manualControls; methods.controlNav.active(); slider.controlNav.bind(eventType, function(event) { event.preventDefault(); if (watchedEvent === "" || watchedEvent === event.type) { var $this = $(this), target = slider.controlNav.index($this); if (!$this.hasClass(namespace + 'active')) { (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev"; slider.flexAnimate(target, slider.vars.pauseOnAction); } } // setup flags to prevent event duplication if (watchedEvent === "") { watchedEvent = event.type; } methods.setToClearWatchedEvent(); }); }, set: function() { var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a'; slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider); }, active: function() { slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active"); }, update: function(action, pos) { if (slider.pagingCount > 1 && action === "add") { slider.controlNavScaffold.append($('
    3. ' + slider.count + '
    4. ')); } else if (slider.pagingCount === 1) { slider.controlNavScaffold.find('li').remove(); } else { slider.controlNav.eq(pos).closest('li').remove(); } methods.controlNav.set(); (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active(); } }, directionNav: { setup: function() { var directionNavScaffold = $(''); // CUSTOM DIRECTION NAV: if (slider.customDirectionNav) { slider.directionNav = slider.customDirectionNav; // CONTROLSCONTAINER: } else if (slider.controlsContainer) { $(slider.controlsContainer).append(directionNavScaffold); slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer); } else { slider.append(directionNavScaffold); slider.directionNav = $('.' + namespace + 'direction-nav li a', slider); } methods.directionNav.update(); slider.directionNav.bind(eventType, function(event) { event.preventDefault(); var target; if (watchedEvent === "" || watchedEvent === event.type) { target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev'); slider.flexAnimate(target, slider.vars.pauseOnAction); } // setup flags to prevent event duplication if (watchedEvent === "") { watchedEvent = event.type; } methods.setToClearWatchedEvent(); }); }, update: function() { var disabledClass = namespace + 'disabled'; if (slider.pagingCount === 1) { slider.directionNav.addClass(disabledClass).attr('tabindex', '-1'); } else if (!slider.vars.animationLoop) { if (slider.animatingTo === 0) { slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1'); } else if (slider.animatingTo === slider.last) { slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1'); } else { slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); } } else { slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); } } }, pausePlay: { setup: function() { var pausePlayScaffold = $('
      '); // CONTROLSCONTAINER: if (slider.controlsContainer) { slider.controlsContainer.append(pausePlayScaffold); slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer); } else { slider.append(pausePlayScaffold); slider.pausePlay = $('.' + namespace + 'pauseplay a', slider); } methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play'); slider.pausePlay.bind(eventType, function(event) { event.preventDefault(); if (watchedEvent === "" || watchedEvent === event.type) { if ($(this).hasClass(namespace + 'pause')) { slider.manualPause = true; slider.manualPlay = false; slider.pause(); } else { slider.manualPause = false; slider.manualPlay = true; slider.play(); } } // setup flags to prevent event duplication if (watchedEvent === "") { watchedEvent = event.type; } methods.setToClearWatchedEvent(); }); }, update: function(state) { (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText); } }, touch: function() { var startX, startY, offset, cwidth, dx, startT, onTouchStart, onTouchMove, onTouchEnd, scrolling = false, localX = 0, localY = 0, accDx = 0; if(!msGesture){ onTouchStart = function(e) { if (slider.animating) { e.preventDefault(); } else if ( ( window.navigator.msPointerEnabled ) || e.touches.length === 1 ) { slider.pause(); // CAROUSEL: cwidth = (vertical) ? slider.h : slider. w; startT = Number(new Date()); // CAROUSEL: // Local vars for X and Y points. localX = e.touches[0].pageX; localY = e.touches[0].pageY; offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : (carousel && slider.currentSlide === slider.last) ? slider.limit : (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; startX = (vertical) ? localY : localX; startY = (vertical) ? localX : localY; el.addEventListener('touchmove', onTouchMove, false); el.addEventListener('touchend', onTouchEnd, false); } }; onTouchMove = function(e) { // Local vars for X and Y points. localX = e.touches[0].pageX; localY = e.touches[0].pageY; dx = (vertical) ? startX - localY : startX - localX; scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY)); var fxms = 500; if ( ! scrolling || Number( new Date() ) - startT > fxms ) { e.preventDefault(); if (!fade && slider.transitions) { if (!slider.vars.animationLoop) { dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1); } slider.setProps(offset + dx, "setTouch"); } } }; onTouchEnd = function(e) { // finish the touch by undoing the touch session el.removeEventListener('touchmove', onTouchMove, false); if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { var updateDx = (reverse) ? -dx : dx, target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) { slider.flexAnimate(target, slider.vars.pauseOnAction); } else { if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); } } } el.removeEventListener('touchend', onTouchEnd, false); startX = null; startY = null; dx = null; offset = null; }; el.addEventListener('touchstart', onTouchStart, false); }else{ el.style.msTouchAction = "none"; el._gesture = new MSGesture(); el._gesture.target = el; el.addEventListener("MSPointerDown", onMSPointerDown, false); el._slider = slider; el.addEventListener("MSGestureChange", onMSGestureChange, false); el.addEventListener("MSGestureEnd", onMSGestureEnd, false); function onMSPointerDown(e){ e.stopPropagation(); if (slider.animating) { e.preventDefault(); }else{ slider.pause(); el._gesture.addPointer(e.pointerId); accDx = 0; cwidth = (vertical) ? slider.h : slider. w; startT = Number(new Date()); // CAROUSEL: offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : (carousel && slider.currentSlide === slider.last) ? slider.limit : (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; } } function onMSGestureChange(e) { e.stopPropagation(); var slider = e.target._slider; if(!slider){ return; } var transX = -e.translationX, transY = -e.translationY; //Accumulate translations. accDx = accDx + ((vertical) ? transY : transX); dx = accDx; scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY)); if(e.detail === e.MSGESTURE_FLAG_INERTIA){ setImmediate(function (){ el._gesture.stop(); }); return; } if (!scrolling || Number(new Date()) - startT > 500) { e.preventDefault(); if (!fade && slider.transitions) { if (!slider.vars.animationLoop) { dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1); } slider.setProps(offset + dx, "setTouch"); } } } function onMSGestureEnd(e) { e.stopPropagation(); var slider = e.target._slider; if(!slider){ return; } if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { var updateDx = (reverse) ? -dx : dx, target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) { slider.flexAnimate(target, slider.vars.pauseOnAction); } else { if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); } } } startX = null; startY = null; dx = null; offset = null; accDx = 0; } } }, resize: function() { if (!slider.animating && slider.is(':visible')) { if (!carousel) { slider.doMath(); } if (fade) { // SMOOTH HEIGHT: methods.smoothHeight(); } else if (carousel) { //CAROUSEL: slider.slides.width(slider.computedW); slider.update(slider.pagingCount); slider.setProps(); } else if (vertical) { //VERTICAL: slider.viewport.height(slider.h); slider.setProps(slider.h, "setTotal"); } else { // SMOOTH HEIGHT: if (slider.vars.smoothHeight) { methods.smoothHeight(); } slider.newSlides.width(slider.computedW); slider.setProps(slider.computedW, "setTotal"); } } }, smoothHeight: function(dur) { if (!vertical || fade) { var $obj = (fade) ? slider : slider.viewport; (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).height()}, dur) : $obj.height(slider.slides.eq(slider.animatingTo).height()); } }, sync: function(action) { var $obj = $(slider.vars.sync).data("flexslider"), target = slider.animatingTo; switch (action) { case "animate": $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); break; case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break; case "pause": $obj.pause(); break; } }, uniqueID: function($clone) { // Append _clone to current level and children elements with id attributes $clone.filter( '[id]' ).add($clone.find( '[id]' )).each(function() { var $this = $(this); $this.attr( 'id', $this.attr( 'id' ) + '_clone' ); }); return $clone; }, pauseInvisible: { visProp: null, init: function() { var visProp = methods.pauseInvisible.getHiddenProp(); if (visProp) { var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange'; document.addEventListener(evtname, function() { if (methods.pauseInvisible.isHidden()) { if(slider.startTimeout) { clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible } else { slider.pause(); //Or just pause } } else { if(slider.started) { slider.play(); //Initiated before, just play } else { if (slider.vars.initDelay > 0) { setTimeout(slider.play, slider.vars.initDelay); } else { slider.play(); //Didn't init before: simply init or wait for it } } } }); } }, isHidden: function() { var prop = methods.pauseInvisible.getHiddenProp(); if (!prop) { return false; } return document[prop]; }, getHiddenProp: function() { var prefixes = ['webkit','moz','ms','o']; // if 'hidden' is natively supported just return it if ('hidden' in document) { return 'hidden'; } // otherwise loop over all the known prefixes until we find one for ( var i = 0; i < prefixes.length; i++ ) { if ((prefixes[i] + 'Hidden') in document) { return prefixes[i] + 'Hidden'; } } // otherwise it's not supported return null; } }, setToClearWatchedEvent: function() { clearTimeout(watchedEventClearTimer); watchedEventClearTimer = setTimeout(function() { watchedEvent = ""; }, 3000); } }; // public methods slider.flexAnimate = function(target, pause, override, withSync, fromNav) { if (!slider.vars.animationLoop && target !== slider.currentSlide) { slider.direction = (target > slider.currentSlide) ? "next" : "prev"; } if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev"; if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) { if (asNav && withSync) { var master = $(slider.vars.asNavFor).data('flexslider'); slider.atEnd = target === 0 || target === slider.count - 1; master.flexAnimate(target, true, false, true, fromNav); slider.direction = (slider.currentItem < target) ? "next" : "prev"; master.direction = slider.direction; if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) { slider.currentItem = target; slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); target = Math.floor(target/slider.visible); } else { slider.currentItem = target; slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); return false; } } slider.animating = true; slider.animatingTo = target; // SLIDESHOW: if (pause) { slider.pause(); } // API: before() animation Callback slider.vars.before(slider); // SYNC: if (slider.syncExists && !fromNav) { methods.sync("animate"); } // CONTROLNAV if (slider.vars.controlNav) { methods.controlNav.active(); } // !CAROUSEL: // CANDIDATE: slide active class (for add/remove slide) if (!carousel) { slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide'); } // INFINITE LOOP: // CANDIDATE: atEnd slider.atEnd = target === 0 || target === slider.last; // DIRECTIONNAV: if (slider.vars.directionNav) { methods.directionNav.update(); } if (target === slider.last) { // API: end() of cycle Callback slider.vars.end(slider); // SLIDESHOW && !INFINITE LOOP: if (!slider.vars.animationLoop) { slider.pause(); } } // SLIDE: if (!fade) { var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW, margin, slideString, calcNext; // INFINITE LOOP / REVERSE: if (carousel) { //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin; margin = slider.vars.itemMargin; calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo; slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext; } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") { slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0; } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") { slideString = (reverse) ? 0 : (slider.count + 1) * dimension; } else { slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension; } slider.setProps(slideString, "", slider.vars.animationSpeed); if (slider.transitions) { if (!slider.vars.animationLoop || !slider.atEnd) { slider.animating = false; slider.currentSlide = slider.animatingTo; } // Unbind previous transitionEnd events and re-bind new transitionEnd event slider.container.unbind("webkitTransitionEnd transitionend"); slider.container.bind("webkitTransitionEnd transitionend", function() { clearTimeout(slider.ensureAnimationEnd); slider.wrapup(dimension); }); // Insurance for the ever-so-fickle transitionEnd event clearTimeout(slider.ensureAnimationEnd); slider.ensureAnimationEnd = setTimeout(function() { slider.wrapup(dimension); }, slider.vars.animationSpeed + 100); } else { slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){ slider.wrapup(dimension); }); } } else { // FADE: if (!touch) { //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing); //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing); slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); } else { slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 }); slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 }); slider.wrapup(dimension); } } // SMOOTH HEIGHT: if (slider.vars.smoothHeight) { methods.smoothHeight(slider.vars.animationSpeed); } } }; slider.wrapup = function(dimension) { // SLIDE: if (!fade && !carousel) { if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) { slider.setProps(dimension, "jumpEnd"); } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) { slider.setProps(dimension, "jumpStart"); } } slider.animating = false; slider.currentSlide = slider.animatingTo; // API: after() animation Callback slider.vars.after(slider); }; // SLIDESHOW: slider.animateSlides = function() { if (!slider.animating && focused ) { slider.flexAnimate(slider.getTarget("next")); } }; // SLIDESHOW: slider.pause = function() { clearInterval(slider.animatedSlides); slider.animatedSlides = null; slider.playing = false; // PAUSEPLAY: if (slider.vars.pausePlay) { methods.pausePlay.update("play"); } // SYNC: if (slider.syncExists) { methods.sync("pause"); } }; // SLIDESHOW: slider.play = function() { if (slider.playing) { clearInterval(slider.animatedSlides); } slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed); slider.started = slider.playing = true; // PAUSEPLAY: if (slider.vars.pausePlay) { methods.pausePlay.update("pause"); } // SYNC: if (slider.syncExists) { methods.sync("play"); } }; // STOP: slider.stop = function () { slider.pause(); slider.stopped = true; }; slider.canAdvance = function(target, fromNav) { // ASNAV: var last = (asNav) ? slider.pagingCount - 1 : slider.last; return (fromNav) ? true : (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true : (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false : (target === slider.currentSlide && !asNav) ? false : (slider.vars.animationLoop) ? true : (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false : (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false : true; }; slider.getTarget = function(dir) { slider.direction = dir; if (dir === "next") { return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1; } else { return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1; } }; // SLIDE: slider.setProps = function(pos, special, dur) { var target = (function() { var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo, posCalc = (function() { if (carousel) { return (special === "setTouch") ? pos : (reverse && slider.animatingTo === slider.last) ? 0 : (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : (slider.animatingTo === slider.last) ? slider.limit : posCheck; } else { switch (special) { case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos; case "setTouch": return (reverse) ? pos : pos; case "jumpEnd": return (reverse) ? pos : slider.count * pos; case "jumpStart": return (reverse) ? slider.count * pos : pos; default: return pos; } } }()); return (posCalc * -1) + "px"; }()); if (slider.transitions) { target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)"; dur = (dur !== undefined) ? (dur/1000) + "s" : "0s"; slider.container.css("-" + slider.pfx + "-transition-duration", dur); slider.container.css("transition-duration", dur); } slider.args[slider.prop] = target; if (slider.transitions || dur === undefined) { slider.container.css(slider.args); } slider.container.css('transform',target); }; slider.setup = function(type) { // SLIDE: if (!fade) { var sliderOffset, arr; if (type === "init") { slider.viewport = $('
      ').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container); // INFINITE LOOP: slider.cloneCount = 0; slider.cloneOffset = 0; // REVERSE: if (reverse) { arr = $.makeArray(slider.slides).reverse(); slider.slides = $(arr); slider.container.empty().append(slider.slides); } } // INFINITE LOOP && !CAROUSEL: if (slider.vars.animationLoop && !carousel) { slider.cloneCount = 2; slider.cloneOffset = 1; // clear out old clones if (type !== "init") { slider.container.find('.clone').remove(); } slider.container.append(methods.uniqueID(slider.slides.first().clone().addClass('clone')).attr('aria-hidden', 'true')) .prepend(methods.uniqueID(slider.slides.last().clone().addClass('clone')).attr('aria-hidden', 'true')); } slider.newSlides = $(slider.vars.selector, slider); sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset; // VERTICAL: if (vertical && !carousel) { slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%"); setTimeout(function(){ slider.newSlides.css({"display": "block"}); slider.doMath(); slider.viewport.height(slider.h); slider.setProps(sliderOffset * slider.h, "init"); }, (type === "init") ? 100 : 0); } else { slider.container.width((slider.count + slider.cloneCount) * 200 + "%"); slider.setProps(sliderOffset * slider.computedW, "init"); setTimeout(function(){ slider.doMath(); slider.newSlides.css({"width": slider.computedW, "float": "left", "display": "block"}); // SMOOTH HEIGHT: if (slider.vars.smoothHeight) { methods.smoothHeight(); } }, (type === "init") ? 100 : 0); } } else { // FADE: slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"}); if (type === "init") { if (!touch) { //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing); if (slider.vars.fadeFirstSlide == false) { slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1}); } else { slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing); } } else { slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2}); } } // SMOOTH HEIGHT: if (slider.vars.smoothHeight) { methods.smoothHeight(); } } // !CAROUSEL: // CANDIDATE: active slide if (!carousel) { slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide"); } //FlexSlider: init() Callback slider.vars.init(slider); }; slider.doMath = function() { var slide = slider.slides.first(), slideMargin = slider.vars.itemMargin, minItems = slider.vars.minItems, maxItems = slider.vars.maxItems; slider.w = (slider.viewport===undefined) ? slider.width() : slider.viewport.width(); slider.h = slide.height(); slider.boxPadding = slide.outerWidth() - slide.width(); // CAROUSEL: if (carousel) { slider.itemT = slider.vars.itemWidth + slideMargin; slider.minW = (minItems) ? minItems * slider.itemT : slider.w; slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w; slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1)))/minItems : (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1)))/maxItems : (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth; slider.visible = Math.floor(slider.w/(slider.itemW)); slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible; slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1); slider.last = slider.pagingCount - 1; slider.limit = (slider.pagingCount === 1) ? 0 : (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin; } else { slider.itemW = slider.w; slider.pagingCount = slider.count; slider.last = slider.count - 1; } slider.computedW = slider.itemW - slider.boxPadding; }; slider.update = function(pos, action) { slider.doMath(); // update currentSlide and slider.animatingTo if necessary if (!carousel) { if (pos < slider.currentSlide) { slider.currentSlide += 1; } else if (pos <= slider.currentSlide && pos !== 0) { slider.currentSlide -= 1; } slider.animatingTo = slider.currentSlide; } // update controlNav if (slider.vars.controlNav && !slider.manualControls) { if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) { methods.controlNav.update("add"); } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) { if (carousel && slider.currentSlide > slider.last) { slider.currentSlide -= 1; slider.animatingTo -= 1; } methods.controlNav.update("remove", slider.last); } } // update directionNav if (slider.vars.directionNav) { methods.directionNav.update(); } }; slider.addSlide = function(obj, pos) { var $obj = $(obj); slider.count += 1; slider.last = slider.count - 1; // append new slide if (vertical && reverse) { (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj); } else { (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj); } // update currentSlide, animatingTo, controlNav, and directionNav slider.update(pos, "add"); // update slider.slides slider.slides = $(slider.vars.selector + ':not(.clone)', slider); // re-setup the slider to accomdate new slide slider.setup(); //FlexSlider: added() Callback slider.vars.added(slider); }; slider.removeSlide = function(obj) { var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj; // update count slider.count -= 1; slider.last = slider.count - 1; // remove slide if (isNaN(obj)) { $(obj, slider.slides).remove(); } else { (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove(); } // update currentSlide, animatingTo, controlNav, and directionNav slider.doMath(); slider.update(pos, "remove"); // update slider.slides slider.slides = $(slider.vars.selector + ':not(.clone)', slider); // re-setup the slider to accomdate new slide slider.setup(); // FlexSlider: removed() Callback slider.vars.removed(slider); }; //FlexSlider: Initialize methods.init(); }; // Ensure the slider isn't focussed if the window loses focus. $( window ).blur( function ( e ) { focused = false; }).focus( function ( e ) { focused = true; }); //FlexSlider: Default Settings $.flexslider.defaults = { namespace: "flex-", //{NEW} String: Prefix string attached to the class of every element generated by the plugin selector: ".slides > li", //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril animation: "fade", //String: Select your animation type, "fade" or "slide" easing: "swing", //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported! direction: "horizontal", //String: Select the sliding direction, "horizontal" or "vertical" reverse: false, //{NEW} Boolean: Reverse the animation direction animationLoop: true, //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end smoothHeight: false, //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode startAt: 0, //Integer: The slide that the slider should start on. Array notation (0 = first slide) slideshow: true, //Boolean: Animate slider automatically slideshowSpeed: 7000, //Integer: Set the speed of the slideshow cycling, in milliseconds animationSpeed: 600, //Integer: Set the speed of animations, in milliseconds initDelay: 0, //{NEW} Integer: Set an initialization delay, in milliseconds randomize: false, //Boolean: Randomize slide order fadeFirstSlide: true, //Boolean: Fade in the first slide when animation type is "fade" thumbCaptions: false, //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav. // Usability features pauseOnAction: true, //Boolean: Pause the slideshow when interacting with control elements, highly recommended. pauseOnHover: false, //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering pauseInvisible: true, //{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage. useCSS: true, //{NEW} Boolean: Slider will use CSS3 transitions if available touch: true, //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices video: false, //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches // Primary Controls controlNav: true, //Boolean: Create navigation for paging control of each slide? Note: Leave true for manualControls usage directionNav: true, //Boolean: Create navigation for previous/next navigation? (true/false) prevText: "Previous", //String: Set the text for the "previous" directionNav item nextText: "Next", //String: Set the text for the "next" directionNav item // Secondary Navigation keyboard: true, //Boolean: Allow slider navigating via keyboard left/right keys multipleKeyboard: false, //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present. mousewheel: false, //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel pausePlay: false, //Boolean: Create pause/play dynamic element pauseText: "Pause", //String: Set the text for the "pause" pausePlay item playText: "Play", //String: Set the text for the "play" pausePlay item // Special properties controlsContainer: "", //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found. manualControls: "", //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs. customDirectionNav: "", //{NEW} jQuery Object/Selector: Custom prev / next button. Must be two jQuery elements. In order to make the events work they have to have the classes "prev" and "next" (plus namespace) sync: "", //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care. asNavFor: "", //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider // Carousel Options itemWidth: 0, //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding. itemMargin: 0, //{NEW} Integer: Margin between carousel items. minItems: 1, //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this. maxItems: 0, //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit. move: 0, //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items. allowOneSlide: true, //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide // Callback API start: function(){}, //Callback: function(slider) - Fires when the slider loads the first slide before: function(){}, //Callback: function(slider) - Fires asynchronously with each slider animation after: function(){}, //Callback: function(slider) - Fires after each slider animation completes end: function(){}, //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous) added: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is added removed: function(){}, //{NEW} Callback: function(slider) - Fires after a slide is removed init: function() {} //{NEW} Callback: function(slider) - Fires after the slider is initially setup }; //FlexSlider: Plugin Function $.fn.flexslider = function(options) { if (options === undefined) { options = {}; } if (typeof options === "object") { return this.each(function() { var $this = $(this), selector = (options.selector) ? options.selector : ".slides > li", $slides = $this.find(selector); if ( ( $slides.length === 1 && options.allowOneSlide === true ) || $slides.length === 0 ) { $slides.fadeIn(400); if (options.start) { options.start($this); } } else if ($this.data('flexslider') === undefined) { new $.flexslider(this, options); } }); } else { // Helper strings to quickly perform functions on the slider var $slider = $(this).data('flexslider'); switch (options) { case "play": $slider.play(); break; case "pause": $slider.pause(); break; case "stop": $slider.stop(); break; case "next": $slider.flexAnimate($slider.getTarget("next"), true); break; case "prev": case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break; default: if (typeof options === "number") { $slider.flexAnimate(options, true); } } } }; })(jQuery); /*! * imagesLoaded PACKAGED v3.1.8 * JavaScript is all like "You images are done yet or what?" * MIT License */ /*! * EventEmitter v4.2.6 - git.io/ee * Oliver Caldwell * MIT license * @preserve */ (function () { /** * Class for managing events. * Can be extended to provide event functionality in other classes. * * @class EventEmitter Manages event registering and emitting. */ function EventEmitter() {} // Shortcuts to improve speed and size var proto = EventEmitter.prototype; var exports = this; var originalGlobalValue = exports.EventEmitter; /** * Finds the index of the listener for the event in it's storage array. * * @param {Function[]} listeners Array of listeners to search through. * @param {Function} listener Method to look for. * @return {Number} Index of the specified listener, -1 if not found * @api private */ function indexOfListener(listeners, listener) { var i = listeners.length; while (i--) { if (listeners[i].listener === listener) { return i; } } return -1; } /** * Alias a method while keeping the context correct, to allow for overwriting of target method. * * @param {String} name The name of the target method. * @return {Function} The aliased method * @api private */ function alias(name) { return function aliasClosure() { return this[name].apply(this, arguments); }; } /** * Returns the listener array for the specified event. * Will initialise the event object and listener arrays if required. * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. * Each property in the object response is an array of listener functions. * * @param {String|RegExp} evt Name of the event to return the listeners from. * @return {Function[]|Object} All listener functions for the event. */ proto.getListeners = function getListeners(evt) { var events = this._getEvents(); var response; var key; // Return a concatenated array of all matching events if // the selector is a regular expression. if (typeof evt === 'object') { response = {}; for (key in events) { if (events.hasOwnProperty(key) && evt.test(key)) { response[key] = events[key]; } } } else { response = events[evt] || (events[evt] = []); } return response; }; /** * Takes a list of listener objects and flattens it into a list of listener functions. * * @param {Object[]} listeners Raw listener objects. * @return {Function[]} Just the listener functions. */ proto.flattenListeners = function flattenListeners(listeners) { var flatListeners = []; var i; for (i = 0; i < listeners.length; i += 1) { flatListeners.push(listeners[i].listener); } return flatListeners; }; /** * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. * * @param {String|RegExp} evt Name of the event to return the listeners from. * @return {Object} All listener functions for an event in an object. */ proto.getListenersAsObject = function getListenersAsObject(evt) { var listeners = this.getListeners(evt); var response; if (listeners instanceof Array) { response = {}; response[evt] = listeners; } return response || listeners; }; /** * Adds a listener function to the specified event. * The listener will not be added if it is a duplicate. * If the listener returns true then it will be removed after it is called. * If you pass a regular expression as the event name then the listener will be added to all events that match it. * * @param {String|RegExp} evt Name of the event to attach the listener to. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. * @return {Object} Current instance of EventEmitter for chaining. */ proto.addListener = function addListener(evt, listener) { var listeners = this.getListenersAsObject(evt); var listenerIsWrapped = typeof listener === 'object'; var key; for (key in listeners) { if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { listeners[key].push(listenerIsWrapped ? listener : { listener: listener, once: false }); } } return this; }; /** * Alias of addListener */ proto.on = alias('addListener'); /** * Semi-alias of addListener. It will add a listener that will be * automatically removed after it's first execution. * * @param {String|RegExp} evt Name of the event to attach the listener to. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. * @return {Object} Current instance of EventEmitter for chaining. */ proto.addOnceListener = function addOnceListener(evt, listener) { return this.addListener(evt, { listener: listener, once: true }); }; /** * Alias of addOnceListener. */ proto.once = alias('addOnceListener'); /** * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. * You need to tell it what event names should be matched by a regex. * * @param {String} evt Name of the event to create. * @return {Object} Current instance of EventEmitter for chaining. */ proto.defineEvent = function defineEvent(evt) { this.getListeners(evt); return this; }; /** * Uses defineEvent to define multiple events. * * @param {String[]} evts An array of event names to define. * @return {Object} Current instance of EventEmitter for chaining. */ proto.defineEvents = function defineEvents(evts) { for (var i = 0; i < evts.length; i += 1) { this.defineEvent(evts[i]); } return this; }; /** * Removes a listener function from the specified event. * When passed a regular expression as the event name, it will remove the listener from all events that match it. * * @param {String|RegExp} evt Name of the event to remove the listener from. * @param {Function} listener Method to remove from the event. * @return {Object} Current instance of EventEmitter for chaining. */ proto.removeListener = function removeListener(evt, listener) { var listeners = this.getListenersAsObject(evt); var index; var key; for (key in listeners) { if (listeners.hasOwnProperty(key)) { index = indexOfListener(listeners[key], listener); if (index !== -1) { listeners[key].splice(index, 1); } } } return this; }; /** * Alias of removeListener */ proto.off = alias('removeListener'); /** * Adds listeners in bulk using the manipulateListeners method. * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. * You can also pass it a regular expression to add the array of listeners to all events that match it. * Yeah, this function does quite a bit. That's probably a bad thing. * * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. * @param {Function[]} [listeners] An optional array of listener functions to add. * @return {Object} Current instance of EventEmitter for chaining. */ proto.addListeners = function addListeners(evt, listeners) { // Pass through to manipulateListeners return this.manipulateListeners(false, evt, listeners); }; /** * Removes listeners in bulk using the manipulateListeners method. * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. * You can also pass it an event name and an array of listeners to be removed. * You can also pass it a regular expression to remove the listeners from all events that match it. * * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. * @param {Function[]} [listeners] An optional array of listener functions to remove. * @return {Object} Current instance of EventEmitter for chaining. */ proto.removeListeners = function removeListeners(evt, listeners) { // Pass through to manipulateListeners return this.manipulateListeners(true, evt, listeners); }; /** * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. * The first argument will determine if the listeners are removed (true) or added (false). * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. * You can also pass it an event name and an array of listeners to be added/removed. * You can also pass it a regular expression to manipulate the listeners of all events that match it. * * @param {Boolean} remove True if you want to remove listeners, false if you want to add. * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. * @param {Function[]} [listeners] An optional array of listener functions to add/remove. * @return {Object} Current instance of EventEmitter for chaining. */ proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { var i; var value; var single = remove ? this.removeListener : this.addListener; var multiple = remove ? this.removeListeners : this.addListeners; // If evt is an object then pass each of it's properties to this method if (typeof evt === 'object' && !(evt instanceof RegExp)) { for (i in evt) { if (evt.hasOwnProperty(i) && (value = evt[i])) { // Pass the single listener straight through to the singular method if (typeof value === 'function') { single.call(this, i, value); } else { // Otherwise pass back to the multiple function multiple.call(this, i, value); } } } } else { // So evt must be a string // And listeners must be an array of listeners // Loop over it and pass each one to the multiple method i = listeners.length; while (i--) { single.call(this, evt, listeners[i]); } } return this; }; /** * Removes all listeners from a specified event. * If you do not specify an event then all listeners will be removed. * That means every event will be emptied. * You can also pass a regex to remove all events that match it. * * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. * @return {Object} Current instance of EventEmitter for chaining. */ proto.removeEvent = function removeEvent(evt) { var type = typeof evt; var events = this._getEvents(); var key; // Remove different things depending on the state of evt if (type === 'string') { // Remove all listeners for the specified event delete events[evt]; } else if (type === 'object') { // Remove all events matching the regex. for (key in events) { if (events.hasOwnProperty(key) && evt.test(key)) { delete events[key]; } } } else { // Remove all listeners in all events delete this._events; } return this; }; /** * Alias of removeEvent. * * Added to mirror the node API. */ proto.removeAllListeners = alias('removeEvent'); /** * Emits an event of your choice. * When emitted, every listener attached to that event will be executed. * If you pass the optional argument array then those arguments will be passed to every listener upon execution. * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. * So they will not arrive within the array on the other side, they will be separate. * You can also pass a regular expression to emit to all events that match it. * * @param {String|RegExp} evt Name of the event to emit and execute listeners for. * @param {Array} [args] Optional array of arguments to be passed to each listener. * @return {Object} Current instance of EventEmitter for chaining. */ proto.emitEvent = function emitEvent(evt, args) { var listeners = this.getListenersAsObject(evt); var listener; var i; var key; var response; for (key in listeners) { if (listeners.hasOwnProperty(key)) { i = listeners[key].length; while (i--) { // If the listener returns true then it shall be removed from the event // The function is executed either with a basic call or an apply if there is an args array listener = listeners[key][i]; if (listener.once === true) { this.removeListener(evt, listener.listener); } response = listener.listener.apply(this, args || []); if (response === this._getOnceReturnValue()) { this.removeListener(evt, listener.listener); } } } } return this; }; /** * Alias of emitEvent */ proto.trigger = alias('emitEvent'); /** * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. * * @param {String|RegExp} evt Name of the event to emit and execute listeners for. * @param {...*} Optional additional arguments to be passed to each listener. * @return {Object} Current instance of EventEmitter for chaining. */ proto.emit = function emit(evt) { var args = Array.prototype.slice.call(arguments, 1); return this.emitEvent(evt, args); }; /** * Sets the current value to check against when executing listeners. If a * listeners return value matches the one set here then it will be removed * after execution. This value defaults to true. * * @param {*} value The new value to check for when executing listeners. * @return {Object} Current instance of EventEmitter for chaining. */ proto.setOnceReturnValue = function setOnceReturnValue(value) { this._onceReturnValue = value; return this; }; /** * Fetches the current value to check against when executing listeners. If * the listeners return value matches this one then it should be removed * automatically. It will return true by default. * * @return {*|Boolean} The current value to check for or the default, true. * @api private */ proto._getOnceReturnValue = function _getOnceReturnValue() { if (this.hasOwnProperty('_onceReturnValue')) { return this._onceReturnValue; } else { return true; } }; /** * Fetches the events object and creates one if required. * * @return {Object} The events storage object. * @api private */ proto._getEvents = function _getEvents() { return this._events || (this._events = {}); }; /** * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. * * @return {Function} Non conflicting EventEmitter class. */ EventEmitter.noConflict = function noConflict() { exports.EventEmitter = originalGlobalValue; return EventEmitter; }; // Expose the class either via AMD, CommonJS or the global object if (typeof define === 'function' && define.amd) { define('eventEmitter/EventEmitter',[],function () { return EventEmitter; }); } else if (typeof module === 'object' && module.exports){ module.exports = EventEmitter; } else { this.EventEmitter = EventEmitter; } }.call(this)); /*! * eventie v1.0.4 * event binding helper * eventie.bind( elem, 'click', myFn ) * eventie.unbind( elem, 'click', myFn ) */ /*jshint browser: true, undef: true, unused: true */ /*global define: false */ ( function( window ) { var docElem = document.documentElement; var bind = function() {}; function getIEEvent( obj ) { var event = window.event; // add event.target event.target = event.target || event.srcElement || obj; return event; } if ( docElem.addEventListener ) { bind = function( obj, type, fn ) { obj.addEventListener( type, fn, false ); }; } else if ( docElem.attachEvent ) { bind = function( obj, type, fn ) { obj[ type + fn ] = fn.handleEvent ? function() { var event = getIEEvent( obj ); fn.handleEvent.call( fn, event ); } : function() { var event = getIEEvent( obj ); fn.call( obj, event ); }; obj.attachEvent( "on" + type, obj[ type + fn ] ); }; } var unbind = function() {}; if ( docElem.removeEventListener ) { unbind = function( obj, type, fn ) { obj.removeEventListener( type, fn, false ); }; } else if ( docElem.detachEvent ) { unbind = function( obj, type, fn ) { obj.detachEvent( "on" + type, obj[ type + fn ] ); try { delete obj[ type + fn ]; } catch ( err ) { // can't delete window object properties obj[ type + fn ] = undefined; } }; } var eventie = { bind: bind, unbind: unbind }; // transport if ( typeof define === 'function' && define.amd ) { // AMD define( 'eventie/eventie',eventie ); } else { // browser global window.eventie = eventie; } })( this ); /*! * imagesLoaded v3.1.8 * JavaScript is all like "You images are done yet or what?" * MIT License */ ( function( window, factory ) { // universal module definition /*global define: false, module: false, require: false */ if ( typeof define === 'function' && define.amd ) { // AMD define( [ 'eventEmitter/EventEmitter', 'eventie/eventie' ], function( EventEmitter, eventie ) { return factory( window, EventEmitter, eventie ); }); } else if ( typeof exports === 'object' ) { // CommonJS module.exports = factory( window, require('wolfy87-eventemitter'), require('eventie') ); } else { // browser global window.imagesLoaded = factory( window, window.EventEmitter, window.eventie ); } })( window, // -------------------------- factory -------------------------- // function factory( window, EventEmitter, eventie ) { var $ = window.jQuery; var console = window.console; var hasConsole = typeof console !== 'undefined'; // -------------------------- helpers -------------------------- // // extend objects function extend( a, b ) { for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a; } var objToString = Object.prototype.toString; function isArray( obj ) { return objToString.call( obj ) === '[object Array]'; } // turn element or nodeList into an array function makeArray( obj ) { var ary = []; if ( isArray( obj ) ) { // use object if already an array ary = obj; } else if ( typeof obj.length === 'number' ) { // convert nodeList to array for ( var i=0, len = obj.length; i < len; i++ ) { ary.push( obj[i] ); } } else { // array of single index ary.push( obj ); } return ary; } // -------------------------- imagesLoaded -------------------------- // /** * @param {Array, Element, NodeList, String} elem * @param {Object or Function} options - if function, use as callback * @param {Function} onAlways - callback function */ function ImagesLoaded( elem, options, onAlways ) { // coerce ImagesLoaded() without new, to be new ImagesLoaded() if ( !( this instanceof ImagesLoaded ) ) { return new ImagesLoaded( elem, options ); } // use elem as selector string if ( typeof elem === 'string' ) { elem = document.querySelectorAll( elem ); } this.elements = makeArray( elem ); this.options = extend( {}, this.options ); if ( typeof options === 'function' ) { onAlways = options; } else { extend( this.options, options ); } if ( onAlways ) { this.on( 'always', onAlways ); } this.getImages(); if ( $ ) { // add jQuery Deferred object this.jqDeferred = new $.Deferred(); } // HACK check async to allow time to bind listeners var _this = this; setTimeout( function() { _this.check(); }); } ImagesLoaded.prototype = new EventEmitter(); ImagesLoaded.prototype.options = {}; ImagesLoaded.prototype.getImages = function() { this.images = []; // filter & find items if we have an item selector for ( var i=0, len = this.elements.length; i < len; i++ ) { var elem = this.elements[i]; // filter siblings if ( elem.nodeName === 'IMG' ) { this.addImage( elem ); } // find children // no non-element nodes, #143 var nodeType = elem.nodeType; if ( !nodeType || !( nodeType === 1 || nodeType === 9 || nodeType === 11 ) ) { continue; } var childElems = elem.querySelectorAll('img'); // concat childElems to filterFound array for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { var img = childElems[j]; this.addImage( img ); } } }; /** * @param {Image} img */ ImagesLoaded.prototype.addImage = function( img ) { var loadingImage = new LoadingImage( img ); this.images.push( loadingImage ); }; ImagesLoaded.prototype.check = function() { var _this = this; var checkedCount = 0; var length = this.images.length; this.hasAnyBroken = false; // complete if no images if ( !length ) { this.complete(); return; } function onConfirm( image, message ) { if ( _this.options.debug && hasConsole ) { console.log( 'confirm', image, message ); } _this.progress( image ); checkedCount++; if ( checkedCount === length ) { _this.complete(); } return true; // bind once } for ( var i=0; i < length; i++ ) { var loadingImage = this.images[i]; loadingImage.on( 'confirm', onConfirm ); loadingImage.check(); } }; ImagesLoaded.prototype.progress = function( image ) { this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; // HACK - Chrome triggers event before object properties have changed. #83 var _this = this; setTimeout( function() { _this.emit( 'progress', _this, image ); if ( _this.jqDeferred && _this.jqDeferred.notify ) { _this.jqDeferred.notify( _this, image ); } }); }; ImagesLoaded.prototype.complete = function() { var eventName = this.hasAnyBroken ? 'fail' : 'done'; this.isComplete = true; var _this = this; // HACK - another setTimeout so that confirm happens after progress setTimeout( function() { _this.emit( eventName, _this ); _this.emit( 'always', _this ); if ( _this.jqDeferred ) { var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; _this.jqDeferred[ jqMethod ]( _this ); } }); }; // -------------------------- jquery -------------------------- // if ( $ ) { $.fn.imagesLoaded = function( options, callback ) { var instance = new ImagesLoaded( this, options, callback ); return instance.jqDeferred.promise( $(this) ); }; } // -------------------------- -------------------------- // function LoadingImage( img ) { this.img = img; } LoadingImage.prototype = new EventEmitter(); LoadingImage.prototype.check = function() { // first check cached any previous images that have same src var resource = cache[ this.img.src ] || new Resource( this.img.src ); if ( resource.isConfirmed ) { this.confirm( resource.isLoaded, 'cached was confirmed' ); return; } // If complete is true and browser supports natural sizes, // try to check for image status manually. if ( this.img.complete && this.img.naturalWidth !== undefined ) { // report based on naturalWidth this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); return; } // If none of the checks above matched, simulate loading on detached element. var _this = this; resource.on( 'confirm', function( resrc, message ) { _this.confirm( resrc.isLoaded, message ); return true; }); resource.check(); }; LoadingImage.prototype.confirm = function( isLoaded, message ) { this.isLoaded = isLoaded; this.emit( 'confirm', this, message ); }; // -------------------------- Resource -------------------------- // // Resource checks each src, only once // separate class from LoadingImage to prevent memory leaks. See #115 var cache = {}; function Resource( src ) { this.src = src; // add to cache cache[ src ] = this; } Resource.prototype = new EventEmitter(); Resource.prototype.check = function() { // only trigger checking once if ( this.isChecked ) { return; } // simulate loading on detached element var proxyImage = new Image(); eventie.bind( proxyImage, 'load', this ); eventie.bind( proxyImage, 'error', this ); proxyImage.src = this.src; // set flag this.isChecked = true; }; // ----- events ----- // // trigger specified handler for event type Resource.prototype.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; Resource.prototype.onload = function( event ) { this.confirm( true, 'onload' ); this.unbindProxyEvents( event ); }; Resource.prototype.onerror = function( event ) { this.confirm( false, 'onerror' ); this.unbindProxyEvents( event ); }; // ----- confirm ----- // Resource.prototype.confirm = function( isLoaded, message ) { this.isConfirmed = true; this.isLoaded = isLoaded; this.emit( 'confirm', this, message ); }; Resource.prototype.unbindProxyEvents = function( event ) { eventie.unbind( event.target, 'load', this ); eventie.unbind( event.target, 'error', this ); }; // ----- ----- // return ImagesLoaded; }); // 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; } } }()); /** * Interaction for the location module * * @author Tijs Verkoyen */ jsFrontend.location = { map: {}, mapFullUrl: null, directionService: null, directionsDisplay: null, // init, something like a constructor init: function() { if($('.parseMap').length > 0) { $('.parseMap').each(function() { var id = $(this).attr('id').replace('map', ''); google.maps.event.addDomListener(window, 'load', jsFrontend.location.initMap(id)); }); } }, // init the map initMap: function(id) { // define some variables we will need var suffix = (id == '') ? '' : '_' + id; var mapId = (id == '') ? 'general' : id; var theme = [ { "featureType": "administrative", "elementType": "labels.text.fill", "stylers": [ { "color": "#444444" } ] }, { "featureType": "landscape", "elementType": "all", "stylers": [ { "color": "#f2f2f2" } ] }, { "featureType": "poi", "elementType": "all", "stylers": [ { "visibility": "off" } ] }, { "featureType": "road", "elementType": "all", "stylers": [ { "saturation": -100 }, { "lightness": 45 } ] }, { "featureType": "road.highway", "elementType": "all", "stylers": [ { "visibility": "simplified" } ] }, { "featureType": "road.arterial", "elementType": "labels.icon", "stylers": [ { "visibility": "off" } ] }, { "featureType": "transit", "elementType": "all", "stylers": [ { "visibility": "off" } ] }, { "featureType": "water", "elementType": "all", "stylers": [ { "color": "#8ba8bc" }, { "visibility": "on" } ] } ]; // build the options var options = { zoom: (jsFrontend.data.get('Location.settings' + suffix + '.zoom_level') == 'auto') ? 0 : parseInt(jsFrontend.data.get('Location.settings' + suffix + '.zoom_level')), center: new google.maps.LatLng(jsFrontend.data.get('Location.settings' + suffix + '.center.lat'), jsFrontend.data.get('Location.settings' + suffix + '.center.lng')), mapTypeId: google.maps.MapTypeId[jsFrontend.data.get('Location.settings' + suffix + '.map_type')], draggable: Modernizr.touch ? false : true, scrollwheel: false, styles: theme }; // create map jsFrontend.location.map[mapId] = new google.maps.Map(document.getElementById('map' + id), options); // get the items var items = jsFrontend.data.get('Location.items' + suffix); // any items if(items.length > 0) { // loop items for(var i in items) { // add markers jsFrontend.location.addMarker(mapId, items[i].id, items[i].lat, items[i].lng, items[i].title); } } // are directions enabled? if(jsFrontend.data.get('Location.settings' + suffix + '.directions')) { // create direction variables if needed if(jsFrontend.location.directionsService == null) jsFrontend.location.directionsService = new google.maps.DirectionsService(); if(jsFrontend.location.directionsDisplay == null) jsFrontend.location.directionsDisplay = new google.maps.DirectionsRenderer(); // bind events $('#locationSearch' + id + ' form').on('submit', function(e) { // prevent default e.preventDefault(); // calculate & display the route jsFrontend.location.setRoute(id, mapId, items[0]); }); } if($('#map-full-url-' + id).length > 0) { jsFrontend.location.mapFullUrl = $('#map-full-url-' + id).attr('href'); } }, // add a marker addMarker: function(mapId, id, lat, lng, title) { // add the marker var marker = new google.maps.Marker( { position: new google.maps.LatLng(lat, lng), map: jsFrontend.location.map[mapId], title: title, locationId: id, icon: '/src/Frontend/Themes/Soda/Core/Layout/Images/Modules/Location/solid-pin-black.png' } ); // show info window on click google.maps.event.addListener(marker, 'click', function() { $markerText = $('#markerText' + marker.locationId); // apparently JS goes bananas with multi line HTMl, so we grab it from the div, this seems like a good idea for SEO if($markerText.length > 0) text = $markerText.html(); var content = '

      ' + title + '

      '; if(typeof text != 'undefined') content += text; new google.maps.InfoWindow( { content: content } ).open(jsFrontend.location.map[mapId], marker); }); }, // calculate the route setRoute: function(id, mapId, item) { $error = $('#locationSearchAddress' + id); $search = $('#locationSearchAddress' + id); // validate if($search.val() == '') $error.addClass('input-error'); else $error.removeClass('input-error'); // build the position var position = new google.maps.LatLng(item.lat, item.lng); // build request var request = { origin: $search.val(), destination: position, travelMode: google.maps.DirectionsTravelMode.DRIVING }; // request the route jsFrontend.location.directionsService.route(request, function(response, status) { // did we find a route if(status == google.maps.DirectionsStatus.OK) { // change the map jsFrontend.location.directionsDisplay.setMap(jsFrontend.location.map[mapId]); // render the route jsFrontend.location.directionsDisplay.setDirections(response); // change the link if (jsFrontend.location.mapFullUrl != null) { // get "a"-link element var $item = $('#map-full-url-' + id); // d = directions var href = jsFrontend.location.mapFullUrl + '&f=d&saddr=' + $search.val() + '&daddr=' + position; // update href $item.attr('href', href); } } // show error else $error.addClass('input-error'); }); } }; $(jsFrontend.location.init); $(window).load(function() { $('.js-photogallery-lightbox').each(function() { var $this = $(this); var lightboxId = $this.data('id'); var lightboxSettings = jsFrontend.data.get('Photogallery.lightbox_settings_' + lightboxId); var show_close_button = lightboxSettings.show_close_button == 'true'; var show_arrows = lightboxSettings.show_arrows == 'true'; var show_caption = lightboxSettings.show_caption == 'true'; var caption_type = lightboxSettings.caption_type; var padding = parseInt(lightboxSettings.padding); var margin = parseInt(lightboxSettings.margin); var modal = lightboxSettings.modal == 'true'; var close_click = lightboxSettings.close_click == 'true'; var media_helper = lightboxSettings.media_helper == 'true'; var show_hover_icon = lightboxSettings.show_hover_icon == 'true'; var navigation_effect = lightboxSettings.navigation_effect; var open_effect = lightboxSettings.open_effect; var close_effect = lightboxSettings.close_effect; var play_speed = parseInt(lightboxSettings.play_speed); var loop = lightboxSettings.loop == 'true'; var show_thumbnails = lightboxSettings.show_thumbnails == 'true'; var thumbnails_position = lightboxSettings.thumbnails_position; var thumbnail_navigation_width = parseInt(lightboxSettings.thumbnail_navigation_width); var thumbnail_navigation_height = parseInt(lightboxSettings.thumbnail_navigation_height); var show_overlay = lightboxSettings.show_overlay == 'true'; var overlay_color = lightboxSettings.overlay_color; var fancybox = $('a.fancybox', this); var h = {}; if(show_hover_icon) { //fancybox.addClass('linkOverlay').linkIcon({background:{css:{'opacity': 0.65}}}); } if(show_thumbnails) { h.thumbs = { width: thumbnail_navigation_width, height: thumbnail_navigation_height, position: thumbnails_position }; } if(show_overlay) { h.overlay = { css: {'background': overlay_color } }; } else { h.overlay = null; } if(media_helper) { h.media = {}; } if(show_caption) { h.title = { type: caption_type }; } else { h.title = null; } fancybox.fancybox({ nextEffect: navigation_effect, prevEffect: navigation_effect, openEffect: open_effect, closeEffect: close_effect, closeBtn: show_close_button, playSpeed: play_speed, loop: loop, arrows: show_arrows, closeClick: close_click, modal: modal, padding: padding, margin: margin, tpl: { closeBtn : '', next : '', prev : '' }, helpers: h, beforeShow: function() { // Get rich titles var currentElement = this.element; var next = $(currentElement).next(); if(next.length && next.hasClass('photogallery-lightbox-caption')) this.title = next.html(); // Disable right click $.fancybox.wrap.bind("contextmenu", function (e) { return false; }); } }); var imageId = utils.url.getGetValue('{$actLightboxImage}'); if(imageId) $this.find("a[data-image-id=" + imageId + "]").trigger('click'); }); }); $(window).load(function() { $('.js-photogallery-slideshow-wrapper').each(function() { var $this = $(this); var slideshowId = $this.data('id'); var slideshowSettings = jsFrontend.data.get('Photogallery.slideshow_settings_' + slideshowId); var controlNav = slideshowSettings.show_pagination == 'true'; var controlType = slideshowSettings.pagination_type; var controlTypeIsThumbnails = (controlType == 'thumbnails'); var slideshow = true; var animationLoop = true; var sync = ''; var randomize = slideshowSettings.random == 'true'; var directionNav = slideshowSettings.show_arrows == 'true'; var slider = '#photogallery-flexslider-id-' + slideshowId; var pauseOnHover = slideshowSettings.pause_on_hover == 'true'; var animation = slideshowSettings.animation; var slideshow_item_width = parseInt(slideshowSettings.slideshow_item_width); if(jQuery.type(slideshow_item_width) == 'number') { if( slideshow_item_width > 0) animation = 'slide'; } if(controlTypeIsThumbnails) { controlNav = false; slideshow = false; animationLoop = false; sync = '#photogallery-flexslider-navigation-id-' + slideshowId; randomize = false; directionNav = directionNav; pauseOnHover = false; $(sync).flexslider({ animation: "slide", controlNav: controlNav, animationLoop: animationLoop, slideshow: slideshow, itemWidth: 150, itemMargin: 5, asNavFor: slider }); } $(slider).flexslider({ slideshowSpeed: slideshowSettings.slideshow_speed, animationSpeed: slideshowSettings.animation_speed, randomize: randomize, pauseOnHover: pauseOnHover, directionNav: directionNav, controlNav: controlNav, sync: sync, animationLoop: animationLoop, slideshow: slideshow, animation: animation, itemWidth: slideshow_item_width }); }) }); var jsSite = { // init, something like a constructor init: function() { $('body').addClass('js'); $('a.page-id-1495').addClass('js-target-blank'); $('a.notification-close').click(function(e) { $('.notification').hide(); e.preventDefault(); }) jsSite.controls.init(); jsSite.contentFixes.init(); jsSite.forms.init(); jsSite.navigation.init(); } } jsSite.controls = { // init, something like a constructor init: function() { jsSite.controls.bindTargetBlank(); }, // bind target blank bindTargetBlank: function() { $('a.js-target-blank').attr('target', '_blank'); } } jsSite.contentFixes = { // init, something like a constructor init: function() { jsSite.contentFixes.equalHeights(); }, equalHeights: function() { if($('.js-equal-heights').length > 0) { imagesLoaded( '.js-equal-heights', function() { $('.js-equal-heights').equalHeights(); }); $(window).on("debouncedresize", function( event ) { $('.js-equal-heights').equalHeights(); }); } } } jsSite.forms = { // init, something like a constructor init: function() { jsSite.forms.bindFocus(); jsSite.forms.bindSubmit(); jsSite.forms.bindSubmitAjaxCM(); }, bindSubmit: function() { $('.js-submit-form').click(function(){ $(this).closest('form').submit(); return false; }); }, bindSubmitAjaxCM: function() { console.log($('.js-ajax-cm')); $('.js-ajax-cm').submit(function(e){ e.preventDefault(); var emailField = $(this).find('input[type=email]'); var label = $("label[for='"+ emailField.attr('id') +"']"); emailField.parent().removeClass('errorArea'); $.getJSON( this.action + "?callback=?", $(this).serialize(), function (data) { if (data.Status === 400) { label.find('span').remove(); emailField.parent().addClass('errorArea'); label.append($( "" + jsFrontend.locale.err('EmailIsInvalid') + "" )) } else { emailField.parent().removeClass('errorArea'); label.find('span').remove(); } } ); }); }, bindFocus: function() { $('.js-focus').first().focus(); $('.js-focus-on-first').find("input:text, textarea").first().focus(); } } jsSite.navigation = { // init, something like a constructor init: function() { jsSite.navigation.responsive(); jsSite.navigation.tabs(); }, tabs: function(){ var hash = window.location.hash; if(hash.indexOf('#tab-') != -1){ var tab = hash.slice(1); var target = $('.tab-content[data-tab-name=' + tab + ']'); if(target.length > 0){ $('.tab-content.tab-selected').removeClass('tab-selected'); target.addClass('tab-selected'); $('.js-tab').closest('li').parent().find('li.selected').removeClass('selected'); $('.js-tab[data-tab-name=' + tab + ']').closest('li').addClass('selected'); } } $('.js-tab').click(function(){ var t = $(this).data('tab-name'); $(this).closest('li').parent().find('li.selected').removeClass('selected'); $(this).closest('li').addClass('selected'); $('.tab-content.tab-selected').removeClass('tab-selected'); $('.tab-content[data-tab-name=' + t + ']').addClass('tab-selected'); window.location.hash = t; return false; }) }, responsive: function() { var $navigationContainer = $('.navigation-wrapper__mobile'), $toggle = $('.js-toggle'); $toggle.click(function() { $toggle.closest('.page-header__navigation-mobile-toggle').toggleClass('is-expanded'); $navigationContainer.toggleClass('is-expanded'); return false; }); } } $(jsSite.init);