14448 lines
488 KiB
JavaScript
14448 lines
488 KiB
JavaScript
/*!
|
|
* jQuery.appear
|
|
* https://github.com/bas2k/jquery.appear/
|
|
* http://code.google.com/p/jquery-appear/
|
|
*
|
|
* Copyright (c) 2009 Michael Hixson
|
|
* Copyright (c) 2012 Alexander Brovikov
|
|
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
|
|
*/
|
|
(function($) {
|
|
$.fn.appear = function(fn, options) {
|
|
|
|
var settings = $.extend({
|
|
|
|
//arbitrary data to pass to fn
|
|
data: undefined,
|
|
|
|
//call fn only on the first appear?
|
|
one: true,
|
|
|
|
// X & Y accuracy
|
|
accX: 0,
|
|
accY: 0
|
|
|
|
}, options);
|
|
|
|
return this.each(function() {
|
|
|
|
var t = $(this);
|
|
|
|
//whether the element is currently visible
|
|
t.appeared = false;
|
|
|
|
if (!fn) {
|
|
|
|
//trigger the custom event
|
|
t.trigger('appear', settings.data);
|
|
return;
|
|
}
|
|
|
|
var w = $(window);
|
|
|
|
//fires the appear event when appropriate
|
|
var check = function() {
|
|
|
|
//is the element hidden?
|
|
if (!t.is(':visible')) {
|
|
|
|
//it became hidden
|
|
t.appeared = false;
|
|
return;
|
|
}
|
|
|
|
//is the element inside the visible window?
|
|
var a = w.scrollLeft();
|
|
var b = w.scrollTop();
|
|
var o = t.offset();
|
|
var x = o.left;
|
|
var y = o.top;
|
|
|
|
var ax = settings.accX;
|
|
var ay = settings.accY;
|
|
var th = t.height();
|
|
var wh = w.height();
|
|
var tw = t.width();
|
|
var ww = w.width();
|
|
|
|
if (y + th + ay >= b &&
|
|
y <= b + wh + ay &&
|
|
x + tw + ax >= a &&
|
|
x <= a + ww + ax) {
|
|
|
|
//trigger the custom event
|
|
if (!t.appeared) t.trigger('appear', settings.data);
|
|
|
|
} else {
|
|
|
|
//it scrolled out of view
|
|
t.appeared = false;
|
|
}
|
|
};
|
|
|
|
//create a modified fn with some additional logic
|
|
var modifiedFn = function() {
|
|
|
|
//mark the element as visible
|
|
t.appeared = true;
|
|
|
|
//is this supposed to happen only once?
|
|
if (settings.one) {
|
|
|
|
//remove the check
|
|
w.unbind('scroll', check);
|
|
var i = $.inArray(check, $.fn.appear.checks);
|
|
if (i >= 0) $.fn.appear.checks.splice(i, 1);
|
|
}
|
|
|
|
//trigger the original fn
|
|
fn.apply(this, arguments);
|
|
};
|
|
|
|
//bind the modified fn to the element
|
|
if (settings.one) t.one('appear', settings.data, modifiedFn);
|
|
else t.bind('appear', settings.data, modifiedFn);
|
|
|
|
//check whenever the window scrolls
|
|
w.scroll(check);
|
|
|
|
//check whenever the dom changes
|
|
$.fn.appear.checks.push(check);
|
|
|
|
//check now
|
|
(check)();
|
|
});
|
|
};
|
|
|
|
//keep a queue of appearance checks
|
|
$.extend($.fn.appear, {
|
|
|
|
checks: [],
|
|
timeout: null,
|
|
|
|
//process the queue
|
|
checkAll: function() {
|
|
var length = $.fn.appear.checks.length;
|
|
if (length > 0) while (length--) ($.fn.appear.checks[length])();
|
|
},
|
|
|
|
//check the queue asynchronously
|
|
run: function() {
|
|
if ($.fn.appear.timeout) clearTimeout($.fn.appear.timeout);
|
|
$.fn.appear.timeout = setTimeout($.fn.appear.checkAll, 20);
|
|
}
|
|
});
|
|
|
|
//run checks when these methods are called
|
|
$.each(['append', 'prepend', 'after', 'before', 'attr',
|
|
'removeAttr', 'addClass', 'removeClass', 'toggleClass',
|
|
'remove', 'css', 'show', 'hide'], function(i, n) {
|
|
var old = $.fn[n];
|
|
if (old) {
|
|
$.fn[n] = function() {
|
|
var r = old.apply(this, arguments);
|
|
$.fn.appear.run();
|
|
return r;
|
|
}
|
|
}
|
|
});
|
|
|
|
})(jQuery);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function($) {
|
|
$.fn.countTo = function(options) {
|
|
// merge the default plugin settings with the custom options
|
|
options = $.extend({}, $.fn.countTo.defaults, options || {});
|
|
|
|
// how many times to update the value, and how much to increment the value on each update
|
|
var loops = Math.ceil(options.speed / options.refreshInterval),
|
|
increment = (options.to - options.from) / loops;
|
|
|
|
return $(this).each(function() {
|
|
var _this = this,
|
|
loopCount = 0,
|
|
value = options.from,
|
|
interval = setInterval(updateTimer, options.refreshInterval);
|
|
|
|
function updateTimer() {
|
|
value += increment;
|
|
loopCount++;
|
|
$(_this).html(value.toFixed(options.decimals));
|
|
|
|
if (typeof(options.onUpdate) == 'function') {
|
|
options.onUpdate.call(_this, value);
|
|
}
|
|
|
|
if (loopCount >= loops) {
|
|
clearInterval(interval);
|
|
value = options.to;
|
|
|
|
if (typeof(options.onComplete) == 'function') {
|
|
options.onComplete.call(_this, value);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
$.fn.countTo.defaults = {
|
|
from: 0, // the number the element should start at
|
|
to: 100, // the number the element should end at
|
|
speed: 1000, // how long it should take to count between the target numbers
|
|
refreshInterval: 100, // how often the element should be updated
|
|
decimals: 0, // the number of decimal places to show
|
|
onUpdate: null, // callback method for every time the element is updated,
|
|
onComplete: null, // callback method for when the element finishes updating
|
|
};
|
|
})(jQuery);
|
|
/*!
|
|
* GMAP3 Plugin for jQuery
|
|
* Version : 6.0.0
|
|
* Date : 2014-04-25
|
|
* Author : DEMONTE Jean-Baptiste
|
|
* Contact : jbdemonte@gmail.com
|
|
* Web site : http://gmap3.net
|
|
* Licence : GPL v3 : http://www.gnu.org/licenses/gpl.html
|
|
*
|
|
* Copyright (c) 2010-2014 Jean-Baptiste DEMONTE
|
|
* All rights reserved.
|
|
*/
|
|
;(function ($, undef) {
|
|
|
|
var defaults, gm,
|
|
gId = 0,
|
|
isFunction = $.isFunction,
|
|
isArray = $.isArray;
|
|
|
|
function isObject(m) {
|
|
return typeof m === "object";
|
|
}
|
|
|
|
function isString(m) {
|
|
return typeof m === "string";
|
|
}
|
|
|
|
function isNumber(m) {
|
|
return typeof m === "number";
|
|
}
|
|
|
|
function isUndefined(m) {
|
|
return m === undef;
|
|
}
|
|
|
|
/**
|
|
* Initialize default values
|
|
* defaults are defined at first gmap3 call to pass the rails asset pipeline and jasmine while google library is not yet loaded
|
|
*/
|
|
function initDefaults() {
|
|
gm = google.maps;
|
|
if (!defaults) {
|
|
defaults = {
|
|
verbose: false,
|
|
queryLimit: {
|
|
attempt: 5,
|
|
delay: 250, // setTimeout(..., delay + random);
|
|
random: 250
|
|
},
|
|
classes: (function () {
|
|
var r = {};
|
|
$.each("Map Marker InfoWindow Circle Rectangle OverlayView StreetViewPanorama KmlLayer TrafficLayer BicyclingLayer GroundOverlay StyledMapType ImageMapType".split(" "), function (_, k) {
|
|
r[k] = gm[k];
|
|
});
|
|
return r;
|
|
}()),
|
|
map: {
|
|
mapTypeId : gm.MapTypeId.ROADMAP,
|
|
center: [46.578498, 2.457275],
|
|
zoom: 2
|
|
},
|
|
overlay: {
|
|
pane: "floatPane",
|
|
content: "",
|
|
offset: {
|
|
x: 0,
|
|
y: 0
|
|
}
|
|
},
|
|
geoloc: {
|
|
getCurrentPosition: {
|
|
maximumAge: 60000,
|
|
timeout: 5000
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Generate a new ID if not defined
|
|
* @param id {string} (optional)
|
|
* @param simulate {boolean} (optional)
|
|
* @returns {*}
|
|
*/
|
|
function globalId(id, simulate) {
|
|
return isUndefined(id) ? "gmap3_" + (simulate ? gId + 1 : ++gId) : id;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return true if current version of Google Maps is equal or above to these in parameter
|
|
* @param version {string} Minimal version required
|
|
* @return {Boolean}
|
|
*/
|
|
function googleVersionMin(version) {
|
|
var i,
|
|
gmVersion = gm.version.split(".");
|
|
version = version.split(".");
|
|
for (i = 0; i < gmVersion.length; i++) {
|
|
gmVersion[i] = parseInt(gmVersion[i], 10);
|
|
}
|
|
for (i = 0; i < version.length; i++) {
|
|
version[i] = parseInt(version[i], 10);
|
|
if (gmVersion.hasOwnProperty(i)) {
|
|
if (gmVersion[i] < version[i]) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* attach events from a container to a sender
|
|
* td[
|
|
* events => { eventName => function, }
|
|
* onces => { eventName => function, }
|
|
* data => mixed data
|
|
* ]
|
|
**/
|
|
function attachEvents($container, args, sender, id, senders) {
|
|
var td = args.td || {},
|
|
context = {
|
|
id: id,
|
|
data: td.data,
|
|
tag: td.tag
|
|
};
|
|
function bind(items, handler) {
|
|
if (items) {
|
|
$.each(items, function (name, f) {
|
|
var self = $container, fn = f;
|
|
if (isArray(f)) {
|
|
self = f[0];
|
|
fn = f[1];
|
|
}
|
|
handler(sender, name, function (event) {
|
|
fn.apply(self, [senders || sender, event, context]);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
bind(td.events, gm.event.addListener);
|
|
bind(td.onces, gm.event.addListenerOnce);
|
|
}
|
|
|
|
/**
|
|
* Extract keys from object
|
|
* @param obj {object}
|
|
* @returns {Array}
|
|
*/
|
|
function getKeys(obj) {
|
|
var k, keys = [];
|
|
for (k in obj) {
|
|
if (obj.hasOwnProperty(k)) {
|
|
keys.push(k);
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
/**
|
|
* copy a key content
|
|
**/
|
|
function copyKey(target, key) {
|
|
var i,
|
|
args = arguments;
|
|
for (i = 2; i < args.length; i++) {
|
|
if (key in args[i]) {
|
|
if (args[i].hasOwnProperty(key)) {
|
|
target[key] = args[i][key];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build a tuple
|
|
* @param args {object}
|
|
* @param value {object}
|
|
* @returns {object}
|
|
*/
|
|
function tuple(args, value) {
|
|
var k, i,
|
|
keys = ["data", "tag", "id", "events", "onces"],
|
|
td = {};
|
|
|
|
// "copy" the common data
|
|
if (args.td) {
|
|
for (k in args.td) {
|
|
if (args.td.hasOwnProperty(k)) {
|
|
if ((k !== "options") && (k !== "values")) {
|
|
td[k] = args.td[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// "copy" some specific keys from value first else args.td
|
|
for (i = 0; i < keys.length; i++) {
|
|
copyKey(td, keys[i], value, args.td);
|
|
}
|
|
|
|
// create an extended options
|
|
td.options = $.extend({}, args.opts || {}, value.options || {});
|
|
|
|
return td;
|
|
}
|
|
|
|
/**
|
|
* Log error
|
|
*/
|
|
function error() {
|
|
if (defaults.verbose) {
|
|
var i, err = [];
|
|
if (window.console && (isFunction(console.error))) {
|
|
for (i = 0; i < arguments.length; i++) {
|
|
err.push(arguments[i]);
|
|
}
|
|
console.error.apply(console, err);
|
|
} else {
|
|
err = "";
|
|
for (i = 0; i < arguments.length; i++) {
|
|
err += arguments[i].toString() + " ";
|
|
}
|
|
alert(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* return true if mixed is usable as number
|
|
**/
|
|
function numeric(mixed) {
|
|
return (isNumber(mixed) || isString(mixed)) && mixed !== "" && !isNaN(mixed);
|
|
}
|
|
|
|
/**
|
|
* convert data to array
|
|
**/
|
|
function array(mixed) {
|
|
var k, a = [];
|
|
if (!isUndefined(mixed)) {
|
|
if (isObject(mixed)) {
|
|
if (isNumber(mixed.length)) {
|
|
a = mixed;
|
|
} else {
|
|
for (k in mixed) {
|
|
a.push(mixed[k]);
|
|
}
|
|
}
|
|
} else {
|
|
a.push(mixed);
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* create a function to check a tag
|
|
*/
|
|
function ftag(tag) {
|
|
if (tag) {
|
|
if (isFunction(tag)) {
|
|
return tag;
|
|
}
|
|
tag = array(tag);
|
|
return function (val) {
|
|
var i;
|
|
if (isUndefined(val)) {
|
|
return false;
|
|
}
|
|
if (isObject(val)) {
|
|
for (i = 0; i < val.length; i++) {
|
|
if ($.inArray(val[i], tag) >= 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return $.inArray(val, tag) >= 0;
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* convert mixed [ lat, lng ] objet to gm.LatLng
|
|
**/
|
|
function toLatLng(mixed, emptyReturnMixed, noFlat) {
|
|
var empty = emptyReturnMixed ? mixed : null;
|
|
if (!mixed || (isString(mixed))) {
|
|
return empty;
|
|
}
|
|
// defined latLng
|
|
if (mixed.latLng) {
|
|
return toLatLng(mixed.latLng);
|
|
}
|
|
// gm.LatLng object
|
|
if (mixed instanceof gm.LatLng) {
|
|
return mixed;
|
|
}
|
|
// {lat:X, lng:Y} object
|
|
if (numeric(mixed.lat)) {
|
|
return new gm.LatLng(mixed.lat, mixed.lng);
|
|
}
|
|
// [X, Y] object
|
|
if (!noFlat && isArray(mixed)) {
|
|
if (!numeric(mixed[0]) || !numeric(mixed[1])) {
|
|
return empty;
|
|
}
|
|
return new gm.LatLng(mixed[0], mixed[1]);
|
|
}
|
|
return empty;
|
|
}
|
|
|
|
/**
|
|
* convert mixed [ sw, ne ] object by gm.LatLngBounds
|
|
**/
|
|
function toLatLngBounds(mixed) {
|
|
var ne, sw;
|
|
if (!mixed || mixed instanceof gm.LatLngBounds) {
|
|
return mixed || null;
|
|
}
|
|
if (isArray(mixed)) {
|
|
if (mixed.length === 2) {
|
|
ne = toLatLng(mixed[0]);
|
|
sw = toLatLng(mixed[1]);
|
|
} else if (mixed.length === 4) {
|
|
ne = toLatLng([mixed[0], mixed[1]]);
|
|
sw = toLatLng([mixed[2], mixed[3]]);
|
|
}
|
|
} else {
|
|
if (("ne" in mixed) && ("sw" in mixed)) {
|
|
ne = toLatLng(mixed.ne);
|
|
sw = toLatLng(mixed.sw);
|
|
} else if (("n" in mixed) && ("e" in mixed) && ("s" in mixed) && ("w" in mixed)) {
|
|
ne = toLatLng([mixed.n, mixed.e]);
|
|
sw = toLatLng([mixed.s, mixed.w]);
|
|
}
|
|
}
|
|
if (ne && sw) {
|
|
return new gm.LatLngBounds(sw, ne);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* resolveLatLng
|
|
**/
|
|
function resolveLatLng(ctx, method, runLatLng, args, attempt) {
|
|
var latLng = runLatLng ? toLatLng(args.td, false, true) : false,
|
|
conf = latLng ? {latLng: latLng} : (args.td.address ? (isString(args.td.address) ? {address: args.td.address} : args.td.address) : false),
|
|
cache = conf ? geocoderCache.get(conf) : false,
|
|
self = this;
|
|
if (conf) {
|
|
attempt = attempt || 0; // convert undefined to int
|
|
if (cache) {
|
|
args.latLng = cache.results[0].geometry.location;
|
|
args.results = cache.results;
|
|
args.status = cache.status;
|
|
method.apply(ctx, [args]);
|
|
} else {
|
|
if (conf.location) {
|
|
conf.location = toLatLng(conf.location);
|
|
}
|
|
if (conf.bounds) {
|
|
conf.bounds = toLatLngBounds(conf.bounds);
|
|
}
|
|
geocoder().geocode(
|
|
conf,
|
|
function (results, status) {
|
|
if (status === gm.GeocoderStatus.OK) {
|
|
geocoderCache.store(conf, {results: results, status: status});
|
|
args.latLng = results[0].geometry.location;
|
|
args.results = results;
|
|
args.status = status;
|
|
method.apply(ctx, [args]);
|
|
} else if ((status === gm.GeocoderStatus.OVER_QUERY_LIMIT) && (attempt < defaults.queryLimit.attempt)) {
|
|
setTimeout(
|
|
function () {
|
|
resolveLatLng.apply(self, [ctx, method, runLatLng, args, attempt + 1]);
|
|
},
|
|
defaults.queryLimit.delay + Math.floor(Math.random() * defaults.queryLimit.random)
|
|
);
|
|
} else {
|
|
error("geocode failed", status, conf);
|
|
args.latLng = args.results = false;
|
|
args.status = status;
|
|
method.apply(ctx, [args]);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
} else {
|
|
args.latLng = toLatLng(args.td, false, true);
|
|
method.apply(ctx, [args]);
|
|
}
|
|
}
|
|
|
|
function resolveAllLatLng(list, ctx, method, args) {
|
|
var self = this, i = -1;
|
|
|
|
function resolve() {
|
|
// look for next address to resolve
|
|
do {
|
|
i++;
|
|
} while ((i < list.length) && !("address" in list[i]));
|
|
|
|
// no address found, so run method
|
|
if (i >= list.length) {
|
|
method.apply(ctx, [args]);
|
|
return;
|
|
}
|
|
|
|
resolveLatLng(
|
|
self,
|
|
function (args) {
|
|
delete args.td;
|
|
$.extend(list[i], args);
|
|
resolve.apply(self, []); // resolve next (using apply avoid too much recursion)
|
|
},
|
|
true,
|
|
{td: list[i]}
|
|
);
|
|
}
|
|
resolve();
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* geolocalise the user and return a LatLng
|
|
**/
|
|
function geoloc(ctx, method, args) {
|
|
var is_echo = false; // sometime, a kind of echo appear, this trick will notice once the first call is run to ignore the next one
|
|
if (navigator && navigator.geolocation) {
|
|
navigator.geolocation.getCurrentPosition(
|
|
function (pos) {
|
|
if (!is_echo) {
|
|
is_echo = true;
|
|
args.latLng = new gm.LatLng(pos.coords.latitude, pos.coords.longitude);
|
|
method.apply(ctx, [args]);
|
|
}
|
|
},
|
|
function () {
|
|
if (!is_echo) {
|
|
is_echo = true;
|
|
args.latLng = false;
|
|
method.apply(ctx, [args]);
|
|
}
|
|
},
|
|
args.opts.getCurrentPosition
|
|
);
|
|
} else {
|
|
args.latLng = false;
|
|
method.apply(ctx, [args]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if get is a direct call
|
|
* it means :
|
|
* - get is the only key
|
|
* - get has no callback
|
|
* @param obj {Object} The request to check
|
|
* @return {Boolean}
|
|
*/
|
|
function isDirectGet(obj) {
|
|
var k,
|
|
result = false;
|
|
if (isObject(obj) && obj.hasOwnProperty("get")) {
|
|
for (k in obj) {
|
|
if (k !== "get") {
|
|
return false;
|
|
}
|
|
}
|
|
result = !obj.get.hasOwnProperty("callback");
|
|
}
|
|
return result;
|
|
}
|
|
var services = {},
|
|
geocoderCache = new GeocoderCache();
|
|
|
|
|
|
function geocoder(){
|
|
if (!services.geocoder) {
|
|
services.geocoder = new gm.Geocoder();
|
|
}
|
|
return services.geocoder;
|
|
}
|
|
/**
|
|
* Class GeocoderCache
|
|
* @constructor
|
|
*/
|
|
function GeocoderCache() {
|
|
var cache = [];
|
|
|
|
this.get = function (request) {
|
|
if (cache.length) {
|
|
var i, j, k, item, eq,
|
|
keys = getKeys(request);
|
|
for (i = 0; i < cache.length; i++) {
|
|
item = cache[i];
|
|
eq = keys.length === item.keys.length;
|
|
for (j = 0; (j < keys.length) && eq; j++) {
|
|
k = keys[j];
|
|
eq = k in item.request;
|
|
if (eq) {
|
|
if (isObject(request[k]) && ("equals" in request[k]) && isFunction(request[k])) {
|
|
eq = request[k].equals(item.request[k]);
|
|
} else {
|
|
eq = request[k] === item.request[k];
|
|
}
|
|
}
|
|
}
|
|
if (eq) {
|
|
return item.results;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.store = function (request, results) {
|
|
cache.push({request: request, keys: getKeys(request), results: results});
|
|
};
|
|
}
|
|
/**
|
|
* Class Stack
|
|
* @constructor
|
|
*/
|
|
function Stack() {
|
|
var st = [],
|
|
self = this;
|
|
|
|
self.empty = function () {
|
|
return !st.length;
|
|
};
|
|
|
|
self.add = function (v) {
|
|
st.push(v);
|
|
};
|
|
|
|
self.get = function () {
|
|
return st.length ? st[0] : false;
|
|
};
|
|
|
|
self.ack = function () {
|
|
st.shift();
|
|
};
|
|
}
|
|
/**
|
|
* Class Store
|
|
* @constructor
|
|
*/
|
|
function Store() {
|
|
var store = {}, // name => [id, ...]
|
|
objects = {}, // id => object
|
|
self = this;
|
|
|
|
function normalize(res) {
|
|
return {
|
|
id: res.id,
|
|
name: res.name,
|
|
object: res.obj,
|
|
tag: res.tag,
|
|
data: res.data
|
|
};
|
|
}
|
|
|
|
/**
|
|
* add a mixed to the store
|
|
**/
|
|
self.add = function (args, name, obj, sub) {
|
|
var td = args.td || {},
|
|
id = globalId(td.id);
|
|
if (!store[name]) {
|
|
store[name] = [];
|
|
}
|
|
if (id in objects) { // object already exists: remove it
|
|
self.clearById(id);
|
|
}
|
|
objects[id] = {obj: obj, sub: sub, name: name, id: id, tag: td.tag, data: td.data};
|
|
store[name].push(id);
|
|
return id;
|
|
};
|
|
|
|
/**
|
|
* return a stored object by its id
|
|
**/
|
|
self.getById = function (id, sub, full) {
|
|
var result = false;
|
|
if (id in objects) {
|
|
if (sub) {
|
|
result = objects[id].sub;
|
|
} else if (full) {
|
|
result = normalize(objects[id]);
|
|
} else {
|
|
result = objects[id].obj;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* return a stored value
|
|
**/
|
|
self.get = function (name, last, tag, full) {
|
|
var n, id, check = ftag(tag);
|
|
if (!store[name] || !store[name].length) {
|
|
return null;
|
|
}
|
|
n = store[name].length;
|
|
while (n) {
|
|
n--;
|
|
id = store[name][last ? n : store[name].length - n - 1];
|
|
if (id && objects[id]) {
|
|
if (check && !check(objects[id].tag)) {
|
|
continue;
|
|
}
|
|
return full ? normalize(objects[id]) : objects[id].obj;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* return all stored values
|
|
**/
|
|
self.all = function (name, tag, full) {
|
|
var result = [],
|
|
check = ftag(tag),
|
|
find = function (n) {
|
|
var i, id;
|
|
for (i = 0; i < store[n].length; i++) {
|
|
id = store[n][i];
|
|
if (id && objects[id]) {
|
|
if (check && !check(objects[id].tag)) {
|
|
continue;
|
|
}
|
|
result.push(full ? normalize(objects[id]) : objects[id].obj);
|
|
}
|
|
}
|
|
};
|
|
if (name in store) {
|
|
find(name);
|
|
} else if (isUndefined(name)) { // internal use only
|
|
for (name in store) {
|
|
find(name);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* hide and remove an object
|
|
**/
|
|
function rm(obj) {
|
|
// Google maps element
|
|
if (isFunction(obj.setMap)) {
|
|
obj.setMap(null);
|
|
}
|
|
// jQuery
|
|
if (isFunction(obj.remove)) {
|
|
obj.remove();
|
|
}
|
|
// internal (cluster)
|
|
if (isFunction(obj.free)) {
|
|
obj.free();
|
|
}
|
|
obj = null;
|
|
}
|
|
|
|
/**
|
|
* remove one object from the store
|
|
**/
|
|
self.rm = function (name, check, pop) {
|
|
var idx, id;
|
|
if (!store[name]) {
|
|
return false;
|
|
}
|
|
if (check) {
|
|
if (pop) {
|
|
for (idx = store[name].length - 1; idx >= 0; idx--) {
|
|
id = store[name][idx];
|
|
if (check(objects[id].tag)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (idx = 0; idx < store[name].length; idx++) {
|
|
id = store[name][idx];
|
|
if (check(objects[id].tag)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
idx = pop ? store[name].length - 1 : 0;
|
|
}
|
|
if (!(idx in store[name])) {
|
|
return false;
|
|
}
|
|
return self.clearById(store[name][idx], idx);
|
|
};
|
|
|
|
/**
|
|
* remove object from the store by its id
|
|
**/
|
|
self.clearById = function (id, idx) {
|
|
if (id in objects) {
|
|
var i, name = objects[id].name;
|
|
for (i = 0; isUndefined(idx) && i < store[name].length; i++) {
|
|
if (id === store[name][i]) {
|
|
idx = i;
|
|
}
|
|
}
|
|
rm(objects[id].obj);
|
|
if (objects[id].sub) {
|
|
rm(objects[id].sub);
|
|
}
|
|
delete objects[id];
|
|
store[name].splice(idx, 1);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* return an object from a container object in the store by its id
|
|
* ! for now, only cluster manage this feature
|
|
**/
|
|
self.objGetById = function (id) {
|
|
var result, idx;
|
|
if (store.clusterer) {
|
|
for (idx in store.clusterer) {
|
|
if ((result = objects[store.clusterer[idx]].obj.getById(id)) !== false) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* remove object from a container object in the store by its id
|
|
* ! for now, only cluster manage this feature
|
|
**/
|
|
self.objClearById = function (id) {
|
|
var idx;
|
|
if (store.clusterer) {
|
|
for (idx in store.clusterer) {
|
|
if (objects[store.clusterer[idx]].obj.clearById(id)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* remove objects from the store
|
|
**/
|
|
self.clear = function (list, last, first, tag) {
|
|
var k, i, name,
|
|
check = ftag(tag);
|
|
if (!list || !list.length) {
|
|
list = [];
|
|
for (k in store) {
|
|
list.push(k);
|
|
}
|
|
} else {
|
|
list = array(list);
|
|
}
|
|
for (i = 0; i < list.length; i++) {
|
|
name = list[i];
|
|
if (last) {
|
|
self.rm(name, check, true);
|
|
} else if (first) {
|
|
self.rm(name, check, false);
|
|
} else { // all
|
|
while (self.rm(name, check, false)) {
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* remove object from a container object in the store by its tags
|
|
* ! for now, only cluster manage this feature
|
|
**/
|
|
self.objClear = function (list, last, first, tag) {
|
|
var idx;
|
|
if (store.clusterer && ($.inArray("marker", list) >= 0 || !list.length)) {
|
|
for (idx in store.clusterer) {
|
|
objects[store.clusterer[idx]].obj.clear(last, first, tag);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
/**
|
|
* Class Task
|
|
* @param ctx
|
|
* @param onEnd
|
|
* @param td
|
|
* @constructor
|
|
*/
|
|
function Task(ctx, onEnd, td) {
|
|
var session = {},
|
|
self = this,
|
|
current,
|
|
resolve = {
|
|
latLng: { // function => bool (=> address = latLng)
|
|
map: false,
|
|
marker: false,
|
|
infowindow: false,
|
|
circle: false,
|
|
overlay: false,
|
|
getlatlng: false,
|
|
getmaxzoom: false,
|
|
getelevation: false,
|
|
streetviewpanorama: false,
|
|
getaddress: true
|
|
},
|
|
geoloc: {
|
|
getgeoloc: true
|
|
}
|
|
};
|
|
|
|
function unify(td) {
|
|
var result = {};
|
|
result[td] = {};
|
|
return result;
|
|
}
|
|
|
|
if (isString(td)) {
|
|
td = unify(td);
|
|
}
|
|
|
|
function next() {
|
|
var k;
|
|
for (k in td) {
|
|
if (td.hasOwnProperty(k) && !session.hasOwnProperty(k)) {
|
|
return k;
|
|
}
|
|
}
|
|
}
|
|
|
|
self.run = function () {
|
|
var k, opts;
|
|
while (k = next()) {
|
|
if (isFunction(ctx[k])) {
|
|
current = k;
|
|
opts = $.extend(true, {}, defaults[k] || {}, td[k].options || {});
|
|
if (k in resolve.latLng) {
|
|
if (td[k].values) {
|
|
resolveAllLatLng(td[k].values, ctx, ctx[k], {td: td[k], opts: opts, session: session});
|
|
} else {
|
|
resolveLatLng(ctx, ctx[k], resolve.latLng[k], {td: td[k], opts: opts, session: session});
|
|
}
|
|
} else if (k in resolve.geoloc) {
|
|
geoloc(ctx, ctx[k], {td: td[k], opts: opts, session: session});
|
|
} else {
|
|
ctx[k].apply(ctx, [{td: td[k], opts: opts, session: session}]);
|
|
}
|
|
return; // wait until ack
|
|
} else {
|
|
session[k] = null;
|
|
}
|
|
}
|
|
onEnd.apply(ctx, [td, session]);
|
|
};
|
|
|
|
self.ack = function(result){
|
|
session[current] = result;
|
|
self.run.apply(self, []);
|
|
};
|
|
}
|
|
|
|
function directionsService(){
|
|
if (!services.ds) {
|
|
services.ds = new gm.DirectionsService();
|
|
}
|
|
return services.ds;
|
|
}
|
|
|
|
function distanceMatrixService() {
|
|
if (!services.dms) {
|
|
services.dms = new gm.DistanceMatrixService();
|
|
}
|
|
return services.dms;
|
|
}
|
|
|
|
function maxZoomService() {
|
|
if (!services.mzs) {
|
|
services.mzs = new gm.MaxZoomService();
|
|
}
|
|
return services.mzs;
|
|
}
|
|
|
|
function elevationService() {
|
|
if (!services.es) {
|
|
services.es = new gm.ElevationService();
|
|
}
|
|
return services.es;
|
|
}
|
|
|
|
/**
|
|
* Usefull to get a projection
|
|
* => done in a function, to let dead-code analyser works without google library loaded
|
|
**/
|
|
function newEmptyOverlay(map, radius) {
|
|
function Overlay() {
|
|
var self = this;
|
|
self.onAdd = function () {};
|
|
self.onRemove = function () {};
|
|
self.draw = function () {};
|
|
return defaults.classes.OverlayView.apply(self, []);
|
|
}
|
|
Overlay.prototype = defaults.classes.OverlayView.prototype;
|
|
var obj = new Overlay();
|
|
obj.setMap(map);
|
|
return obj;
|
|
}
|
|
|
|
/**
|
|
* Class InternalClusterer
|
|
* This class manage clusters thanks to "td" objects
|
|
*
|
|
* Note:
|
|
* Individuals marker are created on the fly thanks to the td objects, they are
|
|
* first set to null to keep the indexes synchronised with the td list
|
|
* This is the "display" function, set by the gmap3 object, which uses theses data
|
|
* to create markers when clusters are not required
|
|
* To remove a marker, the objects are deleted and set not null in arrays
|
|
* markers[key]
|
|
* = null : marker exist but has not been displayed yet
|
|
* = false : marker has been removed
|
|
**/
|
|
function InternalClusterer($container, map, raw) {
|
|
var timer, projection,
|
|
ffilter, fdisplay, ferror, // callback function
|
|
updating = false,
|
|
updated = false,
|
|
redrawing = false,
|
|
ready = false,
|
|
enabled = true,
|
|
self = this,
|
|
events = [],
|
|
store = {}, // combin of index (id1-id2-...) => object
|
|
ids = {}, // unique id => index
|
|
idxs = {}, // index => unique id
|
|
markers = [], // index => marker
|
|
tds = [], // index => td or null if removed
|
|
values = [], // index => value
|
|
overlay = newEmptyOverlay(map, raw.radius);
|
|
|
|
main();
|
|
|
|
function prepareMarker(index) {
|
|
if (!markers[index]) {
|
|
delete tds[index].options.map;
|
|
markers[index] = new defaults.classes.Marker(tds[index].options);
|
|
attachEvents($container, {td: tds[index]}, markers[index], tds[index].id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* return a marker by its id, null if not yet displayed and false if no exist or removed
|
|
**/
|
|
self.getById = function (id) {
|
|
if (id in ids) {
|
|
prepareMarker(ids[id]);
|
|
return markers[ids[id]];
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* remove one object from the store
|
|
**/
|
|
self.rm = function (id) {
|
|
var index = ids[id];
|
|
if (markers[index]) { // can be null
|
|
markers[index].setMap(null);
|
|
}
|
|
delete markers[index];
|
|
markers[index] = false;
|
|
|
|
delete tds[index];
|
|
tds[index] = false;
|
|
|
|
delete values[index];
|
|
values[index] = false;
|
|
|
|
delete ids[id];
|
|
delete idxs[index];
|
|
updated = true;
|
|
};
|
|
|
|
/**
|
|
* remove a marker by its id
|
|
**/
|
|
self.clearById = function (id) {
|
|
if (id in ids){
|
|
self.rm(id);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* remove objects from the store
|
|
**/
|
|
self.clear = function (last, first, tag) {
|
|
var start, stop, step, index, i,
|
|
list = [],
|
|
check = ftag(tag);
|
|
if (last) {
|
|
start = tds.length - 1;
|
|
stop = -1;
|
|
step = -1;
|
|
} else {
|
|
start = 0;
|
|
stop = tds.length;
|
|
step = 1;
|
|
}
|
|
for (index = start; index !== stop; index += step) {
|
|
if (tds[index]) {
|
|
if (!check || check(tds[index].tag)) {
|
|
list.push(idxs[index]);
|
|
if (first || last) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < list.length; i++) {
|
|
self.rm(list[i]);
|
|
}
|
|
};
|
|
|
|
// add a "marker td" to the cluster
|
|
self.add = function (td, value) {
|
|
td.id = globalId(td.id);
|
|
self.clearById(td.id);
|
|
ids[td.id] = markers.length;
|
|
idxs[markers.length] = td.id;
|
|
markers.push(null); // null = marker not yet created / displayed
|
|
tds.push(td);
|
|
values.push(value);
|
|
updated = true;
|
|
};
|
|
|
|
// add a real marker to the cluster
|
|
self.addMarker = function (marker, td) {
|
|
td = td || {};
|
|
td.id = globalId(td.id);
|
|
self.clearById(td.id);
|
|
if (!td.options) {
|
|
td.options = {};
|
|
}
|
|
td.options.position = marker.getPosition();
|
|
attachEvents($container, {td: td}, marker, td.id);
|
|
ids[td.id] = markers.length;
|
|
idxs[markers.length] = td.id;
|
|
markers.push(marker);
|
|
tds.push(td);
|
|
values.push(td.data || {});
|
|
updated = true;
|
|
};
|
|
|
|
// return a "marker td" by its index
|
|
self.td = function (index) {
|
|
return tds[index];
|
|
};
|
|
|
|
// return a "marker value" by its index
|
|
self.value = function (index) {
|
|
return values[index];
|
|
};
|
|
|
|
// return a marker by its index
|
|
self.marker = function (index) {
|
|
if (index in markers) {
|
|
prepareMarker(index);
|
|
return markers[index];
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// return a marker by its index
|
|
self.markerIsSet = function (index) {
|
|
return Boolean(markers[index]);
|
|
};
|
|
|
|
// store a new marker instead if the default "false"
|
|
self.setMarker = function (index, marker) {
|
|
markers[index] = marker;
|
|
};
|
|
|
|
// link the visible overlay to the logical data (to hide overlays later)
|
|
self.store = function (cluster, obj, shadow) {
|
|
store[cluster.ref] = {obj: obj, shadow: shadow};
|
|
};
|
|
|
|
// free all objects
|
|
self.free = function () {
|
|
var i;
|
|
for(i = 0; i < events.length; i++) {
|
|
gm.event.removeListener(events[i]);
|
|
}
|
|
events = [];
|
|
|
|
$.each(store, function (key) {
|
|
flush(key);
|
|
});
|
|
store = {};
|
|
|
|
$.each(tds, function (i) {
|
|
tds[i] = null;
|
|
});
|
|
tds = [];
|
|
|
|
$.each(markers, function (i) {
|
|
if (markers[i]) { // false = removed
|
|
markers[i].setMap(null);
|
|
delete markers[i];
|
|
}
|
|
});
|
|
markers = [];
|
|
|
|
$.each(values, function (i) {
|
|
delete values[i];
|
|
});
|
|
values = [];
|
|
|
|
ids = {};
|
|
idxs = {};
|
|
};
|
|
|
|
// link the display function
|
|
self.filter = function (f) {
|
|
ffilter = f;
|
|
redraw();
|
|
};
|
|
|
|
// enable/disable the clustering feature
|
|
self.enable = function (value) {
|
|
if (enabled !== value) {
|
|
enabled = value;
|
|
redraw();
|
|
}
|
|
};
|
|
|
|
// link the display function
|
|
self.display = function (f) {
|
|
fdisplay = f;
|
|
};
|
|
|
|
// link the errorfunction
|
|
self.error = function (f) {
|
|
ferror = f;
|
|
};
|
|
|
|
// lock the redraw
|
|
self.beginUpdate = function () {
|
|
updating = true;
|
|
};
|
|
|
|
// unlock the redraw
|
|
self.endUpdate = function () {
|
|
updating = false;
|
|
if (updated) {
|
|
redraw();
|
|
}
|
|
};
|
|
|
|
// extends current bounds with internal markers
|
|
self.autofit = function (bounds) {
|
|
var i;
|
|
for (i = 0; i < tds.length; i++) {
|
|
if (tds[i]) {
|
|
bounds.extend(tds[i].options.position);
|
|
}
|
|
}
|
|
};
|
|
|
|
// bind events
|
|
function main() {
|
|
projection = overlay.getProjection();
|
|
if (!projection) {
|
|
setTimeout(function () { main.apply(self, []); }, 25);
|
|
return;
|
|
}
|
|
ready = true;
|
|
events.push(gm.event.addListener(map, "zoom_changed", delayRedraw));
|
|
events.push(gm.event.addListener(map, "bounds_changed", delayRedraw));
|
|
redraw();
|
|
}
|
|
|
|
// flush overlays
|
|
function flush(key) {
|
|
if (isObject(store[key])) { // is overlay
|
|
if (isFunction(store[key].obj.setMap)) {
|
|
store[key].obj.setMap(null);
|
|
}
|
|
if (isFunction(store[key].obj.remove)) {
|
|
store[key].obj.remove();
|
|
}
|
|
if (isFunction(store[key].shadow.remove)) {
|
|
store[key].obj.remove();
|
|
}
|
|
if (isFunction(store[key].shadow.setMap)) {
|
|
store[key].shadow.setMap(null);
|
|
}
|
|
delete store[key].obj;
|
|
delete store[key].shadow;
|
|
} else if (markers[key]) { // marker not removed
|
|
markers[key].setMap(null);
|
|
// don't remove the marker object, it may be displayed later
|
|
}
|
|
delete store[key];
|
|
}
|
|
|
|
/**
|
|
* return the distance between 2 latLng couple into meters
|
|
* Params :
|
|
* Lat1, Lng1, Lat2, Lng2
|
|
* LatLng1, Lat2, Lng2
|
|
* Lat1, Lng1, LatLng2
|
|
* LatLng1, LatLng2
|
|
**/
|
|
function distanceInMeter() {
|
|
var lat1, lat2, lng1, lng2, e, f, g, h,
|
|
cos = Math.cos,
|
|
sin = Math.sin,
|
|
args = arguments;
|
|
if (args[0] instanceof gm.LatLng) {
|
|
lat1 = args[0].lat();
|
|
lng1 = args[0].lng();
|
|
if (args[1] instanceof gm.LatLng) {
|
|
lat2 = args[1].lat();
|
|
lng2 = args[1].lng();
|
|
} else {
|
|
lat2 = args[1];
|
|
lng2 = args[2];
|
|
}
|
|
} else {
|
|
lat1 = args[0];
|
|
lng1 = args[1];
|
|
if (args[2] instanceof gm.LatLng) {
|
|
lat2 = args[2].lat();
|
|
lng2 = args[2].lng();
|
|
} else {
|
|
lat2 = args[2];
|
|
lng2 = args[3];
|
|
}
|
|
}
|
|
e = Math.PI * lat1 / 180;
|
|
f = Math.PI * lng1 / 180;
|
|
g = Math.PI * lat2 / 180;
|
|
h = Math.PI * lng2 / 180;
|
|
return 1000 * 6371 * Math.acos(Math.min(cos(e) * cos(g) * cos(f) * cos(h) + cos(e) * sin(f) * cos(g) * sin(h) + sin(e) * sin(g), 1));
|
|
}
|
|
|
|
// extend the visible bounds
|
|
function extendsMapBounds() {
|
|
var radius = distanceInMeter(map.getCenter(), map.getBounds().getNorthEast()),
|
|
circle = new gm.Circle({
|
|
center: map.getCenter(),
|
|
radius: 1.25 * radius // + 25%
|
|
});
|
|
return circle.getBounds();
|
|
}
|
|
|
|
// return an object where keys are store keys
|
|
function getStoreKeys() {
|
|
var k,
|
|
keys = {};
|
|
for (k in store) {
|
|
keys[k] = true;
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
// async the delay function
|
|
function delayRedraw() {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(redraw, 25);
|
|
}
|
|
|
|
// generate bounds extended by radius
|
|
function extendsBounds(latLng) {
|
|
var p = projection.fromLatLngToDivPixel(latLng),
|
|
ne = projection.fromDivPixelToLatLng(new gm.Point(p.x + raw.radius, p.y - raw.radius)),
|
|
sw = projection.fromDivPixelToLatLng(new gm.Point(p.x - raw.radius, p.y + raw.radius));
|
|
return new gm.LatLngBounds(sw, ne);
|
|
}
|
|
|
|
// run the clustering process and call the display function
|
|
function redraw() {
|
|
if (updating || redrawing || !ready) {
|
|
return;
|
|
}
|
|
|
|
var i, j, k, indexes, check = false, bounds, cluster, position, previous, lat, lng, loop,
|
|
keys = [],
|
|
used = {},
|
|
zoom = map.getZoom(),
|
|
forceDisabled = ("maxZoom" in raw) && (zoom > raw.maxZoom),
|
|
previousKeys = getStoreKeys();
|
|
|
|
// reset flag
|
|
updated = false;
|
|
|
|
if (zoom > 3) {
|
|
// extend the bounds of the visible map to manage clusters near the boundaries
|
|
bounds = extendsMapBounds();
|
|
|
|
// check contain only if boundaries are valid
|
|
check = bounds.getSouthWest().lng() < bounds.getNorthEast().lng();
|
|
}
|
|
|
|
// calculate positions of "visibles" markers (in extended bounds)
|
|
for (i = 0; i < tds.length; i++) {
|
|
if (tds[i] && (!check || bounds.contains(tds[i].options.position)) && (!ffilter || ffilter(values[i]))) {
|
|
keys.push(i);
|
|
}
|
|
}
|
|
|
|
// for each "visible" marker, search its neighbors to create a cluster
|
|
// we can't do a classical "for" loop, because, analysis can bypass a marker while focusing on cluster
|
|
while (1) {
|
|
i = 0;
|
|
while (used[i] && (i < keys.length)) { // look for the next marker not used
|
|
i++;
|
|
}
|
|
if (i === keys.length) {
|
|
break;
|
|
}
|
|
|
|
indexes = [];
|
|
|
|
if (enabled && !forceDisabled) {
|
|
loop = 10;
|
|
do {
|
|
previous = indexes;
|
|
indexes = [];
|
|
loop--;
|
|
|
|
if (previous.length) {
|
|
position = bounds.getCenter();
|
|
} else {
|
|
position = tds[keys[i]].options.position;
|
|
}
|
|
bounds = extendsBounds(position);
|
|
|
|
for (j = i; j < keys.length; j++) {
|
|
if (used[j]) {
|
|
continue;
|
|
}
|
|
if (bounds.contains(tds[keys[j]].options.position)) {
|
|
indexes.push(j);
|
|
}
|
|
}
|
|
} while ((previous.length < indexes.length) && (indexes.length > 1) && loop);
|
|
} else {
|
|
for (j = i; j < keys.length; j++) {
|
|
if (!used[j]) {
|
|
indexes.push(j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cluster = {indexes: [], ref: []};
|
|
lat = lng = 0;
|
|
for (k = 0; k < indexes.length; k++) {
|
|
used[indexes[k]] = true;
|
|
cluster.indexes.push(keys[indexes[k]]);
|
|
cluster.ref.push(keys[indexes[k]]);
|
|
lat += tds[keys[indexes[k]]].options.position.lat();
|
|
lng += tds[keys[indexes[k]]].options.position.lng();
|
|
}
|
|
lat /= indexes.length;
|
|
lng /= indexes.length;
|
|
cluster.latLng = new gm.LatLng(lat, lng);
|
|
|
|
cluster.ref = cluster.ref.join("-");
|
|
|
|
if (cluster.ref in previousKeys) { // cluster doesn't change
|
|
delete previousKeys[cluster.ref]; // remove this entry, these still in this array will be removed
|
|
} else { // cluster is new
|
|
if (indexes.length === 1) { // alone markers are not stored, so need to keep the key (else, will be displayed every time and marker will blink)
|
|
store[cluster.ref] = true;
|
|
}
|
|
fdisplay(cluster);
|
|
}
|
|
}
|
|
|
|
// flush the previous overlays which are not still used
|
|
$.each(previousKeys, function (key) {
|
|
flush(key);
|
|
});
|
|
redrawing = false;
|
|
}
|
|
}
|
|
/**
|
|
* Class Clusterer
|
|
* a facade with limited method for external use
|
|
**/
|
|
function Clusterer(id, internalClusterer) {
|
|
var self = this;
|
|
self.id = function () {
|
|
return id;
|
|
};
|
|
self.filter = function (f) {
|
|
internalClusterer.filter(f);
|
|
};
|
|
self.enable = function () {
|
|
internalClusterer.enable(true);
|
|
};
|
|
self.disable = function () {
|
|
internalClusterer.enable(false);
|
|
};
|
|
self.add = function (marker, td, lock) {
|
|
if (!lock) {
|
|
internalClusterer.beginUpdate();
|
|
}
|
|
internalClusterer.addMarker(marker, td);
|
|
if (!lock) {
|
|
internalClusterer.endUpdate();
|
|
}
|
|
};
|
|
self.getById = function (id) {
|
|
return internalClusterer.getById(id);
|
|
};
|
|
self.clearById = function (id, lock) {
|
|
var result;
|
|
if (!lock) {
|
|
internalClusterer.beginUpdate();
|
|
}
|
|
result = internalClusterer.clearById(id);
|
|
if (!lock) {
|
|
internalClusterer.endUpdate();
|
|
}
|
|
return result;
|
|
};
|
|
self.clear = function (last, first, tag, lock) {
|
|
if (!lock) {
|
|
internalClusterer.beginUpdate();
|
|
}
|
|
internalClusterer.clear(last, first, tag);
|
|
if (!lock) {
|
|
internalClusterer.endUpdate();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Class OverlayView
|
|
* @constructor
|
|
*/
|
|
function OverlayView(map, opts, latLng, $div) {
|
|
var self = this,
|
|
listeners = [];
|
|
|
|
defaults.classes.OverlayView.call(self);
|
|
self.setMap(map);
|
|
|
|
self.onAdd = function () {
|
|
var panes = self.getPanes();
|
|
if (opts.pane in panes) {
|
|
$(panes[opts.pane]).append($div);
|
|
}
|
|
$.each("dblclick click mouseover mousemove mouseout mouseup mousedown".split(" "), function (i, name) {
|
|
listeners.push(
|
|
gm.event.addDomListener($div[0], name, function (e) {
|
|
$.Event(e).stopPropagation();
|
|
gm.event.trigger(self, name, [e]);
|
|
self.draw();
|
|
})
|
|
);
|
|
});
|
|
listeners.push(
|
|
gm.event.addDomListener($div[0], "contextmenu", function (e) {
|
|
$.Event(e).stopPropagation();
|
|
gm.event.trigger(self, "rightclick", [e]);
|
|
self.draw();
|
|
})
|
|
);
|
|
};
|
|
|
|
self.getPosition = function () {
|
|
return latLng;
|
|
};
|
|
|
|
self.setPosition = function (newLatLng) {
|
|
latLng = newLatLng;
|
|
self.draw();
|
|
};
|
|
|
|
self.draw = function () {
|
|
var ps = self.getProjection().fromLatLngToDivPixel(latLng);
|
|
$div
|
|
.css("left", (ps.x + opts.offset.x) + "px")
|
|
.css("top", (ps.y + opts.offset.y) + "px");
|
|
};
|
|
|
|
self.onRemove = function () {
|
|
var i;
|
|
for (i = 0; i < listeners.length; i++) {
|
|
gm.event.removeListener(listeners[i]);
|
|
}
|
|
$div.remove();
|
|
};
|
|
|
|
self.hide = function () {
|
|
$div.hide();
|
|
};
|
|
|
|
self.show = function () {
|
|
$div.show();
|
|
};
|
|
|
|
self.toggle = function () {
|
|
if ($div) {
|
|
if ($div.is(":visible")) {
|
|
self.show();
|
|
} else {
|
|
self.hide();
|
|
}
|
|
}
|
|
};
|
|
|
|
self.toggleDOM = function () {
|
|
self.setMap(self.getMap() ? null : map);
|
|
};
|
|
|
|
self.getDOMElement = function () {
|
|
return $div[0];
|
|
};
|
|
}
|
|
|
|
function Gmap3($this) {
|
|
var self = this,
|
|
stack = new Stack(),
|
|
store = new Store(),
|
|
map = null,
|
|
task;
|
|
|
|
/**
|
|
* if not running, start next action in stack
|
|
**/
|
|
function run() {
|
|
if (!task && (task = stack.get())) {
|
|
task.run();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* called when action in finished, to acknoledge the current in stack and start next one
|
|
**/
|
|
function end() {
|
|
task = null;
|
|
stack.ack();
|
|
run.call(self); // restart to high level scope
|
|
}
|
|
|
|
//-----------------------------------------------------------------------//
|
|
// Tools
|
|
//-----------------------------------------------------------------------//
|
|
|
|
/**
|
|
* execute callback functions
|
|
**/
|
|
function callback(args) {
|
|
var params,
|
|
cb = args.td.callback;
|
|
if (cb) {
|
|
params = Array.prototype.slice.call(arguments, 1);
|
|
if (isFunction(cb)) {
|
|
cb.apply($this, params);
|
|
} else if (isArray(cb)) {
|
|
if (isFunction(cb[1])) {
|
|
cb[1].apply(cb[0], params);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* execute ending functions
|
|
**/
|
|
function manageEnd(args, obj, id) {
|
|
if (id) {
|
|
attachEvents($this, args, obj, id);
|
|
}
|
|
callback(args, obj);
|
|
task.ack(obj);
|
|
}
|
|
|
|
/**
|
|
* initialize the map if not yet initialized
|
|
**/
|
|
function newMap(latLng, args) {
|
|
args = args || {};
|
|
var opts = args.td && args.td.options ? args.td.options : 0;
|
|
if (map) {
|
|
if (opts) {
|
|
if (opts.center) {
|
|
opts.center = toLatLng(opts.center);
|
|
}
|
|
map.setOptions(opts);
|
|
}
|
|
} else {
|
|
opts = args.opts || $.extend(true, {}, defaults.map, opts || {});
|
|
opts.center = latLng || toLatLng(opts.center);
|
|
map = new defaults.classes.Map($this.get(0), opts);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* store actions to execute in a stack manager
|
|
**/
|
|
self._plan = function (list) {
|
|
var k;
|
|
for (k = 0; k < list.length; k++) {
|
|
stack.add(new Task(self, end, list[k]));
|
|
}
|
|
run();
|
|
};
|
|
|
|
/**
|
|
* Initialize gm.Map object
|
|
**/
|
|
self.map = function (args) {
|
|
newMap(args.latLng, args);
|
|
attachEvents($this, args, map);
|
|
manageEnd(args, map);
|
|
};
|
|
|
|
/**
|
|
* destroy an existing instance
|
|
**/
|
|
self.destroy = function (args) {
|
|
store.clear();
|
|
$this.empty();
|
|
if (map) {
|
|
map = null;
|
|
}
|
|
manageEnd(args, true);
|
|
};
|
|
|
|
/**
|
|
* add an overlay
|
|
**/
|
|
self.overlay = function (args, internal) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
args.td.values = [{latLng: args.latLng, options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
if (!OverlayView.__initialised) {
|
|
OverlayView.prototype = new defaults.classes.OverlayView();
|
|
OverlayView.__initialised = true;
|
|
}
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj, td = tuple(args, value),
|
|
$div = $(document.createElement("div")).css({
|
|
border: "none",
|
|
borderWidth: 0,
|
|
position: "absolute"
|
|
});
|
|
$div.append(td.options.content);
|
|
obj = new OverlayView(map, td.options, toLatLng(td) || toLatLng(value), $div);
|
|
objs.push(obj);
|
|
$div = null; // memory leak
|
|
if (!internal) {
|
|
id = store.add(args, "overlay", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
}
|
|
});
|
|
if (internal) {
|
|
return objs[0];
|
|
}
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
};
|
|
|
|
/**
|
|
* Create an InternalClusterer object
|
|
**/
|
|
function createClusterer(raw) {
|
|
var internalClusterer = new InternalClusterer($this, map, raw),
|
|
td = {},
|
|
styles = {},
|
|
thresholds = [],
|
|
isInt = /^[0-9]+$/,
|
|
calculator,
|
|
k;
|
|
|
|
for (k in raw) {
|
|
if (isInt.test(k)) {
|
|
thresholds.push(1 * k); // cast to int
|
|
styles[k] = raw[k];
|
|
styles[k].width = styles[k].width || 0;
|
|
styles[k].height = styles[k].height || 0;
|
|
} else {
|
|
td[k] = raw[k];
|
|
}
|
|
}
|
|
thresholds.sort(function (a, b) { return a > b; });
|
|
|
|
// external calculator
|
|
if (td.calculator) {
|
|
calculator = function (indexes) {
|
|
var data = [];
|
|
$.each(indexes, function (i, index) {
|
|
data.push(internalClusterer.value(index));
|
|
});
|
|
return td.calculator.apply($this, [data]);
|
|
};
|
|
} else {
|
|
calculator = function (indexes) {
|
|
return indexes.length;
|
|
};
|
|
}
|
|
|
|
// set error function
|
|
internalClusterer.error(function () {
|
|
error.apply(self, arguments);
|
|
});
|
|
|
|
// set display function
|
|
internalClusterer.display(function (cluster) {
|
|
var i, style, atd, obj, offset, shadow,
|
|
cnt = calculator(cluster.indexes);
|
|
|
|
// look for the style to use
|
|
if (raw.force || cnt > 1) {
|
|
for (i = 0; i < thresholds.length; i++) {
|
|
if (thresholds[i] <= cnt) {
|
|
style = styles[thresholds[i]];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (style) {
|
|
offset = style.offset || [-style.width/2, -style.height/2];
|
|
// create a custom overlay command
|
|
// nb: 2 extends are faster self a deeper extend
|
|
atd = $.extend({}, td);
|
|
atd.options = $.extend({
|
|
pane: "overlayLayer",
|
|
content: style.content ? style.content.replace("CLUSTER_COUNT", cnt) : "",
|
|
offset: {
|
|
x: ("x" in offset ? offset.x : offset[0]) || 0,
|
|
y: ("y" in offset ? offset.y : offset[1]) || 0
|
|
}
|
|
},
|
|
td.options || {});
|
|
|
|
obj = self.overlay({td: atd, opts: atd.options, latLng: toLatLng(cluster)}, true);
|
|
|
|
atd.options.pane = "floatShadow";
|
|
atd.options.content = $(document.createElement("div")).width(style.width + "px").height(style.height + "px").css({cursor: "pointer"});
|
|
shadow = self.overlay({td: atd, opts: atd.options, latLng: toLatLng(cluster)}, true);
|
|
|
|
// store data to the clusterer
|
|
td.data = {
|
|
latLng: toLatLng(cluster),
|
|
markers:[]
|
|
};
|
|
$.each(cluster.indexes, function(i, index){
|
|
td.data.markers.push(internalClusterer.value(index));
|
|
if (internalClusterer.markerIsSet(index)){
|
|
internalClusterer.marker(index).setMap(null);
|
|
}
|
|
});
|
|
attachEvents($this, {td: td}, shadow, undef, {main: obj, shadow: shadow});
|
|
internalClusterer.store(cluster, obj, shadow);
|
|
} else {
|
|
$.each(cluster.indexes, function (i, index) {
|
|
internalClusterer.marker(index).setMap(map);
|
|
});
|
|
}
|
|
});
|
|
|
|
return internalClusterer;
|
|
}
|
|
|
|
/**
|
|
* add a marker
|
|
**/
|
|
self.marker = function (args) {
|
|
var objs,
|
|
clusterer, internalClusterer,
|
|
multiple = "values" in args.td,
|
|
init = !map;
|
|
if (!multiple) {
|
|
args.opts.position = args.latLng || toLatLng(args.opts.position);
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
if (init) {
|
|
newMap();
|
|
}
|
|
if (args.td.cluster && !map.getBounds()) { // map not initialised => bounds not available : wait for map if clustering feature is required
|
|
gm.event.addListenerOnce(map, "bounds_changed", function () { self.marker.apply(self, [args]); });
|
|
return;
|
|
}
|
|
if (args.td.cluster) {
|
|
if (args.td.cluster instanceof Clusterer) {
|
|
clusterer = args.td.cluster;
|
|
internalClusterer = store.getById(clusterer.id(), true);
|
|
} else {
|
|
internalClusterer = createClusterer(args.td.cluster);
|
|
clusterer = new Clusterer(globalId(args.td.id, true), internalClusterer);
|
|
store.add(args, "clusterer", clusterer, internalClusterer);
|
|
}
|
|
internalClusterer.beginUpdate();
|
|
|
|
$.each(args.td.values, function (i, value) {
|
|
var td = tuple(args, value);
|
|
td.options.position = td.options.position ? toLatLng(td.options.position) : toLatLng(value);
|
|
if (td.options.position) {
|
|
td.options.map = map;
|
|
if (init) {
|
|
map.setCenter(td.options.position);
|
|
init = false;
|
|
}
|
|
internalClusterer.add(td, value);
|
|
}
|
|
});
|
|
|
|
internalClusterer.endUpdate();
|
|
manageEnd(args, clusterer);
|
|
|
|
} else {
|
|
objs = [];
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj,
|
|
td = tuple(args, value);
|
|
td.options.position = td.options.position ? toLatLng(td.options.position) : toLatLng(value);
|
|
if (td.options.position) {
|
|
td.options.map = map;
|
|
if (init) {
|
|
map.setCenter(td.options.position);
|
|
init = false;
|
|
}
|
|
obj = new defaults.classes.Marker(td.options);
|
|
objs.push(obj);
|
|
id = store.add({td: td}, "marker", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
}
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* return a route
|
|
**/
|
|
self.getroute = function (args) {
|
|
args.opts.origin = toLatLng(args.opts.origin, true);
|
|
args.opts.destination = toLatLng(args.opts.destination, true);
|
|
directionsService().route(
|
|
args.opts,
|
|
function (results, status) {
|
|
callback(args, status === gm.DirectionsStatus.OK ? results : false, status);
|
|
task.ack();
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* return the distance between an origin and a destination
|
|
*
|
|
**/
|
|
self.getdistance = function (args) {
|
|
var i;
|
|
args.opts.origins = array(args.opts.origins);
|
|
for (i = 0; i < args.opts.origins.length; i++) {
|
|
args.opts.origins[i] = toLatLng(args.opts.origins[i], true);
|
|
}
|
|
args.opts.destinations = array(args.opts.destinations);
|
|
for (i = 0; i < args.opts.destinations.length; i++) {
|
|
args.opts.destinations[i] = toLatLng(args.opts.destinations[i], true);
|
|
}
|
|
distanceMatrixService().getDistanceMatrix(
|
|
args.opts,
|
|
function (results, status) {
|
|
callback(args, status === gm.DistanceMatrixStatus.OK ? results : false, status);
|
|
task.ack();
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* add an infowindow
|
|
**/
|
|
self.infowindow = function (args) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
if (args.latLng) {
|
|
args.opts.position = args.latLng;
|
|
}
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj,
|
|
td = tuple(args, value);
|
|
td.options.position = td.options.position ? toLatLng(td.options.position) : toLatLng(value.latLng);
|
|
if (!map) {
|
|
newMap(td.options.position);
|
|
}
|
|
obj = new defaults.classes.InfoWindow(td.options);
|
|
if (obj && (isUndefined(td.open) || td.open)) {
|
|
if (multiple) {
|
|
obj.open(map, td.anchor || undef);
|
|
} else {
|
|
obj.open(map, td.anchor || (args.latLng ? undef : (args.session.marker ? args.session.marker : undef)));
|
|
}
|
|
}
|
|
objs.push(obj);
|
|
id = store.add({td: td}, "infowindow", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
};
|
|
|
|
/**
|
|
* add a circle
|
|
**/
|
|
self.circle = function (args) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
args.opts.center = args.latLng || toLatLng(args.opts.center);
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj,
|
|
td = tuple(args, value);
|
|
td.options.center = td.options.center ? toLatLng(td.options.center) : toLatLng(value);
|
|
if (!map) {
|
|
newMap(td.options.center);
|
|
}
|
|
td.options.map = map;
|
|
obj = new defaults.classes.Circle(td.options);
|
|
objs.push(obj);
|
|
id = store.add({td: td}, "circle", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
};
|
|
|
|
/**
|
|
* returns address structure from latlng
|
|
**/
|
|
self.getaddress = function (args) {
|
|
callback(args, args.results, args.status);
|
|
task.ack();
|
|
};
|
|
|
|
/**
|
|
* returns latlng from an address
|
|
**/
|
|
self.getlatlng = function (args) {
|
|
callback(args, args.results, args.status);
|
|
task.ack();
|
|
};
|
|
|
|
/**
|
|
* return the max zoom of a location
|
|
**/
|
|
self.getmaxzoom = function (args) {
|
|
maxZoomService().getMaxZoomAtLatLng(
|
|
args.latLng,
|
|
function (result) {
|
|
callback(args, result.status === gm.MaxZoomStatus.OK ? result.zoom : false, status);
|
|
task.ack();
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* return the elevation of a location
|
|
**/
|
|
self.getelevation = function (args) {
|
|
var i,
|
|
locations = [],
|
|
f = function (results, status) {
|
|
callback(args, status === gm.ElevationStatus.OK ? results : false, status);
|
|
task.ack();
|
|
};
|
|
|
|
if (args.latLng) {
|
|
locations.push(args.latLng);
|
|
} else {
|
|
locations = array(args.td.locations || []);
|
|
for (i = 0; i < locations.length; i++) {
|
|
locations[i] = toLatLng(locations[i]);
|
|
}
|
|
}
|
|
if (locations.length) {
|
|
elevationService().getElevationForLocations({locations: locations}, f);
|
|
} else {
|
|
if (args.td.path && args.td.path.length) {
|
|
for (i = 0; i < args.td.path.length; i++) {
|
|
locations.push(toLatLng(args.td.path[i]));
|
|
}
|
|
}
|
|
if (locations.length) {
|
|
elevationService().getElevationAlongPath({path: locations, samples:args.td.samples}, f);
|
|
} else {
|
|
task.ack();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* define defaults values
|
|
**/
|
|
self.defaults = function (args) {
|
|
$.each(args.td, function(name, value) {
|
|
if (isObject(defaults[name])) {
|
|
defaults[name] = $.extend({}, defaults[name], value);
|
|
} else {
|
|
defaults[name] = value;
|
|
}
|
|
});
|
|
task.ack(true);
|
|
};
|
|
|
|
/**
|
|
* add a rectangle
|
|
**/
|
|
self.rectangle = function (args) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj,
|
|
td = tuple(args, value);
|
|
td.options.bounds = td.options.bounds ? toLatLngBounds(td.options.bounds) : toLatLngBounds(value);
|
|
if (!map) {
|
|
newMap(td.options.bounds.getCenter());
|
|
}
|
|
td.options.map = map;
|
|
|
|
obj = new defaults.classes.Rectangle(td.options);
|
|
objs.push(obj);
|
|
id = store.add({td: td}, "rectangle", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
};
|
|
|
|
/**
|
|
* add a polygone / polyline
|
|
**/
|
|
function poly(args, poly, path) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
newMap();
|
|
$.each(args.td.values, function (_, value) {
|
|
var id, i, j, obj,
|
|
td = tuple(args, value);
|
|
if (td.options[path]) {
|
|
if (td.options[path][0][0] && isArray(td.options[path][0][0])) {
|
|
for (i = 0; i < td.options[path].length; i++) {
|
|
for (j = 0; j < td.options[path][i].length; j++) {
|
|
td.options[path][i][j] = toLatLng(td.options[path][i][j]);
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < td.options[path].length; i++) {
|
|
td.options[path][i] = toLatLng(td.options[path][i]);
|
|
}
|
|
}
|
|
}
|
|
td.options.map = map;
|
|
obj = new gm[poly](td.options);
|
|
objs.push(obj);
|
|
id = store.add({td: td}, poly.toLowerCase(), obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
}
|
|
|
|
self.polyline = function (args) {
|
|
poly(args, "Polyline", "path");
|
|
};
|
|
|
|
self.polygon = function (args) {
|
|
poly(args, "Polygon", "paths");
|
|
};
|
|
|
|
/**
|
|
* add a traffic layer
|
|
**/
|
|
self.trafficlayer = function (args) {
|
|
newMap();
|
|
var obj = store.get("trafficlayer");
|
|
if (!obj) {
|
|
obj = new defaults.classes.TrafficLayer();
|
|
obj.setMap(map);
|
|
store.add(args, "trafficlayer", obj);
|
|
}
|
|
manageEnd(args, obj);
|
|
};
|
|
|
|
/**
|
|
* add a bicycling layer
|
|
**/
|
|
self.bicyclinglayer = function (args) {
|
|
newMap();
|
|
var obj = store.get("bicyclinglayer");
|
|
if (!obj) {
|
|
obj = new defaults.classes.BicyclingLayer();
|
|
obj.setMap(map);
|
|
store.add(args, "bicyclinglayer", obj);
|
|
}
|
|
manageEnd(args, obj);
|
|
};
|
|
|
|
/**
|
|
* add a ground overlay
|
|
**/
|
|
self.groundoverlay = function (args) {
|
|
args.opts.bounds = toLatLngBounds(args.opts.bounds);
|
|
if (args.opts.bounds){
|
|
newMap(args.opts.bounds.getCenter());
|
|
}
|
|
var id,
|
|
obj = new defaults.classes.GroundOverlay(args.opts.url, args.opts.bounds, args.opts.opts);
|
|
obj.setMap(map);
|
|
id = store.add(args, "groundoverlay", obj);
|
|
manageEnd(args, obj, id);
|
|
};
|
|
|
|
/**
|
|
* set a streetview
|
|
**/
|
|
self.streetviewpanorama = function (args) {
|
|
if (!args.opts.opts) {
|
|
args.opts.opts = {};
|
|
}
|
|
if (args.latLng) {
|
|
args.opts.opts.position = args.latLng;
|
|
} else if (args.opts.opts.position) {
|
|
args.opts.opts.position = toLatLng(args.opts.opts.position);
|
|
}
|
|
if (args.td.divId) {
|
|
args.opts.container = document.getElementById(args.td.divId);
|
|
} else if (args.opts.container) {
|
|
args.opts.container = $(args.opts.container).get(0);
|
|
}
|
|
var id, obj = new defaults.classes.StreetViewPanorama(args.opts.container, args.opts.opts);
|
|
if (obj) {
|
|
map.setStreetView(obj);
|
|
}
|
|
id = store.add(args, "streetviewpanorama", obj);
|
|
manageEnd(args, obj, id);
|
|
};
|
|
|
|
self.kmllayer = function (args) {
|
|
var objs = [],
|
|
multiple = "values" in args.td;
|
|
if (!multiple) {
|
|
args.td.values = [{options: args.opts}];
|
|
}
|
|
if (!args.td.values.length) {
|
|
manageEnd(args, false);
|
|
return;
|
|
}
|
|
$.each(args.td.values, function (i, value) {
|
|
var id, obj, options,
|
|
td = tuple(args, value);
|
|
if (!map) {
|
|
newMap();
|
|
}
|
|
options = td.options;
|
|
// compatibility 5.0-
|
|
if (td.options.opts) {
|
|
options = td.options.opts;
|
|
if (td.options.url) {
|
|
options.url = td.options.url;
|
|
}
|
|
}
|
|
// -- end --
|
|
options.map = map;
|
|
if (googleVersionMin("3.10")) {
|
|
obj = new defaults.classes.KmlLayer(options);
|
|
} else {
|
|
obj = new defaults.classes.KmlLayer(options.url, options);
|
|
}
|
|
objs.push(obj);
|
|
id = store.add({td: td}, "kmllayer", obj);
|
|
attachEvents($this, {td: td}, obj, id);
|
|
});
|
|
manageEnd(args, multiple ? objs : objs[0]);
|
|
};
|
|
|
|
/**
|
|
* add a fix panel
|
|
**/
|
|
self.panel = function (args) {
|
|
newMap();
|
|
var id, $content,
|
|
x = 0,
|
|
y = 0,
|
|
$div = $(document.createElement("div"));
|
|
|
|
$div.css({
|
|
position: "absolute",
|
|
zIndex: 1000,
|
|
visibility: "hidden"
|
|
});
|
|
|
|
if (args.opts.content) {
|
|
$content = $(args.opts.content);
|
|
$div.append($content);
|
|
$this.first().prepend($div);
|
|
|
|
if (!isUndefined(args.opts.left)) {
|
|
x = args.opts.left;
|
|
} else if (!isUndefined(args.opts.right)) {
|
|
x = $this.width() - $content.width() - args.opts.right;
|
|
} else if (args.opts.center) {
|
|
x = ($this.width() - $content.width()) / 2;
|
|
}
|
|
|
|
if (!isUndefined(args.opts.top)) {
|
|
y = args.opts.top;
|
|
} else if (!isUndefined(args.opts.bottom)) {
|
|
y = $this.height() - $content.height() - args.opts.bottom;
|
|
} else if (args.opts.middle) {
|
|
y = ($this.height() - $content.height()) / 2
|
|
}
|
|
|
|
$div.css({
|
|
top: y,
|
|
left: x,
|
|
visibility: "visible"
|
|
});
|
|
}
|
|
|
|
id = store.add(args, "panel", $div);
|
|
manageEnd(args, $div, id);
|
|
$div = null; // memory leak
|
|
};
|
|
|
|
/**
|
|
* add a direction renderer
|
|
**/
|
|
self.directionsrenderer = function (args) {
|
|
args.opts.map = map;
|
|
var id,
|
|
obj = new gm.DirectionsRenderer(args.opts);
|
|
if (args.td.divId) {
|
|
obj.setPanel(document.getElementById(args.td.divId));
|
|
} else if (args.td.container) {
|
|
obj.setPanel($(args.td.container).get(0));
|
|
}
|
|
id = store.add(args, "directionsrenderer", obj);
|
|
manageEnd(args, obj, id);
|
|
};
|
|
|
|
/**
|
|
* returns latLng of the user
|
|
**/
|
|
self.getgeoloc = function (args) {
|
|
manageEnd(args, args.latLng);
|
|
};
|
|
|
|
/**
|
|
* add a style
|
|
**/
|
|
self.styledmaptype = function (args) {
|
|
newMap();
|
|
var obj = new defaults.classes.StyledMapType(args.td.styles, args.opts);
|
|
map.mapTypes.set(args.td.id, obj);
|
|
manageEnd(args, obj);
|
|
};
|
|
|
|
/**
|
|
* add an imageMapType
|
|
**/
|
|
self.imagemaptype = function (args) {
|
|
newMap();
|
|
var obj = new defaults.classes.ImageMapType(args.opts);
|
|
map.mapTypes.set(args.td.id, obj);
|
|
manageEnd(args, obj);
|
|
};
|
|
|
|
/**
|
|
* autofit a map using its overlays (markers, rectangles ...)
|
|
**/
|
|
self.autofit = function (args) {
|
|
var bounds = new gm.LatLngBounds();
|
|
$.each(store.all(), function (i, obj) {
|
|
if (obj.getPosition) {
|
|
bounds.extend(obj.getPosition());
|
|
} else if (obj.getBounds) {
|
|
bounds.extend(obj.getBounds().getNorthEast());
|
|
bounds.extend(obj.getBounds().getSouthWest());
|
|
} else if (obj.getPaths) {
|
|
obj.getPaths().forEach(function (path) {
|
|
path.forEach(function (latLng) {
|
|
bounds.extend(latLng);
|
|
});
|
|
});
|
|
} else if (obj.getPath) {
|
|
obj.getPath().forEach(function (latLng) {
|
|
bounds.extend(latLng);
|
|
});
|
|
} else if (obj.getCenter) {
|
|
bounds.extend(obj.getCenter());
|
|
} else if (typeof Clusterer === "function" && obj instanceof Clusterer) {
|
|
obj = store.getById(obj.id(), true);
|
|
if (obj) {
|
|
obj.autofit(bounds);
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!bounds.isEmpty() && (!map.getBounds() || !map.getBounds().equals(bounds))) {
|
|
if ("maxZoom" in args.td) {
|
|
// fitBouds Callback event => detect zoom level and check maxZoom
|
|
gm.event.addListenerOnce(
|
|
map,
|
|
"bounds_changed",
|
|
function () {
|
|
if (this.getZoom() > args.td.maxZoom) {
|
|
this.setZoom(args.td.maxZoom);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
map.fitBounds(bounds);
|
|
}
|
|
manageEnd(args, true);
|
|
};
|
|
|
|
/**
|
|
* remove objects from a map
|
|
**/
|
|
self.clear = function (args) {
|
|
if (isString(args.td)) {
|
|
if (store.clearById(args.td) || store.objClearById(args.td)) {
|
|
manageEnd(args, true);
|
|
return;
|
|
}
|
|
args.td = {name: args.td};
|
|
}
|
|
if (args.td.id) {
|
|
$.each(array(args.td.id), function (i, id) {
|
|
store.clearById(id) || store.objClearById(id);
|
|
});
|
|
} else {
|
|
store.clear(array(args.td.name), args.td.last, args.td.first, args.td.tag);
|
|
store.objClear(array(args.td.name), args.td.last, args.td.first, args.td.tag);
|
|
}
|
|
manageEnd(args, true);
|
|
};
|
|
|
|
/**
|
|
* return objects previously created
|
|
**/
|
|
self.get = function (args, direct, full) {
|
|
var name, res,
|
|
td = direct ? args : args.td;
|
|
if (!direct) {
|
|
full = td.full;
|
|
}
|
|
if (isString(td)) {
|
|
res = store.getById(td, false, full) || store.objGetById(td);
|
|
if (res === false) {
|
|
name = td;
|
|
td = {};
|
|
}
|
|
} else {
|
|
name = td.name;
|
|
}
|
|
if (name === "map") {
|
|
res = map;
|
|
}
|
|
if (!res) {
|
|
res = [];
|
|
if (td.id) {
|
|
$.each(array(td.id), function (i, id) {
|
|
res.push(store.getById(id, false, full) || store.objGetById(id));
|
|
});
|
|
if (!isArray(td.id)) {
|
|
res = res[0];
|
|
}
|
|
} else {
|
|
$.each(name ? array(name) : [undef], function (i, aName) {
|
|
var result;
|
|
if (td.first) {
|
|
result = store.get(aName, false, td.tag, full);
|
|
if (result) {
|
|
res.push(result);
|
|
}
|
|
} else if (td.all) {
|
|
$.each(store.all(aName, td.tag, full), function (i, result) {
|
|
res.push(result);
|
|
});
|
|
} else {
|
|
result = store.get(aName, true, td.tag, full);
|
|
if (result) {
|
|
res.push(result);
|
|
}
|
|
}
|
|
});
|
|
if (!td.all && !isArray(name)) {
|
|
res = res[0];
|
|
}
|
|
}
|
|
}
|
|
res = isArray(res) || !td.all ? res : [res];
|
|
if (direct) {
|
|
return res;
|
|
} else {
|
|
manageEnd(args, res);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* run a function on each items selected
|
|
**/
|
|
self.exec = function (args) {
|
|
$.each(array(args.td.func), function (i, func) {
|
|
$.each(self.get(args.td, true, args.td.hasOwnProperty("full") ? args.td.full : true), function (j, res) {
|
|
func.call($this, res);
|
|
});
|
|
});
|
|
manageEnd(args, true);
|
|
};
|
|
|
|
/**
|
|
* trigger events on the map
|
|
**/
|
|
self.trigger = function (args) {
|
|
if (isString(args.td)) {
|
|
gm.event.trigger(map, args.td);
|
|
} else {
|
|
var options = [map, args.td.eventName];
|
|
if (args.td.var_args) {
|
|
$.each(args.td.var_args, function (i, v) {
|
|
options.push(v);
|
|
});
|
|
}
|
|
gm.event.trigger.apply(gm.event, options);
|
|
}
|
|
callback(args);
|
|
task.ack();
|
|
};
|
|
}
|
|
|
|
$.fn.gmap3 = function () {
|
|
var i,
|
|
list = [],
|
|
empty = true,
|
|
results = [];
|
|
|
|
// init library
|
|
initDefaults();
|
|
|
|
// store all arguments in a td list
|
|
for (i = 0; i < arguments.length; i++) {
|
|
if (arguments[i]) {
|
|
list.push(arguments[i]);
|
|
}
|
|
}
|
|
|
|
// resolve empty call - run init
|
|
if (!list.length) {
|
|
list.push("map");
|
|
}
|
|
|
|
// loop on each jQuery object
|
|
$.each(this, function () {
|
|
var $this = $(this),
|
|
gmap3 = $this.data("gmap3");
|
|
empty = false;
|
|
if (!gmap3) {
|
|
gmap3 = new Gmap3($this);
|
|
$this.data("gmap3", gmap3);
|
|
}
|
|
if (list.length === 1 && (list[0] === "get" || isDirectGet(list[0]))) {
|
|
if (list[0] === "get") {
|
|
results.push(gmap3.get("map", true));
|
|
} else {
|
|
results.push(gmap3.get(list[0].get, true, list[0].get.full));
|
|
}
|
|
} else {
|
|
gmap3._plan(list);
|
|
}
|
|
});
|
|
|
|
// return for direct call only
|
|
if (results.length) {
|
|
if (results.length === 1) { // 1 css selector
|
|
return results[0];
|
|
}
|
|
return results;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
})(jQuery);
|
|
/*!
|
|
* imagesLoaded PACKAGED v3.0.2
|
|
* JavaScript is all like "You images are done yet or what?"
|
|
*/
|
|
|
|
/*!
|
|
* EventEmitter v4.1.0 - git.io/ee
|
|
* Oliver Caldwell
|
|
* MIT license
|
|
* @preserve
|
|
*/
|
|
|
|
(function (exports) {
|
|
// Place the script in strict mode
|
|
'use strict';
|
|
|
|
/**
|
|
* Class for managing events.
|
|
* Can be extended to provide event functionality in other classes.
|
|
*
|
|
* @class Manages event registering and emitting.
|
|
*/
|
|
function EventEmitter() {}
|
|
|
|
// Shortcuts to improve speed and size
|
|
|
|
// Easy access to the prototype
|
|
var proto = EventEmitter.prototype,
|
|
nativeIndexOf = Array.prototype.indexOf ? true : false;
|
|
|
|
/**
|
|
* Finds the index of the listener for the event in it's storage array.
|
|
*
|
|
* @param {Function} listener Method to look for.
|
|
* @param {Function[]} listeners Array of listeners to search through.
|
|
* @return {Number} Index of the specified listener, -1 if not found
|
|
* @api private
|
|
*/
|
|
function indexOfListener(listener, listeners) {
|
|
// Return the index via the native method if possible
|
|
if (nativeIndexOf) {
|
|
return listeners.indexOf(listener);
|
|
}
|
|
|
|
// There is no native method
|
|
// Use a manual loop to find the index
|
|
var i = listeners.length;
|
|
while (i--) {
|
|
// If the listener matches, return it's index
|
|
if (listeners[i] === listener) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// Default to returning -1
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Fetches the events object and creates one if required.
|
|
*
|
|
* @return {Object} The events storage object.
|
|
* @api private
|
|
*/
|
|
proto._getEvents = function () {
|
|
return this._events || (this._events = {});
|
|
};
|
|
|
|
/**
|
|
* 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 (evt) {
|
|
// Create a shortcut to the storage object
|
|
// Initialise it if it does not exists yet
|
|
var events = this._getEvents(),
|
|
response,
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* 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 (evt) {
|
|
var listeners = this.getListeners(evt),
|
|
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 (evt, listener) {
|
|
var listeners = this.getListenersAsObject(evt),
|
|
key;
|
|
|
|
for (key in listeners) {
|
|
if (listeners.hasOwnProperty(key) &&
|
|
indexOfListener(listener, listeners[key]) === -1) {
|
|
listeners[key].push(listener);
|
|
}
|
|
}
|
|
|
|
// Return the instance of EventEmitter to allow chaining
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Alias of addListener
|
|
*/
|
|
proto.on = proto.addListener;
|
|
|
|
/**
|
|
* 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 (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 (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 (evt, listener) {
|
|
var listeners = this.getListenersAsObject(evt),
|
|
index,
|
|
key;
|
|
|
|
for (key in listeners) {
|
|
if (listeners.hasOwnProperty(key)) {
|
|
index = indexOfListener(listener, listeners[key]);
|
|
|
|
if (index !== -1) {
|
|
listeners[key].splice(index, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the instance of EventEmitter to allow chaining
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Alias of removeListener
|
|
*/
|
|
proto.off = proto.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 (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 (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 (remove, evt, listeners) {
|
|
// Initialise any required variables
|
|
var i,
|
|
value,
|
|
single = remove ? this.removeListener : this.addListener,
|
|
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 the instance of EventEmitter to allow chaining
|
|
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 (evt) {
|
|
var type = typeof evt,
|
|
events = this._getEvents(),
|
|
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 the instance of EventEmitter to allow chaining
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* 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 (evt, args) {
|
|
var listeners = this.getListenersAsObject(evt),
|
|
i,
|
|
key,
|
|
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
|
|
response = args ? listeners[key][i].apply(null, args) : listeners[key][i]();
|
|
if (response === true) {
|
|
this.removeListener(evt, listeners[key][i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the instance of EventEmitter to allow chaining
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Alias of emitEvent
|
|
*/
|
|
proto.trigger = proto.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 (evt) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
return this.emitEvent(evt, args);
|
|
};
|
|
|
|
// Expose the class either via AMD or the global object
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(function () {
|
|
return EventEmitter;
|
|
});
|
|
}
|
|
else {
|
|
exports.EventEmitter = EventEmitter;
|
|
}
|
|
}(this));
|
|
/*!
|
|
* eventie v1.0.3
|
|
* 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 ) {
|
|
|
|
'use strict';
|
|
|
|
var docElem = document.documentElement;
|
|
|
|
var bind = function() {};
|
|
|
|
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 = window.event;
|
|
// add event.target
|
|
event.target = event.target || event.srcElement;
|
|
fn.handleEvent.call( fn, event );
|
|
} :
|
|
function() {
|
|
var event = window.event;
|
|
// add event.target
|
|
event.target = event.target || event.srcElement;
|
|
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 );
|
|
} else {
|
|
// browser global
|
|
window.eventie = eventie;
|
|
}
|
|
|
|
})( this );
|
|
|
|
/*!
|
|
* imagesLoaded v3.0.2
|
|
* JavaScript is all like "You images are done yet or what?"
|
|
*/
|
|
|
|
( function( window ) {
|
|
|
|
'use strict';
|
|
|
|
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;
|
|
}
|
|
|
|
// -------------------------- -------------------------- //
|
|
|
|
function defineImagesLoaded( EventEmitter, eventie ) {
|
|
|
|
/**
|
|
* @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
|
|
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;
|
|
this.emit( 'progress', this, image );
|
|
if ( this.jqDeferred ) {
|
|
this.jqDeferred.notify( this, image );
|
|
}
|
|
};
|
|
|
|
ImagesLoaded.prototype.complete = function() {
|
|
var eventName = this.hasAnyBroken ? 'fail' : 'done';
|
|
this.isComplete = true;
|
|
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) );
|
|
};
|
|
}
|
|
|
|
|
|
// -------------------------- -------------------------- //
|
|
|
|
var cache = {};
|
|
|
|
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 cached = cache[ this.img.src ];
|
|
if ( cached ) {
|
|
this.useCached( cached );
|
|
return;
|
|
}
|
|
// add this to cache
|
|
cache[ this.img.src ] = this;
|
|
|
|
// 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 proxyImage = this.proxyImage = new Image();
|
|
eventie.bind( proxyImage, 'load', this );
|
|
eventie.bind( proxyImage, 'error', this );
|
|
proxyImage.src = this.img.src;
|
|
};
|
|
|
|
LoadingImage.prototype.useCached = function( cached ) {
|
|
if ( cached.isConfirmed ) {
|
|
this.confirm( cached.isLoaded, 'cached was confirmed' );
|
|
} else {
|
|
var _this = this;
|
|
cached.on( 'confirm', function( image ) {
|
|
_this.confirm( image.isLoaded, 'cache emitted confirmed' );
|
|
return true; // bind once
|
|
});
|
|
}
|
|
};
|
|
|
|
LoadingImage.prototype.confirm = function( isLoaded, message ) {
|
|
this.isConfirmed = true;
|
|
this.isLoaded = isLoaded;
|
|
this.emit( 'confirm', this, message );
|
|
};
|
|
|
|
// trigger specified handler for event type
|
|
LoadingImage.prototype.handleEvent = function( event ) {
|
|
var method = 'on' + event.type;
|
|
if ( this[ method ] ) {
|
|
this[ method ]( event );
|
|
}
|
|
};
|
|
|
|
LoadingImage.prototype.onload = function() {
|
|
this.confirm( true, 'onload' );
|
|
this.unbindProxyEvents();
|
|
};
|
|
|
|
LoadingImage.prototype.onerror = function() {
|
|
this.confirm( false, 'onerror' );
|
|
this.unbindProxyEvents();
|
|
};
|
|
|
|
LoadingImage.prototype.unbindProxyEvents = function() {
|
|
eventie.unbind( this.proxyImage, 'load', this );
|
|
eventie.unbind( this.proxyImage, 'error', this );
|
|
};
|
|
|
|
// ----- ----- //
|
|
|
|
return ImagesLoaded;
|
|
}
|
|
|
|
// -------------------------- transport -------------------------- //
|
|
|
|
if ( typeof define === 'function' && define.amd ) {
|
|
// AMD
|
|
define( [
|
|
'eventEmitter',
|
|
'eventie'
|
|
],
|
|
defineImagesLoaded );
|
|
} else {
|
|
// browser global
|
|
window.imagesLoaded = defineImagesLoaded(
|
|
window.EventEmitter,
|
|
window.eventie
|
|
);
|
|
}
|
|
|
|
})( window );
|
|
/*!
|
|
* Isotope PACKAGED v3.0.6
|
|
*
|
|
* Licensed GPLv3 for open source use
|
|
* or Isotope Commercial License for commercial use
|
|
*
|
|
* https://isotope.metafizzy.co
|
|
* Copyright 2010-2018 Metafizzy
|
|
*/
|
|
|
|
!function(t,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("jquery")):t.jQueryBridget=e(t,t.jQuery)}(window,function(t,e){"use strict";function i(i,s,a){function u(t,e,o){var n,s="$()."+i+'("'+e+'")';return t.each(function(t,u){var h=a.data(u,i);if(!h)return void r(i+" not initialized. Cannot call methods, i.e. "+s);var d=h[e];if(!d||"_"==e.charAt(0))return void r(s+" is not a valid method");var l=d.apply(h,o);n=void 0===n?l:n}),void 0!==n?n:t}function h(t,e){t.each(function(t,o){var n=a.data(o,i);n?(n.option(e),n._init()):(n=new s(o,e),a.data(o,i,n))})}a=a||e||t.jQuery,a&&(s.prototype.option||(s.prototype.option=function(t){a.isPlainObject(t)&&(this.options=a.extend(!0,this.options,t))}),a.fn[i]=function(t){if("string"==typeof t){var e=n.call(arguments,1);return u(this,t,e)}return h(this,t),this},o(a))}function o(t){!t||t&&t.bridget||(t.bridget=i)}var n=Array.prototype.slice,s=t.console,r="undefined"==typeof s?function(){}:function(t){s.error(t)};return o(e||t.jQuery),i}),function(t,e){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",e):"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,function(){function t(){}var e=t.prototype;return e.on=function(t,e){if(t&&e){var i=this._events=this._events||{},o=i[t]=i[t]||[];return o.indexOf(e)==-1&&o.push(e),this}},e.once=function(t,e){if(t&&e){this.on(t,e);var i=this._onceEvents=this._onceEvents||{},o=i[t]=i[t]||{};return o[e]=!0,this}},e.off=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){var o=i.indexOf(e);return o!=-1&&i.splice(o,1),this}},e.emitEvent=function(t,e){var i=this._events&&this._events[t];if(i&&i.length){i=i.slice(0),e=e||[];for(var o=this._onceEvents&&this._onceEvents[t],n=0;n<i.length;n++){var s=i[n],r=o&&o[s];r&&(this.off(t,s),delete o[s]),s.apply(this,e)}return this}},e.allOff=function(){delete this._events,delete this._onceEvents},t}),function(t,e){"function"==typeof define&&define.amd?define("get-size/get-size",e):"object"==typeof module&&module.exports?module.exports=e():t.getSize=e()}(window,function(){"use strict";function t(t){var e=parseFloat(t),i=t.indexOf("%")==-1&&!isNaN(e);return i&&e}function e(){}function i(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},e=0;e<h;e++){var i=u[e];t[i]=0}return t}function o(t){var e=getComputedStyle(t);return e||a("Style returned "+e+". Are you running this code in a hidden iframe on Firefox? See https://bit.ly/getsizebug1"),e}function n(){if(!d){d=!0;var e=document.createElement("div");e.style.width="200px",e.style.padding="1px 2px 3px 4px",e.style.borderStyle="solid",e.style.borderWidth="1px 2px 3px 4px",e.style.boxSizing="border-box";var i=document.body||document.documentElement;i.appendChild(e);var n=o(e);r=200==Math.round(t(n.width)),s.isBoxSizeOuter=r,i.removeChild(e)}}function s(e){if(n(),"string"==typeof e&&(e=document.querySelector(e)),e&&"object"==typeof e&&e.nodeType){var s=o(e);if("none"==s.display)return i();var a={};a.width=e.offsetWidth,a.height=e.offsetHeight;for(var d=a.isBorderBox="border-box"==s.boxSizing,l=0;l<h;l++){var f=u[l],c=s[f],m=parseFloat(c);a[f]=isNaN(m)?0:m}var p=a.paddingLeft+a.paddingRight,y=a.paddingTop+a.paddingBottom,g=a.marginLeft+a.marginRight,v=a.marginTop+a.marginBottom,_=a.borderLeftWidth+a.borderRightWidth,z=a.borderTopWidth+a.borderBottomWidth,I=d&&r,x=t(s.width);x!==!1&&(a.width=x+(I?0:p+_));var S=t(s.height);return S!==!1&&(a.height=S+(I?0:y+z)),a.innerWidth=a.width-(p+_),a.innerHeight=a.height-(y+z),a.outerWidth=a.width+g,a.outerHeight=a.height+v,a}}var r,a="undefined"==typeof console?e:function(t){console.error(t)},u=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],h=u.length,d=!1;return s}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("desandro-matches-selector/matches-selector",e):"object"==typeof module&&module.exports?module.exports=e():t.matchesSelector=e()}(window,function(){"use strict";var t=function(){var t=window.Element.prototype;if(t.matches)return"matches";if(t.matchesSelector)return"matchesSelector";for(var e=["webkit","moz","ms","o"],i=0;i<e.length;i++){var o=e[i],n=o+"MatchesSelector";if(t[n])return n}}();return function(e,i){return e[t](i)}}),function(t,e){"function"==typeof define&&define.amd?define("fizzy-ui-utils/utils",["desandro-matches-selector/matches-selector"],function(i){return e(t,i)}):"object"==typeof module&&module.exports?module.exports=e(t,require("desandro-matches-selector")):t.fizzyUIUtils=e(t,t.matchesSelector)}(window,function(t,e){var i={};i.extend=function(t,e){for(var i in e)t[i]=e[i];return t},i.modulo=function(t,e){return(t%e+e)%e};var o=Array.prototype.slice;i.makeArray=function(t){if(Array.isArray(t))return t;if(null===t||void 0===t)return[];var e="object"==typeof t&&"number"==typeof t.length;return e?o.call(t):[t]},i.removeFrom=function(t,e){var i=t.indexOf(e);i!=-1&&t.splice(i,1)},i.getParent=function(t,i){for(;t.parentNode&&t!=document.body;)if(t=t.parentNode,e(t,i))return t},i.getQueryElement=function(t){return"string"==typeof t?document.querySelector(t):t},i.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},i.filterFindElements=function(t,o){t=i.makeArray(t);var n=[];return t.forEach(function(t){if(t instanceof HTMLElement){if(!o)return void n.push(t);e(t,o)&&n.push(t);for(var i=t.querySelectorAll(o),s=0;s<i.length;s++)n.push(i[s])}}),n},i.debounceMethod=function(t,e,i){i=i||100;var o=t.prototype[e],n=e+"Timeout";t.prototype[e]=function(){var t=this[n];clearTimeout(t);var e=arguments,s=this;this[n]=setTimeout(function(){o.apply(s,e),delete s[n]},i)}},i.docReady=function(t){var e=document.readyState;"complete"==e||"interactive"==e?setTimeout(t):document.addEventListener("DOMContentLoaded",t)},i.toDashed=function(t){return t.replace(/(.)([A-Z])/g,function(t,e,i){return e+"-"+i}).toLowerCase()};var n=t.console;return i.htmlInit=function(e,o){i.docReady(function(){var s=i.toDashed(o),r="data-"+s,a=document.querySelectorAll("["+r+"]"),u=document.querySelectorAll(".js-"+s),h=i.makeArray(a).concat(i.makeArray(u)),d=r+"-options",l=t.jQuery;h.forEach(function(t){var i,s=t.getAttribute(r)||t.getAttribute(d);try{i=s&&JSON.parse(s)}catch(a){return void(n&&n.error("Error parsing "+r+" on "+t.className+": "+a))}var u=new e(t,i);l&&l.data(t,o,u)})})},i}),function(t,e){"function"==typeof define&&define.amd?define("outlayer/item",["ev-emitter/ev-emitter","get-size/get-size"],e):"object"==typeof module&&module.exports?module.exports=e(require("ev-emitter"),require("get-size")):(t.Outlayer={},t.Outlayer.Item=e(t.EvEmitter,t.getSize))}(window,function(t,e){"use strict";function i(t){for(var e in t)return!1;return e=null,!0}function o(t,e){t&&(this.element=t,this.layout=e,this.position={x:0,y:0},this._create())}function n(t){return t.replace(/([A-Z])/g,function(t){return"-"+t.toLowerCase()})}var s=document.documentElement.style,r="string"==typeof s.transition?"transition":"WebkitTransition",a="string"==typeof s.transform?"transform":"WebkitTransform",u={WebkitTransition:"webkitTransitionEnd",transition:"transitionend"}[r],h={transform:a,transition:r,transitionDuration:r+"Duration",transitionProperty:r+"Property",transitionDelay:r+"Delay"},d=o.prototype=Object.create(t.prototype);d.constructor=o,d._create=function(){this._transn={ingProperties:{},clean:{},onEnd:{}},this.css({position:"absolute"})},d.handleEvent=function(t){var e="on"+t.type;this[e]&&this[e](t)},d.getSize=function(){this.size=e(this.element)},d.css=function(t){var e=this.element.style;for(var i in t){var o=h[i]||i;e[o]=t[i]}},d.getPosition=function(){var t=getComputedStyle(this.element),e=this.layout._getOption("originLeft"),i=this.layout._getOption("originTop"),o=t[e?"left":"right"],n=t[i?"top":"bottom"],s=parseFloat(o),r=parseFloat(n),a=this.layout.size;o.indexOf("%")!=-1&&(s=s/100*a.width),n.indexOf("%")!=-1&&(r=r/100*a.height),s=isNaN(s)?0:s,r=isNaN(r)?0:r,s-=e?a.paddingLeft:a.paddingRight,r-=i?a.paddingTop:a.paddingBottom,this.position.x=s,this.position.y=r},d.layoutPosition=function(){var t=this.layout.size,e={},i=this.layout._getOption("originLeft"),o=this.layout._getOption("originTop"),n=i?"paddingLeft":"paddingRight",s=i?"left":"right",r=i?"right":"left",a=this.position.x+t[n];e[s]=this.getXValue(a),e[r]="";var u=o?"paddingTop":"paddingBottom",h=o?"top":"bottom",d=o?"bottom":"top",l=this.position.y+t[u];e[h]=this.getYValue(l),e[d]="",this.css(e),this.emitEvent("layout",[this])},d.getXValue=function(t){var e=this.layout._getOption("horizontal");return this.layout.options.percentPosition&&!e?t/this.layout.size.width*100+"%":t+"px"},d.getYValue=function(t){var e=this.layout._getOption("horizontal");return this.layout.options.percentPosition&&e?t/this.layout.size.height*100+"%":t+"px"},d._transitionTo=function(t,e){this.getPosition();var i=this.position.x,o=this.position.y,n=t==this.position.x&&e==this.position.y;if(this.setPosition(t,e),n&&!this.isTransitioning)return void this.layoutPosition();var s=t-i,r=e-o,a={};a.transform=this.getTranslate(s,r),this.transition({to:a,onTransitionEnd:{transform:this.layoutPosition},isCleaning:!0})},d.getTranslate=function(t,e){var i=this.layout._getOption("originLeft"),o=this.layout._getOption("originTop");return t=i?t:-t,e=o?e:-e,"translate3d("+t+"px, "+e+"px, 0)"},d.goTo=function(t,e){this.setPosition(t,e),this.layoutPosition()},d.moveTo=d._transitionTo,d.setPosition=function(t,e){this.position.x=parseFloat(t),this.position.y=parseFloat(e)},d._nonTransition=function(t){this.css(t.to),t.isCleaning&&this._removeStyles(t.to);for(var e in t.onTransitionEnd)t.onTransitionEnd[e].call(this)},d.transition=function(t){if(!parseFloat(this.layout.options.transitionDuration))return void this._nonTransition(t);var e=this._transn;for(var i in t.onTransitionEnd)e.onEnd[i]=t.onTransitionEnd[i];for(i in t.to)e.ingProperties[i]=!0,t.isCleaning&&(e.clean[i]=!0);if(t.from){this.css(t.from);var o=this.element.offsetHeight;o=null}this.enableTransition(t.to),this.css(t.to),this.isTransitioning=!0};var l="opacity,"+n(a);d.enableTransition=function(){if(!this.isTransitioning){var t=this.layout.options.transitionDuration;t="number"==typeof t?t+"ms":t,this.css({transitionProperty:l,transitionDuration:t,transitionDelay:this.staggerDelay||0}),this.element.addEventListener(u,this,!1)}},d.onwebkitTransitionEnd=function(t){this.ontransitionend(t)},d.onotransitionend=function(t){this.ontransitionend(t)};var f={"-webkit-transform":"transform"};d.ontransitionend=function(t){if(t.target===this.element){var e=this._transn,o=f[t.propertyName]||t.propertyName;if(delete e.ingProperties[o],i(e.ingProperties)&&this.disableTransition(),o in e.clean&&(this.element.style[t.propertyName]="",delete e.clean[o]),o in e.onEnd){var n=e.onEnd[o];n.call(this),delete e.onEnd[o]}this.emitEvent("transitionEnd",[this])}},d.disableTransition=function(){this.removeTransitionStyles(),this.element.removeEventListener(u,this,!1),this.isTransitioning=!1},d._removeStyles=function(t){var e={};for(var i in t)e[i]="";this.css(e)};var c={transitionProperty:"",transitionDuration:"",transitionDelay:""};return d.removeTransitionStyles=function(){this.css(c)},d.stagger=function(t){t=isNaN(t)?0:t,this.staggerDelay=t+"ms"},d.removeElem=function(){this.element.parentNode.removeChild(this.element),this.css({display:""}),this.emitEvent("remove",[this])},d.remove=function(){return r&&parseFloat(this.layout.options.transitionDuration)?(this.once("transitionEnd",function(){this.removeElem()}),void this.hide()):void this.removeElem()},d.reveal=function(){delete this.isHidden,this.css({display:""});var t=this.layout.options,e={},i=this.getHideRevealTransitionEndProperty("visibleStyle");e[i]=this.onRevealTransitionEnd,this.transition({from:t.hiddenStyle,to:t.visibleStyle,isCleaning:!0,onTransitionEnd:e})},d.onRevealTransitionEnd=function(){this.isHidden||this.emitEvent("reveal")},d.getHideRevealTransitionEndProperty=function(t){var e=this.layout.options[t];if(e.opacity)return"opacity";for(var i in e)return i},d.hide=function(){this.isHidden=!0,this.css({display:""});var t=this.layout.options,e={},i=this.getHideRevealTransitionEndProperty("hiddenStyle");e[i]=this.onHideTransitionEnd,this.transition({from:t.visibleStyle,to:t.hiddenStyle,isCleaning:!0,onTransitionEnd:e})},d.onHideTransitionEnd=function(){this.isHidden&&(this.css({display:"none"}),this.emitEvent("hide"))},d.destroy=function(){this.css({position:"",left:"",right:"",top:"",bottom:"",transition:"",transform:""})},o}),function(t,e){"use strict";"function"==typeof define&&define.amd?define("outlayer/outlayer",["ev-emitter/ev-emitter","get-size/get-size","fizzy-ui-utils/utils","./item"],function(i,o,n,s){return e(t,i,o,n,s)}):"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter"),require("get-size"),require("fizzy-ui-utils"),require("./item")):t.Outlayer=e(t,t.EvEmitter,t.getSize,t.fizzyUIUtils,t.Outlayer.Item)}(window,function(t,e,i,o,n){"use strict";function s(t,e){var i=o.getQueryElement(t);if(!i)return void(u&&u.error("Bad element for "+this.constructor.namespace+": "+(i||t)));this.element=i,h&&(this.$element=h(this.element)),this.options=o.extend({},this.constructor.defaults),this.option(e);var n=++l;this.element.outlayerGUID=n,f[n]=this,this._create();var s=this._getOption("initLayout");s&&this.layout()}function r(t){function e(){t.apply(this,arguments)}return e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e}function a(t){if("number"==typeof t)return t;var e=t.match(/(^\d*\.?\d*)(\w*)/),i=e&&e[1],o=e&&e[2];if(!i.length)return 0;i=parseFloat(i);var n=m[o]||1;return i*n}var u=t.console,h=t.jQuery,d=function(){},l=0,f={};s.namespace="outlayer",s.Item=n,s.defaults={containerStyle:{position:"relative"},initLayout:!0,originLeft:!0,originTop:!0,resize:!0,resizeContainer:!0,transitionDuration:"0.4s",hiddenStyle:{opacity:0,transform:"scale(0.001)"},visibleStyle:{opacity:1,transform:"scale(1)"}};var c=s.prototype;o.extend(c,e.prototype),c.option=function(t){o.extend(this.options,t)},c._getOption=function(t){var e=this.constructor.compatOptions[t];return e&&void 0!==this.options[e]?this.options[e]:this.options[t]},s.compatOptions={initLayout:"isInitLayout",horizontal:"isHorizontal",layoutInstant:"isLayoutInstant",originLeft:"isOriginLeft",originTop:"isOriginTop",resize:"isResizeBound",resizeContainer:"isResizingContainer"},c._create=function(){this.reloadItems(),this.stamps=[],this.stamp(this.options.stamp),o.extend(this.element.style,this.options.containerStyle);var t=this._getOption("resize");t&&this.bindResize()},c.reloadItems=function(){this.items=this._itemize(this.element.children)},c._itemize=function(t){for(var e=this._filterFindItemElements(t),i=this.constructor.Item,o=[],n=0;n<e.length;n++){var s=e[n],r=new i(s,this);o.push(r)}return o},c._filterFindItemElements=function(t){return o.filterFindElements(t,this.options.itemSelector)},c.getItemElements=function(){return this.items.map(function(t){return t.element})},c.layout=function(){this._resetLayout(),this._manageStamps();var t=this._getOption("layoutInstant"),e=void 0!==t?t:!this._isLayoutInited;this.layoutItems(this.items,e),this._isLayoutInited=!0},c._init=c.layout,c._resetLayout=function(){this.getSize()},c.getSize=function(){this.size=i(this.element)},c._getMeasurement=function(t,e){var o,n=this.options[t];n?("string"==typeof n?o=this.element.querySelector(n):n instanceof HTMLElement&&(o=n),this[t]=o?i(o)[e]:n):this[t]=0},c.layoutItems=function(t,e){t=this._getItemsForLayout(t),this._layoutItems(t,e),this._postLayout()},c._getItemsForLayout=function(t){return t.filter(function(t){return!t.isIgnored})},c._layoutItems=function(t,e){if(this._emitCompleteOnItems("layout",t),t&&t.length){var i=[];t.forEach(function(t){var o=this._getItemLayoutPosition(t);o.item=t,o.isInstant=e||t.isLayoutInstant,i.push(o)},this),this._processLayoutQueue(i)}},c._getItemLayoutPosition=function(){return{x:0,y:0}},c._processLayoutQueue=function(t){this.updateStagger(),t.forEach(function(t,e){this._positionItem(t.item,t.x,t.y,t.isInstant,e)},this)},c.updateStagger=function(){var t=this.options.stagger;return null===t||void 0===t?void(this.stagger=0):(this.stagger=a(t),this.stagger)},c._positionItem=function(t,e,i,o,n){o?t.goTo(e,i):(t.stagger(n*this.stagger),t.moveTo(e,i))},c._postLayout=function(){this.resizeContainer()},c.resizeContainer=function(){var t=this._getOption("resizeContainer");if(t){var e=this._getContainerSize();e&&(this._setContainerMeasure(e.width,!0),this._setContainerMeasure(e.height,!1))}},c._getContainerSize=d,c._setContainerMeasure=function(t,e){if(void 0!==t){var i=this.size;i.isBorderBox&&(t+=e?i.paddingLeft+i.paddingRight+i.borderLeftWidth+i.borderRightWidth:i.paddingBottom+i.paddingTop+i.borderTopWidth+i.borderBottomWidth),t=Math.max(t,0),this.element.style[e?"width":"height"]=t+"px"}},c._emitCompleteOnItems=function(t,e){function i(){n.dispatchEvent(t+"Complete",null,[e])}function o(){r++,r==s&&i()}var n=this,s=e.length;if(!e||!s)return void i();var r=0;e.forEach(function(e){e.once(t,o)})},c.dispatchEvent=function(t,e,i){var o=e?[e].concat(i):i;if(this.emitEvent(t,o),h)if(this.$element=this.$element||h(this.element),e){var n=h.Event(e);n.type=t,this.$element.trigger(n,i)}else this.$element.trigger(t,i)},c.ignore=function(t){var e=this.getItem(t);e&&(e.isIgnored=!0)},c.unignore=function(t){var e=this.getItem(t);e&&delete e.isIgnored},c.stamp=function(t){t=this._find(t),t&&(this.stamps=this.stamps.concat(t),t.forEach(this.ignore,this))},c.unstamp=function(t){t=this._find(t),t&&t.forEach(function(t){o.removeFrom(this.stamps,t),this.unignore(t)},this)},c._find=function(t){if(t)return"string"==typeof t&&(t=this.element.querySelectorAll(t)),t=o.makeArray(t)},c._manageStamps=function(){this.stamps&&this.stamps.length&&(this._getBoundingRect(),this.stamps.forEach(this._manageStamp,this))},c._getBoundingRect=function(){var t=this.element.getBoundingClientRect(),e=this.size;this._boundingRect={left:t.left+e.paddingLeft+e.borderLeftWidth,top:t.top+e.paddingTop+e.borderTopWidth,right:t.right-(e.paddingRight+e.borderRightWidth),bottom:t.bottom-(e.paddingBottom+e.borderBottomWidth)}},c._manageStamp=d,c._getElementOffset=function(t){var e=t.getBoundingClientRect(),o=this._boundingRect,n=i(t),s={left:e.left-o.left-n.marginLeft,top:e.top-o.top-n.marginTop,right:o.right-e.right-n.marginRight,bottom:o.bottom-e.bottom-n.marginBottom};return s},c.handleEvent=o.handleEvent,c.bindResize=function(){t.addEventListener("resize",this),this.isResizeBound=!0},c.unbindResize=function(){t.removeEventListener("resize",this),this.isResizeBound=!1},c.onresize=function(){this.resize()},o.debounceMethod(s,"onresize",100),c.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&this.layout()},c.needsResizeLayout=function(){var t=i(this.element),e=this.size&&t;return e&&t.innerWidth!==this.size.innerWidth},c.addItems=function(t){var e=this._itemize(t);return e.length&&(this.items=this.items.concat(e)),e},c.appended=function(t){var e=this.addItems(t);e.length&&(this.layoutItems(e,!0),this.reveal(e))},c.prepended=function(t){var e=this._itemize(t);if(e.length){var i=this.items.slice(0);this.items=e.concat(i),this._resetLayout(),this._manageStamps(),this.layoutItems(e,!0),this.reveal(e),this.layoutItems(i)}},c.reveal=function(t){if(this._emitCompleteOnItems("reveal",t),t&&t.length){var e=this.updateStagger();t.forEach(function(t,i){t.stagger(i*e),t.reveal()})}},c.hide=function(t){if(this._emitCompleteOnItems("hide",t),t&&t.length){var e=this.updateStagger();t.forEach(function(t,i){t.stagger(i*e),t.hide()})}},c.revealItemElements=function(t){var e=this.getItems(t);this.reveal(e)},c.hideItemElements=function(t){var e=this.getItems(t);this.hide(e)},c.getItem=function(t){for(var e=0;e<this.items.length;e++){var i=this.items[e];if(i.element==t)return i}},c.getItems=function(t){t=o.makeArray(t);var e=[];return t.forEach(function(t){var i=this.getItem(t);i&&e.push(i)},this),e},c.remove=function(t){var e=this.getItems(t);this._emitCompleteOnItems("remove",e),e&&e.length&&e.forEach(function(t){t.remove(),o.removeFrom(this.items,t)},this)},c.destroy=function(){var t=this.element.style;t.height="",t.position="",t.width="",this.items.forEach(function(t){t.destroy()}),this.unbindResize();var e=this.element.outlayerGUID;delete f[e],delete this.element.outlayerGUID,h&&h.removeData(this.element,this.constructor.namespace)},s.data=function(t){t=o.getQueryElement(t);var e=t&&t.outlayerGUID;return e&&f[e]},s.create=function(t,e){var i=r(s);return i.defaults=o.extend({},s.defaults),o.extend(i.defaults,e),i.compatOptions=o.extend({},s.compatOptions),i.namespace=t,i.data=s.data,i.Item=r(n),o.htmlInit(i,t),h&&h.bridget&&h.bridget(t,i),i};var m={ms:1,s:1e3};return s.Item=n,s}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/item",["outlayer/outlayer"],e):"object"==typeof module&&module.exports?module.exports=e(require("outlayer")):(t.Isotope=t.Isotope||{},t.Isotope.Item=e(t.Outlayer))}(window,function(t){"use strict";function e(){t.Item.apply(this,arguments)}var i=e.prototype=Object.create(t.Item.prototype),o=i._create;i._create=function(){this.id=this.layout.itemGUID++,o.call(this),this.sortData={}},i.updateSortData=function(){if(!this.isIgnored){this.sortData.id=this.id,this.sortData["original-order"]=this.id,this.sortData.random=Math.random();var t=this.layout.options.getSortData,e=this.layout._sorters;for(var i in t){var o=e[i];this.sortData[i]=o(this.element,this)}}};var n=i.destroy;return i.destroy=function(){n.apply(this,arguments),this.css({display:""})},e}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-mode",["get-size/get-size","outlayer/outlayer"],e):"object"==typeof module&&module.exports?module.exports=e(require("get-size"),require("outlayer")):(t.Isotope=t.Isotope||{},t.Isotope.LayoutMode=e(t.getSize,t.Outlayer))}(window,function(t,e){"use strict";function i(t){this.isotope=t,t&&(this.options=t.options[this.namespace],this.element=t.element,this.items=t.filteredItems,this.size=t.size)}var o=i.prototype,n=["_resetLayout","_getItemLayoutPosition","_manageStamp","_getContainerSize","_getElementOffset","needsResizeLayout","_getOption"];return n.forEach(function(t){o[t]=function(){return e.prototype[t].apply(this.isotope,arguments)}}),o.needsVerticalResizeLayout=function(){var e=t(this.isotope.element),i=this.isotope.size&&e;return i&&e.innerHeight!=this.isotope.size.innerHeight},o._getMeasurement=function(){this.isotope._getMeasurement.apply(this,arguments)},o.getColumnWidth=function(){this.getSegmentSize("column","Width")},o.getRowHeight=function(){this.getSegmentSize("row","Height")},o.getSegmentSize=function(t,e){var i=t+e,o="outer"+e;if(this._getMeasurement(i,o),!this[i]){var n=this.getFirstItemSize();this[i]=n&&n[o]||this.isotope.size["inner"+e]}},o.getFirstItemSize=function(){var e=this.isotope.filteredItems[0];return e&&e.element&&t(e.element)},o.layout=function(){this.isotope.layout.apply(this.isotope,arguments)},o.getSize=function(){this.isotope.getSize(),this.size=this.isotope.size},i.modes={},i.create=function(t,e){function n(){i.apply(this,arguments)}return n.prototype=Object.create(o),n.prototype.constructor=n,e&&(n.options=e),n.prototype.namespace=t,i.modes[t]=n,n},i}),function(t,e){"function"==typeof define&&define.amd?define("masonry-layout/masonry",["outlayer/outlayer","get-size/get-size"],e):"object"==typeof module&&module.exports?module.exports=e(require("outlayer"),require("get-size")):t.Masonry=e(t.Outlayer,t.getSize)}(window,function(t,e){var i=t.create("masonry");i.compatOptions.fitWidth="isFitWidth";var o=i.prototype;return o._resetLayout=function(){this.getSize(),this._getMeasurement("columnWidth","outerWidth"),this._getMeasurement("gutter","outerWidth"),this.measureColumns(),this.colYs=[];for(var t=0;t<this.cols;t++)this.colYs.push(0);this.maxY=0,this.horizontalColIndex=0},o.measureColumns=function(){if(this.getContainerWidth(),!this.columnWidth){var t=this.items[0],i=t&&t.element;this.columnWidth=i&&e(i).outerWidth||this.containerWidth}var o=this.columnWidth+=this.gutter,n=this.containerWidth+this.gutter,s=n/o,r=o-n%o,a=r&&r<1?"round":"floor";s=Math[a](s),this.cols=Math.max(s,1)},o.getContainerWidth=function(){var t=this._getOption("fitWidth"),i=t?this.element.parentNode:this.element,o=e(i);this.containerWidth=o&&o.innerWidth},o._getItemLayoutPosition=function(t){t.getSize();var e=t.size.outerWidth%this.columnWidth,i=e&&e<1?"round":"ceil",o=Math[i](t.size.outerWidth/this.columnWidth);o=Math.min(o,this.cols);for(var n=this.options.horizontalOrder?"_getHorizontalColPosition":"_getTopColPosition",s=this[n](o,t),r={x:this.columnWidth*s.col,y:s.y},a=s.y+t.size.outerHeight,u=o+s.col,h=s.col;h<u;h++)this.colYs[h]=a;return r},o._getTopColPosition=function(t){var e=this._getTopColGroup(t),i=Math.min.apply(Math,e);return{col:e.indexOf(i),y:i}},o._getTopColGroup=function(t){if(t<2)return this.colYs;for(var e=[],i=this.cols+1-t,o=0;o<i;o++)e[o]=this._getColGroupY(o,t);return e},o._getColGroupY=function(t,e){if(e<2)return this.colYs[t];var i=this.colYs.slice(t,t+e);return Math.max.apply(Math,i)},o._getHorizontalColPosition=function(t,e){var i=this.horizontalColIndex%this.cols,o=t>1&&i+t>this.cols;i=o?0:i;var n=e.size.outerWidth&&e.size.outerHeight;return this.horizontalColIndex=n?i+t:this.horizontalColIndex,{col:i,y:this._getColGroupY(i,t)}},o._manageStamp=function(t){var i=e(t),o=this._getElementOffset(t),n=this._getOption("originLeft"),s=n?o.left:o.right,r=s+i.outerWidth,a=Math.floor(s/this.columnWidth);a=Math.max(0,a);var u=Math.floor(r/this.columnWidth);u-=r%this.columnWidth?0:1,u=Math.min(this.cols-1,u);for(var h=this._getOption("originTop"),d=(h?o.top:o.bottom)+i.outerHeight,l=a;l<=u;l++)this.colYs[l]=Math.max(d,this.colYs[l])},o._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var t={height:this.maxY};return this._getOption("fitWidth")&&(t.width=this._getContainerFitWidth()),t},o._getContainerFitWidth=function(){for(var t=0,e=this.cols;--e&&0===this.colYs[e];)t++;return(this.cols-t)*this.columnWidth-this.gutter},o.needsResizeLayout=function(){var t=this.containerWidth;return this.getContainerWidth(),t!=this.containerWidth},i}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/masonry",["../layout-mode","masonry-layout/masonry"],e):"object"==typeof module&&module.exports?module.exports=e(require("../layout-mode"),require("masonry-layout")):e(t.Isotope.LayoutMode,t.Masonry)}(window,function(t,e){"use strict";var i=t.create("masonry"),o=i.prototype,n={_getElementOffset:!0,layout:!0,_getMeasurement:!0};for(var s in e.prototype)n[s]||(o[s]=e.prototype[s]);var r=o.measureColumns;o.measureColumns=function(){this.items=this.isotope.filteredItems,r.call(this)};var a=o._getOption;return o._getOption=function(t){return"fitWidth"==t?void 0!==this.options.isFitWidth?this.options.isFitWidth:this.options.fitWidth:a.apply(this.isotope,arguments)},i}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/fit-rows",["../layout-mode"],e):"object"==typeof exports?module.exports=e(require("../layout-mode")):e(t.Isotope.LayoutMode)}(window,function(t){"use strict";var e=t.create("fitRows"),i=e.prototype;return i._resetLayout=function(){this.x=0,this.y=0,this.maxY=0,this._getMeasurement("gutter","outerWidth")},i._getItemLayoutPosition=function(t){t.getSize();var e=t.size.outerWidth+this.gutter,i=this.isotope.size.innerWidth+this.gutter;0!==this.x&&e+this.x>i&&(this.x=0,this.y=this.maxY);var o={x:this.x,y:this.y};return this.maxY=Math.max(this.maxY,this.y+t.size.outerHeight),this.x+=e,o},i._getContainerSize=function(){return{height:this.maxY}},e}),function(t,e){"function"==typeof define&&define.amd?define("isotope-layout/js/layout-modes/vertical",["../layout-mode"],e):"object"==typeof module&&module.exports?module.exports=e(require("../layout-mode")):e(t.Isotope.LayoutMode)}(window,function(t){"use strict";var e=t.create("vertical",{horizontalAlignment:0}),i=e.prototype;return i._resetLayout=function(){this.y=0},i._getItemLayoutPosition=function(t){t.getSize();var e=(this.isotope.size.innerWidth-t.size.outerWidth)*this.options.horizontalAlignment,i=this.y;return this.y+=t.size.outerHeight,{x:e,y:i}},i._getContainerSize=function(){return{height:this.y}},e}),function(t,e){"function"==typeof define&&define.amd?define(["outlayer/outlayer","get-size/get-size","desandro-matches-selector/matches-selector","fizzy-ui-utils/utils","isotope-layout/js/item","isotope-layout/js/layout-mode","isotope-layout/js/layout-modes/masonry","isotope-layout/js/layout-modes/fit-rows","isotope-layout/js/layout-modes/vertical"],function(i,o,n,s,r,a){return e(t,i,o,n,s,r,a)}):"object"==typeof module&&module.exports?module.exports=e(t,require("outlayer"),require("get-size"),require("desandro-matches-selector"),require("fizzy-ui-utils"),require("isotope-layout/js/item"),require("isotope-layout/js/layout-mode"),require("isotope-layout/js/layout-modes/masonry"),require("isotope-layout/js/layout-modes/fit-rows"),require("isotope-layout/js/layout-modes/vertical")):t.Isotope=e(t,t.Outlayer,t.getSize,t.matchesSelector,t.fizzyUIUtils,t.Isotope.Item,t.Isotope.LayoutMode)}(window,function(t,e,i,o,n,s,r){function a(t,e){return function(i,o){for(var n=0;n<t.length;n++){var s=t[n],r=i.sortData[s],a=o.sortData[s];if(r>a||r<a){var u=void 0!==e[s]?e[s]:e,h=u?1:-1;return(r>a?1:-1)*h}}return 0}}var u=t.jQuery,h=String.prototype.trim?function(t){return t.trim()}:function(t){return t.replace(/^\s+|\s+$/g,"")},d=e.create("isotope",{layoutMode:"masonry",isJQueryFiltering:!0,sortAscending:!0});d.Item=s,d.LayoutMode=r;var l=d.prototype;l._create=function(){this.itemGUID=0,this._sorters={},this._getSorters(),e.prototype._create.call(this),this.modes={},this.filteredItems=this.items,this.sortHistory=["original-order"];for(var t in r.modes)this._initLayoutMode(t)},l.reloadItems=function(){this.itemGUID=0,e.prototype.reloadItems.call(this)},l._itemize=function(){for(var t=e.prototype._itemize.apply(this,arguments),i=0;i<t.length;i++){var o=t[i];o.id=this.itemGUID++}return this._updateItemsSortData(t),t},l._initLayoutMode=function(t){var e=r.modes[t],i=this.options[t]||{};this.options[t]=e.options?n.extend(e.options,i):i,this.modes[t]=new e(this)},l.layout=function(){return!this._isLayoutInited&&this._getOption("initLayout")?void this.arrange():void this._layout()},l._layout=function(){var t=this._getIsInstant();this._resetLayout(),this._manageStamps(),this.layoutItems(this.filteredItems,t),this._isLayoutInited=!0},l.arrange=function(t){this.option(t),this._getIsInstant();var e=this._filter(this.items);this.filteredItems=e.matches,this._bindArrangeComplete(),this._isInstant?this._noTransition(this._hideReveal,[e]):this._hideReveal(e),this._sort(),this._layout()},l._init=l.arrange,l._hideReveal=function(t){this.reveal(t.needReveal),this.hide(t.needHide)},l._getIsInstant=function(){var t=this._getOption("layoutInstant"),e=void 0!==t?t:!this._isLayoutInited;return this._isInstant=e,e},l._bindArrangeComplete=function(){function t(){e&&i&&o&&n.dispatchEvent("arrangeComplete",null,[n.filteredItems])}var e,i,o,n=this;this.once("layoutComplete",function(){e=!0,t()}),this.once("hideComplete",function(){i=!0,t()}),this.once("revealComplete",function(){o=!0,t()})},l._filter=function(t){var e=this.options.filter;e=e||"*";for(var i=[],o=[],n=[],s=this._getFilterTest(e),r=0;r<t.length;r++){var a=t[r];if(!a.isIgnored){var u=s(a);u&&i.push(a),u&&a.isHidden?o.push(a):u||a.isHidden||n.push(a)}}return{matches:i,needReveal:o,needHide:n}},l._getFilterTest=function(t){return u&&this.options.isJQueryFiltering?function(e){return u(e.element).is(t);
|
|
}:"function"==typeof t?function(e){return t(e.element)}:function(e){return o(e.element,t)}},l.updateSortData=function(t){var e;t?(t=n.makeArray(t),e=this.getItems(t)):e=this.items,this._getSorters(),this._updateItemsSortData(e)},l._getSorters=function(){var t=this.options.getSortData;for(var e in t){var i=t[e];this._sorters[e]=f(i)}},l._updateItemsSortData=function(t){for(var e=t&&t.length,i=0;e&&i<e;i++){var o=t[i];o.updateSortData()}};var f=function(){function t(t){if("string"!=typeof t)return t;var i=h(t).split(" "),o=i[0],n=o.match(/^\[(.+)\]$/),s=n&&n[1],r=e(s,o),a=d.sortDataParsers[i[1]];return t=a?function(t){return t&&a(r(t))}:function(t){return t&&r(t)}}function e(t,e){return t?function(e){return e.getAttribute(t)}:function(t){var i=t.querySelector(e);return i&&i.textContent}}return t}();d.sortDataParsers={parseInt:function(t){return parseInt(t,10)},parseFloat:function(t){return parseFloat(t)}},l._sort=function(){if(this.options.sortBy){var t=n.makeArray(this.options.sortBy);this._getIsSameSortBy(t)||(this.sortHistory=t.concat(this.sortHistory));var e=a(this.sortHistory,this.options.sortAscending);this.filteredItems.sort(e)}},l._getIsSameSortBy=function(t){for(var e=0;e<t.length;e++)if(t[e]!=this.sortHistory[e])return!1;return!0},l._mode=function(){var t=this.options.layoutMode,e=this.modes[t];if(!e)throw new Error("No layout mode: "+t);return e.options=this.options[t],e},l._resetLayout=function(){e.prototype._resetLayout.call(this),this._mode()._resetLayout()},l._getItemLayoutPosition=function(t){return this._mode()._getItemLayoutPosition(t)},l._manageStamp=function(t){this._mode()._manageStamp(t)},l._getContainerSize=function(){return this._mode()._getContainerSize()},l.needsResizeLayout=function(){return this._mode().needsResizeLayout()},l.appended=function(t){var e=this.addItems(t);if(e.length){var i=this._filterRevealAdded(e);this.filteredItems=this.filteredItems.concat(i)}},l.prepended=function(t){var e=this._itemize(t);if(e.length){this._resetLayout(),this._manageStamps();var i=this._filterRevealAdded(e);this.layoutItems(this.filteredItems),this.filteredItems=i.concat(this.filteredItems),this.items=e.concat(this.items)}},l._filterRevealAdded=function(t){var e=this._filter(t);return this.hide(e.needHide),this.reveal(e.matches),this.layoutItems(e.matches,!0),e.matches},l.insert=function(t){var e=this.addItems(t);if(e.length){var i,o,n=e.length;for(i=0;i<n;i++)o=e[i],this.element.appendChild(o.element);var s=this._filter(e).matches;for(i=0;i<n;i++)e[i].isLayoutInstant=!0;for(this.arrange(),i=0;i<n;i++)delete e[i].isLayoutInstant;this.reveal(s)}};var c=l.remove;return l.remove=function(t){t=n.makeArray(t);var e=this.getItems(t);c.call(this,t);for(var i=e&&e.length,o=0;i&&o<i;o++){var s=e[o];n.removeFrom(this.filteredItems,s)}},l.shuffle=function(){for(var t=0;t<this.items.length;t++){var e=this.items[t];e.sortData.random=Math.random()}this.options.sortBy="random",this._sort(),this._layout()},l._noTransition=function(t,e){var i=this.options.transitionDuration;this.options.transitionDuration=0;var o=t.apply(this,e);return this.options.transitionDuration=i,o},l.getFilteredItemElements=function(){return this.filteredItems.map(function(t){return t.element})},d});
|
|
/*! jqBootstrapValidation
|
|
* A plugin for automating validation on Twitter Bootstrap formatted forms.
|
|
*
|
|
* v1.3.6
|
|
*
|
|
* License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file
|
|
*
|
|
* http://ReactiveRaven.github.com/jqBootstrapValidation/
|
|
*/
|
|
|
|
(function( $ ){
|
|
|
|
var createdElements = [];
|
|
|
|
var defaults = {
|
|
options: {
|
|
prependExistingHelpBlock: false,
|
|
sniffHtml: true, // sniff for 'required', 'maxlength', etc
|
|
preventSubmit: true, // stop the form submit event from firing if validation fails
|
|
submitError: false, // function called if there is an error when trying to submit
|
|
submitSuccess: false, // function called just before a successful submit event is sent to the server
|
|
semanticallyStrict: false, // set to true to tidy up generated HTML output
|
|
autoAdd: {
|
|
helpBlocks: true
|
|
},
|
|
filter: function () {
|
|
// return $(this).is(":visible"); // only validate elements you can see
|
|
return true; // validate everything
|
|
}
|
|
},
|
|
methods: {
|
|
init : function( options ) {
|
|
|
|
var settings = $.extend(true, {}, defaults);
|
|
|
|
settings.options = $.extend(true, settings.options, options);
|
|
|
|
var $siblingElements = this;
|
|
|
|
var uniqueForms = $.unique(
|
|
$siblingElements.map( function () {
|
|
return $(this).parents("form")[0];
|
|
}).toArray()
|
|
);
|
|
|
|
$(uniqueForms).bind("submit", function (e) {
|
|
var $form = $(this);
|
|
var warningsFound = 0;
|
|
var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
|
|
$inputs.trigger("submit.validation").trigger("validationLostFocus.validation");
|
|
|
|
$inputs.each(function (i, el) {
|
|
var $this = $(el),
|
|
$controlGroup = $this.parents(".form-group").first();
|
|
if (
|
|
$controlGroup.hasClass("warning")
|
|
) {
|
|
$controlGroup.removeClass("warning").addClass("error");
|
|
warningsFound++;
|
|
}
|
|
});
|
|
|
|
$inputs.trigger("validationLostFocus.validation");
|
|
|
|
if (warningsFound) {
|
|
if (settings.options.preventSubmit) {
|
|
e.preventDefault();
|
|
}
|
|
$form.addClass("error");
|
|
if ($.isFunction(settings.options.submitError)) {
|
|
settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true));
|
|
}
|
|
} else {
|
|
$form.removeClass("error");
|
|
if ($.isFunction(settings.options.submitSuccess)) {
|
|
settings.options.submitSuccess($form, e);
|
|
}
|
|
}
|
|
});
|
|
|
|
return this.each(function(){
|
|
|
|
// Get references to everything we're interested in
|
|
var $this = $(this),
|
|
$controlGroup = $this.parents(".form-group").first(),
|
|
$helpBlock = $controlGroup.find(".help-block").first(),
|
|
$form = $this.parents("form").first(),
|
|
validatorNames = [];
|
|
|
|
// create message container if not exists
|
|
if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
|
|
$helpBlock = $('<div class="help-block" />');
|
|
$controlGroup.find('.controls').append($helpBlock);
|
|
createdElements.push($helpBlock[0]);
|
|
}
|
|
|
|
// =============================================================
|
|
// SNIFF HTML FOR VALIDATORS
|
|
// =============================================================
|
|
|
|
// *snort sniff snuffle*
|
|
|
|
if (settings.options.sniffHtml) {
|
|
var message = "";
|
|
// ---------------------------------------------------------
|
|
// PATTERN
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("pattern") !== undefined) {
|
|
message = "Not in the expected format<!-- data-validation-pattern-message to override -->";
|
|
if ($this.data("validationPatternMessage")) {
|
|
message = $this.data("validationPatternMessage");
|
|
}
|
|
$this.data("validationPatternMessage", message);
|
|
$this.data("validationPatternRegex", $this.attr("pattern"));
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MAX
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
|
|
var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
|
|
message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->";
|
|
if ($this.data("validationMaxMessage")) {
|
|
message = $this.data("validationMaxMessage");
|
|
}
|
|
$this.data("validationMaxMessage", message);
|
|
$this.data("validationMaxMax", max);
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MIN
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
|
|
var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
|
|
message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->";
|
|
if ($this.data("validationMinMessage")) {
|
|
message = $this.data("validationMinMessage");
|
|
}
|
|
$this.data("validationMinMessage", message);
|
|
$this.data("validationMinMin", min);
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MAXLENGTH
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("maxlength") !== undefined) {
|
|
message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->";
|
|
if ($this.data("validationMaxlengthMessage")) {
|
|
message = $this.data("validationMaxlengthMessage");
|
|
}
|
|
$this.data("validationMaxlengthMessage", message);
|
|
$this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MINLENGTH
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("minlength") !== undefined) {
|
|
message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->";
|
|
if ($this.data("validationMinlengthMessage")) {
|
|
message = $this.data("validationMinlengthMessage");
|
|
}
|
|
$this.data("validationMinlengthMessage", message);
|
|
$this.data("validationMinlengthMinlength", $this.attr("minlength"));
|
|
}
|
|
// ---------------------------------------------------------
|
|
// REQUIRED
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
|
|
message = settings.builtInValidators.required.message;
|
|
if ($this.data("validationRequiredMessage")) {
|
|
message = $this.data("validationRequiredMessage");
|
|
}
|
|
$this.data("validationRequiredMessage", message);
|
|
}
|
|
// ---------------------------------------------------------
|
|
// NUMBER
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
|
|
message = settings.builtInValidators.number.message;
|
|
if ($this.data("validationNumberMessage")) {
|
|
message = $this.data("validationNumberMessage");
|
|
}
|
|
$this.data("validationNumberMessage", message);
|
|
}
|
|
// ---------------------------------------------------------
|
|
// EMAIL
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
|
|
message = "Not a valid email address<!-- data-validator-validemail-message to override -->";
|
|
if ($this.data("validationValidemailMessage")) {
|
|
message = $this.data("validationValidemailMessage");
|
|
} else if ($this.data("validationEmailMessage")) {
|
|
message = $this.data("validationEmailMessage");
|
|
}
|
|
$this.data("validationValidemailMessage", message);
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MINCHECKED
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("minchecked") !== undefined) {
|
|
message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->";
|
|
if ($this.data("validationMincheckedMessage")) {
|
|
message = $this.data("validationMincheckedMessage");
|
|
}
|
|
$this.data("validationMincheckedMessage", message);
|
|
$this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
|
|
}
|
|
// ---------------------------------------------------------
|
|
// MAXCHECKED
|
|
// ---------------------------------------------------------
|
|
if ($this.attr("maxchecked") !== undefined) {
|
|
message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
|
|
if ($this.data("validationMaxcheckedMessage")) {
|
|
message = $this.data("validationMaxcheckedMessage");
|
|
}
|
|
$this.data("validationMaxcheckedMessage", message);
|
|
$this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
|
|
}
|
|
}
|
|
|
|
// =============================================================
|
|
// COLLECT VALIDATOR NAMES
|
|
// =============================================================
|
|
|
|
// Get named validators
|
|
if ($this.data("validation") !== undefined) {
|
|
validatorNames = $this.data("validation").split(",");
|
|
}
|
|
|
|
// Get extra ones defined on the element's data attributes
|
|
$.each($this.data(), function (i, el) {
|
|
var parts = i.replace(/([A-Z])/g, ",$1").split(",");
|
|
if (parts[0] === "validation" && parts[1]) {
|
|
validatorNames.push(parts[1]);
|
|
}
|
|
});
|
|
|
|
// =============================================================
|
|
// NORMALISE VALIDATOR NAMES
|
|
// =============================================================
|
|
|
|
var validatorNamesToInspect = validatorNames;
|
|
var newValidatorNamesToInspect = [];
|
|
|
|
do // repeatedly expand 'shortcut' validators into their real validators
|
|
{
|
|
// Uppercase only the first letter of each name
|
|
$.each(validatorNames, function (i, el) {
|
|
validatorNames[i] = formatValidatorName(el);
|
|
});
|
|
|
|
// Remove duplicate validator names
|
|
validatorNames = $.unique(validatorNames);
|
|
|
|
// Pull out the new validator names from each shortcut
|
|
newValidatorNamesToInspect = [];
|
|
$.each(validatorNamesToInspect, function(i, el) {
|
|
if ($this.data("validation" + el + "Shortcut") !== undefined) {
|
|
// Are these custom validators?
|
|
// Pull them out!
|
|
$.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
|
|
newValidatorNamesToInspect.push(el2);
|
|
});
|
|
} else if (settings.builtInValidators[el.toLowerCase()]) {
|
|
// Is this a recognised built-in?
|
|
// Pull it out!
|
|
var validator = settings.builtInValidators[el.toLowerCase()];
|
|
if (validator.type.toLowerCase() === "shortcut") {
|
|
$.each(validator.shortcut.split(","), function (i, el) {
|
|
el = formatValidatorName(el);
|
|
newValidatorNamesToInspect.push(el);
|
|
validatorNames.push(el);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
validatorNamesToInspect = newValidatorNamesToInspect;
|
|
|
|
} while (validatorNamesToInspect.length > 0)
|
|
|
|
// =============================================================
|
|
// SET UP VALIDATOR ARRAYS
|
|
// =============================================================
|
|
|
|
var validators = {};
|
|
|
|
$.each(validatorNames, function (i, el) {
|
|
// Set up the 'override' message
|
|
var message = $this.data("validation" + el + "Message");
|
|
var hasOverrideMessage = (message !== undefined);
|
|
var foundValidator = false;
|
|
message =
|
|
(
|
|
message
|
|
? message
|
|
: "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->"
|
|
)
|
|
;
|
|
|
|
$.each(
|
|
settings.validatorTypes,
|
|
function (validatorType, validatorTemplate) {
|
|
if (validators[validatorType] === undefined) {
|
|
validators[validatorType] = [];
|
|
}
|
|
if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
|
|
validators[validatorType].push(
|
|
$.extend(
|
|
true,
|
|
{
|
|
name: formatValidatorName(validatorTemplate.name),
|
|
message: message
|
|
},
|
|
validatorTemplate.init($this, el)
|
|
)
|
|
);
|
|
foundValidator = true;
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
|
|
|
|
var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
|
|
if (hasOverrideMessage) {
|
|
validator.message = message;
|
|
}
|
|
var validatorType = validator.type.toLowerCase();
|
|
|
|
if (validatorType === "shortcut") {
|
|
foundValidator = true;
|
|
} else {
|
|
$.each(
|
|
settings.validatorTypes,
|
|
function (validatorTemplateType, validatorTemplate) {
|
|
if (validators[validatorTemplateType] === undefined) {
|
|
validators[validatorTemplateType] = [];
|
|
}
|
|
if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
|
|
$this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]);
|
|
validators[validatorType].push(
|
|
$.extend(
|
|
validator,
|
|
validatorTemplate.init($this, el)
|
|
)
|
|
);
|
|
foundValidator = true;
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
if (! foundValidator) {
|
|
$.error("Cannot find validation info for '" + el + "'");
|
|
}
|
|
});
|
|
|
|
// =============================================================
|
|
// STORE FALLBACK VALUES
|
|
// =============================================================
|
|
|
|
$helpBlock.data(
|
|
"original-contents",
|
|
(
|
|
$helpBlock.data("original-contents")
|
|
? $helpBlock.data("original-contents")
|
|
: $helpBlock.html()
|
|
)
|
|
);
|
|
|
|
$helpBlock.data(
|
|
"original-role",
|
|
(
|
|
$helpBlock.data("original-role")
|
|
? $helpBlock.data("original-role")
|
|
: $helpBlock.attr("role")
|
|
)
|
|
);
|
|
|
|
$controlGroup.data(
|
|
"original-classes",
|
|
(
|
|
$controlGroup.data("original-clases")
|
|
? $controlGroup.data("original-classes")
|
|
: $controlGroup.attr("class")
|
|
)
|
|
);
|
|
|
|
$this.data(
|
|
"original-aria-invalid",
|
|
(
|
|
$this.data("original-aria-invalid")
|
|
? $this.data("original-aria-invalid")
|
|
: $this.attr("aria-invalid")
|
|
)
|
|
);
|
|
|
|
// =============================================================
|
|
// VALIDATION
|
|
// =============================================================
|
|
|
|
$this.bind(
|
|
"validation.validation",
|
|
function (event, params) {
|
|
|
|
var value = getValue($this);
|
|
|
|
// Get a list of the errors to apply
|
|
var errorsFound = [];
|
|
|
|
$.each(validators, function (validatorType, validatorTypeArray) {
|
|
if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) {
|
|
$.each(validatorTypeArray, function (i, validator) {
|
|
if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
|
|
errorsFound.push(validator.message);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
return errorsFound;
|
|
}
|
|
);
|
|
|
|
$this.bind(
|
|
"getValidators.validation",
|
|
function () {
|
|
return validators;
|
|
}
|
|
);
|
|
|
|
// =============================================================
|
|
// WATCH FOR CHANGES
|
|
// =============================================================
|
|
$this.bind(
|
|
"submit.validation",
|
|
function () {
|
|
return $this.triggerHandler("change.validation", {submitting: true});
|
|
}
|
|
);
|
|
$this.bind(
|
|
[
|
|
"keyup",
|
|
"focus",
|
|
"blur",
|
|
"click",
|
|
"keydown",
|
|
"keypress",
|
|
"change"
|
|
].join(".validation ") + ".validation",
|
|
function (e, params) {
|
|
|
|
var value = getValue($this);
|
|
|
|
var errorsFound = [];
|
|
|
|
$controlGroup.find("input,textarea,select").each(function (i, el) {
|
|
var oldCount = errorsFound.length;
|
|
$.each($(el).triggerHandler("validation.validation", params), function (j, message) {
|
|
errorsFound.push(message);
|
|
});
|
|
if (errorsFound.length > oldCount) {
|
|
$(el).attr("aria-invalid", "true");
|
|
} else {
|
|
var original = $this.data("original-aria-invalid");
|
|
$(el).attr("aria-invalid", (original !== undefined ? original : false));
|
|
}
|
|
});
|
|
|
|
$form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
|
|
|
|
errorsFound = $.unique(errorsFound.sort());
|
|
|
|
// Were there any errors?
|
|
if (errorsFound.length) {
|
|
// Better flag it up as a warning.
|
|
$controlGroup.removeClass("success error").addClass("warning");
|
|
|
|
// How many errors did we find?
|
|
if (settings.options.semanticallyStrict && errorsFound.length === 1) {
|
|
// Only one? Being strict? Just output it.
|
|
$helpBlock.html(errorsFound[0] +
|
|
( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
|
|
} else {
|
|
// Multiple? Being sloppy? Glue them together into an UL.
|
|
$helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" +
|
|
( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
|
|
}
|
|
} else {
|
|
$controlGroup.removeClass("warning error success");
|
|
if (value.length > 0) {
|
|
$controlGroup.addClass("success");
|
|
}
|
|
$helpBlock.html($helpBlock.data("original-contents"));
|
|
}
|
|
|
|
if (e.type === "blur") {
|
|
$controlGroup.removeClass("success");
|
|
}
|
|
}
|
|
);
|
|
$this.bind("validationLostFocus.validation", function () {
|
|
$controlGroup.removeClass("success");
|
|
});
|
|
});
|
|
},
|
|
destroy : function( ) {
|
|
|
|
return this.each(
|
|
function() {
|
|
|
|
var
|
|
$this = $(this),
|
|
$controlGroup = $this.parents(".form-group").first(),
|
|
$helpBlock = $controlGroup.find(".help-block").first();
|
|
|
|
// remove our events
|
|
$this.unbind('.validation'); // events are namespaced.
|
|
// reset help text
|
|
$helpBlock.html($helpBlock.data("original-contents"));
|
|
// reset classes
|
|
$controlGroup.attr("class", $controlGroup.data("original-classes"));
|
|
// reset aria
|
|
$this.attr("aria-invalid", $this.data("original-aria-invalid"));
|
|
// reset role
|
|
$helpBlock.attr("role", $this.data("original-role"));
|
|
// remove all elements we created
|
|
if (createdElements.indexOf($helpBlock[0]) > -1) {
|
|
$helpBlock.remove();
|
|
}
|
|
|
|
}
|
|
);
|
|
|
|
},
|
|
collectErrors : function(includeEmpty) {
|
|
|
|
var errorMessages = {};
|
|
this.each(function (i, el) {
|
|
var $el = $(el);
|
|
var name = $el.attr("name");
|
|
var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
|
|
errorMessages[name] = $.extend(true, errors, errorMessages[name]);
|
|
});
|
|
|
|
$.each(errorMessages, function (i, el) {
|
|
if (el.length === 0) {
|
|
delete errorMessages[i];
|
|
}
|
|
});
|
|
|
|
return errorMessages;
|
|
|
|
},
|
|
hasErrors: function() {
|
|
|
|
var errorMessages = [];
|
|
|
|
this.each(function (i, el) {
|
|
errorMessages = errorMessages.concat(
|
|
$(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
|
|
);
|
|
});
|
|
|
|
return (errorMessages.length > 0);
|
|
},
|
|
override : function (newDefaults) {
|
|
defaults = $.extend(true, defaults, newDefaults);
|
|
}
|
|
},
|
|
validatorTypes: {
|
|
callback: {
|
|
name: "callback",
|
|
init: function ($this, name) {
|
|
return {
|
|
validatorName: name,
|
|
callback: $this.data("validation" + name + "Callback"),
|
|
lastValue: $this.val(),
|
|
lastValid: true,
|
|
lastFinished: true
|
|
};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
if (validator.lastValue === value && validator.lastFinished) {
|
|
return !validator.lastValid;
|
|
}
|
|
|
|
if (validator.lastFinished === true)
|
|
{
|
|
validator.lastValue = value;
|
|
validator.lastValid = true;
|
|
validator.lastFinished = false;
|
|
|
|
var rrjqbvValidator = validator;
|
|
var rrjqbvThis = $this;
|
|
executeFunctionByName(
|
|
validator.callback,
|
|
window,
|
|
$this,
|
|
value,
|
|
function (data) {
|
|
if (rrjqbvValidator.lastValue === data.value) {
|
|
rrjqbvValidator.lastValid = data.valid;
|
|
if (data.message) {
|
|
rrjqbvValidator.message = data.message;
|
|
}
|
|
rrjqbvValidator.lastFinished = true;
|
|
rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message);
|
|
// Timeout is set to avoid problems with the events being considered 'already fired'
|
|
setTimeout(function () {
|
|
rrjqbvThis.trigger("change.validation");
|
|
}, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
},
|
|
ajax: {
|
|
name: "ajax",
|
|
init: function ($this, name) {
|
|
return {
|
|
validatorName: name,
|
|
url: $this.data("validation" + name + "Ajax"),
|
|
lastValue: $this.val(),
|
|
lastValid: true,
|
|
lastFinished: true
|
|
};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
|
|
return validator.lastValid === false;
|
|
}
|
|
|
|
if (validator.lastFinished === true)
|
|
{
|
|
validator.lastValue = value;
|
|
validator.lastValid = true;
|
|
validator.lastFinished = false;
|
|
$.ajax({
|
|
url: validator.url,
|
|
data: "value=" + value + "&field=" + $this.attr("name"),
|
|
dataType: "json",
|
|
success: function (data) {
|
|
if (""+validator.lastValue === ""+data.value) {
|
|
validator.lastValid = !!(data.valid);
|
|
if (data.message) {
|
|
validator.message = data.message;
|
|
}
|
|
validator.lastFinished = true;
|
|
$this.data("validation" + validator.validatorName + "Message", validator.message);
|
|
// Timeout is set to avoid problems with the events being considered 'already fired'
|
|
setTimeout(function () {
|
|
$this.trigger("change.validation");
|
|
}, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
|
|
}
|
|
},
|
|
failure: function () {
|
|
validator.lastValid = true;
|
|
validator.message = "ajax call failed";
|
|
validator.lastFinished = true;
|
|
$this.data("validation" + validator.validatorName + "Message", validator.message);
|
|
// Timeout is set to avoid problems with the events being considered 'already fired'
|
|
setTimeout(function () {
|
|
$this.trigger("change.validation");
|
|
}, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
|
|
}
|
|
});
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
},
|
|
regex: {
|
|
name: "regex",
|
|
init: function ($this, name) {
|
|
return {regex: regexFromString($this.data("validation" + name + "Regex"))};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (!validator.regex.test(value) && ! validator.negative)
|
|
|| (validator.regex.test(value) && validator.negative);
|
|
}
|
|
},
|
|
required: {
|
|
name: "required",
|
|
init: function ($this, name) {
|
|
return {};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return !!(value.length === 0 && ! validator.negative)
|
|
|| !!(value.length > 0 && validator.negative);
|
|
},
|
|
blockSubmit: true
|
|
},
|
|
match: {
|
|
name: "match",
|
|
init: function ($this, name) {
|
|
var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first();
|
|
element.bind("validation.validation", function () {
|
|
$this.trigger("change.validation", {submitting: true});
|
|
});
|
|
return {"element": element};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (value !== validator.element.val() && ! validator.negative)
|
|
|| (value === validator.element.val() && validator.negative);
|
|
},
|
|
blockSubmit: true
|
|
},
|
|
max: {
|
|
name: "max",
|
|
init: function ($this, name) {
|
|
return {max: $this.data("validation" + name + "Max")};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative)
|
|
|| (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
|
|
}
|
|
},
|
|
min: {
|
|
name: "min",
|
|
init: function ($this, name) {
|
|
return {min: $this.data("validation" + name + "Min")};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative)
|
|
|| (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
|
|
}
|
|
},
|
|
maxlength: {
|
|
name: "maxlength",
|
|
init: function ($this, name) {
|
|
return {maxlength: $this.data("validation" + name + "Maxlength")};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return ((value.length > validator.maxlength) && ! validator.negative)
|
|
|| ((value.length <= validator.maxlength) && validator.negative);
|
|
}
|
|
},
|
|
minlength: {
|
|
name: "minlength",
|
|
init: function ($this, name) {
|
|
return {minlength: $this.data("validation" + name + "Minlength")};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return ((value.length < validator.minlength) && ! validator.negative)
|
|
|| ((value.length >= validator.minlength) && validator.negative);
|
|
}
|
|
},
|
|
maxchecked: {
|
|
name: "maxchecked",
|
|
init: function ($this, name) {
|
|
var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
|
|
elements.bind("click.validation", function () {
|
|
$this.trigger("change.validation", {includeEmpty: true});
|
|
});
|
|
return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative)
|
|
|| (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
|
|
},
|
|
blockSubmit: true
|
|
},
|
|
minchecked: {
|
|
name: "minchecked",
|
|
init: function ($this, name) {
|
|
var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
|
|
elements.bind("click.validation", function () {
|
|
$this.trigger("change.validation", {includeEmpty: true});
|
|
});
|
|
return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements};
|
|
},
|
|
validate: function ($this, value, validator) {
|
|
return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative)
|
|
|| (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
|
|
},
|
|
blockSubmit: true
|
|
}
|
|
},
|
|
builtInValidators: {
|
|
email: {
|
|
name: "Email",
|
|
type: "shortcut",
|
|
shortcut: "validemail"
|
|
},
|
|
validemail: {
|
|
name: "Validemail",
|
|
type: "regex",
|
|
regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}",
|
|
message: "Not a valid email address<!-- data-validator-validemail-message to override -->"
|
|
},
|
|
passwordagain: {
|
|
name: "Passwordagain",
|
|
type: "match",
|
|
match: "password",
|
|
message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->"
|
|
},
|
|
positive: {
|
|
name: "Positive",
|
|
type: "shortcut",
|
|
shortcut: "number,positivenumber"
|
|
},
|
|
negative: {
|
|
name: "Negative",
|
|
type: "shortcut",
|
|
shortcut: "number,negativenumber"
|
|
},
|
|
number: {
|
|
name: "Number",
|
|
type: "regex",
|
|
regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?",
|
|
message: "Must be a number<!-- data-validator-number-message to override -->"
|
|
},
|
|
integer: {
|
|
name: "Integer",
|
|
type: "regex",
|
|
regex: "[+-]?\\\d+",
|
|
message: "No decimal places allowed<!-- data-validator-integer-message to override -->"
|
|
},
|
|
positivenumber: {
|
|
name: "Positivenumber",
|
|
type: "min",
|
|
min: 0,
|
|
message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->"
|
|
},
|
|
negativenumber: {
|
|
name: "Negativenumber",
|
|
type: "max",
|
|
max: 0,
|
|
message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->"
|
|
},
|
|
required: {
|
|
name: "Required",
|
|
type: "required",
|
|
message: "This is required<!-- data-validator-required-message to override -->"
|
|
},
|
|
checkone: {
|
|
name: "Checkone",
|
|
type: "minchecked",
|
|
minchecked: 1,
|
|
message: "Check at least one option<!-- data-validation-checkone-message to override -->"
|
|
}
|
|
}
|
|
};
|
|
|
|
var formatValidatorName = function (name) {
|
|
return name
|
|
.toLowerCase()
|
|
.replace(
|
|
/(^|\s)([a-z])/g ,
|
|
function(m,p1,p2) {
|
|
return p1+p2.toUpperCase();
|
|
}
|
|
)
|
|
;
|
|
};
|
|
|
|
var getValue = function ($this) {
|
|
// Extract the value we're talking about
|
|
var value = $this.val();
|
|
var type = $this.attr("type");
|
|
if (type === "checkbox") {
|
|
value = ($this.is(":checked") ? value : "");
|
|
}
|
|
if (type === "radio") {
|
|
value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : "");
|
|
}
|
|
return value;
|
|
};
|
|
|
|
function regexFromString(inputstring) {
|
|
return new RegExp("^" + inputstring + "$");
|
|
}
|
|
|
|
/**
|
|
* Thanks to Jason Bunting via StackOverflow.com
|
|
*
|
|
* http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910
|
|
* Short link: http://tinyurl.com/executeFunctionByName
|
|
**/
|
|
function executeFunctionByName(functionName, context /*, args*/) {
|
|
var args = Array.prototype.slice.call(arguments).splice(2);
|
|
var namespaces = functionName.split(".");
|
|
var func = namespaces.pop();
|
|
for(var i = 0; i < namespaces.length; i++) {
|
|
context = context[namespaces[i]];
|
|
}
|
|
return context[func].apply(this, args);
|
|
}
|
|
|
|
$.fn.jqBootstrapValidation = function( method ) {
|
|
|
|
if ( defaults.methods[method] ) {
|
|
return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
|
|
} else if ( typeof method === 'object' || ! method ) {
|
|
return defaults.methods.init.apply( this, arguments );
|
|
} else {
|
|
$.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' );
|
|
return null;
|
|
}
|
|
|
|
};
|
|
|
|
$.jqBootstrapValidation = function (options) {
|
|
$(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
|
|
};
|
|
|
|
})( jQuery );
|
|
/*! Superslides - v0.6.3-wip - 2013-12-17
|
|
* https://github.com/nicinabox/superslides
|
|
* Copyright (c) 2013 Nic Aitch; Licensed MIT */
|
|
(function(window, $) {
|
|
|
|
var Superslides, plugin = 'superslides';
|
|
|
|
Superslides = function(el, options) {
|
|
this.options = $.extend({
|
|
play: false,
|
|
animation_speed: 600,
|
|
animation_easing: 'swing',
|
|
animation: 'slide',
|
|
inherit_width_from: window,
|
|
inherit_height_from: window,
|
|
pagination: true,
|
|
hashchange: false,
|
|
scrollable: true,
|
|
elements: {
|
|
preserve: '.preserve',
|
|
nav: '.slides-navigation',
|
|
container: '.slides-container',
|
|
pagination: '.slides-pagination'
|
|
}
|
|
}, options);
|
|
|
|
var that = this,
|
|
$control = $('<div>', { "class": 'slides-control' }),
|
|
multiplier = 1;
|
|
|
|
this.$el = $(el);
|
|
this.$container = this.$el.find(this.options.elements.container);
|
|
|
|
// Private Methods
|
|
var initialize = function() {
|
|
multiplier = that._findMultiplier();
|
|
|
|
that.$el.on('click', that.options.elements.nav + " a", function(e) {
|
|
e.preventDefault();
|
|
|
|
that.stop();
|
|
if ($(this).hasClass('next')) {
|
|
that.animate('next', function() {
|
|
that.start();
|
|
});
|
|
} else {
|
|
that.animate('prev', function() {
|
|
that.start();
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).on('keyup', function(e) {
|
|
if (e.keyCode === 37) {
|
|
that.animate('prev');
|
|
}
|
|
if (e.keyCode === 39) {
|
|
that.animate('next');
|
|
}
|
|
});
|
|
|
|
$(window).on('resize', function() {
|
|
setTimeout(function() {
|
|
var $children = that.$container.children();
|
|
|
|
that.width = that._findWidth();
|
|
that.height = that._findHeight();
|
|
|
|
$children.css({
|
|
width: that.width,
|
|
left: that.width
|
|
});
|
|
|
|
that.css.containers();
|
|
that.css.images();
|
|
}, 10);
|
|
});
|
|
|
|
if (that.options.hashchange) {
|
|
$(window).on('hashchange', function() {
|
|
var hash = that._parseHash(), index;
|
|
|
|
index = that._upcomingSlide(hash);
|
|
|
|
if (index >= 0 && index !== that.current) {
|
|
that.animate(index);
|
|
}
|
|
});
|
|
}
|
|
|
|
that.pagination._events();
|
|
|
|
that.start();
|
|
return that;
|
|
};
|
|
|
|
var css = {
|
|
containers: function() {
|
|
if (that.init) {
|
|
that.$el.css({
|
|
height: that.height
|
|
});
|
|
|
|
that.$control.css({
|
|
width: that.width * multiplier,
|
|
left: -that.width
|
|
});
|
|
|
|
that.$container.css({
|
|
|
|
});
|
|
} else {
|
|
$('body').css({
|
|
margin: 0
|
|
});
|
|
|
|
that.$el.css({
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
width: '100%',
|
|
height: that.height
|
|
});
|
|
|
|
that.$control.css({
|
|
position: 'relative',
|
|
transform: 'translate3d(0)',
|
|
height: '100%',
|
|
width: that.width * multiplier,
|
|
left: -that.width
|
|
});
|
|
|
|
that.$container.css({
|
|
display: 'none',
|
|
margin: '0',
|
|
padding: '0',
|
|
listStyle: 'none',
|
|
position: 'relative',
|
|
height: '100%'
|
|
});
|
|
}
|
|
|
|
if (that.size() === 1) {
|
|
that.$el.find(that.options.elements.nav).hide();
|
|
}
|
|
},
|
|
images: function() {
|
|
var $images = that.$container.find('img')
|
|
.not(that.options.elements.preserve)
|
|
|
|
$images.removeAttr('width').removeAttr('height')
|
|
.css({
|
|
"-webkit-backface-visibility": 'hidden',
|
|
"-ms-interpolation-mode": 'bicubic',
|
|
"position": 'absolute',
|
|
"left": '0',
|
|
"top": '0',
|
|
"z-index": '-1',
|
|
"max-width": 'none'
|
|
});
|
|
|
|
$images.each(function() {
|
|
var image_aspect_ratio = that.image._aspectRatio(this),
|
|
image = this;
|
|
|
|
if (!$.data(this, 'processed')) {
|
|
var img = new Image();
|
|
img.onload = function() {
|
|
that.image._scale(image, image_aspect_ratio);
|
|
that.image._center(image, image_aspect_ratio);
|
|
$.data(image, 'processed', true);
|
|
};
|
|
img.src = this.src;
|
|
|
|
} else {
|
|
that.image._scale(image, image_aspect_ratio);
|
|
that.image._center(image, image_aspect_ratio);
|
|
}
|
|
});
|
|
},
|
|
children: function() {
|
|
var $children = that.$container.children();
|
|
|
|
if ($children.is('img')) {
|
|
$children.each(function() {
|
|
if ($(this).is('img')) {
|
|
$(this).wrap('<div>');
|
|
|
|
// move id attribute
|
|
var id = $(this).attr('id');
|
|
$(this).removeAttr('id');
|
|
$(this).parent().attr('id', id);
|
|
}
|
|
});
|
|
|
|
$children = that.$container.children();
|
|
}
|
|
|
|
if (!that.init) {
|
|
$children.css({
|
|
display: 'none',
|
|
left: that.width * 2
|
|
});
|
|
}
|
|
|
|
$children.css({
|
|
position: 'absolute',
|
|
overflow: 'hidden',
|
|
height: '100%',
|
|
width: that.width,
|
|
top: 0,
|
|
zIndex: 0
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
var fx = {
|
|
slide: function(orientation, complete) {
|
|
var $children = that.$container.children(),
|
|
$target = $children.eq(orientation.upcoming_slide);
|
|
|
|
$target.css({
|
|
left: orientation.upcoming_position,
|
|
display: 'block'
|
|
});
|
|
|
|
that.$control.animate({
|
|
left: orientation.offset
|
|
},
|
|
that.options.animation_speed,
|
|
that.options.animation_easing,
|
|
function() {
|
|
if (that.size() > 1) {
|
|
that.$control.css({
|
|
left: -that.width
|
|
});
|
|
|
|
$children.eq(orientation.upcoming_slide).css({
|
|
left: that.width,
|
|
zIndex: 2
|
|
});
|
|
|
|
if (orientation.outgoing_slide >= 0) {
|
|
$children.eq(orientation.outgoing_slide).css({
|
|
left: that.width,
|
|
display: 'none',
|
|
zIndex: 0
|
|
});
|
|
}
|
|
}
|
|
|
|
complete();
|
|
});
|
|
},
|
|
/* fade: function(orientation, complete) {
|
|
var that = this,
|
|
$children = that.$container.children(),
|
|
$outgoing = $children.eq(orientation.outgoing_slide),
|
|
$target = $children.eq(orientation.upcoming_slide);
|
|
|
|
$target.css({
|
|
left: this.width,
|
|
opacity: 0,
|
|
display: 'block'
|
|
}).animate({
|
|
opacity: 1
|
|
},
|
|
that.options.animation_speed,
|
|
that.options.animation_easing
|
|
);
|
|
|
|
if (orientation.outgoing_slide >= 0) {
|
|
$outgoing.animate({
|
|
opacity: 0
|
|
},
|
|
that.options.animation_speed,
|
|
that.options.animation_easing,
|
|
function() {
|
|
if (that.size() > 1) {
|
|
$children.eq(orientation.upcoming_slide).css({
|
|
zIndex: 2
|
|
});
|
|
|
|
if (orientation.outgoing_slide >= 0) {
|
|
$children.eq(orientation.outgoing_slide).css({
|
|
opacity: 1,
|
|
display: 'none',
|
|
zIndex: 0
|
|
});
|
|
}
|
|
}
|
|
|
|
complete();
|
|
});
|
|
} else {
|
|
$target.css({
|
|
zIndex: 2
|
|
});
|
|
complete();
|
|
}
|
|
}*/
|
|
|
|
fade: function(orientation, complete) {
|
|
var that = this,
|
|
$children = that.$container.children(),
|
|
$outgoing = $children.eq(orientation.outgoing_slide),
|
|
$target = $children.eq(orientation.upcoming_slide);
|
|
// alert(orientation.upcoming_slide);
|
|
$target.css({
|
|
left: this.width,
|
|
opacity: 0,
|
|
display: 'block'
|
|
}).animate({
|
|
opacity: 1
|
|
},
|
|
that.options.animation_speed,
|
|
that.options.animation_easing
|
|
);
|
|
$outgoing.animate({
|
|
opacity: 0
|
|
});
|
|
|
|
// if (orientation.outgoing_slide >= 0) {
|
|
that.$control.animate({
|
|
opacity: 1,
|
|
zIndex: 2,
|
|
display: 'block'
|
|
},
|
|
// $outgoing.animate({
|
|
// opacity: 0
|
|
// },
|
|
that.options.animation_speed,
|
|
that.options.animation_easing,
|
|
function() {
|
|
if (that.size() > 1) {
|
|
that.$control.css({
|
|
left: -that.width
|
|
});
|
|
$children.eq(orientation.upcoming_slide).css({
|
|
zIndex: 2
|
|
});
|
|
|
|
if (orientation.outgoing_slide >= 0) {
|
|
$children.eq(orientation.outgoing_slide).css({
|
|
opacity: 1,
|
|
display: 'none',
|
|
zIndex: 0
|
|
});
|
|
}
|
|
}
|
|
|
|
complete();
|
|
});
|
|
// } else {
|
|
// $target.css({
|
|
// zIndex: 2
|
|
// });
|
|
// complete();
|
|
// }
|
|
}
|
|
};
|
|
|
|
fx = $.extend(fx, $.fn.superslides.fx);
|
|
|
|
var image = {
|
|
_centerY: function(image) {
|
|
var $img = $(image);
|
|
|
|
$img.css({
|
|
top: (that.height - $img.height()) / 2
|
|
});
|
|
},
|
|
_centerX: function(image) {
|
|
var $img = $(image);
|
|
|
|
$img.css({
|
|
left: (that.width - $img.width()) / 2
|
|
});
|
|
},
|
|
_center: function(image) {
|
|
that.image._centerX(image);
|
|
that.image._centerY(image);
|
|
},
|
|
_aspectRatio: function(image) {
|
|
if (!image.naturalHeight && !image.naturalWidth) {
|
|
var img = new Image();
|
|
img.src = image.src;
|
|
image.naturalHeight = img.height;
|
|
image.naturalWidth = img.width;
|
|
}
|
|
|
|
return image.naturalHeight / image.naturalWidth;
|
|
},
|
|
_scale: function(image, image_aspect_ratio) {
|
|
image_aspect_ratio = image_aspect_ratio || that.image._aspectRatio(image);
|
|
|
|
var container_aspect_ratio = that.height / that.width,
|
|
$img = $(image);
|
|
|
|
if (container_aspect_ratio > image_aspect_ratio) {
|
|
$img.css({
|
|
height: that.height,
|
|
width: that.height / image_aspect_ratio
|
|
});
|
|
|
|
} else {
|
|
$img.css({
|
|
height: that.width * image_aspect_ratio,
|
|
width: that.width
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
var pagination = {
|
|
_setCurrent: function(i) {
|
|
if (!that.$pagination) { return; }
|
|
|
|
var $pagination_children = that.$pagination.children();
|
|
|
|
$pagination_children.removeClass('current');
|
|
$pagination_children.eq(i)
|
|
.addClass('current');
|
|
},
|
|
_addItem: function(i) {
|
|
var slide_number = i + 1,
|
|
href = slide_number,
|
|
$slide = that.$container.children().eq(i),
|
|
slide_id = $slide.attr('id');
|
|
|
|
if (slide_id) {
|
|
href = slide_id;
|
|
}
|
|
|
|
var $item = $("<a>", {
|
|
'href': "#" + href,
|
|
'text': href
|
|
});
|
|
|
|
$item.appendTo(that.$pagination);
|
|
},
|
|
_setup: function() {
|
|
if (!that.options.pagination || that.size() === 1) { return; }
|
|
|
|
var $pagination = $("<nav>", {
|
|
'class': that.options.elements.pagination.replace(/^\./, '')
|
|
});
|
|
|
|
that.$pagination = $pagination.appendTo(that.$el);
|
|
|
|
for (var i = 0; i < that.size(); i++) {
|
|
that.pagination._addItem(i);
|
|
}
|
|
},
|
|
_events: function() {
|
|
that.$el.on('click', that.options.elements.pagination + ' a', function(e) {
|
|
e.preventDefault();
|
|
|
|
var hash = that._parseHash(this.hash), index;
|
|
index = that._upcomingSlide(hash, true);
|
|
|
|
if (index !== that.current) {
|
|
that.animate(index, function() {
|
|
that.start();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
this.css = css;
|
|
this.image = image;
|
|
this.pagination = pagination;
|
|
this.fx = fx;
|
|
this.animation = this.fx[this.options.animation];
|
|
|
|
this.$control = this.$container.wrap($control).parent('.slides-control');
|
|
|
|
that._findPositions();
|
|
that.width = that._findWidth();
|
|
that.height = that._findHeight();
|
|
|
|
this.css.children();
|
|
this.css.containers();
|
|
this.css.images();
|
|
this.pagination._setup();
|
|
|
|
return initialize();
|
|
};
|
|
|
|
Superslides.prototype = {
|
|
_findWidth: function() {
|
|
return $(this.options.inherit_width_from).width();
|
|
},
|
|
_findHeight: function() {
|
|
return $(this.options.inherit_height_from).height();
|
|
},
|
|
|
|
_findMultiplier: function() {
|
|
return this.size() === 1 ? 1 : 3;
|
|
},
|
|
|
|
_upcomingSlide: function(direction, from_hash_change) {
|
|
if (from_hash_change && !isNaN(direction)) {
|
|
direction = direction - 1;
|
|
}
|
|
|
|
if ((/next/).test(direction)) {
|
|
return this._nextInDom();
|
|
|
|
} else if ((/prev/).test(direction)) {
|
|
return this._prevInDom();
|
|
|
|
} else if ((/\d/).test(direction)) {
|
|
return +direction;
|
|
|
|
} else if (direction && (/\w/).test(direction)) {
|
|
var index = this._findSlideById(direction);
|
|
if (index >= 0) {
|
|
return index;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
} else {
|
|
return 0;
|
|
}
|
|
},
|
|
|
|
_findSlideById: function(id) {
|
|
return this.$container.find('#' + id).index();
|
|
},
|
|
|
|
_findPositions: function(current, thisRef) {
|
|
thisRef = thisRef || this;
|
|
|
|
if (current === undefined) {
|
|
current = -1;
|
|
}
|
|
|
|
thisRef.current = current;
|
|
thisRef.next = thisRef._nextInDom();
|
|
thisRef.prev = thisRef._prevInDom();
|
|
},
|
|
|
|
_nextInDom: function() {
|
|
var index = this.current + 1;
|
|
|
|
if (index === this.size()) {
|
|
index = 0;
|
|
}
|
|
|
|
return index;
|
|
},
|
|
|
|
_prevInDom: function() {
|
|
var index = this.current - 1;
|
|
|
|
if (index < 0) {
|
|
index = this.size() - 1;
|
|
}
|
|
|
|
return index;
|
|
},
|
|
|
|
_parseHash: function(hash) {
|
|
hash = hash || window.location.hash;
|
|
hash = hash.replace(/^#/, '');
|
|
|
|
if (hash && !isNaN(+hash)) {
|
|
hash = +hash;
|
|
}
|
|
|
|
return hash;
|
|
},
|
|
|
|
size: function() {
|
|
return this.$container.children().length;
|
|
},
|
|
|
|
destroy: function() {
|
|
return this.$el.removeData();
|
|
},
|
|
|
|
update: function() {
|
|
this.css.children();
|
|
this.css.containers();
|
|
this.css.images();
|
|
|
|
this.pagination._addItem(this.size())
|
|
|
|
this._findPositions(this.current);
|
|
this.$el.trigger('updated.slides');
|
|
},
|
|
|
|
stop: function() {
|
|
clearInterval(this.play_id);
|
|
delete this.play_id;
|
|
|
|
this.$el.trigger('stopped.slides');
|
|
},
|
|
|
|
start: function() {
|
|
var that = this;
|
|
|
|
if (that.options.hashchange) {
|
|
$(window).trigger('hashchange');
|
|
} else {
|
|
this.animate();
|
|
}
|
|
|
|
if (this.options.play) {
|
|
if (this.play_id) {
|
|
this.stop();
|
|
}
|
|
|
|
this.play_id = setInterval(function() {
|
|
that.animate();
|
|
}, this.options.play);
|
|
}
|
|
|
|
this.$el.trigger('started.slides');
|
|
},
|
|
|
|
animate: function(direction, userCallback) {
|
|
var that = this,
|
|
orientation = {};
|
|
|
|
if (this.animating) {
|
|
return;
|
|
}
|
|
|
|
this.animating = true;
|
|
|
|
if (direction === undefined) {
|
|
direction = 'next';
|
|
}
|
|
|
|
orientation.upcoming_slide = this._upcomingSlide(direction);
|
|
|
|
if (orientation.upcoming_slide >= this.size()) {
|
|
return;
|
|
}
|
|
|
|
orientation.outgoing_slide = this.current;
|
|
orientation.upcoming_position = this.width * 2;
|
|
orientation.offset = -orientation.upcoming_position;
|
|
|
|
if (direction === 'prev' || direction < orientation.outgoing_slide) {
|
|
orientation.upcoming_position = 0;
|
|
orientation.offset = 0;
|
|
}
|
|
|
|
if (that.size() > 1) {
|
|
that.pagination._setCurrent(orientation.upcoming_slide);
|
|
}
|
|
|
|
if (that.options.hashchange) {
|
|
var hash = orientation.upcoming_slide + 1,
|
|
id = that.$container.children(':eq(' + orientation.upcoming_slide + ')').attr('id');
|
|
|
|
if (id) {
|
|
window.location.hash = id;
|
|
} else {
|
|
window.location.hash = hash;
|
|
}
|
|
}
|
|
if (that.size() === 1) {
|
|
that.stop();
|
|
that.options.play = 0;
|
|
that.options.animation_speed = 0;
|
|
orientation.upcoming_slide = 0;
|
|
orientation.outgoing_slide = -1;
|
|
}
|
|
that.$el.trigger('animating.slides', [orientation]);
|
|
|
|
that.animation(orientation, function() {
|
|
that._findPositions(orientation.upcoming_slide, that);
|
|
|
|
if (typeof userCallback === 'function') {
|
|
userCallback();
|
|
}
|
|
|
|
that.animating = false;
|
|
that.$el.trigger('animated.slides');
|
|
|
|
if (!that.init) {
|
|
that.$el.trigger('init.slides');
|
|
that.init = true;
|
|
that.$container.fadeIn('fast');
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// jQuery plugin definition
|
|
|
|
$.fn[plugin] = function(option, args) {
|
|
var result = [];
|
|
|
|
this.each(function() {
|
|
var $this, data, options;
|
|
|
|
$this = $(this);
|
|
data = $this.data(plugin);
|
|
options = typeof option === 'object' && option;
|
|
|
|
if (!data) {
|
|
result = $this.data(plugin, (data = new Superslides(this, options)));
|
|
}
|
|
|
|
if (typeof option === "string") {
|
|
result = data[option];
|
|
if (typeof result === 'function') {
|
|
return result = result.call(data, args);
|
|
}
|
|
}
|
|
});
|
|
|
|
return result;
|
|
};
|
|
|
|
$.fn[plugin].fx = {};
|
|
|
|
})(this, jQuery);
|
|
|
|
/*!
|
|
* FitVids 1.1
|
|
*
|
|
* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
|
|
* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
|
|
* Released under the WTFPL license - http://sam.zoy.org/wtfpl/
|
|
*
|
|
*/
|
|
|
|
(function( $ ){
|
|
|
|
"use strict";
|
|
|
|
$.fn.fitVids = function( options ) {
|
|
var settings = {
|
|
customSelector: null,
|
|
ignore: null
|
|
};
|
|
|
|
if(!document.getElementById('fit-vids-style')) {
|
|
// appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js
|
|
var head = document.head || document.getElementsByTagName('head')[0];
|
|
var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}';
|
|
var div = document.createElement('div');
|
|
div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>';
|
|
head.appendChild(div.childNodes[1]);
|
|
}
|
|
|
|
if ( options ) {
|
|
$.extend( settings, options );
|
|
}
|
|
|
|
return this.each(function(){
|
|
var selectors = [
|
|
"iframe[src*='player.vimeo.com']",
|
|
"iframe[src*='youtube.com']",
|
|
"iframe[src*='youtube-nocookie.com']",
|
|
"iframe[src*='kickstarter.com'][src*='video.html']",
|
|
"object",
|
|
"embed"
|
|
];
|
|
|
|
if (settings.customSelector) {
|
|
selectors.push(settings.customSelector);
|
|
}
|
|
|
|
var ignoreList = '.fitvidsignore';
|
|
|
|
if(settings.ignore) {
|
|
ignoreList = ignoreList + ', ' + settings.ignore;
|
|
}
|
|
|
|
var $allVideos = $(this).find(selectors.join(','));
|
|
$allVideos = $allVideos.not("object object"); // SwfObj conflict patch
|
|
$allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video.
|
|
|
|
$allVideos.each(function(){
|
|
var $this = $(this);
|
|
if($this.parents(ignoreList).length > 0) {
|
|
return; // Disable FitVids on this video.
|
|
}
|
|
if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
|
|
if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width'))))
|
|
{
|
|
$this.attr('height', 9);
|
|
$this.attr('width', 16);
|
|
}
|
|
var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(),
|
|
width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(),
|
|
aspectRatio = height / width;
|
|
if(!$this.attr('id')){
|
|
var videoID = 'fitvid' + Math.floor(Math.random()*999999);
|
|
$this.attr('id', videoID);
|
|
}
|
|
$this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%");
|
|
$this.removeAttr('height').removeAttr('width');
|
|
});
|
|
});
|
|
};
|
|
// Works with either jQuery or Zepto
|
|
})( window.jQuery || window.Zepto );
|
|
|
|
/*! Magnific Popup - v0.9.9 - 2013-12-27
|
|
* http://dimsemenov.com/plugins/magnific-popup/
|
|
* Copyright (c) 2013 Dmitry Semenov; */
|
|
;(function($) {
|
|
|
|
/*>>core*/
|
|
/**
|
|
*
|
|
* Magnific Popup Core JS file
|
|
*
|
|
*/
|
|
|
|
|
|
/**
|
|
* Private static constants
|
|
*/
|
|
var CLOSE_EVENT = 'Close',
|
|
BEFORE_CLOSE_EVENT = 'BeforeClose',
|
|
AFTER_CLOSE_EVENT = 'AfterClose',
|
|
BEFORE_APPEND_EVENT = 'BeforeAppend',
|
|
MARKUP_PARSE_EVENT = 'MarkupParse',
|
|
OPEN_EVENT = 'Open',
|
|
CHANGE_EVENT = 'Change',
|
|
NS = 'mfp',
|
|
EVENT_NS = '.' + NS,
|
|
READY_CLASS = 'mfp-ready',
|
|
REMOVING_CLASS = 'mfp-removing',
|
|
PREVENT_CLOSE_CLASS = 'mfp-prevent-close';
|
|
|
|
|
|
/**
|
|
* Private vars
|
|
*/
|
|
var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this'
|
|
MagnificPopup = function(){},
|
|
_isJQ = !!(window.jQuery),
|
|
_prevStatus,
|
|
_window = $(window),
|
|
_body,
|
|
_document,
|
|
_prevContentType,
|
|
_wrapClasses,
|
|
_currPopupType;
|
|
|
|
|
|
/**
|
|
* Private functions
|
|
*/
|
|
var _mfpOn = function(name, f) {
|
|
mfp.ev.on(NS + name + EVENT_NS, f);
|
|
},
|
|
_getEl = function(className, appendTo, html, raw) {
|
|
var el = document.createElement('div');
|
|
el.className = 'mfp-'+className;
|
|
if(html) {
|
|
el.innerHTML = html;
|
|
}
|
|
if(!raw) {
|
|
el = $(el);
|
|
if(appendTo) {
|
|
el.appendTo(appendTo);
|
|
}
|
|
} else if(appendTo) {
|
|
appendTo.appendChild(el);
|
|
}
|
|
return el;
|
|
},
|
|
_mfpTrigger = function(e, data) {
|
|
mfp.ev.triggerHandler(NS + e, data);
|
|
|
|
if(mfp.st.callbacks) {
|
|
// converts "mfpEventName" to "eventName" callback and triggers it if it's present
|
|
e = e.charAt(0).toLowerCase() + e.slice(1);
|
|
if(mfp.st.callbacks[e]) {
|
|
mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]);
|
|
}
|
|
}
|
|
},
|
|
_getCloseBtn = function(type) {
|
|
if(type !== _currPopupType || !mfp.currTemplate.closeBtn) {
|
|
mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) );
|
|
_currPopupType = type;
|
|
}
|
|
return mfp.currTemplate.closeBtn;
|
|
},
|
|
// Initialize Magnific Popup only when called at least once
|
|
_checkInstance = function() {
|
|
if(!$.magnificPopup.instance) {
|
|
mfp = new MagnificPopup();
|
|
mfp.init();
|
|
$.magnificPopup.instance = mfp;
|
|
}
|
|
},
|
|
// CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
|
|
supportsTransitions = function() {
|
|
var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist
|
|
v = ['ms','O','Moz','Webkit']; // 'v' for vendor
|
|
|
|
if( s['transition'] !== undefined ) {
|
|
return true;
|
|
}
|
|
|
|
while( v.length ) {
|
|
if( v.pop() + 'Transition' in s ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Public functions
|
|
*/
|
|
MagnificPopup.prototype = {
|
|
|
|
constructor: MagnificPopup,
|
|
|
|
/**
|
|
* Initializes Magnific Popup plugin.
|
|
* This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed
|
|
*/
|
|
init: function() {
|
|
var appVersion = navigator.appVersion;
|
|
mfp.isIE7 = appVersion.indexOf("MSIE 7.") !== -1;
|
|
mfp.isIE8 = appVersion.indexOf("MSIE 8.") !== -1;
|
|
mfp.isLowIE = mfp.isIE7 || mfp.isIE8;
|
|
mfp.isAndroid = (/android/gi).test(appVersion);
|
|
mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion);
|
|
mfp.supportsTransition = supportsTransitions();
|
|
|
|
// We disable fixed positioned lightbox on devices that don't handle it nicely.
|
|
// If you know a better way of detecting this - let me know.
|
|
mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) );
|
|
_document = $(document);
|
|
|
|
mfp.popupsCache = {};
|
|
},
|
|
|
|
/**
|
|
* Opens popup
|
|
* @param data [description]
|
|
*/
|
|
open: function(data) {
|
|
|
|
if(!_body) {
|
|
_body = $(document.body);
|
|
}
|
|
|
|
var i;
|
|
|
|
if(data.isObj === false) {
|
|
// convert jQuery collection to array to avoid conflicts later
|
|
mfp.items = data.items.toArray();
|
|
|
|
mfp.index = 0;
|
|
var items = data.items,
|
|
item;
|
|
for(i = 0; i < items.length; i++) {
|
|
item = items[i];
|
|
if(item.parsed) {
|
|
item = item.el[0];
|
|
}
|
|
if(item === data.el[0]) {
|
|
mfp.index = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
mfp.items = $.isArray(data.items) ? data.items : [data.items];
|
|
mfp.index = data.index || 0;
|
|
}
|
|
|
|
// if popup is already opened - we just update the content
|
|
if(mfp.isOpen) {
|
|
mfp.updateItemHTML();
|
|
return;
|
|
}
|
|
|
|
mfp.types = [];
|
|
_wrapClasses = '';
|
|
if(data.mainEl && data.mainEl.length) {
|
|
mfp.ev = data.mainEl.eq(0);
|
|
} else {
|
|
mfp.ev = _document;
|
|
}
|
|
|
|
if(data.key) {
|
|
if(!mfp.popupsCache[data.key]) {
|
|
mfp.popupsCache[data.key] = {};
|
|
}
|
|
mfp.currTemplate = mfp.popupsCache[data.key];
|
|
} else {
|
|
mfp.currTemplate = {};
|
|
}
|
|
|
|
|
|
|
|
mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data );
|
|
mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos;
|
|
|
|
if(mfp.st.modal) {
|
|
mfp.st.closeOnContentClick = false;
|
|
mfp.st.closeOnBgClick = false;
|
|
mfp.st.showCloseBtn = false;
|
|
mfp.st.enableEscapeKey = false;
|
|
}
|
|
|
|
|
|
// Building markup
|
|
// main containers are created only once
|
|
if(!mfp.bgOverlay) {
|
|
|
|
// Dark overlay
|
|
mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() {
|
|
mfp.close();
|
|
});
|
|
|
|
mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) {
|
|
if(mfp._checkIfClose(e.target)) {
|
|
mfp.close();
|
|
}
|
|
});
|
|
|
|
mfp.container = _getEl('container', mfp.wrap);
|
|
}
|
|
|
|
mfp.contentContainer = _getEl('content');
|
|
if(mfp.st.preloader) {
|
|
mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading);
|
|
}
|
|
|
|
|
|
// Initializing modules
|
|
var modules = $.magnificPopup.modules;
|
|
for(i = 0; i < modules.length; i++) {
|
|
var n = modules[i];
|
|
n = n.charAt(0).toUpperCase() + n.slice(1);
|
|
mfp['init'+n].call(mfp);
|
|
}
|
|
_mfpTrigger('BeforeOpen');
|
|
|
|
|
|
if(mfp.st.showCloseBtn) {
|
|
// Close button
|
|
if(!mfp.st.closeBtnInside) {
|
|
mfp.wrap.append( _getCloseBtn() );
|
|
} else {
|
|
_mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) {
|
|
values.close_replaceWith = _getCloseBtn(item.type);
|
|
});
|
|
_wrapClasses += ' mfp-close-btn-in';
|
|
}
|
|
}
|
|
|
|
if(mfp.st.alignTop) {
|
|
_wrapClasses += ' mfp-align-top';
|
|
}
|
|
|
|
|
|
|
|
if(mfp.fixedContentPos) {
|
|
mfp.wrap.css({
|
|
overflow: mfp.st.overflowY,
|
|
overflowX: 'hidden',
|
|
overflowY: mfp.st.overflowY
|
|
});
|
|
} else {
|
|
mfp.wrap.css({
|
|
top: _window.scrollTop(),
|
|
position: 'absolute'
|
|
});
|
|
}
|
|
if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) {
|
|
mfp.bgOverlay.css({
|
|
height: _document.height(),
|
|
position: 'absolute'
|
|
});
|
|
}
|
|
|
|
|
|
|
|
if(mfp.st.enableEscapeKey) {
|
|
// Close on ESC key
|
|
_document.on('keyup' + EVENT_NS, function(e) {
|
|
if(e.keyCode === 27) {
|
|
mfp.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
_window.on('resize' + EVENT_NS, function() {
|
|
mfp.updateSize();
|
|
});
|
|
|
|
|
|
if(!mfp.st.closeOnContentClick) {
|
|
_wrapClasses += ' mfp-auto-cursor';
|
|
}
|
|
|
|
if(_wrapClasses)
|
|
mfp.wrap.addClass(_wrapClasses);
|
|
|
|
|
|
// this triggers recalculation of layout, so we get it once to not to trigger twice
|
|
var windowHeight = mfp.wH = _window.height();
|
|
|
|
|
|
var windowStyles = {};
|
|
|
|
if( mfp.fixedContentPos ) {
|
|
if(mfp._hasScrollBar(windowHeight)){
|
|
var s = mfp._getScrollbarSize();
|
|
if(s) {
|
|
windowStyles.marginRight = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(mfp.fixedContentPos) {
|
|
if(!mfp.isIE7) {
|
|
windowStyles.overflow = 'hidden';
|
|
} else {
|
|
// ie7 double-scroll bug
|
|
$('body, html').css('overflow', 'hidden');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var classesToadd = mfp.st.mainClass;
|
|
if(mfp.isIE7) {
|
|
classesToadd += ' mfp-ie7';
|
|
}
|
|
if(classesToadd) {
|
|
mfp._addClassToMFP( classesToadd );
|
|
}
|
|
|
|
// add content
|
|
mfp.updateItemHTML();
|
|
|
|
_mfpTrigger('BuildControls');
|
|
|
|
// remove scrollbar, add margin e.t.c
|
|
$('html').css(windowStyles);
|
|
|
|
// add everything to DOM
|
|
mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || _body );
|
|
|
|
// Save last focused element
|
|
mfp._lastFocusedEl = document.activeElement;
|
|
|
|
// Wait for next cycle to allow CSS transition
|
|
setTimeout(function() {
|
|
|
|
if(mfp.content) {
|
|
mfp._addClassToMFP(READY_CLASS);
|
|
mfp._setFocus();
|
|
} else {
|
|
// if content is not defined (not loaded e.t.c) we add class only for BG
|
|
mfp.bgOverlay.addClass(READY_CLASS);
|
|
}
|
|
|
|
// Trap the focus in popup
|
|
_document.on('focusin' + EVENT_NS, mfp._onFocusIn);
|
|
|
|
}, 16);
|
|
|
|
mfp.isOpen = true;
|
|
mfp.updateSize(windowHeight);
|
|
_mfpTrigger(OPEN_EVENT);
|
|
|
|
return data;
|
|
},
|
|
|
|
/**
|
|
* Closes the popup
|
|
*/
|
|
close: function() {
|
|
if(!mfp.isOpen) return;
|
|
_mfpTrigger(BEFORE_CLOSE_EVENT);
|
|
|
|
mfp.isOpen = false;
|
|
// for CSS3 animation
|
|
if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition ) {
|
|
mfp._addClassToMFP(REMOVING_CLASS);
|
|
setTimeout(function() {
|
|
mfp._close();
|
|
}, mfp.st.removalDelay);
|
|
} else {
|
|
mfp._close();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Helper for close() function
|
|
*/
|
|
_close: function() {
|
|
_mfpTrigger(CLOSE_EVENT);
|
|
|
|
var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' ';
|
|
|
|
mfp.bgOverlay.detach();
|
|
mfp.wrap.detach();
|
|
mfp.container.empty();
|
|
|
|
if(mfp.st.mainClass) {
|
|
classesToRemove += mfp.st.mainClass + ' ';
|
|
}
|
|
|
|
mfp._removeClassFromMFP(classesToRemove);
|
|
|
|
if(mfp.fixedContentPos) {
|
|
var windowStyles = {marginRight: ''};
|
|
if(mfp.isIE7) {
|
|
$('body, html').css('overflow', '');
|
|
} else {
|
|
windowStyles.overflow = '';
|
|
}
|
|
$('html').css(windowStyles);
|
|
}
|
|
|
|
_document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS);
|
|
mfp.ev.off(EVENT_NS);
|
|
|
|
// clean up DOM elements that aren't removed
|
|
mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style');
|
|
mfp.bgOverlay.attr('class', 'mfp-bg');
|
|
mfp.container.attr('class', 'mfp-container');
|
|
|
|
// remove close button from target element
|
|
if(mfp.st.showCloseBtn &&
|
|
(!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) {
|
|
if(mfp.currTemplate.closeBtn)
|
|
mfp.currTemplate.closeBtn.detach();
|
|
}
|
|
|
|
|
|
if(mfp._lastFocusedEl) {
|
|
$(mfp._lastFocusedEl).focus(); // put tab focus back
|
|
}
|
|
mfp.currItem = null;
|
|
mfp.content = null;
|
|
mfp.currTemplate = null;
|
|
mfp.prevHeight = 0;
|
|
|
|
_mfpTrigger(AFTER_CLOSE_EVENT);
|
|
},
|
|
|
|
updateSize: function(winHeight) {
|
|
|
|
if(mfp.isIOS) {
|
|
// fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
|
|
var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
|
|
var height = window.innerHeight * zoomLevel;
|
|
mfp.wrap.css('height', height);
|
|
mfp.wH = height;
|
|
} else {
|
|
mfp.wH = winHeight || _window.height();
|
|
}
|
|
// Fixes #84: popup incorrectly positioned with position:relative on body
|
|
if(!mfp.fixedContentPos) {
|
|
mfp.wrap.css('height', mfp.wH);
|
|
}
|
|
|
|
_mfpTrigger('Resize');
|
|
|
|
},
|
|
|
|
/**
|
|
* Set content of popup based on current index
|
|
*/
|
|
updateItemHTML: function() {
|
|
var item = mfp.items[mfp.index];
|
|
|
|
// Detach and perform modifications
|
|
mfp.contentContainer.detach();
|
|
|
|
if(mfp.content)
|
|
mfp.content.detach();
|
|
|
|
if(!item.parsed) {
|
|
item = mfp.parseEl( mfp.index );
|
|
}
|
|
|
|
var type = item.type;
|
|
|
|
_mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]);
|
|
// BeforeChange event works like so:
|
|
// _mfpOn('BeforeChange', function(e, prevType, newType) { });
|
|
|
|
mfp.currItem = item;
|
|
|
|
|
|
|
|
|
|
|
|
if(!mfp.currTemplate[type]) {
|
|
var markup = mfp.st[type] ? mfp.st[type].markup : false;
|
|
|
|
// allows to modify markup
|
|
_mfpTrigger('FirstMarkupParse', markup);
|
|
|
|
if(markup) {
|
|
mfp.currTemplate[type] = $(markup);
|
|
} else {
|
|
// if there is no markup found we just define that template is parsed
|
|
mfp.currTemplate[type] = true;
|
|
}
|
|
}
|
|
|
|
if(_prevContentType && _prevContentType !== item.type) {
|
|
mfp.container.removeClass('mfp-'+_prevContentType+'-holder');
|
|
}
|
|
|
|
var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]);
|
|
mfp.appendContent(newContent, type);
|
|
|
|
item.preloaded = true;
|
|
|
|
_mfpTrigger(CHANGE_EVENT, item);
|
|
_prevContentType = item.type;
|
|
|
|
// Append container back after its content changed
|
|
mfp.container.prepend(mfp.contentContainer);
|
|
|
|
_mfpTrigger('AfterChange');
|
|
},
|
|
|
|
|
|
/**
|
|
* Set HTML content of popup
|
|
*/
|
|
appendContent: function(newContent, type) {
|
|
mfp.content = newContent;
|
|
|
|
if(newContent) {
|
|
if(mfp.st.showCloseBtn && mfp.st.closeBtnInside &&
|
|
mfp.currTemplate[type] === true) {
|
|
// if there is no markup, we just append close button element inside
|
|
if(!mfp.content.find('.mfp-close').length) {
|
|
mfp.content.append(_getCloseBtn());
|
|
}
|
|
} else {
|
|
mfp.content = newContent;
|
|
}
|
|
} else {
|
|
mfp.content = '';
|
|
}
|
|
|
|
_mfpTrigger(BEFORE_APPEND_EVENT);
|
|
mfp.container.addClass('mfp-'+type+'-holder');
|
|
|
|
mfp.contentContainer.append(mfp.content);
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Creates Magnific Popup data object based on given data
|
|
* @param {int} index Index of item to parse
|
|
*/
|
|
parseEl: function(index) {
|
|
var item = mfp.items[index],
|
|
type;
|
|
|
|
if(item.tagName) {
|
|
item = { el: $(item) };
|
|
} else {
|
|
type = item.type;
|
|
item = { data: item, src: item.src };
|
|
}
|
|
|
|
if(item.el) {
|
|
var types = mfp.types;
|
|
|
|
// check for 'mfp-TYPE' class
|
|
for(var i = 0; i < types.length; i++) {
|
|
if( item.el.hasClass('mfp-'+types[i]) ) {
|
|
type = types[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
item.src = item.el.attr('data-mfp-src');
|
|
if(!item.src) {
|
|
item.src = item.el.attr('href');
|
|
}
|
|
}
|
|
|
|
item.type = type || mfp.st.type || 'inline';
|
|
item.index = index;
|
|
item.parsed = true;
|
|
mfp.items[index] = item;
|
|
_mfpTrigger('ElementParse', item);
|
|
|
|
return mfp.items[index];
|
|
},
|
|
|
|
|
|
/**
|
|
* Initializes single popup or a group of popups
|
|
*/
|
|
addGroup: function(el, options) {
|
|
var eHandler = function(e) {
|
|
e.mfpEl = this;
|
|
mfp._openClick(e, el, options);
|
|
};
|
|
|
|
if(!options) {
|
|
options = {};
|
|
}
|
|
|
|
var eName = 'click.magnificPopup';
|
|
options.mainEl = el;
|
|
|
|
if(options.items) {
|
|
options.isObj = true;
|
|
el.off(eName).on(eName, eHandler);
|
|
} else {
|
|
options.isObj = false;
|
|
if(options.delegate) {
|
|
el.off(eName).on(eName, options.delegate , eHandler);
|
|
} else {
|
|
options.items = el;
|
|
el.off(eName).on(eName, eHandler);
|
|
}
|
|
}
|
|
},
|
|
_openClick: function(e, el, options) {
|
|
var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick;
|
|
|
|
|
|
if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey ) ) {
|
|
return;
|
|
}
|
|
|
|
var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn;
|
|
|
|
if(disableOn) {
|
|
if($.isFunction(disableOn)) {
|
|
if( !disableOn.call(mfp) ) {
|
|
return true;
|
|
}
|
|
} else { // else it's number
|
|
if( _window.width() < disableOn ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(e.type) {
|
|
e.preventDefault();
|
|
|
|
// This will prevent popup from closing if element is inside and popup is already opened
|
|
if(mfp.isOpen) {
|
|
e.stopPropagation();
|
|
}
|
|
}
|
|
|
|
|
|
options.el = $(e.mfpEl);
|
|
if(options.delegate) {
|
|
options.items = el.find(options.delegate);
|
|
}
|
|
mfp.open(options);
|
|
},
|
|
|
|
|
|
/**
|
|
* Updates text on preloader
|
|
*/
|
|
updateStatus: function(status, text) {
|
|
|
|
if(mfp.preloader) {
|
|
if(_prevStatus !== status) {
|
|
mfp.container.removeClass('mfp-s-'+_prevStatus);
|
|
}
|
|
|
|
if(!text && status === 'loading') {
|
|
text = mfp.st.tLoading;
|
|
}
|
|
|
|
var data = {
|
|
status: status,
|
|
text: text
|
|
};
|
|
// allows to modify status
|
|
_mfpTrigger('UpdateStatus', data);
|
|
|
|
status = data.status;
|
|
text = data.text;
|
|
|
|
mfp.preloader.html(text);
|
|
|
|
mfp.preloader.find('a').on('click', function(e) {
|
|
e.stopImmediatePropagation();
|
|
});
|
|
|
|
mfp.container.addClass('mfp-s-'+status);
|
|
_prevStatus = status;
|
|
}
|
|
},
|
|
|
|
|
|
/*
|
|
"Private" helpers that aren't private at all
|
|
*/
|
|
// Check to close popup or not
|
|
// "target" is an element that was clicked
|
|
_checkIfClose: function(target) {
|
|
|
|
if($(target).hasClass(PREVENT_CLOSE_CLASS)) {
|
|
return;
|
|
}
|
|
|
|
var closeOnContent = mfp.st.closeOnContentClick;
|
|
var closeOnBg = mfp.st.closeOnBgClick;
|
|
|
|
if(closeOnContent && closeOnBg) {
|
|
return true;
|
|
} else {
|
|
|
|
// We close the popup if click is on close button or on preloader. Or if there is no content.
|
|
if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) {
|
|
return true;
|
|
}
|
|
|
|
// if click is outside the content
|
|
if( (target !== mfp.content[0] && !$.contains(mfp.content[0], target)) ) {
|
|
if(closeOnBg) {
|
|
// last check, if the clicked element is in DOM, (in case it's removed onclick)
|
|
if( $.contains(document, target) ) {
|
|
return true;
|
|
}
|
|
}
|
|
} else if(closeOnContent) {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
return false;
|
|
},
|
|
_addClassToMFP: function(cName) {
|
|
mfp.bgOverlay.addClass(cName);
|
|
mfp.wrap.addClass(cName);
|
|
},
|
|
_removeClassFromMFP: function(cName) {
|
|
this.bgOverlay.removeClass(cName);
|
|
mfp.wrap.removeClass(cName);
|
|
},
|
|
_hasScrollBar: function(winHeight) {
|
|
return ( (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
|
|
},
|
|
_setFocus: function() {
|
|
(mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus();
|
|
},
|
|
_onFocusIn: function(e) {
|
|
if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
|
|
mfp._setFocus();
|
|
return false;
|
|
}
|
|
},
|
|
_parseMarkup: function(template, values, item) {
|
|
var arr;
|
|
if(item.data) {
|
|
values = $.extend(item.data, values);
|
|
}
|
|
_mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );
|
|
|
|
$.each(values, function(key, value) {
|
|
if(value === undefined || value === false) {
|
|
return true;
|
|
}
|
|
arr = key.split('_');
|
|
if(arr.length > 1) {
|
|
var el = template.find(EVENT_NS + '-'+arr[0]);
|
|
|
|
if(el.length > 0) {
|
|
var attr = arr[1];
|
|
if(attr === 'replaceWith') {
|
|
if(el[0] !== value[0]) {
|
|
el.replaceWith(value);
|
|
}
|
|
} else if(attr === 'img') {
|
|
if(el.is('img')) {
|
|
el.attr('src', value);
|
|
} else {
|
|
el.replaceWith( '<img src="'+value+'" class="' + el.attr('class') + '" />' );
|
|
}
|
|
} else {
|
|
el.attr(arr[1], value);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
template.find(EVENT_NS + '-'+key).html(value);
|
|
}
|
|
});
|
|
},
|
|
|
|
_getScrollbarSize: function() {
|
|
// thx David
|
|
if(mfp.scrollbarSize === undefined) {
|
|
var scrollDiv = document.createElement("div");
|
|
scrollDiv.id = "mfp-sbm";
|
|
scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
|
|
document.body.appendChild(scrollDiv);
|
|
mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
document.body.removeChild(scrollDiv);
|
|
}
|
|
return mfp.scrollbarSize;
|
|
}
|
|
|
|
}; /* MagnificPopup core prototype end */
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Public static functions
|
|
*/
|
|
$.magnificPopup = {
|
|
instance: null,
|
|
proto: MagnificPopup.prototype,
|
|
modules: [],
|
|
|
|
open: function(options, index) {
|
|
_checkInstance();
|
|
|
|
if(!options) {
|
|
options = {};
|
|
} else {
|
|
options = $.extend(true, {}, options);
|
|
}
|
|
|
|
|
|
options.isObj = true;
|
|
options.index = index || 0;
|
|
return this.instance.open(options);
|
|
},
|
|
|
|
close: function() {
|
|
return $.magnificPopup.instance && $.magnificPopup.instance.close();
|
|
},
|
|
|
|
registerModule: function(name, module) {
|
|
if(module.options) {
|
|
$.magnificPopup.defaults[name] = module.options;
|
|
}
|
|
$.extend(this.proto, module.proto);
|
|
this.modules.push(name);
|
|
},
|
|
|
|
defaults: {
|
|
|
|
// Info about options is in docs:
|
|
// http://dimsemenov.com/plugins/magnific-popup/documentation.html#options
|
|
|
|
disableOn: 0,
|
|
|
|
key: null,
|
|
|
|
midClick: false,
|
|
|
|
mainClass: '',
|
|
|
|
preloader: true,
|
|
|
|
focus: '', // CSS selector of input to focus after popup is opened
|
|
|
|
closeOnContentClick: false,
|
|
|
|
closeOnBgClick: true,
|
|
|
|
closeBtnInside: true,
|
|
|
|
showCloseBtn: true,
|
|
|
|
enableEscapeKey: true,
|
|
|
|
modal: false,
|
|
|
|
alignTop: false,
|
|
|
|
removalDelay: 0,
|
|
|
|
prependTo: null,
|
|
|
|
fixedContentPos: 'auto',
|
|
|
|
fixedBgPos: 'auto',
|
|
|
|
overflowY: 'auto',
|
|
|
|
closeMarkup: '<button title="%title%" type="button" class="mfp-close">×</button>',
|
|
|
|
tClose: 'Close (Esc)',
|
|
|
|
tLoading: 'Loading...'
|
|
|
|
}
|
|
};
|
|
|
|
|
|
|
|
$.fn.magnificPopup = function(options) {
|
|
_checkInstance();
|
|
|
|
var jqEl = $(this);
|
|
|
|
// We call some API method of first param is a string
|
|
if (typeof options === "string" ) {
|
|
|
|
if(options === 'open') {
|
|
var items,
|
|
itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
|
|
index = parseInt(arguments[1], 10) || 0;
|
|
|
|
if(itemOpts.items) {
|
|
items = itemOpts.items[index];
|
|
} else {
|
|
items = jqEl;
|
|
if(itemOpts.delegate) {
|
|
items = items.find(itemOpts.delegate);
|
|
}
|
|
items = items.eq( index );
|
|
}
|
|
mfp._openClick({mfpEl:items}, jqEl, itemOpts);
|
|
} else {
|
|
if(mfp.isOpen)
|
|
mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
|
|
}
|
|
|
|
} else {
|
|
// clone options obj
|
|
options = $.extend(true, {}, options);
|
|
|
|
/*
|
|
* As Zepto doesn't support .data() method for objects
|
|
* and it works only in normal browsers
|
|
* we assign "options" object directly to the DOM element. FTW!
|
|
*/
|
|
if(_isJQ) {
|
|
jqEl.data('magnificPopup', options);
|
|
} else {
|
|
jqEl[0].magnificPopup = options;
|
|
}
|
|
|
|
mfp.addGroup(jqEl, options);
|
|
|
|
}
|
|
return jqEl;
|
|
};
|
|
|
|
|
|
//Quick benchmark
|
|
/*
|
|
var start = performance.now(),
|
|
i,
|
|
rounds = 1000;
|
|
|
|
for(i = 0; i < rounds; i++) {
|
|
|
|
}
|
|
console.log('Test #1:', performance.now() - start);
|
|
|
|
start = performance.now();
|
|
for(i = 0; i < rounds; i++) {
|
|
|
|
}
|
|
console.log('Test #2:', performance.now() - start);
|
|
*/
|
|
|
|
|
|
/*>>core*/
|
|
|
|
/*>>inline*/
|
|
|
|
var INLINE_NS = 'inline',
|
|
_hiddenClass,
|
|
_inlinePlaceholder,
|
|
_lastInlineElement,
|
|
_putInlineElementsBack = function() {
|
|
if(_lastInlineElement) {
|
|
_inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
|
|
_lastInlineElement = null;
|
|
}
|
|
};
|
|
|
|
$.magnificPopup.registerModule(INLINE_NS, {
|
|
options: {
|
|
hiddenClass: 'hide', // will be appended with `mfp-` prefix
|
|
markup: '',
|
|
tNotFound: 'Content not found'
|
|
},
|
|
proto: {
|
|
|
|
initInline: function() {
|
|
mfp.types.push(INLINE_NS);
|
|
|
|
_mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
|
|
_putInlineElementsBack();
|
|
});
|
|
},
|
|
|
|
getInline: function(item, template) {
|
|
|
|
_putInlineElementsBack();
|
|
|
|
if(item.src) {
|
|
var inlineSt = mfp.st.inline,
|
|
el = $(item.src);
|
|
|
|
if(el.length) {
|
|
|
|
// If target element has parent - we replace it with placeholder and put it back after popup is closed
|
|
var parent = el[0].parentNode;
|
|
if(parent && parent.tagName) {
|
|
if(!_inlinePlaceholder) {
|
|
_hiddenClass = inlineSt.hiddenClass;
|
|
_inlinePlaceholder = _getEl(_hiddenClass);
|
|
_hiddenClass = 'mfp-'+_hiddenClass;
|
|
}
|
|
// replace target inline element with placeholder
|
|
_lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
|
|
}
|
|
|
|
mfp.updateStatus('ready');
|
|
} else {
|
|
mfp.updateStatus('error', inlineSt.tNotFound);
|
|
el = $('<div>');
|
|
}
|
|
|
|
item.inlineElement = el;
|
|
return el;
|
|
}
|
|
|
|
mfp.updateStatus('ready');
|
|
mfp._parseMarkup(template, {}, item);
|
|
return template;
|
|
}
|
|
}
|
|
});
|
|
|
|
/*>>inline*/
|
|
|
|
/*>>ajax*/
|
|
var AJAX_NS = 'ajax',
|
|
_ajaxCur,
|
|
_removeAjaxCursor = function() {
|
|
if(_ajaxCur) {
|
|
_body.removeClass(_ajaxCur);
|
|
}
|
|
},
|
|
_destroyAjaxRequest = function() {
|
|
_removeAjaxCursor();
|
|
if(mfp.req) {
|
|
mfp.req.abort();
|
|
}
|
|
};
|
|
|
|
$.magnificPopup.registerModule(AJAX_NS, {
|
|
|
|
options: {
|
|
settings: null,
|
|
cursor: 'mfp-ajax-cur',
|
|
tError: '<a href="%url%">The content</a> could not be loaded.'
|
|
},
|
|
|
|
proto: {
|
|
initAjax: function() {
|
|
mfp.types.push(AJAX_NS);
|
|
_ajaxCur = mfp.st.ajax.cursor;
|
|
|
|
_mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
|
|
_mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
|
|
},
|
|
getAjax: function(item) {
|
|
|
|
if(_ajaxCur)
|
|
_body.addClass(_ajaxCur);
|
|
|
|
mfp.updateStatus('loading');
|
|
|
|
var opts = $.extend({
|
|
url: item.src,
|
|
success: function(data, textStatus, jqXHR) {
|
|
var temp = {
|
|
data:data,
|
|
xhr:jqXHR
|
|
};
|
|
|
|
_mfpTrigger('ParseAjax', temp);
|
|
|
|
mfp.appendContent( $(temp.data), AJAX_NS );
|
|
|
|
item.finished = true;
|
|
|
|
_removeAjaxCursor();
|
|
|
|
mfp._setFocus();
|
|
|
|
setTimeout(function() {
|
|
mfp.wrap.addClass(READY_CLASS);
|
|
}, 16);
|
|
|
|
mfp.updateStatus('ready');
|
|
|
|
_mfpTrigger('AjaxContentAdded');
|
|
},
|
|
error: function() {
|
|
_removeAjaxCursor();
|
|
item.finished = item.loadError = true;
|
|
mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
|
|
}
|
|
}, mfp.st.ajax.settings);
|
|
|
|
mfp.req = $.ajax(opts);
|
|
|
|
return '';
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*>>ajax*/
|
|
|
|
/*>>image*/
|
|
var _imgInterval,
|
|
_getTitle = function(item) {
|
|
if(item.data && item.data.title !== undefined)
|
|
return item.data.title;
|
|
|
|
var src = mfp.st.image.titleSrc;
|
|
|
|
if(src) {
|
|
if($.isFunction(src)) {
|
|
return src.call(mfp, item);
|
|
} else if(item.el) {
|
|
return item.el.attr(src) || '';
|
|
}
|
|
}
|
|
return '';
|
|
};
|
|
|
|
$.magnificPopup.registerModule('image', {
|
|
|
|
options: {
|
|
markup: '<div class="mfp-figure">'+
|
|
'<div class="mfp-close"></div>'+
|
|
'<figure>'+
|
|
'<div class="mfp-img"></div>'+
|
|
'<figcaption>'+
|
|
'<div class="mfp-bottom-bar">'+
|
|
'<div class="mfp-title"></div>'+
|
|
'<div class="mfp-counter"></div>'+
|
|
'</div>'+
|
|
'</figcaption>'+
|
|
'</figure>'+
|
|
'</div>',
|
|
cursor: 'mfp-zoom-out-cur',
|
|
titleSrc: 'title',
|
|
verticalFit: true,
|
|
tError: '<a href="%url%">The image</a> could not be loaded.'
|
|
},
|
|
|
|
proto: {
|
|
initImage: function() {
|
|
var imgSt = mfp.st.image,
|
|
ns = '.image';
|
|
|
|
mfp.types.push('image');
|
|
|
|
_mfpOn(OPEN_EVENT+ns, function() {
|
|
if(mfp.currItem.type === 'image' && imgSt.cursor) {
|
|
_body.addClass(imgSt.cursor);
|
|
}
|
|
});
|
|
|
|
_mfpOn(CLOSE_EVENT+ns, function() {
|
|
if(imgSt.cursor) {
|
|
_body.removeClass(imgSt.cursor);
|
|
}
|
|
_window.off('resize' + EVENT_NS);
|
|
});
|
|
|
|
_mfpOn('Resize'+ns, mfp.resizeImage);
|
|
if(mfp.isLowIE) {
|
|
_mfpOn('AfterChange', mfp.resizeImage);
|
|
}
|
|
},
|
|
resizeImage: function() {
|
|
var item = mfp.currItem;
|
|
if(!item || !item.img) return;
|
|
|
|
if(mfp.st.image.verticalFit) {
|
|
var decr = 0;
|
|
// fix box-sizing in ie7/8
|
|
if(mfp.isLowIE) {
|
|
decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
|
|
}
|
|
item.img.css('max-height', mfp.wH-decr);
|
|
}
|
|
},
|
|
_onImageHasSize: function(item) {
|
|
if(item.img) {
|
|
|
|
item.hasSize = true;
|
|
|
|
if(_imgInterval) {
|
|
clearInterval(_imgInterval);
|
|
}
|
|
|
|
item.isCheckingImgSize = false;
|
|
|
|
_mfpTrigger('ImageHasSize', item);
|
|
|
|
if(item.imgHidden) {
|
|
if(mfp.content)
|
|
mfp.content.removeClass('mfp-loading');
|
|
|
|
item.imgHidden = false;
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Function that loops until the image has size to display elements that rely on it asap
|
|
*/
|
|
findImageSize: function(item) {
|
|
|
|
var counter = 0,
|
|
img = item.img[0],
|
|
mfpSetInterval = function(delay) {
|
|
|
|
if(_imgInterval) {
|
|
clearInterval(_imgInterval);
|
|
}
|
|
// decelerating interval that checks for size of an image
|
|
_imgInterval = setInterval(function() {
|
|
if(img.naturalWidth > 0) {
|
|
mfp._onImageHasSize(item);
|
|
return;
|
|
}
|
|
|
|
if(counter > 200) {
|
|
clearInterval(_imgInterval);
|
|
}
|
|
|
|
counter++;
|
|
if(counter === 3) {
|
|
mfpSetInterval(10);
|
|
} else if(counter === 40) {
|
|
mfpSetInterval(50);
|
|
} else if(counter === 100) {
|
|
mfpSetInterval(500);
|
|
}
|
|
}, delay);
|
|
};
|
|
|
|
mfpSetInterval(1);
|
|
},
|
|
|
|
getImage: function(item, template) {
|
|
|
|
var guard = 0,
|
|
|
|
// image load complete handler
|
|
onLoadComplete = function() {
|
|
if(item) {
|
|
if (item.img[0].complete) {
|
|
item.img.off('.mfploader');
|
|
|
|
if(item === mfp.currItem){
|
|
mfp._onImageHasSize(item);
|
|
|
|
mfp.updateStatus('ready');
|
|
}
|
|
|
|
item.hasSize = true;
|
|
item.loaded = true;
|
|
|
|
_mfpTrigger('ImageLoadComplete');
|
|
|
|
}
|
|
else {
|
|
// if image complete check fails 200 times (20 sec), we assume that there was an error.
|
|
guard++;
|
|
if(guard < 200) {
|
|
setTimeout(onLoadComplete,100);
|
|
} else {
|
|
onLoadError();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// image error handler
|
|
onLoadError = function() {
|
|
if(item) {
|
|
item.img.off('.mfploader');
|
|
if(item === mfp.currItem){
|
|
mfp._onImageHasSize(item);
|
|
mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
|
|
}
|
|
|
|
item.hasSize = true;
|
|
item.loaded = true;
|
|
item.loadError = true;
|
|
}
|
|
},
|
|
imgSt = mfp.st.image;
|
|
|
|
|
|
var el = template.find('.mfp-img');
|
|
if(el.length) {
|
|
var img = document.createElement('img');
|
|
img.className = 'mfp-img';
|
|
item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
|
|
img.src = item.src;
|
|
|
|
// without clone() "error" event is not firing when IMG is replaced by new IMG
|
|
// TODO: find a way to avoid such cloning
|
|
if(el.is('img')) {
|
|
item.img = item.img.clone();
|
|
}
|
|
|
|
img = item.img[0];
|
|
if(img.naturalWidth > 0) {
|
|
item.hasSize = true;
|
|
} else if(!img.width) {
|
|
item.hasSize = false;
|
|
}
|
|
}
|
|
|
|
mfp._parseMarkup(template, {
|
|
title: _getTitle(item),
|
|
img_replaceWith: item.img
|
|
}, item);
|
|
|
|
mfp.resizeImage();
|
|
|
|
if(item.hasSize) {
|
|
if(_imgInterval) clearInterval(_imgInterval);
|
|
|
|
if(item.loadError) {
|
|
template.addClass('mfp-loading');
|
|
mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
|
|
} else {
|
|
template.removeClass('mfp-loading');
|
|
mfp.updateStatus('ready');
|
|
}
|
|
return template;
|
|
}
|
|
|
|
mfp.updateStatus('loading');
|
|
item.loading = true;
|
|
|
|
if(!item.hasSize) {
|
|
item.imgHidden = true;
|
|
template.addClass('mfp-loading');
|
|
mfp.findImageSize(item);
|
|
}
|
|
|
|
return template;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
/*>>image*/
|
|
|
|
/*>>zoom*/
|
|
var hasMozTransform,
|
|
getHasMozTransform = function() {
|
|
if(hasMozTransform === undefined) {
|
|
hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
|
|
}
|
|
return hasMozTransform;
|
|
};
|
|
|
|
$.magnificPopup.registerModule('zoom', {
|
|
|
|
options: {
|
|
enabled: false,
|
|
easing: 'ease-in-out',
|
|
duration: 300,
|
|
opener: function(element) {
|
|
return element.is('img') ? element : element.find('img');
|
|
}
|
|
},
|
|
|
|
proto: {
|
|
|
|
initZoom: function() {
|
|
var zoomSt = mfp.st.zoom,
|
|
ns = '.zoom',
|
|
image;
|
|
|
|
if(!zoomSt.enabled || !mfp.supportsTransition) {
|
|
return;
|
|
}
|
|
|
|
var duration = zoomSt.duration,
|
|
getElToAnimate = function(image) {
|
|
var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
|
|
transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
|
|
cssObj = {
|
|
position: 'fixed',
|
|
zIndex: 9999,
|
|
left: 0,
|
|
top: 0,
|
|
'-webkit-backface-visibility': 'hidden'
|
|
},
|
|
t = 'transition';
|
|
|
|
cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
|
|
|
|
newImg.css(cssObj);
|
|
return newImg;
|
|
},
|
|
showMainContent = function() {
|
|
mfp.content.css('visibility', 'visible');
|
|
},
|
|
openTimeout,
|
|
animatedImg;
|
|
|
|
_mfpOn('BuildControls'+ns, function() {
|
|
if(mfp._allowZoom()) {
|
|
|
|
clearTimeout(openTimeout);
|
|
mfp.content.css('visibility', 'hidden');
|
|
|
|
// Basically, all code below does is clones existing image, puts in on top of the current one and animated it
|
|
|
|
image = mfp._getItemToZoom();
|
|
|
|
if(!image) {
|
|
showMainContent();
|
|
return;
|
|
}
|
|
|
|
animatedImg = getElToAnimate(image);
|
|
|
|
animatedImg.css( mfp._getOffset() );
|
|
|
|
mfp.wrap.append(animatedImg);
|
|
|
|
openTimeout = setTimeout(function() {
|
|
animatedImg.css( mfp._getOffset( true ) );
|
|
openTimeout = setTimeout(function() {
|
|
|
|
showMainContent();
|
|
|
|
setTimeout(function() {
|
|
animatedImg.remove();
|
|
image = animatedImg = null;
|
|
_mfpTrigger('ZoomAnimationEnded');
|
|
}, 16); // avoid blink when switching images
|
|
|
|
}, duration); // this timeout equals animation duration
|
|
|
|
}, 16); // by adding this timeout we avoid short glitch at the beginning of animation
|
|
|
|
|
|
// Lots of timeouts...
|
|
}
|
|
});
|
|
_mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
|
|
if(mfp._allowZoom()) {
|
|
|
|
clearTimeout(openTimeout);
|
|
|
|
mfp.st.removalDelay = duration;
|
|
|
|
if(!image) {
|
|
image = mfp._getItemToZoom();
|
|
if(!image) {
|
|
return;
|
|
}
|
|
animatedImg = getElToAnimate(image);
|
|
}
|
|
|
|
|
|
animatedImg.css( mfp._getOffset(true) );
|
|
mfp.wrap.append(animatedImg);
|
|
mfp.content.css('visibility', 'hidden');
|
|
|
|
setTimeout(function() {
|
|
animatedImg.css( mfp._getOffset() );
|
|
}, 16);
|
|
}
|
|
|
|
});
|
|
|
|
_mfpOn(CLOSE_EVENT+ns, function() {
|
|
if(mfp._allowZoom()) {
|
|
showMainContent();
|
|
if(animatedImg) {
|
|
animatedImg.remove();
|
|
}
|
|
image = null;
|
|
}
|
|
});
|
|
},
|
|
|
|
_allowZoom: function() {
|
|
return mfp.currItem.type === 'image';
|
|
},
|
|
|
|
_getItemToZoom: function() {
|
|
if(mfp.currItem.hasSize) {
|
|
return mfp.currItem.img;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
// Get element postion relative to viewport
|
|
_getOffset: function(isLarge) {
|
|
var el;
|
|
if(isLarge) {
|
|
el = mfp.currItem.img;
|
|
} else {
|
|
el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
|
|
}
|
|
|
|
var offset = el.offset();
|
|
var paddingTop = parseInt(el.css('padding-top'),10);
|
|
var paddingBottom = parseInt(el.css('padding-bottom'),10);
|
|
offset.top -= ( $(window).scrollTop() - paddingTop );
|
|
|
|
|
|
/*
|
|
|
|
Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
|
|
|
|
*/
|
|
var obj = {
|
|
width: el.width(),
|
|
// fix Zepto height+padding issue
|
|
height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
|
|
};
|
|
|
|
// I hate to do this, but there is no another option
|
|
if( getHasMozTransform() ) {
|
|
obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
|
|
} else {
|
|
obj.left = offset.left;
|
|
obj.top = offset.top;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
|
|
|
|
/*>>zoom*/
|
|
|
|
/*>>iframe*/
|
|
|
|
var IFRAME_NS = 'iframe',
|
|
_emptyPage = '//about:blank',
|
|
|
|
_fixIframeBugs = function(isShowing) {
|
|
if(mfp.currTemplate[IFRAME_NS]) {
|
|
var el = mfp.currTemplate[IFRAME_NS].find('iframe');
|
|
if(el.length) {
|
|
// reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
|
|
if(!isShowing) {
|
|
el[0].src = _emptyPage;
|
|
}
|
|
|
|
// IE8 black screen bug fix
|
|
if(mfp.isIE8) {
|
|
el.css('display', isShowing ? 'block' : 'none');
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
$.magnificPopup.registerModule(IFRAME_NS, {
|
|
|
|
options: {
|
|
markup: '<div class="mfp-iframe-scaler">'+
|
|
'<div class="mfp-close"></div>'+
|
|
'<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
|
|
'</div>',
|
|
|
|
srcAction: 'iframe_src',
|
|
|
|
// we don't care and support only one default type of URL by default
|
|
patterns: {
|
|
youtube: {
|
|
index: 'youtube.com',
|
|
id: 'v=',
|
|
src: '//www.youtube.com/embed/%id%?autoplay=1'
|
|
},
|
|
vimeo: {
|
|
index: 'vimeo.com/',
|
|
id: '/',
|
|
src: '//player.vimeo.com/video/%id%?autoplay=1'
|
|
},
|
|
gmaps: {
|
|
index: '//maps.google.',
|
|
src: '%id%&output=embed'
|
|
}
|
|
}
|
|
},
|
|
|
|
proto: {
|
|
initIframe: function() {
|
|
mfp.types.push(IFRAME_NS);
|
|
|
|
_mfpOn('BeforeChange', function(e, prevType, newType) {
|
|
if(prevType !== newType) {
|
|
if(prevType === IFRAME_NS) {
|
|
_fixIframeBugs(); // iframe if removed
|
|
} else if(newType === IFRAME_NS) {
|
|
_fixIframeBugs(true); // iframe is showing
|
|
}
|
|
}// else {
|
|
// iframe source is switched, don't do anything
|
|
//}
|
|
});
|
|
|
|
_mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
|
|
_fixIframeBugs();
|
|
});
|
|
},
|
|
|
|
getIframe: function(item, template) {
|
|
var embedSrc = item.src;
|
|
var iframeSt = mfp.st.iframe;
|
|
|
|
$.each(iframeSt.patterns, function() {
|
|
if(embedSrc.indexOf( this.index ) > -1) {
|
|
if(this.id) {
|
|
if(typeof this.id === 'string') {
|
|
embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
|
|
} else {
|
|
embedSrc = this.id.call( this, embedSrc );
|
|
}
|
|
}
|
|
embedSrc = this.src.replace('%id%', embedSrc );
|
|
return false; // break;
|
|
}
|
|
});
|
|
|
|
var dataObj = {};
|
|
if(iframeSt.srcAction) {
|
|
dataObj[iframeSt.srcAction] = embedSrc;
|
|
}
|
|
mfp._parseMarkup(template, dataObj, item);
|
|
|
|
mfp.updateStatus('ready');
|
|
|
|
return template;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
/*>>iframe*/
|
|
|
|
/*>>gallery*/
|
|
/**
|
|
* Get looped index depending on number of slides
|
|
*/
|
|
var _getLoopedId = function(index) {
|
|
var numSlides = mfp.items.length;
|
|
if(index > numSlides - 1) {
|
|
return index - numSlides;
|
|
} else if(index < 0) {
|
|
return numSlides + index;
|
|
}
|
|
return index;
|
|
},
|
|
_replaceCurrTotal = function(text, curr, total) {
|
|
return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
|
|
};
|
|
|
|
$.magnificPopup.registerModule('gallery', {
|
|
|
|
options: {
|
|
enabled: false,
|
|
arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
|
|
preload: [0,2],
|
|
navigateByImgClick: true,
|
|
arrows: true,
|
|
|
|
tPrev: 'Précédent',
|
|
tNext: 'Suivant',
|
|
tCounter: '%curr% de %total%'
|
|
},
|
|
|
|
proto: {
|
|
initGallery: function() {
|
|
|
|
var gSt = mfp.st.gallery,
|
|
ns = '.mfp-gallery',
|
|
supportsFastClick = Boolean($.fn.mfpFastClick);
|
|
|
|
mfp.direction = true; // true - next, false - prev
|
|
|
|
if(!gSt || !gSt.enabled ) return false;
|
|
|
|
_wrapClasses += ' mfp-gallery';
|
|
|
|
_mfpOn(OPEN_EVENT+ns, function() {
|
|
|
|
if(gSt.navigateByImgClick) {
|
|
mfp.wrap.on('click'+ns, '.mfp-img', function() {
|
|
if(mfp.items.length > 1) {
|
|
mfp.next();
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
_document.on('keydown'+ns, function(e) {
|
|
if (e.keyCode === 37) {
|
|
mfp.prev();
|
|
} else if (e.keyCode === 39) {
|
|
mfp.next();
|
|
}
|
|
});
|
|
});
|
|
|
|
_mfpOn('UpdateStatus'+ns, function(e, data) {
|
|
if(data.text) {
|
|
data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
|
|
}
|
|
});
|
|
|
|
_mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
|
|
var l = mfp.items.length;
|
|
values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
|
|
});
|
|
|
|
_mfpOn('BuildControls' + ns, function() {
|
|
if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
|
|
var markup = gSt.arrowMarkup,
|
|
arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
|
|
arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
|
|
|
|
var eName = supportsFastClick ? 'mfpFastClick' : 'click';
|
|
arrowLeft[eName](function() {
|
|
mfp.prev();
|
|
});
|
|
arrowRight[eName](function() {
|
|
mfp.next();
|
|
});
|
|
|
|
// Polyfill for :before and :after (adds elements with classes mfp-a and mfp-b)
|
|
if(mfp.isIE7) {
|
|
_getEl('b', arrowLeft[0], false, true);
|
|
_getEl('a', arrowLeft[0], false, true);
|
|
_getEl('b', arrowRight[0], false, true);
|
|
_getEl('a', arrowRight[0], false, true);
|
|
}
|
|
|
|
mfp.container.append(arrowLeft.add(arrowRight));
|
|
}
|
|
});
|
|
|
|
_mfpOn(CHANGE_EVENT+ns, function() {
|
|
if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
|
|
|
|
mfp._preloadTimeout = setTimeout(function() {
|
|
mfp.preloadNearbyImages();
|
|
mfp._preloadTimeout = null;
|
|
}, 16);
|
|
});
|
|
|
|
|
|
_mfpOn(CLOSE_EVENT+ns, function() {
|
|
_document.off(ns);
|
|
mfp.wrap.off('click'+ns);
|
|
|
|
if(mfp.arrowLeft && supportsFastClick) {
|
|
mfp.arrowLeft.add(mfp.arrowRight).destroyMfpFastClick();
|
|
}
|
|
mfp.arrowRight = mfp.arrowLeft = null;
|
|
});
|
|
|
|
},
|
|
next: function() {
|
|
mfp.direction = true;
|
|
mfp.index = _getLoopedId(mfp.index + 1);
|
|
mfp.updateItemHTML();
|
|
},
|
|
prev: function() {
|
|
mfp.direction = false;
|
|
mfp.index = _getLoopedId(mfp.index - 1);
|
|
mfp.updateItemHTML();
|
|
},
|
|
goTo: function(newIndex) {
|
|
mfp.direction = (newIndex >= mfp.index);
|
|
mfp.index = newIndex;
|
|
mfp.updateItemHTML();
|
|
},
|
|
preloadNearbyImages: function() {
|
|
var p = mfp.st.gallery.preload,
|
|
preloadBefore = Math.min(p[0], mfp.items.length),
|
|
preloadAfter = Math.min(p[1], mfp.items.length),
|
|
i;
|
|
|
|
for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
|
|
mfp._preloadItem(mfp.index+i);
|
|
}
|
|
for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
|
|
mfp._preloadItem(mfp.index-i);
|
|
}
|
|
},
|
|
_preloadItem: function(index) {
|
|
index = _getLoopedId(index);
|
|
|
|
if(mfp.items[index].preloaded) {
|
|
return;
|
|
}
|
|
|
|
var item = mfp.items[index];
|
|
if(!item.parsed) {
|
|
item = mfp.parseEl( index );
|
|
}
|
|
|
|
_mfpTrigger('LazyLoad', item);
|
|
|
|
if(item.type === 'image') {
|
|
item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
|
|
item.hasSize = true;
|
|
}).on('error.mfploader', function() {
|
|
item.hasSize = true;
|
|
item.loadError = true;
|
|
_mfpTrigger('LazyLoadError', item);
|
|
}).attr('src', item.src);
|
|
}
|
|
|
|
|
|
item.preloaded = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
/*
|
|
Touch Support that might be implemented some day
|
|
|
|
addSwipeGesture: function() {
|
|
var startX,
|
|
moved,
|
|
multipleTouches;
|
|
|
|
return;
|
|
|
|
var namespace = '.mfp',
|
|
addEventNames = function(pref, down, move, up, cancel) {
|
|
mfp._tStart = pref + down + namespace;
|
|
mfp._tMove = pref + move + namespace;
|
|
mfp._tEnd = pref + up + namespace;
|
|
mfp._tCancel = pref + cancel + namespace;
|
|
};
|
|
|
|
if(window.navigator.msPointerEnabled) {
|
|
addEventNames('MSPointer', 'Down', 'Move', 'Up', 'Cancel');
|
|
} else if('ontouchstart' in window) {
|
|
addEventNames('touch', 'start', 'move', 'end', 'cancel');
|
|
} else {
|
|
return;
|
|
}
|
|
_window.on(mfp._tStart, function(e) {
|
|
var oE = e.originalEvent;
|
|
multipleTouches = moved = false;
|
|
startX = oE.pageX || oE.changedTouches[0].pageX;
|
|
}).on(mfp._tMove, function(e) {
|
|
if(e.originalEvent.touches.length > 1) {
|
|
multipleTouches = e.originalEvent.touches.length;
|
|
} else {
|
|
//e.preventDefault();
|
|
moved = true;
|
|
}
|
|
}).on(mfp._tEnd + ' ' + mfp._tCancel, function(e) {
|
|
if(moved && !multipleTouches) {
|
|
var oE = e.originalEvent,
|
|
diff = startX - (oE.pageX || oE.changedTouches[0].pageX);
|
|
|
|
if(diff > 20) {
|
|
mfp.next();
|
|
} else if(diff < -20) {
|
|
mfp.prev();
|
|
}
|
|
}
|
|
});
|
|
},
|
|
*/
|
|
|
|
|
|
/*>>gallery*/
|
|
|
|
/*>>retina*/
|
|
|
|
var RETINA_NS = 'retina';
|
|
|
|
$.magnificPopup.registerModule(RETINA_NS, {
|
|
options: {
|
|
replaceSrc: function(item) {
|
|
return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
|
|
},
|
|
ratio: 1 // Function or number. Set to 1 to disable.
|
|
},
|
|
proto: {
|
|
initRetina: function() {
|
|
if(window.devicePixelRatio > 1) {
|
|
|
|
var st = mfp.st.retina,
|
|
ratio = st.ratio;
|
|
|
|
ratio = !isNaN(ratio) ? ratio : ratio();
|
|
|
|
if(ratio > 1) {
|
|
_mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
|
|
item.img.css({
|
|
'max-width': item.img[0].naturalWidth / ratio,
|
|
'width': '100%'
|
|
});
|
|
});
|
|
_mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
|
|
item.src = st.replaceSrc(item, ratio);
|
|
});
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
});
|
|
|
|
/*>>retina*/
|
|
|
|
/*>>fastclick*/
|
|
/**
|
|
* FastClick event implementation. (removes 300ms delay on touch devices)
|
|
* Based on https://developers.google.com/mobile/articles/fast_buttons
|
|
*
|
|
* You may use it outside the Magnific Popup by calling just:
|
|
*
|
|
* $('.your-el').mfpFastClick(function() {
|
|
* console.log('Clicked!');
|
|
* });
|
|
*
|
|
* To unbind:
|
|
* $('.your-el').destroyMfpFastClick();
|
|
*
|
|
*
|
|
* Note that it's a very basic and simple implementation, it blocks ghost click on the same element where it was bound.
|
|
* If you need something more advanced, use plugin by FT Labs https://github.com/ftlabs/fastclick
|
|
*
|
|
*/
|
|
|
|
(function() {
|
|
var ghostClickDelay = 1000,
|
|
supportsTouch = 'ontouchstart' in window,
|
|
unbindTouchMove = function() {
|
|
_window.off('touchmove'+ns+' touchend'+ns);
|
|
},
|
|
eName = 'mfpFastClick',
|
|
ns = '.'+eName;
|
|
|
|
|
|
// As Zepto.js doesn't have an easy way to add custom events (like jQuery), so we implement it in this way
|
|
$.fn.mfpFastClick = function(callback) {
|
|
|
|
return $(this).each(function() {
|
|
|
|
var elem = $(this),
|
|
lock;
|
|
|
|
if( supportsTouch ) {
|
|
|
|
var timeout,
|
|
startX,
|
|
startY,
|
|
pointerMoved,
|
|
point,
|
|
numPointers;
|
|
|
|
elem.on('touchstart' + ns, function(e) {
|
|
pointerMoved = false;
|
|
numPointers = 1;
|
|
|
|
point = e.originalEvent ? e.originalEvent.touches[0] : e.touches[0];
|
|
startX = point.clientX;
|
|
startY = point.clientY;
|
|
|
|
_window.on('touchmove'+ns, function(e) {
|
|
point = e.originalEvent ? e.originalEvent.touches : e.touches;
|
|
numPointers = point.length;
|
|
point = point[0];
|
|
if (Math.abs(point.clientX - startX) > 10 ||
|
|
Math.abs(point.clientY - startY) > 10) {
|
|
pointerMoved = true;
|
|
unbindTouchMove();
|
|
}
|
|
}).on('touchend'+ns, function(e) {
|
|
unbindTouchMove();
|
|
if(pointerMoved || numPointers > 1) {
|
|
return;
|
|
}
|
|
lock = true;
|
|
e.preventDefault();
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(function() {
|
|
lock = false;
|
|
}, ghostClickDelay);
|
|
callback();
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
elem.on('click' + ns, function() {
|
|
if(!lock) {
|
|
callback();
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
$.fn.destroyMfpFastClick = function() {
|
|
$(this).off('touchstart' + ns + ' click' + ns);
|
|
if(supportsTouch) _window.off('touchmove'+ns+' touchend'+ns);
|
|
};
|
|
})();
|
|
|
|
/*>>fastclick*/
|
|
_checkInstance(); })(window.jQuery || window.Zepto);
|
|
/**!
|
|
* easy-pie-chart
|
|
* Lightweight plugin to render simple, animated and retina optimized pie charts
|
|
*
|
|
* @license
|
|
* @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)
|
|
* @version 2.1.7
|
|
**/
|
|
|
|
(function (root, factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD. Register as an anonymous module unless amdModuleId is set
|
|
define(["jquery"], function (a0) {
|
|
return (factory(a0));
|
|
});
|
|
} else if (typeof exports === 'object') {
|
|
// Node. Does not work with strict CommonJS, but
|
|
// only CommonJS-like environments that support module.exports,
|
|
// like Node.
|
|
module.exports = factory(require("jquery"));
|
|
} else {
|
|
factory(jQuery);
|
|
}
|
|
}(this, function ($) {
|
|
|
|
/**
|
|
* Renderer to render the chart on a canvas object
|
|
* @param {DOMElement} el DOM element to host the canvas (root of the plugin)
|
|
* @param {object} options options object of the plugin
|
|
*/
|
|
var CanvasRenderer = function(el, options) {
|
|
var cachedBackground;
|
|
var canvas = document.createElement('canvas');
|
|
|
|
el.appendChild(canvas);
|
|
|
|
if (typeof(G_vmlCanvasManager) === 'object') {
|
|
G_vmlCanvasManager.initElement(canvas);
|
|
}
|
|
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
canvas.width = canvas.height = options.size;
|
|
|
|
// canvas on retina devices
|
|
var scaleBy = 1;
|
|
if (window.devicePixelRatio > 1) {
|
|
scaleBy = window.devicePixelRatio;
|
|
canvas.style.width = canvas.style.height = [options.size, 'px'].join('');
|
|
canvas.width = canvas.height = options.size * scaleBy;
|
|
ctx.scale(scaleBy, scaleBy);
|
|
}
|
|
|
|
// move 0,0 coordinates to the center
|
|
ctx.translate(options.size / 2, options.size / 2);
|
|
|
|
// rotate canvas -90deg
|
|
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);
|
|
|
|
var radius = (options.size - options.lineWidth) / 2;
|
|
if (options.scaleColor && options.scaleLength) {
|
|
radius -= options.scaleLength + 2; // 2 is the distance between scale and bar
|
|
}
|
|
|
|
// IE polyfill for Date
|
|
Date.now = Date.now || function() {
|
|
return +(new Date());
|
|
};
|
|
|
|
/**
|
|
* Draw a circle around the center of the canvas
|
|
* @param {strong} color Valid CSS color string
|
|
* @param {number} lineWidth Width of the line in px
|
|
* @param {number} percent Percentage to draw (float between -1 and 1)
|
|
*/
|
|
var drawCircle = function(color, lineWidth, percent) {
|
|
percent = Math.min(Math.max(-1, percent || 0), 1);
|
|
var isNegative = percent <= 0 ? true : false;
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);
|
|
|
|
ctx.strokeStyle = color;
|
|
ctx.lineWidth = lineWidth;
|
|
|
|
ctx.stroke();
|
|
};
|
|
|
|
/**
|
|
* Draw the scale of the chart
|
|
*/
|
|
var drawScale = function() {
|
|
var offset;
|
|
var length;
|
|
|
|
ctx.lineWidth = 1;
|
|
ctx.fillStyle = options.scaleColor;
|
|
|
|
ctx.save();
|
|
for (var i = 24; i > 0; --i) {
|
|
if (i % 6 === 0) {
|
|
length = options.scaleLength;
|
|
offset = 0;
|
|
} else {
|
|
length = options.scaleLength * 0.6;
|
|
offset = options.scaleLength - length;
|
|
}
|
|
ctx.fillRect(-options.size/2 + offset, 0, length, 1);
|
|
ctx.rotate(Math.PI / 12);
|
|
}
|
|
ctx.restore();
|
|
};
|
|
|
|
/**
|
|
* Request animation frame wrapper with polyfill
|
|
* @return {function} Request animation frame method or timeout fallback
|
|
*/
|
|
var reqAnimationFrame = (function() {
|
|
return window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
function(callback) {
|
|
window.setTimeout(callback, 1000 / 60);
|
|
};
|
|
}());
|
|
|
|
/**
|
|
* Draw the background of the plugin including the scale and the track
|
|
*/
|
|
var drawBackground = function() {
|
|
if(options.scaleColor) drawScale();
|
|
if(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);
|
|
};
|
|
|
|
/**
|
|
* Canvas accessor
|
|
*/
|
|
this.getCanvas = function() {
|
|
return canvas;
|
|
};
|
|
|
|
/**
|
|
* Canvas 2D context 'ctx' accessor
|
|
*/
|
|
this.getCtx = function() {
|
|
return ctx;
|
|
};
|
|
|
|
/**
|
|
* Clear the complete canvas
|
|
*/
|
|
this.clear = function() {
|
|
ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);
|
|
};
|
|
|
|
/**
|
|
* Draw the complete chart
|
|
* @param {number} percent Percent shown by the chart between -100 and 100
|
|
*/
|
|
this.draw = function(percent) {
|
|
// do we need to render a background
|
|
if (!!options.scaleColor || !!options.trackColor) {
|
|
// getImageData and putImageData are supported
|
|
if (ctx.getImageData && ctx.putImageData) {
|
|
if (!cachedBackground) {
|
|
drawBackground();
|
|
cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);
|
|
} else {
|
|
ctx.putImageData(cachedBackground, 0, 0);
|
|
}
|
|
} else {
|
|
this.clear();
|
|
drawBackground();
|
|
}
|
|
} else {
|
|
this.clear();
|
|
}
|
|
|
|
ctx.lineCap = options.lineCap;
|
|
|
|
// if barcolor is a function execute it and pass the percent as a value
|
|
var color;
|
|
if (typeof(options.barColor) === 'function') {
|
|
color = options.barColor(percent);
|
|
} else {
|
|
color = options.barColor;
|
|
}
|
|
|
|
// draw bar
|
|
drawCircle(color, options.lineWidth, percent / 100);
|
|
}.bind(this);
|
|
|
|
/**
|
|
* Animate from some percent to some other percentage
|
|
* @param {number} from Starting percentage
|
|
* @param {number} to Final percentage
|
|
*/
|
|
this.animate = function(from, to) {
|
|
var startTime = Date.now();
|
|
options.onStart(from, to);
|
|
var animation = function() {
|
|
var process = Math.min(Date.now() - startTime, options.animate.duration);
|
|
var currentValue = options.easing(this, process, from, to - from, options.animate.duration);
|
|
this.draw(currentValue);
|
|
options.onStep(from, to, currentValue);
|
|
if (process >= options.animate.duration) {
|
|
options.onStop(from, to);
|
|
} else {
|
|
reqAnimationFrame(animation);
|
|
}
|
|
}.bind(this);
|
|
|
|
reqAnimationFrame(animation);
|
|
}.bind(this);
|
|
};
|
|
|
|
var EasyPieChart = function(el, opts) {
|
|
var defaultOptions = {
|
|
barColor: '#ef1e25',
|
|
trackColor: '#f9f9f9',
|
|
scaleColor: '#dfe0e0',
|
|
scaleLength: 5,
|
|
lineCap: 'round',
|
|
lineWidth: 3,
|
|
trackWidth: undefined,
|
|
size: 110,
|
|
rotate: 0,
|
|
animate: {
|
|
duration: 1000,
|
|
enabled: true
|
|
},
|
|
easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/
|
|
t = t / (d/2);
|
|
if (t < 1) {
|
|
return c / 2 * t * t + b;
|
|
}
|
|
return -c/2 * ((--t)*(t-2) - 1) + b;
|
|
},
|
|
onStart: function(from, to) {
|
|
return;
|
|
},
|
|
onStep: function(from, to, currentValue) {
|
|
return;
|
|
},
|
|
onStop: function(from, to) {
|
|
return;
|
|
}
|
|
};
|
|
|
|
// detect present renderer
|
|
if (typeof(CanvasRenderer) !== 'undefined') {
|
|
defaultOptions.renderer = CanvasRenderer;
|
|
} else if (typeof(SVGRenderer) !== 'undefined') {
|
|
defaultOptions.renderer = SVGRenderer;
|
|
} else {
|
|
throw new Error('Please load either the SVG- or the CanvasRenderer');
|
|
}
|
|
|
|
var options = {};
|
|
var currentValue = 0;
|
|
|
|
/**
|
|
* Initialize the plugin by creating the options object and initialize rendering
|
|
*/
|
|
var init = function() {
|
|
this.el = el;
|
|
this.options = options;
|
|
|
|
// merge user options into default options
|
|
for (var i in defaultOptions) {
|
|
if (defaultOptions.hasOwnProperty(i)) {
|
|
options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];
|
|
if (typeof(options[i]) === 'function') {
|
|
options[i] = options[i].bind(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for jQuery easing
|
|
if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {
|
|
options.easing = jQuery.easing[options.easing];
|
|
} else {
|
|
options.easing = defaultOptions.easing;
|
|
}
|
|
|
|
// process earlier animate option to avoid bc breaks
|
|
if (typeof(options.animate) === 'number') {
|
|
options.animate = {
|
|
duration: options.animate,
|
|
enabled: true
|
|
};
|
|
}
|
|
|
|
if (typeof(options.animate) === 'boolean' && !options.animate) {
|
|
options.animate = {
|
|
duration: 1000,
|
|
enabled: options.animate
|
|
};
|
|
}
|
|
|
|
// create renderer
|
|
this.renderer = new options.renderer(el, options);
|
|
|
|
// initial draw
|
|
this.renderer.draw(currentValue);
|
|
|
|
// initial update
|
|
if (el.dataset && el.dataset.percent) {
|
|
this.update(parseFloat(el.dataset.percent));
|
|
} else if (el.getAttribute && el.getAttribute('data-percent')) {
|
|
this.update(parseFloat(el.getAttribute('data-percent')));
|
|
}
|
|
}.bind(this);
|
|
|
|
/**
|
|
* Update the value of the chart
|
|
* @param {number} newValue Number between 0 and 100
|
|
* @return {object} Instance of the plugin for method chaining
|
|
*/
|
|
this.update = function(newValue) {
|
|
newValue = parseFloat(newValue);
|
|
if (options.animate.enabled) {
|
|
this.renderer.animate(currentValue, newValue);
|
|
} else {
|
|
this.renderer.draw(newValue);
|
|
}
|
|
currentValue = newValue;
|
|
return this;
|
|
}.bind(this);
|
|
|
|
/**
|
|
* Disable animation
|
|
* @return {object} Instance of the plugin for method chaining
|
|
*/
|
|
this.disableAnimation = function() {
|
|
options.animate.enabled = false;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Enable animation
|
|
* @return {object} Instance of the plugin for method chaining
|
|
*/
|
|
this.enableAnimation = function() {
|
|
options.animate.enabled = true;
|
|
return this;
|
|
};
|
|
|
|
init();
|
|
};
|
|
|
|
$.fn.easyPieChart = function(options) {
|
|
return this.each(function() {
|
|
var instanceOptions;
|
|
|
|
if (!$.data(this, 'easyPieChart')) {
|
|
instanceOptions = $.extend({}, options, $(this).data());
|
|
$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
}));
|
|
|
|
/**
|
|
* Owl Carousel v2.2.1
|
|
* Copyright 2013-2017 David Deutsch
|
|
* Licensed under ()
|
|
*/
|
|
/**
|
|
* Owl carousel
|
|
* @version 2.1.6
|
|
* @author Bartosz Wojciechowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
* @todo Lazy Load Icon
|
|
* @todo prevent animationend bubling
|
|
* @todo itemsScaleUp
|
|
* @todo Test Zepto
|
|
* @todo stagePadding calculate wrong active classes
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates a carousel.
|
|
* @class The Owl Carousel.
|
|
* @public
|
|
* @param {HTMLElement|jQuery} element - The element to create the carousel for.
|
|
* @param {Object} [options] - The options
|
|
*/
|
|
function Owl(element, options) {
|
|
|
|
/**
|
|
* Current settings for the carousel.
|
|
* @public
|
|
*/
|
|
this.settings = null;
|
|
|
|
/**
|
|
* Current options set by the caller including defaults.
|
|
* @public
|
|
*/
|
|
this.options = $.extend({}, Owl.Defaults, options);
|
|
|
|
/**
|
|
* Plugin element.
|
|
* @public
|
|
*/
|
|
this.$element = $(element);
|
|
|
|
/**
|
|
* Proxied event handlers.
|
|
* @protected
|
|
*/
|
|
this._handlers = {};
|
|
|
|
/**
|
|
* References to the running plugins of this carousel.
|
|
* @protected
|
|
*/
|
|
this._plugins = {};
|
|
|
|
/**
|
|
* Currently suppressed events to prevent them from beeing retriggered.
|
|
* @protected
|
|
*/
|
|
this._supress = {};
|
|
|
|
/**
|
|
* Absolute current position.
|
|
* @protected
|
|
*/
|
|
this._current = null;
|
|
|
|
/**
|
|
* Animation speed in milliseconds.
|
|
* @protected
|
|
*/
|
|
this._speed = null;
|
|
|
|
/**
|
|
* Coordinates of all items in pixel.
|
|
* @todo The name of this member is missleading.
|
|
* @protected
|
|
*/
|
|
this._coordinates = [];
|
|
|
|
/**
|
|
* Current breakpoint.
|
|
* @todo Real media queries would be nice.
|
|
* @protected
|
|
*/
|
|
this._breakpoint = null;
|
|
|
|
/**
|
|
* Current width of the plugin element.
|
|
*/
|
|
this._width = null;
|
|
|
|
/**
|
|
* All real items.
|
|
* @protected
|
|
*/
|
|
this._items = [];
|
|
|
|
/**
|
|
* All cloned items.
|
|
* @protected
|
|
*/
|
|
this._clones = [];
|
|
|
|
/**
|
|
* Merge values of all items.
|
|
* @todo Maybe this could be part of a plugin.
|
|
* @protected
|
|
*/
|
|
this._mergers = [];
|
|
|
|
/**
|
|
* Widths of all items.
|
|
*/
|
|
this._widths = [];
|
|
|
|
/**
|
|
* Invalidated parts within the update process.
|
|
* @protected
|
|
*/
|
|
this._invalidated = {};
|
|
|
|
/**
|
|
* Ordered list of workers for the update process.
|
|
* @protected
|
|
*/
|
|
this._pipe = [];
|
|
|
|
/**
|
|
* Current state information for the drag operation.
|
|
* @todo #261
|
|
* @protected
|
|
*/
|
|
this._drag = {
|
|
time: null,
|
|
target: null,
|
|
pointer: null,
|
|
stage: {
|
|
start: null,
|
|
current: null
|
|
},
|
|
direction: null
|
|
};
|
|
|
|
/**
|
|
* Current state information and their tags.
|
|
* @type {Object}
|
|
* @protected
|
|
*/
|
|
this._states = {
|
|
current: {},
|
|
tags: {
|
|
'initializing': [ 'busy' ],
|
|
'animating': [ 'busy' ],
|
|
'dragging': [ 'interacting' ]
|
|
}
|
|
};
|
|
|
|
$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
|
|
this._handlers[handler] = $.proxy(this[handler], this);
|
|
}, this));
|
|
|
|
$.each(Owl.Plugins, $.proxy(function(key, plugin) {
|
|
this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
|
|
= new plugin(this);
|
|
}, this));
|
|
|
|
$.each(Owl.Workers, $.proxy(function(priority, worker) {
|
|
this._pipe.push({
|
|
'filter': worker.filter,
|
|
'run': $.proxy(worker.run, this)
|
|
});
|
|
}, this));
|
|
|
|
this.setup();
|
|
this.initialize();
|
|
}
|
|
|
|
/**
|
|
* Default options for the carousel.
|
|
* @public
|
|
*/
|
|
Owl.Defaults = {
|
|
items: 3,
|
|
loop: false,
|
|
center: false,
|
|
rewind: false,
|
|
|
|
mouseDrag: true,
|
|
touchDrag: true,
|
|
pullDrag: true,
|
|
freeDrag: false,
|
|
|
|
margin: 0,
|
|
stagePadding: 0,
|
|
|
|
merge: false,
|
|
mergeFit: true,
|
|
autoWidth: false,
|
|
|
|
startPosition: 0,
|
|
rtl: false,
|
|
|
|
smartSpeed: 250,
|
|
fluidSpeed: false,
|
|
dragEndSpeed: false,
|
|
|
|
responsive: {},
|
|
responsiveRefreshRate: 200,
|
|
responsiveBaseElement: window,
|
|
|
|
fallbackEasing: 'swing',
|
|
|
|
info: false,
|
|
|
|
nestedItemSelector: false,
|
|
itemElement: 'div',
|
|
stageElement: 'div',
|
|
|
|
refreshClass: 'owl-refresh',
|
|
loadedClass: 'owl-loaded',
|
|
loadingClass: 'owl-loading',
|
|
rtlClass: 'owl-rtl',
|
|
responsiveClass: 'owl-responsive',
|
|
dragClass: 'owl-drag',
|
|
itemClass: 'owl-item',
|
|
stageClass: 'owl-stage',
|
|
stageOuterClass: 'owl-stage-outer',
|
|
grabClass: 'owl-grab'
|
|
};
|
|
|
|
/**
|
|
* Enumeration for width.
|
|
* @public
|
|
* @readonly
|
|
* @enum {String}
|
|
*/
|
|
Owl.Width = {
|
|
Default: 'default',
|
|
Inner: 'inner',
|
|
Outer: 'outer'
|
|
};
|
|
|
|
/**
|
|
* Enumeration for types.
|
|
* @public
|
|
* @readonly
|
|
* @enum {String}
|
|
*/
|
|
Owl.Type = {
|
|
Event: 'event',
|
|
State: 'state'
|
|
};
|
|
|
|
/**
|
|
* Contains all registered plugins.
|
|
* @public
|
|
*/
|
|
Owl.Plugins = {};
|
|
|
|
/**
|
|
* List of workers involved in the update process.
|
|
*/
|
|
Owl.Workers = [ {
|
|
filter: [ 'width', 'settings' ],
|
|
run: function() {
|
|
this._width = this.$element.width();
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function(cache) {
|
|
cache.current = this._items && this._items[this.relative(this._current)];
|
|
}
|
|
}, {
|
|
filter: [ 'items', 'settings' ],
|
|
run: function() {
|
|
this.$stage.children('.cloned').remove();
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function(cache) {
|
|
var margin = this.settings.margin || '',
|
|
grid = !this.settings.autoWidth,
|
|
rtl = this.settings.rtl,
|
|
css = {
|
|
'width': 'auto',
|
|
'margin-left': rtl ? margin : '',
|
|
'margin-right': rtl ? '' : margin
|
|
};
|
|
|
|
!grid && this.$stage.children().css(css);
|
|
|
|
cache.css = css;
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function(cache) {
|
|
var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
|
|
merge = null,
|
|
iterator = this._items.length,
|
|
grid = !this.settings.autoWidth,
|
|
widths = [];
|
|
|
|
cache.items = {
|
|
merge: false,
|
|
width: width
|
|
};
|
|
|
|
while (iterator--) {
|
|
merge = this._mergers[iterator];
|
|
merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
|
|
|
|
cache.items.merge = merge > 1 || cache.items.merge;
|
|
|
|
widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
|
|
}
|
|
|
|
this._widths = widths;
|
|
}
|
|
}, {
|
|
filter: [ 'items', 'settings' ],
|
|
run: function() {
|
|
var clones = [],
|
|
items = this._items,
|
|
settings = this.settings,
|
|
// TODO: Should be computed from number of min width items in stage
|
|
view = Math.max(settings.items * 2, 4),
|
|
size = Math.ceil(items.length / 2) * 2,
|
|
repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
|
|
append = '',
|
|
prepend = '';
|
|
|
|
repeat /= 2;
|
|
|
|
while (repeat--) {
|
|
// Switch to only using appended clones
|
|
clones.push(this.normalize(clones.length / 2, true));
|
|
append = append + items[clones[clones.length - 1]][0].outerHTML;
|
|
clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
|
|
prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
|
|
}
|
|
|
|
this._clones = clones;
|
|
|
|
$(append).addClass('cloned').appendTo(this.$stage);
|
|
$(prepend).addClass('cloned').prependTo(this.$stage);
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function() {
|
|
var rtl = this.settings.rtl ? 1 : -1,
|
|
size = this._clones.length + this._items.length,
|
|
iterator = -1,
|
|
previous = 0,
|
|
current = 0,
|
|
coordinates = [];
|
|
|
|
while (++iterator < size) {
|
|
previous = coordinates[iterator - 1] || 0;
|
|
current = this._widths[this.relative(iterator)] + this.settings.margin;
|
|
coordinates.push(previous + current * rtl);
|
|
}
|
|
|
|
this._coordinates = coordinates;
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function() {
|
|
var padding = this.settings.stagePadding,
|
|
coordinates = this._coordinates,
|
|
css = {
|
|
'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
|
|
'padding-left': padding || '',
|
|
'padding-right': padding || ''
|
|
};
|
|
|
|
this.$stage.css(css);
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function(cache) {
|
|
var iterator = this._coordinates.length,
|
|
grid = !this.settings.autoWidth,
|
|
items = this.$stage.children();
|
|
|
|
if (grid && cache.items.merge) {
|
|
while (iterator--) {
|
|
cache.css.width = this._widths[this.relative(iterator)];
|
|
items.eq(iterator).css(cache.css);
|
|
}
|
|
} else if (grid) {
|
|
cache.css.width = cache.items.width;
|
|
items.css(cache.css);
|
|
}
|
|
}
|
|
}, {
|
|
filter: [ 'items' ],
|
|
run: function() {
|
|
this._coordinates.length < 1 && this.$stage.removeAttr('style');
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'items', 'settings' ],
|
|
run: function(cache) {
|
|
cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
|
|
cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
|
|
this.reset(cache.current);
|
|
}
|
|
}, {
|
|
filter: [ 'position' ],
|
|
run: function() {
|
|
this.animate(this.coordinates(this._current));
|
|
}
|
|
}, {
|
|
filter: [ 'width', 'position', 'items', 'settings' ],
|
|
run: function() {
|
|
var rtl = this.settings.rtl ? 1 : -1,
|
|
padding = this.settings.stagePadding * 2,
|
|
begin = this.coordinates(this.current()) + padding,
|
|
end = begin + this.width() * rtl,
|
|
inner, outer, matches = [], i, n;
|
|
|
|
for (i = 0, n = this._coordinates.length; i < n; i++) {
|
|
inner = this._coordinates[i - 1] || 0;
|
|
outer = Math.abs(this._coordinates[i]) + padding * rtl;
|
|
|
|
if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
|
|
|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
|
|
matches.push(i);
|
|
}
|
|
}
|
|
|
|
this.$stage.children('.active').removeClass('active');
|
|
this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
|
|
|
|
if (this.settings.center) {
|
|
this.$stage.children('.center').removeClass('center');
|
|
this.$stage.children().eq(this.current()).addClass('center');
|
|
}
|
|
}
|
|
} ];
|
|
|
|
/**
|
|
* Initializes the carousel.
|
|
* @protected
|
|
*/
|
|
Owl.prototype.initialize = function() {
|
|
this.enter('initializing');
|
|
this.trigger('initialize');
|
|
|
|
this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
|
|
|
|
if (this.settings.autoWidth && !this.is('pre-loading')) {
|
|
var imgs, nestedSelector, width;
|
|
imgs = this.$element.find('img');
|
|
nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
|
|
width = this.$element.children(nestedSelector).width();
|
|
|
|
if (imgs.length && width <= 0) {
|
|
this.preloadAutoWidthImages(imgs);
|
|
}
|
|
}
|
|
|
|
this.$element.addClass(this.options.loadingClass);
|
|
|
|
// create stage
|
|
this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
|
|
.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
|
|
|
|
// append stage
|
|
this.$element.append(this.$stage.parent());
|
|
|
|
// append content
|
|
this.replace(this.$element.children().not(this.$stage.parent()));
|
|
|
|
// check visibility
|
|
if (this.$element.is(':visible')) {
|
|
// update view
|
|
this.refresh();
|
|
} else {
|
|
// invalidate width
|
|
this.invalidate('width');
|
|
}
|
|
|
|
this.$element
|
|
.removeClass(this.options.loadingClass)
|
|
.addClass(this.options.loadedClass);
|
|
|
|
// register event handlers
|
|
this.registerEventHandlers();
|
|
|
|
this.leave('initializing');
|
|
this.trigger('initialized');
|
|
};
|
|
|
|
/**
|
|
* Setups the current settings.
|
|
* @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
|
|
* @todo Support for media queries by using `matchMedia` would be nice.
|
|
* @public
|
|
*/
|
|
Owl.prototype.setup = function() {
|
|
var viewport = this.viewport(),
|
|
overwrites = this.options.responsive,
|
|
match = -1,
|
|
settings = null;
|
|
|
|
if (!overwrites) {
|
|
settings = $.extend({}, this.options);
|
|
} else {
|
|
$.each(overwrites, function(breakpoint) {
|
|
if (breakpoint <= viewport && breakpoint > match) {
|
|
match = Number(breakpoint);
|
|
}
|
|
});
|
|
|
|
settings = $.extend({}, this.options, overwrites[match]);
|
|
if (typeof settings.stagePadding === 'function') {
|
|
settings.stagePadding = settings.stagePadding();
|
|
}
|
|
delete settings.responsive;
|
|
|
|
// responsive class
|
|
if (settings.responsiveClass) {
|
|
this.$element.attr('class',
|
|
this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
|
|
);
|
|
}
|
|
}
|
|
|
|
this.trigger('change', { property: { name: 'settings', value: settings } });
|
|
this._breakpoint = match;
|
|
this.settings = settings;
|
|
this.invalidate('settings');
|
|
this.trigger('changed', { property: { name: 'settings', value: this.settings } });
|
|
};
|
|
|
|
/**
|
|
* Updates option logic if necessery.
|
|
* @protected
|
|
*/
|
|
Owl.prototype.optionsLogic = function() {
|
|
if (this.settings.autoWidth) {
|
|
this.settings.stagePadding = false;
|
|
this.settings.merge = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Prepares an item before add.
|
|
* @todo Rename event parameter `content` to `item`.
|
|
* @protected
|
|
* @returns {jQuery|HTMLElement} - The item container.
|
|
*/
|
|
Owl.prototype.prepare = function(item) {
|
|
var event = this.trigger('prepare', { content: item });
|
|
|
|
if (!event.data) {
|
|
event.data = $('<' + this.settings.itemElement + '/>')
|
|
.addClass(this.options.itemClass).append(item)
|
|
}
|
|
|
|
this.trigger('prepared', { content: event.data });
|
|
|
|
return event.data;
|
|
};
|
|
|
|
/**
|
|
* Updates the view.
|
|
* @public
|
|
*/
|
|
Owl.prototype.update = function() {
|
|
var i = 0,
|
|
n = this._pipe.length,
|
|
filter = $.proxy(function(p) { return this[p] }, this._invalidated),
|
|
cache = {};
|
|
|
|
while (i < n) {
|
|
if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
|
|
this._pipe[i].run(cache);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
this._invalidated = {};
|
|
|
|
!this.is('valid') && this.enter('valid');
|
|
};
|
|
|
|
/**
|
|
* Gets the width of the view.
|
|
* @public
|
|
* @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
|
|
* @returns {Number} - The width of the view in pixel.
|
|
*/
|
|
Owl.prototype.width = function(dimension) {
|
|
dimension = dimension || Owl.Width.Default;
|
|
switch (dimension) {
|
|
case Owl.Width.Inner:
|
|
case Owl.Width.Outer:
|
|
return this._width;
|
|
default:
|
|
return this._width - this.settings.stagePadding * 2 + this.settings.margin;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Refreshes the carousel primarily for adaptive purposes.
|
|
* @public
|
|
*/
|
|
Owl.prototype.refresh = function() {
|
|
this.enter('refreshing');
|
|
this.trigger('refresh');
|
|
|
|
this.setup();
|
|
|
|
this.optionsLogic();
|
|
|
|
this.$element.addClass(this.options.refreshClass);
|
|
|
|
this.update();
|
|
|
|
this.$element.removeClass(this.options.refreshClass);
|
|
|
|
this.leave('refreshing');
|
|
this.trigger('refreshed');
|
|
};
|
|
|
|
/**
|
|
* Checks window `resize` event.
|
|
* @protected
|
|
*/
|
|
Owl.prototype.onThrottledResize = function() {
|
|
window.clearTimeout(this.resizeTimer);
|
|
this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
|
|
};
|
|
|
|
/**
|
|
* Checks window `resize` event.
|
|
* @protected
|
|
*/
|
|
Owl.prototype.onResize = function() {
|
|
if (!this._items.length) {
|
|
return false;
|
|
}
|
|
|
|
if (this._width === this.$element.width()) {
|
|
return false;
|
|
}
|
|
|
|
if (!this.$element.is(':visible')) {
|
|
return false;
|
|
}
|
|
|
|
this.enter('resizing');
|
|
|
|
if (this.trigger('resize').isDefaultPrevented()) {
|
|
this.leave('resizing');
|
|
return false;
|
|
}
|
|
|
|
this.invalidate('width');
|
|
|
|
this.refresh();
|
|
|
|
this.leave('resizing');
|
|
this.trigger('resized');
|
|
};
|
|
|
|
/**
|
|
* Registers event handlers.
|
|
* @todo Check `msPointerEnabled`
|
|
* @todo #261
|
|
* @protected
|
|
*/
|
|
Owl.prototype.registerEventHandlers = function() {
|
|
if ($.support.transition) {
|
|
this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
|
|
}
|
|
|
|
if (this.settings.responsive !== false) {
|
|
this.on(window, 'resize', this._handlers.onThrottledResize);
|
|
}
|
|
|
|
if (this.settings.mouseDrag) {
|
|
this.$element.addClass(this.options.dragClass);
|
|
this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
|
|
this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
|
|
}
|
|
|
|
if (this.settings.touchDrag){
|
|
this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
|
|
this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handles `touchstart` and `mousedown` events.
|
|
* @todo Horizontal swipe threshold as option
|
|
* @todo #261
|
|
* @protected
|
|
* @param {Event} event - The event arguments.
|
|
*/
|
|
Owl.prototype.onDragStart = function(event) {
|
|
var stage = null;
|
|
|
|
if (event.which === 3) {
|
|
return;
|
|
}
|
|
|
|
if ($.support.transform) {
|
|
stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
|
|
stage = {
|
|
x: stage[stage.length === 16 ? 12 : 4],
|
|
y: stage[stage.length === 16 ? 13 : 5]
|
|
};
|
|
} else {
|
|
stage = this.$stage.position();
|
|
stage = {
|
|
x: this.settings.rtl ?
|
|
stage.left + this.$stage.width() - this.width() + this.settings.margin :
|
|
stage.left,
|
|
y: stage.top
|
|
};
|
|
}
|
|
|
|
if (this.is('animating')) {
|
|
$.support.transform ? this.animate(stage.x) : this.$stage.stop()
|
|
this.invalidate('position');
|
|
}
|
|
|
|
this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
|
|
|
|
this.speed(0);
|
|
|
|
this._drag.time = new Date().getTime();
|
|
this._drag.target = $(event.target);
|
|
this._drag.stage.start = stage;
|
|
this._drag.stage.current = stage;
|
|
this._drag.pointer = this.pointer(event);
|
|
|
|
$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
|
|
|
|
$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
|
|
var delta = this.difference(this._drag.pointer, this.pointer(event));
|
|
|
|
$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
|
|
|
|
if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
|
|
return;
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
this.enter('dragging');
|
|
this.trigger('drag');
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Handles the `touchmove` and `mousemove` events.
|
|
* @todo #261
|
|
* @protected
|
|
* @param {Event} event - The event arguments.
|
|
*/
|
|
Owl.prototype.onDragMove = function(event) {
|
|
var minimum = null,
|
|
maximum = null,
|
|
pull = null,
|
|
delta = this.difference(this._drag.pointer, this.pointer(event)),
|
|
stage = this.difference(this._drag.stage.start, delta);
|
|
|
|
if (!this.is('dragging')) {
|
|
return;
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
if (this.settings.loop) {
|
|
minimum = this.coordinates(this.minimum());
|
|
maximum = this.coordinates(this.maximum() + 1) - minimum;
|
|
stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
|
|
} else {
|
|
minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
|
|
maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
|
|
pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
|
|
stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
|
|
}
|
|
|
|
this._drag.stage.current = stage;
|
|
|
|
this.animate(stage.x);
|
|
};
|
|
|
|
/**
|
|
* Handles the `touchend` and `mouseup` events.
|
|
* @todo #261
|
|
* @todo Threshold for click event
|
|
* @protected
|
|
* @param {Event} event - The event arguments.
|
|
*/
|
|
Owl.prototype.onDragEnd = function(event) {
|
|
var delta = this.difference(this._drag.pointer, this.pointer(event)),
|
|
stage = this._drag.stage.current,
|
|
direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
|
|
|
|
$(document).off('.owl.core');
|
|
|
|
this.$element.removeClass(this.options.grabClass);
|
|
|
|
if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
|
|
this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
|
|
this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
|
|
this.invalidate('position');
|
|
this.update();
|
|
|
|
this._drag.direction = direction;
|
|
|
|
if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
|
|
this._drag.target.one('click.owl.core', function() { return false; });
|
|
}
|
|
}
|
|
|
|
if (!this.is('dragging')) {
|
|
return;
|
|
}
|
|
|
|
this.leave('dragging');
|
|
this.trigger('dragged');
|
|
};
|
|
|
|
/**
|
|
* Gets absolute position of the closest item for a coordinate.
|
|
* @todo Setting `freeDrag` makes `closest` not reusable. See #165.
|
|
* @protected
|
|
* @param {Number} coordinate - The coordinate in pixel.
|
|
* @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
|
|
* @return {Number} - The absolute position of the closest item.
|
|
*/
|
|
Owl.prototype.closest = function(coordinate, direction) {
|
|
var position = -1,
|
|
pull = 30,
|
|
width = this.width(),
|
|
coordinates = this.coordinates();
|
|
|
|
if (!this.settings.freeDrag) {
|
|
// check closest item
|
|
$.each(coordinates, $.proxy(function(index, value) {
|
|
// on a left pull, check on current index
|
|
if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
|
|
position = index;
|
|
// on a right pull, check on previous index
|
|
// to do so, subtract width from value and set position = index + 1
|
|
} else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
|
|
position = index + 1;
|
|
} else if (this.op(coordinate, '<', value)
|
|
&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
|
|
position = direction === 'left' ? index + 1 : index;
|
|
}
|
|
return position === -1;
|
|
}, this));
|
|
}
|
|
|
|
if (!this.settings.loop) {
|
|
// non loop boundries
|
|
if (this.op(coordinate, '>', coordinates[this.minimum()])) {
|
|
position = coordinate = this.minimum();
|
|
} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
|
|
position = coordinate = this.maximum();
|
|
}
|
|
}
|
|
|
|
return position;
|
|
};
|
|
|
|
/**
|
|
* Animates the stage.
|
|
* @todo #270
|
|
* @public
|
|
* @param {Number} coordinate - The coordinate in pixels.
|
|
*/
|
|
Owl.prototype.animate = function(coordinate) {
|
|
var animate = this.speed() > 0;
|
|
|
|
this.is('animating') && this.onTransitionEnd();
|
|
|
|
if (animate) {
|
|
this.enter('animating');
|
|
this.trigger('translate');
|
|
}
|
|
|
|
if ($.support.transform3d && $.support.transition) {
|
|
this.$stage.css({
|
|
transform: 'translate3d(' + coordinate + 'px,0px,0px)',
|
|
transition: (this.speed() / 1000) + 's'
|
|
});
|
|
} else if (animate) {
|
|
this.$stage.animate({
|
|
left: coordinate + 'px'
|
|
}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
|
|
} else {
|
|
this.$stage.css({
|
|
left: coordinate + 'px'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Checks whether the carousel is in a specific state or not.
|
|
* @param {String} state - The state to check.
|
|
* @returns {Boolean} - The flag which indicates if the carousel is busy.
|
|
*/
|
|
Owl.prototype.is = function(state) {
|
|
return this._states.current[state] && this._states.current[state] > 0;
|
|
};
|
|
|
|
/**
|
|
* Sets the absolute position of the current item.
|
|
* @public
|
|
* @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
|
|
* @returns {Number} - The absolute position of the current item.
|
|
*/
|
|
Owl.prototype.current = function(position) {
|
|
if (position === undefined) {
|
|
return this._current;
|
|
}
|
|
|
|
if (this._items.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
position = this.normalize(position);
|
|
|
|
if (this._current !== position) {
|
|
var event = this.trigger('change', { property: { name: 'position', value: position } });
|
|
|
|
if (event.data !== undefined) {
|
|
position = this.normalize(event.data);
|
|
}
|
|
|
|
this._current = position;
|
|
|
|
this.invalidate('position');
|
|
|
|
this.trigger('changed', { property: { name: 'position', value: this._current } });
|
|
}
|
|
|
|
return this._current;
|
|
};
|
|
|
|
/**
|
|
* Invalidates the given part of the update routine.
|
|
* @param {String} [part] - The part to invalidate.
|
|
* @returns {Array.<String>} - The invalidated parts.
|
|
*/
|
|
Owl.prototype.invalidate = function(part) {
|
|
if ($.type(part) === 'string') {
|
|
this._invalidated[part] = true;
|
|
this.is('valid') && this.leave('valid');
|
|
}
|
|
return $.map(this._invalidated, function(v, i) { return i });
|
|
};
|
|
|
|
/**
|
|
* Resets the absolute position of the current item.
|
|
* @public
|
|
* @param {Number} position - The absolute position of the new item.
|
|
*/
|
|
Owl.prototype.reset = function(position) {
|
|
position = this.normalize(position);
|
|
|
|
if (position === undefined) {
|
|
return;
|
|
}
|
|
|
|
this._speed = 0;
|
|
this._current = position;
|
|
|
|
this.suppress([ 'translate', 'translated' ]);
|
|
|
|
this.animate(this.coordinates(position));
|
|
|
|
this.release([ 'translate', 'translated' ]);
|
|
};
|
|
|
|
/**
|
|
* Normalizes an absolute or a relative position of an item.
|
|
* @public
|
|
* @param {Number} position - The absolute or relative position to normalize.
|
|
* @param {Boolean} [relative=false] - Whether the given position is relative or not.
|
|
* @returns {Number} - The normalized position.
|
|
*/
|
|
Owl.prototype.normalize = function(position, relative) {
|
|
var n = this._items.length,
|
|
m = relative ? 0 : this._clones.length;
|
|
|
|
if (!this.isNumeric(position) || n < 1) {
|
|
position = undefined;
|
|
} else if (position < 0 || position >= n + m) {
|
|
position = ((position - m / 2) % n + n) % n + m / 2;
|
|
}
|
|
|
|
return position;
|
|
};
|
|
|
|
/**
|
|
* Converts an absolute position of an item into a relative one.
|
|
* @public
|
|
* @param {Number} position - The absolute position to convert.
|
|
* @returns {Number} - The converted position.
|
|
*/
|
|
Owl.prototype.relative = function(position) {
|
|
position -= this._clones.length / 2;
|
|
return this.normalize(position, true);
|
|
};
|
|
|
|
/**
|
|
* Gets the maximum position for the current item.
|
|
* @public
|
|
* @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
|
|
* @returns {Number}
|
|
*/
|
|
Owl.prototype.maximum = function(relative) {
|
|
var settings = this.settings,
|
|
maximum = this._coordinates.length,
|
|
iterator,
|
|
reciprocalItemsWidth,
|
|
elementWidth;
|
|
|
|
if (settings.loop) {
|
|
maximum = this._clones.length / 2 + this._items.length - 1;
|
|
} else if (settings.autoWidth || settings.merge) {
|
|
iterator = this._items.length;
|
|
reciprocalItemsWidth = this._items[--iterator].width();
|
|
elementWidth = this.$element.width();
|
|
while (iterator--) {
|
|
reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
|
|
if (reciprocalItemsWidth > elementWidth) {
|
|
break;
|
|
}
|
|
}
|
|
maximum = iterator + 1;
|
|
} else if (settings.center) {
|
|
maximum = this._items.length - 1;
|
|
} else {
|
|
maximum = this._items.length - settings.items;
|
|
}
|
|
|
|
if (relative) {
|
|
maximum -= this._clones.length / 2;
|
|
}
|
|
|
|
return Math.max(maximum, 0);
|
|
};
|
|
|
|
/**
|
|
* Gets the minimum position for the current item.
|
|
* @public
|
|
* @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
|
|
* @returns {Number}
|
|
*/
|
|
Owl.prototype.minimum = function(relative) {
|
|
return relative ? 0 : this._clones.length / 2;
|
|
};
|
|
|
|
/**
|
|
* Gets an item at the specified relative position.
|
|
* @public
|
|
* @param {Number} [position] - The relative position of the item.
|
|
* @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
|
|
*/
|
|
Owl.prototype.items = function(position) {
|
|
if (position === undefined) {
|
|
return this._items.slice();
|
|
}
|
|
|
|
position = this.normalize(position, true);
|
|
return this._items[position];
|
|
};
|
|
|
|
/**
|
|
* Gets an item at the specified relative position.
|
|
* @public
|
|
* @param {Number} [position] - The relative position of the item.
|
|
* @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
|
|
*/
|
|
Owl.prototype.mergers = function(position) {
|
|
if (position === undefined) {
|
|
return this._mergers.slice();
|
|
}
|
|
|
|
position = this.normalize(position, true);
|
|
return this._mergers[position];
|
|
};
|
|
|
|
/**
|
|
* Gets the absolute positions of clones for an item.
|
|
* @public
|
|
* @param {Number} [position] - The relative position of the item.
|
|
* @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
|
|
*/
|
|
Owl.prototype.clones = function(position) {
|
|
var odd = this._clones.length / 2,
|
|
even = odd + this._items.length,
|
|
map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
|
|
|
|
if (position === undefined) {
|
|
return $.map(this._clones, function(v, i) { return map(i) });
|
|
}
|
|
|
|
return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
|
|
};
|
|
|
|
/**
|
|
* Sets the current animation speed.
|
|
* @public
|
|
* @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
|
|
* @returns {Number} - The current animation speed in milliseconds.
|
|
*/
|
|
Owl.prototype.speed = function(speed) {
|
|
if (speed !== undefined) {
|
|
this._speed = speed;
|
|
}
|
|
|
|
return this._speed;
|
|
};
|
|
|
|
/**
|
|
* Gets the coordinate of an item.
|
|
* @todo The name of this method is missleanding.
|
|
* @public
|
|
* @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
|
|
* @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
|
|
*/
|
|
Owl.prototype.coordinates = function(position) {
|
|
var multiplier = 1,
|
|
newPosition = position - 1,
|
|
coordinate;
|
|
|
|
if (position === undefined) {
|
|
return $.map(this._coordinates, $.proxy(function(coordinate, index) {
|
|
return this.coordinates(index);
|
|
}, this));
|
|
}
|
|
|
|
if (this.settings.center) {
|
|
if (this.settings.rtl) {
|
|
multiplier = -1;
|
|
newPosition = position + 1;
|
|
}
|
|
|
|
coordinate = this._coordinates[position];
|
|
coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
|
|
} else {
|
|
coordinate = this._coordinates[newPosition] || 0;
|
|
}
|
|
|
|
coordinate = Math.ceil(coordinate);
|
|
|
|
return coordinate;
|
|
};
|
|
|
|
/**
|
|
* Calculates the speed for a translation.
|
|
* @protected
|
|
* @param {Number} from - The absolute position of the start item.
|
|
* @param {Number} to - The absolute position of the target item.
|
|
* @param {Number} [factor=undefined] - The time factor in milliseconds.
|
|
* @returns {Number} - The time in milliseconds for the translation.
|
|
*/
|
|
Owl.prototype.duration = function(from, to, factor) {
|
|
if (factor === 0) {
|
|
return 0;
|
|
}
|
|
|
|
return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
|
|
};
|
|
|
|
/**
|
|
* Slides to the specified item.
|
|
* @public
|
|
* @param {Number} position - The position of the item.
|
|
* @param {Number} [speed] - The time in milliseconds for the transition.
|
|
*/
|
|
Owl.prototype.to = function(position, speed) {
|
|
var current = this.current(),
|
|
revert = null,
|
|
distance = position - this.relative(current),
|
|
direction = (distance > 0) - (distance < 0),
|
|
items = this._items.length,
|
|
minimum = this.minimum(),
|
|
maximum = this.maximum();
|
|
|
|
if (this.settings.loop) {
|
|
if (!this.settings.rewind && Math.abs(distance) > items / 2) {
|
|
distance += direction * -1 * items;
|
|
}
|
|
|
|
position = current + distance;
|
|
revert = ((position - minimum) % items + items) % items + minimum;
|
|
|
|
if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
|
|
current = revert - distance;
|
|
position = revert;
|
|
this.reset(current);
|
|
}
|
|
} else if (this.settings.rewind) {
|
|
maximum += 1;
|
|
position = (position % maximum + maximum) % maximum;
|
|
} else {
|
|
position = Math.max(minimum, Math.min(maximum, position));
|
|
}
|
|
|
|
this.speed(this.duration(current, position, speed));
|
|
this.current(position);
|
|
|
|
if (this.$element.is(':visible')) {
|
|
this.update();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Slides to the next item.
|
|
* @public
|
|
* @param {Number} [speed] - The time in milliseconds for the transition.
|
|
*/
|
|
Owl.prototype.next = function(speed) {
|
|
speed = speed || false;
|
|
this.to(this.relative(this.current()) + 1, speed);
|
|
};
|
|
|
|
/**
|
|
* Slides to the previous item.
|
|
* @public
|
|
* @param {Number} [speed] - The time in milliseconds for the transition.
|
|
*/
|
|
Owl.prototype.prev = function(speed) {
|
|
speed = speed || false;
|
|
this.to(this.relative(this.current()) - 1, speed);
|
|
};
|
|
|
|
/**
|
|
* Handles the end of an animation.
|
|
* @protected
|
|
* @param {Event} event - The event arguments.
|
|
*/
|
|
Owl.prototype.onTransitionEnd = function(event) {
|
|
|
|
// if css2 animation then event object is undefined
|
|
if (event !== undefined) {
|
|
event.stopPropagation();
|
|
|
|
// Catch only owl-stage transitionEnd event
|
|
if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
this.leave('animating');
|
|
this.trigger('translated');
|
|
};
|
|
|
|
/**
|
|
* Gets viewport width.
|
|
* @protected
|
|
* @return {Number} - The width in pixel.
|
|
*/
|
|
Owl.prototype.viewport = function() {
|
|
var width;
|
|
if (this.options.responsiveBaseElement !== window) {
|
|
width = $(this.options.responsiveBaseElement).width();
|
|
} else if (window.innerWidth) {
|
|
width = window.innerWidth;
|
|
} else if (document.documentElement && document.documentElement.clientWidth) {
|
|
width = document.documentElement.clientWidth;
|
|
} else {
|
|
console.warn('Can not detect viewport width.');
|
|
}
|
|
return width;
|
|
};
|
|
|
|
/**
|
|
* Replaces the current content.
|
|
* @public
|
|
* @param {HTMLElement|jQuery|String} content - The new content.
|
|
*/
|
|
Owl.prototype.replace = function(content) {
|
|
this.$stage.empty();
|
|
this._items = [];
|
|
|
|
if (content) {
|
|
content = (content instanceof jQuery) ? content : $(content);
|
|
}
|
|
|
|
if (this.settings.nestedItemSelector) {
|
|
content = content.find('.' + this.settings.nestedItemSelector);
|
|
}
|
|
|
|
content.filter(function() {
|
|
return this.nodeType === 1;
|
|
}).each($.proxy(function(index, item) {
|
|
item = this.prepare(item);
|
|
this.$stage.append(item);
|
|
this._items.push(item);
|
|
this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
|
|
}, this));
|
|
|
|
this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
|
|
|
|
this.invalidate('items');
|
|
};
|
|
|
|
/**
|
|
* Adds an item.
|
|
* @todo Use `item` instead of `content` for the event arguments.
|
|
* @public
|
|
* @param {HTMLElement|jQuery|String} content - The item content to add.
|
|
* @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
|
|
*/
|
|
Owl.prototype.add = function(content, position) {
|
|
var current = this.relative(this._current);
|
|
|
|
position = position === undefined ? this._items.length : this.normalize(position, true);
|
|
content = content instanceof jQuery ? content : $(content);
|
|
|
|
this.trigger('add', { content: content, position: position });
|
|
|
|
content = this.prepare(content);
|
|
|
|
if (this._items.length === 0 || position === this._items.length) {
|
|
this._items.length === 0 && this.$stage.append(content);
|
|
this._items.length !== 0 && this._items[position - 1].after(content);
|
|
this._items.push(content);
|
|
this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
|
|
} else {
|
|
this._items[position].before(content);
|
|
this._items.splice(position, 0, content);
|
|
this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
|
|
}
|
|
|
|
this._items[current] && this.reset(this._items[current].index());
|
|
|
|
this.invalidate('items');
|
|
|
|
this.trigger('added', { content: content, position: position });
|
|
};
|
|
|
|
/**
|
|
* Removes an item by its position.
|
|
* @todo Use `item` instead of `content` for the event arguments.
|
|
* @public
|
|
* @param {Number} position - The relative position of the item to remove.
|
|
*/
|
|
Owl.prototype.remove = function(position) {
|
|
position = this.normalize(position, true);
|
|
|
|
if (position === undefined) {
|
|
return;
|
|
}
|
|
|
|
this.trigger('remove', { content: this._items[position], position: position });
|
|
|
|
this._items[position].remove();
|
|
this._items.splice(position, 1);
|
|
this._mergers.splice(position, 1);
|
|
|
|
this.invalidate('items');
|
|
|
|
this.trigger('removed', { content: null, position: position });
|
|
};
|
|
|
|
/**
|
|
* Preloads images with auto width.
|
|
* @todo Replace by a more generic approach
|
|
* @protected
|
|
*/
|
|
Owl.prototype.preloadAutoWidthImages = function(images) {
|
|
images.each($.proxy(function(i, element) {
|
|
this.enter('pre-loading');
|
|
element = $(element);
|
|
$(new Image()).one('load', $.proxy(function(e) {
|
|
element.attr('src', e.target.src);
|
|
element.css('opacity', 1);
|
|
this.leave('pre-loading');
|
|
!this.is('pre-loading') && !this.is('initializing') && this.refresh();
|
|
}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Destroys the carousel.
|
|
* @public
|
|
*/
|
|
Owl.prototype.destroy = function() {
|
|
|
|
this.$element.off('.owl.core');
|
|
this.$stage.off('.owl.core');
|
|
$(document).off('.owl.core');
|
|
|
|
if (this.settings.responsive !== false) {
|
|
window.clearTimeout(this.resizeTimer);
|
|
this.off(window, 'resize', this._handlers.onThrottledResize);
|
|
}
|
|
|
|
for (var i in this._plugins) {
|
|
this._plugins[i].destroy();
|
|
}
|
|
|
|
this.$stage.children('.cloned').remove();
|
|
|
|
this.$stage.unwrap();
|
|
this.$stage.children().contents().unwrap();
|
|
this.$stage.children().unwrap();
|
|
|
|
this.$element
|
|
.removeClass(this.options.refreshClass)
|
|
.removeClass(this.options.loadingClass)
|
|
.removeClass(this.options.loadedClass)
|
|
.removeClass(this.options.rtlClass)
|
|
.removeClass(this.options.dragClass)
|
|
.removeClass(this.options.grabClass)
|
|
.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
|
|
.removeData('owl.carousel');
|
|
};
|
|
|
|
/**
|
|
* Operators to calculate right-to-left and left-to-right.
|
|
* @protected
|
|
* @param {Number} [a] - The left side operand.
|
|
* @param {String} [o] - The operator.
|
|
* @param {Number} [b] - The right side operand.
|
|
*/
|
|
Owl.prototype.op = function(a, o, b) {
|
|
var rtl = this.settings.rtl;
|
|
switch (o) {
|
|
case '<':
|
|
return rtl ? a > b : a < b;
|
|
case '>':
|
|
return rtl ? a < b : a > b;
|
|
case '>=':
|
|
return rtl ? a <= b : a >= b;
|
|
case '<=':
|
|
return rtl ? a >= b : a <= b;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Attaches to an internal event.
|
|
* @protected
|
|
* @param {HTMLElement} element - The event source.
|
|
* @param {String} event - The event name.
|
|
* @param {Function} listener - The event handler to attach.
|
|
* @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
|
|
*/
|
|
Owl.prototype.on = function(element, event, listener, capture) {
|
|
if (element.addEventListener) {
|
|
element.addEventListener(event, listener, capture);
|
|
} else if (element.attachEvent) {
|
|
element.attachEvent('on' + event, listener);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Detaches from an internal event.
|
|
* @protected
|
|
* @param {HTMLElement} element - The event source.
|
|
* @param {String} event - The event name.
|
|
* @param {Function} listener - The attached event handler to detach.
|
|
* @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
|
|
*/
|
|
Owl.prototype.off = function(element, event, listener, capture) {
|
|
if (element.removeEventListener) {
|
|
element.removeEventListener(event, listener, capture);
|
|
} else if (element.detachEvent) {
|
|
element.detachEvent('on' + event, listener);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Triggers a public event.
|
|
* @todo Remove `status`, `relatedTarget` should be used instead.
|
|
* @protected
|
|
* @param {String} name - The event name.
|
|
* @param {*} [data=null] - The event data.
|
|
* @param {String} [namespace=carousel] - The event namespace.
|
|
* @param {String} [state] - The state which is associated with the event.
|
|
* @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
|
|
* @returns {Event} - The event arguments.
|
|
*/
|
|
Owl.prototype.trigger = function(name, data, namespace, state, enter) {
|
|
var status = {
|
|
item: { count: this._items.length, index: this.current() }
|
|
}, handler = $.camelCase(
|
|
$.grep([ 'on', name, namespace ], function(v) { return v })
|
|
.join('-').toLowerCase()
|
|
), event = $.Event(
|
|
[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
|
|
$.extend({ relatedTarget: this }, status, data)
|
|
);
|
|
|
|
if (!this._supress[name]) {
|
|
$.each(this._plugins, function(name, plugin) {
|
|
if (plugin.onTrigger) {
|
|
plugin.onTrigger(event);
|
|
}
|
|
});
|
|
|
|
this.register({ type: Owl.Type.Event, name: name });
|
|
this.$element.trigger(event);
|
|
|
|
if (this.settings && typeof this.settings[handler] === 'function') {
|
|
this.settings[handler].call(this, event);
|
|
}
|
|
}
|
|
|
|
return event;
|
|
};
|
|
|
|
/**
|
|
* Enters a state.
|
|
* @param name - The state name.
|
|
*/
|
|
Owl.prototype.enter = function(name) {
|
|
$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
|
|
if (this._states.current[name] === undefined) {
|
|
this._states.current[name] = 0;
|
|
}
|
|
|
|
this._states.current[name]++;
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Leaves a state.
|
|
* @param name - The state name.
|
|
*/
|
|
Owl.prototype.leave = function(name) {
|
|
$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
|
|
this._states.current[name]--;
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Registers an event or state.
|
|
* @public
|
|
* @param {Object} object - The event or state to register.
|
|
*/
|
|
Owl.prototype.register = function(object) {
|
|
if (object.type === Owl.Type.Event) {
|
|
if (!$.event.special[object.name]) {
|
|
$.event.special[object.name] = {};
|
|
}
|
|
|
|
if (!$.event.special[object.name].owl) {
|
|
var _default = $.event.special[object.name]._default;
|
|
$.event.special[object.name]._default = function(e) {
|
|
if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
|
|
return _default.apply(this, arguments);
|
|
}
|
|
return e.namespace && e.namespace.indexOf('owl') > -1;
|
|
};
|
|
$.event.special[object.name].owl = true;
|
|
}
|
|
} else if (object.type === Owl.Type.State) {
|
|
if (!this._states.tags[object.name]) {
|
|
this._states.tags[object.name] = object.tags;
|
|
} else {
|
|
this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
|
|
}
|
|
|
|
this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
|
|
return $.inArray(tag, this._states.tags[object.name]) === i;
|
|
}, this));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Suppresses events.
|
|
* @protected
|
|
* @param {Array.<String>} events - The events to suppress.
|
|
*/
|
|
Owl.prototype.suppress = function(events) {
|
|
$.each(events, $.proxy(function(index, event) {
|
|
this._supress[event] = true;
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Releases suppressed events.
|
|
* @protected
|
|
* @param {Array.<String>} events - The events to release.
|
|
*/
|
|
Owl.prototype.release = function(events) {
|
|
$.each(events, $.proxy(function(index, event) {
|
|
delete this._supress[event];
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Gets unified pointer coordinates from event.
|
|
* @todo #261
|
|
* @protected
|
|
* @param {Event} - The `mousedown` or `touchstart` event.
|
|
* @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
|
|
*/
|
|
Owl.prototype.pointer = function(event) {
|
|
var result = { x: null, y: null };
|
|
|
|
event = event.originalEvent || event || window.event;
|
|
|
|
event = event.touches && event.touches.length ?
|
|
event.touches[0] : event.changedTouches && event.changedTouches.length ?
|
|
event.changedTouches[0] : event;
|
|
|
|
if (event.pageX) {
|
|
result.x = event.pageX;
|
|
result.y = event.pageY;
|
|
} else {
|
|
result.x = event.clientX;
|
|
result.y = event.clientY;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Determines if the input is a Number or something that can be coerced to a Number
|
|
* @protected
|
|
* @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
|
|
* @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
|
|
*/
|
|
Owl.prototype.isNumeric = function(number) {
|
|
return !isNaN(parseFloat(number));
|
|
};
|
|
|
|
/**
|
|
* Gets the difference of two vectors.
|
|
* @todo #261
|
|
* @protected
|
|
* @param {Object} - The first vector.
|
|
* @param {Object} - The second vector.
|
|
* @returns {Object} - The difference.
|
|
*/
|
|
Owl.prototype.difference = function(first, second) {
|
|
return {
|
|
x: first.x - second.x,
|
|
y: first.y - second.y
|
|
};
|
|
};
|
|
|
|
/**
|
|
* The jQuery Plugin for the Owl Carousel
|
|
* @todo Navigation plugin `next` and `prev`
|
|
* @public
|
|
*/
|
|
$.fn.owlCarousel = function(option) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
return this.each(function() {
|
|
var $this = $(this),
|
|
data = $this.data('owl.carousel');
|
|
|
|
if (!data) {
|
|
data = new Owl(this, typeof option == 'object' && option);
|
|
$this.data('owl.carousel', data);
|
|
|
|
$.each([
|
|
'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
|
|
], function(i, event) {
|
|
data.register({ type: Owl.Type.Event, name: event });
|
|
data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
|
|
if (e.namespace && e.relatedTarget !== this) {
|
|
this.suppress([ event ]);
|
|
data[event].apply(this, [].slice.call(arguments, 1));
|
|
this.release([ event ]);
|
|
}
|
|
}, data));
|
|
});
|
|
}
|
|
|
|
if (typeof option == 'string' && option.charAt(0) !== '_') {
|
|
data[option].apply(data, args);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* The constructor for the jQuery Plugin
|
|
* @public
|
|
*/
|
|
$.fn.owlCarousel.Constructor = Owl;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* AutoRefresh Plugin
|
|
* @version 2.1.0
|
|
* @author Artus Kolanowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the auto refresh plugin.
|
|
* @class The Auto Refresh Plugin
|
|
* @param {Owl} carousel - The Owl Carousel
|
|
*/
|
|
var AutoRefresh = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* Refresh interval.
|
|
* @protected
|
|
* @type {number}
|
|
*/
|
|
this._interval = null;
|
|
|
|
/**
|
|
* Whether the element is currently visible or not.
|
|
* @protected
|
|
* @type {Boolean}
|
|
*/
|
|
this._visible = null;
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'initialized.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.autoRefresh) {
|
|
this.watch();
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
|
|
|
|
// register event handlers
|
|
this._core.$element.on(this._handlers);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
AutoRefresh.Defaults = {
|
|
autoRefresh: true,
|
|
autoRefreshInterval: 500
|
|
};
|
|
|
|
/**
|
|
* Watches the element.
|
|
*/
|
|
AutoRefresh.prototype.watch = function() {
|
|
if (this._interval) {
|
|
return;
|
|
}
|
|
|
|
this._visible = this._core.$element.is(':visible');
|
|
this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
|
|
};
|
|
|
|
/**
|
|
* Refreshes the element.
|
|
*/
|
|
AutoRefresh.prototype.refresh = function() {
|
|
if (this._core.$element.is(':visible') === this._visible) {
|
|
return;
|
|
}
|
|
|
|
this._visible = !this._visible;
|
|
|
|
this._core.$element.toggleClass('owl-hidden', !this._visible);
|
|
|
|
this._visible && (this._core.invalidate('width') && this._core.refresh());
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
*/
|
|
AutoRefresh.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
window.clearInterval(this._interval);
|
|
|
|
for (handler in this._handlers) {
|
|
this._core.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Lazy Plugin
|
|
* @version 2.1.0
|
|
* @author Bartosz Wojciechowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the lazy plugin.
|
|
* @class The Lazy Plugin
|
|
* @param {Owl} carousel - The Owl Carousel
|
|
*/
|
|
var Lazy = function(carousel) {
|
|
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* Already loaded items.
|
|
* @protected
|
|
* @type {Array.<jQuery>}
|
|
*/
|
|
this._loaded = [];
|
|
|
|
/**
|
|
* Event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
|
|
if (!e.namespace) {
|
|
return;
|
|
}
|
|
|
|
if (!this._core.settings || !this._core.settings.lazyLoad) {
|
|
return;
|
|
}
|
|
|
|
if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
|
|
var settings = this._core.settings,
|
|
n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
|
|
i = ((settings.center && n * -1) || 0),
|
|
position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
|
|
clones = this._core.clones().length,
|
|
load = $.proxy(function(i, v) { this.load(v) }, this);
|
|
|
|
while (i++ < n) {
|
|
this.load(clones / 2 + this._core.relative(position));
|
|
clones && $.each(this._core.clones(this._core.relative(position)), load);
|
|
position++;
|
|
}
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set the default options
|
|
this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
|
|
|
|
// register event handler
|
|
this._core.$element.on(this._handlers);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
Lazy.Defaults = {
|
|
lazyLoad: false
|
|
};
|
|
|
|
/**
|
|
* Loads all resources of an item at the specified position.
|
|
* @param {Number} position - The absolute position of the item.
|
|
* @protected
|
|
*/
|
|
Lazy.prototype.load = function(position) {
|
|
var $item = this._core.$stage.children().eq(position),
|
|
$elements = $item && $item.find('.owl-lazy');
|
|
|
|
if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
|
|
return;
|
|
}
|
|
|
|
$elements.each($.proxy(function(index, element) {
|
|
var $element = $(element), image,
|
|
url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
|
|
|
|
this._core.trigger('load', { element: $element, url: url }, 'lazy');
|
|
|
|
if ($element.is('img')) {
|
|
$element.one('load.owl.lazy', $.proxy(function() {
|
|
$element.css('opacity', 1);
|
|
this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
|
|
}, this)).attr('src', url);
|
|
} else {
|
|
image = new Image();
|
|
image.onload = $.proxy(function() {
|
|
$element.css({
|
|
'background-image': 'url("' + url + '")',
|
|
'opacity': '1'
|
|
});
|
|
this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
|
|
}, this);
|
|
image.src = url;
|
|
}
|
|
}, this));
|
|
|
|
this._loaded.push($item.get(0));
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
* @public
|
|
*/
|
|
Lazy.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
for (handler in this.handlers) {
|
|
this._core.$element.off(handler, this.handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* AutoHeight Plugin
|
|
* @version 2.1.0
|
|
* @author Bartosz Wojciechowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the auto height plugin.
|
|
* @class The Auto Height Plugin
|
|
* @param {Owl} carousel - The Owl Carousel
|
|
*/
|
|
var AutoHeight = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.autoHeight) {
|
|
this.update();
|
|
}
|
|
}, this),
|
|
'changed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
|
|
this.update();
|
|
}
|
|
}, this),
|
|
'loaded.owl.lazy': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.autoHeight
|
|
&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
|
|
this.update();
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
|
|
|
|
// register event handlers
|
|
this._core.$element.on(this._handlers);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
AutoHeight.Defaults = {
|
|
autoHeight: false,
|
|
autoHeightClass: 'owl-height'
|
|
};
|
|
|
|
/**
|
|
* Updates the view.
|
|
*/
|
|
AutoHeight.prototype.update = function() {
|
|
var start = this._core._current,
|
|
end = start + this._core.settings.items,
|
|
visible = this._core.$stage.children().toArray().slice(start, end),
|
|
heights = [],
|
|
maxheight = 0;
|
|
|
|
$.each(visible, function(index, item) {
|
|
heights.push($(item).height());
|
|
});
|
|
|
|
maxheight = Math.max.apply(null, heights);
|
|
|
|
this._core.$stage.parent()
|
|
.height(maxheight)
|
|
.addClass(this._core.settings.autoHeightClass);
|
|
};
|
|
|
|
AutoHeight.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
for (handler in this._handlers) {
|
|
this._core.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Video Plugin
|
|
* @version 2.1.0
|
|
* @author Bartosz Wojciechowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the video plugin.
|
|
* @class The Video Plugin
|
|
* @param {Owl} carousel - The Owl Carousel
|
|
*/
|
|
var Video = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* Cache all video URLs.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._videos = {};
|
|
|
|
/**
|
|
* Current playing item.
|
|
* @protected
|
|
* @type {jQuery}
|
|
*/
|
|
this._playing = null;
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @todo The cloned content removale is too late
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'initialized.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace) {
|
|
this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
|
|
}
|
|
}, this),
|
|
'resize.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
|
|
e.preventDefault();
|
|
}
|
|
}, this),
|
|
'refreshed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.is('resizing')) {
|
|
this._core.$stage.find('.cloned .owl-video-frame').remove();
|
|
}
|
|
}, this),
|
|
'changed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && e.property.name === 'position' && this._playing) {
|
|
this.stop();
|
|
}
|
|
}, this),
|
|
'prepared.owl.carousel': $.proxy(function(e) {
|
|
if (!e.namespace) {
|
|
return;
|
|
}
|
|
|
|
var $element = $(e.content).find('.owl-video');
|
|
|
|
if ($element.length) {
|
|
$element.css('display', 'none');
|
|
this.fetch($element, $(e.content));
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, Video.Defaults, this._core.options);
|
|
|
|
// register event handlers
|
|
this._core.$element.on(this._handlers);
|
|
|
|
this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
|
|
this.play(e);
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
Video.Defaults = {
|
|
video: false,
|
|
videoHeight: false,
|
|
videoWidth: false
|
|
};
|
|
|
|
/**
|
|
* Gets the video ID and the type (YouTube/Vimeo/vzaar only).
|
|
* @protected
|
|
* @param {jQuery} target - The target containing the video data.
|
|
* @param {jQuery} item - The item containing the video.
|
|
*/
|
|
Video.prototype.fetch = function(target, item) {
|
|
var type = (function() {
|
|
if (target.attr('data-vimeo-id')) {
|
|
return 'vimeo';
|
|
} else if (target.attr('data-vzaar-id')) {
|
|
return 'vzaar'
|
|
} else {
|
|
return 'youtube';
|
|
}
|
|
})(),
|
|
id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
|
|
width = target.attr('data-width') || this._core.settings.videoWidth,
|
|
height = target.attr('data-height') || this._core.settings.videoHeight,
|
|
url = target.attr('href');
|
|
|
|
if (url) {
|
|
|
|
/*
|
|
Parses the id's out of the following urls (and probably more):
|
|
https://www.youtube.com/watch?v=:id
|
|
https://youtu.be/:id
|
|
https://vimeo.com/:id
|
|
https://vimeo.com/channels/:channel/:id
|
|
https://vimeo.com/groups/:group/videos/:id
|
|
https://app.vzaar.com/videos/:id
|
|
|
|
Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
|
|
*/
|
|
|
|
id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
|
|
|
|
if (id[3].indexOf('youtu') > -1) {
|
|
type = 'youtube';
|
|
} else if (id[3].indexOf('vimeo') > -1) {
|
|
type = 'vimeo';
|
|
} else if (id[3].indexOf('vzaar') > -1) {
|
|
type = 'vzaar';
|
|
} else {
|
|
throw new Error('Video URL not supported.');
|
|
}
|
|
id = id[6];
|
|
} else {
|
|
throw new Error('Missing video URL.');
|
|
}
|
|
|
|
this._videos[url] = {
|
|
type: type,
|
|
id: id,
|
|
width: width,
|
|
height: height
|
|
};
|
|
|
|
item.attr('data-video', url);
|
|
|
|
this.thumbnail(target, this._videos[url]);
|
|
};
|
|
|
|
/**
|
|
* Creates video thumbnail.
|
|
* @protected
|
|
* @param {jQuery} target - The target containing the video data.
|
|
* @param {Object} info - The video info object.
|
|
* @see `fetch`
|
|
*/
|
|
Video.prototype.thumbnail = function(target, video) {
|
|
var tnLink,
|
|
icon,
|
|
path,
|
|
dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
|
|
customTn = target.find('img'),
|
|
srcType = 'src',
|
|
lazyClass = '',
|
|
settings = this._core.settings,
|
|
create = function(path) {
|
|
icon = '<div class="owl-video-play-icon"></div>';
|
|
|
|
if (settings.lazyLoad) {
|
|
tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
|
|
} else {
|
|
tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
|
|
}
|
|
target.after(tnLink);
|
|
target.after(icon);
|
|
};
|
|
|
|
// wrap video content into owl-video-wrapper div
|
|
target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
|
|
|
|
if (this._core.settings.lazyLoad) {
|
|
srcType = 'data-src';
|
|
lazyClass = 'owl-lazy';
|
|
}
|
|
|
|
// custom thumbnail
|
|
if (customTn.length) {
|
|
create(customTn.attr(srcType));
|
|
customTn.remove();
|
|
return false;
|
|
}
|
|
|
|
if (video.type === 'youtube') {
|
|
path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
|
|
create(path);
|
|
} else if (video.type === 'vimeo') {
|
|
$.ajax({
|
|
type: 'GET',
|
|
url: '//vimeo.com/api/v2/video/' + video.id + '.json',
|
|
jsonp: 'callback',
|
|
dataType: 'jsonp',
|
|
success: function(data) {
|
|
path = data[0].thumbnail_large;
|
|
create(path);
|
|
}
|
|
});
|
|
} else if (video.type === 'vzaar') {
|
|
$.ajax({
|
|
type: 'GET',
|
|
url: '//vzaar.com/api/videos/' + video.id + '.json',
|
|
jsonp: 'callback',
|
|
dataType: 'jsonp',
|
|
success: function(data) {
|
|
path = data.framegrab_url;
|
|
create(path);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Stops the current video.
|
|
* @public
|
|
*/
|
|
Video.prototype.stop = function() {
|
|
this._core.trigger('stop', null, 'video');
|
|
this._playing.find('.owl-video-frame').remove();
|
|
this._playing.removeClass('owl-video-playing');
|
|
this._playing = null;
|
|
this._core.leave('playing');
|
|
this._core.trigger('stopped', null, 'video');
|
|
};
|
|
|
|
/**
|
|
* Starts the current video.
|
|
* @public
|
|
* @param {Event} event - The event arguments.
|
|
*/
|
|
Video.prototype.play = function(event) {
|
|
var target = $(event.target),
|
|
item = target.closest('.' + this._core.settings.itemClass),
|
|
video = this._videos[item.attr('data-video')],
|
|
width = video.width || '100%',
|
|
height = video.height || this._core.$stage.height(),
|
|
html;
|
|
|
|
if (this._playing) {
|
|
return;
|
|
}
|
|
|
|
this._core.enter('playing');
|
|
this._core.trigger('play', null, 'video');
|
|
|
|
item = this._core.items(this._core.relative(item.index()));
|
|
|
|
this._core.reset(item.index());
|
|
|
|
if (video.type === 'youtube') {
|
|
html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
|
|
video.id + '?autoplay=1&rel=0&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
|
|
} else if (video.type === 'vimeo') {
|
|
html = '<iframe src="//player.vimeo.com/video/' + video.id +
|
|
'?autoplay=1" width="' + width + '" height="' + height +
|
|
'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
|
|
} else if (video.type === 'vzaar') {
|
|
html = '<iframe frameborder="0"' + 'height="' + height + '"' + 'width="' + width +
|
|
'" allowfullscreen mozallowfullscreen webkitAllowFullScreen ' +
|
|
'src="//view.vzaar.com/' + video.id + '/player?autoplay=true"></iframe>';
|
|
}
|
|
|
|
$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
|
|
|
|
this._playing = item.addClass('owl-video-playing');
|
|
};
|
|
|
|
/**
|
|
* Checks whether an video is currently in full screen mode or not.
|
|
* @todo Bad style because looks like a readonly method but changes members.
|
|
* @protected
|
|
* @returns {Boolean}
|
|
*/
|
|
Video.prototype.isInFullScreen = function() {
|
|
var element = document.fullscreenElement || document.mozFullScreenElement ||
|
|
document.webkitFullscreenElement;
|
|
|
|
return element && $(element).parent().hasClass('owl-video-frame');
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
*/
|
|
Video.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
this._core.$element.off('click.owl.video');
|
|
|
|
for (handler in this._handlers) {
|
|
this._core.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.Video = Video;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Animate Plugin
|
|
* @version 2.1.0
|
|
* @author Bartosz Wojciechowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the animate plugin.
|
|
* @class The Navigation Plugin
|
|
* @param {Owl} scope - The Owl Carousel
|
|
*/
|
|
var Animate = function(scope) {
|
|
this.core = scope;
|
|
this.core.options = $.extend({}, Animate.Defaults, this.core.options);
|
|
this.swapping = true;
|
|
this.previous = undefined;
|
|
this.next = undefined;
|
|
|
|
this.handlers = {
|
|
'change.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && e.property.name == 'position') {
|
|
this.previous = this.core.current();
|
|
this.next = e.property.value;
|
|
}
|
|
}, this),
|
|
'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace) {
|
|
this.swapping = e.type == 'translated';
|
|
}
|
|
}, this),
|
|
'translate.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
|
|
this.swap();
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
this.core.$element.on(this.handlers);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
Animate.Defaults = {
|
|
animateOut: false,
|
|
animateIn: false
|
|
};
|
|
|
|
/**
|
|
* Toggles the animation classes whenever an translations starts.
|
|
* @protected
|
|
* @returns {Boolean|undefined}
|
|
*/
|
|
Animate.prototype.swap = function() {
|
|
|
|
if (this.core.settings.items !== 1) {
|
|
return;
|
|
}
|
|
|
|
if (!$.support.animation || !$.support.transition) {
|
|
return;
|
|
}
|
|
|
|
this.core.speed(0);
|
|
|
|
var left,
|
|
clear = $.proxy(this.clear, this),
|
|
previous = this.core.$stage.children().eq(this.previous),
|
|
next = this.core.$stage.children().eq(this.next),
|
|
incoming = this.core.settings.animateIn,
|
|
outgoing = this.core.settings.animateOut;
|
|
|
|
if (this.core.current() === this.previous) {
|
|
return;
|
|
}
|
|
|
|
if (outgoing) {
|
|
left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
|
|
previous.one($.support.animation.end, clear)
|
|
.css( { 'left': left + 'px' } )
|
|
.addClass('animated owl-animated-out')
|
|
.addClass(outgoing);
|
|
}
|
|
|
|
if (incoming) {
|
|
next.one($.support.animation.end, clear)
|
|
.addClass('animated owl-animated-in')
|
|
.addClass(incoming);
|
|
}
|
|
};
|
|
|
|
Animate.prototype.clear = function(e) {
|
|
$(e.target).css( { 'left': '' } )
|
|
.removeClass('animated owl-animated-out owl-animated-in')
|
|
.removeClass(this.core.settings.animateIn)
|
|
.removeClass(this.core.settings.animateOut);
|
|
this.core.onTransitionEnd();
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
* @public
|
|
*/
|
|
Animate.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
for (handler in this.handlers) {
|
|
this.core.$element.off(handler, this.handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Autoplay Plugin
|
|
* @version 2.1.0
|
|
* @author Bartosz Wojciechowski
|
|
* @author Artus Kolanowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
/**
|
|
* Creates the autoplay plugin.
|
|
* @class The Autoplay Plugin
|
|
* @param {Owl} scope - The Owl Carousel
|
|
*/
|
|
var Autoplay = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* The autoplay timeout.
|
|
* @type {Timeout}
|
|
*/
|
|
this._timeout = null;
|
|
|
|
/**
|
|
* Indicates whenever the autoplay is paused.
|
|
* @type {Boolean}
|
|
*/
|
|
this._paused = false;
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'changed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && e.property.name === 'settings') {
|
|
if (this._core.settings.autoplay) {
|
|
this.play();
|
|
} else {
|
|
this.stop();
|
|
}
|
|
} else if (e.namespace && e.property.name === 'position') {
|
|
//console.log('play?', e);
|
|
if (this._core.settings.autoplay) {
|
|
this._setAutoPlayInterval();
|
|
}
|
|
}
|
|
}, this),
|
|
'initialized.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.autoplay) {
|
|
this.play();
|
|
}
|
|
}, this),
|
|
'play.owl.autoplay': $.proxy(function(e, t, s) {
|
|
if (e.namespace) {
|
|
this.play(t, s);
|
|
}
|
|
}, this),
|
|
'stop.owl.autoplay': $.proxy(function(e) {
|
|
if (e.namespace) {
|
|
this.stop();
|
|
}
|
|
}, this),
|
|
'mouseover.owl.autoplay': $.proxy(function() {
|
|
if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
|
|
this.pause();
|
|
}
|
|
}, this),
|
|
'mouseleave.owl.autoplay': $.proxy(function() {
|
|
if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
|
|
this.play();
|
|
}
|
|
}, this),
|
|
'touchstart.owl.core': $.proxy(function() {
|
|
if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
|
|
this.pause();
|
|
}
|
|
}, this),
|
|
'touchend.owl.core': $.proxy(function() {
|
|
if (this._core.settings.autoplayHoverPause) {
|
|
this.play();
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// register event handlers
|
|
this._core.$element.on(this._handlers);
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
Autoplay.Defaults = {
|
|
autoplay: false,
|
|
autoplayTimeout: 5000,
|
|
autoplayHoverPause: false,
|
|
autoplaySpeed: false
|
|
};
|
|
|
|
/**
|
|
* Starts the autoplay.
|
|
* @public
|
|
* @param {Number} [timeout] - The interval before the next animation starts.
|
|
* @param {Number} [speed] - The animation speed for the animations.
|
|
*/
|
|
Autoplay.prototype.play = function(timeout, speed) {
|
|
this._paused = false;
|
|
|
|
if (this._core.is('rotating')) {
|
|
return;
|
|
}
|
|
|
|
this._core.enter('rotating');
|
|
|
|
this._setAutoPlayInterval();
|
|
};
|
|
|
|
/**
|
|
* Gets a new timeout
|
|
* @private
|
|
* @param {Number} [timeout] - The interval before the next animation starts.
|
|
* @param {Number} [speed] - The animation speed for the animations.
|
|
* @return {Timeout}
|
|
*/
|
|
Autoplay.prototype._getNextTimeout = function(timeout, speed) {
|
|
if ( this._timeout ) {
|
|
window.clearTimeout(this._timeout);
|
|
}
|
|
return window.setTimeout($.proxy(function() {
|
|
if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
|
|
return;
|
|
}
|
|
this._core.next(speed || this._core.settings.autoplaySpeed);
|
|
}, this), timeout || this._core.settings.autoplayTimeout);
|
|
};
|
|
|
|
/**
|
|
* Sets autoplay in motion.
|
|
* @private
|
|
*/
|
|
Autoplay.prototype._setAutoPlayInterval = function() {
|
|
this._timeout = this._getNextTimeout();
|
|
};
|
|
|
|
/**
|
|
* Stops the autoplay.
|
|
* @public
|
|
*/
|
|
Autoplay.prototype.stop = function() {
|
|
if (!this._core.is('rotating')) {
|
|
return;
|
|
}
|
|
|
|
window.clearTimeout(this._timeout);
|
|
this._core.leave('rotating');
|
|
};
|
|
|
|
/**
|
|
* Stops the autoplay.
|
|
* @public
|
|
*/
|
|
Autoplay.prototype.pause = function() {
|
|
if (!this._core.is('rotating')) {
|
|
return;
|
|
}
|
|
|
|
this._paused = true;
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
*/
|
|
Autoplay.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
this.stop();
|
|
|
|
for (handler in this._handlers) {
|
|
this._core.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Navigation Plugin
|
|
* @version 2.1.0
|
|
* @author Artus Kolanowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Creates the navigation plugin.
|
|
* @class The Navigation Plugin
|
|
* @param {Owl} carousel - The Owl Carousel.
|
|
*/
|
|
var Navigation = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* Indicates whether the plugin is initialized or not.
|
|
* @protected
|
|
* @type {Boolean}
|
|
*/
|
|
this._initialized = false;
|
|
|
|
/**
|
|
* The current paging indexes.
|
|
* @protected
|
|
* @type {Array}
|
|
*/
|
|
this._pages = [];
|
|
|
|
/**
|
|
* All DOM elements of the user interface.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._controls = {};
|
|
|
|
/**
|
|
* Markup for an indicator.
|
|
* @protected
|
|
* @type {Array.<String>}
|
|
*/
|
|
this._templates = [];
|
|
|
|
/**
|
|
* The carousel element.
|
|
* @type {jQuery}
|
|
*/
|
|
this.$element = this._core.$element;
|
|
|
|
/**
|
|
* Overridden methods of the carousel.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._overrides = {
|
|
next: this._core.next,
|
|
prev: this._core.prev,
|
|
to: this._core.to
|
|
};
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'prepared.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.dotsData) {
|
|
this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
|
|
$(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
|
|
}
|
|
}, this),
|
|
'added.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.dotsData) {
|
|
this._templates.splice(e.position, 0, this._templates.pop());
|
|
}
|
|
}, this),
|
|
'remove.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.dotsData) {
|
|
this._templates.splice(e.position, 1);
|
|
}
|
|
}, this),
|
|
'changed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && e.property.name == 'position') {
|
|
this.draw();
|
|
}
|
|
}, this),
|
|
'initialized.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && !this._initialized) {
|
|
this._core.trigger('initialize', null, 'navigation');
|
|
this.initialize();
|
|
this.update();
|
|
this.draw();
|
|
this._initialized = true;
|
|
this._core.trigger('initialized', null, 'navigation');
|
|
}
|
|
}, this),
|
|
'refreshed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._initialized) {
|
|
this._core.trigger('refresh', null, 'navigation');
|
|
this.update();
|
|
this.draw();
|
|
this._core.trigger('refreshed', null, 'navigation');
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
|
|
|
|
// register event handlers
|
|
this.$element.on(this._handlers);
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
* @todo Rename `slideBy` to `navBy`
|
|
*/
|
|
Navigation.Defaults = {
|
|
nav: false,
|
|
navText: [ 'prev', 'next' ],
|
|
navSpeed: false,
|
|
navElement: 'div',
|
|
navContainer: false,
|
|
navContainerClass: 'owl-nav',
|
|
navClass: [ 'owl-prev', 'owl-next' ],
|
|
slideBy: 1,
|
|
dotClass: 'owl-dot',
|
|
dotsClass: 'owl-dots',
|
|
dots: true,
|
|
dotsEach: false,
|
|
dotsData: false,
|
|
dotsSpeed: false,
|
|
dotsContainer: false
|
|
};
|
|
|
|
/**
|
|
* Initializes the layout of the plugin and extends the carousel.
|
|
* @protected
|
|
*/
|
|
Navigation.prototype.initialize = function() {
|
|
var override,
|
|
settings = this._core.settings;
|
|
|
|
// create DOM structure for relative navigation
|
|
this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
|
|
: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
|
|
|
|
this._controls.$previous = $('<' + settings.navElement + '>')
|
|
.addClass(settings.navClass[0])
|
|
.html(settings.navText[0])
|
|
.prependTo(this._controls.$relative)
|
|
.on('click', $.proxy(function(e) {
|
|
this.prev(settings.navSpeed);
|
|
}, this));
|
|
this._controls.$next = $('<' + settings.navElement + '>')
|
|
.addClass(settings.navClass[1])
|
|
.html(settings.navText[1])
|
|
.appendTo(this._controls.$relative)
|
|
.on('click', $.proxy(function(e) {
|
|
this.next(settings.navSpeed);
|
|
}, this));
|
|
|
|
// create DOM structure for absolute navigation
|
|
if (!settings.dotsData) {
|
|
this._templates = [ $('<div>')
|
|
.addClass(settings.dotClass)
|
|
.append($('<span>'))
|
|
.prop('outerHTML') ];
|
|
}
|
|
|
|
this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
|
|
: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
|
|
|
|
this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
|
|
var index = $(e.target).parent().is(this._controls.$absolute)
|
|
? $(e.target).index() : $(e.target).parent().index();
|
|
|
|
e.preventDefault();
|
|
|
|
this.to(index, settings.dotsSpeed);
|
|
}, this));
|
|
|
|
// override public methods of the carousel
|
|
for (override in this._overrides) {
|
|
this._core[override] = $.proxy(this[override], this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
* @protected
|
|
*/
|
|
Navigation.prototype.destroy = function() {
|
|
var handler, control, property, override;
|
|
|
|
for (handler in this._handlers) {
|
|
this.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (control in this._controls) {
|
|
this._controls[control].remove();
|
|
}
|
|
for (override in this.overides) {
|
|
this._core[override] = this._overrides[override];
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Updates the internal state.
|
|
* @protected
|
|
*/
|
|
Navigation.prototype.update = function() {
|
|
var i, j, k,
|
|
lower = this._core.clones().length / 2,
|
|
upper = lower + this._core.items().length,
|
|
maximum = this._core.maximum(true),
|
|
settings = this._core.settings,
|
|
size = settings.center || settings.autoWidth || settings.dotsData
|
|
? 1 : settings.dotsEach || settings.items;
|
|
|
|
if (settings.slideBy !== 'page') {
|
|
settings.slideBy = Math.min(settings.slideBy, settings.items);
|
|
}
|
|
|
|
if (settings.dots || settings.slideBy == 'page') {
|
|
this._pages = [];
|
|
|
|
for (i = lower, j = 0, k = 0; i < upper; i++) {
|
|
if (j >= size || j === 0) {
|
|
this._pages.push({
|
|
start: Math.min(maximum, i - lower),
|
|
end: i - lower + size - 1
|
|
});
|
|
if (Math.min(maximum, i - lower) === maximum) {
|
|
break;
|
|
}
|
|
j = 0, ++k;
|
|
}
|
|
j += this._core.mergers(this._core.relative(i));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Draws the user interface.
|
|
* @todo The option `dotsData` wont work.
|
|
* @protected
|
|
*/
|
|
Navigation.prototype.draw = function() {
|
|
var difference,
|
|
settings = this._core.settings,
|
|
disabled = this._core.items().length <= settings.items,
|
|
index = this._core.relative(this._core.current()),
|
|
loop = settings.loop || settings.rewind;
|
|
|
|
this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
|
|
|
|
if (settings.nav) {
|
|
this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
|
|
this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
|
|
}
|
|
|
|
this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
|
|
|
|
if (settings.dots) {
|
|
difference = this._pages.length - this._controls.$absolute.children().length;
|
|
|
|
if (settings.dotsData && difference !== 0) {
|
|
this._controls.$absolute.html(this._templates.join(''));
|
|
} else if (difference > 0) {
|
|
this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
|
|
} else if (difference < 0) {
|
|
this._controls.$absolute.children().slice(difference).remove();
|
|
}
|
|
|
|
this._controls.$absolute.find('.active').removeClass('active');
|
|
this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Extends event data.
|
|
* @protected
|
|
* @param {Event} event - The event object which gets thrown.
|
|
*/
|
|
Navigation.prototype.onTrigger = function(event) {
|
|
var settings = this._core.settings;
|
|
|
|
event.page = {
|
|
index: $.inArray(this.current(), this._pages),
|
|
count: this._pages.length,
|
|
size: settings && (settings.center || settings.autoWidth || settings.dotsData
|
|
? 1 : settings.dotsEach || settings.items)
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Gets the current page position of the carousel.
|
|
* @protected
|
|
* @returns {Number}
|
|
*/
|
|
Navigation.prototype.current = function() {
|
|
var current = this._core.relative(this._core.current());
|
|
return $.grep(this._pages, $.proxy(function(page, index) {
|
|
return page.start <= current && page.end >= current;
|
|
}, this)).pop();
|
|
};
|
|
|
|
/**
|
|
* Gets the current succesor/predecessor position.
|
|
* @protected
|
|
* @returns {Number}
|
|
*/
|
|
Navigation.prototype.getPosition = function(successor) {
|
|
var position, length,
|
|
settings = this._core.settings;
|
|
|
|
if (settings.slideBy == 'page') {
|
|
position = $.inArray(this.current(), this._pages);
|
|
length = this._pages.length;
|
|
successor ? ++position : --position;
|
|
position = this._pages[((position % length) + length) % length].start;
|
|
} else {
|
|
position = this._core.relative(this._core.current());
|
|
length = this._core.items().length;
|
|
successor ? position += settings.slideBy : position -= settings.slideBy;
|
|
}
|
|
|
|
return position;
|
|
};
|
|
|
|
/**
|
|
* Slides to the next item or page.
|
|
* @public
|
|
* @param {Number} [speed=false] - The time in milliseconds for the transition.
|
|
*/
|
|
Navigation.prototype.next = function(speed) {
|
|
$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
|
|
};
|
|
|
|
/**
|
|
* Slides to the previous item or page.
|
|
* @public
|
|
* @param {Number} [speed=false] - The time in milliseconds for the transition.
|
|
*/
|
|
Navigation.prototype.prev = function(speed) {
|
|
$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
|
|
};
|
|
|
|
/**
|
|
* Slides to the specified item or page.
|
|
* @public
|
|
* @param {Number} position - The position of the item or page.
|
|
* @param {Number} [speed] - The time in milliseconds for the transition.
|
|
* @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
|
|
*/
|
|
Navigation.prototype.to = function(position, speed, standard) {
|
|
var length;
|
|
|
|
if (!standard && this._pages.length) {
|
|
length = this._pages.length;
|
|
$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
|
|
} else {
|
|
$.proxy(this._overrides.to, this._core)(position, speed);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Hash Plugin
|
|
* @version 2.1.0
|
|
* @author Artus Kolanowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Creates the hash plugin.
|
|
* @class The Hash Plugin
|
|
* @param {Owl} carousel - The Owl Carousel
|
|
*/
|
|
var Hash = function(carousel) {
|
|
/**
|
|
* Reference to the core.
|
|
* @protected
|
|
* @type {Owl}
|
|
*/
|
|
this._core = carousel;
|
|
|
|
/**
|
|
* Hash index for the items.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._hashes = {};
|
|
|
|
/**
|
|
* The carousel element.
|
|
* @type {jQuery}
|
|
*/
|
|
this.$element = this._core.$element;
|
|
|
|
/**
|
|
* All event handlers.
|
|
* @protected
|
|
* @type {Object}
|
|
*/
|
|
this._handlers = {
|
|
'initialized.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && this._core.settings.startPosition === 'URLHash') {
|
|
$(window).trigger('hashchange.owl.navigation');
|
|
}
|
|
}, this),
|
|
'prepared.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace) {
|
|
var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
|
|
|
|
if (!hash) {
|
|
return;
|
|
}
|
|
|
|
this._hashes[hash] = e.content;
|
|
}
|
|
}, this),
|
|
'changed.owl.carousel': $.proxy(function(e) {
|
|
if (e.namespace && e.property.name === 'position') {
|
|
var current = this._core.items(this._core.relative(this._core.current())),
|
|
hash = $.map(this._hashes, function(item, hash) {
|
|
return item === current ? hash : null;
|
|
}).join();
|
|
|
|
if (!hash || window.location.hash.slice(1) === hash) {
|
|
return;
|
|
}
|
|
|
|
window.location.hash = hash;
|
|
}
|
|
}, this)
|
|
};
|
|
|
|
// set default options
|
|
this._core.options = $.extend({}, Hash.Defaults, this._core.options);
|
|
|
|
// register the event handlers
|
|
this.$element.on(this._handlers);
|
|
|
|
// register event listener for hash navigation
|
|
$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
|
|
var hash = window.location.hash.substring(1),
|
|
items = this._core.$stage.children(),
|
|
position = this._hashes[hash] && items.index(this._hashes[hash]);
|
|
|
|
if (position === undefined || position === this._core.current()) {
|
|
return;
|
|
}
|
|
|
|
this._core.to(this._core.relative(position), false, true);
|
|
}, this));
|
|
};
|
|
|
|
/**
|
|
* Default options.
|
|
* @public
|
|
*/
|
|
Hash.Defaults = {
|
|
URLhashListener: false
|
|
};
|
|
|
|
/**
|
|
* Destroys the plugin.
|
|
* @public
|
|
*/
|
|
Hash.prototype.destroy = function() {
|
|
var handler, property;
|
|
|
|
$(window).off('hashchange.owl.navigation');
|
|
|
|
for (handler in this._handlers) {
|
|
this._core.$element.off(handler, this._handlers[handler]);
|
|
}
|
|
for (property in Object.getOwnPropertyNames(this)) {
|
|
typeof this[property] != 'function' && (this[property] = null);
|
|
}
|
|
};
|
|
|
|
$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/**
|
|
* Support Plugin
|
|
*
|
|
* @version 2.1.0
|
|
* @author Vivid Planet Software GmbH
|
|
* @author Artus Kolanowski
|
|
* @author David Deutsch
|
|
* @license The MIT License (MIT)
|
|
*/
|
|
;(function($, window, document, undefined) {
|
|
|
|
var style = $('<support>').get(0).style,
|
|
prefixes = 'Webkit Moz O ms'.split(' '),
|
|
events = {
|
|
transition: {
|
|
end: {
|
|
WebkitTransition: 'webkitTransitionEnd',
|
|
MozTransition: 'transitionend',
|
|
OTransition: 'oTransitionEnd',
|
|
transition: 'transitionend'
|
|
}
|
|
},
|
|
animation: {
|
|
end: {
|
|
WebkitAnimation: 'webkitAnimationEnd',
|
|
MozAnimation: 'animationend',
|
|
OAnimation: 'oAnimationEnd',
|
|
animation: 'animationend'
|
|
}
|
|
}
|
|
},
|
|
tests = {
|
|
csstransforms: function() {
|
|
return !!test('transform');
|
|
},
|
|
csstransforms3d: function() {
|
|
return !!test('perspective');
|
|
},
|
|
csstransitions: function() {
|
|
return !!test('transition');
|
|
},
|
|
cssanimations: function() {
|
|
return !!test('animation');
|
|
}
|
|
};
|
|
|
|
function test(property, prefixed) {
|
|
var result = false,
|
|
upper = property.charAt(0).toUpperCase() + property.slice(1);
|
|
|
|
$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
|
|
if (style[property] !== undefined) {
|
|
result = prefixed ? property : true;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function prefixed(property) {
|
|
return test(property, true);
|
|
}
|
|
|
|
if (tests.csstransitions()) {
|
|
/* jshint -W053 */
|
|
$.support.transition = new String(prefixed('transition'))
|
|
$.support.transition.end = events.transition.end[ $.support.transition ];
|
|
}
|
|
|
|
if (tests.cssanimations()) {
|
|
/* jshint -W053 */
|
|
$.support.animation = new String(prefixed('animation'))
|
|
$.support.animation.end = events.animation.end[ $.support.animation ];
|
|
}
|
|
|
|
if (tests.csstransforms()) {
|
|
/* jshint -W053 */
|
|
$.support.transform = new String(prefixed('transform'));
|
|
$.support.transform3d = tests.csstransforms3d();
|
|
}
|
|
|
|
})(window.Zepto || window.jQuery, window, document);
|
|
|
|
/*********************************************************************
|
|
* #### Twitter Post Fetcher v18.0.3 ####
|
|
* Coded by Jason Mayes 2015. A present to all the developers out there.
|
|
* www.jasonmayes.com
|
|
* Please keep this disclaimer with my code if you use it. Thanks. :-)
|
|
* Got feedback or questions, ask here:
|
|
* http://www.jasonmayes.com/projects/twitterApi/
|
|
* Github: https://github.com/jasonmayes/Twitter-Post-Fetcher
|
|
* Updates will be posted to this site.
|
|
*********************************************************************/
|
|
(function(root, factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD. Register as an anonymous module.
|
|
define([], factory);
|
|
} else if (typeof exports === 'object') {
|
|
// Node. Does not work with strict CommonJS, but
|
|
// only CommonJS-like environments that support module.exports,
|
|
// like Node.
|
|
module.exports = factory();
|
|
} else {
|
|
// Browser globals.
|
|
factory();
|
|
}
|
|
}(this, function() {
|
|
var domNode = '';
|
|
var maxTweets = 20;
|
|
var parseLinks = true;
|
|
var queue = [];
|
|
var inProgress = false;
|
|
var printTime = true;
|
|
var printUser = true;
|
|
var formatterFunction = null;
|
|
var supportsClassName = true;
|
|
var showRts = true;
|
|
var customCallbackFunction = null;
|
|
var showInteractionLinks = true;
|
|
var showImages = false;
|
|
var useEmoji = false;
|
|
var targetBlank = true;
|
|
var lang = 'en';
|
|
var permalinks = true;
|
|
var dataOnly = false;
|
|
var script = null;
|
|
var scriptAdded = false;
|
|
|
|
function handleTweets(tweets){
|
|
if (customCallbackFunction === null) {
|
|
var x = tweets.length;
|
|
var n = 0;
|
|
var element = document.getElementById(domNode);
|
|
var html = '<ul>';
|
|
while(n < x) {
|
|
html += '<li>' + tweets[n] + '</li>';
|
|
n++;
|
|
}
|
|
html += '</ul>';
|
|
element.innerHTML = html;
|
|
} else {
|
|
customCallbackFunction(tweets);
|
|
}
|
|
}
|
|
|
|
function strip(data) {
|
|
return data.replace(/<b[^>]*>(.*?)<\/b>/gi, function(a,s){return s;})
|
|
.replace(/class="(?!(tco-hidden|tco-display|tco-ellipsis))+.*?"|data-query-source=".*?"|dir=".*?"|rel=".*?"/gi,
|
|
'');
|
|
}
|
|
|
|
function targetLinksToNewWindow(el) {
|
|
var links = el.getElementsByTagName('a');
|
|
for (var i = links.length - 1; i >= 0; i--) {
|
|
links[i].setAttribute('target', '_blank');
|
|
links[i].setAttribute('rel', 'noopener');
|
|
}
|
|
}
|
|
|
|
function getElementsByClassName (node, classname) {
|
|
var a = [];
|
|
var regex = new RegExp('(^| )' + classname + '( |$)');
|
|
var elems = node.getElementsByTagName('*');
|
|
for (var i = 0, j = elems.length; i < j; i++) {
|
|
if(regex.test(elems[i].className)){
|
|
a.push(elems[i]);
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
|
|
function extractImagesUrl(image_data) {
|
|
if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0) {
|
|
var data_src = image_data.innerHTML.match(/data-image=\"([A-z0-9]+:\/\/[A-z0-9]+\.[A-z0-9]+\.[A-z0-9]+\/[A-z0-9]+\/[A-z0-9\-]+)\"/ig);
|
|
for (var i = 0; i < data_src.length; i++) {
|
|
data_src[i] = data_src[i].match(/data-image=\"([A-z0-9]+:\/\/[A-z0-9]+\.[A-z0-9]+\.[A-z0-9]+\/[A-z0-9]+\/[A-z0-9\-]+)\"/i)[1];
|
|
data_src[i] = decodeURIComponent(data_src[i]) + '.jpg';
|
|
}
|
|
return data_src;
|
|
}
|
|
}
|
|
|
|
|
|
var twitterFetcher = {
|
|
fetch: function(config) {
|
|
if (config.maxTweets === undefined) {
|
|
config.maxTweets = 20;
|
|
}
|
|
if (config.enableLinks === undefined) {
|
|
config.enableLinks = true;
|
|
}
|
|
if (config.showUser === undefined) {
|
|
config.showUser = true;
|
|
}
|
|
if (config.showTime === undefined) {
|
|
config.showTime = true;
|
|
}
|
|
if (config.dateFunction === undefined) {
|
|
config.dateFunction = 'default';
|
|
}
|
|
if (config.showRetweet === undefined) {
|
|
config.showRetweet = true;
|
|
}
|
|
if (config.customCallback === undefined) {
|
|
config.customCallback = null;
|
|
}
|
|
if (config.showInteraction === undefined) {
|
|
config.showInteraction = true;
|
|
}
|
|
if (config.showImages === undefined) {
|
|
config.showImages = false;
|
|
}
|
|
if (config.useEmoji === undefined) {
|
|
config.useEmoji = false;
|
|
}
|
|
if (config.linksInNewWindow === undefined) {
|
|
config.linksInNewWindow = true;
|
|
}
|
|
if (config.showPermalinks === undefined) {
|
|
config.showPermalinks = true;
|
|
}
|
|
if (config.dataOnly === undefined) {
|
|
config.dataOnly = false;
|
|
}
|
|
|
|
if (inProgress) {
|
|
queue.push(config);
|
|
} else {
|
|
inProgress = true;
|
|
|
|
domNode = config.domId;
|
|
maxTweets = config.maxTweets;
|
|
parseLinks = config.enableLinks;
|
|
printUser = config.showUser;
|
|
printTime = config.showTime;
|
|
showRts = config.showRetweet;
|
|
formatterFunction = config.dateFunction;
|
|
customCallbackFunction = config.customCallback;
|
|
showInteractionLinks = config.showInteraction;
|
|
showImages = config.showImages;
|
|
useEmoji = config.useEmoji;
|
|
targetBlank = config.linksInNewWindow;
|
|
permalinks = config.showPermalinks;
|
|
dataOnly = config.dataOnly;
|
|
|
|
var head = document.getElementsByTagName('head')[0];
|
|
if (script !== null) {
|
|
head.removeChild(script);
|
|
}
|
|
script = document.createElement('script');
|
|
script.type = 'text/javascript';
|
|
if (config.list !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/list?' +
|
|
'callback=__twttrf.callback&dnt=false&list_slug=' +
|
|
config.list.listSlug + '&screen_name=' + config.list.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.profile !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/profile?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&screen_name=' + config.profile.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.likes !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/likes?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&screen_name=' + config.likes.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.collection !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/collection?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&collection_id=' + config.collection.collectionId +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else {
|
|
script.src = 'https://cdn.syndication.twimg.com/widgets/timelines/' +
|
|
config.id + '?&lang=' + (config.lang || lang) +
|
|
'&callback=__twttrf.callback&' +
|
|
'suppress_response_codes=true&rnd=' + Math.random();
|
|
}
|
|
head.appendChild(script);
|
|
}
|
|
},
|
|
callback: function(data) {
|
|
if (data === undefined || data.body === undefined) {
|
|
inProgress = false;
|
|
|
|
if (queue.length > 0) {
|
|
twitterFetcher.fetch(queue[0]);
|
|
queue.splice(0,1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Remove emoji and summary card images.
|
|
if(!useEmoji){
|
|
data.body = data.body.replace(/(<img[^c]*class="Emoji[^>]*>)|(<img[^c]*class="u-block[^>]*>)/g, '');
|
|
}
|
|
|
|
// Remove display images.
|
|
if (!showImages) {
|
|
data.body = data.body.replace(/(<img[^c]*class="NaturalImage-image[^>]*>|(<img[^c]*class="CroppedImage-image[^>]*>))/g, '');
|
|
}
|
|
// Remove avatar images.
|
|
if (!printUser) {
|
|
data.body = data.body.replace(/(<img[^c]*class="Avatar"[^>]*>)/g, '');
|
|
}
|
|
|
|
var div = document.createElement('div');
|
|
div.innerHTML = data.body;
|
|
if (typeof(div.getElementsByClassName) === 'undefined') {
|
|
supportsClassName = false;
|
|
}
|
|
|
|
function swapDataSrc(element) {
|
|
var avatarImg = element.getElementsByTagName('img')[0];
|
|
if (avatarImg) {
|
|
avatarImg.src = avatarImg.getAttribute('data-src-2x');
|
|
} else {
|
|
var screenName = element.getElementsByTagName('a')[0]
|
|
.getAttribute('href').split('twitter.com/')[1];
|
|
var img = document.createElement('img');
|
|
img.setAttribute('src', 'https://twitter.com/' + screenName +
|
|
'/profile_image?size=bigger');
|
|
element.prepend(img);
|
|
}
|
|
return element;
|
|
}
|
|
|
|
var tweets = [];
|
|
var authors = [];
|
|
var times = [];
|
|
var images = [];
|
|
var rts = [];
|
|
var tids = [];
|
|
var permalinksURL = [];
|
|
var x = 0;
|
|
|
|
if (supportsClassName) {
|
|
var tmp = div.getElementsByClassName('timeline-Tweet');
|
|
while (x < tmp.length) {
|
|
if (tmp[x].getElementsByClassName('timeline-Tweet-retweetCredit').length > 0) {
|
|
rts.push(true);
|
|
} else {
|
|
rts.push(false);
|
|
}
|
|
if (!rts[x] || rts[x] && showRts) {
|
|
tweets.push(tmp[x].getElementsByClassName('timeline-Tweet-text')[0]);
|
|
tids.push(tmp[x].getAttribute('data-tweet-id'));
|
|
if (printUser) {
|
|
authors.push(swapDataSrc(tmp[x].getElementsByClassName('timeline-Tweet-author')[0]));
|
|
}
|
|
times.push(tmp[x].getElementsByClassName('dt-updated')[0]);
|
|
permalinksURL.push(tmp[x].getElementsByClassName('timeline-Tweet-timestamp')[0]);
|
|
if (tmp[x].getElementsByClassName('timeline-Tweet-media')[0] !==
|
|
undefined) {
|
|
images.push(tmp[x].getElementsByClassName('timeline-Tweet-media')[0]);
|
|
} else {
|
|
images.push(undefined);
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
} else {
|
|
var tmp = getElementsByClassName(div, 'timeline-Tweet');
|
|
while (x < tmp.length) {
|
|
if (getElementsByClassName(tmp[x], 'timeline-Tweet-retweetCredit').length > 0) {
|
|
rts.push(true);
|
|
} else {
|
|
rts.push(false);
|
|
}
|
|
if (!rts[x] || rts[x] && showRts) {
|
|
tweets.push(getElementsByClassName(tmp[x], 'timeline-Tweet-text')[0]);
|
|
tids.push(tmp[x].getAttribute('data-tweet-id'));
|
|
if (printUser) {
|
|
authors.push(swapDataSrc(getElementsByClassName(tmp[x],'timeline-Tweet-author')[0]));
|
|
}
|
|
times.push(getElementsByClassName(tmp[x], 'dt-updated')[0]);
|
|
permalinksURL.push(getElementsByClassName(tmp[x], 'timeline-Tweet-timestamp')[0]);
|
|
if (getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0] !== undefined) {
|
|
images.push(getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0]);
|
|
} else {
|
|
images.push(undefined);
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
}
|
|
|
|
if (tweets.length > maxTweets) {
|
|
tweets.splice(maxTweets, (tweets.length - maxTweets));
|
|
authors.splice(maxTweets, (authors.length - maxTweets));
|
|
times.splice(maxTweets, (times.length - maxTweets));
|
|
rts.splice(maxTweets, (rts.length - maxTweets));
|
|
images.splice(maxTweets, (images.length - maxTweets));
|
|
permalinksURL.splice(maxTweets, (permalinksURL.length - maxTweets));
|
|
}
|
|
|
|
var arrayTweets = [];
|
|
var x = tweets.length;
|
|
var n = 0;
|
|
if (dataOnly) {
|
|
while (n < x) {
|
|
arrayTweets.push({
|
|
tweet: tweets[n].innerHTML,
|
|
author: authors[n] ? authors[n].innerHTML : 'Unknown Author',
|
|
author_data: {
|
|
profile_url: authors[n] ? authors[n].querySelector('[data-scribe="element:user_link"]').href : null,
|
|
profile_image: authors[n] ?
|
|
'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=bigger' : null,
|
|
profile_image_2x: authors[n] ? 'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=original' : null,
|
|
screen_name: authors[n] ? authors[n].querySelector('[data-scribe="element:screen_name"]').title : null,
|
|
name: authors[n] ? authors[n].querySelector('[data-scribe="element:name"]').title : null
|
|
},
|
|
time: times[n].textContent,
|
|
timestamp: times[n].getAttribute('datetime').replace('+0000', 'Z').replace(/([\+\-])(\d\d)(\d\d)/, '$1$2:$3'),
|
|
image: (extractImagesUrl(images[n]) ? extractImagesUrl(images[n])[0] : undefined),
|
|
images: extractImagesUrl(images[n]),
|
|
rt: rts[n],
|
|
tid: tids[n],
|
|
permalinkURL: (permalinksURL[n] === undefined) ?
|
|
'' : permalinksURL[n].href
|
|
});
|
|
n++;
|
|
}
|
|
} else {
|
|
while (n < x) {
|
|
if (typeof(formatterFunction) !== 'string') {
|
|
var datetimeText = times[n].getAttribute('datetime');
|
|
var newDate = new Date(times[n].getAttribute('datetime')
|
|
.replace(/-/g,'/').replace('T', ' ').split('+')[0]);
|
|
var dateString = formatterFunction(newDate, datetimeText);
|
|
times[n].setAttribute('aria-label', dateString);
|
|
|
|
if (tweets[n].textContent) {
|
|
// IE hack.
|
|
if (supportsClassName) {
|
|
times[n].textContent = dateString;
|
|
} else {
|
|
var h = document.createElement('p');
|
|
var t = document.createTextNode(dateString);
|
|
h.appendChild(t);
|
|
h.setAttribute('aria-label', dateString);
|
|
times[n] = h;
|
|
}
|
|
} else {
|
|
times[n].textContent = dateString;
|
|
}
|
|
}
|
|
var op = '';
|
|
if (parseLinks) {
|
|
if (targetBlank) {
|
|
targetLinksToNewWindow(tweets[n]);
|
|
if (printUser) {
|
|
targetLinksToNewWindow(authors[n]);
|
|
}
|
|
}
|
|
if (printUser) {
|
|
op += '<div class="user">' + strip(authors[n].innerHTML) +
|
|
'</div>';
|
|
}
|
|
op += '<p class="tweet">' + strip(tweets[n].innerHTML) + '</p>';
|
|
if (printTime) {
|
|
if (permalinks) {
|
|
op += '<p class="timePosted"><a href="' + permalinksURL[n] +
|
|
'">' + times[n].getAttribute('aria-label') + '</a></p>';
|
|
} else {
|
|
op += '<p class="timePosted">' +
|
|
times[n].getAttribute('aria-label') + '</p>';
|
|
}
|
|
}
|
|
} else {
|
|
if (tweets[n].textContent) {
|
|
if (printUser) {
|
|
op += '<p class="user">' + authors[n].textContent + '</p>';
|
|
}
|
|
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
|
|
if (printTime) {
|
|
op += '<p class="timePosted">' + times[n].textContent + '</p>';
|
|
}
|
|
|
|
} else {
|
|
if (printUser) {
|
|
op += '<p class="user">' + authors[n].textContent + '</p>';
|
|
}
|
|
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
|
|
if (printTime) {
|
|
op += '<p class="timePosted">' + times[n].textContent + '</p>';
|
|
}
|
|
}
|
|
}
|
|
if (showInteractionLinks) {
|
|
op += '<p class="interact"><a href="https://twitter.com/intent/' +
|
|
'tweet?in_reply_to=' + tids[n] +
|
|
'" class="twitter_reply_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') +
|
|
'Reply</a><a href="https://twitter.com/intent/retweet?' +
|
|
'tweet_id=' + tids[n] + '" class="twitter_retweet_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + 'Retweet</a>' +
|
|
'<a href="https://twitter.com/intent/favorite?tweet_id=' +
|
|
tids[n] + '" class="twitter_fav_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + 'Favorite</a></p>';
|
|
}
|
|
if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined) {
|
|
var extractedImages = extractImagesUrl(images[n]);
|
|
for (var i = 0; i < extractedImages.length; i++) {
|
|
op += '<div class="media">' +
|
|
'<img src="' + extractedImages[i] +
|
|
'" alt="Image from tweet" />' + '</div>';
|
|
}
|
|
}
|
|
if (showImages) {
|
|
arrayTweets.push(op);
|
|
} else if (!showImages && tweets[n].textContent.length) {
|
|
arrayTweets.push(op);
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
|
|
handleTweets(arrayTweets);
|
|
inProgress = false;
|
|
|
|
if (queue.length > 0) {
|
|
twitterFetcher.fetch(queue[0]);
|
|
queue.splice(0,1);
|
|
}
|
|
}
|
|
};
|
|
|
|
// It must be a global variable because it will be called by JSONP.
|
|
window.__twttrf = twitterFetcher;
|
|
window.twitterFetcher = twitterFetcher;
|
|
return twitterFetcher;
|
|
}));
|
|
|
|
|
|
// Prepend polyfill for IE/Edge.
|
|
(function (arr) {
|
|
arr.forEach(function (item) {
|
|
if (item.hasOwnProperty('prepend')) {
|
|
return;
|
|
}
|
|
Object.defineProperty(item, 'prepend', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
writable: true,
|
|
value: function prepend() {
|
|
var argArr = Array.prototype.slice.call(arguments),
|
|
docFrag = document.createDocumentFragment();
|
|
|
|
argArr.forEach(function (argItem) {
|
|
var isNode = argItem instanceof Node;
|
|
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
|
|
});
|
|
|
|
this.insertBefore(docFrag, this.firstChild);
|
|
}
|
|
});
|
|
});
|
|
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
|
|
(function (factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD
|
|
define(['jquery'], factory);
|
|
} else if (typeof exports === 'object') {
|
|
// CommonJS
|
|
factory(require('jquery'));
|
|
} else {
|
|
// Browser globals
|
|
factory(jQuery);
|
|
}
|
|
}(function ($) {
|
|
var CountTo = function (element, options) {
|
|
this.$element = $(element);
|
|
this.options = $.extend({}, CountTo.DEFAULTS, this.dataOptions(), options);
|
|
this.init();
|
|
};
|
|
|
|
CountTo.DEFAULTS = {
|
|
from: 0, // the number the element should start at
|
|
to: 0, // the number the element should end at
|
|
speed: 1000, // how long it should take to count between the target numbers
|
|
refreshInterval: 100, // how often the element should be updated
|
|
decimals: 0, // the number of decimal places to show
|
|
formatter: formatter, // handler for formatting the value before rendering
|
|
onUpdate: null, // callback method for every time the element is updated
|
|
onComplete: null // callback method for when the element finishes updating
|
|
};
|
|
|
|
CountTo.prototype.init = function () {
|
|
this.value = this.options.from;
|
|
this.loops = Math.ceil(this.options.speed / this.options.refreshInterval);
|
|
this.loopCount = 0;
|
|
this.increment = (this.options.to - this.options.from) / this.loops;
|
|
};
|
|
|
|
CountTo.prototype.dataOptions = function () {
|
|
var options = {
|
|
from: this.$element.data('from'),
|
|
to: this.$element.data('to'),
|
|
speed: this.$element.data('speed'),
|
|
refreshInterval: this.$element.data('refresh-interval'),
|
|
decimals: this.$element.data('decimals')
|
|
};
|
|
|
|
var keys = Object.keys(options);
|
|
|
|
for (var i in keys) {
|
|
var key = keys[i];
|
|
|
|
if (typeof(options[key]) === 'undefined') {
|
|
delete options[key];
|
|
}
|
|
}
|
|
|
|
return options;
|
|
};
|
|
|
|
CountTo.prototype.update = function () {
|
|
this.value += this.increment;
|
|
this.loopCount++;
|
|
|
|
this.render();
|
|
|
|
if (typeof(this.options.onUpdate) == 'function') {
|
|
this.options.onUpdate.call(this.$element, this.value);
|
|
}
|
|
|
|
if (this.loopCount >= this.loops) {
|
|
clearInterval(this.interval);
|
|
this.value = this.options.to;
|
|
|
|
if (typeof(this.options.onComplete) == 'function') {
|
|
this.options.onComplete.call(this.$element, this.value);
|
|
}
|
|
}
|
|
};
|
|
|
|
CountTo.prototype.render = function () {
|
|
var formattedValue = this.options.formatter.call(this.$element, this.value, this.options);
|
|
this.$element.text(formattedValue);
|
|
};
|
|
|
|
CountTo.prototype.restart = function () {
|
|
this.stop();
|
|
this.init();
|
|
this.start();
|
|
};
|
|
|
|
CountTo.prototype.start = function () {
|
|
this.stop();
|
|
this.render();
|
|
this.interval = setInterval(this.update.bind(this), this.options.refreshInterval);
|
|
};
|
|
|
|
CountTo.prototype.stop = function () {
|
|
if (this.interval) {
|
|
clearInterval(this.interval);
|
|
}
|
|
};
|
|
|
|
CountTo.prototype.toggle = function () {
|
|
if (this.interval) {
|
|
this.stop();
|
|
} else {
|
|
this.start();
|
|
}
|
|
};
|
|
|
|
function formatter(value, options) {
|
|
return value.toFixed(options.decimals);
|
|
}
|
|
|
|
$.fn.countTo = function (option) {
|
|
return this.each(function () {
|
|
var $this = $(this);
|
|
var data = $this.data('countTo');
|
|
var init = !data || typeof(option) === 'object';
|
|
var options = typeof(option) === 'object' ? option : {};
|
|
var method = typeof(option) === 'string' ? option : 'start';
|
|
|
|
if (init) {
|
|
if (data) data.stop();
|
|
$this.data('countTo', data = new CountTo(this, options));
|
|
}
|
|
|
|
data[method].call(data);
|
|
});
|
|
};
|
|
}));
|
|
|
|
// Generated by CoffeeScript 1.9.2
|
|
|
|
/**
|
|
@license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
|
|
*/
|
|
|
|
(function() {
|
|
var $, win;
|
|
|
|
$ = this.jQuery || window.jQuery;
|
|
|
|
win = $(window);
|
|
|
|
$.fn.stick_in_parent = function(opts) {
|
|
var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, parent_selector, recalc_every, sticky_class;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
|
|
if (offset_top == null) {
|
|
offset_top = 0;
|
|
}
|
|
if (parent_selector == null) {
|
|
parent_selector = void 0;
|
|
}
|
|
if (inner_scrolling == null) {
|
|
inner_scrolling = true;
|
|
}
|
|
if (sticky_class == null) {
|
|
sticky_class = "is_stuck";
|
|
}
|
|
doc = $(document);
|
|
if (enable_bottoming == null) {
|
|
enable_bottoming = true;
|
|
}
|
|
fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
|
|
var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
|
|
if (elm.data("sticky_kit")) {
|
|
return;
|
|
}
|
|
elm.data("sticky_kit", true);
|
|
last_scroll_height = doc.height();
|
|
parent = elm.parent();
|
|
if (parent_selector != null) {
|
|
parent = parent.closest(parent_selector);
|
|
}
|
|
if (!parent.length) {
|
|
throw "failed to find stick parent";
|
|
}
|
|
fixed = false;
|
|
bottomed = false;
|
|
spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
|
|
if (spacer) {
|
|
spacer.css('position', elm.css('position'));
|
|
}
|
|
recalc = function() {
|
|
var border_top, padding_top, restore;
|
|
if (detached) {
|
|
return;
|
|
}
|
|
last_scroll_height = doc.height();
|
|
border_top = parseInt(parent.css("border-top-width"), 10);
|
|
padding_top = parseInt(parent.css("padding-top"), 10);
|
|
padding_bottom = parseInt(parent.css("padding-bottom"), 10);
|
|
parent_top = parent.offset().top + border_top + padding_top;
|
|
parent_height = parent.height();
|
|
if (fixed) {
|
|
fixed = false;
|
|
bottomed = false;
|
|
if (manual_spacer == null) {
|
|
elm.insertAfter(spacer);
|
|
spacer.detach();
|
|
}
|
|
elm.css({
|
|
position: "",
|
|
top: "",
|
|
width: "",
|
|
bottom: ""
|
|
}).removeClass(sticky_class);
|
|
restore = true;
|
|
}
|
|
top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
|
|
height = elm.outerHeight(true);
|
|
el_float = elm.css("float");
|
|
if (spacer) {
|
|
spacer.css({
|
|
width: elm.outerWidth(true),
|
|
height: height,
|
|
display: elm.css("display"),
|
|
"vertical-align": elm.css("vertical-align"),
|
|
"float": el_float
|
|
});
|
|
}
|
|
if (restore) {
|
|
return tick();
|
|
}
|
|
};
|
|
recalc();
|
|
if (height === parent_height) {
|
|
return;
|
|
}
|
|
last_pos = void 0;
|
|
offset = offset_top;
|
|
recalc_counter = recalc_every;
|
|
tick = function() {
|
|
var css, delta, recalced, scroll, will_bottom, win_height;
|
|
if (detached) {
|
|
return;
|
|
}
|
|
recalced = false;
|
|
if (recalc_counter != null) {
|
|
recalc_counter -= 1;
|
|
if (recalc_counter <= 0) {
|
|
recalc_counter = recalc_every;
|
|
recalc();
|
|
recalced = true;
|
|
}
|
|
}
|
|
if (!recalced && doc.height() !== last_scroll_height) {
|
|
recalc();
|
|
recalced = true;
|
|
}
|
|
scroll = win.scrollTop();
|
|
if (last_pos != null) {
|
|
delta = scroll - last_pos;
|
|
}
|
|
last_pos = scroll;
|
|
if (fixed) {
|
|
if (enable_bottoming) {
|
|
will_bottom = scroll + height + offset > parent_height + parent_top;
|
|
if (bottomed && !will_bottom) {
|
|
bottomed = false;
|
|
elm.css({
|
|
position: "fixed",
|
|
bottom: "",
|
|
top: offset
|
|
}).trigger("sticky_kit:unbottom");
|
|
}
|
|
}
|
|
if (scroll < top) {
|
|
fixed = false;
|
|
offset = offset_top;
|
|
if (manual_spacer == null) {
|
|
if (el_float === "left" || el_float === "right") {
|
|
elm.insertAfter(spacer);
|
|
}
|
|
spacer.detach();
|
|
}
|
|
css = {
|
|
position: "",
|
|
width: "",
|
|
top: ""
|
|
};
|
|
elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
|
|
}
|
|
if (inner_scrolling) {
|
|
win_height = win.height();
|
|
if (height + offset_top > win_height) {
|
|
if (!bottomed) {
|
|
offset -= delta;
|
|
offset = Math.max(win_height - height, offset);
|
|
offset = Math.min(offset_top, offset);
|
|
if (fixed) {
|
|
elm.css({
|
|
top: offset + "px"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (scroll > top) {
|
|
fixed = true;
|
|
css = {
|
|
position: "fixed",
|
|
top: offset
|
|
};
|
|
css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
|
|
elm.css(css).addClass(sticky_class);
|
|
if (manual_spacer == null) {
|
|
elm.after(spacer);
|
|
if (el_float === "left" || el_float === "right") {
|
|
spacer.append(elm);
|
|
}
|
|
}
|
|
elm.trigger("sticky_kit:stick");
|
|
}
|
|
}
|
|
if (fixed && enable_bottoming) {
|
|
if (will_bottom == null) {
|
|
will_bottom = scroll + height + offset > parent_height + parent_top;
|
|
}
|
|
if (!bottomed && will_bottom) {
|
|
bottomed = true;
|
|
if (parent.css("position") === "static") {
|
|
parent.css({
|
|
position: "relative"
|
|
});
|
|
}
|
|
return elm.css({
|
|
position: "absolute",
|
|
bottom: padding_bottom,
|
|
top: "auto"
|
|
}).trigger("sticky_kit:bottom");
|
|
}
|
|
}
|
|
};
|
|
recalc_and_tick = function() {
|
|
recalc();
|
|
return tick();
|
|
};
|
|
detach = function() {
|
|
detached = true;
|
|
win.off("touchmove", tick);
|
|
win.off("scroll", tick);
|
|
win.off("resize", recalc_and_tick);
|
|
$(document.body).off("sticky_kit:recalc", recalc_and_tick);
|
|
elm.off("sticky_kit:detach", detach);
|
|
elm.removeData("sticky_kit");
|
|
elm.css({
|
|
position: "",
|
|
bottom: "",
|
|
top: "",
|
|
width: ""
|
|
});
|
|
parent.position("position", "");
|
|
if (fixed) {
|
|
if (manual_spacer == null) {
|
|
if (el_float === "left" || el_float === "right") {
|
|
elm.insertAfter(spacer);
|
|
}
|
|
spacer.remove();
|
|
}
|
|
return elm.removeClass(sticky_class);
|
|
}
|
|
};
|
|
win.on("touchmove", tick);
|
|
win.on("scroll", tick);
|
|
win.on("resize", recalc_and_tick);
|
|
$(document.body).on("sticky_kit:recalc", recalc_and_tick);
|
|
elm.on("sticky_kit:detach", detach);
|
|
return setTimeout(tick, 0);
|
|
};
|
|
for (i = 0, len = this.length; i < len; i++) {
|
|
elm = this[i];
|
|
fn($(elm));
|
|
}
|
|
return this;
|
|
};
|
|
|
|
}).call(this);
|
|
/**
|
|
* Single Page Nav Plugin
|
|
* Copyright (c) 2014 Chris Wojcik <hello@chriswojcik.net>
|
|
* Dual licensed under MIT and GPL.
|
|
* @author Chris Wojcik
|
|
* @version 1.2.0
|
|
*/
|
|
|
|
// Utility
|
|
if (typeof Object.create !== 'function') {
|
|
Object.create = function(obj) {
|
|
function F() {}
|
|
F.prototype = obj;
|
|
return new F();
|
|
};
|
|
}
|
|
|
|
(function($, window, document, undefined) {
|
|
"use strict";
|
|
|
|
var SinglePageNav = {
|
|
|
|
init: function(options, container) {
|
|
|
|
this.options = $.extend({}, $.fn.singlePageNav.defaults, options);
|
|
|
|
this.container = container;
|
|
this.$container = $(container);
|
|
this.$links = this.$container.find('a');
|
|
|
|
if (this.options.filter !== '') {
|
|
this.$links = this.$links.filter(this.options.filter);
|
|
}
|
|
|
|
this.$window = $(window);
|
|
this.$htmlbody = $('html, body');
|
|
|
|
this.$links.on('click.singlePageNav', $.proxy(this.handleClick, this));
|
|
|
|
this.didScroll = false;
|
|
this.checkPosition();
|
|
this.setTimer();
|
|
},
|
|
|
|
handleClick: function(e) {
|
|
var self = this,
|
|
link = e.currentTarget,
|
|
$elem = $(link.hash);
|
|
|
|
e.preventDefault();
|
|
|
|
if ($elem.length) { // Make sure the target elem exists
|
|
|
|
// Prevent active link from cycling during the scroll
|
|
self.clearTimer();
|
|
|
|
// Before scrolling starts
|
|
if (typeof self.options.beforeStart === 'function') {
|
|
self.options.beforeStart();
|
|
}
|
|
|
|
self.setActiveLink(link.hash);
|
|
|
|
self.scrollTo($elem, function() {
|
|
|
|
if (self.options.updateHash && history.pushState) {
|
|
history.pushState(null,null, link.hash);
|
|
}
|
|
|
|
self.setTimer();
|
|
|
|
// After scrolling ends
|
|
if (typeof self.options.onComplete === 'function') {
|
|
self.options.onComplete();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
scrollTo: function($elem, callback) {
|
|
var self = this;
|
|
var target = self.getCoords($elem).top;
|
|
var called = false;
|
|
|
|
self.$htmlbody.stop().animate(
|
|
{scrollTop: target},
|
|
{
|
|
duration: self.options.speed,
|
|
easing: self.options.easing,
|
|
complete: function() {
|
|
if (typeof callback === 'function' && !called) {
|
|
callback();
|
|
}
|
|
called = true;
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
setTimer: function() {
|
|
var self = this;
|
|
|
|
self.$window.on('scroll.singlePageNav', function() {
|
|
self.didScroll = true;
|
|
});
|
|
|
|
self.timer = setInterval(function() {
|
|
if (self.didScroll) {
|
|
self.didScroll = false;
|
|
self.checkPosition();
|
|
}
|
|
}, 250);
|
|
},
|
|
|
|
clearTimer: function() {
|
|
clearInterval(this.timer);
|
|
this.$window.off('scroll.singlePageNav');
|
|
this.didScroll = false;
|
|
},
|
|
|
|
// Check the scroll position and set the active section
|
|
checkPosition: function() {
|
|
var scrollPos = this.$window.scrollTop();
|
|
var currentSection = this.getCurrentSection(scrollPos);
|
|
if(currentSection!==null) {
|
|
this.setActiveLink(currentSection);
|
|
}
|
|
},
|
|
|
|
getCoords: function($elem) {
|
|
return {
|
|
top: Math.round($elem.offset().top) - this.options.offset
|
|
};
|
|
},
|
|
|
|
setActiveLink: function(href) {
|
|
var $activeLink = this.$container.find("a[href$='" + href + "']");
|
|
|
|
if (!$activeLink.hasClass(this.options.currentClass)) {
|
|
this.$links.removeClass(this.options.currentClass);
|
|
$activeLink.addClass(this.options.currentClass);
|
|
}
|
|
},
|
|
|
|
getCurrentSection: function(scrollPos) {
|
|
var i, hash, coords, section;
|
|
|
|
for (i = 0; i < this.$links.length; i++) {
|
|
hash = this.$links[i].hash;
|
|
|
|
if ($(hash).length) {
|
|
coords = this.getCoords($(hash));
|
|
|
|
if (scrollPos >= coords.top - this.options.threshold) {
|
|
section = hash;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The current section or the first link if it is found
|
|
return section || ((this.$links.length===0) ? (null) : (this.$links[0].hash));
|
|
}
|
|
};
|
|
|
|
$.fn.singlePageNav = function(options) {
|
|
return this.each(function() {
|
|
var singlePageNav = Object.create(SinglePageNav);
|
|
singlePageNav.init(options, this);
|
|
});
|
|
};
|
|
|
|
$.fn.singlePageNav.defaults = {
|
|
offset: 0,
|
|
threshold: 120,
|
|
speed: 400,
|
|
currentClass: 'current',
|
|
easing: 'swing',
|
|
updateHash: false,
|
|
filter: '',
|
|
onComplete: false,
|
|
beforeStart: false
|
|
};
|
|
|
|
})(jQuery, window, document);
|
|
/*!
|
|
* Name : Just Another Parallax [Jarallax]
|
|
* Version : 1.12.3
|
|
* Author : nK <https://nkdev.info>
|
|
* GitHub : https://github.com/nk-o/jarallax
|
|
*/
|
|
/******/ (function(modules) { // webpackBootstrap
|
|
/******/ // The module cache
|
|
/******/ var installedModules = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/
|
|
/******/ // Check if module is in cache
|
|
/******/ if(installedModules[moduleId]) {
|
|
/******/ return installedModules[moduleId].exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = installedModules[moduleId] = {
|
|
/******/ i: moduleId,
|
|
/******/ l: false,
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Flag the module as loaded
|
|
/******/ module.l = true;
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/******/
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
/******/ __webpack_require__.m = modules;
|
|
/******/
|
|
/******/ // expose the module cache
|
|
/******/ __webpack_require__.c = installedModules;
|
|
/******/
|
|
/******/ // define getter function for harmony exports
|
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
/******/ }
|
|
/******/ };
|
|
/******/
|
|
/******/ // define __esModule on exports
|
|
/******/ __webpack_require__.r = function(exports) {
|
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
/******/ }
|
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
/******/ };
|
|
/******/
|
|
/******/ // create a fake namespace object
|
|
/******/ // mode & 1: value is a module id, require it
|
|
/******/ // mode & 2: merge all properties of value into the ns
|
|
/******/ // mode & 4: return value when already ns object
|
|
/******/ // mode & 8|1: behave like require
|
|
/******/ __webpack_require__.t = function(value, mode) {
|
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
|
/******/ if(mode & 8) return value;
|
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
/******/ var ns = Object.create(null);
|
|
/******/ __webpack_require__.r(ns);
|
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
/******/ return ns;
|
|
/******/ };
|
|
/******/
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
/******/ __webpack_require__.n = function(module) {
|
|
/******/ var getter = module && module.__esModule ?
|
|
/******/ function getDefault() { return module['default']; } :
|
|
/******/ function getModuleExports() { return module; };
|
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
/******/ return getter;
|
|
/******/ };
|
|
/******/
|
|
/******/ // Object.prototype.hasOwnProperty.call
|
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
/******/
|
|
/******/ // __webpack_public_path__
|
|
/******/ __webpack_require__.p = "";
|
|
/******/
|
|
/******/
|
|
/******/ // Load entry module and return exports
|
|
/******/ return __webpack_require__(__webpack_require__.s = 10);
|
|
/******/ })
|
|
/************************************************************************/
|
|
/******/ ([
|
|
/* 0 */,
|
|
/* 1 */,
|
|
/* 2 */
|
|
/***/ (function(module, exports) {
|
|
|
|
module.exports = function (callback) {
|
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
// Already ready or interactive, execute callback
|
|
callback.call();
|
|
} else if (document.attachEvent) {
|
|
// Old browsers
|
|
document.attachEvent('onreadystatechange', function () {
|
|
if (document.readyState === 'interactive') callback.call();
|
|
});
|
|
} else if (document.addEventListener) {
|
|
// Modern browsers
|
|
document.addEventListener('DOMContentLoaded', callback);
|
|
}
|
|
};
|
|
|
|
/***/ }),
|
|
/* 3 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
/* WEBPACK VAR INJECTION */(function(global) {var win;
|
|
|
|
if (typeof window !== "undefined") {
|
|
win = window;
|
|
} else if (typeof global !== "undefined") {
|
|
win = global;
|
|
} else if (typeof self !== "undefined") {
|
|
win = self;
|
|
} else {
|
|
win = {};
|
|
}
|
|
|
|
module.exports = win;
|
|
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(4)))
|
|
|
|
/***/ }),
|
|
/* 4 */
|
|
/***/ (function(module, exports) {
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
var g; // This works in non-strict mode
|
|
|
|
g = function () {
|
|
return this;
|
|
}();
|
|
|
|
try {
|
|
// This works if eval is allowed (see CSP)
|
|
g = g || new Function("return this")();
|
|
} catch (e) {
|
|
// This works if the window reference is available
|
|
if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") g = window;
|
|
} // g can still be undefined, but nothing to do about it...
|
|
// We return undefined, instead of nothing here, so it's
|
|
// easier to handle this case. if(!global) { ...}
|
|
|
|
|
|
module.exports = g;
|
|
|
|
/***/ }),
|
|
/* 5 */,
|
|
/* 6 */,
|
|
/* 7 */,
|
|
/* 8 */,
|
|
/* 9 */,
|
|
/* 10 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
module.exports = __webpack_require__(11);
|
|
|
|
|
|
/***/ }),
|
|
/* 11 */
|
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lite_ready__WEBPACK_IMPORTED_MODULE_0__);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global__WEBPACK_IMPORTED_MODULE_1__);
|
|
/* harmony import */ var _jarallax_esm__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(12);
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
|
|
|
|
// no conflict
|
|
|
|
var oldPlugin = global__WEBPACK_IMPORTED_MODULE_1__["window"].jarallax;
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].jarallax = _jarallax_esm__WEBPACK_IMPORTED_MODULE_2__["default"];
|
|
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].jarallax.noConflict = function () {
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].jarallax = oldPlugin;
|
|
return this;
|
|
}; // jQuery support
|
|
|
|
|
|
if ('undefined' !== typeof global__WEBPACK_IMPORTED_MODULE_1__["jQuery"]) {
|
|
var jQueryPlugin = function jQueryPlugin() {
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
Array.prototype.unshift.call(args, this);
|
|
var res = _jarallax_esm__WEBPACK_IMPORTED_MODULE_2__["default"].apply(global__WEBPACK_IMPORTED_MODULE_1__["window"], args);
|
|
return 'object' !== _typeof(res) ? res : this;
|
|
};
|
|
|
|
jQueryPlugin.constructor = _jarallax_esm__WEBPACK_IMPORTED_MODULE_2__["default"].constructor; // no conflict
|
|
|
|
var oldJqPlugin = global__WEBPACK_IMPORTED_MODULE_1__["jQuery"].fn.jarallax;
|
|
global__WEBPACK_IMPORTED_MODULE_1__["jQuery"].fn.jarallax = jQueryPlugin;
|
|
|
|
global__WEBPACK_IMPORTED_MODULE_1__["jQuery"].fn.jarallax.noConflict = function () {
|
|
global__WEBPACK_IMPORTED_MODULE_1__["jQuery"].fn.jarallax = oldJqPlugin;
|
|
return this;
|
|
};
|
|
} // data-jarallax initialization
|
|
|
|
|
|
lite_ready__WEBPACK_IMPORTED_MODULE_0___default()(function () {
|
|
Object(_jarallax_esm__WEBPACK_IMPORTED_MODULE_2__["default"])(document.querySelectorAll('[data-jarallax]'));
|
|
});
|
|
|
|
/***/ }),
|
|
/* 12 */
|
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lite_ready__WEBPACK_IMPORTED_MODULE_0__);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global__WEBPACK_IMPORTED_MODULE_1__);
|
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
|
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
|
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
|
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
|
|
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
|
|
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
|
|
|
|
var navigator = global__WEBPACK_IMPORTED_MODULE_1__["window"].navigator;
|
|
var isIE = -1 < navigator.userAgent.indexOf('MSIE ') || -1 < navigator.userAgent.indexOf('Trident/') || -1 < navigator.userAgent.indexOf('Edge/');
|
|
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
|
|
var supportTransform = function () {
|
|
var prefixes = 'transform WebkitTransform MozTransform'.split(' ');
|
|
var div = document.createElement('div');
|
|
|
|
for (var i = 0; i < prefixes.length; i += 1) {
|
|
if (div && div.style[prefixes[i]] !== undefined) {
|
|
return prefixes[i];
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}();
|
|
|
|
var $deviceHelper;
|
|
/**
|
|
* The most popular mobile browsers changes height after page scroll and this generates image jumping.
|
|
* We can fix it using this workaround with vh units.
|
|
*/
|
|
|
|
function getDeviceHeight() {
|
|
if (!$deviceHelper && document.body) {
|
|
$deviceHelper = document.createElement('div');
|
|
$deviceHelper.style.cssText = 'position: fixed; top: -9999px; left: 0; height: 100vh; width: 0;';
|
|
document.body.appendChild($deviceHelper);
|
|
}
|
|
|
|
return ($deviceHelper ? $deviceHelper.clientHeight : 0) || global__WEBPACK_IMPORTED_MODULE_1__["window"].innerHeight || document.documentElement.clientHeight;
|
|
} // Window height data
|
|
|
|
|
|
var wndH;
|
|
|
|
function updateWndVars() {
|
|
if (isMobile) {
|
|
wndH = getDeviceHeight();
|
|
} else {
|
|
wndH = global__WEBPACK_IMPORTED_MODULE_1__["window"].innerHeight || document.documentElement.clientHeight;
|
|
}
|
|
}
|
|
|
|
updateWndVars();
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].addEventListener('resize', updateWndVars);
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].addEventListener('orientationchange', updateWndVars);
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].addEventListener('load', updateWndVars);
|
|
lite_ready__WEBPACK_IMPORTED_MODULE_0___default()(function () {
|
|
updateWndVars({
|
|
type: 'dom-loaded'
|
|
});
|
|
}); // list with all jarallax instances
|
|
// need to render all in one scroll/resize event
|
|
|
|
var jarallaxList = []; // get all parents of the element.
|
|
|
|
function getParents(elem) {
|
|
var parents = [];
|
|
|
|
while (null !== elem.parentElement) {
|
|
elem = elem.parentElement;
|
|
|
|
if (1 === elem.nodeType) {
|
|
parents.push(elem);
|
|
}
|
|
}
|
|
|
|
return parents;
|
|
}
|
|
|
|
function updateParallax() {
|
|
if (!jarallaxList.length) {
|
|
return;
|
|
}
|
|
|
|
jarallaxList.forEach(function (data, k) {
|
|
var instance = data.instance,
|
|
oldData = data.oldData;
|
|
var clientRect = instance.$item.getBoundingClientRect();
|
|
var newData = {
|
|
width: clientRect.width,
|
|
height: clientRect.height,
|
|
top: clientRect.top,
|
|
bottom: clientRect.bottom,
|
|
wndW: global__WEBPACK_IMPORTED_MODULE_1__["window"].innerWidth,
|
|
wndH: wndH
|
|
};
|
|
var isResized = !oldData || oldData.wndW !== newData.wndW || oldData.wndH !== newData.wndH || oldData.width !== newData.width || oldData.height !== newData.height;
|
|
var isScrolled = isResized || !oldData || oldData.top !== newData.top || oldData.bottom !== newData.bottom;
|
|
jarallaxList[k].oldData = newData;
|
|
|
|
if (isResized) {
|
|
instance.onResize();
|
|
}
|
|
|
|
if (isScrolled) {
|
|
instance.onScroll();
|
|
}
|
|
});
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].requestAnimationFrame(updateParallax);
|
|
}
|
|
|
|
var instanceID = 0; // Jarallax class
|
|
|
|
var Jarallax = /*#__PURE__*/function () {
|
|
function Jarallax(item, userOptions) {
|
|
_classCallCheck(this, Jarallax);
|
|
|
|
var self = this;
|
|
self.instanceID = instanceID;
|
|
instanceID += 1;
|
|
self.$item = item;
|
|
self.defaults = {
|
|
type: 'scroll',
|
|
// type of parallax: scroll, scale, opacity, scale-opacity, scroll-opacity
|
|
speed: 0.5,
|
|
// supported value from -1 to 2
|
|
imgSrc: null,
|
|
imgElement: '.jarallax-img',
|
|
imgSize: 'cover',
|
|
imgPosition: '50% 50%',
|
|
imgRepeat: 'no-repeat',
|
|
// supported only for background, not for <img> tag
|
|
keepImg: false,
|
|
// keep <img> tag in it's default place
|
|
elementInViewport: null,
|
|
zIndex: -100,
|
|
disableParallax: false,
|
|
disableVideo: false,
|
|
// video
|
|
videoSrc: null,
|
|
videoStartTime: 0,
|
|
videoEndTime: 0,
|
|
videoVolume: 0,
|
|
videoLoop: true,
|
|
videoPlayOnlyVisible: true,
|
|
videoLazyLoading: true,
|
|
// events
|
|
onScroll: null,
|
|
// function(calculations) {}
|
|
onInit: null,
|
|
// function() {}
|
|
onDestroy: null,
|
|
// function() {}
|
|
onCoverImage: null // function() {}
|
|
|
|
}; // prepare data-options
|
|
|
|
var dataOptions = self.$item.dataset || {};
|
|
var pureDataOptions = {};
|
|
Object.keys(dataOptions).forEach(function (key) {
|
|
var loweCaseOption = key.substr(0, 1).toLowerCase() + key.substr(1);
|
|
|
|
if (loweCaseOption && 'undefined' !== typeof self.defaults[loweCaseOption]) {
|
|
pureDataOptions[loweCaseOption] = dataOptions[key];
|
|
}
|
|
});
|
|
self.options = self.extend({}, self.defaults, pureDataOptions, userOptions);
|
|
self.pureOptions = self.extend({}, self.options); // prepare 'true' and 'false' strings to boolean
|
|
|
|
Object.keys(self.options).forEach(function (key) {
|
|
if ('true' === self.options[key]) {
|
|
self.options[key] = true;
|
|
} else if ('false' === self.options[key]) {
|
|
self.options[key] = false;
|
|
}
|
|
}); // fix speed option [-1.0, 2.0]
|
|
|
|
self.options.speed = Math.min(2, Math.max(-1, parseFloat(self.options.speed))); // prepare disableParallax callback
|
|
|
|
if ('string' === typeof self.options.disableParallax) {
|
|
self.options.disableParallax = new RegExp(self.options.disableParallax);
|
|
}
|
|
|
|
if (self.options.disableParallax instanceof RegExp) {
|
|
var disableParallaxRegexp = self.options.disableParallax;
|
|
|
|
self.options.disableParallax = function () {
|
|
return disableParallaxRegexp.test(navigator.userAgent);
|
|
};
|
|
}
|
|
|
|
if ('function' !== typeof self.options.disableParallax) {
|
|
self.options.disableParallax = function () {
|
|
return false;
|
|
};
|
|
} // prepare disableVideo callback
|
|
|
|
|
|
if ('string' === typeof self.options.disableVideo) {
|
|
self.options.disableVideo = new RegExp(self.options.disableVideo);
|
|
}
|
|
|
|
if (self.options.disableVideo instanceof RegExp) {
|
|
var disableVideoRegexp = self.options.disableVideo;
|
|
|
|
self.options.disableVideo = function () {
|
|
return disableVideoRegexp.test(navigator.userAgent);
|
|
};
|
|
}
|
|
|
|
if ('function' !== typeof self.options.disableVideo) {
|
|
self.options.disableVideo = function () {
|
|
return false;
|
|
};
|
|
} // custom element to check if parallax in viewport
|
|
|
|
|
|
var elementInVP = self.options.elementInViewport; // get first item from array
|
|
|
|
if (elementInVP && 'object' === _typeof(elementInVP) && 'undefined' !== typeof elementInVP.length) {
|
|
var _elementInVP = elementInVP;
|
|
|
|
var _elementInVP2 = _slicedToArray(_elementInVP, 1);
|
|
|
|
elementInVP = _elementInVP2[0];
|
|
} // check if dom element
|
|
|
|
|
|
if (!(elementInVP instanceof Element)) {
|
|
elementInVP = null;
|
|
}
|
|
|
|
self.options.elementInViewport = elementInVP;
|
|
self.image = {
|
|
src: self.options.imgSrc || null,
|
|
$container: null,
|
|
useImgTag: false,
|
|
// position fixed is needed for the most of browsers because absolute position have glitches
|
|
// on MacOS with smooth scroll there is a huge lags with absolute position - https://github.com/nk-o/jarallax/issues/75
|
|
// on mobile devices better scrolled with absolute position
|
|
position: /iPad|iPhone|iPod|Android/.test(navigator.userAgent) ? 'absolute' : 'fixed'
|
|
};
|
|
|
|
if (self.initImg() && self.canInitParallax()) {
|
|
self.init();
|
|
}
|
|
} // add styles to element
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
|
|
_createClass(Jarallax, [{
|
|
key: "css",
|
|
value: function css(el, styles) {
|
|
if ('string' === typeof styles) {
|
|
return global__WEBPACK_IMPORTED_MODULE_1__["window"].getComputedStyle(el).getPropertyValue(styles);
|
|
} // add transform property with vendor prefix
|
|
|
|
|
|
if (styles.transform && supportTransform) {
|
|
styles[supportTransform] = styles.transform;
|
|
}
|
|
|
|
Object.keys(styles).forEach(function (key) {
|
|
el.style[key] = styles[key];
|
|
});
|
|
return el;
|
|
} // Extend like jQuery.extend
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
}, {
|
|
key: "extend",
|
|
value: function extend(out) {
|
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
out = out || {};
|
|
Object.keys(args).forEach(function (i) {
|
|
if (!args[i]) {
|
|
return;
|
|
}
|
|
|
|
Object.keys(args[i]).forEach(function (key) {
|
|
out[key] = args[i][key];
|
|
});
|
|
});
|
|
return out;
|
|
} // get window size and scroll position. Useful for extensions
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
}, {
|
|
key: "getWindowData",
|
|
value: function getWindowData() {
|
|
return {
|
|
width: global__WEBPACK_IMPORTED_MODULE_1__["window"].innerWidth || document.documentElement.clientWidth,
|
|
height: wndH,
|
|
y: document.documentElement.scrollTop
|
|
};
|
|
} // Jarallax functions
|
|
|
|
}, {
|
|
key: "initImg",
|
|
value: function initImg() {
|
|
var self = this; // find image element
|
|
|
|
var $imgElement = self.options.imgElement;
|
|
|
|
if ($imgElement && 'string' === typeof $imgElement) {
|
|
$imgElement = self.$item.querySelector($imgElement);
|
|
} // check if dom element
|
|
|
|
|
|
if (!($imgElement instanceof Element)) {
|
|
if (self.options.imgSrc) {
|
|
$imgElement = new Image();
|
|
$imgElement.src = self.options.imgSrc;
|
|
} else {
|
|
$imgElement = null;
|
|
}
|
|
}
|
|
|
|
if ($imgElement) {
|
|
if (self.options.keepImg) {
|
|
self.image.$item = $imgElement.cloneNode(true);
|
|
} else {
|
|
self.image.$item = $imgElement;
|
|
self.image.$itemParent = $imgElement.parentNode;
|
|
}
|
|
|
|
self.image.useImgTag = true;
|
|
} // true if there is img tag
|
|
|
|
|
|
if (self.image.$item) {
|
|
return true;
|
|
} // get image src
|
|
|
|
|
|
if (null === self.image.src) {
|
|
self.image.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
self.image.bgImage = self.css(self.$item, 'background-image');
|
|
}
|
|
|
|
return !(!self.image.bgImage || 'none' === self.image.bgImage);
|
|
}
|
|
}, {
|
|
key: "canInitParallax",
|
|
value: function canInitParallax() {
|
|
return supportTransform && !this.options.disableParallax();
|
|
}
|
|
}, {
|
|
key: "init",
|
|
value: function init() {
|
|
var self = this;
|
|
var containerStyles = {
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
height: '100%',
|
|
overflow: 'hidden'
|
|
};
|
|
var imageStyles = {
|
|
pointerEvents: 'none',
|
|
transformStyle: 'preserve-3d',
|
|
backfaceVisibility: 'hidden',
|
|
willChange: 'transform,opacity'
|
|
};
|
|
|
|
if (!self.options.keepImg) {
|
|
// save default user styles
|
|
var curStyle = self.$item.getAttribute('style');
|
|
|
|
if (curStyle) {
|
|
self.$item.setAttribute('data-jarallax-original-styles', curStyle);
|
|
}
|
|
|
|
if (self.image.useImgTag) {
|
|
var curImgStyle = self.image.$item.getAttribute('style');
|
|
|
|
if (curImgStyle) {
|
|
self.image.$item.setAttribute('data-jarallax-original-styles', curImgStyle);
|
|
}
|
|
}
|
|
} // set relative position and z-index to the parent
|
|
|
|
|
|
if ('static' === self.css(self.$item, 'position')) {
|
|
self.css(self.$item, {
|
|
position: 'relative'
|
|
});
|
|
}
|
|
|
|
if ('auto' === self.css(self.$item, 'z-index')) {
|
|
self.css(self.$item, {
|
|
zIndex: 0
|
|
});
|
|
} // container for parallax image
|
|
|
|
|
|
self.image.$container = document.createElement('div');
|
|
self.css(self.image.$container, containerStyles);
|
|
self.css(self.image.$container, {
|
|
'z-index': self.options.zIndex
|
|
}); // fix for IE https://github.com/nk-o/jarallax/issues/110
|
|
|
|
if (isIE) {
|
|
self.css(self.image.$container, {
|
|
opacity: 0.9999
|
|
});
|
|
}
|
|
|
|
self.image.$container.setAttribute('id', "jarallax-container-".concat(self.instanceID));
|
|
self.$item.appendChild(self.image.$container); // use img tag
|
|
|
|
if (self.image.useImgTag) {
|
|
imageStyles = self.extend({
|
|
'object-fit': self.options.imgSize,
|
|
'object-position': self.options.imgPosition,
|
|
// support for plugin https://github.com/bfred-it/object-fit-images
|
|
'font-family': "object-fit: ".concat(self.options.imgSize, "; object-position: ").concat(self.options.imgPosition, ";"),
|
|
'max-width': 'none'
|
|
}, containerStyles, imageStyles); // use div with background image
|
|
} else {
|
|
self.image.$item = document.createElement('div');
|
|
|
|
if (self.image.src) {
|
|
imageStyles = self.extend({
|
|
'background-position': self.options.imgPosition,
|
|
'background-size': self.options.imgSize,
|
|
'background-repeat': self.options.imgRepeat,
|
|
'background-image': self.image.bgImage || "url(\"".concat(self.image.src, "\")")
|
|
}, containerStyles, imageStyles);
|
|
}
|
|
}
|
|
|
|
if ('opacity' === self.options.type || 'scale' === self.options.type || 'scale-opacity' === self.options.type || 1 === self.options.speed) {
|
|
self.image.position = 'absolute';
|
|
} // 1. Check if one of parents have transform style (without this check, scroll transform will be inverted if used parallax with position fixed)
|
|
// discussion - https://github.com/nk-o/jarallax/issues/9
|
|
// 2. Check if parents have overflow scroll
|
|
|
|
|
|
if ('fixed' === self.image.position) {
|
|
var $parents = getParents(self.$item).filter(function (el) {
|
|
var styles = global__WEBPACK_IMPORTED_MODULE_1__["window"].getComputedStyle(el);
|
|
var parentTransform = styles['-webkit-transform'] || styles['-moz-transform'] || styles.transform;
|
|
var overflowRegex = /(auto|scroll)/;
|
|
return parentTransform && 'none' !== parentTransform || overflowRegex.test(styles.overflow + styles['overflow-y'] + styles['overflow-x']);
|
|
});
|
|
self.image.position = $parents.length ? 'absolute' : 'fixed';
|
|
} // add position to parallax block
|
|
|
|
|
|
imageStyles.position = self.image.position; // insert parallax image
|
|
|
|
self.css(self.image.$item, imageStyles);
|
|
self.image.$container.appendChild(self.image.$item); // set initial position and size
|
|
|
|
self.onResize();
|
|
self.onScroll(true); // call onInit event
|
|
|
|
if (self.options.onInit) {
|
|
self.options.onInit.call(self);
|
|
} // remove default user background
|
|
|
|
|
|
if ('none' !== self.css(self.$item, 'background-image')) {
|
|
self.css(self.$item, {
|
|
'background-image': 'none'
|
|
});
|
|
}
|
|
|
|
self.addToParallaxList();
|
|
} // add to parallax instances list
|
|
|
|
}, {
|
|
key: "addToParallaxList",
|
|
value: function addToParallaxList() {
|
|
jarallaxList.push({
|
|
instance: this
|
|
});
|
|
|
|
if (1 === jarallaxList.length) {
|
|
global__WEBPACK_IMPORTED_MODULE_1__["window"].requestAnimationFrame(updateParallax);
|
|
}
|
|
} // remove from parallax instances list
|
|
|
|
}, {
|
|
key: "removeFromParallaxList",
|
|
value: function removeFromParallaxList() {
|
|
var self = this;
|
|
jarallaxList.forEach(function (data, key) {
|
|
if (data.instance.instanceID === self.instanceID) {
|
|
jarallaxList.splice(key, 1);
|
|
}
|
|
});
|
|
}
|
|
}, {
|
|
key: "destroy",
|
|
value: function destroy() {
|
|
var self = this;
|
|
self.removeFromParallaxList(); // return styles on container as before jarallax init
|
|
|
|
var originalStylesTag = self.$item.getAttribute('data-jarallax-original-styles');
|
|
self.$item.removeAttribute('data-jarallax-original-styles'); // null occurs if there is no style tag before jarallax init
|
|
|
|
if (!originalStylesTag) {
|
|
self.$item.removeAttribute('style');
|
|
} else {
|
|
self.$item.setAttribute('style', originalStylesTag);
|
|
}
|
|
|
|
if (self.image.useImgTag) {
|
|
// return styles on img tag as before jarallax init
|
|
var originalStylesImgTag = self.image.$item.getAttribute('data-jarallax-original-styles');
|
|
self.image.$item.removeAttribute('data-jarallax-original-styles'); // null occurs if there is no style tag before jarallax init
|
|
|
|
if (!originalStylesImgTag) {
|
|
self.image.$item.removeAttribute('style');
|
|
} else {
|
|
self.image.$item.setAttribute('style', originalStylesTag);
|
|
} // move img tag to its default position
|
|
|
|
|
|
if (self.image.$itemParent) {
|
|
self.image.$itemParent.appendChild(self.image.$item);
|
|
}
|
|
} // remove additional dom elements
|
|
|
|
|
|
if (self.$clipStyles) {
|
|
self.$clipStyles.parentNode.removeChild(self.$clipStyles);
|
|
}
|
|
|
|
if (self.image.$container) {
|
|
self.image.$container.parentNode.removeChild(self.image.$container);
|
|
} // call onDestroy event
|
|
|
|
|
|
if (self.options.onDestroy) {
|
|
self.options.onDestroy.call(self);
|
|
} // delete jarallax from item
|
|
|
|
|
|
delete self.$item.jarallax;
|
|
} // it will remove some image overlapping
|
|
// overlapping occur due to an image position fixed inside absolute position element
|
|
|
|
}, {
|
|
key: "clipContainer",
|
|
value: function clipContainer() {
|
|
// needed only when background in fixed position
|
|
if ('fixed' !== this.image.position) {
|
|
return;
|
|
}
|
|
|
|
var self = this;
|
|
var rect = self.image.$container.getBoundingClientRect();
|
|
var width = rect.width,
|
|
height = rect.height;
|
|
|
|
if (!self.$clipStyles) {
|
|
self.$clipStyles = document.createElement('style');
|
|
self.$clipStyles.setAttribute('type', 'text/css');
|
|
self.$clipStyles.setAttribute('id', "jarallax-clip-".concat(self.instanceID));
|
|
var head = document.head || document.getElementsByTagName('head')[0];
|
|
head.appendChild(self.$clipStyles);
|
|
} // clip is used for old browsers.
|
|
// clip-path for modern browsers (also fixes Safari v14 bug https://github.com/nk-o/jarallax/issues/181 ).
|
|
|
|
|
|
var styles = "#jarallax-container-".concat(self.instanceID, " {\n clip: rect(0 ").concat(width, "px ").concat(height, "px 0);\n clip: rect(0, ").concat(width, "px, ").concat(height, "px, 0);\n -webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);\n clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);\n }"); // add clip styles inline (this method need for support IE8 and less browsers)
|
|
|
|
if (self.$clipStyles.styleSheet) {
|
|
self.$clipStyles.styleSheet.cssText = styles;
|
|
} else {
|
|
self.$clipStyles.innerHTML = styles;
|
|
}
|
|
}
|
|
}, {
|
|
key: "coverImage",
|
|
value: function coverImage() {
|
|
var self = this;
|
|
var rect = self.image.$container.getBoundingClientRect();
|
|
var contH = rect.height;
|
|
var speed = self.options.speed;
|
|
var isScroll = 'scroll' === self.options.type || 'scroll-opacity' === self.options.type;
|
|
var scrollDist = 0;
|
|
var resultH = contH;
|
|
var resultMT = 0; // scroll parallax
|
|
|
|
if (isScroll) {
|
|
// scroll distance and height for image
|
|
if (0 > speed) {
|
|
scrollDist = speed * Math.max(contH, wndH);
|
|
|
|
if (wndH < contH) {
|
|
scrollDist -= speed * (contH - wndH);
|
|
}
|
|
} else {
|
|
scrollDist = speed * (contH + wndH);
|
|
} // size for scroll parallax
|
|
|
|
|
|
if (1 < speed) {
|
|
resultH = Math.abs(scrollDist - wndH);
|
|
} else if (0 > speed) {
|
|
resultH = scrollDist / speed + Math.abs(scrollDist);
|
|
} else {
|
|
resultH += (wndH - contH) * (1 - speed);
|
|
}
|
|
|
|
scrollDist /= 2;
|
|
} // store scroll distance
|
|
|
|
|
|
self.parallaxScrollDistance = scrollDist; // vertical center
|
|
|
|
if (isScroll) {
|
|
resultMT = (wndH - resultH) / 2;
|
|
} else {
|
|
resultMT = (contH - resultH) / 2;
|
|
} // apply result to item
|
|
|
|
|
|
self.css(self.image.$item, {
|
|
height: "".concat(resultH, "px"),
|
|
marginTop: "".concat(resultMT, "px"),
|
|
left: 'fixed' === self.image.position ? "".concat(rect.left, "px") : '0',
|
|
width: "".concat(rect.width, "px")
|
|
}); // call onCoverImage event
|
|
|
|
if (self.options.onCoverImage) {
|
|
self.options.onCoverImage.call(self);
|
|
} // return some useful data. Used in the video cover function
|
|
|
|
|
|
return {
|
|
image: {
|
|
height: resultH,
|
|
marginTop: resultMT
|
|
},
|
|
container: rect
|
|
};
|
|
}
|
|
}, {
|
|
key: "isVisible",
|
|
value: function isVisible() {
|
|
return this.isElementInViewport || false;
|
|
}
|
|
}, {
|
|
key: "onScroll",
|
|
value: function onScroll(force) {
|
|
var self = this;
|
|
var rect = self.$item.getBoundingClientRect();
|
|
var contT = rect.top;
|
|
var contH = rect.height;
|
|
var styles = {}; // check if in viewport
|
|
|
|
var viewportRect = rect;
|
|
|
|
if (self.options.elementInViewport) {
|
|
viewportRect = self.options.elementInViewport.getBoundingClientRect();
|
|
}
|
|
|
|
self.isElementInViewport = 0 <= viewportRect.bottom && 0 <= viewportRect.right && viewportRect.top <= wndH && viewportRect.left <= global__WEBPACK_IMPORTED_MODULE_1__["window"].innerWidth; // stop calculations if item is not in viewport
|
|
|
|
if (force ? false : !self.isElementInViewport) {
|
|
return;
|
|
} // calculate parallax helping variables
|
|
|
|
|
|
var beforeTop = Math.max(0, contT);
|
|
var beforeTopEnd = Math.max(0, contH + contT);
|
|
var afterTop = Math.max(0, -contT);
|
|
var beforeBottom = Math.max(0, contT + contH - wndH);
|
|
var beforeBottomEnd = Math.max(0, contH - (contT + contH - wndH));
|
|
var afterBottom = Math.max(0, -contT + wndH - contH);
|
|
var fromViewportCenter = 1 - 2 * ((wndH - contT) / (wndH + contH)); // calculate on how percent of section is visible
|
|
|
|
var visiblePercent = 1;
|
|
|
|
if (contH < wndH) {
|
|
visiblePercent = 1 - (afterTop || beforeBottom) / contH;
|
|
} else if (beforeTopEnd <= wndH) {
|
|
visiblePercent = beforeTopEnd / wndH;
|
|
} else if (beforeBottomEnd <= wndH) {
|
|
visiblePercent = beforeBottomEnd / wndH;
|
|
} // opacity
|
|
|
|
|
|
if ('opacity' === self.options.type || 'scale-opacity' === self.options.type || 'scroll-opacity' === self.options.type) {
|
|
styles.transform = 'translate3d(0,0,0)';
|
|
styles.opacity = visiblePercent;
|
|
} // scale
|
|
|
|
|
|
if ('scale' === self.options.type || 'scale-opacity' === self.options.type) {
|
|
var scale = 1;
|
|
|
|
if (0 > self.options.speed) {
|
|
scale -= self.options.speed * visiblePercent;
|
|
} else {
|
|
scale += self.options.speed * (1 - visiblePercent);
|
|
}
|
|
|
|
styles.transform = "scale(".concat(scale, ") translate3d(0,0,0)");
|
|
} // scroll
|
|
|
|
|
|
if ('scroll' === self.options.type || 'scroll-opacity' === self.options.type) {
|
|
var positionY = self.parallaxScrollDistance * fromViewportCenter; // fix if parallax block in absolute position
|
|
|
|
if ('absolute' === self.image.position) {
|
|
positionY -= contT;
|
|
}
|
|
|
|
styles.transform = "translate3d(0,".concat(positionY, "px,0)");
|
|
}
|
|
|
|
self.css(self.image.$item, styles); // call onScroll event
|
|
|
|
if (self.options.onScroll) {
|
|
self.options.onScroll.call(self, {
|
|
section: rect,
|
|
beforeTop: beforeTop,
|
|
beforeTopEnd: beforeTopEnd,
|
|
afterTop: afterTop,
|
|
beforeBottom: beforeBottom,
|
|
beforeBottomEnd: beforeBottomEnd,
|
|
afterBottom: afterBottom,
|
|
visiblePercent: visiblePercent,
|
|
fromViewportCenter: fromViewportCenter
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: "onResize",
|
|
value: function onResize() {
|
|
this.coverImage();
|
|
this.clipContainer();
|
|
}
|
|
}]);
|
|
|
|
return Jarallax;
|
|
}(); // global definition
|
|
|
|
|
|
var plugin = function plugin(items, options) {
|
|
// check for dom element
|
|
// thanks: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
|
|
if ('object' === (typeof HTMLElement === "undefined" ? "undefined" : _typeof(HTMLElement)) ? items instanceof HTMLElement : items && 'object' === _typeof(items) && null !== items && 1 === items.nodeType && 'string' === typeof items.nodeName) {
|
|
items = [items];
|
|
}
|
|
|
|
var len = items.length;
|
|
var k = 0;
|
|
var ret;
|
|
|
|
for (var _len2 = arguments.length, args = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
|
|
args[_key2 - 2] = arguments[_key2];
|
|
}
|
|
|
|
for (k; k < len; k += 1) {
|
|
if ('object' === _typeof(options) || 'undefined' === typeof options) {
|
|
if (!items[k].jarallax) {
|
|
items[k].jarallax = new Jarallax(items[k], options);
|
|
}
|
|
} else if (items[k].jarallax) {
|
|
// eslint-disable-next-line prefer-spread
|
|
ret = items[k].jarallax[options].apply(items[k].jarallax, args);
|
|
}
|
|
|
|
if ('undefined' !== typeof ret) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return items;
|
|
};
|
|
|
|
plugin.constructor = Jarallax;
|
|
/* harmony default export */ __webpack_exports__["default"] = (plugin);
|
|
|
|
/***/ })
|
|
/******/ ]);
|
|
/*!
|
|
* Name : Video Background Extension for Jarallax
|
|
* Version : 1.0.1
|
|
* Author : nK <https://nkdev.info>
|
|
* GitHub : https://github.com/nk-o/jarallax
|
|
*/
|
|
/******/ (function(modules) { // webpackBootstrap
|
|
/******/ // The module cache
|
|
/******/ var installedModules = {};
|
|
/******/
|
|
/******/ // The require function
|
|
/******/ function __webpack_require__(moduleId) {
|
|
/******/
|
|
/******/ // Check if module is in cache
|
|
/******/ if(installedModules[moduleId]) {
|
|
/******/ return installedModules[moduleId].exports;
|
|
/******/ }
|
|
/******/ // Create a new module (and put it into the cache)
|
|
/******/ var module = installedModules[moduleId] = {
|
|
/******/ i: moduleId,
|
|
/******/ l: false,
|
|
/******/ exports: {}
|
|
/******/ };
|
|
/******/
|
|
/******/ // Execute the module function
|
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
/******/
|
|
/******/ // Flag the module as loaded
|
|
/******/ module.l = true;
|
|
/******/
|
|
/******/ // Return the exports of the module
|
|
/******/ return module.exports;
|
|
/******/ }
|
|
/******/
|
|
/******/
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
/******/ __webpack_require__.m = modules;
|
|
/******/
|
|
/******/ // expose the module cache
|
|
/******/ __webpack_require__.c = installedModules;
|
|
/******/
|
|
/******/ // define getter function for harmony exports
|
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
/******/ }
|
|
/******/ };
|
|
/******/
|
|
/******/ // define __esModule on exports
|
|
/******/ __webpack_require__.r = function(exports) {
|
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
/******/ }
|
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
/******/ };
|
|
/******/
|
|
/******/ // create a fake namespace object
|
|
/******/ // mode & 1: value is a module id, require it
|
|
/******/ // mode & 2: merge all properties of value into the ns
|
|
/******/ // mode & 4: return value when already ns object
|
|
/******/ // mode & 8|1: behave like require
|
|
/******/ __webpack_require__.t = function(value, mode) {
|
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
|
/******/ if(mode & 8) return value;
|
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
/******/ var ns = Object.create(null);
|
|
/******/ __webpack_require__.r(ns);
|
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
/******/ return ns;
|
|
/******/ };
|
|
/******/
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
/******/ __webpack_require__.n = function(module) {
|
|
/******/ var getter = module && module.__esModule ?
|
|
/******/ function getDefault() { return module['default']; } :
|
|
/******/ function getModuleExports() { return module; };
|
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
/******/ return getter;
|
|
/******/ };
|
|
/******/
|
|
/******/ // Object.prototype.hasOwnProperty.call
|
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
/******/
|
|
/******/ // __webpack_public_path__
|
|
/******/ __webpack_require__.p = "";
|
|
/******/
|
|
/******/
|
|
/******/ // Load entry module and return exports
|
|
/******/ return __webpack_require__(__webpack_require__.s = 6);
|
|
/******/ })
|
|
/************************************************************************/
|
|
/******/ ([
|
|
/* 0 */,
|
|
/* 1 */,
|
|
/* 2 */
|
|
/***/ (function(module, exports) {
|
|
|
|
module.exports = function (callback) {
|
|
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
// Already ready or interactive, execute callback
|
|
callback.call();
|
|
} else if (document.attachEvent) {
|
|
// Old browsers
|
|
document.attachEvent('onreadystatechange', function () {
|
|
if (document.readyState === 'interactive') callback.call();
|
|
});
|
|
} else if (document.addEventListener) {
|
|
// Modern browsers
|
|
document.addEventListener('DOMContentLoaded', callback);
|
|
}
|
|
};
|
|
|
|
/***/ }),
|
|
/* 3 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
/* WEBPACK VAR INJECTION */(function(global) {var win;
|
|
|
|
if (typeof window !== "undefined") {
|
|
win = window;
|
|
} else if (typeof global !== "undefined") {
|
|
win = global;
|
|
} else if (typeof self !== "undefined") {
|
|
win = self;
|
|
} else {
|
|
win = {};
|
|
}
|
|
|
|
module.exports = win;
|
|
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(4)))
|
|
|
|
/***/ }),
|
|
/* 4 */
|
|
/***/ (function(module, exports) {
|
|
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
var g; // This works in non-strict mode
|
|
|
|
g = function () {
|
|
return this;
|
|
}();
|
|
|
|
try {
|
|
// This works if eval is allowed (see CSP)
|
|
g = g || new Function("return this")();
|
|
} catch (e) {
|
|
// This works if the window reference is available
|
|
if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") g = window;
|
|
} // g can still be undefined, but nothing to do about it...
|
|
// We return undefined, instead of nothing here, so it's
|
|
// easier to handle this case. if(!global) { ...}
|
|
|
|
|
|
module.exports = g;
|
|
|
|
/***/ }),
|
|
/* 5 */,
|
|
/* 6 */
|
|
/***/ (function(module, exports, __webpack_require__) {
|
|
|
|
module.exports = __webpack_require__(7);
|
|
|
|
|
|
/***/ }),
|
|
/* 7 */
|
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony import */ var video_worker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global__WEBPACK_IMPORTED_MODULE_1__);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
|
|
/* harmony import */ var lite_ready__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lite_ready__WEBPACK_IMPORTED_MODULE_2__);
|
|
/* harmony import */ var _jarallax_video_esm__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
|
|
|
|
|
|
|
|
// add video worker globally to fallback jarallax < 1.10 versions
|
|
|
|
global__WEBPACK_IMPORTED_MODULE_1___default.a.VideoWorker = global__WEBPACK_IMPORTED_MODULE_1___default.a.VideoWorker || video_worker__WEBPACK_IMPORTED_MODULE_0__["default"];
|
|
Object(_jarallax_video_esm__WEBPACK_IMPORTED_MODULE_3__["default"])(); // data-jarallax-video initialization
|
|
|
|
lite_ready__WEBPACK_IMPORTED_MODULE_2___default()(function () {
|
|
if ('undefined' !== typeof global__WEBPACK_IMPORTED_MODULE_1___default.a.jarallax) {
|
|
global__WEBPACK_IMPORTED_MODULE_1___default.a.jarallax(document.querySelectorAll('[data-jarallax-video]'));
|
|
}
|
|
});
|
|
|
|
/***/ }),
|
|
/* 8 */
|
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return VideoWorker; });
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(global__WEBPACK_IMPORTED_MODULE_0__);
|
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
|
|
// Deferred
|
|
// thanks http://stackoverflow.com/questions/18096715/implement-deferred-object-without-using-jquery
|
|
|
|
function Deferred() {
|
|
this.doneCallbacks = [];
|
|
this.failCallbacks = [];
|
|
}
|
|
|
|
Deferred.prototype = {
|
|
execute: function execute(list, args) {
|
|
var i = list.length;
|
|
args = Array.prototype.slice.call(args);
|
|
|
|
while (i) {
|
|
i -= 1;
|
|
list[i].apply(null, args);
|
|
}
|
|
},
|
|
resolve: function resolve() {
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
this.execute(this.doneCallbacks, args);
|
|
},
|
|
reject: function reject() {
|
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
args[_key2] = arguments[_key2];
|
|
}
|
|
|
|
this.execute(this.failCallbacks, args);
|
|
},
|
|
done: function done(callback) {
|
|
this.doneCallbacks.push(callback);
|
|
},
|
|
fail: function fail(callback) {
|
|
this.failCallbacks.push(callback);
|
|
}
|
|
};
|
|
var ID = 0;
|
|
var YoutubeAPIadded = 0;
|
|
var VimeoAPIadded = 0;
|
|
var loadingYoutubePlayer = 0;
|
|
var loadingVimeoPlayer = 0;
|
|
var loadingYoutubeDefer = new Deferred();
|
|
var loadingVimeoDefer = new Deferred();
|
|
|
|
var VideoWorker = /*#__PURE__*/function () {
|
|
function VideoWorker(url, options) {
|
|
_classCallCheck(this, VideoWorker);
|
|
|
|
var self = this;
|
|
self.url = url;
|
|
self.options_default = {
|
|
autoplay: false,
|
|
loop: false,
|
|
mute: false,
|
|
volume: 100,
|
|
showContols: true,
|
|
// start / end video time in seconds
|
|
startTime: 0,
|
|
endTime: 0
|
|
};
|
|
self.options = self.extend({}, self.options_default, options); // check URL
|
|
|
|
self.videoID = self.parseURL(url); // init
|
|
|
|
if (self.videoID) {
|
|
self.ID = ID;
|
|
ID += 1;
|
|
self.loadAPI();
|
|
self.init();
|
|
}
|
|
} // Extend like jQuery.extend
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
|
|
_createClass(VideoWorker, [{
|
|
key: "extend",
|
|
value: function extend() {
|
|
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
args[_key3] = arguments[_key3];
|
|
}
|
|
|
|
var out = args[0] || {};
|
|
Object.keys(args).forEach(function (i) {
|
|
if (!args[i]) {
|
|
return;
|
|
}
|
|
|
|
Object.keys(args[i]).forEach(function (key) {
|
|
out[key] = args[i][key];
|
|
});
|
|
});
|
|
return out;
|
|
}
|
|
}, {
|
|
key: "parseURL",
|
|
value: function parseURL(url) {
|
|
// parse youtube ID
|
|
function getYoutubeID(ytUrl) {
|
|
// eslint-disable-next-line no-useless-escape
|
|
var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
|
|
var match = ytUrl.match(regExp);
|
|
return match && 11 === match[1].length ? match[1] : false;
|
|
} // parse vimeo ID
|
|
|
|
|
|
function getVimeoID(vmUrl) {
|
|
// eslint-disable-next-line no-useless-escape
|
|
var regExp = /https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/;
|
|
var match = vmUrl.match(regExp);
|
|
return match && match[3] ? match[3] : false;
|
|
} // parse local string
|
|
|
|
|
|
function getLocalVideos(locUrl) {
|
|
// eslint-disable-next-line no-useless-escape
|
|
var videoFormats = locUrl.split(/,(?=mp4\:|webm\:|ogv\:|ogg\:)/);
|
|
var result = {};
|
|
var ready = 0;
|
|
videoFormats.forEach(function (val) {
|
|
// eslint-disable-next-line no-useless-escape
|
|
var match = val.match(/^(mp4|webm|ogv|ogg)\:(.*)/);
|
|
|
|
if (match && match[1] && match[2]) {
|
|
// eslint-disable-next-line prefer-destructuring
|
|
result['ogv' === match[1] ? 'ogg' : match[1]] = match[2];
|
|
ready = 1;
|
|
}
|
|
});
|
|
return ready ? result : false;
|
|
}
|
|
|
|
var Youtube = getYoutubeID(url);
|
|
var Vimeo = getVimeoID(url);
|
|
var Local = getLocalVideos(url);
|
|
|
|
if (Youtube) {
|
|
this.type = 'youtube';
|
|
return Youtube;
|
|
}
|
|
|
|
if (Vimeo) {
|
|
this.type = 'vimeo';
|
|
return Vimeo;
|
|
}
|
|
|
|
if (Local) {
|
|
this.type = 'local';
|
|
return Local;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}, {
|
|
key: "isValid",
|
|
value: function isValid() {
|
|
return !!this.videoID;
|
|
} // events
|
|
|
|
}, {
|
|
key: "on",
|
|
value: function on(name, callback) {
|
|
this.userEventsList = this.userEventsList || []; // add new callback in events list
|
|
|
|
(this.userEventsList[name] || (this.userEventsList[name] = [])).push(callback);
|
|
}
|
|
}, {
|
|
key: "off",
|
|
value: function off(name, callback) {
|
|
var _this = this;
|
|
|
|
if (!this.userEventsList || !this.userEventsList[name]) {
|
|
return;
|
|
}
|
|
|
|
if (!callback) {
|
|
delete this.userEventsList[name];
|
|
} else {
|
|
this.userEventsList[name].forEach(function (val, key) {
|
|
if (val === callback) {
|
|
_this.userEventsList[name][key] = false;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: "fire",
|
|
value: function fire(name) {
|
|
var _this2 = this;
|
|
|
|
for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
|
|
args[_key4 - 1] = arguments[_key4];
|
|
}
|
|
|
|
if (this.userEventsList && 'undefined' !== typeof this.userEventsList[name]) {
|
|
this.userEventsList[name].forEach(function (val) {
|
|
// call with all arguments
|
|
if (val) {
|
|
val.apply(_this2, args);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: "play",
|
|
value: function play(start) {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.playVideo) {
|
|
if ('undefined' !== typeof start) {
|
|
self.player.seekTo(start || 0);
|
|
}
|
|
|
|
if (global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PLAYING !== self.player.getPlayerState()) {
|
|
self.player.playVideo();
|
|
}
|
|
}
|
|
|
|
if ('vimeo' === self.type) {
|
|
if ('undefined' !== typeof start) {
|
|
self.player.setCurrentTime(start);
|
|
}
|
|
|
|
self.player.getPaused().then(function (paused) {
|
|
if (paused) {
|
|
self.player.play();
|
|
}
|
|
});
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
if ('undefined' !== typeof start) {
|
|
self.player.currentTime = start;
|
|
}
|
|
|
|
if (self.player.paused) {
|
|
self.player.play();
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: "pause",
|
|
value: function pause() {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.pauseVideo) {
|
|
if (global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PLAYING === self.player.getPlayerState()) {
|
|
self.player.pauseVideo();
|
|
}
|
|
}
|
|
|
|
if ('vimeo' === self.type) {
|
|
self.player.getPaused().then(function (paused) {
|
|
if (!paused) {
|
|
self.player.pause();
|
|
}
|
|
});
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
if (!self.player.paused) {
|
|
self.player.pause();
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: "mute",
|
|
value: function mute() {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.mute) {
|
|
self.player.mute();
|
|
}
|
|
|
|
if ('vimeo' === self.type && self.player.setVolume) {
|
|
self.player.setVolume(0);
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
self.$video.muted = true;
|
|
}
|
|
}
|
|
}, {
|
|
key: "unmute",
|
|
value: function unmute() {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.mute) {
|
|
self.player.unMute();
|
|
}
|
|
|
|
if ('vimeo' === self.type && self.player.setVolume) {
|
|
self.player.setVolume(self.options.volume);
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
self.$video.muted = false;
|
|
}
|
|
}
|
|
}, {
|
|
key: "setVolume",
|
|
value: function setVolume() {
|
|
var volume = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
var self = this;
|
|
|
|
if (!self.player || !volume) {
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.setVolume) {
|
|
self.player.setVolume(volume);
|
|
}
|
|
|
|
if ('vimeo' === self.type && self.player.setVolume) {
|
|
self.player.setVolume(volume);
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
self.$video.volume = volume / 100;
|
|
}
|
|
}
|
|
}, {
|
|
key: "getVolume",
|
|
value: function getVolume(callback) {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
callback(false);
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.getVolume) {
|
|
callback(self.player.getVolume());
|
|
}
|
|
|
|
if ('vimeo' === self.type && self.player.getVolume) {
|
|
self.player.getVolume().then(function (volume) {
|
|
callback(volume);
|
|
});
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
callback(self.$video.volume * 100);
|
|
}
|
|
}
|
|
}, {
|
|
key: "getMuted",
|
|
value: function getMuted(callback) {
|
|
var self = this;
|
|
|
|
if (!self.player) {
|
|
callback(null);
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type && self.player.isMuted) {
|
|
callback(self.player.isMuted());
|
|
}
|
|
|
|
if ('vimeo' === self.type && self.player.getVolume) {
|
|
self.player.getVolume().then(function (volume) {
|
|
callback(!!volume);
|
|
});
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
callback(self.$video.muted);
|
|
}
|
|
}
|
|
}, {
|
|
key: "getImageURL",
|
|
value: function getImageURL(callback) {
|
|
var self = this;
|
|
|
|
if (self.videoImage) {
|
|
callback(self.videoImage);
|
|
return;
|
|
}
|
|
|
|
if ('youtube' === self.type) {
|
|
var availableSizes = ['maxresdefault', 'sddefault', 'hqdefault', '0'];
|
|
var step = 0;
|
|
var tempImg = new Image();
|
|
|
|
tempImg.onload = function () {
|
|
// if no thumbnail, youtube add their own image with width = 120px
|
|
if (120 !== (this.naturalWidth || this.width) || step === availableSizes.length - 1) {
|
|
// ok
|
|
self.videoImage = "https://img.youtube.com/vi/".concat(self.videoID, "/").concat(availableSizes[step], ".jpg");
|
|
callback(self.videoImage);
|
|
} else {
|
|
// try another size
|
|
step += 1;
|
|
this.src = "https://img.youtube.com/vi/".concat(self.videoID, "/").concat(availableSizes[step], ".jpg");
|
|
}
|
|
};
|
|
|
|
tempImg.src = "https://img.youtube.com/vi/".concat(self.videoID, "/").concat(availableSizes[step], ".jpg");
|
|
}
|
|
|
|
if ('vimeo' === self.type) {
|
|
var request = new XMLHttpRequest();
|
|
request.open('GET', "https://vimeo.com/api/v2/video/".concat(self.videoID, ".json"), true);
|
|
|
|
request.onreadystatechange = function () {
|
|
if (4 === this.readyState) {
|
|
if (200 <= this.status && 400 > this.status) {
|
|
// Success!
|
|
var response = JSON.parse(this.responseText);
|
|
self.videoImage = response[0].thumbnail_large;
|
|
callback(self.videoImage);
|
|
} else {// Error :(
|
|
}
|
|
}
|
|
};
|
|
|
|
request.send();
|
|
request = null;
|
|
}
|
|
} // fallback to the old version.
|
|
|
|
}, {
|
|
key: "getIframe",
|
|
value: function getIframe(callback) {
|
|
this.getVideo(callback);
|
|
}
|
|
}, {
|
|
key: "getVideo",
|
|
value: function getVideo(callback) {
|
|
var self = this; // return generated video block
|
|
|
|
if (self.$video) {
|
|
callback(self.$video);
|
|
return;
|
|
} // generate new video block
|
|
|
|
|
|
self.onAPIready(function () {
|
|
var hiddenDiv;
|
|
|
|
if (!self.$video) {
|
|
hiddenDiv = document.createElement('div');
|
|
hiddenDiv.style.display = 'none';
|
|
} // Youtube
|
|
|
|
|
|
if ('youtube' === self.type) {
|
|
self.playerOptions = {};
|
|
self.playerOptions.videoId = self.videoID;
|
|
self.playerOptions.playerVars = {
|
|
autohide: 1,
|
|
rel: 0,
|
|
autoplay: 0,
|
|
// autoplay enable on mobile devices
|
|
playsinline: 1
|
|
}; // hide controls
|
|
|
|
if (!self.options.showContols) {
|
|
self.playerOptions.playerVars.iv_load_policy = 3;
|
|
self.playerOptions.playerVars.modestbranding = 1;
|
|
self.playerOptions.playerVars.controls = 0;
|
|
self.playerOptions.playerVars.showinfo = 0;
|
|
self.playerOptions.playerVars.disablekb = 1;
|
|
} // events
|
|
|
|
|
|
var ytStarted;
|
|
var ytProgressInterval;
|
|
self.playerOptions.events = {
|
|
onReady: function onReady(e) {
|
|
// mute
|
|
if (self.options.mute) {
|
|
e.target.mute();
|
|
} else if (self.options.volume) {
|
|
e.target.setVolume(self.options.volume);
|
|
} // autoplay
|
|
|
|
|
|
if (self.options.autoplay) {
|
|
self.play(self.options.startTime);
|
|
}
|
|
|
|
self.fire('ready', e); // For seamless loops, set the endTime to 0.1 seconds less than the video's duration
|
|
// https://github.com/nk-o/video-worker/issues/2
|
|
|
|
if (self.options.loop && !self.options.endTime) {
|
|
var secondsOffset = 0.1;
|
|
self.options.endTime = self.player.getDuration() - secondsOffset;
|
|
} // volumechange
|
|
|
|
|
|
setInterval(function () {
|
|
self.getVolume(function (volume) {
|
|
if (self.options.volume !== volume) {
|
|
self.options.volume = volume;
|
|
self.fire('volumechange', e);
|
|
}
|
|
});
|
|
}, 150);
|
|
},
|
|
onStateChange: function onStateChange(e) {
|
|
// loop
|
|
if (self.options.loop && e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.ENDED) {
|
|
self.play(self.options.startTime);
|
|
}
|
|
|
|
if (!ytStarted && e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PLAYING) {
|
|
ytStarted = 1;
|
|
self.fire('started', e);
|
|
}
|
|
|
|
if (e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PLAYING) {
|
|
self.fire('play', e);
|
|
}
|
|
|
|
if (e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PAUSED) {
|
|
self.fire('pause', e);
|
|
}
|
|
|
|
if (e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.ENDED) {
|
|
self.fire('ended', e);
|
|
} // progress check
|
|
|
|
|
|
if (e.data === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.PlayerState.PLAYING) {
|
|
ytProgressInterval = setInterval(function () {
|
|
self.fire('timeupdate', e); // check for end of video and play again or stop
|
|
|
|
if (self.options.endTime && self.player.getCurrentTime() >= self.options.endTime) {
|
|
if (self.options.loop) {
|
|
self.play(self.options.startTime);
|
|
} else {
|
|
self.pause();
|
|
}
|
|
}
|
|
}, 150);
|
|
} else {
|
|
clearInterval(ytProgressInterval);
|
|
}
|
|
},
|
|
onError: function onError(e) {
|
|
self.fire('error', e);
|
|
}
|
|
};
|
|
var firstInit = !self.$video;
|
|
|
|
if (firstInit) {
|
|
var div = document.createElement('div');
|
|
div.setAttribute('id', self.playerID);
|
|
hiddenDiv.appendChild(div);
|
|
document.body.appendChild(hiddenDiv);
|
|
}
|
|
|
|
self.player = self.player || new global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.Player(self.playerID, self.playerOptions);
|
|
|
|
if (firstInit) {
|
|
self.$video = document.getElementById(self.playerID); // get video width and height
|
|
|
|
self.videoWidth = parseInt(self.$video.getAttribute('width'), 10) || 1280;
|
|
self.videoHeight = parseInt(self.$video.getAttribute('height'), 10) || 720;
|
|
}
|
|
} // Vimeo
|
|
|
|
|
|
if ('vimeo' === self.type) {
|
|
self.playerOptions = {
|
|
id: self.videoID,
|
|
autopause: 0,
|
|
transparent: 0,
|
|
autoplay: self.options.autoplay ? 1 : 0,
|
|
loop: self.options.loop ? 1 : 0,
|
|
muted: self.options.mute ? 1 : 0
|
|
};
|
|
|
|
if (self.options.volume) {
|
|
self.playerOptions.volume = self.options.volume;
|
|
} // hide controls
|
|
|
|
|
|
if (!self.options.showContols) {
|
|
self.playerOptions.badge = 0;
|
|
self.playerOptions.byline = 0;
|
|
self.playerOptions.portrait = 0;
|
|
self.playerOptions.title = 0;
|
|
self.playerOptions.background = 1;
|
|
}
|
|
|
|
if (!self.$video) {
|
|
var playerOptionsString = '';
|
|
Object.keys(self.playerOptions).forEach(function (key) {
|
|
if ('' !== playerOptionsString) {
|
|
playerOptionsString += '&';
|
|
}
|
|
|
|
playerOptionsString += "".concat(key, "=").concat(encodeURIComponent(self.playerOptions[key]));
|
|
}); // we need to create iframe manually because when we create it using API
|
|
// js events won't triggers after iframe moved to another place
|
|
|
|
self.$video = document.createElement('iframe');
|
|
self.$video.setAttribute('id', self.playerID);
|
|
self.$video.setAttribute('src', "https://player.vimeo.com/video/".concat(self.videoID, "?").concat(playerOptionsString));
|
|
self.$video.setAttribute('frameborder', '0');
|
|
self.$video.setAttribute('mozallowfullscreen', '');
|
|
self.$video.setAttribute('allowfullscreen', '');
|
|
hiddenDiv.appendChild(self.$video);
|
|
document.body.appendChild(hiddenDiv);
|
|
}
|
|
|
|
self.player = self.player || new global__WEBPACK_IMPORTED_MODULE_0___default.a.Vimeo.Player(self.$video, self.playerOptions); // set current time for autoplay
|
|
|
|
if (self.options.startTime && self.options.autoplay) {
|
|
self.player.setCurrentTime(self.options.startTime);
|
|
} // get video width and height
|
|
|
|
|
|
self.player.getVideoWidth().then(function (width) {
|
|
self.videoWidth = width || 1280;
|
|
});
|
|
self.player.getVideoHeight().then(function (height) {
|
|
self.videoHeight = height || 720;
|
|
}); // events
|
|
|
|
var vmStarted;
|
|
self.player.on('timeupdate', function (e) {
|
|
if (!vmStarted) {
|
|
self.fire('started', e);
|
|
vmStarted = 1;
|
|
}
|
|
|
|
self.fire('timeupdate', e); // check for end of video and play again or stop
|
|
|
|
if (self.options.endTime) {
|
|
if (self.options.endTime && e.seconds >= self.options.endTime) {
|
|
if (self.options.loop) {
|
|
self.play(self.options.startTime);
|
|
} else {
|
|
self.pause();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
self.player.on('play', function (e) {
|
|
self.fire('play', e); // check for the start time and start with it
|
|
|
|
if (self.options.startTime && 0 === e.seconds) {
|
|
self.play(self.options.startTime);
|
|
}
|
|
});
|
|
self.player.on('pause', function (e) {
|
|
self.fire('pause', e);
|
|
});
|
|
self.player.on('ended', function (e) {
|
|
self.fire('ended', e);
|
|
});
|
|
self.player.on('loaded', function (e) {
|
|
self.fire('ready', e);
|
|
});
|
|
self.player.on('volumechange', function (e) {
|
|
self.fire('volumechange', e);
|
|
});
|
|
self.player.on('error', function (e) {
|
|
self.fire('error', e);
|
|
});
|
|
} // Local
|
|
|
|
|
|
function addSourceToLocal(element, src, type) {
|
|
var source = document.createElement('source');
|
|
source.src = src;
|
|
source.type = type;
|
|
element.appendChild(source);
|
|
}
|
|
|
|
if ('local' === self.type) {
|
|
if (!self.$video) {
|
|
self.$video = document.createElement('video'); // show controls
|
|
|
|
if (self.options.showContols) {
|
|
self.$video.controls = true;
|
|
} // mute
|
|
|
|
|
|
if (self.options.mute) {
|
|
self.$video.muted = true;
|
|
} else if (self.$video.volume) {
|
|
self.$video.volume = self.options.volume / 100;
|
|
} // loop
|
|
|
|
|
|
if (self.options.loop) {
|
|
self.$video.loop = true;
|
|
} // autoplay enable on mobile devices
|
|
|
|
|
|
self.$video.setAttribute('playsinline', '');
|
|
self.$video.setAttribute('webkit-playsinline', '');
|
|
self.$video.setAttribute('id', self.playerID);
|
|
hiddenDiv.appendChild(self.$video);
|
|
document.body.appendChild(hiddenDiv);
|
|
Object.keys(self.videoID).forEach(function (key) {
|
|
addSourceToLocal(self.$video, self.videoID[key], "video/".concat(key));
|
|
});
|
|
}
|
|
|
|
self.player = self.player || self.$video;
|
|
var locStarted;
|
|
self.player.addEventListener('playing', function (e) {
|
|
if (!locStarted) {
|
|
self.fire('started', e);
|
|
}
|
|
|
|
locStarted = 1;
|
|
});
|
|
self.player.addEventListener('timeupdate', function (e) {
|
|
self.fire('timeupdate', e); // check for end of video and play again or stop
|
|
|
|
if (self.options.endTime) {
|
|
if (self.options.endTime && this.currentTime >= self.options.endTime) {
|
|
if (self.options.loop) {
|
|
self.play(self.options.startTime);
|
|
} else {
|
|
self.pause();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
self.player.addEventListener('play', function (e) {
|
|
self.fire('play', e);
|
|
});
|
|
self.player.addEventListener('pause', function (e) {
|
|
self.fire('pause', e);
|
|
});
|
|
self.player.addEventListener('ended', function (e) {
|
|
self.fire('ended', e);
|
|
});
|
|
self.player.addEventListener('loadedmetadata', function () {
|
|
// get video width and height
|
|
self.videoWidth = this.videoWidth || 1280;
|
|
self.videoHeight = this.videoHeight || 720;
|
|
self.fire('ready'); // autoplay
|
|
|
|
if (self.options.autoplay) {
|
|
self.play(self.options.startTime);
|
|
}
|
|
});
|
|
self.player.addEventListener('volumechange', function (e) {
|
|
self.getVolume(function (volume) {
|
|
self.options.volume = volume;
|
|
});
|
|
self.fire('volumechange', e);
|
|
});
|
|
self.player.addEventListener('error', function (e) {
|
|
self.fire('error', e);
|
|
});
|
|
}
|
|
|
|
callback(self.$video);
|
|
});
|
|
}
|
|
}, {
|
|
key: "init",
|
|
value: function init() {
|
|
var self = this;
|
|
self.playerID = "VideoWorker-".concat(self.ID);
|
|
}
|
|
}, {
|
|
key: "loadAPI",
|
|
value: function loadAPI() {
|
|
var self = this;
|
|
|
|
if (YoutubeAPIadded && VimeoAPIadded) {
|
|
return;
|
|
}
|
|
|
|
var src = ''; // load Youtube API
|
|
|
|
if ('youtube' === self.type && !YoutubeAPIadded) {
|
|
YoutubeAPIadded = 1;
|
|
src = 'https://www.youtube.com/iframe_api';
|
|
} // load Vimeo API
|
|
|
|
|
|
if ('vimeo' === self.type && !VimeoAPIadded) {
|
|
VimeoAPIadded = 1; // Useful when Vimeo API added using RequireJS https://github.com/nk-o/video-worker/pull/7
|
|
|
|
if ('undefined' !== typeof global__WEBPACK_IMPORTED_MODULE_0___default.a.Vimeo) {
|
|
return;
|
|
}
|
|
|
|
src = 'https://player.vimeo.com/api/player.js';
|
|
}
|
|
|
|
if (!src) {
|
|
return;
|
|
} // add script in head section
|
|
|
|
|
|
var tag = document.createElement('script');
|
|
var head = document.getElementsByTagName('head')[0];
|
|
tag.src = src;
|
|
head.appendChild(tag);
|
|
head = null;
|
|
tag = null;
|
|
}
|
|
}, {
|
|
key: "onAPIready",
|
|
value: function onAPIready(callback) {
|
|
var self = this; // Youtube
|
|
|
|
if ('youtube' === self.type) {
|
|
// Listen for global YT player callback
|
|
if (('undefined' === typeof global__WEBPACK_IMPORTED_MODULE_0___default.a.YT || 0 === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.loaded) && !loadingYoutubePlayer) {
|
|
// Prevents Ready event from being called twice
|
|
loadingYoutubePlayer = 1; // Creates deferred so, other players know when to wait.
|
|
|
|
window.onYouTubeIframeAPIReady = function () {
|
|
window.onYouTubeIframeAPIReady = null;
|
|
loadingYoutubeDefer.resolve('done');
|
|
callback();
|
|
};
|
|
} else if ('object' === _typeof(global__WEBPACK_IMPORTED_MODULE_0___default.a.YT) && 1 === global__WEBPACK_IMPORTED_MODULE_0___default.a.YT.loaded) {
|
|
callback();
|
|
} else {
|
|
loadingYoutubeDefer.done(function () {
|
|
callback();
|
|
});
|
|
}
|
|
} // Vimeo
|
|
|
|
|
|
if ('vimeo' === self.type) {
|
|
if ('undefined' === typeof global__WEBPACK_IMPORTED_MODULE_0___default.a.Vimeo && !loadingVimeoPlayer) {
|
|
loadingVimeoPlayer = 1;
|
|
var vimeoInterval = setInterval(function () {
|
|
if ('undefined' !== typeof global__WEBPACK_IMPORTED_MODULE_0___default.a.Vimeo) {
|
|
clearInterval(vimeoInterval);
|
|
loadingVimeoDefer.resolve('done');
|
|
callback();
|
|
}
|
|
}, 20);
|
|
} else if ('undefined' !== typeof global__WEBPACK_IMPORTED_MODULE_0___default.a.Vimeo) {
|
|
callback();
|
|
} else {
|
|
loadingVimeoDefer.done(function () {
|
|
callback();
|
|
});
|
|
}
|
|
} // Local
|
|
|
|
|
|
if ('local' === self.type) {
|
|
callback();
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return VideoWorker;
|
|
}();
|
|
|
|
|
|
|
|
/***/ }),
|
|
/* 9 */
|
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
|
|
"use strict";
|
|
__webpack_require__.r(__webpack_exports__);
|
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return jarallaxVideo; });
|
|
/* harmony import */ var video_worker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
|
|
/* harmony import */ var global__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global__WEBPACK_IMPORTED_MODULE_1__);
|
|
|
|
|
|
function jarallaxVideo() {
|
|
var jarallax = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : global__WEBPACK_IMPORTED_MODULE_1___default.a.jarallax;
|
|
|
|
if ('undefined' === typeof jarallax) {
|
|
return;
|
|
}
|
|
|
|
var Jarallax = jarallax.constructor; // append video after when block will be visible.
|
|
|
|
var defOnScroll = Jarallax.prototype.onScroll;
|
|
|
|
Jarallax.prototype.onScroll = function () {
|
|
var self = this;
|
|
defOnScroll.apply(self);
|
|
var isReady = !self.isVideoInserted && self.video && (!self.options.videoLazyLoading || self.isElementInViewport) && !self.options.disableVideo();
|
|
|
|
if (isReady) {
|
|
self.isVideoInserted = true;
|
|
self.video.getVideo(function (video) {
|
|
var $parent = video.parentNode;
|
|
self.css(video, {
|
|
position: self.image.position,
|
|
top: '0px',
|
|
left: '0px',
|
|
right: '0px',
|
|
bottom: '0px',
|
|
width: '100%',
|
|
height: '100%',
|
|
maxWidth: 'none',
|
|
maxHeight: 'none',
|
|
margin: 0,
|
|
zIndex: -1
|
|
});
|
|
self.$video = video; // add Poster attribute to self-hosted video
|
|
|
|
if ('local' === self.video.type) {
|
|
if (self.image.src) {
|
|
self.$video.setAttribute('poster', self.image.src);
|
|
} else if (self.image.$item && 'IMG' === self.image.$item.tagName && self.image.$item.src) {
|
|
self.$video.setAttribute('poster', self.image.$item.src);
|
|
}
|
|
} // insert video tag
|
|
|
|
|
|
self.image.$container.appendChild(video); // remove parent video element (created by VideoWorker)
|
|
|
|
$parent.parentNode.removeChild($parent);
|
|
});
|
|
}
|
|
}; // cover video
|
|
|
|
|
|
var defCoverImage = Jarallax.prototype.coverImage;
|
|
|
|
Jarallax.prototype.coverImage = function () {
|
|
var self = this;
|
|
var imageData = defCoverImage.apply(self);
|
|
var node = self.image.$item ? self.image.$item.nodeName : false;
|
|
|
|
if (imageData && self.video && node && ('IFRAME' === node || 'VIDEO' === node)) {
|
|
var h = imageData.image.height;
|
|
var w = h * self.image.width / self.image.height;
|
|
var ml = (imageData.container.width - w) / 2;
|
|
var mt = imageData.image.marginTop;
|
|
|
|
if (imageData.container.width > w) {
|
|
w = imageData.container.width;
|
|
h = w * self.image.height / self.image.width;
|
|
ml = 0;
|
|
mt += (imageData.image.height - h) / 2;
|
|
} // add video height over than need to hide controls
|
|
|
|
|
|
if ('IFRAME' === node) {
|
|
h += 400;
|
|
mt -= 200;
|
|
}
|
|
|
|
self.css(self.$video, {
|
|
width: "".concat(w, "px"),
|
|
marginLeft: "".concat(ml, "px"),
|
|
height: "".concat(h, "px"),
|
|
marginTop: "".concat(mt, "px")
|
|
});
|
|
}
|
|
|
|
return imageData;
|
|
}; // init video
|
|
|
|
|
|
var defInitImg = Jarallax.prototype.initImg;
|
|
|
|
Jarallax.prototype.initImg = function () {
|
|
var self = this;
|
|
var defaultResult = defInitImg.apply(self);
|
|
|
|
if (!self.options.videoSrc) {
|
|
self.options.videoSrc = self.$item.getAttribute('data-jarallax-video') || null;
|
|
}
|
|
|
|
if (self.options.videoSrc) {
|
|
self.defaultInitImgResult = defaultResult;
|
|
return true;
|
|
}
|
|
|
|
return defaultResult;
|
|
};
|
|
|
|
var defCanInitParallax = Jarallax.prototype.canInitParallax;
|
|
|
|
Jarallax.prototype.canInitParallax = function () {
|
|
var self = this;
|
|
var defaultResult = defCanInitParallax.apply(self);
|
|
|
|
if (!self.options.videoSrc) {
|
|
return defaultResult;
|
|
} // Init video api
|
|
|
|
|
|
var video = new video_worker__WEBPACK_IMPORTED_MODULE_0__["default"](self.options.videoSrc, {
|
|
autoplay: true,
|
|
loop: self.options.videoLoop,
|
|
showContols: false,
|
|
startTime: self.options.videoStartTime || 0,
|
|
endTime: self.options.videoEndTime || 0,
|
|
mute: self.options.videoVolume ? 0 : 1,
|
|
volume: self.options.videoVolume || 0
|
|
});
|
|
|
|
function resetDefaultImage() {
|
|
if (self.image.$default_item) {
|
|
self.image.$item = self.image.$default_item;
|
|
self.image.$item.style.display = 'block'; // set image width and height
|
|
|
|
self.coverImage();
|
|
self.clipContainer();
|
|
self.onScroll();
|
|
}
|
|
}
|
|
|
|
if (video.isValid()) {
|
|
// Force enable parallax.
|
|
// When the parallax disabled on mobile devices, we still need to display videos.
|
|
// https://github.com/nk-o/jarallax/issues/159
|
|
if (this.options.disableParallax()) {
|
|
defaultResult = true;
|
|
self.image.position = 'absolute';
|
|
self.options.type = 'scroll';
|
|
self.options.speed = 1;
|
|
} // if parallax will not be inited, we can add thumbnail on background.
|
|
|
|
|
|
if (!defaultResult) {
|
|
if (!self.defaultInitImgResult) {
|
|
video.getImageURL(function (url) {
|
|
// save default user styles
|
|
var curStyle = self.$item.getAttribute('style');
|
|
|
|
if (curStyle) {
|
|
self.$item.setAttribute('data-jarallax-original-styles', curStyle);
|
|
} // set new background
|
|
|
|
|
|
self.css(self.$item, {
|
|
'background-image': "url(\"".concat(url, "\")"),
|
|
'background-position': 'center',
|
|
'background-size': 'cover'
|
|
});
|
|
});
|
|
} // init video
|
|
|
|
} else {
|
|
video.on('ready', function () {
|
|
if (self.options.videoPlayOnlyVisible) {
|
|
var oldOnScroll = self.onScroll;
|
|
|
|
self.onScroll = function () {
|
|
oldOnScroll.apply(self);
|
|
|
|
if (!self.videoError && (self.options.videoLoop || !self.options.videoLoop && !self.videoEnded)) {
|
|
if (self.isVisible()) {
|
|
video.play();
|
|
} else {
|
|
video.pause();
|
|
}
|
|
}
|
|
};
|
|
} else {
|
|
video.play();
|
|
}
|
|
});
|
|
video.on('started', function () {
|
|
self.image.$default_item = self.image.$item;
|
|
self.image.$item = self.$video; // set video width and height
|
|
|
|
self.image.width = self.video.videoWidth || 1280;
|
|
self.image.height = self.video.videoHeight || 720;
|
|
self.coverImage();
|
|
self.clipContainer();
|
|
self.onScroll(); // hide image
|
|
|
|
if (self.image.$default_item) {
|
|
self.image.$default_item.style.display = 'none';
|
|
}
|
|
});
|
|
video.on('ended', function () {
|
|
self.videoEnded = true; // show default image if Loop disabled.
|
|
|
|
resetDefaultImage();
|
|
});
|
|
video.on('error', function () {
|
|
self.videoError = true; // show default image if video loading error.
|
|
|
|
resetDefaultImage();
|
|
});
|
|
self.video = video; // set image if not exists
|
|
|
|
if (!self.defaultInitImgResult) {
|
|
// set empty image on self-hosted video if not defined
|
|
self.image.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
|
|
if ('local' !== video.type) {
|
|
video.getImageURL(function (url) {
|
|
self.image.bgImage = "url(\"".concat(url, "\")");
|
|
self.init();
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return defaultResult;
|
|
}; // Destroy video parallax
|
|
|
|
|
|
var defDestroy = Jarallax.prototype.destroy;
|
|
|
|
Jarallax.prototype.destroy = function () {
|
|
var self = this;
|
|
|
|
if (self.image.$default_item) {
|
|
self.image.$item = self.image.$default_item;
|
|
delete self.image.$default_item;
|
|
}
|
|
|
|
defDestroy.apply(self);
|
|
};
|
|
}
|
|
|
|
/***/ })
|
|
/******/ ]);
|
|
/*!
|
|
* Bootstrap submenu fix
|
|
* Version: 1.2
|
|
* Author web-master72
|
|
*/
|
|
|
|
(function($){
|
|
|
|
$(window).on('load', function() {
|
|
|
|
var navBreakpoint = 991,
|
|
mobileTest;
|
|
|
|
/* ---------------------------------------------- /*
|
|
* Mobile detect
|
|
/* ---------------------------------------------- */
|
|
|
|
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
|
mobileTest = true;
|
|
} else {
|
|
mobileTest = false;
|
|
}
|
|
|
|
/* ---------------------------------------------- /*
|
|
* Nav hover/click dropdown
|
|
/* ---------------------------------------------- */
|
|
|
|
$(window).resize(function(){
|
|
|
|
var width = Math.max($(window).width(), window.innerWidth);
|
|
var menuItem = $('.menu-item-has-children').not('.mega-menu-col');
|
|
|
|
// Remove old margins from sub-menus
|
|
menuItem.children('.sub-menu, .mega-menu').css('margin-left', '');
|
|
|
|
if ( width > navBreakpoint ) {
|
|
menuItem.removeClass('sub-menu-open');
|
|
}
|
|
|
|
if ( (width > navBreakpoint) && (mobileTest !== true) ) {
|
|
|
|
menuItem.children('a').unbind('click');
|
|
menuItem.unbind('mouseenter mouseleave');
|
|
menuItem.on({
|
|
mouseenter: function () {
|
|
$(this).addClass('sub-menu-open');
|
|
},
|
|
mouseleave: function () {
|
|
$(this).removeClass('sub-menu-open');
|
|
}
|
|
});
|
|
} else {
|
|
menuItem.unbind('mouseenter mouseleave');
|
|
menuItem.children('a').unbind('click').click(function(e) {
|
|
e.preventDefault();
|
|
$(this).parent().toggleClass('sub-menu-open');
|
|
|
|
// If device has big screen
|
|
if ( (width > navBreakpoint) && (mobileTest == true) ) {
|
|
$(this).parent().siblings().removeClass('sub-menu-open');
|
|
$(this).parent().siblings().find('.sub-menu-open').removeClass('sub-menu-open');
|
|
}
|
|
});
|
|
}
|
|
|
|
// if ( (width > navBreakpoint) && (mobileTest !== true) ) {
|
|
|
|
if (width >= navBreakpoint) {
|
|
menuItem.children('.sub-menu, .mega-menu').each(function() {
|
|
var a = $(this).offset();
|
|
var b = $(this).width() + a.left;
|
|
var c = width - (b + 30);
|
|
|
|
if ( (b + 30) > width ) {
|
|
$(this).css('margin-left', c);
|
|
} else {
|
|
$(this).css('margin-left', '');
|
|
}
|
|
});
|
|
}
|
|
|
|
}).resize();
|
|
|
|
});
|
|
|
|
})(jQuery);
|
|
/* PrismJS 1.10.0
|
|
http://prismjs.com/download.html?themes=prism&languages=markup+clike+javascript+pug */
|
|
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function(e){var t=n.util.type(e);switch(t){case"Object":var r={};for(var a in e)e.hasOwnProperty(a)&&(r[a]=n.util.clone(e[a]));return r;case"Array":return e.map(function(e){return n.util.clone(e)})}return e}},languages:{extend:function(e,t){var r=n.util.clone(n.languages[e]);for(var a in t)r[a]=t[a];return r},insertBefore:function(e,t,r,a){a=a||n.languages;var l=a[e];if(2==arguments.length){r=arguments[1];for(var i in r)r.hasOwnProperty(i)&&(l[i]=r[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in r)r.hasOwnProperty(i)&&(o[i]=r[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===a[e]&&t!=e&&(this[t]=o)}),a[e]=o},DFS:function(e,t,r,a){a=a||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],r||l),"Object"!==n.util.type(e[l])||a[n.util.objId(e[l])]?"Array"!==n.util.type(e[l])||a[n.util.objId(e[l])]||(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,a)):(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,a)))}},plugins:{},highlightAll:function(e,t){n.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,r){var a={callback:r,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};n.hooks.run("before-highlightall",a);for(var l,i=a.elements||e.querySelectorAll(a.selector),o=0;l=i[o++];)n.highlightElement(l,t===!0,a.callback)},highlightElement:function(t,r,a){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1].toLowerCase(),i=n.languages[l]),t.className=t.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,t.parentNode&&(o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l));var s=t.textContent,g={element:t,language:l,grammar:i,code:s};if(n.hooks.run("before-sanity-check",g),!g.code||!g.grammar)return g.code&&(n.hooks.run("before-highlight",g),g.element.textContent=g.code,n.hooks.run("after-highlight",g)),n.hooks.run("complete",g),void 0;if(n.hooks.run("before-highlight",g),r&&_self.Worker){var u=new Worker(n.filename);u.onmessage=function(e){g.highlightedCode=e.data,n.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,a&&a.call(g.element),n.hooks.run("after-highlight",g),n.hooks.run("complete",g)},u.postMessage(JSON.stringify({language:g.language,code:g.code,immediateClose:!0}))}else g.highlightedCode=n.highlight(g.code,g.grammar,g.language),n.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,a&&a.call(t),n.hooks.run("after-highlight",g),n.hooks.run("complete",g)},highlight:function(e,t,a){var l=n.tokenize(e,t);return r.stringify(n.util.encode(l),a)},matchGrammar:function(e,t,r,a,l,i,o){var s=n.Token;for(var g in r)if(r.hasOwnProperty(g)&&r[g]){if(g==o)return;var u=r[g];u="Array"===n.util.type(u)?u:[u];for(var c=0;c<u.length;++c){var h=u[c],f=h.inside,d=!!h.lookbehind,m=!!h.greedy,p=0,y=h.alias;if(m&&!h.pattern.global){var v=h.pattern.toString().match(/[imuy]*$/)[0];h.pattern=RegExp(h.pattern.source,v+"g")}h=h.pattern||h;for(var b=a,k=l;b<t.length;k+=t[b].length,++b){var w=t[b];if(t.length>e.length)return;if(!(w instanceof s)){h.lastIndex=0;var _=h.exec(w),P=1;if(!_&&m&&b!=t.length-1){if(h.lastIndex=k,_=h.exec(e),!_)break;for(var A=_.index+(d?_[1].length:0),j=_.index+_[0].length,x=b,O=k,N=t.length;N>x&&(j>O||!t[x].type&&!t[x-1].greedy);++x)O+=t[x].length,A>=O&&(++b,k=O);if(t[b]instanceof s||t[x-1].greedy)continue;P=x-b,w=e.slice(k,O),_.index-=k}if(_){d&&(p=_[1].length);var A=_.index+p,_=_[0].slice(p),j=A+_.length,S=w.slice(0,A),C=w.slice(j),M=[b,P];S&&(++b,k+=S.length,M.push(S));var E=new s(g,f?n.tokenize(_,f):_,y,_,m);if(M.push(E),C&&M.push(C),Array.prototype.splice.apply(t,M),1!=P&&n.matchGrammar(e,t,r,b,k,!0,g),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
|
|
Prism.languages.markup={comment:/<!--[\s\S]*?-->/,prolog:/<\?[\s\S]+?\?>/,doctype:/<!DOCTYPE[\s\S]+?>/i,cdata:/<!\[CDATA\[[\s\S]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
|
|
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
|
|
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|\d*\.?\d+(?:[Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"}}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\s\S]*?>)[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript;
|
|
!function(e){e.languages.pug={comment:{pattern:/(^([\t ]*))\/\/.*(?:(?:\r?\n|\r)\2[\t ]+.+)*/m,lookbehind:!0},"multiline-script":{pattern:/(^([\t ]*)script\b.*\.[\t ]*)(?:(?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},filter:{pattern:/(^([\t ]*)):.+(?:(?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"}}},"multiline-plain-text":{pattern:/(^([\t ]*)[\w\-#.]+\.[\t ]*)(?:(?:\r?\n|\r(?!\n))(?:\2[\t ]+.+|\s*?(?=\r?\n|\r)))+/m,lookbehind:!0},markup:{pattern:/(^[\t ]*)<.+/m,lookbehind:!0,inside:{rest:e.languages.markup}},doctype:{pattern:/((?:^|\n)[\t ]*)doctype(?: .+)?/,lookbehind:!0},"flow-control":{pattern:/(^[\t ]*)(?:if|unless|else|case|when|default|each|while)\b(?: .+)?/m,lookbehind:!0,inside:{each:{pattern:/^each .+? in\b/,inside:{keyword:/\b(?:each|in)\b/,punctuation:/,/}},branch:{pattern:/^(?:if|unless|else|case|when|default|while)\b/,alias:"keyword"},rest:e.languages.javascript}},keyword:{pattern:/(^[\t ]*)(?:block|extends|include|append|prepend)\b.+/m,lookbehind:!0},mixin:[{pattern:/(^[\t ]*)mixin .+/m,lookbehind:!0,inside:{keyword:/^mixin/,"function":/\w+(?=\s*\(|\s*$)/,punctuation:/[(),.]/}},{pattern:/(^[\t ]*)\+.+/m,lookbehind:!0,inside:{name:{pattern:/^\+\w+/,alias:"function"},rest:e.languages.javascript}}],script:{pattern:/(^[\t ]*script(?:(?:&[^(]+)?\([^)]+\))*[\t ]+).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}},"plain-text":{pattern:/(^[\t ]*(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?[\t ]+).+/m,lookbehind:!0},tag:{pattern:/(^[\t ]*)(?!-)[\w\-#.]*[\w\-](?:(?:&[^(]+)?\([^)]+\))*\/?:?/m,lookbehind:!0,inside:{attributes:[{pattern:/&[^(]+\([^)]+\)/,inside:{rest:e.languages.javascript}},{pattern:/\([^)]+\)/,inside:{"attr-value":{pattern:/(=\s*)(?:\{[^}]*\}|[^,)\r\n]+)/,lookbehind:!0,inside:{rest:e.languages.javascript}},"attr-name":/[\w-]+(?=\s*!?=|\s*[,)])/,punctuation:/[!=(),]+/}}],punctuation:/:/}},code:[{pattern:/(^[\t ]*(?:-|!?=)).+/m,lookbehind:!0,inside:{rest:e.languages.javascript}}],punctuation:/[.\-!=|]+/};for(var t="(^([\\t ]*)):{{filter_name}}(?:(?:\\r?\\n|\\r(?!\\n))(?:\\2[\\t ]+.+|\\s*?(?=\\r?\\n|\\r)))+",n=[{filter:"atpl",language:"twig"},{filter:"coffee",language:"coffeescript"},"ejs","handlebars","hogan","less","livescript","markdown","mustache","plates",{filter:"sass",language:"scss"},"stylus","swig"],a={},i=0,r=n.length;r>i;i++){var s=n[i];s="string"==typeof s?{filter:s,language:s}:s,e.languages[s.language]&&(a["filter-"+s.filter]={pattern:RegExp(t.replace("{{filter_name}}",s.filter),"m"),lookbehind:!0,inside:{"filter-name":{pattern:/^:[\w-]+/,alias:"variable"},rest:e.languages[s.language]}})}e.languages.insertBefore("pug","filter",a)}(Prism);
|