| Current Path : /var/www/cesa.co.za/app/framework7/ |
| Current File : /var/www/cesa.co.za/app/framework7/framework7.esm.bundle.js |
/**
* Framework7 2.0.6
* Full featured mobile HTML framework for building iOS & Android apps
* http://framework7.io/
*
* Copyright 2014-2018 Vladimir Kharlampidi
*
* Released under the MIT License
*
* Released on: January 9, 2018
*/
import Template7 from 'template7';
import $ from 'dom7';
import PathToRegexp from 'path-to-regexp';
/**
* https://github.com/gre/bezier-easing
* BezierEasing - use bezier curve for transition easing function
* by Gaëtan Renaudeau 2014 - 2015 – MIT License
*/
/* eslint-disable */
// These values are established by empiricism with tests (tradeoff: performance VS precision)
var NEWTON_ITERATIONS = 4;
var NEWTON_MIN_SLOPE = 0.001;
var SUBDIVISION_PRECISION = 0.0000001;
var SUBDIVISION_MAX_ITERATIONS = 10;
var kSplineTableSize = 11;
var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
var float32ArraySupported = typeof Float32Array === 'function';
function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
function C (aA1) { return 3.0 * aA1; }
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; }
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); }
function binarySubdivide (aX, aA, aB, mX1, mX2) {
var currentX, currentT, i = 0;
do {
currentT = aA + (aB - aA) / 2.0;
currentX = calcBezier(currentT, mX1, mX2) - aX;
if (currentX > 0.0) {
aB = currentT;
} else {
aA = currentT;
}
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
return currentT;
}
function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
var currentSlope = getSlope(aGuessT, mX1, mX2);
if (currentSlope === 0.0) {
return aGuessT;
}
var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
aGuessT -= currentX / currentSlope;
}
return aGuessT;
}
function bezier (mX1, mY1, mX2, mY2) {
if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
throw new Error('bezier x values must be in [0, 1] range');
}
// Precompute samples table
var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
if (mX1 !== mY1 || mX2 !== mY2) {
for (var i = 0; i < kSplineTableSize; ++i) {
sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
}
}
function getTForX (aX) {
var intervalStart = 0.0;
var currentSample = 1;
var lastSample = kSplineTableSize - 1;
for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
intervalStart += kSampleStepSize;
}
--currentSample;
// Interpolate to provide an initial guess for t
var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
var guessForT = intervalStart + dist * kSampleStepSize;
var initialSlope = getSlope(guessForT, mX1, mX2);
if (initialSlope >= NEWTON_MIN_SLOPE) {
return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
} else if (initialSlope === 0.0) {
return guessForT;
} else {
return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
}
}
return function BezierEasing (x) {
if (mX1 === mY1 && mX2 === mY2) {
return x; // linear
}
// Because JavaScript number are imprecise, we should guarantee the extremes are right.
if (x === 0) {
return 0;
}
if (x === 1) {
return 1;
}
return calcBezier(getTForX(x), mY1, mY2);
};
}
// Remove Diacritics
const defaultDiacriticsRemovalap = [
{ base: 'A', letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' },
{ base: 'AA', letters: '\uA732' },
{ base: 'AE', letters: '\u00C6\u01FC\u01E2' },
{ base: 'AO', letters: '\uA734' },
{ base: 'AU', letters: '\uA736' },
{ base: 'AV', letters: '\uA738\uA73A' },
{ base: 'AY', letters: '\uA73C' },
{ base: 'B', letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181' },
{ base: 'C', letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E' },
{ base: 'D', letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779' },
{ base: 'DZ', letters: '\u01F1\u01C4' },
{ base: 'Dz', letters: '\u01F2\u01C5' },
{ base: 'E', letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E' },
{ base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
{ base: 'G', letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E' },
{ base: 'H', letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D' },
{ base: 'I', letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197' },
{ base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
{ base: 'K', letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2' },
{ base: 'L', letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780' },
{ base: 'LJ', letters: '\u01C7' },
{ base: 'Lj', letters: '\u01C8' },
{ base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
{ base: 'N', letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4' },
{ base: 'NJ', letters: '\u01CA' },
{ base: 'Nj', letters: '\u01CB' },
{ base: 'O', letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C' },
{ base: 'OI', letters: '\u01A2' },
{ base: 'OO', letters: '\uA74E' },
{ base: 'OU', letters: '\u0222' },
{ base: 'OE', letters: '\u008C\u0152' },
{ base: 'oe', letters: '\u009C\u0153' },
{ base: 'P', letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754' },
{ base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
{ base: 'R', letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782' },
{ base: 'S', letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784' },
{ base: 'T', letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786' },
{ base: 'TZ', letters: '\uA728' },
{ base: 'U', letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244' },
{ base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
{ base: 'VY', letters: '\uA760' },
{ base: 'W', letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72' },
{ base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
{ base: 'Y', letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE' },
{ base: 'Z', letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762' },
{ base: 'a', letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250' },
{ base: 'aa', letters: '\uA733' },
{ base: 'ae', letters: '\u00E6\u01FD\u01E3' },
{ base: 'ao', letters: '\uA735' },
{ base: 'au', letters: '\uA737' },
{ base: 'av', letters: '\uA739\uA73B' },
{ base: 'ay', letters: '\uA73D' },
{ base: 'b', letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253' },
{ base: 'c', letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184' },
{ base: 'd', letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A' },
{ base: 'dz', letters: '\u01F3\u01C6' },
{ base: 'e', letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD' },
{ base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
{ base: 'g', letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F' },
{ base: 'h', letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265' },
{ base: 'hv', letters: '\u0195' },
{ base: 'i', letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131' },
{ base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
{ base: 'k', letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3' },
{ base: 'l', letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747' },
{ base: 'lj', letters: '\u01C9' },
{ base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
{ base: 'n', letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5' },
{ base: 'nj', letters: '\u01CC' },
{ base: 'o', letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275' },
{ base: 'oi', letters: '\u01A3' },
{ base: 'ou', letters: '\u0223' },
{ base: 'oo', letters: '\uA74F' },
{ base: 'p', letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755' },
{ base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
{ base: 'r', letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783' },
{ base: 's', letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B' },
{ base: 't', letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787' },
{ base: 'tz', letters: '\uA729' },
{ base: 'u', letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289' },
{ base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
{ base: 'vy', letters: '\uA761' },
{ base: 'w', letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73' },
{ base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
{ base: 'y', letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF' },
{ base: 'z', letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' },
];
const diacriticsMap = {};
for (let i = 0; i < defaultDiacriticsRemovalap.length; i += 1) {
const letters = defaultDiacriticsRemovalap[i].letters;
for (let j = 0; j < letters.length; j += 1) {
diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;
}
}
const createPromise = function createPromise(handler) {
let resolved = false;
let rejected = false;
let resolveArgs;
let rejectArgs;
const promiseHandlers = {
then: undefined,
catch: undefined,
};
const promise = {
then(thenHandler) {
if (resolved) {
thenHandler(...resolveArgs);
} else {
promiseHandlers.then = thenHandler;
}
return promise;
},
catch(catchHandler) {
if (rejected) {
catchHandler(...rejectArgs);
} else {
promiseHandlers.catch = catchHandler;
}
return promise;
},
};
function resolve(...args) {
resolved = true;
if (promiseHandlers.then) promiseHandlers.then(...args);
else resolveArgs = args;
}
function reject(...args) {
rejected = true;
if (promiseHandlers.catch) promiseHandlers.catch(...args);
else rejectArgs = args;
}
handler(resolve, reject);
return promise;
};
const Utils = {
mdPreloaderContent: `
<span class="preloader-inner">
<span class="preloader-inner-gap"></span>
<span class="preloader-inner-left">
<span class="preloader-inner-half-circle"></span>
</span>
<span class="preloader-inner-right">
<span class="preloader-inner-half-circle"></span>
</span>
</span>
`.trim(),
eventNameToColonCase(eventName) {
let hasColon;
return eventName.split('').map((char, index) => {
if (char.match(/[A-Z]/) && index !== 0 && !hasColon) {
hasColon = true;
return `:${char.toLowerCase()}`;
}
return char.toLowerCase();
}).join('');
},
deleteProps(obj) {
const object = obj;
Object.keys(object).forEach((key) => {
try {
object[key] = null;
} catch (e) {
// no getter for object
}
try {
delete object[key];
} catch (e) {
// something got wrong
}
});
},
bezier(...args) {
return bezier(...args);
},
nextTick(callback, delay = 0) {
return setTimeout(callback, delay);
},
nextFrame(callback) {
return Utils.requestAnimationFrame(callback);
},
now() {
return Date.now();
},
promise(handler) {
return window.Promise ? new Promise(handler) : createPromise(handler);
},
requestAnimationFrame(callback) {
if (window.requestAnimationFrame) return window.requestAnimationFrame(callback);
else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback);
return window.setTimeout(callback, 1000 / 60);
},
cancelAnimationFrame(id) {
if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id);
else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id);
return window.clearTimeout(id);
},
removeDiacritics(str) {
return str.replace(/[^\u0000-\u007E]/g, a => diacriticsMap[a] || a);
},
parseUrlQuery(url) {
const query = {};
let urlToParse = url || window.location.href;
let i;
let params;
let param;
let length;
if (typeof urlToParse === 'string' && urlToParse.length) {
urlToParse = urlToParse.indexOf('?') > -1 ? urlToParse.replace(/\S*\?/, '') : '';
params = urlToParse.split('&').filter(paramsPart => paramsPart !== '');
length = params.length;
for (i = 0; i < length; i += 1) {
param = params[i].replace(/#\S+/g, '').split('=');
query[decodeURIComponent(param[0])] = typeof param[1] === 'undefined' ? undefined : decodeURIComponent(param[1]) || '';
}
}
return query;
},
getTranslate(el, axis = 'x') {
let matrix;
let curTransform;
let transformMatrix;
const curStyle = window.getComputedStyle(el, null);
if (window.WebKitCSSMatrix) {
curTransform = curStyle.transform || curStyle.webkitTransform;
if (curTransform.split(',').length > 6) {
curTransform = curTransform.split(', ').map(a => a.replace(',', '.')).join(', ');
}
// Some old versions of Webkit choke when 'none' is passed; pass
// empty string instead in this case
transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
} else {
transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
matrix = transformMatrix.toString().split(',');
}
if (axis === 'x') {
// Latest Chrome and webkits Fix
if (window.WebKitCSSMatrix) curTransform = transformMatrix.m41;
// Crazy IE10 Matrix
else if (matrix.length === 16) curTransform = parseFloat(matrix[12]);
// Normal Browsers
else curTransform = parseFloat(matrix[4]);
}
if (axis === 'y') {
// Latest Chrome and webkits Fix
if (window.WebKitCSSMatrix) curTransform = transformMatrix.m42;
// Crazy IE10 Matrix
else if (matrix.length === 16) curTransform = parseFloat(matrix[13]);
// Normal Browsers
else curTransform = parseFloat(matrix[5]);
}
return curTransform || 0;
},
serializeObject(obj, parents = []) {
if (typeof obj === 'string') return obj;
const resultArray = [];
const separator = '&';
let newParents;
function varName(name) {
if (parents.length > 0) {
let parentParts = '';
for (let j = 0; j < parents.length; j += 1) {
if (j === 0) parentParts += parents[j];
else parentParts += `[${encodeURIComponent(parents[j])}]`;
}
return `${parentParts}[${encodeURIComponent(name)}]`;
}
return encodeURIComponent(name);
}
function varValue(value) {
return encodeURIComponent(value);
}
Object.keys(obj).forEach((prop) => {
let toPush;
if (Array.isArray(obj[prop])) {
toPush = [];
for (let i = 0; i < obj[prop].length; i += 1) {
if (!Array.isArray(obj[prop][i]) && typeof obj[prop][i] === 'object') {
newParents = parents.slice();
newParents.push(prop);
newParents.push(String(i));
toPush.push(Utils.serializeObject(obj[prop][i], newParents));
} else {
toPush.push(`${varName(prop)}[]=${varValue(obj[prop][i])}`);
}
}
if (toPush.length > 0) resultArray.push(toPush.join(separator));
} else if (obj[prop] === null || obj[prop] === '') {
resultArray.push(`${varName(prop)}=`);
} else if (typeof obj[prop] === 'object') {
// Object, convert to named array
newParents = parents.slice();
newParents.push(prop);
toPush = Utils.serializeObject(obj[prop], newParents);
if (toPush !== '') resultArray.push(toPush);
} else if (typeof obj[prop] !== 'undefined' && obj[prop] !== '') {
// Should be string or plain value
resultArray.push(`${varName(prop)}=${varValue(obj[prop])}`);
} else if (obj[prop] === '') resultArray.push(varName(prop));
});
return resultArray.join(separator);
},
isObject(o) {
return typeof o === 'object' && o !== null && o.constructor && o.constructor === Object;
},
extend(...args) {
let deep = true;
let to;
let from;
if (typeof args[0] === 'boolean') {
deep = args[0];
to = args[1];
args.splice(0, 2);
from = args;
} else {
to = args[0];
args.splice(0, 1);
from = args;
}
for (let i = 0; i < from.length; i += 1) {
const nextSource = args[i];
if (nextSource !== undefined && nextSource !== null) {
const keysArray = Object.keys(Object(nextSource));
for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
const nextKey = keysArray[nextIndex];
const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
if (!deep) {
to[nextKey] = nextSource[nextKey];
} else if (Utils.isObject(to[nextKey]) && Utils.isObject(nextSource[nextKey])) {
Utils.extend(to[nextKey], nextSource[nextKey]);
} else if (!Utils.isObject(to[nextKey]) && Utils.isObject(nextSource[nextKey])) {
to[nextKey] = {};
Utils.extend(to[nextKey], nextSource[nextKey]);
} else {
to[nextKey] = nextSource[nextKey];
}
}
}
}
}
return to;
},
};
const Device = (function Device() {
const ua = window.navigator.userAgent;
const device = {
ios: false,
android: false,
androidChrome: false,
desktop: false,
windows: false,
iphone: false,
iphoneX: false,
ipod: false,
ipad: false,
cordova: window.cordova || window.phonegap,
phonegap: window.cordova || window.phonegap,
};
const windows = ua.match(/(Windows Phone);?[\s\/]+([\d.]+)?/); // eslint-disable-line
const android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // eslint-disable-line
const ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
const iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/);
const iphoneX = iphone && window.screen.width === 375 && window.screen.height === 812;
// Windows
if (windows) {
device.os = 'windows';
device.osVersion = windows[2];
device.windows = true;
}
// Android
if (android && !windows) {
device.os = 'android';
device.osVersion = android[2];
device.android = true;
device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
}
if (ipad || iphone || ipod) {
device.os = 'ios';
device.ios = true;
}
// iOS
if (iphone && !ipod) {
device.osVersion = iphone[2].replace(/_/g, '.');
device.iphone = true;
device.iphoneX = iphoneX;
}
if (ipad) {
device.osVersion = ipad[2].replace(/_/g, '.');
device.ipad = true;
}
if (ipod) {
device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
device.iphone = true;
}
// iOS 8+ changed UA
if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
if (device.osVersion.split('.')[0] === '10') {
device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
}
}
// Webview
device.webView = (iphone || ipad || ipod) && (ua.match(/.*AppleWebKit(?!.*Safari)/i) || window.navigator.standalone);
device.webview = device.webView;
// Desktop
device.desktop = !(device.os || device.android || device.webView);
// Minimal UI
if (device.os && device.os === 'ios') {
const osVersionArr = device.osVersion.split('.');
const metaViewport = document.querySelector('meta[name="viewport"]');
device.minimalUi =
!device.webView &&
(ipod || iphone) &&
(osVersionArr[0] * 1 === 7 ? osVersionArr[1] * 1 >= 1 : osVersionArr[0] * 1 > 7) &&
metaViewport && metaViewport.getAttribute('content').indexOf('minimal-ui') >= 0;
}
// Check for status bar and fullscreen app mode
device.needsStatusbarOverlay = function needsStatusbarOverlay() {
if (device.webView && (window.innerWidth * window.innerHeight === window.screen.width * window.screen.height)) {
if (device.iphoneX && (window.orientation === 90 || window.orientation === -90)) {
return false;
}
return true;
}
return false;
};
device.statusbar = device.needsStatusbarOverlay();
// Pixel Ratio
device.pixelRatio = window.devicePixelRatio || 1;
// Export object
return device;
}());
class Framework7Class {
constructor(params = {}, parents = []) {
const self = this;
self.params = params;
// Events
self.eventsParents = parents;
self.eventsListeners = {};
if (self.params && self.params.on) {
Object.keys(self.params.on).forEach((eventName) => {
self.on(eventName, self.params.on[eventName]);
});
}
}
on(events, handler) {
const self = this;
if (typeof handler !== 'function') return self;
events.split(' ').forEach((event) => {
if (!self.eventsListeners[event]) self.eventsListeners[event] = [];
self.eventsListeners[event].push(handler);
});
return self;
}
once(events, handler) {
const self = this;
if (typeof handler !== 'function') return self;
function onceHandler(...args) {
handler.apply(self, args);
self.off(events, onceHandler);
}
return self.on(events, onceHandler);
}
off(events, handler) {
const self = this;
if (!self.eventsListeners) return self;
events.split(' ').forEach((event) => {
if (typeof handler === 'undefined') {
self.eventsListeners[event] = [];
} else {
self.eventsListeners[event].forEach((eventHandler, index) => {
if (eventHandler === handler) {
self.eventsListeners[event].splice(index, 1);
}
});
}
});
return self;
}
emit(...args) {
const self = this;
if (!self.eventsListeners) return self;
let events;
let data;
let context;
let eventsParents;
if (typeof args[0] === 'string' || Array.isArray(args[0])) {
events = args[0];
data = args.slice(1, args.length);
context = self;
eventsParents = self.eventsParents;
} else {
events = args[0].events;
data = args[0].data;
context = args[0].context || self;
eventsParents = args[0].local ? [] : args[0].parents || self.eventsParents;
}
const eventsArray = Array.isArray(events) ? events : events.split(' ');
const localEvents = eventsArray.map(eventName => eventName.replace('local::', ''));
const parentEvents = eventsArray.filter(eventName => eventName.indexOf('local::') < 0);
localEvents.forEach((event) => {
if (self.eventsListeners[event]) {
const handlers = [];
self.eventsListeners[event].forEach((eventHandler) => {
handlers.push(eventHandler);
});
handlers.forEach((eventHandler) => {
eventHandler.apply(context, data);
});
}
});
if (eventsParents && eventsParents.length > 0) {
eventsParents.forEach((eventsParent) => {
eventsParent.emit(parentEvents, ...data);
});
}
return self;
}
useModulesParams(instanceParams) {
const instance = this;
if (!instance.modules) return;
Object.keys(instance.modules).forEach((moduleName) => {
const module = instance.modules[moduleName];
// Extend params
if (module.params) {
Utils.extend(instanceParams, module.params);
}
});
}
useModules(modulesParams = {}) {
const instance = this;
if (!instance.modules) return;
Object.keys(instance.modules).forEach((moduleName) => {
const module = instance.modules[moduleName];
const moduleParams = modulesParams[moduleName] || {};
// Extend instance methods and props
if (module.instance) {
Object.keys(module.instance).forEach((modulePropName) => {
const moduleProp = module.instance[modulePropName];
if (typeof moduleProp === 'function') {
instance[modulePropName] = moduleProp.bind(instance);
} else {
instance[modulePropName] = moduleProp;
}
});
}
// Add event listeners
if (module.on && instance.on) {
Object.keys(module.on).forEach((moduleEventName) => {
instance.on(moduleEventName, module.on[moduleEventName]);
});
}
// Module create callback
if (module.create) {
module.create.bind(instance)(moduleParams);
}
});
}
static set components(components) {
const Class = this;
if (!Class.use) return;
Class.use(components);
}
static installModule(module, ...params) {
const Class = this;
if (!Class.prototype.modules) Class.prototype.modules = {};
const name = module.name || (`${Object.keys(Class.prototype.modules).length}_${Utils.now()}`);
Class.prototype.modules[name] = module;
// Prototype
if (module.proto) {
Object.keys(module.proto).forEach((key) => {
Class.prototype[key] = module.proto[key];
});
}
// Class
if (module.static) {
Object.keys(module.static).forEach((key) => {
Class[key] = module.static[key];
});
}
// Callback
if (module.install) {
module.install.apply(Class, params);
}
return Class;
}
static use(module, ...params) {
const Class = this;
if (Array.isArray(module)) {
module.forEach(m => Class.installModule(m));
return Class;
}
return Class.installModule(module, ...params);
}
}
class Framework7$1 extends Framework7Class {
constructor(params) {
super(params);
const passedParams = Utils.extend({}, params);
// App Instance
const app = this;
// Default
const defaults = {
version: '1.0.0',
id: 'io.framework7.testapp',
root: 'body',
theme: 'auto',
language: window.navigator.language,
routes: [],
name: 'Framework7',
initOnDeviceReady: true,
init: true,
};
// Extend defaults with modules params
app.useModulesParams(defaults);
// Extend defaults with passed params
app.params = Utils.extend(defaults, params);
const $rootEl = $(app.params.root);
Utils.extend(app, {
// App Id
id: app.params.id,
// App Name
name: app.params.name,
// App version
version: app.params.version,
// Routes
routes: app.params.routes,
// Lang
language: app.params.language,
// Root
root: $rootEl,
// Local Storage
ls: window.localStorage,
// RTL
rtl: $rootEl.css('direction') === 'rtl',
// Theme
theme: (function getTheme() {
if (app.params.theme === 'auto') {
return Device.ios ? 'ios' : 'md';
}
return app.params.theme;
}()),
// Initially passed parameters
passedParams,
});
// Save Root
app.root[0].f7 = app;
// Install Modules
app.useModules();
// Init
if (app.params.init) {
if (Device.cordova && app.params.initOnDeviceReady) {
$(document).on('deviceready', () => {
app.init();
});
} else {
app.init();
}
}
// Return app instance
return app;
}
init() {
const app = this;
if (app.initialized) return;
app.root.addClass('framework7-initializing');
// RTL attr
if (app.rtl) {
$('html').attr('dir', 'rtl');
}
// Root class
app.root.addClass('framework7-root');
// Theme class
$('html').removeClass('ios md').addClass(app.theme);
// Data
app.data = {};
if (app.params.data && typeof app.params.data === 'function') {
Utils.extend(app.data, app.params.data.bind(app)());
} else if (app.params.data) {
Utils.extend(app.data, app.params.data);
}
// Methods
app.methods = {};
if (app.params.methods) {
Utils.extend(app.methods, app.params.methods);
}
// Init class
Utils.nextFrame(() => {
app.root.removeClass('framework7-initializing');
});
// Emit, init other modules
app.initialized = true;
app.emit('init');
}
// eslint-disable-next-line
get $() {
return $;
}
// eslint-disable-next-line
get t7() {
return Template7;
}
static get Dom7() {
return $;
}
static get $() {
return $;
}
static get Template7() {
return Template7;
}
static get Class() {
return Framework7Class;
}
}
var Device$2 = {
name: 'device',
proto: {
device: Device,
},
static: {
device: Device,
},
on: {
init() {
const classNames = [];
const html = document.querySelector('html');
// Pixel Ratio
classNames.push(`device-pixel-ratio-${Math.floor(Device.pixelRatio)}`);
if (Device.pixelRatio >= 2) {
classNames.push('device-retina');
}
// OS classes
if (Device.os) {
classNames.push(
`device-${Device.os}`,
`device-${Device.os}-${Device.osVersion.split('.')[0]}`,
`device-${Device.os}-${Device.osVersion.replace(/\./g, '-')}`
);
if (Device.os === 'ios') {
const major = parseInt(Device.osVersion.split('.')[0], 10);
for (let i = major - 1; i >= 6; i -= 1) {
classNames.push(`device-ios-gt-${i}`);
}
if (Device.iphoneX) {
classNames.push('device-iphone-x');
}
}
} else if (Device.desktop) {
classNames.push('device-desktop');
}
// Status bar classes
if (Device.statusbar) {
classNames.push('with-statusbar');
} else {
html.classList.remove('with-statusbar');
}
// Add html classes
classNames.forEach((className) => {
html.classList.add(className);
});
},
},
};
const Support$1 = (function Support() {
const positionSticky = (function supportPositionSticky() {
let support = false;
const div = document.createElement('div');
('sticky -webkit-sticky -moz-sticky').split(' ').forEach((prop) => {
if (support) return;
div.style.position = prop;
if (div.style.position === prop) {
support = true;
}
});
return support;
}());
return {
positionSticky,
touch: (function checkTouch() {
return !!(('ontouchstart' in window) || (window.DocumentTouch && document instanceof window.DocumentTouch));
}()),
transforms3d: (function checkTransforms3d() {
const div = document.createElement('div').style;
return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div);
}()),
flexbox: (function checkFlexbox() {
const div = document.createElement('div').style;
const styles = ('alignItems webkitAlignItems webkitBoxAlign msFlexAlign mozBoxAlign webkitFlexDirection msFlexDirection mozBoxDirection mozBoxOrient webkitBoxDirection webkitBoxOrient').split(' ');
for (let i = 0; i < styles.length; i += 1) {
if (styles[i] in div) return true;
}
return false;
}()),
observer: (function checkObserver() {
return ('MutationObserver' in window || 'WebkitMutationObserver' in window);
}()),
passiveListener: (function checkPassiveListener() {
let supportsPassive = false;
try {
const opts = Object.defineProperty({}, 'passive', {
// eslint-disable-next-line
get() {
supportsPassive = true;
},
});
window.addEventListener('testPassiveListener', null, opts);
} catch (e) {
// No support
}
return supportsPassive;
}()),
gestures: (function checkGestures() {
return 'ongesturestart' in window;
}()),
};
}());
var Support = {
name: 'support',
proto: {
support: Support$1,
},
static: {
support: Support$1,
},
on: {
init() {
const html = document.querySelector('html');
const classNames = [];
if (Support$1.positionSticky) {
classNames.push('support-position-sticky');
}
// Add html classes
classNames.forEach((className) => {
html.classList.add(className);
});
},
},
};
var Utils$2 = {
name: 'utils',
proto: {
utils: Utils,
},
static: {
utils: Utils,
},
};
var Resize = {
name: 'resize',
instance: {
getSize() {
const app = this;
const offset = app.root.offset();
const [width, height, left, top] = [app.root[0].offsetWidth, app.root[0].offsetHeight, offset.left, offset.top];
app.width = width;
app.height = height;
app.left = left;
app.top = top;
return { width, height, left, top };
},
},
on: {
init() {
const app = this;
// Get Size
app.getSize();
// Emit resize
window.addEventListener('resize', () => {
app.emit('resize');
}, false);
// Emit orientationchange
window.addEventListener('orientationchange', () => {
app.emit('orientationchange');
});
},
orientationchange() {
const app = this;
if (app.device && app.device.minimalUi) {
if (window.orientation === 90 || window.orientation === -90) {
document.body.scrollTop = 0;
}
}
// Fix iPad weird body scroll
if (app.device.ipad) {
document.body.scrollLeft = 0;
setTimeout(() => {
document.body.scrollLeft = 0;
}, 0);
}
},
resize() {
const app = this;
app.getSize();
},
},
};
const globals = {};
let jsonpRequests = 0;
function Request$1(requestOptions) {
const globalsNoCallbacks = Utils.extend({}, globals);
('beforeCreate beforeOpen beforeSend error complete success statusCode').split(' ').forEach((callbackName) => {
delete globalsNoCallbacks[callbackName];
});
const defaults = Utils.extend({
url: window.location.toString(),
method: 'GET',
data: false,
async: true,
cache: true,
user: '',
password: '',
headers: {},
xhrFields: {},
statusCode: {},
processData: true,
dataType: 'text',
contentType: 'application/x-www-form-urlencoded',
timeout: 0,
}, globalsNoCallbacks);
const options = Utils.extend({}, defaults, requestOptions);
// Function to run XHR callbacks and events
function fireCallback(callbackName, ...data) {
/*
Callbacks:
beforeCreate (options),
beforeOpen (xhr, options),
beforeSend (xhr, options),
error (xhr, status),
complete (xhr, stautus),
success (response, status, xhr),
statusCode ()
*/
if (globals[callbackName]) globals[callbackName](...data);
if (options[callbackName]) options[callbackName](...data);
}
// Before create callback
fireCallback('beforeCreate', options);
// For jQuery guys
if (options.type) options.method = options.type;
// Parameters Prefix
let paramsPrefix = options.url.indexOf('?') >= 0 ? '&' : '?';
// UC method
const method = options.method.toUpperCase();
// Data to modify GET URL
if ((method === 'GET' || method === 'HEAD' || method === 'OPTIONS' || method === 'DELETE') && options.data) {
let stringData;
if (typeof options.data === 'string') {
// Should be key=value string
if (options.data.indexOf('?') >= 0) stringData = options.data.split('?')[1];
else stringData = options.data;
} else {
// Should be key=value object
stringData = Utils.serializeObject(options.data);
}
if (stringData.length) {
options.url += paramsPrefix + stringData;
if (paramsPrefix === '?') paramsPrefix = '&';
}
}
// JSONP
if (options.dataType === 'json' && options.url.indexOf('callback=') >= 0) {
const callbackName = `f7jsonp_${Date.now() + ((jsonpRequests += 1))}`;
let abortTimeout;
const callbackSplit = options.url.split('callback=');
let requestUrl = `${callbackSplit[0]}callback=${callbackName}`;
if (callbackSplit[1].indexOf('&') >= 0) {
const addVars = callbackSplit[1].split('&').filter(el => el.indexOf('=') > 0).join('&');
if (addVars.length > 0) requestUrl += `&${addVars}`;
}
// Create script
let script = document.createElement('script');
script.type = 'text/javascript';
script.onerror = function onerror() {
clearTimeout(abortTimeout);
fireCallback('error', null, 'scripterror');
fireCallback('complete', null, 'scripterror');
};
script.src = requestUrl;
// Handler
window[callbackName] = function jsonpCallback(data) {
clearTimeout(abortTimeout);
fireCallback('success', data);
script.parentNode.removeChild(script);
script = null;
delete window[callbackName];
};
document.querySelector('head').appendChild(script);
if (options.timeout > 0) {
abortTimeout = setTimeout(() => {
script.parentNode.removeChild(script);
script = null;
fireCallback('error', null, 'timeout');
}, options.timeout);
}
return undefined;
}
// Cache for GET/HEAD requests
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS' || method === 'DELETE') {
if (options.cache === false) {
options.url += `${paramsPrefix}_nocache${Date.now()}`;
}
}
// Create XHR
const xhr = new XMLHttpRequest();
// Save Request URL
xhr.requestUrl = options.url;
xhr.requestParameters = options;
// Before open callback
fireCallback('beforeOpen', xhr, options);
// Open XHR
xhr.open(method, options.url, options.async, options.user, options.password);
// Create POST Data
let postData = null;
if ((method === 'POST' || method === 'PUT' || method === 'PATCH') && options.data) {
if (options.processData) {
const postDataInstances = [ArrayBuffer, Blob, Document, FormData];
// Post Data
if (postDataInstances.indexOf(options.data.constructor) >= 0) {
postData = options.data;
} else {
// POST Headers
const boundary = `---------------------------${Date.now().toString(16)}`;
if (options.contentType === 'multipart/form-data') {
xhr.setRequestHeader('Content-Type', `multipart/form-data; boundary=${boundary}`);
} else {
xhr.setRequestHeader('Content-Type', options.contentType);
}
postData = '';
let data = Utils.serializeObject(options.data);
if (options.contentType === 'multipart/form-data') {
data = data.split('&');
const newData = [];
for (let i = 0; i < data.length; i += 1) {
newData.push(`Content-Disposition: form-data; name="${data[i].split('=')[0]}"\r\n\r\n${data[i].split('=')[1]}\r\n`);
}
postData = `--${boundary}\r\n${newData.join(`--${boundary}\r\n`)}--${boundary}--\r\n`;
} else {
postData = data;
}
}
} else {
postData = options.data;
xhr.setRequestHeader('Content-Type', options.contentType);
}
}
// Additional headers
if (options.headers) {
Object.keys(options.headers).forEach((headerName) => {
xhr.setRequestHeader(headerName, options.headers[headerName]);
});
}
// Check for crossDomain
if (typeof options.crossDomain === 'undefined') {
// eslint-disable-next-line
options.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(options.url) && RegExp.$2 !== window.location.host;
}
if (!options.crossDomain) {
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
if (options.xhrFields) {
Utils.extend(xhr, options.xhrFields);
}
let xhrTimeout;
// Handle XHR
xhr.onload = function onload() {
if (xhrTimeout) clearTimeout(xhrTimeout);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
let responseData;
if (options.dataType === 'json') {
try {
responseData = JSON.parse(xhr.responseText);
fireCallback('success', responseData, xhr.status, xhr);
} catch (err) {
fireCallback('error', xhr, 'parseerror');
}
} else {
responseData = xhr.responseType === 'text' || xhr.responseType === '' ? xhr.responseText : xhr.response;
fireCallback('success', responseData, xhr.status, xhr);
}
} else {
fireCallback('error', xhr, xhr.status);
}
if (options.statusCode) {
if (globals.statusCode && globals.statusCode[xhr.status]) globals.statusCode[xhr.status](xhr);
if (options.statusCode[xhr.status]) options.statusCode[xhr.status](xhr);
}
fireCallback('complete', xhr, xhr.status);
};
xhr.onerror = function onerror() {
if (xhrTimeout) clearTimeout(xhrTimeout);
fireCallback('error', xhr, xhr.status);
fireCallback('complete', xhr, 'error');
};
// Timeout
if (options.timeout > 0) {
xhr.onabort = function onabort() {
if (xhrTimeout) clearTimeout(xhrTimeout);
};
xhrTimeout = setTimeout(() => {
xhr.abort();
fireCallback('error', xhr, 'timeout');
fireCallback('complete', xhr, 'timeout');
}, options.timeout);
}
// Ajax start callback
fireCallback('beforeSend', xhr, options);
// Send XHR
xhr.send(postData);
// Return XHR object
return xhr;
}
function RequestShortcut(method, ...args) {
let [url, data, success, error, dataType] = [];
if (typeof args[1] === 'function') {
[url, success, error, dataType] = args;
} else {
[url, data, success, error, dataType] = args;
}
[success, error].forEach((callback) => {
if (typeof callback === 'string') {
dataType = callback;
if (callback === success) success = undefined;
else error = undefined;
}
});
dataType = dataType || (method === 'json' || method === 'postJSON' ? 'json' : undefined);
const requestOptions = {
url,
method: method === 'post' || method === 'postJSON' ? 'POST' : 'GET',
data,
success,
error,
dataType,
};
if (method === 'postJSON') {
Utils.extend(requestOptions, {
contentType: 'application/json',
processData: false,
crossDomain: true,
data: typeof data === 'string' ? data : JSON.stringify(data),
});
}
return Request$1(requestOptions);
}
Request$1.get = function get(...args) {
return RequestShortcut('get', ...args);
};
Request$1.post = function post(...args) {
return RequestShortcut('post', ...args);
};
Request$1.json = function json(...args) {
return RequestShortcut('json', ...args);
};
Request$1.getJSON = Request$1.json;
Request$1.postJSON = function postJSON(...args) {
return RequestShortcut('postJSON', ...args);
};
Request$1.setup = function setup(options) {
if (options.type && !options.method) {
Utils.extend(options, { method: options.type });
}
Utils.extend(globals, options);
};
/* eslint no-param-reassign: "off" */
var Request = {
name: 'request',
proto: {
request: Request$1,
},
static: {
request: Request$1,
},
};
function initTouch() {
const app = this;
const params = app.params.touch;
const useRipple = app.theme === 'md' && params.materialRipple;
if (Device.ios && Device.webView) {
// Strange hack required for iOS 8 webview to work on inputs
window.addEventListener('touchstart', () => {});
}
let touchStartX;
let touchStartY;
let touchStartTime;
let targetElement;
let trackClick;
let activeSelection;
let scrollParent;
let lastClickTime;
let isMoved;
let tapHoldFired;
let tapHoldTimeout;
let activableElement;
let activeTimeout;
let needsFastClick;
let needsFastClickTimeOut;
let rippleWave;
let rippleTarget;
let rippleTimeout;
function findActivableElement(el) {
const target = $(el);
const parents = target.parents(params.activeStateElements);
let activable;
if (target.is(params.activeStateElements)) {
activable = target;
}
if (parents.length > 0) {
activable = activable ? activable.add(parents) : parents;
}
return activable || target;
}
function isInsideScrollableView(el) {
const pageContent = el.parents('.page-content, .panel');
if (pageContent.length === 0) {
return false;
}
// This event handler covers the "tap to stop scrolling".
if (pageContent.prop('scrollHandlerSet') !== 'yes') {
pageContent.on('scroll', () => {
clearTimeout(activeTimeout);
clearTimeout(rippleTimeout);
});
pageContent.prop('scrollHandlerSet', 'yes');
}
return true;
}
function addActive() {
if (!activableElement) return;
activableElement.addClass('active-state');
}
function removeActive() {
if (!activableElement) return;
activableElement.removeClass('active-state');
activableElement = null;
}
function isFormElement(el) {
const nodes = ('input select textarea label').split(' ');
if (el.nodeName && nodes.indexOf(el.nodeName.toLowerCase()) >= 0) return true;
return false;
}
function androidNeedsBlur(el) {
const noBlur = ('button input textarea select').split(' ');
if (document.activeElement && el !== document.activeElement && document.activeElement !== document.body) {
if (noBlur.indexOf(el.nodeName.toLowerCase()) >= 0) {
return false;
}
return true;
}
return false;
}
function targetNeedsFastClick(el) {
/*
if (
Device.ios
&&
(
Device.osVersion.split('.')[0] > 9
||
(Device.osVersion.split('.')[0] * 1 === 9 && Device.osVersion.split('.')[1] >= 1)
)
) {
return false;
}
*/
const $el = $(el);
if (el.nodeName.toLowerCase() === 'input' && (el.type === 'file' || el.type === 'range')) return false;
if (el.nodeName.toLowerCase() === 'select' && Device.android) return false;
if ($el.hasClass('no-fastclick') || $el.parents('.no-fastclick').length > 0) return false;
if (params.fastClicksExclude && $el.is(params.fastClicksExclude)) return false;
return true;
}
function targetNeedsFocus(el) {
if (document.activeElement === el) {
return false;
}
const tag = el.nodeName.toLowerCase();
const skipInputs = ('button checkbox file image radio submit').split(' ');
if (el.disabled || el.readOnly) return false;
if (tag === 'textarea') return true;
if (tag === 'select') {
if (Device.android) return false;
return true;
}
if (tag === 'input' && skipInputs.indexOf(el.type) < 0) return true;
return false;
}
function targetNeedsPrevent(el) {
const $el = $(el);
let prevent = true;
if ($el.is('label') || $el.parents('label').length > 0) {
if (Device.android) {
prevent = false;
} else if (Device.ios && $el.is('input')) {
prevent = true;
} else prevent = false;
}
return prevent;
}
// Ripple handlers
function findRippleElement(el) {
const rippleElements = params.materialRippleElements;
const $el = $(el);
if ($el.is(rippleElements)) {
if ($el.hasClass('no-ripple')) {
return false;
}
return $el;
} else if ($el.parents(rippleElements).length > 0) {
const rippleParent = $el.parents(rippleElements).eq(0);
if (rippleParent.hasClass('no-ripple')) {
return false;
}
return rippleParent;
}
return false;
}
function createRipple($el, x, y) {
if (!$el) return;
rippleWave = app.touchRipple.create($el, x, y);
}
function removeRipple() {
if (!rippleWave) return;
rippleWave.remove();
rippleWave = undefined;
rippleTarget = undefined;
}
function rippleTouchStart(el) {
rippleTarget = findRippleElement(el);
if (!rippleTarget || rippleTarget.length === 0) {
rippleTarget = undefined;
return;
}
if (!isInsideScrollableView(rippleTarget)) {
createRipple(rippleTarget, touchStartX, touchStartY);
} else {
rippleTimeout = setTimeout(() => {
createRipple(rippleTarget, touchStartX, touchStartY);
}, 80);
}
}
function rippleTouchMove() {
clearTimeout(rippleTimeout);
removeRipple();
}
function rippleTouchEnd() {
if (rippleWave) {
removeRipple();
} else if (rippleTarget && !isMoved) {
clearTimeout(rippleTimeout);
createRipple(rippleTarget, touchStartX, touchStartY);
setTimeout(removeRipple, 0);
} else {
removeRipple();
}
}
// Mouse Handlers
function handleMouseDown(e) {
findActivableElement(e.target).addClass('active-state');
if ('which' in e && e.which === 3) {
setTimeout(() => {
$('.active-state').removeClass('active-state');
}, 0);
}
if (useRipple) {
touchStartX = e.pageX;
touchStartY = e.pageY;
rippleTouchStart(e.target, e.pageX, e.pageY);
}
}
function handleMouseMove() {
$('.active-state').removeClass('active-state');
if (useRipple) {
rippleTouchMove();
}
}
function handleMouseUp() {
$('.active-state').removeClass('active-state');
if (useRipple) {
rippleTouchEnd();
}
}
// Send Click
function sendClick(e) {
const touch = e.changedTouches[0];
const evt = document.createEvent('MouseEvents');
let eventType = 'click';
if (Device.android && targetElement.nodeName.toLowerCase() === 'select') {
eventType = 'mousedown';
}
evt.initMouseEvent(eventType, true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
evt.forwardedTouchEvent = true;
if (app.device.ios && window.navigator.standalone) {
// Fix the issue happens in iOS home screen apps where the wrong element is selected during a momentum scroll.
// Upon tapping, we give the scrolling time to stop, then we grab the element based where the user tapped.
setTimeout(() => {
targetElement = document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
targetElement.dispatchEvent(evt);
}, 10);
} else {
targetElement.dispatchEvent(evt);
}
}
// Touch Handlers
function handleTouchStart(e) {
isMoved = false;
tapHoldFired = false;
if (e.targetTouches.length > 1) {
if (activableElement) removeActive();
return true;
}
if (e.touches.length > 1 && activableElement) {
removeActive();
}
if (params.tapHold) {
if (tapHoldTimeout) clearTimeout(tapHoldTimeout);
tapHoldTimeout = setTimeout(() => {
if (e && e.touches && e.touches.length > 1) return;
tapHoldFired = true;
e.preventDefault();
$(e.target).trigger('taphold');
}, params.tapHoldDelay);
}
if (needsFastClickTimeOut) clearTimeout(needsFastClickTimeOut);
needsFastClick = targetNeedsFastClick(e.target);
if (!needsFastClick) {
trackClick = false;
return true;
}
if (Device.ios || (Device.android && 'getSelection' in window)) {
const selection = window.getSelection();
if (
selection.rangeCount &&
selection.focusNode !== document.body &&
(!selection.isCollapsed || document.activeElement === selection.focusNode)
) {
activeSelection = true;
return true;
}
activeSelection = false;
}
if (Device.android) {
if (androidNeedsBlur(e.target)) {
document.activeElement.blur();
}
}
trackClick = true;
targetElement = e.target;
touchStartTime = (new Date()).getTime();
touchStartX = e.targetTouches[0].pageX;
touchStartY = e.targetTouches[0].pageY;
// Detect scroll parent
if (Device.ios) {
scrollParent = undefined;
$(targetElement).parents().each(() => {
const parent = this;
if (parent.scrollHeight > parent.offsetHeight && !scrollParent) {
scrollParent = parent;
scrollParent.f7ScrollTop = scrollParent.scrollTop;
}
});
}
if ((e.timeStamp - lastClickTime) < params.fastClicksDelayBetweenClicks) {
e.preventDefault();
}
if (params.activeState) {
activableElement = findActivableElement(targetElement);
// If it's inside a scrollable view, we don't trigger active-state yet,
// because it can be a scroll instead. Based on the link:
// http://labnote.beedesk.com/click-scroll-and-pseudo-active-on-mobile-webk
if (!isInsideScrollableView(activableElement)) {
addActive();
} else {
activeTimeout = setTimeout(addActive, 80);
}
}
if (useRipple) {
rippleTouchStart(targetElement, touchStartX, touchStartY);
}
return true;
}
function handleTouchMove(e) {
if (!trackClick) return;
const distance = params.fastClicksDistanceThreshold;
if (distance) {
const pageX = e.targetTouches[0].pageX;
const pageY = e.targetTouches[0].pageY;
if (Math.abs(pageX - touchStartX) > distance || Math.abs(pageY - touchStartY) > distance) {
isMoved = true;
}
} else {
isMoved = true;
}
if (isMoved) {
trackClick = false;
targetElement = null;
isMoved = true;
if (params.tapHold) {
clearTimeout(tapHoldTimeout);
}
if (params.activeState) {
clearTimeout(activeTimeout);
removeActive();
}
if (useRipple) {
rippleTouchMove();
}
}
}
function handleTouchEnd(e) {
clearTimeout(activeTimeout);
clearTimeout(tapHoldTimeout);
if (!trackClick) {
if (!activeSelection && needsFastClick) {
if (!(Device.android && !e.cancelable) && e.cancelable) {
e.preventDefault();
}
}
return true;
}
if (document.activeElement === e.target) {
if (params.activeState) removeActive();
if (useRipple) {
rippleTouchEnd();
}
return true;
}
if (!activeSelection) {
e.preventDefault();
}
if ((e.timeStamp - lastClickTime) < params.fastClicksDelayBetweenClicks) {
setTimeout(removeActive, 0);
return true;
}
lastClickTime = e.timeStamp;
trackClick = false;
if (Device.ios && scrollParent) {
if (scrollParent.scrollTop !== scrollParent.f7ScrollTop) {
return false;
}
}
// Add active-state here because, in a very fast tap, the timeout didn't
// have the chance to execute. Removing active-state in a timeout gives
// the chance to the animation execute.
if (params.activeState) {
addActive();
setTimeout(removeActive, 0);
}
// Remove Ripple
if (useRipple) {
rippleTouchEnd();
}
// Trigger focus when required
if (targetNeedsFocus(targetElement)) {
if (Device.ios && Device.webView) {
if ((e.timeStamp - touchStartTime) > 159) {
targetElement = null;
return false;
}
targetElement.focus();
return false;
}
targetElement.focus();
}
// Blur active elements
if (document.activeElement && targetElement !== document.activeElement && document.activeElement !== document.body && targetElement.nodeName.toLowerCase() !== 'label') {
document.activeElement.blur();
}
// Send click
e.preventDefault();
sendClick(e);
return false;
}
function handleTouchCancel() {
trackClick = false;
targetElement = null;
// Remove Active State
clearTimeout(activeTimeout);
clearTimeout(tapHoldTimeout);
if (params.activeState) {
removeActive();
}
// Remove Ripple
if (useRipple) {
rippleTouchEnd();
}
}
function handleClick(e) {
let allowClick = false;
if (trackClick) {
targetElement = null;
trackClick = false;
return true;
}
if ((e.target.type === 'submit' && e.detail === 0) || e.target.type === 'file') {
return true;
}
if (!targetElement) {
if (!isFormElement(e.target)) {
allowClick = true;
}
}
if (!needsFastClick) {
allowClick = true;
}
if (document.activeElement === targetElement) {
allowClick = true;
}
if (e.forwardedTouchEvent) {
allowClick = true;
}
if (!e.cancelable) {
allowClick = true;
}
if (params.tapHold && params.tapHoldPreventClicks && tapHoldFired) {
allowClick = false;
}
if (!allowClick) {
e.stopImmediatePropagation();
e.stopPropagation();
if (targetElement) {
if (targetNeedsPrevent(targetElement) || isMoved) {
e.preventDefault();
}
} else {
e.preventDefault();
}
targetElement = null;
}
needsFastClickTimeOut = setTimeout(() => {
needsFastClick = false;
}, (Device.ios || Device.androidChrome ? 100 : 400));
if (params.tapHold) {
tapHoldTimeout = setTimeout(() => {
tapHoldFired = false;
}, (Device.ios || Device.androidChrome ? 100 : 400));
}
return allowClick;
}
function emitAppTouchEvent(name, e) {
app.emit({
events: name,
data: [e],
});
}
function appClick(e) {
emitAppTouchEvent('click', e);
}
function appTouchStartActive(e) {
emitAppTouchEvent('touchstart touchstart:active', e);
}
function appTouchMoveActive(e) {
emitAppTouchEvent('touchmove touchmove:active', e);
}
function appTouchEndActive(e) {
emitAppTouchEvent('touchend touchend:active', e);
}
function appTouchStartPassive(e) {
emitAppTouchEvent('touchstart:passive', e);
}
function appTouchMovePassive(e) {
emitAppTouchEvent('touchmove:passive', e);
}
function appTouchEndPassive(e) {
emitAppTouchEvent('touchend:passive', e);
}
const passiveListener = Support$1.passiveListener ? { passive: true } : false;
const activeListener = Support$1.passiveListener ? { passive: false } : false;
document.addEventListener('click', appClick, true);
if (Support$1.passiveListener) {
document.addEventListener(app.touchEvents.start, appTouchStartActive, activeListener);
document.addEventListener(app.touchEvents.move, appTouchMoveActive, activeListener);
document.addEventListener(app.touchEvents.end, appTouchEndActive, activeListener);
document.addEventListener(app.touchEvents.start, appTouchStartPassive, passiveListener);
document.addEventListener(app.touchEvents.move, appTouchMovePassive, passiveListener);
document.addEventListener(app.touchEvents.end, appTouchEndPassive, passiveListener);
} else {
document.addEventListener(app.touchEvents.start, (e) => {
appTouchStartActive(e);
appTouchStartPassive(e);
}, false);
document.addEventListener(app.touchEvents.move, (e) => {
appTouchMoveActive(e);
appTouchMovePassive(e);
}, false);
document.addEventListener(app.touchEvents.end, (e) => {
appTouchEndActive(e);
appTouchEndPassive(e);
}, false);
}
if (Support$1.touch) {
app.on('click', handleClick);
app.on('touchstart', handleTouchStart);
app.on('touchmove', handleTouchMove);
app.on('touchend', handleTouchEnd);
document.addEventListener('touchcancel', handleTouchCancel, { passive: true });
} else if (params.activeState) {
app.on('touchstart', handleMouseDown);
app.on('touchmove', handleMouseMove);
app.on('touchend', handleMouseUp);
}
document.addEventListener('contextmenu', (e) => {
if (params.disableContextMenu && (Device.ios || Device.android || Device.cordova)) {
e.preventDefault();
}
if (useRipple) {
if (activableElement) removeActive();
rippleTouchEnd();
}
});
}
var Touch = {
name: 'touch',
params: {
touch: {
// Fast clicks
fastClicks: true,
fastClicksDistanceThreshold: 10,
fastClicksDelayBetweenClicks: 50,
fastClicksExclude: '', // CSS selector
// ContextMenu
disableContextMenu: true,
// Tap Hold
tapHold: false,
tapHoldDelay: 750,
tapHoldPreventClicks: true,
// Active State
activeState: true,
activeStateElements: 'a, button, label, span, .actions-button',
materialRipple: true,
materialRippleElements: '.ripple, .link, .item-link, .links-list a, .button, button, .input-clear-button, .dialog-button, .tab-link, .item-radio, .item-checkbox, .actions-button, .searchbar-disable-button, .fab a, .checkbox, .radio, .data-table .sortable-cell, .notification-close-button',
},
},
instance: {
touchEvents: {
start: Support$1.touch ? 'touchstart' : 'mousedown',
move: Support$1.touch ? 'touchmove' : 'mousemove',
end: Support$1.touch ? 'touchend' : 'mouseup',
},
},
on: {
init: initTouch,
},
};
const tempDom = document.createElement('div');
class Framework7Component {
constructor(c, extendContext = {}) {
const context = Utils.extend({}, extendContext);
let component = Utils.extend(this, c, { context });
// Apply context
('beforeCreate created beforeMount mounted beforeDestroy destroyed').split(' ').forEach((cycleKey) => {
if (component[cycleKey]) component[cycleKey] = component[cycleKey].bind(context);
});
if (component.data) {
component.data = component.data.bind(context);
// Data
Utils.extend(context, component.data());
}
if (component.render) component.render = component.render.bind(context);
if (component.methods) {
Object.keys(component.methods).forEach((methodName) => {
context[methodName] = component.methods[methodName].bind(context);
});
}
// Bind Events
if (component.on) {
Object.keys(component.on).forEach((eventName) => {
component.on[eventName] = component.on[eventName].bind(context);
});
}
if (component.once) {
Object.keys(component.once).forEach((eventName) => {
component.once[eventName] = component.once[eventName].bind(context);
});
}
if (component.beforeCreate) component.beforeCreate();
// Watchers
if (component.watch) {
Object.keys(component.watch).forEach((watchKey) => {
let dataKeyValue = component.context[watchKey];
Object.defineProperty(component.context, watchKey, {
enumerable: true,
configurable: true,
set(newValue) {
dataKeyValue = newValue;
component.watch[watchKey].call(context, dataKeyValue);
},
get() {
return dataKeyValue;
},
});
});
}
// Render template
let html = '';
if (component.render) {
html = component.render();
} else if (component.template) {
if (typeof component.template === 'string') {
try {
html = Template7.compile(component.template)(context);
} catch (err) {
throw err;
}
} else {
// Supposed to be function
html = component.template(context);
}
}
// Make Dom
if (html && typeof html === 'string') {
html = html.trim();
tempDom.innerHTML = html;
} else if (html) {
tempDom.innerHTML = '';
tempDom.appendChild(html);
}
// Extend context with $el
const el = tempDom.children[0];
const $el = $(el);
context.$el = $el;
context.el = el;
component.el = el;
// Find Events
const events = [];
$(tempDom).find('*').each((index, element) => {
const attrs = [];
for (let i = 0; i < element.attributes.length; i += 1) {
const attr = element.attributes[i];
if (attr.name.indexOf('@') === 0) {
attrs.push({
name: attr.name,
value: attr.value,
});
}
}
attrs.forEach((attr) => {
element.removeAttribute(attr.name);
const event = attr.name.replace('@', '');
let name = event;
let stop = false;
let prevent = false;
let once = false;
if (event.indexOf('.') >= 0) {
event.split('.').forEach((eventNamePart, eventNameIndex) => {
if (eventNameIndex === 0) name = eventNamePart;
else {
if (eventNamePart === 'stop') stop = true;
if (eventNamePart === 'prevent') prevent = true;
if (eventNamePart === 'once') once = true;
}
});
}
const value = attr.value.toString();
events.push({
el: element,
name,
once,
handler(...args) {
const e = args[0];
if (stop) e.stopPropagation();
if (prevent) e.preventDefault();
let methodName;
let method;
let customArgs = [];
if (value.indexOf('(') < 0) {
customArgs = args;
methodName = value;
} else {
methodName = value.split('(')[0];
value.split('(')[1].split(')')[0].split(',').forEach((argument) => {
let arg = argument.trim();
// eslint-disable-next-line
if (!isNaN(arg)) arg = parseFloat(arg);
else if (arg === 'true') arg = true;
else if (arg === 'false') arg = false;
else if (arg === 'null') arg = null;
else if (arg === 'undefined') arg = undefined;
else if (arg[0] === '"') arg = arg.replace(/"/g, '');
else if (arg[0] === '\'') arg = arg.replace(/'/g, '');
else if (arg.indexOf('.') > 0) {
let deepArg;
arg.split('.').forEach((path) => {
if (!deepArg) deepArg = context;
deepArg = deepArg[path];
});
arg = deepArg;
} else {
arg = context[arg];
}
customArgs.push(arg);
});
}
if (methodName.indexOf('.') >= 0) {
methodName.split('.').forEach((path, pathIndex) => {
if (!method) method = context;
if (method[path]) method = method[path];
else {
throw new Error(`Component doesn't have method "${methodName.split('.').slice(0, pathIndex + 1).join('.')}"`);
}
});
} else {
if (!context[methodName]) {
throw new Error(`Component doesn't have method "${methodName}"`);
}
method = context[methodName];
}
method(...customArgs);
},
});
});
});
// Set styles scope ID
let styleEl;
if (component.style) {
styleEl = document.createElement('style');
styleEl.innerHTML = component.style;
}
if (component.styleScopeId) {
el.setAttribute('data-scope', component.styleScopeId);
}
// Attach events
function attachEvents() {
if (component.on) {
Object.keys(component.on).forEach((eventName) => {
$el.on(Utils.eventNameToColonCase(eventName), component.on[eventName]);
});
}
if (component.once) {
Object.keys(component.once).forEach((eventName) => {
$el.once(Utils.eventNameToColonCase(eventName), component.once[eventName]);
});
}
events.forEach((event) => {
$(event.el)[event.once ? 'once' : 'on'](event.name, event.handler);
});
}
function detachEvents() {
if (component.on) {
Object.keys(component.on).forEach((eventName) => {
$el.off(Utils.eventNameToColonCase(eventName), component.on[eventName]);
});
}
if (component.once) {
Object.keys(component.once).forEach((eventName) => {
$el.off(Utils.eventNameToColonCase(eventName), component.once[eventName]);
});
}
events.forEach((event) => {
$(event.el).off(event.name, event.handler);
});
}
attachEvents();
// Created callback
if (component.created) component.created();
// Mount
component.mount = function mount(mountMethod) {
if (component.beforeMount) component.beforeMount();
if (styleEl) $('head').append(styleEl);
if (mountMethod) mountMethod(el);
if (component.mounted) component.mounted();
};
// Destroy
component.destroy = function destroy() {
if (component.beforeDestroy) component.beforeDestroy();
if (styleEl) $(styleEl).remove();
detachEvents();
if (component.destroyed) component.destroyed();
// Store component instance
if (el && el.f7Component) {
el.f7Component = null;
delete el.f7Component;
}
component = null;
};
// Store component instance
for (let i = 0; i < tempDom.children.length; i += 1) {
tempDom.children[i].f7Component = component;
}
return component;
}
}
const Component = {
parse(componentString) {
const callbackName = `f7_component_callback_${new Date().getTime()}`;
// Template
let template;
if (componentString.indexOf('<template>') >= 0) {
template = componentString
.split('<template>')
.filter((item, index) => index > 0)
.join('<template>')
.split('</template>')
.filter((item, index, arr) => index < arr.length - 1)
.join('</template>')
.replace(/{{#raw}}([ \n]*)<template/g, '{{#raw}}<template')
.replace(/\/template>([ \n]*){{\/raw}}/g, '/template>{{/raw}}')
.replace(/([ \n])<template/g, '$1{{#raw}}<template')
.replace(/\/template>([ \n])/g, '/template>{{/raw}}$1');
}
// Styles
let style;
const styleScopeId = Utils.now();
if (componentString.indexOf('<style>') >= 0) {
style = componentString.split('<style>')[1].split('</style>')[0];
} else if (componentString.indexOf('<style scoped>') >= 0) {
style = componentString.split('<style scoped>')[1].split('</style>')[0];
style = style.split('\n').map((line) => {
if (line.indexOf('{') >= 0) {
if (line.indexOf('{{this}}') >= 0) {
return line.replace('{{this}}', `[data-scope="${styleScopeId}"]`);
}
return `[data-scope="${styleScopeId}"] ${line.trim()}`;
}
return line;
}).join('\n');
}
let scriptContent;
if (componentString.indexOf('<script>') >= 0) {
const scripts = componentString.split('<script>');
scriptContent = scripts[scripts.length - 1].split('</script>')[0].trim();
} else {
scriptContent = 'return {}';
}
scriptContent = `window.${callbackName} = function () {${scriptContent}}`;
// Insert Script El
const scriptEl = document.createElement('script');
scriptEl.innerHTML = scriptContent;
$('head').append(scriptEl);
const component = window[callbackName]();
// Remove Script El
$(scriptEl).remove();
if (!component.template && !component.render) {
component.template = template;
}
if (style) {
component.style = style;
component.styleScopeId = styleScopeId;
}
return component;
},
create(c, extendContext = {}) {
return new Framework7Component(c, extendContext);
},
};
const History = {
queue: [],
clearQueue() {
if (History.queue.length === 0) return;
const currentQueue = History.queue.shift();
currentQueue();
},
routerQueue: [],
clearRouterQueue() {
if (History.routerQueue.length === 0) return;
const currentQueue = History.routerQueue.pop();
const { router, stateUrl, action } = currentQueue;
let animate = router.params.animate;
if (router.params.pushStateAnimate === false) animate = false;
if (action === 'back') {
router.back({ animate, pushState: false });
}
if (action === 'load') {
router.navigate(stateUrl, { animate, pushState: false });
}
},
handle(e) {
if (History.blockPopstate) return;
const app = this;
// const mainView = app.views.main;
let state = e.state;
History.previousState = History.state;
History.state = state;
History.allowChange = true;
History.clearQueue();
state = History.state;
if (!state) state = {};
app.views.forEach((view) => {
const router = view.router;
let viewState = state[view.id];
if (!viewState && view.params.pushState) {
viewState = {
url: view.router.history[0],
};
}
if (!viewState) return;
const stateUrl = viewState.url || undefined;
let animate = router.params.animate;
if (router.params.pushStateAnimate === false) animate = false;
if (stateUrl !== router.url) {
if (router.history.indexOf(stateUrl) >= 0) {
// Go Back
if (router.allowPageChange) {
router.back({ animate, pushState: false });
} else {
History.routerQueue.push({
action: 'back',
router,
});
}
} else if (router.allowPageChange) {
// Load page
router.navigate(stateUrl, { animate, pushState: false });
} else {
History.routerQueue.unshift({
action: 'load',
stateUrl,
router,
});
}
}
});
},
push(viewId, viewState, url) {
if (!History.allowChange) {
History.queue.push(() => {
History.push(viewId, viewState, url);
});
return;
}
History.previousState = History.state;
const newState = Utils.extend({}, (History.previousState || {}), {
[viewId]: viewState,
});
History.state = newState;
window.history.pushState(newState, '', url);
},
replace(viewId, viewState, url) {
if (!History.allowChange) {
History.queue.push(() => {
History.replace(viewId, viewState, url);
});
return;
}
History.previousState = History.state;
const newState = Utils.extend({}, (History.previousState || {}), {
[viewId]: viewState,
});
History.state = newState;
window.history.replaceState(newState, '', url);
},
go(index) {
History.allowChange = false;
window.history.go(index);
},
back() {
History.allowChange = false;
window.history.back();
},
allowChange: true,
previousState: {},
state: window.history.state,
blockPopstate: true,
init(app) {
$(window).on('load', () => {
setTimeout(() => {
History.blockPopstate = false;
}, 0);
});
if (document.readyState && document.readyState === 'complete') {
History.blockPopstate = false;
}
$(window).on('popstate', History.handle.bind(app));
},
};
function SwipeBack(r) {
const router = r;
const { $el, $navbarEl, app } = router;
let isTouched = false;
let isMoved = false;
const touchesStart = {};
let isScrolling;
let currentPage = [];
let previousPage = [];
let viewContainerWidth;
let touchesDiff;
let allowViewTouchMove = true;
let touchStartTime;
let currentNavbar = [];
let previousNavbar = [];
let currentNavElements;
let previousNavElements;
let activeNavBackIcon;
let activeNavBackIconText;
let previousNavBackIcon;
// let previousNavBackIconText;
let dynamicNavbar;
let separateNavbar;
let pageShadow;
let pageOpacity;
let navbarWidth;
function handleTouchStart(e) {
if (!allowViewTouchMove || !router.params.iosSwipeBack || isTouched || (app.swipeout && app.swipeout.el) || !router.allowPageChange) return;
if ($(e.target).closest('.range-slider, .calendar-months').length > 0) return;
isMoved = false;
isTouched = true;
isScrolling = undefined;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchStartTime = Utils.now();
dynamicNavbar = router.dynamicNavbar;
separateNavbar = router.separateNavbar;
}
function handleTouchMove(e) {
if (!isTouched) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x)) || pageX < touchesStart.x;
}
if (isScrolling || e.f7PreventSwipeBack || app.preventSwipeBack) {
isTouched = false;
return;
}
if (!isMoved) {
// Calc values during first move fired
let cancel = false;
const target = $(e.target);
const swipeout = target.closest('.swipeout');
if (swipeout.length > 0) {
if (!app.rtl && swipeout.find('.swipeout-actions-left').length > 0) cancel = true;
if (app.rtl && swipeout.find('.swipeout-actions-right').length > 0) cancel = true;
}
currentPage = target.closest('.page');
if (currentPage.hasClass('no-swipeback') || target.closest('.no-swipeback').length > 0) cancel = true;
previousPage = $el.find('.page-previous:not(.stacked)');
let notFromBorder = touchesStart.x - $el.offset().left > router.params.iosSwipeBackActiveArea;
viewContainerWidth = $el.width();
if (app.rtl) {
notFromBorder = touchesStart.x < ($el.offset().left - $el[0].scrollLeft) + (viewContainerWidth - router.params.iosSwipeBackActiveArea);
} else {
notFromBorder = touchesStart.x - $el.offset().left > router.params.iosSwipeBackActiveArea;
}
if (notFromBorder) cancel = true;
if (previousPage.length === 0 || currentPage.length === 0) cancel = true;
if (cancel) {
isTouched = false;
return;
}
if (router.params.iosSwipeBackAnimateShadow) {
pageShadow = currentPage.find('.page-shadow-effect');
if (pageShadow.length === 0) {
pageShadow = $('<div class="page-shadow-effect"></div>');
currentPage.append(pageShadow);
}
}
if (router.params.iosSwipeBackAnimateOpacity) {
pageOpacity = previousPage.find('.page-opacity-effect');
if (pageOpacity.length === 0) {
pageOpacity = $('<div class="page-opacity-effect"></div>');
previousPage.append(pageOpacity);
}
}
if (dynamicNavbar) {
if (separateNavbar) {
currentNavbar = $navbarEl.find('.navbar-current:not(.stacked)');
previousNavbar = $navbarEl.find('.navbar-previous:not(.stacked)');
} else {
currentNavbar = currentPage.children('.navbar').children('.navbar-inner');
previousNavbar = previousPage.children('.navbar').children('.navbar-inner');
}
navbarWidth = $navbarEl[0].offsetWidth;
currentNavElements = currentNavbar.children('.left, .title, .right, .subnavbar, .fading');
previousNavElements = previousNavbar.children('.left, .title, .right, .subnavbar, .fading');
if (router.params.iosAnimateNavbarBackIcon) {
if (currentNavbar.hasClass('sliding')) {
activeNavBackIcon = currentNavbar.children('.left').find('.back .icon');
activeNavBackIconText = currentNavbar.children('.left').find('.back span').eq(0);
} else {
activeNavBackIcon = currentNavbar.children('.left.sliding').find('.back .icon');
activeNavBackIconText = currentNavbar.children('.left.sliding').find('.back span').eq(0);
}
if (previousNavbar.hasClass('sliding')) {
previousNavBackIcon = previousNavbar.children('.left').find('.back .icon');
// previousNavBackIconText = previousNavbar.children('left').find('.back span').eq(0);
} else {
previousNavBackIcon = previousNavbar.children('.left.sliding').find('.back .icon');
// previousNavBackIconText = previousNavbar.children('.left.sliding').find('.back span').eq(0);
}
}
}
// Close/Hide Any Picker
if ($('.sheet.modal-in').length > 0 && app.sheet) {
app.sheet.close($('.sheet.modal-in'));
}
}
e.f7PreventPanelSwipe = true;
isMoved = true;
app.preventSwipePanelBySwipeBack = true;
e.preventDefault();
// RTL inverter
const inverter = app.rtl ? -1 : 1;
// Touches diff
touchesDiff = (pageX - touchesStart.x - router.params.iosSwipeBackThreshold) * inverter;
if (touchesDiff < 0) touchesDiff = 0;
const percentage = touchesDiff / viewContainerWidth;
// Swipe Back Callback
const callbackData = {
percentage,
currentPageEl: currentPage[0],
previousPageEl: previousPage[0],
currentNavbarEl: currentNavbar[0],
previousNavbarEl: previousNavbar[0],
};
$el.trigger('swipeback:move', callbackData);
router.emit('swipebackMove', callbackData);
// Transform pages
let currentPageTranslate = touchesDiff * inverter;
let previousPageTranslate = ((touchesDiff / 5) - (viewContainerWidth / 5)) * inverter;
if (Device.pixelRatio === 1) {
currentPageTranslate = Math.round(currentPageTranslate);
previousPageTranslate = Math.round(previousPageTranslate);
}
currentPage.transform(`translate3d(${currentPageTranslate}px,0,0)`);
if (router.params.iosSwipeBackAnimateShadow) pageShadow[0].style.opacity = 1 - (1 * percentage);
previousPage.transform(`translate3d(${previousPageTranslate}px,0,0)`);
if (router.params.iosSwipeBackAnimateOpacity) pageOpacity[0].style.opacity = 1 - (1 * percentage);
// Dynamic Navbars Animation
if (dynamicNavbar) {
currentNavElements.each((index, navEl) => {
const $navEl = $(navEl);
if (!$navEl.is('.subnavbar')) $navEl[0].style.opacity = (1 - (percentage ** 0.33));
if ($navEl[0].className.indexOf('sliding') >= 0 || currentNavbar.hasClass('sliding')) {
let activeNavTranslate = percentage * $navEl[0].f7NavbarRightOffset;
if (Device.pixelRatio === 1) activeNavTranslate = Math.round(activeNavTranslate);
$navEl.transform(`translate3d(${activeNavTranslate}px,0,0)`);
if (router.params.iosAnimateNavbarBackIcon) {
if ($navEl[0].className.indexOf('left') >= 0 && activeNavBackIcon.length > 0) {
let iconTranslate = -activeNavTranslate;
if (!separateNavbar) {
iconTranslate -= navbarWidth * percentage;
}
activeNavBackIcon.transform(`translate3d(${iconTranslate}px,0,0)`);
}
}
}
});
previousNavElements.each((index, navEl) => {
const $navEl = $(navEl);
if (!$navEl.is('.subnavbar')) $navEl[0].style.opacity = (percentage ** 3);
if ($navEl[0].className.indexOf('sliding') >= 0 || previousNavbar.hasClass('sliding')) {
let previousNavTranslate = $navEl[0].f7NavbarLeftOffset * (1 - percentage);
if ($navEl[0].className.indexOf('title') >= 0 && activeNavBackIcon && activeNavBackIcon.length && activeNavBackIconText.length) {
previousNavTranslate = ($navEl[0].f7NavbarLeftOffset + activeNavBackIconText[0].offsetLeft) * (1 - percentage);
} else {
previousNavTranslate = $navEl[0].f7NavbarLeftOffset * (1 - percentage);
}
if (Device.pixelRatio === 1) previousNavTranslate = Math.round(previousNavTranslate);
$navEl.transform(`translate3d(${previousNavTranslate}px,0,0)`);
if (router.params.iosAnimateNavbarBackIcon) {
if ($navEl[0].className.indexOf('left') >= 0 && previousNavBackIcon.length > 0) {
let iconTranslate = -previousNavTranslate;
if (!separateNavbar) {
iconTranslate += (navbarWidth / 5) * (1 - percentage);
}
previousNavBackIcon.transform(`translate3d(${iconTranslate}px,0,0)`);
}
}
}
});
}
}
function handleTouchEnd() {
app.preventSwipePanelBySwipeBack = false;
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
if (touchesDiff === 0) {
$([currentPage[0], previousPage[0]]).transform('');
if (dynamicNavbar) {
currentNavElements.transform('').css({ opacity: '' });
previousNavElements.transform('').css({ opacity: '' });
if (activeNavBackIcon && activeNavBackIcon.length > 0) activeNavBackIcon.transform('');
if (previousNavBackIcon && activeNavBackIcon.length > 0) previousNavBackIcon.transform('');
}
return;
}
const timeDiff = Utils.now() - touchStartTime;
let pageChanged = false;
// Swipe back to previous page
if (
(timeDiff < 300 && touchesDiff > 10) ||
(timeDiff >= 300 && touchesDiff > viewContainerWidth / 2)
) {
currentPage.removeClass('page-current').addClass('page-next');
previousPage.removeClass('page-previous').addClass('page-current');
if (pageShadow) pageShadow[0].style.opacity = '';
if (pageOpacity) pageOpacity[0].style.opacity = '';
if (dynamicNavbar) {
currentNavbar.removeClass('navbar-current').addClass('navbar-next');
previousNavbar.removeClass('navbar-previous').addClass('navbar-current');
}
pageChanged = true;
}
// Reset custom styles
// Add transitioning class for transition-duration
$([currentPage[0], previousPage[0]]).addClass('page-transitioning').transform('');
if (dynamicNavbar) {
currentNavElements.css({ opacity: '' })
.each((navElIndex, navEl) => {
const translate = pageChanged ? navEl.f7NavbarRightOffset : 0;
const sliding = $(navEl);
let iconTranslate = pageChanged ? -translate : 0;
if (!separateNavbar && pageChanged) iconTranslate -= navbarWidth;
sliding.transform(`translate3d(${translate}px,0,0)`);
if (router.params.iosAnimateNavbarBackIcon) {
if (sliding.hasClass('left') && activeNavBackIcon.length > 0) {
activeNavBackIcon.addClass('navbar-transitioning').transform(`translate3d(${iconTranslate}px,0,0)`);
}
}
}).addClass('navbar-transitioning');
previousNavElements.transform('').css({ opacity: '' }).each((navElIndex, navEl) => {
const translate = pageChanged ? 0 : navEl.f7NavbarLeftOffset;
const sliding = $(navEl);
let iconTranslate = pageChanged ? 0 : -translate;
if (!separateNavbar && !pageChanged) iconTranslate += navbarWidth / 5;
sliding.transform(`translate3d(${translate}px,0,0)`);
if (router.params.iosAnimateNavbarBackIcon) {
if (sliding.hasClass('left') && previousNavBackIcon.length > 0) {
previousNavBackIcon.addClass('navbar-transitioning').transform(`translate3d(${iconTranslate}px,0,0)`);
}
}
}).addClass('navbar-transitioning');
}
allowViewTouchMove = false;
router.allowPageChange = false;
// Swipe Back Callback
const callbackData = {
currentPage: currentPage[0],
previousPage: previousPage[0],
currentNavbar: currentNavbar[0],
previousNavbar: previousNavbar[0],
};
if (pageChanged) {
// Update Route
router.currentRoute = previousPage[0].f7Page.route;
router.currentPage = previousPage[0];
// Page before animation callback
router.pageCallback('beforeOut', currentPage, currentNavbar, 'current', 'next', { route: currentPage[0].f7Page.route });
router.pageCallback('beforeIn', previousPage, previousNavbar, 'previous', 'current', { route: previousPage[0].f7Page.route });
$el.trigger('swipeback:beforechange', callbackData);
router.emit('swipebackBeforeChange', callbackData);
} else {
$el.trigger('swipeback:beforereset', callbackData);
router.emit('swipebackBeforeReset', callbackData);
}
currentPage.transitionEnd(() => {
$([currentPage[0], previousPage[0]]).removeClass('page-transitioning');
if (dynamicNavbar) {
currentNavElements.removeClass('navbar-transitioning').css({ opacity: '' }).transform('');
previousNavElements.removeClass('navbar-transitioning').css({ opacity: '' }).transform('');
if (activeNavBackIcon && activeNavBackIcon.length > 0) activeNavBackIcon.removeClass('navbar-transitioning');
if (previousNavBackIcon && previousNavBackIcon.length > 0) previousNavBackIcon.removeClass('navbar-transitioning');
}
allowViewTouchMove = true;
router.allowPageChange = true;
if (pageChanged) {
// Update History
if (router.history.length === 1) {
router.history.unshift(router.url);
}
router.history.pop();
router.saveHistory();
// Update push state
if (router.params.pushState) {
History.back();
}
// Page after animation callback
router.pageCallback('afterOut', currentPage, currentNavbar, 'current', 'next', { route: currentPage[0].f7Page.route });
router.pageCallback('afterIn', previousPage, previousNavbar, 'previous', 'current', { route: previousPage[0].f7Page.route });
// Remove Old Page
if (router.params.stackPages && router.initialPages.indexOf(currentPage[0]) >= 0) {
currentPage.addClass('stacked');
if (separateNavbar) {
currentNavbar.addClass('stacked');
}
} else {
router.pageCallback('beforeRemove', currentPage, currentNavbar, 'next');
router.removePage(currentPage);
if (separateNavbar) {
router.removeNavbar(currentNavbar);
}
}
$el.trigger('swipeback:afterchange', callbackData);
router.emit('swipebackAfterChange', callbackData);
router.emit('routeChanged', router.currentRoute, router.previousRoute, router);
if (router.params.preloadPreviousPage) {
router.back(router.history[router.history.length - 2], { preload: true });
}
} else {
$el.trigger('swipeback:afterreset', callbackData);
router.emit('swipebackAfterReset', callbackData);
}
if (pageShadow && pageShadow.length > 0) pageShadow.remove();
if (pageOpacity && pageOpacity.length > 0) pageOpacity.remove();
});
}
function attachEvents() {
const passiveListener = (app.touchEvents.start === 'touchstart' && Support$1.passiveListener) ? { passive: true, capture: false } : false;
$el.on(app.touchEvents.start, handleTouchStart, passiveListener);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
}
function detachEvents() {
const passiveListener = (app.touchEvents.start === 'touchstart' && Support$1.passiveListener) ? { passive: true, capture: false } : false;
$el.off(app.touchEvents.start, handleTouchStart, passiveListener);
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
}
attachEvents();
router.on('routerDestroy', detachEvents);
}
var redirect = function (direction, route, options) {
const router = this;
const redirect = route.route.redirect;
function redirectResolve(redirectUrl, redirectOptions = {}) {
router.allowPageChange = true;
router[direction](redirectUrl, Utils.extend({}, options, redirectOptions));
}
function redirectReject() {
router.allowPageChange = true;
}
if (typeof redirect === 'function') {
router.allowPageChange = false;
const redirectUrl = redirect.call(router, route, redirectResolve, redirectReject);
if (redirectUrl && typeof redirectUrl === 'string') {
router.allowPageChange = true;
return router[direction](redirectUrl, options);
}
return router;
}
return router[direction](redirect, options);
};
function refreshPage() {
const router = this;
return router.navigate(router.currentRoute.url, {
ignoreCache: true,
reloadCurrent: true,
});
}
function forward(el, forwardOptions = {}) {
const router = this;
const app = router.app;
const view = router.view;
const options = Utils.extend({
animate: router.params.animate,
pushState: true,
history: true,
reloadCurrent: router.params.reloadPages,
reloadPrevious: false,
reloadAll: false,
on: {},
}, forwardOptions);
const dynamicNavbar = router.dynamicNavbar;
const separateNavbar = router.separateNavbar;
const $viewEl = router.$el;
const $newPage = $(el);
const reload = options.reloadPrevious || options.reloadCurrent || options.reloadAll;
let $oldPage;
let $navbarEl;
let $newNavbarInner;
let $oldNavbarInner;
if ($newPage.length) {
// Remove theme elements
router.removeThemeElements($newPage);
}
if (dynamicNavbar) {
$newNavbarInner = $newPage.children('.navbar').children('.navbar-inner');
if (separateNavbar) {
$navbarEl = router.$navbarEl;
if ($newNavbarInner.length > 0) {
$newPage.children('.navbar').remove();
}
if ($newNavbarInner.length === 0 && $newPage[0].f7Page) {
// Try from pageData
$newNavbarInner = $newPage[0].f7Page.$navbarEl;
}
}
}
router.allowPageChange = false;
if ($newPage.length === 0) {
router.allowPageChange = true;
return router;
}
// Pages In View
const $pagesInView = $viewEl
.children('.page:not(.stacked)')
.filter((index, pageInView) => pageInView !== $newPage[0]);
// Navbars In View
let $navbarsInView;
if (separateNavbar) {
$navbarsInView = $navbarEl
.children('.navbar-inner:not(.stacked)')
.filter((index, navbarInView) => navbarInView !== $newNavbarInner[0]);
}
// Exit when reload previous and only 1 page in view so nothing ro reload
if (options.reloadPrevious && $pagesInView.length < 2) {
router.allowPageChange = true;
return router;
}
// New Page
let newPagePosition = 'next';
if (options.reloadCurrent || options.reloadAll) {
newPagePosition = 'current';
} else if (options.reloadPrevious) {
newPagePosition = 'previous';
}
$newPage
.addClass(`page-${newPagePosition}`)
.removeClass('stacked');
if (dynamicNavbar && $newNavbarInner.length) {
$newNavbarInner
.addClass(`navbar-${newPagePosition}`)
.removeClass('stacked');
}
// Find Old Page
if (options.reloadCurrent) {
$oldPage = $pagesInView.eq($pagesInView.length - 1);
if (separateNavbar) {
// $oldNavbarInner = $navbarsInView.eq($pagesInView.length - 1);
$oldNavbarInner = $(app.navbar.getElByPage($oldPage));
}
} else if (options.reloadPrevious) {
$oldPage = $pagesInView.eq($pagesInView.length - 2);
if (separateNavbar) {
// $oldNavbarInner = $navbarsInView.eq($pagesInView.length - 2);
$oldNavbarInner = $(app.navbar.getElByPage($oldPage));
}
} else if (options.reloadAll) {
$oldPage = $pagesInView.filter((index, pageEl) => pageEl !== $newPage[0]);
if (separateNavbar) {
$oldNavbarInner = $navbarsInView.filter((index, navbarEl) => navbarEl !== $newNavbarInner[0]);
}
} else {
if ($pagesInView.length > 1) {
let i = 0;
for (i = 0; i < $pagesInView.length - 1; i += 1) {
const oldNavbarInnerEl = app.navbar.getElByPage($pagesInView.eq(i));
if (router.params.stackPages) {
$pagesInView.eq(i).addClass('stacked');
if (separateNavbar) {
// $navbarsInView.eq(i).addClass('stacked');
$(oldNavbarInnerEl).addClass('stacked');
}
} else {
// Page remove event
router.pageCallback('beforeRemove', $pagesInView[i], $navbarsInView && $navbarsInView[i], 'previous', undefined, options);
router.removePage($pagesInView[i]);
if (separateNavbar && oldNavbarInnerEl) {
router.removeNavbar(oldNavbarInnerEl);
}
}
}
}
$oldPage = $viewEl
.children('.page:not(.stacked)')
.filter((index, page) => page !== $newPage[0]);
if (separateNavbar) {
$oldNavbarInner = $navbarEl
.children('.navbar-inner:not(.stacked)')
.filter((index, navbarInner) => navbarInner !== $newNavbarInner[0]);
}
}
if (dynamicNavbar && !separateNavbar) {
$oldNavbarInner = $oldPage.children('.navbar').children('.navbar-inner');
}
// Push State
if (router.params.pushState && options.pushState && !options.reloadPrevious) {
const pushStateRoot = router.params.pushStateRoot || '';
History[options.reloadCurrent || options.reloadAll ? 'replace' : 'push'](
view.id,
{
url: options.route.url,
},
pushStateRoot + router.params.pushStateSeparator + options.route.url
);
}
// Current Page & Navbar
router.currentPageEl = $newPage[0];
if (dynamicNavbar && $newNavbarInner.length) {
router.currentNavbarEl = $newNavbarInner[0];
} else {
delete router.currentNavbarEl;
}
// Current Route
router.currentRoute = options.route;
// Update router history
const url = options.route.url;
if (options.history) {
if (options.reloadCurrent && router.history.length > 0) {
router.history[router.history.length - (options.reloadPrevious ? 2 : 1)] = url;
} else if (options.reloadAll) {
router.history = [url];
} else {
router.history.push(url);
}
}
router.saveHistory();
// Insert new page and navbar
const newPageInDom = $newPage.parents(document).length > 0;
const f7Component = $newPage[0].f7Component;
if (options.reloadPrevious) {
if (f7Component && !newPageInDom) {
f7Component.mount((componentEl) => {
$(componentEl).insertBefore($oldPage);
});
} else {
$newPage.insertBefore($oldPage);
}
if (separateNavbar && $newNavbarInner.length) {
if ($oldNavbarInner.length) {
$newNavbarInner.insertBefore($oldNavbarInner);
} else {
if (!router.$navbarEl.parents(document).length) {
router.$el.prepend(router.$navbarEl);
}
$navbarEl.append($newNavbarInner);
}
}
} else {
if ($oldPage.next('.page')[0] !== $newPage[0]) {
if (f7Component && !newPageInDom) {
f7Component.mount((componentEl) => {
$viewEl.append(componentEl);
});
} else {
$viewEl.append($newPage[0]);
}
}
if (separateNavbar && $newNavbarInner.length) {
if (!router.$navbarEl.parents(document).length) {
router.$el.prepend(router.$navbarEl);
}
$navbarEl.append($newNavbarInner[0]);
}
}
if (!newPageInDom) {
router.pageCallback('mounted', $newPage, $newNavbarInner, newPagePosition, reload ? newPagePosition : 'current', options, $oldPage);
}
// Remove old page
if (options.reloadCurrent && $oldPage.length > 0) {
if (router.params.stackPages && router.initialPages.indexOf($oldPage[0]) >= 0) {
$oldPage.addClass('stacked');
if (separateNavbar) {
$oldNavbarInner.addClass('stacked');
}
} else {
// Page remove event
router.pageCallback('beforeRemove', $oldPage, $oldNavbarInner, 'previous', undefined, options);
router.removePage($oldPage);
if (separateNavbar && $oldNavbarInner && $oldNavbarInner.length) {
router.removeNavbar($oldNavbarInner);
}
}
} else if (options.reloadAll) {
$oldPage.each((index, pageEl) => {
const $oldPageEl = $(pageEl);
const $oldNavbarInnerEl = $(app.navbar.getElByPage($oldPageEl));
if (router.params.stackPages && router.initialPages.indexOf($oldPageEl[0]) >= 0) {
$oldPageEl.addClass('stacked');
if (separateNavbar) {
$oldNavbarInnerEl.addClass('stacked');
}
} else {
// Page remove event
router.pageCallback('beforeRemove', $oldPageEl, $oldNavbarInner && $oldNavbarInner.eq(index), 'previous', undefined, options);
router.removePage($oldPageEl);
if (separateNavbar && $oldNavbarInnerEl.length) {
router.removeNavbar($oldNavbarInnerEl);
}
}
});
}
// Load Tab
if (options.route.route.tab) {
router.tabLoad(options.route.route.tab, Utils.extend({}, options, {
history: false,
pushState: false,
}));
}
// Page init and before init events
router.pageCallback('init', $newPage, $newNavbarInner, newPagePosition, reload ? newPagePosition : 'current', options, $oldPage);
if (options.reloadCurrent || options.reloadAll) {
router.allowPageChange = true;
router.pageCallback('beforeIn', $newPage, $newNavbarInner, newPagePosition, 'current', options);
router.pageCallback('afterIn', $newPage, $newNavbarInner, newPagePosition, 'current', options);
return router;
}
// Before animation event
router.pageCallback('beforeIn', $newPage, $newNavbarInner, 'next', 'current', options);
router.pageCallback('beforeOut', $oldPage, $oldNavbarInner, 'current', 'previous', options);
// Animation
function afterAnimation() {
const pageClasses = 'page-previous page-current page-next';
const navbarClasses = 'navbar-previous navbar-current navbar-next';
$newPage.removeClass(pageClasses).addClass('page-current').removeAttr('aria-hidden');
$oldPage.removeClass(pageClasses).addClass('page-previous').attr('aria-hidden', 'true');
if (dynamicNavbar) {
$newNavbarInner.removeClass(navbarClasses).addClass('navbar-current').removeAttr('aria-hidden');
$oldNavbarInner.removeClass(navbarClasses).addClass('navbar-previous').attr('aria-hidden', 'true');
}
// After animation event
router.allowPageChange = true;
router.pageCallback('afterIn', $newPage, $newNavbarInner, 'next', 'current', options);
router.pageCallback('afterOut', $oldPage, $oldNavbarInner, 'current', 'previous', options);
let keepOldPage = app.theme === 'ios' ? (router.params.preloadPreviousPage || router.params.iosSwipeBack) : router.params.preloadPreviousPage;
if (!keepOldPage) {
if ($newPage.hasClass('smart-select-page') || $newPage.hasClass('photo-browser-page') || $newPage.hasClass('autocomplete-page')) {
keepOldPage = true;
}
}
if (!keepOldPage) {
if (router.params.stackPages) {
$oldPage.addClass('stacked');
if (separateNavbar) {
$oldNavbarInner.addClass('stacked');
}
} else if (!($newPage.attr('data-name') && $newPage.attr('data-name') === 'smart-select-page')) {
// Remove event
router.pageCallback('beforeRemove', $oldPage, $oldNavbarInner, 'previous', undefined, options);
router.removePage($oldPage);
if (separateNavbar && $oldNavbarInner.length) {
router.removeNavbar($oldNavbarInner);
}
}
}
router.emit('routeChanged', router.currentRoute, router.previousRoute, router);
if (router.params.pushState) {
History.clearRouterQueue();
}
}
function setPositionClasses() {
const pageClasses = 'page-previous page-current page-next';
const navbarClasses = 'navbar-previous navbar-current navbar-next';
$oldPage.removeClass(pageClasses).addClass('page-current').removeAttr('aria-hidden');
$newPage.removeClass(pageClasses).addClass('page-next').removeAttr('aria-hidden');
if (dynamicNavbar) {
$oldNavbarInner.removeClass(navbarClasses).addClass('navbar-current').removeAttr('aria-hidden');
$newNavbarInner.removeClass(navbarClasses).addClass('navbar-next').removeAttr('aria-hidden');
}
}
if (options.animate) {
const delay = router.app.theme === 'md' ? router.params.materialPageLoadDelay : router.params.iosPageLoadDelay;
if (delay) {
setTimeout(() => {
setPositionClasses();
router.animate($oldPage, $newPage, $oldNavbarInner, $newNavbarInner, 'forward', () => {
afterAnimation();
});
}, delay);
} else {
setPositionClasses();
router.animate($oldPage, $newPage, $oldNavbarInner, $newNavbarInner, 'forward', () => {
afterAnimation();
});
}
} else {
afterAnimation();
}
return router;
}
function load(loadParams = {}, loadOptions = {}, ignorePageChange) {
const router = this;
if (!router.allowPageChange && !ignorePageChange) return router;
const params = loadParams;
const options = loadOptions;
const { url, content, el, pageName, template, templateUrl, component, componentUrl } = params;
if (!options.reloadCurrent &&
options.route &&
options.route.route &&
options.route.route.parentPath &&
router.currentRoute.route &&
router.currentRoute.route.parentPath === options.route.route.parentPath) {
// Do something nested
if (options.route.url === router.url) {
return false;
}
// Check for same params
let sameParams = Object.keys(options.route.params).length === Object.keys(router.currentRoute.params).length;
if (sameParams) {
// Check for equal params name
Object.keys(options.route.params).forEach((paramName) => {
if (
!(paramName in router.currentRoute.params) ||
(router.currentRoute.params[paramName] !== options.route.params[paramName])
) {
sameParams = false;
}
});
}
if (sameParams) {
if (options.route.route.tab) {
return router.tabLoad(options.route.route.tab, options);
}
return false;
}
}
if (
options.route &&
options.route.url &&
router.url === options.route.url &&
!(options.reloadCurrent || options.reloadPrevious) &&
!router.params.allowDuplicateUrls
) {
return false;
}
if (!options.route && url) {
options.route = router.parseRouteUrl(url);
Utils.extend(options.route, { route: { url, path: url } });
}
// Component Callbacks
function resolve(pageEl, newOptions) {
return router.forward(pageEl, Utils.extend(options, newOptions));
}
function reject() {
router.allowPageChange = true;
return router;
}
if (url || templateUrl || componentUrl) {
router.allowPageChange = false;
}
// Proceed
if (content) {
router.forward(router.getPageEl(content), options);
} else if (template || templateUrl) {
// Parse template and send page element
try {
router.pageTemplateLoader(template, templateUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (el) {
// Load page from specified HTMLElement or by page name in pages container
router.forward(router.getPageEl(el), options);
} else if (pageName) {
// Load page by page name in pages container
router.forward(router.$el.children(`.page[data-name="${pageName}"]`).eq(0), options);
} else if (component || componentUrl) {
// Load from component (F7/Vue/React/...)
try {
router.pageComponentLoader(router.el, component, componentUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (url) {
// Load using XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router.xhrRequest(url, options)
.then((pageContent) => {
router.forward(router.getPageEl(pageContent), options);
})
.catch(() => {
router.allowPageChange = true;
});
}
return router;
}
function navigate(navigateParams, navigateOptions = {}) {
const router = this;
let url;
let createRoute;
if (typeof navigateParams === 'string') {
url = navigateParams;
} else {
url = navigateParams.url;
createRoute = navigateParams.route;
}
const app = router.app;
if (!router.view) {
if (app.views.main) {
app.views.main.router.navigate(url, navigateOptions);
}
return router;
}
if (url === '#' || url === '') {
return router;
}
let navigateUrl = url.replace('./', '');
if (navigateUrl[0] !== '/' && navigateUrl.indexOf('#') !== 0) {
const currentPath = router.currentRoute.parentPath || router.currentRoute.path;
navigateUrl = ((currentPath ? `${currentPath}/` : '/') + navigateUrl)
.replace('///', '/')
.replace('//', '/');
}
let route;
if (createRoute) {
route = Utils.extend(router.parseRouteUrl(navigateUrl), {
route: Utils.extend({}, createRoute),
});
} else {
route = router.findMatchingRoute(navigateUrl);
}
if (!route) {
return router;
}
if (route.route.redirect) {
return redirect.call(router, 'navigate', route, navigateOptions);
}
const options = {};
if (route.route.options) {
Utils.extend(options, route.route.options, navigateOptions, { route });
} else {
Utils.extend(options, navigateOptions, { route });
}
('popup popover sheet loginScreen actions customModal').split(' ').forEach((modalLoadProp) => {
if (route.route[modalLoadProp]) {
router.modalLoad(modalLoadProp, route, options);
}
});
('url content component pageName el componentUrl template templateUrl').split(' ').forEach((pageLoadProp) => {
if (route.route[pageLoadProp]) {
router.load({ [pageLoadProp]: route.route[pageLoadProp] }, options);
}
});
// Async
function asyncResolve(resolveParams, resolveOptions) {
router.allowPageChange = false;
let resolvedAsModal = false;
('popup popover sheet loginScreen actions customModal').split(' ').forEach((modalLoadProp) => {
if (resolveParams[modalLoadProp]) {
resolvedAsModal = true;
const modalRoute = Utils.extend({}, route, { route: resolveParams });
router.allowPageChange = true;
router.modalLoad(modalLoadProp, modalRoute, Utils.extend(options, resolveOptions));
}
});
if (resolvedAsModal) return;
router.load(resolveParams, Utils.extend(options, resolveOptions), true);
}
function asyncReject() {
router.allowPageChange = true;
}
if (route.route.async) {
router.allowPageChange = false;
route.route.async.call(router, route, router.currentRoute, asyncResolve, asyncReject);
}
// Retur Router
return router;
}
function tabLoad(tabRoute, loadOptions = {}) {
const router = this;
const options = Utils.extend({
animate: router.params.animate,
pushState: true,
history: true,
on: {},
}, loadOptions);
if (options.route) {
// Set Route
if (options.route !== router.currentRoute) {
router.currentRoute = options.route;
}
// Update Browser History
if (router.params.pushState && options.pushState && !options.reloadPrevious) {
History.replace(
router.view.id,
{
url: options.route.url,
},
(router.params.pushStateRoot || '') + router.params.pushStateSeparator + options.route.url
);
}
// Update Router History
if (options.history) {
router.history[router.history.length - 1] = options.route.url;
router.saveHistory();
}
}
// Show Tab
const $currentPageEl = $(router.currentPageEl);
let tabEl;
if ($currentPageEl.length && $currentPageEl.find(`#${tabRoute.id}`).length) {
tabEl = $currentPageEl.find(`#${tabRoute.id}`).eq(0);
} else if (router.view.selector) {
tabEl = `${router.view.selector} #${tabRoute.id}`;
} else {
tabEl = `#${tabRoute.id}`;
}
const tabShowResult = router.app.tab.show({
tabEl,
animate: options.animate,
tabRoute: options.route,
});
const { $newTabEl, $oldTabEl, animated, onTabsChanged } = tabShowResult;
if ($newTabEl && $newTabEl.parents('.page').length > 0 && options.route) {
const tabParentPageData = $newTabEl.parents('.page')[0].f7Page;
if (tabParentPageData && options.route) {
tabParentPageData.route = options.route;
}
}
// Load Tab Content
const { url, content, el, template, templateUrl, component, componentUrl } = tabRoute;
function onTabLoaded(contentEl) {
// Remove theme elements
router.removeThemeElements($newTabEl);
let tabEventTarget = $newTabEl;
if (typeof contentEl !== 'string') tabEventTarget = $(contentEl);
tabEventTarget.trigger('tab:init tab:mounted', tabRoute);
router.emit('tabInit tabMounted', $newTabEl[0], tabRoute);
if ($oldTabEl && router.params.unloadTabContent) {
if (animated) {
onTabsChanged(() => {
router.tabRemove($oldTabEl, $newTabEl, tabRoute);
});
} else {
router.tabRemove($oldTabEl, $newTabEl, tabRoute);
}
}
}
if (!router.params.unloadTabContent) {
if ($newTabEl[0].f7RouterTabLoaded) return;
}
const { on = {}, once = {} } = tabRoute;
if (options.on) {
Utils.extend(on, options.on);
}
if (options.once) {
Utils.extend(once, options.once);
}
// Component/Template Callbacks
function resolve(contentEl) {
if (!contentEl) return;
if (typeof contentEl === 'string') {
$newTabEl.html(contentEl);
} else {
$newTabEl.html('');
if (contentEl.f7Component) {
contentEl.f7Component.mount((componentEl) => {
$newTabEl.append(componentEl);
});
} else {
$newTabEl.append(contentEl);
}
}
if (!router.params.unloadTabContent) {
$newTabEl[0].f7RouterTabLoaded = true;
}
onTabLoaded(contentEl);
}
function reject() {
router.allowPageChange = true;
return router;
}
if (content) {
resolve(content);
} else if (template || templateUrl) {
try {
router.tabTemplateLoader(template, templateUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (el) {
resolve(el);
} else if (component || componentUrl) {
// Load from component (F7/Vue/React/...)
try {
router.tabComponentLoader($newTabEl[0], component, componentUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (url) {
// Load using XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router.xhrRequest(url, options)
.then((tabContent) => {
resolve(tabContent);
})
.catch(() => {
router.allowPageChange = true;
});
}
}
function tabRemove($oldTabEl, $newTabEl, tabRoute) {
const router = this;
$oldTabEl.trigger('tab:beforeremove', tabRoute);
router.emit('tabBeforeRemove', $oldTabEl[0], $newTabEl[0], tabRoute);
$oldTabEl.children().each((index, tabChild) => {
if (tabChild.f7Component) {
tabChild.f7Component.destroy();
}
});
router.removeTabContent($oldTabEl[0], tabRoute);
}
function modalLoad(modalType, route, loadOptions = {}) {
const router = this;
const app = router.app;
const options = Utils.extend({
animate: router.params.animate,
pushState: true,
history: true,
on: {},
}, loadOptions);
const modalParams = route.route[modalType];
const modalRoute = route.route;
// Load Modal Props
const { url, template, templateUrl, component, componentUrl } = modalParams;
function onModalLoaded() {
// Create Modal
const modal = app[modalType].create(modalParams);
modalRoute.modalInstance = modal;
function closeOnSwipeBack() {
modal.close();
}
modal.on('modalOpen', () => {
router.once('swipeBackMove', closeOnSwipeBack);
});
modal.on('modalClose', () => {
router.off('swipeBackMove', closeOnSwipeBack);
if (!modal.closeByRouter) {
router.back();
}
});
modal.on('modalClosed', () => {
modal.$el.trigger(`${modalType.toLowerCase()}:beforeremove`, route, modal);
modal.emit(`modalBeforeRemove ${modalType}BeforeRemove`, modal.el, route, modal);
const modalComponent = modal.el.f7Component;
if (modalComponent) {
modalComponent.destroy();
}
Utils.nextTick(() => {
if (modalComponent) {
router.removeModal(modal.el);
}
modal.destroy();
delete modalRoute.modalInstance;
});
});
if (options.route) {
// Update Browser History
if (router.params.pushState && options.pushState) {
History.push(
router.view.id,
{
url: options.route.url,
modal: modalType,
},
(router.params.pushStateRoot || '') + router.params.pushStateSeparator + options.route.url
);
}
// Set Route
if (options.route !== router.currentRoute) {
router.currentRoute = Utils.extend(options.route, { modal });
}
// Update Router History
if (options.history) {
router.history.push(options.route.url);
router.saveHistory();
}
}
// Remove theme elements
router.removeThemeElements(modal.el);
// Emit events
modal.$el.trigger(`${modalType.toLowerCase()}:init ${modalType.toLowerCase()}:mounted`, route, modal);
router.emit(`modalInit ${modalType}Init ${modalType}Mounted`, modal.el, route, modal);
// Open
modal.open();
}
// Component/Template Callbacks
function resolve(contentEl) {
if (contentEl) {
if (typeof contentEl === 'string') {
modalParams.content = contentEl;
} else if (contentEl.f7Component) {
contentEl.f7Component.mount((componentEl) => {
modalParams.el = componentEl;
app.root.append(componentEl);
});
} else {
modalParams.el = contentEl;
}
onModalLoaded();
}
}
function reject() {
router.allowPageChange = true;
return router;
}
if (template || templateUrl) {
try {
router.modalTemplateLoader(template, templateUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (component || componentUrl) {
// Load from component (F7/Vue/React/...)
try {
router.modalComponentLoader(app.root[0], component, componentUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (url) {
// Load using XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router.xhrRequest(url, options)
.then((modalContent) => {
modalParams.content = modalContent;
onModalLoaded();
})
.catch(() => {
router.allowPageChange = true;
});
} else {
onModalLoaded();
}
}
function modalRemove(modal) {
Utils.extend(modal, { closeByRouter: true });
modal.close();
}
function backward(el, backwardOptions) {
const router = this;
const app = router.app;
const view = router.view;
const options = Utils.extend({
animate: router.params.animate,
pushState: true,
}, backwardOptions);
const dynamicNavbar = router.dynamicNavbar;
const separateNavbar = router.separateNavbar;
const $newPage = $(el);
const $oldPage = router.$el.children('.page-current');
if ($newPage.length) {
// Remove theme elements
router.removeThemeElements($newPage);
}
let $navbarEl;
let $newNavbarInner;
let $oldNavbarInner;
if (dynamicNavbar) {
$newNavbarInner = $newPage.children('.navbar').children('.navbar-inner');
if (separateNavbar) {
$navbarEl = router.$navbarEl;
if ($newNavbarInner.length > 0) {
$newPage.children('.navbar').remove();
}
if ($newNavbarInner.length === 0 && $newPage[0].f7Page) {
// Try from pageData
$newNavbarInner = $newPage[0].f7Page.$navbarEl;
}
$oldNavbarInner = $navbarEl.find('.navbar-current');
} else {
$oldNavbarInner = $oldPage.children('.navbar').children('.navbar-inner');
}
}
router.allowPageChange = false;
if ($newPage.length === 0 || $oldPage.length === 0) {
router.allowPageChange = true;
return router;
}
// Remove theme elements
router.removeThemeElements($newPage);
// New Page
$newPage
.addClass('page-previous')
.removeClass('stacked')
.removeAttr('aria-hidden');
if (dynamicNavbar && $newNavbarInner.length > 0) {
$newNavbarInner
.addClass('navbar-previous')
.removeClass('stacked')
.removeAttr('aria-hidden');
}
// Remove previous page in case of "forced"
let backIndex;
if (options.force) {
if ($oldPage.prev('.page-previous:not(.stacked)').length > 0 || $oldPage.prev('.page-previous').length === 0) {
if (router.history.indexOf(options.route.url) >= 0) {
backIndex = router.history.length - router.history.indexOf(options.route.url) - 1;
router.history = router.history.slice(0, router.history.indexOf(options.route.url) + 2);
view.history = router.history;
} else if (router.history[[router.history.length - 2]]) {
router.history[router.history.length - 2] = options.route.url;
} else {
router.history.unshift(router.url);
}
if (backIndex && router.params.stackPages) {
$oldPage.prevAll('.page-previous').each((index, pageToRemove) => {
const $pageToRemove = $(pageToRemove);
let $navbarToRemove;
if (separateNavbar) {
// $navbarToRemove = $oldNavbarInner.prevAll('.navbar-previous').eq(index);
$navbarToRemove = $(app.navbar.getElByPage($pageToRemove));
}
if ($pageToRemove[0] !== $newPage[0] && $pageToRemove.index() > $newPage.index()) {
if (router.initialPages.indexOf($pageToRemove[0]) >= 0) {
$pageToRemove.addClass('stacked');
if (separateNavbar) {
$navbarToRemove.addClass('stacked');
}
} else {
router.pageCallback('beforeRemove', $pageToRemove, $navbarToRemove, 'previous', undefined, options);
router.removePage($pageToRemove);
if (separateNavbar && $navbarToRemove.length > 0) {
router.removeNavbar($navbarToRemove);
}
}
}
});
} else {
const $pageToRemove = $oldPage.prev('.page-previous:not(.stacked)');
let $navbarToRemove;
if (separateNavbar) {
// $navbarToRemove = $oldNavbarInner.prev('.navbar-inner:not(.stacked)');
$navbarToRemove = $(app.navbar.getElByPage($pageToRemove));
}
if (router.params.stackPages && router.initialPages.indexOf($pageToRemove[0]) >= 0) {
$pageToRemove.addClass('stacked');
$navbarToRemove.addClass('stacked');
} else if ($pageToRemove.length > 0) {
router.pageCallback('beforeRemove', $pageToRemove, $navbarToRemove, 'previous', undefined, options);
router.removePage($pageToRemove);
if (separateNavbar && $navbarToRemove.length) {
router.removeNavbar($navbarToRemove);
}
}
}
}
}
// Insert new page
const newPageInDom = $newPage.parents(document).length > 0;
const f7Component = $newPage[0].f7Component;
function insertPage() {
if ($newPage.next($oldPage).length === 0) {
if (!newPageInDom && f7Component) {
f7Component.mount((componentEl) => {
$(componentEl).insertBefore($oldPage);
});
} else {
$newPage.insertBefore($oldPage);
}
}
if (separateNavbar && $newNavbarInner.length) {
$newNavbarInner.insertBefore($oldNavbarInner);
if ($oldNavbarInner.length > 0) {
$newNavbarInner.insertBefore($oldNavbarInner);
} else {
if (!router.$navbarEl.parents(document).length) {
router.$el.prepend(router.$navbarEl);
}
$navbarEl.append($newNavbarInner);
}
}
if (!newPageInDom) {
router.pageCallback('mounted', $newPage, $newNavbarInner, 'previous', 'current', options, $oldPage);
}
}
if (options.preload) {
// Insert Page
insertPage();
// Page init and before init events
router.pageCallback('init', $newPage, $newNavbarInner, 'previous', 'current', options, $oldPage);
if ($newPage.prevAll('.page-previous:not(.stacked)').length > 0) {
$newPage.prevAll('.page-previous:not(.stacked)').each((index, pageToRemove) => {
const $pageToRemove = $(pageToRemove);
let $navbarToRemove;
if (separateNavbar) {
// $navbarToRemove = $newNavbarInner.prevAll('.navbar-previous:not(.stacked)').eq(index);
$navbarToRemove = $(app.navbar.getElByPage($pageToRemove));
}
if (router.params.stackPages && router.initialPages.indexOf(pageToRemove) >= 0) {
$pageToRemove.addClass('stacked');
if (separateNavbar) {
$navbarToRemove.addClass('stacked');
}
} else {
router.pageCallback('beforeRemove', $pageToRemove, $navbarToRemove, 'previous', undefined);
router.removePage($pageToRemove);
if (separateNavbar && $navbarToRemove.length) {
router.removeNavbar($navbarToRemove);
}
}
});
}
router.allowPageChange = true;
return router;
}
// History State
if (router.params.pushState && options.pushState) {
if (backIndex) History.go(-backIndex);
else History.back();
}
// Update History
if (router.history.length === 1) {
router.history.unshift(router.url);
}
router.history.pop();
router.saveHistory();
// Current Page & Navbar
router.currentPageEl = $newPage[0];
if (dynamicNavbar && $newNavbarInner.length) {
router.currentNavbarEl = $newNavbarInner[0];
} else {
delete router.currentNavbarEl;
}
// Current Route
router.currentRoute = options.route;
// Insert Page
insertPage();
// Load Tab
if (options.route.route.tab) {
router.tabLoad(options.route.route.tab, Utils.extend({}, options, {
history: false,
pushState: false,
}));
}
// Page init and before init events
router.pageCallback('init', $newPage, $newNavbarInner, 'previous', 'current', options, $oldPage);
// Before animation callback
router.pageCallback('beforeIn', $newPage, $newNavbarInner, 'previous', 'current', options);
router.pageCallback('beforeOut', $oldPage, $oldNavbarInner, 'current', 'next', options);
// Animation
function afterAnimation() {
// Set classes
const pageClasses = 'page-previous page-current page-next';
const navbarClasses = 'navbar-previous navbar-current navbar-next';
$newPage.removeClass(pageClasses).addClass('page-current').removeAttr('aria-hidden');
$oldPage.removeClass(pageClasses).addClass('page-next').attr('aria-hidden', 'true');
if (dynamicNavbar) {
$newNavbarInner.removeClass(navbarClasses).addClass('navbar-current').removeAttr('aria-hidden');
$oldNavbarInner.removeClass(navbarClasses).addClass('navbar-next').attr('aria-hidden', 'true');
}
// After animation event
router.pageCallback('afterIn', $newPage, $newNavbarInner, 'previous', 'current', options);
router.pageCallback('afterOut', $oldPage, $oldNavbarInner, 'current', 'next', options);
// Remove Old Page
if (router.params.stackPages && router.initialPages.indexOf($oldPage[0]) >= 0) {
$oldPage.addClass('stacked');
if (separateNavbar) {
$oldNavbarInner.addClass('stacked');
}
} else {
router.pageCallback('beforeRemove', $oldPage, $oldNavbarInner, 'next', undefined, options);
router.removePage($oldPage);
if (separateNavbar && $oldNavbarInner.length) {
router.removeNavbar($oldNavbarInner);
}
}
router.allowPageChange = true;
router.emit('routeChanged', router.currentRoute, router.previousRoute, router);
// Preload previous page
const preloadPreviousPage = app.theme === 'ios' ? (router.params.preloadPreviousPage || router.params.iosSwipeBack) : router.params.preloadPreviousPage;
if (preloadPreviousPage) {
router.back(router.history[router.history.length - 2], { preload: true });
}
if (router.params.pushState) {
History.clearRouterQueue();
}
}
function setPositionClasses() {
const pageClasses = 'page-previous page-current page-next';
const navbarClasses = 'navbar-previous navbar-current navbar-next';
$oldPage.removeClass(pageClasses).addClass('page-current');
$newPage.removeClass(pageClasses).addClass('page-previous').removeAttr('aria-hidden');
if (dynamicNavbar) {
$oldNavbarInner.removeClass(navbarClasses).addClass('navbar-current');
$newNavbarInner.removeClass(navbarClasses).addClass('navbar-previous').removeAttr('aria-hidden');
}
}
if (options.animate) {
setPositionClasses();
router.animate($oldPage, $newPage, $oldNavbarInner, $newNavbarInner, 'backward', () => {
afterAnimation();
});
} else {
afterAnimation();
}
return router;
}
function loadBack(backParams, backOptions, ignorePageChange) {
const router = this;
if (!router.allowPageChange && !ignorePageChange) return router;
const params = backParams;
const options = backOptions;
const { url, content, el, pageName, template, templateUrl, component, componentUrl } = params;
if (
options.route.url &&
router.url === options.route.url &&
!(options.reloadCurrent || options.reloadPrevious) &&
!router.params.allowDuplicateUrls
) {
return false;
}
if (!options.route && url) {
options.route = router.parseRouteUrl(url);
}
// Component Callbacks
function resolve(pageEl, newOptions) {
return router.backward(pageEl, Utils.extend(options, newOptions));
}
function reject() {
router.allowPageChange = true;
return router;
}
if (url || templateUrl || componentUrl) {
router.allowPageChange = false;
}
// Proceed
if (content) {
router.backward(router.getPageEl(content), options);
} else if (template || templateUrl) {
// Parse template and send page element
try {
router.pageTemplateLoader(template, templateUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (el) {
// Load page from specified HTMLElement or by page name in pages container
router.backward(router.getPageEl(el), options);
} else if (pageName) {
// Load page by page name in pages container
router.backward(router.$el.children(`.page[data-name="${pageName}"]`).eq(0), options);
} else if (component || componentUrl) {
// Load from component (F7/Vue/React/...)
try {
router.pageComponentLoader(router.el, component, componentUrl, options, resolve, reject);
} catch (err) {
router.allowPageChange = true;
throw err;
}
} else if (url) {
// Load using XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router.xhrRequest(url, options)
.then((pageContent) => {
router.backward(router.getPageEl(pageContent), options);
})
.catch(() => {
router.allowPageChange = true;
});
}
return router;
}
function back(...args) {
let navigateUrl;
let navigateOptions;
if (typeof args[0] === 'object') {
navigateOptions = args[0] || {};
} else {
navigateUrl = args[0];
navigateOptions = args[1] || {};
}
const router = this;
const app = router.app;
if (!router.view) {
app.views.main.router.back(navigateUrl, navigateOptions);
return router;
}
let currentRouteIsModal = router.currentRoute.modal;
let modalType;
if (!currentRouteIsModal) {
('popup popover sheet loginScreen actions customModal').split(' ').forEach((modalLoadProp) => {
if (router.currentRoute.route[modalLoadProp]) {
currentRouteIsModal = true;
modalType = modalLoadProp;
}
});
}
if (currentRouteIsModal) {
const modalToClose = router.currentRoute.modal ||
router.currentRoute.route.modalInstance ||
app[modalType].get();
const previousUrl = router.history[router.history.length - 2];
let previousRoute = router.findMatchingRoute(previousUrl);
if (!previousRoute && previousUrl) {
previousRoute = {
url: previousUrl,
path: previousUrl.split('?')[0],
query: Utils.parseUrlQuery(previousUrl),
route: {
path: previousUrl.split('?')[0],
url: previousUrl,
},
};
}
if (!previousRoute || !modalToClose) {
return router;
}
if (router.params.pushState && navigateOptions.pushState !== false) {
History.back();
}
router.currentRoute = previousRoute;
router.history.pop();
router.saveHistory();
router.modalRemove(modalToClose);
return router;
}
const $previousPage = router.$el.children('.page-current').prevAll('.page-previous').eq(0);
if (!navigateOptions.force && $previousPage.length > 0) {
if (router.params.pushState && $previousPage[0].f7Page && router.history[router.history.length - 2] !== $previousPage[0].f7Page.route.url) {
router.back(router.history[router.history.length - 2], Utils.extend(navigateOptions, { force: true }));
return router;
}
router.loadBack({ el: $previousPage }, Utils.extend(navigateOptions, {
route: $previousPage[0].f7Page.route,
}));
return router;
}
// Navigate URL
if (navigateUrl === '#') {
navigateUrl = undefined;
}
if (navigateUrl && navigateUrl[0] !== '/' && navigateUrl.indexOf('#') !== 0) {
navigateUrl = ((router.path || '/') + navigateUrl).replace('//', '/');
}
if (!navigateUrl && router.history.length > 1) {
navigateUrl = router.history[router.history.length - 2];
}
// Find route to load
let route = router.findMatchingRoute(navigateUrl);
if (!route) {
if (navigateUrl) {
route = {
url: navigateUrl,
path: navigateUrl.split('?')[0],
query: Utils.parseUrlQuery(navigateUrl),
route: {
path: navigateUrl.split('?')[0],
url: navigateUrl,
},
};
}
}
if (!route) {
return router;
}
if (route.route.redirect) {
return redirect.call(router, 'back', route, navigateOptions);
}
const options = {};
if (route.route.options) {
Utils.extend(options, route.route.options, navigateOptions, { route });
} else {
Utils.extend(options, navigateOptions, { route });
}
if (options.force && router.params.stackPages) {
router.$el.children('.page-previous.stacked').each((index, pageEl) => {
if (pageEl.f7Page && pageEl.f7Page.route && pageEl.f7Page.route.url === route.url) {
router.loadBack({ el: pageEl }, options);
}
});
}
('url content component pageName el componentUrl template templateUrl').split(' ').forEach((pageLoadProp) => {
if (route.route[pageLoadProp]) {
router.loadBack({ [pageLoadProp]: route.route[pageLoadProp] }, options);
}
});
// Async
function asyncResolve(resolveParams, resolveOptions) {
router.allowPageChange = false;
router.loadBack(resolveParams, Utils.extend(options, resolveOptions), true);
}
function asyncReject() {
router.allowPageChange = true;
}
if (route.route.async) {
router.allowPageChange = false;
route.route.async.call(router, route, router.currentRoute, asyncResolve, asyncReject);
}
// Return Router
return router;
}
class Router$1 extends Framework7Class {
constructor(app, view) {
super({}, [typeof view === 'undefined' ? app : view]);
const router = this;
// Is App Router
router.isAppRouter = typeof view === 'undefined';
if (router.isAppRouter) {
// App Router
Utils.extend(false, router, {
app,
params: app.params.view,
routes: app.routes || [],
cache: app.cache,
});
} else {
// View Router
Utils.extend(false, router, {
app,
view,
viewId: view.id,
params: view.params,
routes: view.routes,
$el: view.$el,
el: view.el,
$navbarEl: view.$navbarEl,
navbarEl: view.navbarEl,
history: view.history,
scrollHistory: view.scrollHistory,
cache: app.cache,
dynamicNavbar: app.theme === 'ios' && view.params.iosDynamicNavbar,
separateNavbar: app.theme === 'ios' && view.params.iosDynamicNavbar && view.params.iosSeparateDynamicNavbar,
initialPages: [],
initialNavbars: [],
});
}
// Install Modules
router.useModules();
// Temporary Dom
router.tempDom = document.createElement('div');
// AllowPageChage
router.allowPageChange = true;
// Current Route
let currentRoute = {};
let previousRoute = {};
Object.defineProperty(router, 'currentRoute', {
enumerable: true,
configurable: true,
set(newRoute = {}) {
previousRoute = Utils.extend({}, currentRoute);
currentRoute = newRoute;
if (!currentRoute) return;
router.url = currentRoute.url;
router.emit('routeChange', newRoute, previousRoute, router);
},
get() {
return currentRoute;
},
});
Object.defineProperty(router, 'previousRoute', {
enumerable: true,
configurable: true,
get() {
return previousRoute;
},
set(newRoute) {
previousRoute = newRoute;
},
});
Utils.extend(router, {
// Load
forward,
load,
navigate,
refreshPage,
// Tab
tabLoad,
tabRemove,
// Modal
modalLoad,
modalRemove,
// Back
backward,
loadBack,
back,
});
return router;
}
animatableNavElements(newNavbarInner, oldNavbarInner) {
const router = this;
const dynamicNavbar = router.dynamicNavbar;
const animateIcon = router.params.iosAnimateNavbarBackIcon;
let newNavEls;
let oldNavEls;
function animatableNavEl(el, navbarInner) {
const $el = $(el);
const isSliding = $el.hasClass('sliding') || navbarInner.hasClass('sliding');
const isSubnavbar = $el.hasClass('subnavbar');
const needsOpacityTransition = isSliding ? !isSubnavbar : true;
const hasIcon = isSliding && animateIcon && $el.hasClass('left') && $el.find('.back .icon').length > 0;
let $iconEl;
if (hasIcon) $iconEl = $el.find('.back .icon');
return {
$el,
$iconEl,
hasIcon,
leftOffset: $el[0].f7NavbarLeftOffset,
rightOffset: $el[0].f7NavbarRightOffset,
isSliding,
isSubnavbar,
needsOpacityTransition,
};
}
if (dynamicNavbar) {
newNavEls = [];
oldNavEls = [];
newNavbarInner.children('.left, .right, .title, .subnavbar').each((index, navEl) => {
newNavEls.push(animatableNavEl(navEl, newNavbarInner));
});
oldNavbarInner.children('.left, .right, .title, .subnavbar').each((index, navEl) => {
oldNavEls.push(animatableNavEl(navEl, oldNavbarInner));
});
[oldNavEls, newNavEls].forEach((navEls) => {
navEls.forEach((navEl) => {
const n = navEl;
const { isSliding, $el } = navEl;
const otherEls = navEls === oldNavEls ? newNavEls : oldNavEls;
if (!(isSliding && $el.hasClass('title') && otherEls)) return;
otherEls.forEach((otherNavEl) => {
if (otherNavEl.$el.hasClass('left') && otherNavEl.hasIcon) {
const iconTextEl = otherNavEl.$el.find('.back span')[0];
n.leftOffset += iconTextEl ? iconTextEl.offsetLeft : 0;
}
});
});
});
}
return { newNavEls, oldNavEls };
}
animateWithCSS(oldPage, newPage, oldNavbarInner, newNavbarInner, direction, callback) {
const router = this;
const dynamicNavbar = router.dynamicNavbar;
const separateNavbar = router.separateNavbar;
const ios = router.app.theme === 'ios';
// Router Animation class
const routerTransitionClass = `router-transition-${direction} router-transition-css-${direction}`;
let newNavEls;
let oldNavEls;
let navbarWidth = 0;
if (ios && dynamicNavbar) {
if (!separateNavbar) {
navbarWidth = newNavbarInner[0].offsetWidth;
}
const navEls = router.animatableNavElements(newNavbarInner, oldNavbarInner);
newNavEls = navEls.newNavEls;
oldNavEls = navEls.oldNavEls;
}
function animateNavbars(progress) {
if (ios && dynamicNavbar) {
newNavEls.forEach((navEl) => {
const $el = navEl.$el;
const offset = direction === 'forward' ? navEl.rightOffset : navEl.leftOffset;
if (navEl.isSliding) {
$el.transform(`translate3d(${offset * (1 - progress)}px,0,0)`);
}
if (navEl.hasIcon) {
if (direction === 'forward') {
navEl.$iconEl.transform(`translate3d(${(-offset - navbarWidth) * (1 - progress)}px,0,0)`);
} else {
navEl.$iconEl.transform(`translate3d(${(-offset + (navbarWidth / 5)) * (1 - progress)}px,0,0)`);
}
}
});
oldNavEls.forEach((navEl) => {
const $el = navEl.$el;
const offset = direction === 'forward' ? navEl.leftOffset : navEl.rightOffset;
if (navEl.isSliding) {
$el.transform(`translate3d(${offset * (progress)}px,0,0)`);
}
if (navEl.hasIcon) {
if (direction === 'forward') {
navEl.$iconEl.transform(`translate3d(${(-offset + (navbarWidth / 5)) * (progress)}px,0,0)`);
} else {
navEl.$iconEl.transform(`translate3d(${(-offset - navbarWidth) * (progress)}px,0,0)`);
}
}
});
}
}
// AnimationEnd Callback
function onDone() {
if (router.dynamicNavbar) {
if (newNavbarInner.hasClass('sliding')) {
newNavbarInner.find('.title, .left, .right, .left .icon, .subnavbar').transform('');
} else {
newNavbarInner.find('.sliding').transform('');
}
if (oldNavbarInner.hasClass('sliding')) {
oldNavbarInner.find('.title, .left, .right, .left .icon, .subnavbar').transform('');
} else {
oldNavbarInner.find('.sliding').transform('');
}
}
router.$el.removeClass(routerTransitionClass);
if (callback) callback();
}
(direction === 'forward' ? newPage : oldPage).animationEnd(() => {
onDone();
});
// Animate
if (dynamicNavbar) {
// Prepare Navbars
animateNavbars(0);
Utils.nextTick(() => {
// Add class, start animation
animateNavbars(1);
router.$el.addClass(routerTransitionClass);
});
} else {
// Add class, start animation
router.$el.addClass(routerTransitionClass);
}
}
animateWithJS(oldPage, newPage, oldNavbarInner, newNavbarInner, direction, callback) {
const router = this;
const dynamicNavbar = router.dynamicNavbar;
const separateNavbar = router.separateNavbar;
const ios = router.app.theme === 'ios';
const duration = ios ? 400 : 250;
const routerTransitionClass = `router-transition-${direction} router-transition-js-${direction}`;
let startTime = null;
let done = false;
let newNavEls;
let oldNavEls;
let navbarWidth = 0;
if (ios && dynamicNavbar) {
if (!separateNavbar) {
navbarWidth = newNavbarInner[0].offsetWidth;
}
const navEls = router.animatableNavElements(newNavbarInner, oldNavbarInner);
newNavEls = navEls.newNavEls;
oldNavEls = navEls.oldNavEls;
}
let $shadowEl;
let $opacityEl;
if (ios) {
$shadowEl = $('<div class="page-shadow-effect"></div>');
$opacityEl = $('<div class="page-opacity-effect"></div>');
if (direction === 'forward') {
newPage.append($shadowEl);
oldPage.append($opacityEl);
} else {
newPage.append($opacityEl);
oldPage.append($shadowEl);
}
}
const easing = Utils.bezier(0.25, 0.1, 0.25, 1);
function onDone() {
newPage.transform('').css('opacity', '');
oldPage.transform('').css('opacity', '');
if (ios) {
$shadowEl.remove();
$opacityEl.remove();
if (dynamicNavbar) {
newNavEls.forEach((navEl) => {
navEl.$el.transform('');
navEl.$el.css('opacity', '');
});
oldNavEls.forEach((navEl) => {
navEl.$el.transform('');
navEl.$el.css('opacity', '');
});
newNavEls = [];
oldNavEls = [];
}
}
router.$el.removeClass(routerTransitionClass);
if (callback) callback();
}
function render() {
const time = Utils.now();
if (!startTime) startTime = time;
const progress = Math.max(Math.min((time - startTime) / duration, 1), 0);
const easeProgress = easing(progress);
if (progress >= 1) {
done = true;
}
const inverter = router.app.rtl ? -1 : 1;
if (ios) {
if (direction === 'forward') {
newPage.transform(`translate3d(${(1 - easeProgress) * 100 * inverter}%,0,0)`);
oldPage.transform(`translate3d(${-easeProgress * 20 * inverter}%,0,0)`);
$shadowEl[0].style.opacity = easeProgress;
$opacityEl[0].style.opacity = easeProgress;
} else {
newPage.transform(`translate3d(${-(1 - easeProgress) * 20 * inverter}%,0,0)`);
oldPage.transform(`translate3d(${easeProgress * 100 * inverter}%,0,0)`);
$shadowEl[0].style.opacity = 1 - easeProgress;
$opacityEl[0].style.opacity = 1 - easeProgress;
}
if (dynamicNavbar) {
newNavEls.forEach((navEl) => {
const $el = navEl.$el;
const offset = direction === 'forward' ? navEl.rightOffset : navEl.leftOffset;
if (navEl.needsOpacityTransition) {
$el[0].style.opacity = easeProgress;
}
if (navEl.isSliding) {
$el.transform(`translate3d(${offset * (1 - easeProgress)}px,0,0)`);
}
if (navEl.hasIcon) {
if (direction === 'forward') {
navEl.$iconEl.transform(`translate3d(${(-offset - navbarWidth) * (1 - easeProgress)}px,0,0)`);
} else {
navEl.$iconEl.transform(`translate3d(${(-offset + (navbarWidth / 5)) * (1 - easeProgress)}px,0,0)`);
}
}
});
oldNavEls.forEach((navEl) => {
const $el = navEl.$el;
const offset = direction === 'forward' ? navEl.leftOffset : navEl.rightOffset;
if (navEl.needsOpacityTransition) {
$el[0].style.opacity = (1 - easeProgress);
}
if (navEl.isSliding) {
$el.transform(`translate3d(${offset * (easeProgress)}px,0,0)`);
}
if (navEl.hasIcon) {
if (direction === 'forward') {
navEl.$iconEl.transform(`translate3d(${(-offset + (navbarWidth / 5)) * (easeProgress)}px,0,0)`);
} else {
navEl.$iconEl.transform(`translate3d(${(-offset - navbarWidth) * (easeProgress)}px,0,0)`);
}
}
});
}
} else if (direction === 'forward') {
newPage.transform(`translate3d(0, ${(1 - easeProgress) * 56}px,0)`);
newPage.css('opacity', easeProgress);
} else {
oldPage.transform(`translate3d(0, ${easeProgress * 56}px,0)`);
oldPage.css('opacity', 1 - easeProgress);
}
if (done) {
onDone();
return;
}
Utils.nextFrame(render);
}
router.$el.addClass(routerTransitionClass);
Utils.nextFrame(render);
}
animate(...args) {
// Args: oldPage, newPage, oldNavbarInner, newNavbarInner, direction, callback
const router = this;
if (router.params.animateCustom) {
router.params.animateCustom.apply(router, args);
} else if (router.params.animateWithJS) {
router.animateWithJS(...args);
} else {
router.animateWithCSS(...args);
}
}
removeModal(modalEl) {
const router = this;
router.removeEl(modalEl);
}
// eslint-disable-next-line
removeTabContent(tabEl) {
const $tabEl = $(tabEl);
$tabEl.html('');
}
removeNavbar(el) {
const router = this;
router.removeEl(el);
}
removePage(el) {
const router = this;
router.removeEl(el);
}
removeEl(el) {
if (!el) return;
const router = this;
const $el = $(el);
if ($el.length === 0) return;
if ($el[0].f7Component && $el[0].f7Component.destroy) {
$el[0].f7Component.destroy();
}
if (!router.params.removeElements) {
return;
}
if (router.params.removeElementsWithTimeout) {
setTimeout(() => {
$el.remove();
}, router.params.removeElementsTimeout);
} else {
$el.remove();
}
}
getPageEl(content) {
const router = this;
if (typeof content === 'string') {
router.tempDom.innerHTML = content;
} else {
if ($(content).hasClass('page')) {
return content;
}
router.tempDom.innerHTML = '';
$(router.tempDom).append(content);
}
return router.findElement('.page', router.tempDom);
}
findElement(stringSelector, container, notStacked) {
const router = this;
const view = router.view;
const app = router.app;
// Modals Selector
const modalsSelector = '.popup, .dialog, .popover, .actions-modal, .sheet-modal, .login-screen, .page';
const $container = $(container);
let selector = stringSelector;
if (notStacked) selector += ':not(.stacked)';
let found = $container
.find(selector)
.filter((index, el) => $(el).parents(modalsSelector).length === 0);
if (found.length > 1) {
if (typeof view.selector === 'string') {
// Search in related view
found = $container.find(`${view.selector} ${selector}`);
}
if (found.length > 1) {
// Search in main view
found = $container.find(`.${app.params.viewMainClass} ${selector}`);
}
}
if (found.length === 1) return found;
// Try to find not stacked
if (!notStacked) found = router.findElement(selector, $container, true);
if (found && found.length === 1) return found;
if (found && found.length > 1) return $(found[0]);
return undefined;
}
flattenRoutes(routes = this.routes) {
let flattenedRoutes = [];
routes.forEach((route) => {
if ('routes' in route) {
const mergedPathsRoutes = route.routes.map((childRoute) => {
const cRoute = Utils.extend({}, childRoute);
cRoute.path = (`${route.path}/${cRoute.path}`).replace('///', '/').replace('//', '/');
return cRoute;
});
flattenedRoutes = flattenedRoutes.concat(route, this.flattenRoutes(mergedPathsRoutes));
} else if ('tabs' in route && route.tabs) {
const mergedPathsRoutes = route.tabs.map((tabRoute) => {
const tRoute = Utils.extend({}, route, {
path: (`${route.path}/${tabRoute.path}`).replace('///', '/').replace('//', '/'),
parentPath: route.path,
tab: tabRoute,
});
delete tRoute.tabs;
return tRoute;
});
flattenedRoutes = flattenedRoutes.concat(this.flattenRoutes(mergedPathsRoutes));
} else {
flattenedRoutes.push(route);
}
});
return flattenedRoutes;
}
// eslint-disable-next-line
parseRouteUrl(url) {
if (!url) return {};
const query = Utils.parseUrlQuery(url);
const hash = url.split('#')[1];
const params = {};
const path = url.split('#')[0].split('?')[0];
return {
query,
hash,
params,
url,
path,
};
}
findTabRoute(tabEl) {
const router = this;
const $tabEl = $(tabEl);
const parentPath = router.currentRoute.route.parentPath;
const tabId = $tabEl.attr('id');
const flattenedRoutes = router.flattenRoutes(router.routes);
let foundTabRoute;
flattenedRoutes.forEach((route) => {
if (
route.parentPath === parentPath &&
route.tab &&
route.tab.id === tabId
) {
foundTabRoute = route;
}
});
return foundTabRoute;
}
findRouteByKey(key, value) {
const router = this;
const routes = router.routes;
const flattenedRoutes = router.flattenRoutes(routes);
let matchingRoute;
flattenedRoutes.forEach((route) => {
if (matchingRoute) return;
if (route[key] === value) {
matchingRoute = route;
}
});
return matchingRoute;
}
findMatchingRoute(url) {
if (!url) return undefined;
const router = this;
const routes = router.routes;
const flattenedRoutes = router.flattenRoutes(routes);
const { path, query, hash, params } = router.parseRouteUrl(url);
let matchingRoute;
flattenedRoutes.forEach((route) => {
if (matchingRoute) return;
const keys = [];
const pathsToMatch = [route.path];
if (route.alias) {
if (typeof route.alias === 'string') pathsToMatch.push(route.alias);
else if (Array.isArray(route.alias)) {
route.alias.forEach((aliasPath) => {
pathsToMatch.push(aliasPath);
});
}
}
let matched;
pathsToMatch.forEach((pathToMatch) => {
if (matched) return;
matched = PathToRegexp(pathToMatch, keys).exec(path);
});
if (matched) {
keys.forEach((keyObj, index) => {
const paramValue = matched[index + 1];
params[keyObj.name] = paramValue;
});
let parentPath;
if (route.parentPath) {
parentPath = path.split('/').slice(0, route.parentPath.split('/').length - 1).join('/');
}
matchingRoute = {
query,
hash,
params,
url,
path,
parentPath,
route,
name: route.name,
};
}
});
return matchingRoute;
}
removeFromXhrCache(url) {
const router = this;
const xhrCache = router.cache.xhr;
let index = false;
for (let i = 0; i < xhrCache.length; i += 1) {
if (xhrCache[i].url === url) index = i;
}
if (index !== false) xhrCache.splice(index, 1);
}
xhrRequest(requestUrl, options) {
const router = this;
const params = router.params;
const { ignoreCache } = options;
let url = requestUrl;
let hasQuery = url.indexOf('?') >= 0;
if (params.passRouteQueryToRequest &&
options &&
options.route &&
options.route.query &&
Object.keys(options.route.query).length
) {
url += `${hasQuery ? '&' : '?'}${Utils.serializeObject(options.route.query)}`;
hasQuery = true;
}
if (params.passRouteParamsToRequest &&
options &&
options.route &&
options.route.params &&
Object.keys(options.route.params).length
) {
url += `${hasQuery ? '&' : '?'}${Utils.serializeObject(options.route.params)}`;
hasQuery = true;
}
if (url.indexOf('{{') >= 0 &&
options &&
options.route &&
options.route.params &&
Object.keys(options.route.params).length
) {
Object.keys(options.route.params).forEach((paramName) => {
const regExp = new RegExp(`{{${paramName}}}`, 'g');
url = url.replace(regExp, options.route.params[paramName] || '');
});
}
// should we ignore get params or not
if (params.xhrCacheIgnoreGetParameters && url.indexOf('?') >= 0) {
url = url.split('?')[0];
}
return Utils.promise((resolve, reject) => {
if (params.xhrCache && !ignoreCache && url.indexOf('nocache') < 0 && params.xhrCacheIgnore.indexOf(url) < 0) {
for (let i = 0; i < router.cache.xhr.length; i += 1) {
const cachedUrl = router.cache.xhr[i];
if (cachedUrl.url === url) {
// Check expiration
if (Utils.now() - cachedUrl.time < params.xhrCacheDuration) {
// Load from cache
resolve(cachedUrl.content);
return;
}
}
}
}
router.xhr = router.app.request({
url,
method: 'GET',
beforeSend(xhr) {
router.emit('routerAjaxStart', xhr, options);
},
complete(xhr, status) {
router.emit('routerAjaxComplete', xhr);
if ((status !== 'error' && status !== 'timeout' && (xhr.status >= 200 && xhr.status < 300)) || xhr.status === 0) {
if (params.xhrCache && xhr.responseText !== '') {
router.removeFromXhrCache(url);
router.cache.xhr.push({
url,
time: Utils.now(),
content: xhr.responseText,
});
}
router.emit('routerAjaxSuccess', xhr, options);
resolve(xhr.responseText);
} else {
router.emit('routerAjaxError', xhr, options);
reject(xhr);
}
},
error(xhr) {
router.emit('routerAjaxError', xhr, options);
reject(xhr);
},
});
});
}
// Remove theme elements
removeThemeElements(el) {
const router = this;
const theme = router.app.theme;
$(el).find(`.${theme === 'md' ? 'ios' : 'md'}-only, .if-${theme === 'md' ? 'ios' : 'md'}`).remove();
}
templateLoader(template, templateUrl, options, resolve, reject) {
const router = this;
function compile(t) {
let compiledHtml;
let context;
try {
context = options.context || {};
if (typeof context === 'function') context = context.call(router);
else if (typeof context === 'string') {
try {
context = JSON.parse(context);
} catch (err) {
reject();
throw (err);
}
}
if (typeof t === 'function') {
compiledHtml = t(context);
} else {
compiledHtml = Template7.compile(t)(Utils.extend({}, context || {}, {
$app: router.app,
$root: Utils.extend({}, router.app.data, router.app.methods),
$route: options.route,
$router: router,
$theme: {
ios: router.app.theme === 'ios',
md: router.app.theme === 'md',
},
}));
}
} catch (err) {
reject();
throw (err);
}
resolve(compiledHtml, { context });
}
if (templateUrl) {
// Load via XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router
.xhrRequest(templateUrl, options)
.then((templateContent) => {
compile(templateContent);
})
.catch(() => {
reject();
});
} else {
compile(template);
}
}
modalTemplateLoader(template, templateUrl, options, resolve, reject) {
const router = this;
return router.templateLoader(template, templateUrl, options, (html) => {
resolve(html);
}, reject);
}
tabTemplateLoader(template, templateUrl, options, resolve, reject) {
const router = this;
return router.templateLoader(template, templateUrl, options, (html) => {
resolve(html);
}, reject);
}
pageTemplateLoader(template, templateUrl, options, resolve, reject) {
const router = this;
return router.templateLoader(template, templateUrl, options, (html, newOptions = {}) => {
resolve(router.getPageEl(html), newOptions);
}, reject);
}
componentLoader(component, componentUrl, options = {}, resolve, reject) {
const router = this;
const url = typeof component === 'string' ? component : componentUrl;
function compile(c) {
const extendContext = Utils.extend(
{},
options.context || {},
{
$,
$$: $,
$app: router.app,
$root: Utils.extend({}, router.app.data, router.app.methods),
$route: options.route,
$router: router,
$dom7: $,
$theme: {
ios: router.app.theme === 'ios',
md: router.app.theme === 'md',
},
}
);
const createdComponent = Component.create(c, extendContext);
resolve(createdComponent.el);
}
if (url) {
// Load via XHR
if (router.xhr) {
router.xhr.abort();
router.xhr = false;
}
router
.xhrRequest(url, options)
.then((loadedComponent) => {
compile(Component.parse(loadedComponent));
})
.catch((err) => {
reject();
throw (err);
});
} else {
compile(component);
}
}
modalComponentLoader(rootEl, component, componentUrl, options, resolve, reject) {
const router = this;
router.componentLoader(component, componentUrl, options, (el) => {
resolve(el);
}, reject);
}
tabComponentLoader(tabEl, component, componentUrl, options, resolve, reject) {
const router = this;
router.componentLoader(component, componentUrl, options, (el) => {
resolve(el);
}, reject);
}
pageComponentLoader(routerEl, component, componentUrl, options, resolve, reject) {
const router = this;
router.componentLoader(component, componentUrl, options, (el, newOptions = {}) => {
resolve(el, newOptions);
}, reject);
}
getPageData(pageEl, navbarEl, from, to, route = {}, pageFromEl) {
const router = this;
const $pageEl = $(pageEl);
const $navbarEl = $(navbarEl);
const currentPage = $pageEl[0].f7Page || {};
let direction;
let pageFrom;
if ((from === 'next' && to === 'current') || (from === 'current' && to === 'previous')) direction = 'forward';
if ((from === 'current' && to === 'next') || (from === 'previous' && to === 'current')) direction = 'backward';
if (currentPage && !currentPage.fromPage) {
const $pageFromEl = $(pageFromEl);
if ($pageFromEl.length) {
pageFrom = $pageFromEl[0].f7Page;
}
}
const page = {
app: router.app,
view: router.view,
router,
$el: $pageEl,
el: $pageEl[0],
$pageEl,
pageEl: $pageEl[0],
$navbarEl,
navbarEl: $navbarEl[0],
name: $pageEl.attr('data-name'),
position: from,
from,
to,
direction,
route: currentPage.route ? currentPage.route : route,
pageFrom: currentPage.pageFrom || pageFrom,
};
if ($navbarEl && $navbarEl[0]) {
$navbarEl[0].f7Page = page;
}
$pageEl[0].f7Page = page;
return page;
}
// Callbacks
pageCallback(callback, pageEl, navbarEl, from, to, options = {}, pageFromEl) {
if (!pageEl) return;
const router = this;
const $pageEl = $(pageEl);
if (!$pageEl.length) return;
const { route } = options;
const restoreScrollTopOnBack = router.params.restoreScrollTopOnBack;
const camelName = `page${callback[0].toUpperCase() + callback.slice(1, callback.length)}`;
const colonName = `page:${callback.toLowerCase()}`;
let page = {};
if (callback === 'beforeRemove' && $pageEl[0].f7Page) {
page = Utils.extend($pageEl[0].f7Page, { from, to, position: from });
} else {
page = router.getPageData(pageEl, navbarEl, from, to, route, pageFromEl);
}
const { on = {}, once = {} } = options.route ? options.route.route : {};
if (options.on) {
Utils.extend(on, options.on);
}
if (options.once) {
Utils.extend(once, options.once);
}
function attachEvents() {
if ($pageEl[0].f7RouteEventsAttached) return;
$pageEl[0].f7RouteEventsAttached = true;
if (on && Object.keys(on).length > 0) {
$pageEl[0].f7RouteEventsOn = on;
Object.keys(on).forEach((eventName) => {
on[eventName] = on[eventName].bind(router);
$pageEl.on(Utils.eventNameToColonCase(eventName), on[eventName]);
});
}
if (once && Object.keys(once).length > 0) {
$pageEl[0].f7RouteEventsOnce = once;
Object.keys(once).forEach((eventName) => {
once[eventName] = once[eventName].bind(router);
$pageEl.once(Utils.eventNameToColonCase(eventName), once[eventName]);
});
}
}
function detachEvents() {
if (!$pageEl[0].f7RouteEventsAttached) return;
if ($pageEl[0].f7RouteEventsOn) {
Object.keys($pageEl[0].f7RouteEventsOn).forEach((eventName) => {
$pageEl.off(Utils.eventNameToColonCase(eventName), $pageEl[0].f7RouteEventsOn[eventName]);
});
}
if ($pageEl[0].f7RouteEventsOnce) {
Object.keys($pageEl[0].f7RouteEventsOnce).forEach((eventName) => {
$pageEl.off(Utils.eventNameToColonCase(eventName), $pageEl[0].f7RouteEventsOnce[eventName]);
});
}
$pageEl[0].f7RouteEventsAttached = null;
$pageEl[0].f7RouteEventsOn = null;
$pageEl[0].f7RouteEventsOnce = null;
delete $pageEl[0].f7RouteEventsAttached;
delete $pageEl[0].f7RouteEventsOn;
delete $pageEl[0].f7RouteEventsOnce;
}
if (callback === 'mounted') {
attachEvents();
}
if (callback === 'init') {
if (restoreScrollTopOnBack && (from === 'previous' || !from) && to === 'current' && router.scrollHistory[page.route.url]) {
$pageEl.find('.page-content').scrollTop(router.scrollHistory[page.route.url]);
}
attachEvents();
if ($pageEl[0].f7PageInitialized) {
$pageEl.trigger('page:reinit', page);
router.emit('pageReinit', page);
return;
}
$pageEl[0].f7PageInitialized = true;
}
if (restoreScrollTopOnBack && callback === 'beforeOut' && from === 'current' && to === 'previous') {
// Save scroll position
router.scrollHistory[page.route.url] = $pageEl.find('.page-content').scrollTop();
}
if (restoreScrollTopOnBack && callback === 'beforeOut' && from === 'current' && to === 'next') {
// Delete scroll position
delete router.scrollHistory[page.route.url];
}
$pageEl.trigger(colonName, page);
router.emit(camelName, page);
if (callback === 'beforeRemove') {
detachEvents();
$pageEl[0].f7Page = null;
}
}
saveHistory() {
const router = this;
router.view.history = router.history;
if (router.params.pushState) {
window.localStorage[`f7router-${router.view.id}-history`] = JSON.stringify(router.history);
}
}
restoreHistory() {
const router = this;
if (router.params.pushState && window.localStorage[`f7router-${router.view.id}-history`]) {
router.history = JSON.parse(window.localStorage[`f7router-${router.view.id}-history`]);
router.view.history = router.history;
}
}
clearHistory() {
const router = this;
router.history = [];
router.saveHistory();
}
init() {
const router = this;
const { app, view } = router;
// Init Swipeback
{
if (view && router.params.iosSwipeBack && app.theme === 'ios') {
SwipeBack(router);
}
}
// Dynamic not separated navbbar
if (router.dynamicNavbar && !router.separateNavbar) {
router.$el.addClass('router-dynamic-navbar-inside');
}
let initUrl = router.params.url;
let documentUrl = document.location.href.split(document.location.origin)[1];
let historyRestored;
if (!router.params.pushState) {
if (!initUrl) {
initUrl = documentUrl;
}
if (document.location.search && initUrl.indexOf('?') < 0) {
initUrl += document.location.search;
}
if (document.location.hash && initUrl.indexOf('#') < 0) {
initUrl += document.location.hash;
}
} else {
if (router.params.pushStateRoot && documentUrl.indexOf(router.params.pushStateRoot) >= 0) {
documentUrl = documentUrl.split(router.params.pushStateRoot)[1];
if (documentUrl === '') documentUrl = '/';
}
if (router.params.pushStateSeparator.length > 0 && documentUrl.indexOf(router.params.pushStateSeparator) >= 0) {
initUrl = documentUrl.split(router.params.pushStateSeparator)[1];
} else {
initUrl = documentUrl;
}
router.restoreHistory();
if (router.history.indexOf(initUrl) >= 0) {
router.history = router.history.slice(0, router.history.indexOf(initUrl) + 1);
} else if (router.params.url === initUrl) {
router.history = [initUrl];
} else if (History.state && History.state[view.id] && History.state[view.id].url === router.history[router.history.length - 1]) {
initUrl = router.history[router.history.length - 1];
} else {
router.history = [documentUrl.split(router.params.pushStateSeparator)[0] || '/', initUrl];
}
if (router.history.length > 1) {
historyRestored = true;
} else {
router.history = [];
}
router.saveHistory();
}
let currentRoute;
if (router.history.length > 1) {
// Will load page
currentRoute = router.findMatchingRoute(router.history[0]);
if (!currentRoute) {
currentRoute = Utils.extend(router.parseRouteUrl(router.history[0]), {
route: {
url: router.history[0],
path: router.history[0].split('?')[0],
},
});
}
} else {
// Don't load page
currentRoute = router.findMatchingRoute(initUrl);
if (!currentRoute) {
currentRoute = Utils.extend(router.parseRouteUrl(initUrl), {
route: {
url: initUrl,
path: initUrl.split('?')[0],
},
});
}
}
if (router.params.stackPages) {
router.$el.children('.page').each((index, pageEl) => {
const $pageEl = $(pageEl);
router.initialPages.push($pageEl[0]);
if (router.separateNavbar && $pageEl.children('.navbar').length > 0) {
router.initialNavbars.push($pageEl.children('.navbar').find('.navbar-inner')[0]);
}
});
}
if (router.$el.children('.page:not(.stacked)').length === 0 && initUrl) {
// No pages presented in DOM, reload new page
router.navigate(initUrl, {
reloadCurrent: true,
pushState: false,
});
} else {
// Init current DOM page
router.currentRoute = currentRoute;
router.$el.children('.page:not(.stacked)').each((index, pageEl) => {
const $pageEl = $(pageEl);
let $navbarInnerEl;
$pageEl.addClass('page-current');
if (router.separateNavbar) {
$navbarInnerEl = $pageEl.children('.navbar').children('.navbar-inner');
if ($navbarInnerEl.length > 0) {
if (!router.$navbarEl.parents(document).length) {
router.$el.prepend(router.$navbarEl);
}
router.$navbarEl.append($navbarInnerEl);
$pageEl.children('.navbar').remove();
} else {
router.$navbarEl.addClass('navbar-hidden');
}
}
const initOptions = {
route: router.currentRoute,
};
if (router.currentRoute && router.currentRoute.route && router.currentRoute.route.options) {
Utils.extend(initOptions, router.currentRoute.route.options);
}
router.currentPageEl = $pageEl[0];
if (router.dynamicNavbar && $navbarInnerEl.length) {
router.currentNavbarEl = $navbarInnerEl[0];
}
router.removeThemeElements($pageEl);
if (router.dynamicNavbar && $navbarInnerEl.length) {
router.removeThemeElements($navbarInnerEl);
}
if (initOptions.route.route.tab) {
router.tabLoad(initOptions.route.route.tab, Utils.extend({}, initOptions));
}
router.pageCallback('init', $pageEl, $navbarInnerEl, 'current', undefined, initOptions);
});
if (historyRestored) {
router.navigate(initUrl, {
pushState: false,
history: false,
animate: router.params.pushStateAnimateOnLoad,
once: {
pageAfterIn() {
if (router.history.length > 2) {
router.back({ preload: true });
}
},
},
});
} else {
router.history.push(initUrl);
router.saveHistory();
}
}
router.emit('local::init routerInit', router);
}
destroy() {
let router = this;
router.emit('local::destroy routerDestroy', router);
// Delete props & methods
Object.keys(router).forEach((routerProp) => {
router[routerProp] = null;
delete router[routerProp];
});
router = null;
}
}
var Router = {
name: 'router',
static: {
Router: Router$1,
},
instance: {
cache: {
xhr: [],
templates: [],
components: [],
},
},
create() {
const instance = this;
if (instance.app) {
// View Router
if (instance.params.router) {
instance.router = new Router$1(instance.app, instance);
}
} else {
// App Router
instance.router = new Router$1(instance);
}
},
};
class View extends Framework7Class {
constructor(appInstance, el, viewParams = {}) {
super(viewParams, [appInstance]);
const app = appInstance;
const $el = $(el);
const view = this;
const defaults = {
routes: [],
routesAdd: [],
};
// Default View params
view.params = Utils.extend(defaults, app.params.view, viewParams);
// Routes
if (view.params.routes.length > 0) {
view.routes = view.params.routes;
} else {
view.routes = [].concat(app.routes, view.params.routesAdd);
}
// Selector
let selector;
if (typeof el === 'string') selector = el;
else {
// Supposed to be HTMLElement or Dom7
selector = ($el.attr('id') ? `#${$el.attr('id')}` : '') + ($el.attr('class') ? `.${$el.attr('class').replace(/ /g, '.').replace('.active', '')}` : '');
}
// DynamicNavbar
let $navbarEl;
if (app.theme === 'ios' && view.params.iosDynamicNavbar && view.params.iosSeparateDynamicNavbar) {
$navbarEl = $el.children('.navbar').eq(0);
if ($navbarEl.length === 0) {
$navbarEl = $('<div class="navbar"></div>');
}
}
// View Props
Utils.extend(false, view, {
app,
$el,
el: $el[0],
name: view.params.name,
main: view.params.main || $el.hasClass('view-main'),
$navbarEl,
navbarEl: $navbarEl ? $navbarEl[0] : undefined,
selector,
history: [],
scrollHistory: {},
});
// Save in DOM
$el[0].f7View = view;
// Install Modules
view.useModules();
// Add to app
app.views.push(view);
if (view.main) {
app.views.main = view;
}
if (view.name) {
app.views[view.name] = view;
}
// Index
view.index = app.views.indexOf(view);
// View ID
let viewId;
if (view.name) {
viewId = `view_${view.name}`;
} else if (view.main) {
viewId = 'view_main';
} else {
viewId = `view_${view.index}`;
}
view.id = viewId;
// Init View
if (app.initialized) {
view.init();
} else {
app.on('init', () => {
view.init();
});
}
return view;
}
destroy() {
let view = this;
const app = view.app;
view.$el.trigger('view:beforedestroy', view);
view.emit('local::beforeDestroy viewBeforeDestroy', view);
if (view.main) {
app.views.main = null;
delete app.views.main;
} else if (view.name) {
app.views[view.name] = null;
delete app.views[view.name];
}
view.$el[0].f7View = null;
delete view.$el[0].f7View;
app.views.splice(app.views.indexOf(view), 1);
// Destroy Router
if (view.params.router && view.router) {
view.router.destroy();
}
view.emit('local::destroy viewDestroy', view);
// Delete props & methods
Object.keys(view).forEach((viewProp) => {
view[viewProp] = null;
delete view[viewProp];
});
view = null;
}
init() {
const view = this;
if (view.params.router) {
view.router.init();
}
}
}
// Use Router
View.use(Router);
function initClicks(app) {
function handleClicks(e) {
const clicked = $(e.target);
const clickedLink = clicked.closest('a');
const isLink = clickedLink.length > 0;
const url = isLink && clickedLink.attr('href');
const isTabLink = isLink && clickedLink.hasClass('tab-link') && (clickedLink.attr('data-tab') || (url && url.indexOf('#') === 0));
// Check if link is external
if (isLink) {
// eslint-disable-next-line
if (clickedLink.is(app.params.clicks.externalLinks) || (url && url.indexOf('javascript:') >= 0)) {
const target = clickedLink.attr('target');
if (url && (target === '_system' || target === '_blank')) {
e.preventDefault();
if (window.cordova && window.cordova.InAppBrowser) {
window.cordova.InAppBrowser.open(url, target);
} else {
window.open(url, target);
}
}
return;
}
}
// Modules Clicks
Object.keys(app.modules).forEach((moduleName) => {
const moduleClicks = app.modules[moduleName].clicks;
if (!moduleClicks) return;
Object.keys(moduleClicks).forEach((clickSelector) => {
const matchingClickedElement = clicked.closest(clickSelector).eq(0);
if (matchingClickedElement.length > 0) {
moduleClicks[clickSelector].call(app, matchingClickedElement, matchingClickedElement.dataset());
}
});
});
// Load Page
let clickedLinkData = {};
if (isLink) {
e.preventDefault();
clickedLinkData = clickedLink.dataset();
}
const validUrl = url && url.length > 0 && url !== '#' && !isTabLink;
const template = clickedLinkData.template;
if (validUrl || clickedLink.hasClass('back') || template) {
let view;
if (clickedLinkData.view) {
view = $(clickedLinkData.view)[0].f7View;
} else {
view = clicked.parents('.view')[0] && clicked.parents('.view')[0].f7View;
if (view && view.params.linksView) {
if (typeof view.params.linksView === 'string') view = $(view.params.linksView)[0].f7View;
else if (view.params.linksView instanceof View) view = view.params.linksView;
}
}
if (!view) {
if (app.views.main) view = app.views.main;
}
if (!view || !view.router) return;
if (clickedLink.hasClass('back')) view.router.back(url, clickedLinkData);
else view.router.navigate(url, clickedLinkData);
}
}
app.on('click', handleClicks);
// Prevent scrolling on overlays
function preventScrolling(e) {
e.preventDefault();
}
if (Support$1.touch && !Device.android) {
const activeListener = Support$1.passiveListener ? { passive: false, capture: false } : false;
$(document).on((app.params.fastClicks ? 'touchstart' : 'touchmove'), '.panel-backdrop, .dialog-backdrop, .preloader-backdrop, .popup-backdrop, .searchbar-backdrop', preventScrolling, activeListener);
}
}
var Clicks = {
name: 'clicks',
params: {
clicks: {
// External Links
externalLinks: '.external',
},
},
on: {
init() {
const app = this;
initClicks(app);
},
},
};
var History$2 = {
name: 'history',
static: {
history: History,
},
on: {
init() {
History.init(this);
},
},
};
const keyPrefix = 'f7storage-';
const Storage = {
get(key) {
return Utils.promise((resolve, reject) => {
try {
const value = JSON.parse(window.localStorage.getItem(`${keyPrefix}${key}`));
resolve(value);
} catch (e) {
reject(e);
}
});
},
set(key, value) {
return Utils.promise((resolve, reject) => {
try {
window.localStorage.setItem(`${keyPrefix}${key}`, JSON.stringify(value));
resolve();
} catch (e) {
reject(e);
}
});
},
remove(key) {
return Utils.promise((resolve, reject) => {
try {
window.localStorage.removeItem(`${keyPrefix}${key}`);
resolve();
} catch (e) {
reject(e);
}
});
},
clear() {
},
length() {
},
keys() {
return Utils.promise((resolve, reject) => {
try {
const keys = Object.keys(window.localStorage)
.filter(keyName => keyName.indexOf(keyPrefix) === 0)
.map(keyName => keyName.replace(keyPrefix, ''));
resolve(keys);
} catch (e) {
reject(e);
}
});
},
forEach(callback) {
return Utils.promise((resolve, reject) => {
try {
Object.keys(window.localStorage)
.filter(keyName => keyName.indexOf(keyPrefix) === 0)
.forEach((keyName, index) => {
const key = keyName.replace(keyPrefix, '');
Storage.get(key).then((value) => {
callback(key, value, index);
});
});
resolve();
} catch (e) {
reject(e);
}
});
},
};
var Storage$1 = {
name: 'storage',
static: {
Storage,
storage: Storage,
},
};
const Statusbar = {
hide() {
$('html').removeClass('with-statusbar');
if (Device.cordova && window.StatusBar) {
window.StatusBar.hide();
}
},
show() {
if (Device.cordova && window.StatusBar) {
window.StatusBar.show();
Utils.nextTick(() => {
if (Device.needsStatusbarOverlay()) {
$('html').addClass('with-statusbar');
}
});
return;
}
$('html').addClass('with-statusbar');
},
onClick() {
const app = this;
let pageContent;
if ($('.popup.modal-in').length > 0) {
// Check for opened popup
pageContent = $('.popup.modal-in').find('.page:not(.page-previous):not(.page-next):not(.cached)').find('.page-content');
} else if ($('.panel.panel-active').length > 0) {
// Check for opened panel
pageContent = $('.panel.panel-active').find('.page:not(.page-previous):not(.page-next):not(.cached)').find('.page-content');
} else if ($('.views > .view.tab-active').length > 0) {
// View in tab bar app layout
pageContent = $('.views > .view.tab-active').find('.page:not(.page-previous):not(.page-next):not(.cached)').find('.page-content');
} else if ($('.views').length > 0) {
pageContent = $('.views').find('.page:not(.page-previous):not(.page-next):not(.cached)').find('.page-content');
} else {
pageContent = app.root.children('.view').find('.page:not(.page-previous):not(.page-next):not(.cached)').find('.page-content');
}
if (pageContent && pageContent.length > 0) {
// Check for tab
if (pageContent.hasClass('tab')) {
pageContent = pageContent.parent('.tabs').children('.page-content.tab-active');
}
if (pageContent.length > 0) pageContent.scrollTop(0, 300);
}
},
setIosTextColor(color) {
if (Device.cordova && window.StatusBar) {
if (color === 'white') {
window.StatusBar.styleLightContent();
} else {
window.StatusBar.styleDefault();
}
}
},
setBackgroundColor(color) {
$('.statusbar').css('background-color', color);
if (Device.cordova && window.StatusBar) {
window.StatusBar.backgroundColorByHexString(color);
}
},
isVisible() {
if (Device.cordova && window.StatusBar) {
return window.StatusBar.isVisible;
}
return false;
},
iosOverlaysWebView(overlays = true) {
if (!Device.ios) return;
if (Device.cordova && window.StatusBar) {
window.StatusBar.overlaysWebView(overlays);
if (overlays) {
$('html').addClass('with-statusbar');
} else {
$('html').removeClass('with-statusbar');
}
}
},
checkOverlay() {
if (Device.needsStatusbarOverlay()) {
$('html').addClass('with-statusbar');
} else {
$('html').removeClass('with-statusbar');
}
},
init() {
const app = this;
const params = app.params.statusbar;
if (!params.enabled) return;
if (params.overlay === 'auto') {
if (Device.needsStatusbarOverlay()) {
$('html').addClass('with-statusbar');
}
if (Device.ios && (Device.cordova || Device.webView)) {
if (window.orientation === 0) {
app.once('resize', () => {
Statusbar.checkOverlay();
});
}
$(document).on('resume', () => {
Statusbar.checkOverlay();
}, false);
app.on('orientationchange resize', () => {
Statusbar.checkOverlay();
});
}
} else if (params.overlay === true) {
$('html').addClass('with-statusbar');
} else if (params.overlay === false) {
$('html').removeClass('with-statusbar');
}
if (Device.cordova && window.StatusBar) {
if (params.scrollTopOnClick) {
$(window).on('statusTap', Statusbar.onClick.bind(app));
}
if (params.iosOverlaysWebView) {
window.StatusBar.overlaysWebView(true);
} else {
window.StatusBar.overlaysWebView(false);
}
if (params.iosTextColor === 'white') {
window.StatusBar.styleLightContent();
} else {
window.StatusBar.styleDefault();
}
}
if (params.iosBackgroundColor && app.theme === 'ios') {
Statusbar.setBackgroundColor(params.iosBackgroundColor);
}
if (params.materialBackgroundColor && app.theme === 'md') {
Statusbar.setBackgroundColor(params.materialBackgroundColor);
}
},
};
var Statusbar$1 = {
name: 'statusbar',
params: {
statusbar: {
enabled: true,
overlay: 'auto',
scrollTopOnClick: true,
iosOverlaysWebView: true,
iosTextColor: 'black',
iosBackgroundColor: null,
materialBackgroundColor: null,
},
},
create() {
const app = this;
Utils.extend(app, {
statusbar: {
checkOverlay: Statusbar.checkOverlay,
hide: Statusbar.hide,
show: Statusbar.show,
iosOverlaysWebView: Statusbar.iosOverlaysWebView,
setIosTextColor: Statusbar.setIosTextColor,
setBackgroundColor: Statusbar.setBackgroundColor,
isVisible: Statusbar.isVisible,
init: Statusbar.init.bind(app),
},
});
},
on: {
init() {
const app = this;
Statusbar.init.call(app);
},
},
clicks: {
'.statusbar': function onStatusbarClick() {
const app = this;
if (!app.params.statusbar.enabled) return;
if (!app.params.statusbar.scrollTopOnClick) return;
Statusbar.onClick.call(app);
},
},
};
function getCurrentView(app) {
const popoverView = $('.popover.modal-in .view');
const popupView = $('.popup.modal-in .view');
const panelView = $('.panel.panel-active .view');
let appViews = $('.views');
if (appViews.length === 0) appViews = app.root;
// Find active view as tab
let appView = appViews.children('.view');
// Propably in tabs or split view
if (appView.length > 1) {
if (appView.hasClass('tab')) {
// Tabs
appView = appViews.children('.view.tab-active');
} else {
// Split View, leave appView intact
}
}
if (popoverView.length > 0 && popoverView[0].f7View) return popoverView[0].f7View;
if (popupView.length > 0 && popupView[0].f7View) return popupView[0].f7View;
if (panelView.length > 0 && panelView[0].f7View) return panelView[0].f7View;
if (appView.length > 0) {
if (appView.length === 1 && appView[0].f7View) return appView[0].f7View;
if (appView.length > 1) {
return app.views.main;
}
}
return undefined;
}
var View$2 = {
name: 'view',
params: {
view: {
name: undefined,
main: false,
router: true,
linksView: null,
stackPages: false,
xhrCache: true,
xhrCacheIgnore: [],
xhrCacheIgnoreGetParameters: false,
xhrCacheDuration: 1000 * 60 * 10, // Ten minutes
preloadPreviousPage: true,
uniqueHistory: false,
uniqueHistoryIgnoreGetParameters: false,
allowDuplicateUrls: false,
reloadPages: false,
removeElements: true,
removeElementsWithTimeout: false,
removeElementsTimeout: 0,
restoreScrollTopOnBack: true,
unloadTabContent: true,
passRouteQueryToRequest: true,
passRouteParamsToRequest: false,
// Swipe Back
iosSwipeBack: true,
iosSwipeBackAnimateShadow: true,
iosSwipeBackAnimateOpacity: true,
iosSwipeBackActiveArea: 30,
iosSwipeBackThreshold: 0,
// Push State
pushState: false,
pushStateRoot: undefined,
pushStateAnimate: true,
pushStateAnimateOnLoad: false,
pushStateSeparator: '#!',
pushStateOnLoad: true,
// Animate Pages
animate: true,
animateWithJS: false,
// iOS Dynamic Navbar
iosDynamicNavbar: true,
iosSeparateDynamicNavbar: true,
// Animate iOS Navbar Back Icon
iosAnimateNavbarBackIcon: true,
// Delays
iosPageLoadDelay: 0,
materialPageLoadDelay: 0,
},
},
static: {
View,
},
create() {
const app = this;
Utils.extend(app, {
views: Utils.extend([], {
create(el, params) {
return new View(app, el, params);
},
get(viewEl) {
const $viewEl = $(viewEl);
if ($viewEl.length && $viewEl[0].f7View) return $viewEl[0].f7View;
return undefined;
},
}),
});
Object.defineProperty(app.views, 'current', {
enumerable: true,
configurable: true,
get() {
return getCurrentView(app);
},
});
// Alias
app.view = app.views;
},
on: {
init() {
const app = this;
$('.view-init').each((index, viewEl) => {
if (viewEl.f7View) return;
const viewParams = $(viewEl).dataset();
app.views.create(viewEl, viewParams);
});
},
modalOpen(modal) {
const app = this;
modal.$el.find('.view-init').each((index, viewEl) => {
if (viewEl.f7View) return;
const viewParams = $(viewEl).dataset();
app.views.create(viewEl, viewParams);
});
},
modalBeforeDestroy(modal) {
if (!modal || !modal.$el) return;
modal.$el.find('.view-init').each((index, viewEl) => {
const view = viewEl.f7View;
if (!view) return;
view.destroy();
});
},
},
};
const Navbar = {
size(el) {
const app = this;
if (app.theme !== 'ios') return;
let $el = $(el);
if ($el.hasClass('navbar')) {
$el = $el.children('.navbar-inner').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
return;
}
if (
$el.hasClass('stacked') ||
$el.parents('.stacked').length > 0 ||
$el.parents('.tab:not(.tab-active)').length > 0 ||
$el.parents('.popup:not(.modal-in)').length > 0
) {
return;
}
const $viewEl = $el.parents('.view').eq(0);
const left = app.rtl ? $el.children('.right') : $el.children('.left');
const right = app.rtl ? $el.children('.left') : $el.children('.right');
const title = $el.children('.title');
const subnavbar = $el.children('.subnavbar');
const noLeft = left.length === 0;
const noRight = right.length === 0;
const leftWidth = noLeft ? 0 : left.outerWidth(true);
const rightWidth = noRight ? 0 : right.outerWidth(true);
const titleWidth = title.outerWidth(true);
const navbarStyles = $el.styles();
const navbarWidth = $el[0].offsetWidth;
const navbarInnerWidth = navbarWidth - parseInt(navbarStyles.paddingLeft, 10) - parseInt(navbarStyles.paddingRight, 10);
const isPrevious = $el.hasClass('navbar-previous');
const sliding = $el.hasClass('sliding');
let router;
let dynamicNavbar;
let separateNavbar;
let separateNavbarRightOffset = 0;
let separateNavbarLeftOffset = 0;
if ($viewEl.length > 0 && $viewEl[0].f7View) {
router = $viewEl[0].f7View.router;
dynamicNavbar = router && router.dynamicNavbar;
separateNavbar = router && router.separateNavbar;
if (!separateNavbar) {
separateNavbarRightOffset = navbarWidth;
separateNavbarLeftOffset = navbarWidth / 5;
}
}
let currLeft;
let diff;
if (noRight) {
currLeft = navbarInnerWidth - titleWidth;
}
if (noLeft) {
currLeft = 0;
}
if (!noLeft && !noRight) {
currLeft = ((navbarInnerWidth - rightWidth - titleWidth) + leftWidth) / 2;
}
let requiredLeft = (navbarInnerWidth - titleWidth) / 2;
if (navbarInnerWidth - leftWidth - rightWidth > titleWidth) {
if (requiredLeft < leftWidth) {
requiredLeft = leftWidth;
}
if (requiredLeft + titleWidth > navbarInnerWidth - rightWidth) {
requiredLeft = navbarInnerWidth - rightWidth - titleWidth;
}
diff = requiredLeft - currLeft;
} else {
diff = 0;
}
// RTL inverter
const inverter = app.rtl ? -1 : 1;
if (dynamicNavbar) {
if (title.hasClass('sliding') || (title.length > 0 && sliding)) {
let titleLeftOffset = (-(currLeft + diff) * inverter) + separateNavbarLeftOffset;
const titleRightOffset = ((navbarInnerWidth - currLeft - diff - titleWidth) * inverter) - separateNavbarRightOffset;
if (isPrevious) {
if (router && router.params.iosAnimateNavbarBackIcon) {
const activeNavbarBackLink = $el.parent().find('.navbar-current').children('.left.sliding').find('.back .icon ~ span');
if (activeNavbarBackLink.length > 0) {
titleLeftOffset += activeNavbarBackLink[0].offsetLeft;
}
}
}
title[0].f7NavbarLeftOffset = titleLeftOffset;
title[0].f7NavbarRightOffset = titleRightOffset;
}
if (!noLeft && (left.hasClass('sliding') || sliding)) {
if (app.rtl) {
left[0].f7NavbarLeftOffset = (-(navbarInnerWidth - left[0].offsetWidth) / 2) * inverter;
left[0].f7NavbarRightOffset = leftWidth * inverter;
} else {
left[0].f7NavbarLeftOffset = -leftWidth + separateNavbarLeftOffset;
left[0].f7NavbarRightOffset = ((navbarInnerWidth - left[0].offsetWidth) / 2) - separateNavbarRightOffset;
if (router && router.params.iosAnimateNavbarBackIcon && left.find('.back .icon').length > 0) {
left[0].f7NavbarRightOffset -= left.find('.back .icon')[0].offsetWidth;
}
}
}
if (!noRight && (right.hasClass('sliding') || sliding)) {
if (app.rtl) {
right[0].f7NavbarLeftOffset = -rightWidth * inverter;
right[0].f7NavbarRightOffset = ((navbarInnerWidth - right[0].offsetWidth) / 2) * inverter;
} else {
right[0].f7NavbarLeftOffset = (-(navbarInnerWidth - right[0].offsetWidth) / 2) + separateNavbarLeftOffset;
right[0].f7NavbarRightOffset = rightWidth - separateNavbarRightOffset;
}
}
if (subnavbar.length && (subnavbar.hasClass('sliding') || sliding)) {
subnavbar[0].f7NavbarLeftOffset = app.rtl ? subnavbar[0].offsetWidth : (-subnavbar[0].offsetWidth + separateNavbarLeftOffset);
subnavbar[0].f7NavbarRightOffset = (-subnavbar[0].f7NavbarLeftOffset - separateNavbarRightOffset) + separateNavbarLeftOffset;
}
}
// Title left
if (app.params.navbar.iosCenterTitle) {
let titleLeft = diff;
if (app.rtl && noLeft && noRight && title.length > 0) titleLeft = -titleLeft;
title.css({ left: `${titleLeft}px` });
}
},
hide(el, animate = true) {
let $el = $(el);
if ($el.hasClass('navbar-inner')) $el = $el.parents('.navbar');
if (!$el.length) return;
if ($el.hasClass('navbar-hidden')) return;
const className = `navbar-hidden${animate ? ' navbar-transitioning' : ''}`;
$el.transitionEnd(() => {
$el.removeClass('navbar-transitioning');
});
$el.addClass(className);
},
show(el = '.navbar-hidden', animate = true) {
let $el = $(el);
if ($el.hasClass('navbar-inner')) $el = $el.parents('.navbar');
if (!$el.length) return;
if (!$el.hasClass('navbar-hidden')) return;
if (animate) {
$el.addClass('navbar-transitioning');
$el.transitionEnd(() => {
$el.removeClass('navbar-transitioning');
});
}
$el.removeClass('navbar-hidden');
},
getElByPage(page) {
let $pageEl;
let $navbarEl;
let pageData;
if (page.$navbarEl || page.$el) {
pageData = page;
$pageEl = page.$el;
} else {
$pageEl = $(page);
if ($pageEl.length > 0) pageData = $pageEl[0].f7Page;
}
if (pageData && pageData.$navbarEl && pageData.$navbarEl.length > 0) {
$navbarEl = pageData.$navbarEl;
} else if ($pageEl) {
$navbarEl = $pageEl.children('.navbar').children('.navbar-inner');
}
if (!$navbarEl || ($navbarEl && $navbarEl.length === 0)) return undefined;
return $navbarEl[0];
},
getPageByEl(navbarInnerEl) {
let $navbarInnerEl = $(navbarInnerEl);
if ($navbarInnerEl.hasClass('navbar')) {
$navbarInnerEl = $navbarInnerEl.find('.navbar-inner');
if ($navbarInnerEl.length > 1) return undefined;
}
return $navbarInnerEl[0].f7Page;
},
initHideNavbarOnScroll(pageEl, navbarInnerEl) {
const app = this;
const $pageEl = $(pageEl);
const $navbarEl = $(navbarInnerEl || app.navbar.getElByPage(pageEl)).closest('.navbar');
let previousScrollTop;
let currentScrollTop;
let scrollHeight;
let offsetHeight;
let reachEnd;
let action;
let navbarHidden;
function handleScroll() {
const scrollContent = this;
if ($pageEl.hasClass('page-previous')) return;
currentScrollTop = scrollContent.scrollTop;
scrollHeight = scrollContent.scrollHeight;
offsetHeight = scrollContent.offsetHeight;
reachEnd = currentScrollTop + offsetHeight >= scrollHeight;
navbarHidden = $navbarEl.hasClass('navbar-hidden');
if (reachEnd) {
if (app.params.navbar.showOnPageScrollEnd) {
action = 'show';
}
} else if (previousScrollTop > currentScrollTop) {
if (app.params.navbar.showOnPageScrollTop || currentScrollTop <= 44) {
action = 'show';
} else {
action = 'hide';
}
} else if (currentScrollTop > 44) {
action = 'hide';
} else {
action = 'show';
}
if (action === 'show' && navbarHidden) {
app.navbar.show($navbarEl);
navbarHidden = false;
} else if (action === 'hide' && !navbarHidden) {
app.navbar.hide($navbarEl);
navbarHidden = true;
}
previousScrollTop = currentScrollTop;
}
$pageEl.on('scroll', '.page-content', handleScroll, true);
$pageEl[0].f7ScrollNavbarHandler = handleScroll;
},
};
var Navbar$1 = {
name: 'navbar',
create() {
const app = this;
Utils.extend(app, {
navbar: {
size: Navbar.size.bind(app),
hide: Navbar.hide.bind(app),
show: Navbar.show.bind(app),
getElByPage: Navbar.getElByPage.bind(app),
initHideNavbarOnScroll: Navbar.initHideNavbarOnScroll.bind(app),
},
});
},
params: {
navbar: {
scrollTopOnTitleClick: true,
iosCenterTitle: true,
hideOnPageScroll: false,
showOnPageScrollEnd: true,
showOnPageScrollTop: true,
},
},
on: {
'panelBreakpoint resize': function onResize() {
const app = this;
if (app.theme !== 'ios') return;
$('.navbar').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
},
pageBeforeRemove(page) {
if (page.$el[0].f7ScrollNavbarHandler) {
page.$el.off('scroll', '.page-content', page.$el[0].f7ScrollNavbarHandler, true);
}
},
pageBeforeIn(page) {
const app = this;
if (app.theme !== 'ios') return;
let $navbarEl;
const view = page.$el.parents('.view')[0].f7View;
const navbarInnerEl = app.navbar.getElByPage(page);
if (!navbarInnerEl) {
$navbarEl = page.$el.parents('.view').children('.navbar');
} else {
$navbarEl = $(navbarInnerEl).parents('.navbar');
}
if (page.$el.hasClass('no-navbar') || (view.router.dynamicNavbar && !navbarInnerEl)) {
const animate = !!(page.pageFrom && page.router.history.length > 0);
app.navbar.hide($navbarEl, animate);
} else {
app.navbar.show($navbarEl);
}
},
pageReinit(page) {
const app = this;
if (app.theme !== 'ios') return;
const $navbarEl = $(app.navbar.getElByPage(page));
if (!$navbarEl || $navbarEl.length === 0) return;
app.navbar.size($navbarEl);
},
pageInit(page) {
const app = this;
const $navbarEl = $(app.navbar.getElByPage(page));
if (!$navbarEl || $navbarEl.length === 0) return;
if (app.theme === 'ios') {
app.navbar.size($navbarEl);
}
if (
app.params.navbar.hideOnPageScroll ||
page.$el.find('.hide-navbar-on-scroll').length ||
page.$el.hasClass('hide-navbar-on-scroll') ||
page.$el.find('.hide-bars-on-scroll').length ||
page.$el.hasClass('hide-bars-on-scroll')
) {
if (
page.$el.find('.keep-navbar-on-scroll').length ||
page.$el.find('.keep-bars-on-scroll').length
) {
return;
}
app.navbar.initHideNavbarOnScroll(page.el, $navbarEl[0]);
}
},
modalOpen(modal) {
const app = this;
if (app.theme !== 'ios') return;
modal.$el.find('.navbar:not(.navbar-previous):not(.stacked)').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
},
panelOpen(panel) {
const app = this;
if (app.theme !== 'ios') return;
panel.$el.find('.navbar:not(.navbar-previous):not(.stacked)').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
},
panelSwipeOpen(panel) {
const app = this;
if (app.theme !== 'ios') return;
panel.$el.find('.navbar:not(.navbar-previous):not(.stacked)').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
},
tabShow(tabEl) {
const app = this;
$(tabEl).find('.navbar:not(.navbar-previous):not(.stacked)').each((index, navbarEl) => {
app.navbar.size(navbarEl);
});
},
},
clicks: {
'.navbar .title': function onTitleClick($clickedEl) {
const app = this;
if (!app.params.navbar.scrollTopOnTitleClick) return;
if ($clickedEl.closest('a').length > 0) {
return;
}
let pageContent;
// Find active page
const navbar = $clickedEl.parents('.navbar');
// Static Layout
pageContent = navbar.parents('.page-content');
if (pageContent.length === 0) {
// Fixed Layout
if (navbar.parents('.page').length > 0) {
pageContent = navbar.parents('.page').find('.page-content');
}
// Through Layout
if (pageContent.length === 0) {
if (navbar.nextAll('.page-current:not(.stacked)').length > 0) {
pageContent = navbar.nextAll('.page-current:not(.stacked)').find('.page-content');
}
}
}
if (pageContent && pageContent.length > 0) {
// Check for tab
if (pageContent.hasClass('tab')) {
pageContent = pageContent.parent('.tabs').children('.page-content.tab-active');
}
if (pageContent.length > 0) pageContent.scrollTop(0, 300);
}
},
},
};
const Toolbar = {
setHighlight(tabbarEl) {
const app = this;
if (app.theme !== 'md') return;
const $tabbarEl = $(tabbarEl);
if ($tabbarEl.length === 0 || !($tabbarEl.hasClass('tabbar') || $tabbarEl.hasClass('tabbar-labels'))) return;
if ($tabbarEl.find('.tab-link-highlight').length === 0) {
$tabbarEl.children('.toolbar-inner').append('<span class="tab-link-highlight"></span>');
}
const $highlightEl = $tabbarEl.find('.tab-link-highlight');
const $activeLink = $tabbarEl.find('.tab-link-active');
let highlightWidth;
let highlightTranslate;
if ($tabbarEl.hasClass('tabbar-scrollable')) {
highlightWidth = `${$activeLink[0].offsetWidth}px`;
highlightTranslate = `${$activeLink[0].offsetLeft}px`;
} else {
const activeIndex = $activeLink.index();
const tabLinksCount = $tabbarEl.find('.tab-link').length;
highlightWidth = `${100 / tabLinksCount}%`;
highlightTranslate = `${(app.rtl ? -activeIndex : activeIndex) * 100}%`;
}
$highlightEl
.css('width', highlightWidth)
.transform(`translate3d(${highlightTranslate},0,0)`);
},
init(tabbarEl) {
const app = this;
app.toolbar.setHighlight(tabbarEl);
},
hide(el, animate = true) {
const $el = $(el);
if ($el.hasClass('toolbar-hidden')) return;
const className = `toolbar-hidden${animate ? ' toolbar-transitioning' : ''}`;
$el.transitionEnd(() => {
$el.removeClass('toolbar-transitioning');
});
$el.addClass(className);
},
show(el, animate = true) {
const $el = $(el);
if (!$el.hasClass('toolbar-hidden')) return;
if (animate) {
$el.addClass('toolbar-transitioning');
$el.transitionEnd(() => {
$el.removeClass('toolbar-transitioning');
});
}
$el.removeClass('toolbar-hidden');
},
initHideToolbarOnScroll(pageEl) {
const app = this;
const $pageEl = $(pageEl);
let $toolbarEl = $pageEl.parents('.view').children('.toolbar');
if ($toolbarEl.length === 0) {
$toolbarEl = $pageEl.find('.toolbar');
}
if ($toolbarEl.length === 0) {
$toolbarEl = $pageEl.parents('.views').children('.tabbar, .tabbar-labels');
}
if ($toolbarEl.length === 0) {
return;
}
let previousScrollTop;
let currentScrollTop;
let scrollHeight;
let offsetHeight;
let reachEnd;
let action;
let toolbarHidden;
function handleScroll() {
const scrollContent = this;
if ($pageEl.hasClass('page-previous')) return;
currentScrollTop = scrollContent.scrollTop;
scrollHeight = scrollContent.scrollHeight;
offsetHeight = scrollContent.offsetHeight;
reachEnd = currentScrollTop + offsetHeight >= scrollHeight;
toolbarHidden = $toolbarEl.hasClass('toolbar-hidden');
if (reachEnd) {
if (app.params.toolbar.showOnPageScrollEnd) {
action = 'show';
}
} else if (previousScrollTop > currentScrollTop) {
if (app.params.toolbar.showOnPageScrollTop || currentScrollTop <= 44) {
action = 'show';
} else {
action = 'hide';
}
} else if (currentScrollTop > 44) {
action = 'hide';
} else {
action = 'show';
}
if (action === 'show' && toolbarHidden) {
app.toolbar.show($toolbarEl);
toolbarHidden = false;
} else if (action === 'hide' && !toolbarHidden) {
app.toolbar.hide($toolbarEl);
toolbarHidden = true;
}
previousScrollTop = currentScrollTop;
}
$pageEl.on('scroll', '.page-content', handleScroll, true);
$pageEl[0].f7ScrollToolbarHandler = handleScroll;
},
};
var Toolbar$1 = {
name: 'toolbar',
create() {
const app = this;
Utils.extend(app, {
toolbar: {
hide: Toolbar.hide.bind(app),
show: Toolbar.show.bind(app),
setHighlight: Toolbar.setHighlight.bind(app),
initHideToolbarOnScroll: Toolbar.initHideToolbarOnScroll.bind(app),
init: Toolbar.init.bind(app),
},
});
},
params: {
toolbar: {
hideOnPageScroll: false,
showOnPageScrollEnd: true,
showOnPageScrollTop: true,
},
},
on: {
pageBeforeRemove(page) {
if (page.$el[0].f7ScrollToolbarHandler) {
page.$el.off('scroll', '.page-content', page.$el[0].f7ScrollToolbarHandler, true);
}
},
pageBeforeIn(page) {
const app = this;
if (app.theme !== 'ios') return;
let $toolbarEl = page.$el.parents('.view').children('.toolbar');
if ($toolbarEl.length === 0) {
$toolbarEl = page.$el.find('.toolbar');
}
if ($toolbarEl.length === 0) {
$toolbarEl = page.$el.parents('.views').children('.tabbar, .tabbar-labels');
}
if ($toolbarEl.length === 0) {
return;
}
if (page.$el.hasClass('no-toolbar')) {
app.toolbar.hide($toolbarEl);
} else {
app.toolbar.show($toolbarEl);
}
},
pageInit(page) {
const app = this;
page.$el.find('.tabbar, .tabbar-labels').each((index, tabbarEl) => {
app.toolbar.init(tabbarEl);
});
if (
app.params.toolbar.hideOnPageScroll ||
page.$el.find('.hide-toolbar-on-scroll').length ||
page.$el.hasClass('hide-toolbar-on-scroll') ||
page.$el.find('.hide-bars-on-scroll').length ||
page.$el.hasClass('hide-bars-on-scroll')
) {
if (
page.$el.find('.keep-toolbar-on-scroll').length ||
page.$el.find('.keep-bars-on-scroll').length
) {
return;
}
app.toolbar.initHideToolbarOnScroll(page.el);
}
},
init() {
const app = this;
app.root.find('.tabbar, .tabbar-labels').each((index, tabbarEl) => {
app.toolbar.init(tabbarEl);
});
},
},
};
var Subnavbar = {
name: 'subnavbar',
on: {
pageInit(page) {
if (page.$navbarEl && page.$navbarEl.length && page.$navbarEl.find('.subnavbar').length) {
page.$el.addClass('page-with-subnavbar');
}
if (page.$el.find('.subnavbar').length) {
page.$el.addClass('page-with-subnavbar');
}
},
},
};
class TouchRipple$1 {
constructor($el, x, y) {
const ripple = this;
if (!$el) return undefined;
const box = $el[0].getBoundingClientRect();
const center = {
x: x - box.left,
y: y - box.top,
};
const width = box.width;
const height = box.height;
const diameter = Math.max((((height ** 2) + (width ** 2)) ** 0.5), 48);
ripple.$rippleWaveEl = $(`<div class="ripple-wave" style="width: ${diameter}px; height: ${diameter}px; margin-top:-${diameter / 2}px; margin-left:-${diameter / 2}px; left:${center.x}px; top:${center.y}px;"></div>`);
$el.prepend(ripple.$rippleWaveEl);
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
ripple._clientLeft = ripple.$rippleWaveEl[0].clientLeft;
ripple.rippleTransform = `translate3d(${-center.x + (width / 2)}px, ${-center.y + (height / 2)}px, 0) scale(1)`;
ripple.$rippleWaveEl.transform(ripple.rippleTransform);
return ripple;
}
onRemove() {
let ripple = this;
ripple.$rippleWaveEl.remove();
Object.keys(ripple).forEach((key) => {
ripple[key] = null;
delete ripple[key];
});
ripple = null;
}
remove() {
const ripple = this;
if (ripple.removing) return;
const $rippleWaveEl = this.$rippleWaveEl;
const rippleTransform = this.rippleTransform;
let removeTimeout = Utils.nextTick(() => {
ripple.onRemove();
}, 400);
ripple.removing = true;
$rippleWaveEl
.addClass('ripple-wave-fill')
.transform(rippleTransform.replace('scale(1)', 'scale(1.01)'))
.transitionEnd(() => {
clearTimeout(removeTimeout);
Utils.nextFrame(() => {
$rippleWaveEl
.addClass('ripple-wave-out')
.transform(rippleTransform.replace('scale(1)', 'scale(1.01)'));
removeTimeout = Utils.nextTick(() => {
ripple.onRemove();
}, 700);
$rippleWaveEl.transitionEnd(() => {
clearTimeout(removeTimeout);
ripple.onRemove();
});
});
});
}
}
var TouchRipple$$1 = {
name: 'touch-ripple',
static: {
TouchRipple: TouchRipple$1,
},
create() {
const app = this;
app.touchRipple = {
create(...args) {
return new TouchRipple$1(...args);
},
};
},
};
const openedModals = [];
const dialogsQueue = [];
function clearDialogsQueue() {
if (dialogsQueue.length === 0) return;
const dialog = dialogsQueue.shift();
dialog.open();
}
class Modal$1 extends Framework7Class {
constructor(app, params) {
super(params, [app]);
const modal = this;
const defaults = {};
// Extend defaults with modules params
modal.useModulesParams(defaults);
modal.params = Utils.extend(defaults, params);
// Install Modules
modal.useModules();
return this;
}
onOpen() {
const modal = this;
openedModals.push(modal);
$('html').addClass(`with-modal-${modal.type.toLowerCase()}`);
modal.$el.trigger(`modal:open ${modal.type.toLowerCase()}:open`, modal);
modal.emit(`local::open modalOpen ${modal.type}Open`, modal);
}
onOpened() {
const modal = this;
modal.$el.trigger(`modal:opened ${modal.type.toLowerCase()}:opened`, modal);
modal.emit(`local::opened modalOpened ${modal.type}Opened`, modal);
}
onClose() {
const modal = this;
if (!modal.type || !modal.$el) return;
openedModals.splice(openedModals.indexOf(modal), 1);
$('html').removeClass(`with-modal-${modal.type.toLowerCase()}`);
modal.$el.trigger(`modal:close ${modal.type.toLowerCase()}:close`, modal);
modal.emit(`local::close modalClose ${modal.type}Close`, modal);
}
onClosed() {
const modal = this;
if (!modal.type || !modal.$el) return;
modal.$el.removeClass('modal-out');
modal.$el.hide();
modal.$el.trigger(`modal:closed ${modal.type.toLowerCase()}:closed`, modal);
modal.emit(`local::closed modalClosed ${modal.type}Closed`, modal);
}
open(animateModal) {
const modal = this;
const app = modal.app;
const $el = modal.$el;
const $backdropEl = modal.$backdropEl;
const type = modal.type;
let animate = true;
if (typeof animateModal !== 'undefined') animate = animateModal;
else if (typeof modal.params.animate !== 'undefined') {
animate = modal.params.animate;
}
if (!$el || $el.hasClass('modal-in')) {
return modal;
}
if (type === 'dialog' && app.params.modal.queueDialogs) {
let pushToQueue;
if ($('.dialog.modal-in').length > 0) {
pushToQueue = true;
} else if (openedModals.length > 0) {
openedModals.forEach((openedModal) => {
if (openedModal.type === 'dialog') pushToQueue = true;
});
}
if (pushToQueue) {
dialogsQueue.push(modal);
return modal;
}
}
const $modalParentEl = $el.parent();
const wasInDom = $el.parents(document).length > 0;
if (app.params.modal.moveToRoot && !$modalParentEl.is(app.root)) {
app.root.append($el);
modal.once(`${type}Closed`, () => {
if (wasInDom) {
$modalParentEl.append($el);
} else {
$el.remove();
}
});
}
// Show Modal
$el.show();
// Set Dialog offset
if (type === 'dialog') {
$el.css({
marginTop: `${-Math.round($el.outerHeight() / 2)}px`,
});
}
// Emit open
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
modal._clientLeft = $el[0].clientLeft;
// Backdrop
if ($backdropEl) {
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
$backdropEl.addClass('backdrop-in');
}
// Modal
function transitionEnd() {
if ($el.hasClass('modal-out')) {
modal.onClosed();
} else {
modal.onOpened();
}
}
if (animate) {
$el
.animationEnd(() => {
transitionEnd();
});
$el
.transitionEnd(() => {
transitionEnd();
});
$el
.removeClass('modal-out not-animated')
.addClass('modal-in');
modal.onOpen();
} else {
$el.removeClass('modal-out').addClass('modal-in not-animated');
modal.onOpen();
modal.onOpened();
}
return modal;
}
close(animateModal) {
const modal = this;
const $el = modal.$el;
const $backdropEl = modal.$backdropEl;
let animate = true;
if (typeof animateModal !== 'undefined') animate = animateModal;
else if (typeof modal.params.animate !== 'undefined') {
animate = modal.params.animate;
}
if (!$el || !$el.hasClass('modal-in')) {
return modal;
}
// backdrop
if ($backdropEl) {
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
$backdropEl.removeClass('backdrop-in');
}
// Modal
$el[animate ? 'removeClass' : 'addClass']('not-animated');
function transitionEnd() {
if ($el.hasClass('modal-out')) {
modal.onClosed();
} else {
modal.onOpened();
}
}
if (animate) {
$el
.animationEnd(() => {
transitionEnd();
});
$el
.transitionEnd(() => {
transitionEnd();
});
$el
.removeClass('modal-in')
.addClass('modal-out');
// Emit close
modal.onClose();
} else {
$el
.addClass('not-animated')
.removeClass('modal-in')
.addClass('modal-out');
// Emit close
modal.onClose();
modal.onClosed();
}
if (modal.type === 'dialog') {
clearDialogsQueue();
}
return modal;
}
destroy() {
const modal = this;
if (modal.destroyed) return;
modal.emit(`local::beforeDestroy modalBeforeDestroy ${modal.type}BeforeDestroy`, modal);
if (modal.$el) {
modal.$el.trigger(`modal:beforedestroy ${modal.type.toLowerCase()}:beforedestroy`, modal);
if (modal.$el.length && modal.$el[0].f7Modal) {
delete modal.$el[0].f7Modal;
}
}
Utils.deleteProps(modal);
modal.destroyed = true;
}
}
class CustomModal extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
backdrop: true,
closeByBackdropClick: true,
on: {},
}, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const customModal = this;
customModal.params = extendedParams;
// Find Element
let $el;
if (!customModal.params.el) {
$el = $(customModal.params.content);
} else {
$el = $(customModal.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return customModal.destroy();
}
let $backdropEl;
if (customModal.params.backdrop) {
$backdropEl = app.root.children('.custom-modal-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="custom-modal-backdrop"></div>');
app.root.append($backdropEl);
}
}
function handleClick(e) {
if (!customModal || customModal.destroyed) return;
if ($backdropEl && e.target === $backdropEl[0]) {
customModal.close();
}
}
customModal.on('customModalOpened', () => {
if (customModal.params.closeByBackdropClick && customModal.params.backdrop) {
app.on('click', handleClick);
}
});
customModal.on('customModalClose', () => {
if (customModal.params.closeByBackdropClick && customModal.params.backdrop) {
app.off('click', handleClick);
}
});
Utils.extend(customModal, {
app,
$el,
el: $el[0],
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'customModal',
});
$el[0].f7Modal = customModal;
return customModal;
}
}
var Modal = {
name: 'modal',
static: {
Modal: Modal$1,
CustomModal,
},
create() {
const app = this;
app.customModal = {
create(params) {
return new CustomModal(app, params);
},
};
},
params: {
modal: {
moveToRoot: true,
queueDialogs: true,
},
},
};
class Dialog$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
title: app.params.dialog.title,
text: undefined,
content: '',
buttons: [],
verticalButtons: false,
onClick: undefined,
cssClass: undefined,
on: {},
}, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const dialog = this;
const { title, text, content, buttons, verticalButtons, cssClass } = extendedParams;
dialog.params = extendedParams;
// Find Element
let $el;
if (!dialog.params.el) {
const dialogClasses = ['dialog'];
if (buttons.length === 0) dialogClasses.push('dialog-no-buttons');
if (buttons.length > 0) dialogClasses.push(`dialog-buttons-${buttons.length}`);
if (verticalButtons) dialogClasses.push('dialog-buttons-vertical');
if (cssClass) dialogClasses.push(cssClass);
let buttonsHTML = '';
if (buttons.length > 0) {
buttonsHTML = `
<div class="dialog-buttons">
${buttons.map(button => `
<span class="dialog-button${button.bold ? ' dialog-button-bold' : ''}${button.color ? ` color-${button.color}` : ''}${button.cssClass ? ` ${button.cssClass}` : ''}">${button.text}</span>
`).join('')}
</div>
`;
}
const dialogHtml = `
<div class="${dialogClasses.join(' ')}">
<div class="dialog-inner">
${title ? `<div class="dialog-title">${title}</div>` : ''}
${text ? `<div class="dialog-text">${text}</div>` : ''}
${content}
</div>
${buttonsHTML}
</div>
`;
$el = $(dialogHtml);
} else {
$el = $(dialog.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return dialog.destroy();
}
let $backdropEl = app.root.children('.dialog-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="dialog-backdrop"></div>');
app.root.append($backdropEl);
}
// Assign events
function buttonOnClick(e) {
const buttonEl = this;
const index = $(buttonEl).index();
const button = buttons[index];
if (button.onClick) button.onClick(dialog, e);
if (dialog.params.onClick) dialog.params.onClick(dialog, index);
if (button.close !== false) dialog.close();
}
if (buttons && buttons.length > 0) {
$el.find('.dialog-button').each((index, buttonEl) => {
$(buttonEl).on('click', buttonOnClick);
});
dialog.on('close', () => {
$el.find('.dialog-button').each((index, buttonEl) => {
$(buttonEl).off('click', buttonOnClick);
});
});
}
Utils.extend(dialog, {
app,
$el,
el: $el[0],
$backdropEl,
backdropEl: $backdropEl[0],
type: 'dialog',
setProgress(progress, duration) {
app.progressbar.set($el.find('.progressbar'), progress, duration);
return dialog;
},
setText(newText) {
let $textEl = $el.find('.dialog-text');
if ($textEl.length === 0) {
$textEl = $('<div class="dialog-text"></div>');
if (typeof title !== 'undefined') {
$textEl.insertAfter($el.find('.dialog-title'));
} else {
$el.find('.dialog-inner').prepend($textEl);
}
}
$textEl.html(newText);
dialog.params.text = newText;
return dialog;
},
setTitle(newTitle) {
let $titleEl = $el.find('.dialog-title');
if ($titleEl.length === 0) {
$titleEl = $('<div class="dialog-title"></div>');
$el.find('.dialog-inner').prepend($titleEl);
}
$titleEl.html(newTitle);
dialog.params.title = newTitle;
return dialog;
},
});
$el[0].f7Modal = dialog;
return dialog;
}
}
var ConstructorMethods = function (parameters = {}) {
const {
defaultSelector,
constructor,
domProp,
app,
addMethods,
} = parameters;
const methods = {
create(...args) {
if (app) return new constructor(app, ...args);
return new constructor(...args);
},
get(el = defaultSelector) {
if (el instanceof constructor) return el;
const $el = $(el);
if ($el.length === 0) return undefined;
return $el[0][domProp];
},
destroy(el) {
const instance = methods.get(el);
if (instance && instance.destroy) return instance.destroy();
return undefined;
},
};
if (addMethods && Array.isArray(addMethods)) {
addMethods.forEach((methodName) => {
methods[methodName] = (el = defaultSelector, ...args) => {
const instance = methods.get(el);
if (instance && instance[methodName]) return instance[methodName](...args);
return undefined;
};
});
}
return methods;
};
var ModalMethods = function (parameters = {}) {
const { defaultSelector, constructor, app } = parameters;
const methods = Utils.extend(
ConstructorMethods({
defaultSelector,
constructor,
app,
domProp: 'f7Modal',
}),
{
open(el, animate) {
const $el = $(el);
let instance = $el[0].f7Modal;
if (!instance) instance = new constructor(app, { el: $el });
return instance.open(animate);
},
close(el = defaultSelector, animate) {
const $el = $(el);
if ($el.length === 0) return undefined;
let instance = $el[0].f7Modal;
if (!instance) instance = new constructor(app, { el: $el });
return instance.close(animate);
},
}
);
return methods;
};
var Dialog = {
name: 'dialog',
params: {
dialog: {
title: undefined,
buttonOk: 'OK',
buttonCancel: 'Cancel',
usernamePlaceholder: 'Username',
passwordPlaceholder: 'Password',
preloaderTitle: 'Loading... ',
progressTitle: 'Loading... ',
closeByBackdropClick: false,
},
},
static: {
Dialog: Dialog$1,
},
create() {
const app = this;
const defaultDialogTitle = app.params.dialog.title || app.name;
app.dialog = Utils.extend(
ModalMethods({
app,
constructor: Dialog$1,
defaultSelector: '.dialog.modal-in',
}),
{
// Shortcuts
alert(...args) {
let [text, title, callbackOk] = args;
if (args.length === 2 && typeof args[1] === 'function') {
[text, callbackOk, title] = args;
}
return new Dialog$1(app, {
title: typeof title === 'undefined' ? defaultDialogTitle : title,
text,
buttons: [{
text: app.params.dialog.buttonOk,
bold: true,
onClick: callbackOk,
}],
}).open();
},
prompt(...args) {
let [text, title, callbackOk, callbackCancel] = args;
if (typeof args[1] === 'function') {
[text, callbackOk, callbackCancel, title] = args;
}
return new Dialog$1(app, {
title: typeof title === 'undefined' ? defaultDialogTitle : title,
text,
content: '<div class="dialog-input-field item-input"><div class="item-input-wrap"><input type="text" class="dialog-input"></div></div>',
buttons: [
{
text: app.params.dialog.buttonCancel,
},
{
text: app.params.dialog.buttonOk,
bold: true,
},
],
onClick(dialog, index) {
const inputValue = dialog.$el.find('.dialog-input').val();
if (index === 0 && callbackCancel) callbackCancel(inputValue);
if (index === 1 && callbackOk) callbackOk(inputValue);
},
}).open();
},
confirm(...args) {
let [text, title, callbackOk, callbackCancel] = args;
if (typeof args[1] === 'function') {
[text, callbackOk, callbackCancel, title] = args;
}
return new Dialog$1(app, {
title: typeof title === 'undefined' ? defaultDialogTitle : title,
text,
buttons: [
{
text: app.params.dialog.buttonCancel,
onClick: callbackCancel,
},
{
text: app.params.dialog.buttonOk,
bold: true,
onClick: callbackOk,
},
],
}).open();
},
login(...args) {
let [text, title, callbackOk, callbackCancel] = args;
if (typeof args[1] === 'function') {
[text, callbackOk, callbackCancel, title] = args;
}
return new Dialog$1(app, {
title: typeof title === 'undefined' ? defaultDialogTitle : title,
text,
content: `
<div class="dialog-input-field dialog-input-double item-input">
<div class="item-input-wrap">
<input type="text" name="dialog-username" placeholder="${app.params.dialog.usernamePlaceholder}" class="dialog-input">
</div>
</div>
<div class="dialog-input-field dialog-input-double item-input">
<div class="item-input-wrap">
<input type="password" name="dialog-password" placeholder="${app.params.dialog.passwordPlaceholder}" class="dialog-input">
</div>
</div>`,
buttons: [
{
text: app.params.dialog.buttonCancel,
},
{
text: app.params.dialog.buttonOk,
bold: true,
},
],
onClick(dialog, index) {
const username = dialog.$el.find('[name="dialog-username"]').val();
const password = dialog.$el.find('[name="dialog-password"]').val();
if (index === 0 && callbackCancel) callbackCancel(username, password);
if (index === 1 && callbackOk) callbackOk(username, password);
},
}).open();
},
password(...args) {
let [text, title, callbackOk, callbackCancel] = args;
if (typeof args[1] === 'function') {
[text, callbackOk, callbackCancel, title] = args;
}
return new Dialog$1(app, {
title: typeof title === 'undefined' ? defaultDialogTitle : title,
text,
content: `
<div class="dialog-input-field item-input">
<div class="item-input-wrap">
<input type="password" name="dialog-password" placeholder="${app.params.dialog.passwordPlaceholder}" class="dialog-input">
</div>
</div>`,
buttons: [
{
text: app.params.dialog.buttonCancel,
},
{
text: app.params.dialog.buttonOk,
bold: true,
},
],
onClick(dialog, index) {
const password = dialog.$el.find('[name="dialog-password"]').val();
if (index === 0 && callbackCancel) callbackCancel(password);
if (index === 1 && callbackOk) callbackOk(password);
},
}).open();
},
preloader(title) {
const preloaderInner = app.theme !== 'md' ? '' : Utils.mdPreloaderContent;
return new Dialog$1(app, {
title: typeof title === 'undefined' ? app.params.dialog.preloaderTitle : title,
content: `<div class="preloader">${preloaderInner}</div>`,
cssClass: 'dialog-preloader',
}).open();
},
progress(...args) {
let [title, progress, color] = args;
if (args.length === 2) {
if (typeof args[0] === 'number') {
[progress, color, title] = args;
} else if (typeof args[0] === 'string' && typeof args[1] === 'string') {
[title, color, progress] = args;
}
} else if (args.length === 1) {
if (typeof args[0] === 'number') {
[progress, title, color] = args;
}
}
const infinite = typeof progress === 'undefined';
const dialog = new Dialog$1(app, {
title: typeof title === 'undefined' ? app.params.dialog.progressTitle : title,
cssClass: 'dialog-progress',
content: `
<div class="progressbar${infinite ? '-infinite' : ''}${color ? ` color-${color}` : ''}">
${!infinite ? '<span></span>' : ''}
</div>
`,
});
if (!infinite) dialog.setProgress(progress);
return dialog.open();
},
}
);
},
clicks: {
'.dialog-backdrop': function closeDialog() {
const app = this;
if (!app.params.dialog.closeByBackdropClick) return;
app.dialog.close();
},
},
};
class Popup$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend(
{ on: {} },
app.params.popup,
params
);
// Extends with open/close Modal methods;
super(app, extendedParams);
const popup = this;
popup.params = extendedParams;
// Find Element
let $el;
if (!popup.params.el) {
$el = $(popup.params.content);
} else {
$el = $(popup.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return popup.destroy();
}
let $backdropEl;
if (popup.params.backdrop) {
$backdropEl = app.root.children('.popup-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="popup-backdrop"></div>');
app.root.append($backdropEl);
}
}
Utils.extend(popup, {
app,
$el,
el: $el[0],
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'popup',
});
$el[0].f7Modal = popup;
return popup;
}
}
var Popup = {
name: 'popup',
params: {
popup: {
backdrop: true,
closeByBackdropClick: true,
},
},
static: {
Popup: Popup$1,
},
create() {
const app = this;
app.popup = ModalMethods({
app,
constructor: Popup$1,
defaultSelector: '.popup.modal-in',
});
},
clicks: {
'.popup-open': function openPopup($clickedEl, data = {}) {
const app = this;
app.popup.open(data.popup, data.animate);
},
'.popup-close': function closePopup($clickedEl, data = {}) {
const app = this;
app.popup.close(data.popup, data.animate);
},
'.popup-backdrop': function closePopup() {
const app = this;
if (!app.params.popup.closeByBackdropClick) return;
app.popup.close();
},
},
};
class LoginScreen$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
on: {},
}, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const loginScreen = this;
loginScreen.params = extendedParams;
// Find Element
let $el;
if (!loginScreen.params.el) {
$el = $(loginScreen.params.content);
} else {
$el = $(loginScreen.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return loginScreen.destroy();
}
Utils.extend(loginScreen, {
app,
$el,
el: $el[0],
type: 'loginScreen',
});
$el[0].f7Modal = loginScreen;
return loginScreen;
}
}
var LoginScreen = {
name: 'loginScreen',
static: {
LoginScreen: LoginScreen$1,
},
create() {
const app = this;
app.loginScreen = ModalMethods({
app,
constructor: LoginScreen$1,
defaultSelector: '.login-screen.modal-in',
});
},
clicks: {
'.login-screen-open': function openLoginScreen($clickedEl, data = {}) {
const app = this;
app.loginScreen.open(data.loginScreen, data.animate);
},
'.login-screen-close': function closeLoginScreen($clickedEl, data = {}) {
const app = this;
app.loginScreen.close(data.loginScreen, data.animate);
},
},
};
class Popover$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend(
{ on: {} },
app.params.popover,
params
);
// Extends with open/close Modal methods;
super(app, extendedParams);
const popover = this;
popover.params = extendedParams;
// Find Element
let $el;
if (!popover.params.el) {
$el = $(popover.params.content);
} else {
$el = $(popover.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
// Find Target
const $targetEl = $(popover.params.targetEl).eq(0);
if ($el.length === 0) {
return popover.destroy();
}
// Backdrop
let $backdropEl;
if (popover.params.backdrop) {
$backdropEl = app.root.children('.popover-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="popover-backdrop"></div>');
app.root.append($backdropEl);
}
}
// Find Angle
let $angleEl;
if ($el.find('.popover-angle').length === 0) {
$angleEl = $('<div class="popover-angle"></div>');
$el.prepend($angleEl);
} else {
$angleEl = $el.find('.popover-angle');
}
// Open
const originalOpen = popover.open;
Utils.extend(popover, {
app,
$el,
el: $el[0],
$targetEl,
targetEl: $targetEl[0],
$angleEl,
angleEl: $angleEl[0],
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'popover',
open(...args) {
let [targetEl, animate] = args;
if (typeof args[0] === 'boolean') [animate, targetEl] = args;
if (targetEl) {
popover.$targetEl = $(targetEl);
popover.targetEl = popover.$targetEl[0];
}
originalOpen.call(popover, animate);
},
});
function handleResize() {
popover.resize();
}
popover.on('popoverOpen', () => {
popover.resize();
app.on('resize', handleResize);
popover.on('popoverClose popoverBeforeDestroy', () => {
app.off('resize', handleResize);
});
});
function handleClick(e) {
const target = e.target;
if ($(target).closest(popover.el).length === 0) {
popover.close();
}
}
popover.on('popoverOpened', () => {
if (popover.params.closeByOutsideClick && !popover.params.backdrop) {
app.on('click', handleClick);
}
});
popover.on('popoverClose', () => {
if (popover.params.closeByOutsideClick && !popover.params.backdrop) {
app.off('click', handleClick);
}
});
$el[0].f7Modal = popover;
return popover;
}
resize() {
const popover = this;
const { app, $el, $targetEl, $angleEl } = popover;
const { targetX, targetY } = popover.params;
$el.css({ left: '', top: '' });
const [width, height] = [$el.width(), $el.height()];
let angleSize = 0;
let angleLeft;
let angleTop;
if (app.theme === 'ios') {
$angleEl.removeClass('on-left on-right on-top on-bottom').css({ left: '', top: '' });
angleSize = $angleEl.width() / 2;
} else {
$el.removeClass('popover-on-left popover-on-right popover-on-top popover-on-bottom').css({ left: '', top: '' });
}
let targetWidth;
let targetHeight;
let targetOffsetLeft;
let targetOffsetTop;
if ($targetEl && $targetEl.length > 0) {
targetWidth = $targetEl.outerWidth();
targetHeight = $targetEl.outerHeight();
const targetOffset = $targetEl.offset();
targetOffsetLeft = targetOffset.left - app.left;
targetOffsetTop = targetOffset.top - app.top;
const targetParentPage = $targetEl.parents('.page');
if (targetParentPage.length > 0) {
targetOffsetTop -= targetParentPage[0].scrollTop;
}
} else if (typeof targetX !== 'undefined' && targetY !== 'undefined') {
targetOffsetLeft = targetX;
targetOffsetTop = targetY;
targetWidth = popover.params.targetWidth || 0;
targetHeight = popover.params.targetHeight || 0;
}
let [left, top, diff] = [0, 0, 0];
// Top Position
let position = app.theme === 'md' ? 'bottom' : 'top';
if (app.theme === 'md') {
if (height < app.height - targetOffsetTop - targetHeight) {
// On bottom
position = 'bottom';
top = targetOffsetTop;
} else if (height < targetOffsetTop) {
// On top
top = (targetOffsetTop - height) + targetHeight;
position = 'top';
} else {
// On middle
position = 'bottom';
top = targetOffsetTop;
}
if (top <= 0) {
top = 8;
} else if (top + height >= app.height) {
top = app.height - height - 8;
}
// Horizontal Position
left = (targetOffsetLeft + targetWidth) - width - 8;
if (left + width >= app.width - 8) {
left = (targetOffsetLeft + targetWidth) - width - 8;
}
if (left < 8) {
left = 8;
}
if (position === 'top') {
$el.addClass('popover-on-top');
}
if (position === 'bottom') {
$el.addClass('popover-on-bottom');
}
} else {
if ((height + angleSize) < targetOffsetTop) {
// On top
top = targetOffsetTop - height - angleSize;
} else if ((height + angleSize) < app.height - targetOffsetTop - targetHeight) {
// On bottom
position = 'bottom';
top = targetOffsetTop + targetHeight + angleSize;
} else {
// On middle
position = 'middle';
top = ((targetHeight / 2) + targetOffsetTop) - (height / 2);
diff = top;
if (top <= 0) {
top = 5;
} else if (top + height >= app.height) {
top = app.height - height - 5;
}
diff -= top;
}
// Horizontal Position
if (position === 'top' || position === 'bottom') {
left = ((targetWidth / 2) + targetOffsetLeft) - (width / 2);
diff = left;
if (left < 5) left = 5;
if (left + width > app.width) left = app.width - width - 5;
if (left < 0) left = 0;
if (position === 'top') {
$angleEl.addClass('on-bottom');
}
if (position === 'bottom') {
$angleEl.addClass('on-top');
}
diff -= left;
angleLeft = ((width / 2) - angleSize) + diff;
angleLeft = Math.max(Math.min(angleLeft, width - (angleSize * 2) - 13), 13);
$angleEl.css({ left: `${angleLeft}px` });
} else if (position === 'middle') {
left = targetOffsetLeft - width - angleSize;
$angleEl.addClass('on-right');
if (left < 5 || (left + width > app.width)) {
if (left < 5) left = targetOffsetLeft + targetWidth + angleSize;
if (left + width > app.width) left = app.width - width - 5;
$angleEl.removeClass('on-right').addClass('on-left');
}
angleTop = ((height / 2) - angleSize) + diff;
angleTop = Math.max(Math.min(angleTop, height - (angleSize * 2) - 13), 13);
$angleEl.css({ top: `${angleTop}px` });
}
}
// Apply Styles
$el.css({ top: `${top}px`, left: `${left}px` });
}
}
var Popover = {
name: 'popover',
params: {
popover: {
closeByBackdropClick: true,
closeByOutsideClick: true,
backdrop: true,
},
},
static: {
Popover: Popover$1,
},
create() {
const app = this;
app.popover = Utils.extend(
ModalMethods({
app,
constructor: Popover$1,
defaultSelector: '.popover.modal-in',
}),
{
open(popoverEl, targetEl, animate) {
const $popoverEl = $(popoverEl);
let popover = $popoverEl[0].f7Modal;
if (!popover) popover = new Popover$1(app, { el: $popoverEl, targetEl });
return popover.open(targetEl, animate);
},
}
);
},
clicks: {
'.popover-open': function openPopover($clickedEl, data = {}) {
const app = this;
app.popover.open(data.popover, $clickedEl, data.animate);
},
'.popover-close': function closePopover($clickedEl, data = {}) {
const app = this;
app.popover.close(data.popover, data.animate);
},
'.popover-backdrop': function closePopover() {
const app = this;
if (!app.params.popover.closeByBackdropClick) return;
app.popover.close();
},
},
};
/* eslint indent: ["off"] */
class Actions$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend(
{ on: {} },
app.params.actions,
params
);
// Extends with open/close Modal methods;
super(app, extendedParams);
const actions = this;
actions.params = extendedParams;
// Buttons
let groups;
if (actions.params.buttons) {
groups = actions.params.buttons;
if (!Array.isArray(groups[0])) groups = [groups];
}
actions.groups = groups;
// Find Element
let $el;
if (actions.params.el) {
$el = $(actions.params.el);
} else if (actions.params.content) {
$el = $(actions.params.content);
} else if (actions.params.buttons) {
if (actions.params.convertToPopover) {
actions.popoverHtml = actions.renderPopover();
}
actions.actionsHtml = actions.render();
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el && $el.length === 0 && !(actions.actionsHtml || actions.popoverHtml)) {
return actions.destroy();
}
// Backdrop
let $backdropEl;
if (actions.params.backdrop) {
$backdropEl = app.root.children('.actions-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="actions-backdrop"></div>');
app.root.append($backdropEl);
}
}
const originalOpen = actions.open;
const originalClose = actions.close;
let popover;
function buttonOnClick(e) {
const buttonEl = this;
let buttonIndex;
let groupIndex;
if ($(buttonEl).hasClass('item-link')) {
buttonIndex = $(buttonEl).parents('li').index();
groupIndex = $(buttonEl).parents('.list').index();
} else {
buttonIndex = $(buttonEl).index();
groupIndex = $(buttonEl).parents('.actions-group').index();
}
const button = groups[groupIndex][buttonIndex];
if (button.onClick) button.onClick(actions, e);
if (actions.params.onClick) actions.params.onClick(actions, e);
if (button.close !== false) actions.close();
}
actions.open = function open(animate) {
let convertToPopover = false;
const { targetEl, targetX, targetY, targetWidth, targetHeight } = actions.params;
if (actions.params.convertToPopover && (targetEl || (targetX !== undefined && targetY !== undefined))) {
// Popover
if (
actions.params.forceToPopover ||
(app.device.ios && app.device.ipad) ||
app.width >= 768
) {
convertToPopover = true;
}
}
if (convertToPopover && actions.popoverHtml) {
popover = app.popover.create({
content: actions.popoverHtml,
backdrop: actions.params.backdrop,
targetEl,
targetX,
targetY,
targetWidth,
targetHeight,
});
popover.open(animate);
popover.once('popoverOpened', () => {
popover.$el.find('.item-link').each((groupIndex, buttonEl) => {
$(buttonEl).on('click', buttonOnClick);
});
});
popover.once('popoverClosed', () => {
popover.$el.find('.item-link').each((groupIndex, buttonEl) => {
$(buttonEl).off('click', buttonOnClick);
});
Utils.nextTick(() => {
popover.destroy();
popover = undefined;
});
});
} else {
actions.$el = actions.actionsHtml ? $(actions.actionsHtml) : actions.$el;
actions.$el[0].f7Modal = actions;
actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
$(buttonEl).on('click', buttonOnClick);
});
actions.once('actionsClosed', () => {
actions.$el.find('.list-button').each((groupIndex, buttonEl) => {
$(buttonEl).off('click', buttonOnClick);
});
});
originalOpen.call(actions, animate);
}
return actions;
};
actions.close = function close(animate) {
if (popover) {
popover.close(animate);
} else {
originalClose.call(actions, animate);
}
return actions;
};
Utils.extend(actions, {
app,
$el,
el: $el ? $el[0] : undefined,
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'actions',
});
if ($el) {
$el[0].f7Modal = actions;
}
return actions;
}
render() {
const actions = this;
if (actions.params.render) return actions.params.render.call(actions, actions);
const { groups } = actions;
return `
<div class="actions-modal${actions.params.grid ? ' actions-grid' : ''}">
${groups.map(group =>
`<div class="actions-group">
${group.map((button) => {
const buttonClasses = [`actions-${button.label ? 'label' : 'button'}`];
const { color, bg, bold, disabled, label, text, icon } = button;
if (color) buttonClasses.push(`color-${color}`);
if (bg) buttonClasses.push(`bg-${color}`);
if (bold) buttonClasses.push('actions-button-bold');
if (disabled) buttonClasses.push('disabled');
if (label) {
return `<div class="${buttonClasses.join(' ')}">${text}</div>`;
}
return `
<div class="${buttonClasses.join(' ')}">
${icon ? `<div class="actions-button-media">${icon}</div>` : ''}
<div class="actions-button-text">${text}</div>
</div>`.trim();
}).join('')}
</div>`).join('')}
</div>
`.trim();
}
renderPopover() {
const actions = this;
if (actions.params.renderPopover) return actions.params.renderPopover.call(actions, actions);
const { groups } = actions;
return `
<div class="popover popover-from-actions">
<div class="popover-inner">
${groups.map(group => `
<div class="list">
<ul>
${group.map((button) => {
const itemClasses = [];
const { color, bg, bold, disabled, label, text, icon } = button;
if (color) itemClasses.push(`color-${color}`);
if (bg) itemClasses.push(`bg-${bg}`);
if (bold) itemClasses.push('popover-from-actions-bold');
if (disabled) itemClasses.push('disabled');
if (label) {
itemClasses.push('popover-from-actions-label');
return `<li class="${itemClasses.join(' ')}">${text}</li>`;
}
itemClasses.push('item-link');
if (icon) {
itemClasses.push('item-content');
return `
<li>
<a class="${itemClasses.join(' ')}">
<div class="item-media">
${icon}
</div>
<div class="item-inner">
<div class="item-title">
${text}
</div>
</div>
</a>
</li>
`;
}
itemClasses.push('list-button');
return `
<li>
<a href="#" class="list-button ${itemClasses.join(' ')}">${text}</a>
</li>
`;
}).join('')}
</ul>
</div>
`).join('')}
</div>
</div>
`.trim();
}
}
var Actions = {
name: 'actions',
params: {
actions: {
convertToPopover: true,
forceToPopover: false,
closeByBackdropClick: true,
render: null,
renderPopover: null,
backdrop: true,
},
},
static: {
Actions: Actions$1,
},
create() {
const app = this;
app.actions = ModalMethods({
app,
constructor: Actions$1,
defaultSelector: '.actions-modal.modal-in',
});
},
clicks: {
'.actions-open': function openActions($clickedEl, data = {}) {
const app = this;
app.actions.open(data.actions, data.animate);
},
'.actions-close': function closeActions($clickedEl, data = {}) {
const app = this;
app.actions.close(data.actions, data.animate);
},
'.actions-backdrop': function closeActions() {
const app = this;
if (!app.params.actions.closeByBackdropClick) return;
app.actions.close();
},
},
};
class Sheet$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
backdrop: app.theme === 'md',
closeByOutsideClick: app.params.sheet.closeByOutsideClick,
on: {},
}, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const sheet = this;
sheet.params = extendedParams;
// Find Element
let $el;
if (!sheet.params.el) {
$el = $(sheet.params.content);
} else {
$el = $(sheet.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return sheet.destroy();
}
let $backdropEl;
if (sheet.params.backdrop) {
$backdropEl = app.root.children('.sheet-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="sheet-backdrop"></div>');
app.root.append($backdropEl);
}
}
let $pageContentEl;
function scrollToOpen() {
const $scrollEl = $(sheet.params.scrollToEl).eq(0);
if ($scrollEl.length === 0) return;
$pageContentEl = $scrollEl.parents('.page-content');
if ($pageContentEl.length === 0) return;
const paddingTop = parseInt($pageContentEl.css('padding-top'), 10);
const paddingBottom = parseInt($pageContentEl.css('padding-bottom'), 10);
const pageHeight = $pageContentEl[0].offsetHeight - paddingTop - $el.height();
const pageScrollHeight = $pageContentEl[0].scrollHeight - paddingTop - $el.height();
const pageScroll = $pageContentEl.scrollTop();
let newPaddingBottom;
const scrollElTop = ($scrollEl.offset().top - paddingTop) + $scrollEl[0].offsetHeight;
if (scrollElTop > pageHeight) {
const scrollTop = (pageScroll + scrollElTop) - pageHeight;
if (scrollTop + pageHeight > pageScrollHeight) {
newPaddingBottom = ((scrollTop + pageHeight) - pageScrollHeight) + paddingBottom;
if (pageHeight === pageScrollHeight) {
newPaddingBottom = $el.height();
}
$pageContentEl.css({
'padding-bottom': `${newPaddingBottom}px`,
});
}
$pageContentEl.scrollTop(scrollTop, 300);
}
}
function scrollToClose() {
if ($pageContentEl && $pageContentEl.length > 0) {
$pageContentEl.css({
'padding-bottom': '',
});
}
}
function handleClick(e) {
const target = e.target;
if ($(target).closest(sheet.el).length === 0) {
sheet.close();
}
}
sheet.on('sheetOpen', () => {
if (sheet.params.scrollToEl) {
scrollToOpen();
}
});
sheet.on('sheetOpened', () => {
if (sheet.params.closeByOutsideClick && !sheet.params.backdrop) {
app.on('click', handleClick);
}
});
sheet.on('sheetClose', () => {
if (sheet.params.scrollToEl) {
scrollToClose();
}
if (sheet.params.closeByOutsideClick && !sheet.params.backdrop) {
app.off('click', handleClick);
}
});
Utils.extend(sheet, {
app,
$el,
el: $el[0],
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
type: 'sheet',
});
$el[0].f7Modal = sheet;
return sheet;
}
}
var Sheet = {
name: 'sheet',
params: {
sheet: {
closeByBackdropClick: true,
closeByOutsideClick: false,
},
},
static: {
Sheet: Sheet$1,
},
create() {
const app = this;
app.sheet = Utils.extend(
{},
ModalMethods({
app,
constructor: Sheet$1,
defaultSelector: '.sheet-modal.modal-in',
})
);
},
clicks: {
'.sheet-open': function openSheet($clickedEl, data = {}) {
const app = this;
if ($('.sheet-modal.modal-in').length > 0 && data.sheet && $(data.sheet)[0] !== $('.sheet-modal.modal-in')[0]) {
app.sheet.close('.sheet-modal.modal-in');
}
app.sheet.open(data.sheet, data.animate);
},
'.sheet-close': function closeSheet($clickedEl, data = {}) {
const app = this;
app.sheet.close(data.sheet, data.animate);
},
'.sheet-backdrop': function closeSheet() {
const app = this;
if (!app.params.sheet.closeByBackdropClick) return;
app.sheet.close();
},
},
};
class Toast$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
on: {},
}, app.params.toast, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const toast = this;
toast.app = app;
toast.params = extendedParams;
const { closeButton, closeTimeout } = toast.params;
let $el;
if (!toast.params.el) {
// Find Element
const toastHtml = toast.render();
$el = $(toastHtml);
} else {
$el = $(toast.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return toast.destroy();
}
Utils.extend(toast, {
$el,
el: $el[0],
type: 'toast',
});
$el[0].f7Modal = toast;
if (closeButton) {
$el.find('.toast-button').on('click', () => {
toast.emit('local::closeButtonClick toastCloseButtonClick', toast);
toast.close();
});
toast.on('beforeDestroy', () => {
$el.find('.toast-button').off('click');
});
}
let timeoutId;
toast.on('open', () => {
$('.toast.modal-in').each((index, openedEl) => {
const toastInstance = app.toast.get(openedEl);
if (openedEl !== toast.el && toastInstance) {
toastInstance.close();
}
});
if (closeTimeout) {
timeoutId = Utils.nextTick(() => {
toast.close();
}, closeTimeout);
}
});
toast.on('close', () => {
window.clearTimeout(timeoutId);
});
return toast;
}
render() {
const toast = this;
const app = toast.app;
if (toast.params.render) return toast.params.render.call(toast, toast);
const { position, cssClass, icon, text, closeButton, closeButtonColor, closeButtonText } = toast.params;
return `
<div class="toast toast-${position} ${cssClass || ''} ${icon ? 'toast-with-icon' : ''}">
<div class="toast-content">
${icon ? `<div class="toast-icon">${icon}</div>` : ''}
<div class="toast-text">${text}</div>
${closeButton && !icon ? `
<a class="toast-button ${app.theme === 'md' ? 'button' : 'link'} ${closeButtonColor ? `color-${closeButtonColor}` : ''}">${closeButtonText}</a>
`.trim() : ''}
</div>
</div>
`.trim();
}
}
var Toast = {
name: 'toast',
static: {
Toast: Toast$1,
},
create() {
const app = this;
app.toast = Utils.extend(
{},
ModalMethods({
app,
constructor: Toast$1,
defaultSelector: '.toast.modal-in',
})
);
},
params: {
toast: {
icon: null,
text: null,
position: 'bottom',
closeButton: false,
closeButtonColor: null,
closeButtonText: 'Ok',
closeTimeout: null,
cssClass: null,
render: null,
},
},
};
const Preloader = {
init(el) {
const app = this;
if (app.theme !== 'md') return;
const $el = $(el);
if ($el.length === 0 || $el.children('.preloader-inner').length > 0) return;
$el.append(Utils.mdPreloaderContent);
},
// Modal
visible: false,
show(color = 'white') {
const app = this;
if (Preloader.visible) return;
const preloaderInner = app.theme !== 'md' ? '' : Utils.mdPreloaderContent;
$('html').addClass('with-modal-preloader');
app.root.append(`
<div class="preloader-backdrop"></div>
<div class="preloader-modal">
<div class="preloader color-${color}">${preloaderInner}</div>
</div>
`);
Preloader.visible = true;
},
hide() {
const app = this;
if (!Preloader.visible) return;
$('html').removeClass('with-modal-preloader');
app.root.find('.preloader-backdrop, .preloader-modal').remove();
Preloader.visible = false;
},
};
var Preloader$1 = {
name: 'preloader',
create() {
const app = this;
Utils.extend(app, {
preloader: {
init: Preloader.init.bind(app),
show: Preloader.show.bind(app),
hide: Preloader.hide.bind(app),
},
});
},
on: {
photoBrowserOpen(pb) {
const app = this;
if (app.theme !== 'md') return;
pb.$el.find('.preloader').each((index, preloaderEl) => {
app.preloader.init(preloaderEl);
});
},
pageInit(page) {
const app = this;
if (app.theme !== 'md') return;
page.$el.find('.preloader').each((index, preloaderEl) => {
app.preloader.init(preloaderEl);
});
},
},
};
const Progressbar = {
set(...args) {
const app = this;
let [el, progress, duration] = args;
if (typeof args[0] === 'number') {
[progress, duration] = args;
el = app.root;
}
if (typeof progress === 'undefined' || progress === null) return el;
if (!progress) progress = 0;
const $el = $(el || app.root);
if ($el.length === 0) {
return el;
}
const progressNormalized = Math.min(Math.max(progress, 0), 100);
let $progressbarEl;
if ($el.hasClass('progressbar')) $progressbarEl = $el.eq(0);
else {
$progressbarEl = $el.children('.progressbar');
}
if ($progressbarEl.length === 0 || $progressbarEl.hasClass('progressbar-infinite')) {
return $progressbarEl;
}
let $progressbarLine = $progressbarEl.children('span');
if ($progressbarLine.length === 0) {
$progressbarLine = $('<span></span>');
$progressbarEl.append($progressbarLine);
}
$progressbarLine
.transition(typeof duration !== 'undefined' ? duration : '')
.transform(`translate3d(${(-100 + progressNormalized)}%,0,0)`);
return $progressbarEl[0];
},
show(...args) {
const app = this;
// '.page', 50, 'multi'
let [el, progress, color] = args;
let type = 'determined';
if (args.length === 2) {
if ((typeof args[0] === 'string' || typeof args[0] === 'object') && typeof args[1] === 'string') {
// '.page', 'multi'
[el, color, progress] = args;
type = 'infinite';
} else if (typeof args[0] === 'number' && typeof args[1] === 'string') {
// 50, 'multi'
[progress, color] = args;
el = app.root;
}
} else if (args.length === 1) {
if (typeof args[0] === 'number') {
el = app.root;
progress = args[0];
} else if (typeof args[0] === 'string') {
type = 'infinite';
el = app.root;
color = args[0];
}
} else if (args.length === 0) {
type = 'infinite';
el = app.root;
}
const $el = $(el);
if ($el.length === 0) return undefined;
let $progressbarEl;
if ($el.hasClass('progressbar') || $el.hasClass('progressbar-infinite')) {
$progressbarEl = $el;
} else {
$progressbarEl = $el.children('.progressbar:not(.progressbar-out), .progressbar-infinite:not(.progressbar-out)');
if ($progressbarEl.length === 0) {
$progressbarEl = $(`
<span class="progressbar${type === 'infinite' ? '-infinite' : ''}${color ? ` color-${color}` : ''} progressbar-in">
${type === 'infinite' ? '' : '<span></span>'}
</span>`);
$el.append($progressbarEl);
}
}
if (typeof progress !== 'undefined') {
app.progressbar.set($progressbarEl, progress);
}
return $progressbarEl[0];
},
hide(el, removeAfterHide = true) {
const app = this;
const $el = $(el || app.root);
if ($el.length === 0) return undefined;
let $progressbarEl;
if ($el.hasClass('progressbar') || $el.hasClass('progressbar-infinite')) {
$progressbarEl = $el;
} else {
$progressbarEl = $el.children('.progressbar, .progressbar-infinite');
}
if ($progressbarEl.length === 0 || !$progressbarEl.hasClass('progressbar-in') || $progressbarEl.hasClass('progressbar-out')) {
return $progressbarEl;
}
$progressbarEl
.removeClass('progressbar-in')
.addClass('progressbar-out')
.animationEnd(() => {
if (removeAfterHide) {
$progressbarEl.remove();
}
});
return $progressbarEl;
},
};
var Progressbar$1 = {
name: 'progressbar',
create() {
const app = this;
Utils.extend(app, {
progressbar: {
set: Progressbar.set.bind(app),
show: Progressbar.show.bind(app),
hide: Progressbar.hide.bind(app),
},
});
},
on: {
pageInit(page) {
const app = this;
page.$el.find('.progressbar').each((index, progressbarEl) => {
const $progressbarEl = $(progressbarEl);
app.progressbar.set($progressbarEl, $progressbarEl.attr('data-progress'));
});
},
},
};
const Sortable = {
init() {
const app = this;
let isTouched;
let isMoved;
let touchStartY;
let touchesDiff;
let $sortingEl;
let $sortingItems;
let $sortableContainer;
let sortingElHeight;
let minTop;
let maxTop;
let $insertAfterEl;
let $insertBeforeEl;
let indexFrom;
let $pageEl;
let $pageContentEl;
let pageHeight;
let pageOffset;
let sortingElOffsetLocal;
let sortingElOffsetTop;
let initialScrollTop;
function handleTouchStart(e) {
isMoved = false;
isTouched = true;
touchStartY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
$sortingEl = $(this).parent('li');
indexFrom = $sortingEl.index();
$sortableContainer = $sortingEl.parents('.sortable');
$sortingItems = $sortableContainer.children('ul').children('li');
if (app.panel) app.panel.allowOpen = false;
if (app.swipeout) app.swipeout.allow = false;
}
function handleTouchMove(e) {
if (!isTouched || !$sortingEl) return;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (!isMoved) {
$pageEl = $sortingEl.parents('.page');
$pageContentEl = $sortingEl.parents('.page-content');
const paddingTop = parseInt($pageContentEl.css('padding-top'), 10);
const paddingBottom = parseInt($pageContentEl.css('padding-bottom'), 10);
initialScrollTop = $pageContentEl[0].scrollTop;
pageOffset = $pageEl.offset().top + paddingTop;
pageHeight = $pageEl.height() - paddingTop - paddingBottom;
$sortingEl.addClass('sorting');
$sortableContainer.addClass('sortable-sorting');
sortingElOffsetLocal = $sortingEl[0].offsetTop;
minTop = $sortingEl[0].offsetTop;
maxTop = $sortingEl.parent().height() - sortingElOffsetLocal - $sortingEl.height();
sortingElHeight = $sortingEl[0].offsetHeight;
sortingElOffsetTop = $sortingEl.offset().top;
}
isMoved = true;
e.preventDefault();
e.f7PreventSwipePanel = true;
touchesDiff = pageY - touchStartY;
const translateScrollOffset = $pageContentEl[0].scrollTop - initialScrollTop;
const translate = Math.min(Math.max(touchesDiff + translateScrollOffset, -minTop), maxTop);
$sortingEl.transform(`translate3d(0,${translate}px,0)`);
const scrollAddition = 44;
let allowScroll = true;
if ((touchesDiff + translateScrollOffset) + scrollAddition < -minTop) {
allowScroll = false;
}
if ((touchesDiff + translateScrollOffset) - scrollAddition > maxTop) {
allowScroll = false;
}
$insertBeforeEl = undefined;
$insertAfterEl = undefined;
let scrollDiff;
if (allowScroll) {
if (sortingElOffsetTop + touchesDiff + sortingElHeight + scrollAddition > pageOffset + pageHeight) {
// To Bottom
scrollDiff = (sortingElOffsetTop + touchesDiff + sortingElHeight + scrollAddition) - (pageOffset + pageHeight);
}
if (sortingElOffsetTop + touchesDiff < pageOffset + scrollAddition) {
// To Top
scrollDiff = (sortingElOffsetTop + touchesDiff) - pageOffset - scrollAddition;
}
if (scrollDiff) {
$pageContentEl[0].scrollTop += scrollDiff;
}
}
$sortingItems.each((index, el) => {
const $currentEl = $(el);
if ($currentEl[0] === $sortingEl[0]) return;
const currentElOffset = $currentEl[0].offsetTop;
const currentElHeight = $currentEl.height();
const sortingElOffset = sortingElOffsetLocal + translate;
if ((sortingElOffset >= currentElOffset - (currentElHeight / 2)) && $sortingEl.index() < $currentEl.index()) {
$currentEl.transform(`translate3d(0, ${-sortingElHeight}px,0)`);
$insertAfterEl = $currentEl;
$insertBeforeEl = undefined;
} else if ((sortingElOffset <= currentElOffset + (currentElHeight / 2)) && $sortingEl.index() > $currentEl.index()) {
$currentEl.transform(`translate3d(0, ${sortingElHeight}px,0)`);
$insertAfterEl = undefined;
if (!$insertBeforeEl) $insertBeforeEl = $currentEl;
} else {
$currentEl.transform('translate3d(0, 0%,0)');
}
});
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
if (isTouched && !isMoved) {
if (app.panel) app.panel.allowOpen = true;
if (app.swipeout) app.swipeout.allow = true;
}
return;
}
if (app.panel) app.panel.allowOpen = true;
if (app.swipeout) app.swipeout.allow = true;
$sortingItems.transform('');
$sortingEl.removeClass('sorting');
$sortableContainer.removeClass('sortable-sorting');
let virtualList;
let oldIndex;
let newIndex;
if ($insertAfterEl) {
$sortingEl.insertAfter($insertAfterEl);
}
if ($insertBeforeEl) {
$sortingEl.insertBefore($insertBeforeEl);
}
$sortingEl.trigger('sortable:sort', { from: indexFrom, to: $sortingEl.index() });
app.emit('sortableSort', $sortingEl[0], { from: indexFrom, to: $sortingEl.index() });
if (($insertAfterEl || $insertBeforeEl) && $sortableContainer.hasClass('virtual-list')) {
virtualList = $sortableContainer[0].f7VirtualList;
oldIndex = $sortingEl[0].f7VirtualListIndex;
newIndex = $insertBeforeEl ? $insertBeforeEl[0].f7VirtualListIndex : $insertAfterEl[0].f7VirtualListIndex;
if (virtualList) virtualList.moveItem(oldIndex, newIndex);
}
$insertBeforeEl = undefined;
$insertAfterEl = undefined;
isTouched = false;
isMoved = false;
}
const activeListener = app.support.passiveListener ? { passive: false, capture: false } : false;
$(document).on(app.touchEvents.start, '.list.sortable .sortable-handler', handleTouchStart, activeListener);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
},
enable(el = '.list.sortable') {
const app = this;
const $el = $(el);
if ($el.length === 0) return;
$el.addClass('sortable-enabled');
$el.trigger('sortable:enable');
app.emit('sortableEnable', $el[0]);
},
disable(el = '.list.sortable') {
const app = this;
const $el = $(el);
if ($el.length === 0) return;
$el.removeClass('sortable-enabled');
$el.trigger('sortable:disable');
app.emit('sortableDisable', $el[0]);
},
toggle(el = '.list.sortable') {
const app = this;
const $el = $(el);
if ($el.length === 0) return;
if ($el.hasClass('sortable-enabled')) {
app.sortable.disable($el);
} else {
app.sortable.enable($el);
}
},
};
var Sortable$1 = {
name: 'sortable',
params: {
sortable: true,
},
create() {
const app = this;
Utils.extend(app, {
sortable: {
init: Sortable.init.bind(app),
enable: Sortable.enable.bind(app),
disable: Sortable.disable.bind(app),
toggle: Sortable.toggle.bind(app),
},
});
},
on: {
init() {
const app = this;
if (app.params.sortable) app.sortable.init();
},
},
clicks: {
'.sortable-enable': function enable($clickedEl, data = {}) {
const app = this;
app.sortable.enable(data.sortable);
},
'.sortable-disable': function disable($clickedEl, data = {}) {
const app = this;
app.sortable.disable(data.sortable);
},
'.sortable-toggle': function toggle($clickedEl, data = {}) {
const app = this;
app.sortable.toggle(data.sortable);
},
},
};
const Swipeout = {
init() {
const app = this;
const touchesStart = {};
let isTouched;
let isMoved;
let isScrolling;
let touchStartTime;
let touchesDiff;
let $swipeoutEl;
let $swipeoutContent;
let $actionsRight;
let $actionsLeft;
let actionsLeftWidth;
let actionsRightWidth;
let translate;
let opened;
let openedActionsSide;
let $leftButtons;
let $rightButtons;
let direction;
let $overswipeLeftButton;
let $overswipeRightButton;
let overswipeLeft;
let overswipeRight;
function handleTouchStart(e) {
if (!Swipeout.allow) return;
isMoved = false;
isTouched = true;
isScrolling = undefined;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchStartTime = (new Date()).getTime();
$swipeoutEl = $(this);
}
function handleTouchMove(e) {
if (!isTouched) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
if (!isMoved) {
if ($('.list.sortable-opened').length > 0) return;
$swipeoutContent = $swipeoutEl.find('.swipeout-content');
$actionsRight = $swipeoutEl.find('.swipeout-actions-right');
$actionsLeft = $swipeoutEl.find('.swipeout-actions-left');
actionsLeftWidth = null;
actionsRightWidth = null;
$leftButtons = null;
$rightButtons = null;
$overswipeRightButton = null;
$overswipeLeftButton = null;
if ($actionsLeft.length > 0) {
actionsLeftWidth = $actionsLeft.outerWidth();
$leftButtons = $actionsLeft.children('a');
$overswipeLeftButton = $actionsLeft.find('.swipeout-overswipe');
}
if ($actionsRight.length > 0) {
actionsRightWidth = $actionsRight.outerWidth();
$rightButtons = $actionsRight.children('a');
$overswipeRightButton = $actionsRight.find('.swipeout-overswipe');
}
opened = $swipeoutEl.hasClass('swipeout-opened');
if (opened) {
openedActionsSide = $swipeoutEl.find('.swipeout-actions-left.swipeout-actions-opened').length > 0 ? 'left' : 'right';
}
$swipeoutEl.removeClass('swipeout-transitioning');
if (!app.params.swipeout.noFollow) {
$swipeoutEl.find('.swipeout-actions-opened').removeClass('swipeout-actions-opened');
$swipeoutEl.removeClass('swipeout-opened');
}
}
isMoved = true;
e.preventDefault();
touchesDiff = pageX - touchesStart.x;
translate = touchesDiff;
if (opened) {
if (openedActionsSide === 'right') translate -= actionsRightWidth;
else translate += actionsLeftWidth;
}
if (
(translate > 0 && $actionsLeft.length === 0)
||
(translate < 0 && $actionsRight.length === 0)
) {
if (!opened) {
isTouched = false;
isMoved = false;
$swipeoutContent.transform('');
if ($rightButtons && $rightButtons.length > 0) {
$rightButtons.transform('');
}
if ($leftButtons && $leftButtons.length > 0) {
$leftButtons.transform('');
}
return;
}
translate = 0;
}
if (translate < 0) direction = 'to-left';
else if (translate > 0) direction = 'to-right';
else if (!direction) direction = 'to-left';
let buttonOffset;
let progress;
e.f7PreventSwipePanel = true;
if (app.params.swipeout.noFollow) {
if (opened) {
if (openedActionsSide === 'right' && touchesDiff > 0) {
app.swipeout.close($swipeoutEl);
}
if (openedActionsSide === 'left' && touchesDiff < 0) {
app.swipeout.close($swipeoutEl);
}
} else {
if (touchesDiff < 0 && $actionsRight.length > 0) {
app.swipeout.open($swipeoutEl, 'right');
}
if (touchesDiff > 0 && $actionsLeft.length > 0) {
app.swipeout.open($swipeoutEl, 'left');
}
}
isTouched = false;
isMoved = false;
return;
}
overswipeLeft = false;
overswipeRight = false;
if ($actionsRight.length > 0) {
// Show right actions
let buttonTranslate = translate;
progress = buttonTranslate / actionsRightWidth;
if (buttonTranslate < -actionsRightWidth) {
buttonTranslate = -actionsRightWidth - ((-buttonTranslate - actionsRightWidth) ** 0.8);
translate = buttonTranslate;
if ($overswipeRightButton.length > 0) {
overswipeRight = true;
}
}
if (direction !== 'to-left') {
progress = 0;
buttonTranslate = 0;
}
$rightButtons.each((index, buttonEl) => {
const $buttonEl = $(buttonEl);
if (typeof buttonEl.f7SwipeoutButtonOffset === 'undefined') {
$buttonEl[0].f7SwipeoutButtonOffset = buttonEl.offsetLeft;
}
buttonOffset = buttonEl.f7SwipeoutButtonOffset;
if ($overswipeRightButton.length > 0 && $buttonEl.hasClass('swipeout-overswipe') && direction === 'to-left') {
$buttonEl.css({ left: `${overswipeRight ? -buttonOffset : 0}px` });
if (overswipeRight) {
$buttonEl.addClass('swipeout-overswipe-active');
} else {
$buttonEl.removeClass('swipeout-overswipe-active');
}
}
$buttonEl.transform(`translate3d(${buttonTranslate - (buttonOffset * (1 + Math.max(progress, -1)))}px,0,0)`);
});
}
if ($actionsLeft.length > 0) {
// Show left actions
let buttonTranslate = translate;
progress = buttonTranslate / actionsLeftWidth;
if (buttonTranslate > actionsLeftWidth) {
buttonTranslate = actionsLeftWidth + ((buttonTranslate - actionsLeftWidth) ** 0.8);
translate = buttonTranslate;
if ($overswipeLeftButton.length > 0) {
overswipeLeft = true;
}
}
if (direction !== 'to-right') {
buttonTranslate = 0;
progress = 0;
}
$leftButtons.each((index, buttonEl) => {
const $buttonEl = $(buttonEl);
if (typeof buttonEl.f7SwipeoutButtonOffset === 'undefined') {
$buttonEl[0].f7SwipeoutButtonOffset = actionsLeftWidth - buttonEl.offsetLeft - buttonEl.offsetWidth;
}
buttonOffset = buttonEl.f7SwipeoutButtonOffset;
if ($overswipeLeftButton.length > 0 && $buttonEl.hasClass('swipeout-overswipe') && direction === 'to-right') {
$buttonEl.css({ left: `${overswipeLeft ? buttonOffset : 0}px` });
if (overswipeLeft) {
$buttonEl.addClass('swipeout-overswipe-active');
} else {
$buttonEl.removeClass('swipeout-overswipe-active');
}
}
if ($leftButtons.length > 1) {
$buttonEl.css('z-index', $leftButtons.length - index);
}
$buttonEl.transform(`translate3d(${buttonTranslate + (buttonOffset * (1 - Math.min(progress, 1)))}px,0,0)`);
});
}
$swipeoutEl.trigger('swipeout', progress);
app.emit('swipeout', $swipeoutEl[0], progress);
$swipeoutContent.transform(`translate3d(${translate}px,0,0)`);
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
const timeDiff = (new Date()).getTime() - touchStartTime;
const $actions = direction === 'to-left' ? $actionsRight : $actionsLeft;
const actionsWidth = direction === 'to-left' ? actionsRightWidth : actionsLeftWidth;
let action;
let $buttons;
let i;
if (
(
timeDiff < 300
&&
(
(touchesDiff < -10 && direction === 'to-left')
||
(touchesDiff > 10 && direction === 'to-right')
)
)
||
(
timeDiff >= 300
&&
(Math.abs(translate) > actionsWidth / 2)
)
) {
action = 'open';
} else {
action = 'close';
}
if (timeDiff < 300) {
if (Math.abs(translate) === 0) action = 'close';
if (Math.abs(translate) === actionsWidth) action = 'open';
}
if (action === 'open') {
Swipeout.el = $swipeoutEl[0];
$swipeoutEl.trigger('swipeout:open');
app.emit('swipeoutOpen', $swipeoutEl[0]);
$swipeoutEl.addClass('swipeout-opened swipeout-transitioning');
const newTranslate = direction === 'to-left' ? -actionsWidth : actionsWidth;
$swipeoutContent.transform(`translate3d(${newTranslate}px,0,0)`);
$actions.addClass('swipeout-actions-opened');
$buttons = direction === 'to-left' ? $rightButtons : $leftButtons;
if ($buttons) {
for (i = 0; i < $buttons.length; i += 1) {
$($buttons[i]).transform(`translate3d(${newTranslate}px,0,0)`);
}
}
if (overswipeRight) {
$actionsRight.find('.swipeout-overswipe')[0].click();
}
if (overswipeLeft) {
$actionsLeft.find('.swipeout-overswipe')[0].click();
}
} else {
$swipeoutEl.trigger('swipeout:close');
app.emit('swipeoutClose', $swipeoutEl[0]);
Swipeout.el = undefined;
$swipeoutEl.addClass('swipeout-transitioning').removeClass('swipeout-opened');
$swipeoutContent.transform('');
$actions.removeClass('swipeout-actions-opened');
}
let buttonOffset;
if ($leftButtons && $leftButtons.length > 0 && $leftButtons !== $buttons) {
$leftButtons.each((index, buttonEl) => {
const $buttonEl = $(buttonEl);
buttonOffset = buttonEl.f7SwipeoutButtonOffset;
if (typeof buttonOffset === 'undefined') {
$buttonEl[0].f7SwipeoutButtonOffset = actionsLeftWidth - buttonEl.offsetLeft - buttonEl.offsetWidth;
}
$buttonEl.transform(`translate3d(${buttonOffset}px,0,0)`);
});
}
if ($rightButtons && $rightButtons.length > 0 && $rightButtons !== $buttons) {
$rightButtons.each((index, buttonEl) => {
const $buttonEl = $(buttonEl);
buttonOffset = buttonEl.f7SwipeoutButtonOffset;
if (typeof buttonOffset === 'undefined') {
$buttonEl[0].f7SwipeoutButtonOffset = buttonEl.offsetLeft;
}
$buttonEl.transform(`translate3d(${-buttonOffset}px,0,0)`);
});
}
$swipeoutContent.transitionEnd(() => {
if ((opened && action === 'open') || (!opened && action === 'close')) return;
$swipeoutEl.trigger(action === 'open' ? 'swipeout:opened' : 'swipeout:closed');
app.emit(action === 'open' ? 'swipeoutOpened' : 'swipeoutClosed', $swipeoutEl[0]);
$swipeoutEl.removeClass('swipeout-transitioning');
if (opened && action === 'close') {
if ($actionsRight.length > 0) {
$rightButtons.transform('');
}
if ($actionsLeft.length > 0) {
$leftButtons.transform('');
}
}
});
}
const passiveListener = app.support.passiveListener ? { passive: true } : false;
app.on('touchstart', (e) => {
if (Swipeout.el) {
const $targetEl = $(e.target);
if (!(
$(Swipeout.el).is($targetEl[0]) ||
$targetEl.parents('.swipeout').is(Swipeout.el) ||
$targetEl.hasClass('modal-in') ||
$targetEl[0].className.indexOf('-backdrop') > 0 ||
$targetEl.hasClass('actions-modal') ||
$targetEl.parents('.actions-modal.modal-in, .dialog.modal-in').length > 0
)) {
app.swipeout.close(Swipeout.el);
}
}
});
$(document).on(app.touchEvents.start, 'li.swipeout', handleTouchStart, passiveListener);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
},
allow: true,
el: undefined,
open(...args) {
const app = this;
let [el, side, callback] = args;
if (typeof args[1] === 'function') {
[el, callback, side] = args;
}
const $el = $(el).eq(0);
if ($el.length === 0) return;
if (!$el.hasClass('swipeout') || $el.hasClass('swipeout-opened')) return;
if (!side) {
if ($el.find('.swipeout-actions-right').length > 0) side = 'right';
else side = 'left';
}
const $swipeoutActions = $el.find(`.swipeout-actions-${side}`);
const $swipeoutContent = $el.find('.swipeout-content');
if ($swipeoutActions.length === 0) return;
$el.trigger('swipeout:open').addClass('swipeout-opened').removeClass('swipeout-transitioning');
app.emit('swipeoutOpen', $el[0]);
$swipeoutActions.addClass('swipeout-actions-opened');
const $buttons = $swipeoutActions.children('a');
const swipeoutActionsWidth = $swipeoutActions.outerWidth();
const translate = side === 'right' ? -swipeoutActionsWidth : swipeoutActionsWidth;
if ($buttons.length > 1) {
$buttons.each((buttonIndex, buttonEl) => {
const $buttonEl = $(buttonEl);
if (side === 'right') {
$buttonEl.transform(`translate3d(${-buttonEl.offsetLeft}px,0,0)`);
} else {
$buttonEl.css('z-index', $buttons.length - buttonIndex).transform(`translate3d(${swipeoutActionsWidth - buttonEl.offsetWidth - buttonEl.offsetLeft}px,0,0)`);
}
});
}
$el.addClass('swipeout-transitioning');
$swipeoutContent.transitionEnd(() => {
$el.trigger('swipeout:opened');
app.emit('swipeoutOpened', $el[0]);
if (callback) callback.call($el[0]);
});
Utils.nextFrame(() => {
$buttons.transform(`translate3d(${translate}px,0,0)`);
$swipeoutContent.transform(`translate3d(${translate}px,0,0)`);
});
Swipeout.el = $el[0];
},
close(el, callback) {
const app = this;
const $el = $(el).eq(0);
if ($el.length === 0) return;
if (!$el.hasClass('swipeout-opened')) return;
const side = $el.find('.swipeout-actions-opened').hasClass('swipeout-actions-right') ? 'right' : 'left';
const $swipeoutActions = $el.find('.swipeout-actions-opened').removeClass('swipeout-actions-opened');
const $buttons = $swipeoutActions.children('a');
const swipeoutActionsWidth = $swipeoutActions.outerWidth();
Swipeout.allow = false;
$el.trigger('swipeout:close');
app.emit('swipeoutClose', $el[0]);
$el.removeClass('swipeout-opened').addClass('swipeout-transitioning');
let closeTimeout;
function onSwipeoutClose() {
Swipeout.allow = true;
if ($el.hasClass('swipeout-opened')) return;
$el.removeClass('swipeout-transitioning');
$buttons.transform('');
$el.trigger('swipeout:closed');
app.emit('swipeoutClosed', $el[0]);
if (callback) callback.call($el[0]);
if (closeTimeout) clearTimeout(closeTimeout);
}
$el.find('.swipeout-content').transform('').transitionEnd(onSwipeoutClose);
closeTimeout = setTimeout(onSwipeoutClose, 500);
$buttons.each((index, buttonEl) => {
const $buttonEl = $(buttonEl);
if (side === 'right') {
$buttonEl.transform(`translate3d(${-buttonEl.offsetLeft}px,0,0)`);
} else {
$buttonEl.transform(`translate3d(${swipeoutActionsWidth - buttonEl.offsetWidth - buttonEl.offsetLeft}px,0,0)`);
}
$buttonEl.css({ left: '0px' }).removeClass('swipeout-overswipe-active');
});
if (Swipeout.el && Swipeout.el === $el[0]) Swipeout.el = undefined;
},
delete(el, callback) {
const app = this;
const $el = $(el).eq(0);
if ($el.length === 0) return;
Swipeout.el = undefined;
$el.trigger('swipeout:delete');
app.emit('swipeoutDelete', $el[0]);
$el.css({ height: `${$el.outerHeight()}px` });
$el.transitionEnd(() => {
$el.trigger('swipeout:deleted');
app.emit('swipeoutDeleted', $el[0]);
if (callback) callback.call($el[0]);
if ($el.parents('.virtual-list').length > 0) {
const virtualList = $el.parents('.virtual-list')[0].f7VirtualList;
const virtualIndex = $el[0].f7VirtualListIndex;
if (virtualList && typeof virtualIndex !== 'undefined') virtualList.deleteItem(virtualIndex);
} else if (app.params.swipeout.removeElements) {
if (app.params.swipeout.removeElementsWithTimeout) {
setTimeout(() => {
$el.remove();
}, app.params.swipeout.removeElementsTimeout);
} else {
$el.remove();
}
} else {
$el.removeClass('swipeout-deleting swipeout-transitioning');
}
});
Utils.nextFrame(() => {
$el
.addClass('swipeout-deleting swipeout-transitioning')
.css({ height: '0px' })
.find('.swipeout-content')
.transform('translate3d(-100%,0,0)');
});
},
};
var Swipeout$1 = {
name: 'swipeout',
params: {
swipeout: {
actionsNoFold: false,
noFollow: false,
removeElements: true,
removeElementsWithTimeout: false,
removeElementsTimeout: 0,
},
},
create() {
const app = this;
Utils.extend(app, {
swipeout: {
init: Swipeout.init.bind(app),
open: Swipeout.open.bind(app),
close: Swipeout.close.bind(app),
delete: Swipeout.delete.bind(app),
},
});
Object.defineProperty(app.swipeout, 'el', {
enumerable: true,
configurable: true,
get: () => Swipeout.el,
set(el) {
Swipeout.el = el;
},
});
Object.defineProperty(app.swipeout, 'allow', {
enumerable: true,
configurable: true,
get: () => Swipeout.allow,
set(allow) {
Swipeout.allow = allow;
},
});
},
clicks: {
'.swipeout-open': function openSwipeout($clickedEl, data = {}) {
const app = this;
app.swipeout.open(data.swipeout, data.side);
},
'.swipeout-close': function closeSwipeout($clickedEl) {
const app = this;
const $swipeoutEl = $clickedEl.closest('.swipeout');
if ($swipeoutEl.length === 0) return;
app.swipeout.close($swipeoutEl);
},
'.swipeout-delete': function deleteSwipeout($clickedEl, data = {}) {
const app = this;
const $swipeoutEl = $clickedEl.closest('.swipeout');
if ($swipeoutEl.length === 0) return;
const { confirm, confirmTitle } = data;
if (data.confirm) {
app.dialog.confirm(confirm, confirmTitle, () => {
app.swipeout.delete($swipeoutEl);
});
} else {
app.swipeout.delete($swipeoutEl);
}
},
},
on: {
init() {
const app = this;
if (!app.params.swipeout) return;
app.swipeout.init();
},
},
};
const Accordion = {
toggleClicked($clickedEl) {
const app = this;
let $accordionItemEl = $clickedEl.closest('.accordion-item').eq(0);
if (!$accordionItemEl.length) $accordionItemEl = $clickedEl.parents('li').eq(0);
app.accordion.toggle($accordionItemEl);
},
open(el) {
const app = this;
const $el = $(el);
const $list = $el.parents('.accordion-list').eq(0);
let $contentEl = $el.children('.accordion-item-content');
if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
if ($contentEl.length === 0) return;
const $openedItem = $list.length > 0 && $el.parent().children('.accordion-item-opened');
if ($openedItem.length > 0) {
app.accordion.close($openedItem);
}
$contentEl.transitionEnd(() => {
if ($el.hasClass('accordion-item-opened')) {
$contentEl.css('height', '');
$contentEl.transition('');
$el.trigger('accordion:opened');
app.emit('accordionOpened', $el[0]);
} else {
$contentEl.css('height', '');
$el.trigger('accordion:closed');
app.emit('accordionClosed', $el[0]);
}
});
$contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
$el.trigger('accordion:open');
$el.addClass('accordion-item-opened');
app.emit('accordionOpen', $el[0]);
},
close(el) {
const app = this;
const $el = $(el);
let $contentEl = $el.children('.accordion-item-content');
if ($contentEl.length === 0) $contentEl = $el.find('.accordion-item-content');
$el.removeClass('accordion-item-opened');
$contentEl.transition(0);
$contentEl.css('height', `${$contentEl[0].scrollHeight}px`);
// Close
$contentEl.transitionEnd(() => {
if ($el.hasClass('accordion-item-opened')) {
$contentEl.css('height', '');
$contentEl.transition('');
$el.trigger('accordion:opened');
app.emit('accordionOpened', $el[0]);
} else {
$contentEl.css('height', '');
$el.trigger('accordion:closed');
app.emit('accordionClosed', $el[0]);
}
});
Utils.nextFrame(() => {
$contentEl.transition('');
$contentEl.css('height', '');
$el.trigger('accordion:close');
app.emit('accordionClose');
});
},
toggle(el) {
const app = this;
const $el = $(el);
if ($el.length === 0) return;
if ($el.hasClass('accordion-item-opened')) app.accordion.close(el);
else app.accordion.open(el);
},
};
var Accordion$1 = {
name: 'accordion',
create() {
const app = this;
Utils.extend(app, {
accordion: {
open: Accordion.open.bind(app),
close: Accordion.close.bind(app),
toggle: Accordion.toggle.bind(app),
},
});
},
clicks: {
'.accordion-item .item-link, .accordion-item-toggle, .links-list.accordion-list > ul > li > a': function open($clickedEl) {
const app = this;
Accordion.toggleClicked.call(app, $clickedEl);
},
},
};
class VirtualList$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const vl = this;
const defaults = {
cols: 1,
height: app.theme === 'md' ? 48 : 44,
cache: true,
dynamicHeightBufferSize: 1,
showFilteredItemsOnly: false,
renderExternal: undefined,
setListHeight: true,
searchByItem: undefined,
searchAll: undefined,
itemTemplate: undefined,
renderItem(item) {
return `
<li>
<div class="item-content">
<div class="item-inner">
<div class="item-title">${item}</div>
</div>
</div>
</li>
`.trim();
},
on: {},
};
// Extend defaults with modules params
vl.useModulesParams(defaults);
vl.params = Utils.extend(defaults, params);
if (vl.params.height === undefined || !vl.params.height) {
vl.params.height = app.theme === 'md' ? 48 : 44;
}
vl.$el = $(params.el);
vl.el = vl.$el[0];
if (vl.$el.length === 0) return undefined;
vl.$el[0].f7VirtualList = vl;
vl.items = vl.params.items;
if (vl.params.showFilteredItemsOnly) {
vl.filteredItems = [];
}
if (vl.params.itemTemplate) {
if (typeof vl.params.itemTemplate === 'string') vl.renderItem = Template7.compile(vl.params.itemTemplate);
else if (typeof vl.params.itemTemplate === 'function') vl.renderItem = vl.params.itemTemplate;
} else if (vl.params.renderItem) {
vl.renderItem = vl.params.renderItem;
}
vl.$pageContentEl = vl.$el.parents('.page-content');
vl.pageContentEl = vl.$pageContentEl[0];
// Bad scroll
if (typeof vl.params.updatableScroll !== 'undefined') {
vl.updatableScroll = vl.params.updatableScroll;
} else {
vl.updatableScroll = true;
if (Device.ios && Device.osVersion.split('.')[0] < 8) {
vl.updatableScroll = false;
}
}
// Append <ul>
vl.$ul = vl.params.ul ? $(vl.params.ul) : vl.$el.children('ul');
if (vl.$ul.length === 0) {
vl.$el.append('<ul></ul>');
vl.$ul = vl.$el.children('ul');
}
vl.ul = vl.$ul[0];
Utils.extend(vl, {
// DOM cached items
domCache: {},
displayDomCache: {},
// Temporary DOM Element
tempDomElement: document.createElement('ul'),
// Last repain position
lastRepaintY: null,
// Fragment
fragment: document.createDocumentFragment(),
// Props
pageHeight: undefined,
rowsPerScreen: undefined,
rowsBefore: undefined,
rowsAfter: undefined,
rowsToRender: undefined,
maxBufferHeight: 0,
listHeight: undefined,
dynamicHeight: typeof vl.params.height === 'function',
});
// Install Modules
vl.useModules();
// Attach events
const handleScrollBound = vl.handleScroll.bind(vl);
const handleResizeBound = vl.handleResize.bind(vl);
let $pageEl;
let $tabEl;
let $panelEl;
let $popupEl;
vl.attachEvents = function attachEvents() {
$pageEl = vl.$el.parents('.page').eq(0);
$tabEl = vl.$el.parents('.tab').eq(0);
$panelEl = vl.$el.parents('.panel').eq(0);
$popupEl = vl.$el.parents('.popup').eq(0);
vl.$pageContentEl.on('scroll', handleScrollBound);
if ($pageEl) $pageEl.on('page:reinit', handleResizeBound);
if ($tabEl) $tabEl.on('tab:show', handleResizeBound);
if ($panelEl) $panelEl.on('panel:open', handleResizeBound);
if ($popupEl) $popupEl.on('popup:open', handleResizeBound);
app.on('resize', handleResizeBound);
};
vl.detachEvents = function attachEvents() {
vl.$pageContentEl.off('scroll', handleScrollBound);
if ($pageEl) $pageEl.off('page:reinit', handleResizeBound);
if ($tabEl) $tabEl.off('tab:show', handleResizeBound);
if ($panelEl) $panelEl.off('panel:open', handleResizeBound);
if ($popupEl) $popupEl.off('popup:open', handleResizeBound);
app.off('resize', handleResizeBound);
};
// Init
vl.init();
return vl;
}
setListSize() {
const vl = this;
const items = vl.filteredItems || vl.items;
vl.pageHeight = vl.$pageContentEl[0].offsetHeight;
if (vl.dynamicHeight) {
vl.listHeight = 0;
vl.heights = [];
for (let i = 0; i < items.length; i += 1) {
const itemHeight = vl.params.height(items[i]);
vl.listHeight += itemHeight;
vl.heights.push(itemHeight);
}
} else {
vl.listHeight = Math.ceil(items.length / vl.params.cols) * vl.params.height;
vl.rowsPerScreen = Math.ceil(vl.pageHeight / vl.params.height);
vl.rowsBefore = vl.params.rowsBefore || vl.rowsPerScreen * 2;
vl.rowsAfter = vl.params.rowsAfter || vl.rowsPerScreen;
vl.rowsToRender = (vl.rowsPerScreen + vl.rowsBefore + vl.rowsAfter);
vl.maxBufferHeight = (vl.rowsBefore / 2) * vl.params.height;
}
if (vl.updatableScroll || vl.params.setListHeight) {
vl.$ul.css({ height: `${vl.listHeight}px` });
}
}
render(force, forceScrollTop) {
const vl = this;
if (force) vl.lastRepaintY = null;
let scrollTop = -(vl.$el[0].getBoundingClientRect().top - vl.$pageContentEl[0].getBoundingClientRect().top);
if (typeof forceScrollTop !== 'undefined') scrollTop = forceScrollTop;
if (vl.lastRepaintY === null || Math.abs(scrollTop - vl.lastRepaintY) > vl.maxBufferHeight || (!vl.updatableScroll && (vl.$pageContentEl[0].scrollTop + vl.pageHeight >= vl.$pageContentEl[0].scrollHeight))) {
vl.lastRepaintY = scrollTop;
} else {
return;
}
const items = vl.filteredItems || vl.items;
let fromIndex;
let toIndex;
let heightBeforeFirstItem = 0;
let heightBeforeLastItem = 0;
if (vl.dynamicHeight) {
let itemTop = 0;
let itemHeight;
vl.maxBufferHeight = vl.pageHeight;
for (let j = 0; j < vl.heights.length; j += 1) {
itemHeight = vl.heights[j];
if (typeof fromIndex === 'undefined') {
if (itemTop + itemHeight >= scrollTop - (vl.pageHeight * 2 * vl.params.dynamicHeightBufferSize)) fromIndex = j;
else heightBeforeFirstItem += itemHeight;
}
if (typeof toIndex === 'undefined') {
if (itemTop + itemHeight >= scrollTop + (vl.pageHeight * 2 * vl.params.dynamicHeightBufferSize) || j === vl.heights.length - 1) toIndex = j + 1;
heightBeforeLastItem += itemHeight;
}
itemTop += itemHeight;
}
toIndex = Math.min(toIndex, items.length);
} else {
fromIndex = (parseInt(scrollTop / vl.params.height, 10) - vl.rowsBefore) * vl.params.cols;
if (fromIndex < 0) {
fromIndex = 0;
}
toIndex = Math.min(fromIndex + (vl.rowsToRender * vl.params.cols), items.length);
}
let topPosition;
const renderExternalItems = [];
vl.reachEnd = false;
let i;
for (i = fromIndex; i < toIndex; i += 1) {
let itemEl;
// Define real item index
const index = vl.items.indexOf(items[i]);
if (i === fromIndex) vl.currentFromIndex = index;
if (i === toIndex - 1) vl.currentToIndex = index;
if (vl.filteredItems) {
if (vl.items[index] === vl.filteredItems[vl.filteredItems.length - 1]) vl.reachEnd = true;
} else if (index === vl.items.length - 1) vl.reachEnd = true;
// Find items
if (vl.params.renderExternal) {
renderExternalItems.push(items[i]);
} else if (vl.domCache[index]) {
itemEl = vl.domCache[index];
itemEl.f7VirtualListIndex = index;
} else {
if (vl.renderItem) {
vl.tempDomElement.innerHTML = vl.renderItem(items[i], index).trim();
} else {
vl.tempDomElement.innerHTML = items[i].toString().trim();
}
itemEl = vl.tempDomElement.childNodes[0];
if (vl.params.cache) vl.domCache[index] = itemEl;
itemEl.f7VirtualListIndex = index;
}
// Set item top position
if (i === fromIndex) {
if (vl.dynamicHeight) {
topPosition = heightBeforeFirstItem;
} else {
topPosition = ((i * vl.params.height) / vl.params.cols);
}
}
if (!vl.params.renderExternal) {
itemEl.style.top = `${topPosition}px`;
// Before item insert
vl.emit('local::itemBeforeInsert vlItemBeforeInsert', vl, itemEl, items[i]);
// Append item to fragment
vl.fragment.appendChild(itemEl);
}
}
// Update list height with not updatable scroll
if (!vl.updatableScroll) {
if (vl.dynamicHeight) {
vl.ul.style.height = `${heightBeforeLastItem}px`;
} else {
vl.ul.style.height = `${(i * vl.params.height) / vl.params.cols}px`;
}
}
// Update list html
if (vl.params.renderExternal) {
if (items && items.length === 0) {
vl.reachEnd = true;
}
} else {
vl.emit('local::beforeClear vlBeforeClear', vl, vl.fragment);
vl.ul.innerHTML = '';
vl.emit('local::itemsBeforeInsert vlItemsBeforeInsert', vl, vl.fragment);
if (items && items.length === 0) {
vl.reachEnd = true;
if (vl.params.emptyTemplate) vl.ul.innerHTML = vl.params.emptyTemplate;
} else {
vl.ul.appendChild(vl.fragment);
}
vl.emit('local::itemsAfterInsert vlItemsAfterInsert', vl, vl.fragment);
}
if (typeof forceScrollTop !== 'undefined' && force) {
vl.$pageContentEl.scrollTop(forceScrollTop, 0);
}
if (vl.params.renderExternal) {
vl.params.renderExternal(vl, {
fromIndex,
toIndex,
listHeight: vl.listHeight,
topPosition,
items: renderExternalItems,
});
}
}
// Filter
filterItems(indexes, resetScrollTop = true) {
const vl = this;
vl.filteredItems = [];
for (let i = 0; i < indexes.length; i += 1) {
vl.filteredItems.push(vl.items[indexes[i]]);
}
if (resetScrollTop) {
vl.$pageContentEl[0].scrollTop = 0;
}
vl.update();
}
resetFilter() {
const vl = this;
if (vl.params.showFilteredItemsOnly) {
vl.filteredItems = [];
} else {
vl.filteredItems = null;
delete vl.filteredItems;
}
vl.update();
}
scrollToItem(index) {
const vl = this;
if (index > vl.items.length) return false;
let itemTop = 0;
if (vl.dynamicHeight) {
for (let i = 0; i < index; i += 1) {
itemTop += vl.heights[i];
}
} else {
itemTop = index * vl.params.height;
}
const listTop = vl.$el[0].offsetTop;
vl.render(true, (listTop + itemTop) - parseInt(vl.$pageContentEl.css('padding-top'), 10));
return true;
}
handleScroll() {
const vl = this;
vl.render();
}
// Handle resize event
isVisible() {
const vl = this;
return !!(vl.el.offsetWidth || vl.el.offsetHeight || vl.el.getClientRects().length);
}
handleResize() {
const vl = this;
if (vl.isVisible()) {
vl.setListSize();
vl.render(true);
}
}
// Append
appendItems(items) {
const vl = this;
for (let i = 0; i < items.length; i += 1) {
vl.items.push(items[i]);
}
vl.update();
}
appendItem(item) {
const vl = this;
vl.appendItems([item]);
}
// Replace
replaceAllItems(items) {
const vl = this;
vl.items = items;
delete vl.filteredItems;
vl.domCache = {};
vl.update();
}
replaceItem(index, item) {
const vl = this;
vl.items[index] = item;
if (vl.params.cache) delete vl.domCache[index];
vl.update();
}
// Prepend
prependItems(items) {
const vl = this;
for (let i = items.length - 1; i >= 0; i -= 1) {
vl.items.unshift(items[i]);
}
if (vl.params.cache) {
const newCache = {};
Object.keys(vl.domCache).forEach((cached) => {
newCache[parseInt(cached, 10) + items.length] = vl.domCache[cached];
});
vl.domCache = newCache;
}
vl.update();
}
prependItem(item) {
const vl = this;
vl.prependItems([item]);
}
// Move
moveItem(from, to) {
const vl = this;
const fromIndex = from;
let toIndex = to;
if (fromIndex === toIndex) return;
// remove item from array
const item = vl.items.splice(fromIndex, 1)[0];
if (toIndex >= vl.items.length) {
// Add item to the end
vl.items.push(item);
toIndex = vl.items.length - 1;
} else {
// Add item to new index
vl.items.splice(toIndex, 0, item);
}
// Update cache
if (vl.params.cache) {
const newCache = {};
Object.keys(vl.domCache).forEach((cached) => {
const cachedIndex = parseInt(cached, 10);
const leftIndex = fromIndex < toIndex ? fromIndex : toIndex;
const rightIndex = fromIndex < toIndex ? toIndex : fromIndex;
const indexShift = fromIndex < toIndex ? -1 : 1;
if (cachedIndex < leftIndex || cachedIndex > rightIndex) newCache[cachedIndex] = vl.domCache[cachedIndex];
if (cachedIndex === leftIndex) newCache[rightIndex] = vl.domCache[cachedIndex];
if (cachedIndex > leftIndex && cachedIndex <= rightIndex) newCache[cachedIndex + indexShift] = vl.domCache[cachedIndex];
});
vl.domCache = newCache;
}
vl.update();
}
// Insert before
insertItemBefore(index, item) {
const vl = this;
if (index === 0) {
vl.prependItem(item);
return;
}
if (index >= vl.items.length) {
vl.appendItem(item);
return;
}
vl.items.splice(index, 0, item);
// Update cache
if (vl.params.cache) {
const newCache = {};
Object.keys(vl.domCache).forEach((cached) => {
const cachedIndex = parseInt(cached, 10);
if (cachedIndex >= index) {
newCache[cachedIndex + 1] = vl.domCache[cachedIndex];
}
});
vl.domCache = newCache;
}
vl.update();
}
// Delete
deleteItems(indexes) {
const vl = this;
let prevIndex;
let indexShift = 0;
for (let i = 0; i < indexes.length; i += 1) {
let index = indexes[i];
if (typeof prevIndex !== 'undefined') {
if (index > prevIndex) {
indexShift = -i;
}
}
index += indexShift;
prevIndex = indexes[i];
// Delete item
const deletedItem = vl.items.splice(index, 1)[0];
// Delete from filtered
if (vl.filteredItems && vl.filteredItems.indexOf(deletedItem) >= 0) {
vl.filteredItems.splice(vl.filteredItems.indexOf(deletedItem), 1);
}
// Update cache
if (vl.params.cache) {
const newCache = {};
Object.keys(vl.domCache).forEach((cached) => {
const cachedIndex = parseInt(cached, 10);
if (cachedIndex === index) {
delete vl.domCache[index];
} else if (parseInt(cached, 10) > index) {
newCache[cachedIndex - 1] = vl.domCache[cached];
} else {
newCache[cachedIndex] = vl.domCache[cached];
}
});
vl.domCache = newCache;
}
}
vl.update();
}
deleteAllItems() {
const vl = this;
vl.items = [];
delete vl.filteredItems;
if (vl.params.cache) vl.domCache = {};
vl.update();
}
deleteItem(index) {
const vl = this;
vl.deleteItems([index]);
}
// Clear cache
clearCachefunction() {
const vl = this;
vl.domCache = {};
}
// Update Virtual List
update() {
const vl = this;
vl.setListSize();
vl.render(true);
}
init() {
const vl = this;
vl.attachEvents();
vl.setListSize();
vl.render();
}
destroy() {
let vl = this;
vl.detachEvents();
vl.$el[0].f7VirtualList = null;
delete vl.$el[0].f7VirtualList;
Utils.deleteProps(vl);
vl = null;
}
}
var VirtualList = {
name: 'virtualList',
static: {
VirtualList: VirtualList$1,
},
create() {
const app = this;
app.virtualList = ConstructorMethods({
defaultSelector: '.virtual-list',
constructor: VirtualList$1,
app,
domProp: 'f7VirtualList',
});
},
};
var Timeline = {
name: 'timeline',
};
const Tab = {
show(...args) {
const app = this;
let tabEl;
let tabLinkEl;
let animate;
let tabRoute;
if (args.length === 1 && args[0].constructor === Object) {
tabEl = args[0].tabEl;
tabLinkEl = args[0].tabLinkEl;
animate = args[0].animate;
tabRoute = args[0].tabRoute;
} else {
[tabEl, tabLinkEl, animate, tabRoute] = args;
if (typeof args[1] === 'boolean') {
[tabEl, animate, tabLinkEl, tabRoute] = args;
if (args.length > 2 && tabLinkEl.constructor === Object) {
[tabEl, animate, tabRoute, tabLinkEl] = args;
}
}
}
if (typeof animate === 'undefined') animate = true;
const $newTabEl = $(tabEl);
if ($newTabEl.length === 0 || $newTabEl.hasClass('tab-active')) {
return {
$newTabEl,
newTabEl: $newTabEl[0],
};
}
let $tabLinkEl;
if (tabLinkEl) $tabLinkEl = $(tabLinkEl);
const $tabsEl = $newTabEl.parent('.tabs');
if ($tabsEl.length === 0) {
return {
$newTabEl,
newTabEl: $newTabEl[0],
};
}
// Release swipeouts in hidden tabs
if (app.swipeout) app.swipeout.allowOpen = true;
// Animated tabs
const tabsChangedCallbacks = [];
function onTabsChanged(callback) {
tabsChangedCallbacks.push(callback);
}
function tabsChanged() {
tabsChangedCallbacks.forEach((callback) => {
callback();
});
}
let animated = false;
if ($tabsEl.parent().hasClass('tabs-animated-wrap')) {
$tabsEl.parent()[animate ? 'removeClass' : 'addClass']('not-animated');
const transitionDuration = parseFloat($tabsEl.css('transition-duration').replace(',', '.'));
if (animate && transitionDuration) {
$tabsEl.transitionEnd(tabsChanged);
animated = true;
}
const tabsTranslate = (app.rtl ? $newTabEl.index() : -$newTabEl.index()) * 100;
$tabsEl.transform(`translate3d(${tabsTranslate}%,0,0)`);
}
// Swipeable tabs
if ($tabsEl.parent().hasClass('tabs-swipeable-wrap') && app.swiper) {
const swiper = $tabsEl.parent()[0].swiper;
if (swiper && swiper.activeIndex !== $newTabEl.index()) {
animated = true;
swiper
.once('slideChangeTransitionEnd', () => {
tabsChanged();
})
.slideTo($newTabEl.index(), animate ? undefined : 0);
}
}
// Remove active class from old tabs
const $oldTabEl = $tabsEl.children('.tab-active');
$oldTabEl
.removeClass('tab-active')
.trigger('tab:hide');
app.emit('tabHide', $oldTabEl[0]);
// Trigger 'show' event on new tab
$newTabEl
.addClass('tab-active')
.trigger('tab:show');
app.emit('tabShow', $newTabEl[0]);
// Find related link for new tab
if (!$tabLinkEl) {
// Search by id
if (typeof tabEl === 'string') $tabLinkEl = $(`.tab-link[href="${tabEl}"]`);
else $tabLinkEl = $(`.tab-link[href="#${$newTabEl.attr('id')}"]`);
// Search by data-tab
if (!$tabLinkEl || ($tabLinkEl && $tabLinkEl.length === 0)) {
$('[data-tab]').each((index, el) => {
if ($newTabEl.is($(el).attr('data-tab'))) $tabLinkEl = $(el);
});
}
if (tabRoute && (!$tabLinkEl || ($tabLinkEl && $tabLinkEl.length === 0))) {
$tabLinkEl = $(`[data-route-tab-id="${tabRoute.route.tab.id}"]`);
if ($tabLinkEl.length === 0) {
$tabLinkEl = $(`.tab-link[href="${tabRoute.url}"]`);
}
}
if ($tabLinkEl.length > 1 && $newTabEl.parents('.page').length) {
// eslint-disable-next-line
$tabLinkEl = $tabLinkEl.filter((index, tabLinkElement) => {
return $(tabLinkElement).parents('.page')[0] === $newTabEl.parents('.page')[0];
});
if (app.theme === 'ios' && $tabLinkEl.length === 0 && tabRoute) {
const $pageEl = $newTabEl.parents('.page');
const $navbarEl = $(app.navbar.getElByPage($pageEl));
$tabLinkEl = $navbarEl.find(`[data-route-tab-id="${tabRoute.route.tab.id}"]`);
if ($tabLinkEl.length === 0) {
$tabLinkEl = $navbarEl.find(`.tab-link[href="${tabRoute.url}"]`);
}
}
}
}
if ($tabLinkEl.length > 0) {
// Find related link for old tab
let $oldTabLinkEl;
if ($oldTabEl && $oldTabEl.length > 0) {
// Search by id
const oldTabId = $oldTabEl.attr('id');
if (oldTabId) $oldTabLinkEl = $(`.tab-link[href="#${oldTabId}"]`);
// Search by data-tab
if (!$oldTabLinkEl || ($oldTabLinkEl && $oldTabLinkEl.length === 0)) {
$('[data-tab]').each((index, tabLinkElement) => {
if ($oldTabEl.is($(tabLinkElement).attr('data-tab'))) $oldTabLinkEl = $(tabLinkElement);
});
}
if (!$oldTabLinkEl || ($oldTabLinkEl && $oldTabLinkEl.length === 0)) {
$oldTabLinkEl = $tabLinkEl.siblings('.tab-link-active');
}
} else if (tabRoute) {
$oldTabLinkEl = $tabLinkEl.siblings('.tab-link-active');
}
if ($oldTabLinkEl && $oldTabLinkEl.length > 1 && $oldTabEl && $oldTabEl.parents('.page').length) {
// eslint-disable-next-line
$oldTabLinkEl = $oldTabLinkEl.filter((index, tabLinkElement) => {
return $(tabLinkElement).parents('.page')[0] === $oldTabEl.parents('.page')[0];
});
}
if ($oldTabLinkEl && $oldTabLinkEl.length > 0) $oldTabLinkEl.removeClass('tab-link-active');
// Update links' classes
if ($tabLinkEl && $tabLinkEl.length > 0) {
$tabLinkEl.addClass('tab-link-active');
// Material Highlight
if (app.theme === 'md' && app.toolbar) {
const $tabbarEl = $tabLinkEl.parents('.tabbar, .tabbar-labels');
if ($tabbarEl.length > 0) {
app.toolbar.setHighlight($tabbarEl);
}
}
}
}
return {
$newTabEl,
newTabEl: $newTabEl[0],
$oldTabEl,
oldTabEl: $oldTabEl[0],
onTabsChanged,
animated,
};
},
};
var Tabs = {
name: 'tabs',
create() {
const app = this;
Utils.extend(app, {
tab: {
show: Tab.show.bind(app),
},
});
},
clicks: {
'.tab-link': function tabLinkClick($clickedEl, data = {}) {
const app = this;
if (($clickedEl.attr('href') && $clickedEl.attr('href').indexOf('#') === 0) || $clickedEl.attr('data-tab')) {
app.tab.show({
tabEl: data.tab || $clickedEl.attr('href'),
tabLinkEl: $clickedEl,
animate: data.animate,
});
}
},
},
};
function swipePanel$1(panel) {
const app = panel.app;
Utils.extend(panel, {
swipeable: true,
swipeInitialized: true,
});
const params = app.params.panel;
const { $el, $backdropEl, side, effect } = panel;
let otherPanel;
let isTouched;
let isMoved;
let isScrolling;
const touchesStart = {};
let touchStartTime;
let touchesDiff;
let translate;
let backdropOpacity;
let panelWidth;
let direction;
let $viewEl;
let touchMoves = 0;
function handleTouchStart(e) {
if (!panel.swipeable) return;
if (!app.panel.allowOpen || (!params.swipe && !params.swipeOnlyClose) || isTouched) return;
if ($('.modal-in, .photo-browser-in').length > 0) return;
otherPanel = app.panel[side === 'left' ? 'right' : 'left'] || {};
if (!panel.opened && otherPanel.opened) return;
if (!(params.swipeCloseOpposite || params.swipeOnlyClose)) {
if (otherPanel.opened) return;
}
if (e.target && e.target.nodeName.toLowerCase() === 'input' && e.target.type === 'range') return;
if ($(e.target).closest('.range-slider, .tabs-swipeable-wrap, .calendar-months, .no-swipe-panel').length > 0) return;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
if (params.swipeOnlyClose && !panel.opened) {
return;
}
if (params.swipe !== 'both' && params.swipeCloseOpposite && params.swipe !== side && !panel.opened) {
return;
}
if (params.swipeActiveArea && !panel.opened) {
if (side === 'left') {
if (touchesStart.x > params.swipeActiveArea) return;
}
if (side === 'right') {
if (touchesStart.x < app.width - params.swipeActiveArea) return;
}
}
touchMoves = 0;
$viewEl = $(panel.getViewEl());
isMoved = false;
isTouched = true;
isScrolling = undefined;
touchStartTime = Utils.now();
direction = undefined;
}
function handleTouchMove(e) {
if (!isTouched) return;
touchMoves += 1;
if (touchMoves < 2) return;
if (e.f7PreventSwipePanel || app.preventSwipePanelBySwipeBack || app.preventSwipePanel) {
isTouched = false;
return;
}
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
if (!direction) {
if (pageX > touchesStart.x) {
direction = 'to-right';
} else {
direction = 'to-left';
}
if (params.swipe === 'both') {
if (params.swipeActiveArea > 0) {
if (side === 'left' && touchesStart.x > params.swipeActiveArea) {
isTouched = false;
return;
}
if (side === 'right' && touchesStart.x < app.width - params.swipeActiveArea) {
isTouched = false;
return;
}
}
}
if ($el.hasClass('panel-visible-by-breakpoint')) {
isTouched = false;
return;
}
if (
(side === 'left' &&
(
direction === 'to-left' && !$el.hasClass('panel-active')
)
)
||
(side === 'right' &&
(
direction === 'to-right' && !$el.hasClass('panel-active')
)
)
) {
isTouched = false;
return;
}
}
if (params.swipeNoFollow) {
const timeDiff = (new Date()).getTime() - touchStartTime;
if (timeDiff < 300) {
if (direction === 'to-left') {
if (side === 'right') app.panel.open(side);
if (side === 'left' && $el.hasClass('panel-active')) app.panel.close();
}
if (direction === 'to-right') {
if (side === 'left') app.panel.open(side);
if (side === 'right' && $el.hasClass('panel-active')) app.panel.close();
}
}
isTouched = false;
isMoved = false;
return;
}
if (!isMoved) {
if (!panel.opened) {
$el.show();
$backdropEl.show();
$el.trigger('panel:swipeopen', panel);
panel.emit('local::swipeOpen panelSwipeOpen', panel);
}
panelWidth = $el[0].offsetWidth;
$el.transition(0);
}
isMoved = true;
e.preventDefault();
let threshold = panel.opened ? 0 : -params.swipeThreshold;
if (side === 'right') threshold = -threshold;
touchesDiff = (pageX - touchesStart.x) + threshold;
if (side === 'right') {
if (effect === 'cover') {
translate = touchesDiff + (panel.opened ? 0 : panelWidth);
if (translate < 0) translate = 0;
if (translate > panelWidth) {
translate = panelWidth;
}
} else {
translate = touchesDiff - (panel.opened ? panelWidth : 0);
if (translate > 0) translate = 0;
if (translate < -panelWidth) {
translate = -panelWidth;
}
}
} else {
translate = touchesDiff + (panel.opened ? panelWidth : 0);
if (translate < 0) translate = 0;
if (translate > panelWidth) {
translate = panelWidth;
}
}
if (effect === 'reveal') {
$viewEl.transform(`translate3d(${translate}px,0,0)`).transition(0);
$backdropEl.transform(`translate3d(${translate}px,0,0)`).transition(0);
$el.trigger('panel:swipe', panel, Math.abs(translate / panelWidth));
panel.emit('local::swipe panelSwipe', panel, Math.abs(translate / panelWidth));
} else {
if (side === 'left') translate -= panelWidth;
$el.transform(`translate3d(${translate}px,0,0)`).transition(0);
$backdropEl.transition(0);
backdropOpacity = 1 - Math.abs(translate / panelWidth);
$backdropEl.css({ opacity: backdropOpacity });
$el.trigger('panel:swipe', panel, Math.abs(translate / panelWidth));
panel.emit('local::swipe panelSwipe', panel, Math.abs(translate / panelWidth));
}
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
const timeDiff = (new Date()).getTime() - touchStartTime;
let action;
const edge = (translate === 0 || Math.abs(translate) === panelWidth);
if (!panel.opened) {
if (effect === 'cover') {
if (translate === 0) {
action = 'swap'; // open
} else if (timeDiff < 300 && Math.abs(translate) > 0) {
action = 'swap'; // open
} else if (timeDiff >= 300 && Math.abs(translate) < panelWidth / 2) {
action = 'swap'; // open
} else {
action = 'reset'; // close
}
} else if (translate === 0) {
action = 'reset';
} else if (
(timeDiff < 300 && Math.abs(translate) > 0)
||
(timeDiff >= 300 && (Math.abs(translate) >= panelWidth / 2))
) {
action = 'swap';
} else {
action = 'reset';
}
} else if (effect === 'cover') {
if (translate === 0) {
action = 'reset'; // open
} else if (timeDiff < 300 && Math.abs(translate) > 0) {
action = 'swap'; // open
} else if (timeDiff >= 300 && Math.abs(translate) < panelWidth / 2) {
action = 'reset'; // open
} else {
action = 'swap'; // close
}
} else if (translate === -panelWidth) {
action = 'reset';
} else if (
(timeDiff < 300 && Math.abs(translate) >= 0)
||
(timeDiff >= 300 && (Math.abs(translate) <= panelWidth / 2))
) {
if (side === 'left' && translate === panelWidth) action = 'reset';
else action = 'swap';
} else {
action = 'reset';
}
if (action === 'swap') {
if (panel.opened) {
panel.close(!edge);
} else {
panel.open(!edge);
}
}
if (action === 'reset') {
if (!panel.opened) {
if (edge) {
$el.css({ display: '' });
} else {
const target = effect === 'reveal' ? $viewEl : $el;
$('html').addClass('with-panel-transitioning');
target.transitionEnd(() => {
if ($el.hasClass('panel-active')) return;
$el.css({ display: '' });
$('html').removeClass('with-panel-transitioning');
});
}
}
}
if (effect === 'reveal') {
Utils.nextFrame(() => {
$viewEl.transition('');
$viewEl.transform('');
});
}
$el.transition('').transform('');
$backdropEl.css({ display: '' }).transform('').transition('').css('opacity', '');
}
// Add Events
app.on('touchstart:passive', handleTouchStart);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
panel.on('panelDestroy', () => {
app.off('touchstart:passive', handleTouchStart);
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
});
}
class Panel$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const panel = this;
const el = params.el;
const $el = $(el);
if ($el.length === 0) return panel;
if ($el[0].f7Panel) return $el[0].f7Panel;
$el[0].f7Panel = panel;
let { opened, side, effect } = params;
if (typeof opened === 'undefined') opened = $el.hasClass('panel-active');
if (typeof side === 'undefined') side = $el.hasClass('panel-left') ? 'left' : 'right';
if (typeof effect === 'undefined') effect = $el.hasClass('panel-cover') ? 'cover' : 'reveal';
if (!app.panel[side]) {
Utils.extend(app.panel, {
[side]: panel,
});
}
let $backdropEl = $('.panel-backdrop');
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="panel-backdrop"></div>');
$backdropEl.insertBefore($el);
}
Utils.extend(panel, {
app,
side,
effect,
$el,
el: $el[0],
opened,
$backdropEl,
backdropEl: $backdropEl[0],
});
// Install Modules
panel.useModules();
// Init
panel.init();
return panel;
}
init() {
const panel = this;
const app = panel.app;
if (app.params.panel[`${panel.side}Breakpoint`]) {
panel.initBreakpoints();
}
{
if (
(app.params.panel.swipe === panel.side)
||
(app.params.panel.swipe === 'both')
||
(app.params.panel.swipe && app.params.panel.swipe !== panel.side && app.params.panel.swipeCloseOpposite)
) {
panel.initSwipePanel();
}
}
}
getViewEl() {
const panel = this;
const app = panel.app;
let viewEl;
if (app.root.children('.views').length > 0) {
viewEl = app.root.children('.views')[0];
} else {
viewEl = app.root.children('.view')[0];
}
return viewEl;
}
setBreakpoint() {
const panel = this;
const app = panel.app;
const { side, $el } = panel;
const $viewEl = $(panel.getViewEl());
const breakpoint = app.params.panel[`${side}Breakpoint`];
const wasVisible = $el.hasClass('panel-visible-by-breakpoint');
if (app.width >= breakpoint) {
if (!wasVisible) {
$('html').removeClass(`with-panel-${side}-reveal with-panel-${side}-cover with-panel`);
$el.css('display', '').addClass('panel-visible-by-breakpoint').removeClass('panel-active');
panel.onOpen();
panel.onOpened();
$viewEl.css({
[`margin-${side}`]: `${$el.width()}px`,
});
app.allowPanelOpen = true;
app.emit('local::breakpoint panelBreakpoint');
panel.$el.trigger('panel:breakpoint', panel);
}
} else if (wasVisible) {
$el.css('display', '').removeClass('panel-visible-by-breakpoint panel-active');
panel.onClose();
panel.onClosed();
$viewEl.css({
[`margin-${side}`]: '',
});
app.emit('local::breakpoint panelBreakpoint');
panel.$el.trigger('panel:breakpoint', panel);
}
}
initBreakpoints() {
const panel = this;
const app = panel.app;
panel.resizeHandler = function resizeHandler() {
panel.setBreakpoint();
};
if (app.params.panel[`${panel.side}Breakpoint`]) {
app.on('resize', panel.resizeHandler);
}
panel.setBreakpoint();
return panel;
}
initSwipePanel() {
{
swipePanel$1(this);
}
}
destroy() {
let panel = this;
const app = panel.app;
panel.emit('local::beforeDestroy panelBeforeDestroy', panel);
panel.$el.trigger('panel:beforedestroy', panel);
if (panel.resizeHandler) {
app.off('resize', panel.resizeHandler);
}
panel.$el.trigger('panel:destroy', panel);
panel.emit('local::destroy panelDestroy');
delete app.panel[panel.side];
delete panel.el.f7Panel;
Utils.deleteProps(panel);
panel = null;
}
open(animate = true) {
const panel = this;
const app = panel.app;
if (!app.panel.allowOpen) return false;
const { side, effect, $el, $backdropEl, opened } = panel;
// Ignore if opened
if (opened || $el.hasClass('panel-visible-by-breakpoint') || $el.hasClass('panel-active')) return false;
// Close if some panel is opened
app.panel.close(side === 'left' ? 'right' : 'left', animate);
app.panel.allowOpen = false;
$el[animate ? 'removeClass' : 'addClass']('not-animated');
$el
.css({ display: 'block' })
.addClass('panel-active');
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
$backdropEl.show();
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
panel._clientLeft = $el[0].clientLeft;
$('html').addClass(`with-panel with-panel-${side}-${effect}`);
panel.onOpen();
// Transition End;
const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;
function panelTransitionEnd() {
transitionEndTarget.transitionEnd((e) => {
if ($(e.target).is(transitionEndTarget)) {
if ($el.hasClass('panel-active')) {
panel.onOpened();
$backdropEl.css({ display: '' });
} else {
panel.onClosed();
$backdropEl.css({ display: '' });
}
} else panelTransitionEnd();
});
}
if (animate) {
panelTransitionEnd();
} else {
panel.onOpened();
$backdropEl.css({ display: '' });
}
return true;
}
close(animate = true) {
const panel = this;
const app = panel.app;
const { side, effect, $el, $backdropEl, opened } = panel;
if (!opened || $el.hasClass('panel-visible-by-breakpoint') || !$el.hasClass('panel-active')) return false;
$el[animate ? 'removeClass' : 'addClass']('not-animated');
$el.removeClass('panel-active');
$backdropEl[animate ? 'removeClass' : 'addClass']('not-animated');
const transitionEndTarget = effect === 'reveal' ? $el.nextAll('.view, .views').eq(0) : $el;
panel.onClose();
app.panel.allowOpen = false;
if (animate) {
transitionEndTarget.transitionEnd(() => {
if ($el.hasClass('panel-active')) return;
$el.css({ display: '' });
$('html').removeClass('with-panel-transitioning');
panel.onClosed();
});
$('html')
.removeClass(`with-panel with-panel-${side}-${effect}`)
.addClass('with-panel-transitioning');
} else {
$el.css({ display: '' });
$el.removeClass('not-animated');
$('html').removeClass(`with-panel with-panel-transitioning with-panel-${side}-${effect}`);
panel.onClosed();
}
return true;
}
onOpen() {
const panel = this;
panel.opened = true;
panel.$el.trigger('panel:open', panel);
panel.emit('local::open panelOpen', panel);
}
onOpened() {
const panel = this;
const app = panel.app;
app.panel.allowOpen = true;
panel.$el.trigger('panel:opened', panel);
panel.emit('local::opened panelOpened', panel);
}
onClose() {
const panel = this;
panel.opened = false;
panel.$el.addClass('panel-closing');
panel.$el.trigger('panel:close', panel);
panel.emit('local::close panelClose', panel);
}
onClosed() {
const panel = this;
const app = panel.app;
app.panel.allowOpen = true;
panel.$el.removeClass('panel-closing');
panel.$el.trigger('panel:closed', panel);
panel.emit('local::closed panelClosed', panel);
}
}
var Panel = {
name: 'panel',
params: {
panel: {
leftBreakpoint: 0,
rightBreakpoint: 0,
swipe: undefined, // or 'left' or 'right' or 'both'
swipeActiveArea: 0,
swipeCloseOpposite: true,
swipeOnlyClose: false,
swipeNoFollow: false,
swipeThreshold: 0,
closeByBackdropClick: true,
},
},
static: {
Panel: Panel$1,
},
instance: {
panel: {
allowOpen: true,
},
},
create() {
const app = this;
Utils.extend(app.panel, {
disableSwipe(panel = 'both') {
let side;
let panels = [];
if (typeof panel === 'string') {
if (panel === 'both') {
side = 'both';
panels = [app.panel.left, app.panel.right];
} else {
side = panel;
panels = app.panel[side];
}
} else {
panels = [panel];
}
panels.forEach((panelInstance) => {
if (panelInstance) Utils.extend(panelInstance, { swipeable: false });
});
},
enableSwipe(panel = 'both') {
let panels = [];
let side;
if (typeof panel === 'string') {
side = panel;
if (
(app.params.panel.swipe === 'left' && side === 'right') ||
(app.params.panel.swipe === 'right' && side === 'left') ||
side === 'both'
) {
side = 'both';
app.params.panel.swipe = side;
panels = [app.panel.left, app.panel.right];
} else {
app.params.panel.swipe = side;
panels.push(app.panel[side]);
}
} else if (panel) {
panels.push(panel);
}
if (panels.length) {
panels.forEach((panelInstance) => {
if (!panelInstance) return;
if (!panelInstance.swipeInitialized) {
panelInstance.initSwipePanel();
} else {
Utils.extend(panelInstance, { swipeable: true });
}
});
}
},
create(params) {
return new Panel$1(app, params);
},
open(side, animate) {
let panelSide = side;
if (!panelSide) {
if ($('.panel').length > 1) {
return false;
}
panelSide = $('.panel').hasClass('panel-left') ? 'left' : 'right';
}
if (!panelSide) return false;
if (app.panel[panelSide]) {
return app.panel[panelSide].open(animate);
}
const $panelEl = $(`.panel-${panelSide}`);
if ($panelEl.length > 0) {
return app.panel.create({ el: $panelEl }).open(animate);
}
return false;
},
close(side, animate) {
let $panelEl;
let panelSide;
if (panelSide) {
panelSide = side;
$panelEl = $(`.panel-${panelSide}`);
} else {
$panelEl = $('.panel.panel-active');
panelSide = $panelEl.hasClass('panel-left') ? 'left' : 'right';
}
if (!panelSide) return false;
if (app.panel[panelSide]) {
return app.panel[panelSide].close(animate);
}
if ($panelEl.length > 0) {
return app.panel.create({ el: $panelEl }).close(animate);
}
return false;
},
get(side) {
let panelSide = side;
if (!panelSide) {
if ($('.panel').length > 1) {
return undefined;
}
panelSide = $('.panel').hasClass('panel-left') ? 'left' : 'right';
}
if (!panelSide) return undefined;
if (app.panel[panelSide]) {
return app.panel[panelSide];
}
const $panelEl = $(`.panel-${panelSide}`);
if ($panelEl.length > 0) {
return app.panel.create({ el: $panelEl });
}
return undefined;
},
});
},
on: {
init() {
const app = this;
// Create Panels
$('.panel').each((index, panelEl) => {
const side = $(panelEl).hasClass('panel-left') ? 'left' : 'right';
app.panel[side] = app.panel.create({ el: panelEl, side });
});
},
},
clicks: {
'.panel-open': function open(clickedEl, data = {}) {
const app = this;
let side = 'left';
if (data.panel === 'right' || ($('.panel').length === 1 && $('.panel').hasClass('panel-right'))) {
side = 'right';
}
app.panel.open(side, data.animate);
},
'.panel-close': function close(clickedEl, data = {}) {
const app = this;
const side = data.panel;
app.panel.close(side, data.animate);
},
'.panel-backdrop': function close() {
const app = this;
const $panelEl = $('.panel-active');
const instance = $panelEl[0] && $panelEl[0].f7Panel;
$panelEl.trigger('panel:backdrop-click');
if (instance) {
instance.emit('backdropClick', instance);
}
app.emit('panelBackdropClick', instance || $panelEl[0]);
if (app.params.panel.closeByBackdropClick) app.panel.close();
},
},
};
var Card = {
name: 'card',
};
var Chip = {
name: 'chip',
};
// Form Data
const FormData$1 = {
store(form, data) {
const app = this;
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
// Store form data in app.formsData
app.form.data[`form-${formId}`] = data;
// Store form data in local storage also
try {
window.localStorage[`f7form-${formId}`] = JSON.stringify(data);
} catch (e) {
throw e;
}
},
get(form) {
const app = this;
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
try {
if (window.localStorage[`f7form-${formId}`]) {
return JSON.parse(window.localStorage[`f7form-${formId}`]);
}
} catch (e) {
throw e;
}
if (app.form.data[`form-${formId}`]) {
return app.form.data[`form-${formId}`];
}
return undefined;
},
remove(form) {
const app = this;
let formId = form;
const $formEl = $(form);
if ($formEl.length && $formEl.is('form') && $formEl.attr('id')) {
formId = $formEl.attr('id');
}
// Delete form data from app.formsData
if (app.form.data[`form-${formId}`]) {
app.form.data[`form-${formId}`] = '';
delete app.form.data[`form-${formId}`];
}
// Delete form data from local storage also
try {
if (window.localStorage[`f7form-${formId}`]) {
window.localStorage[`f7form-${formId}`] = '';
window.localStorage.removeItem(`f7form-${formId}`);
}
} catch (e) {
throw e;
}
},
};
// Form Storage
const FormStorage = {
init(formEl) {
const app = this;
const $formEl = $(formEl);
const formId = $formEl.attr('id');
if (!formId) return;
const initialData = app.form.getFormData(formId);
if (initialData) {
app.form.fillFromData($formEl, initialData);
}
function store() {
const data = app.form.convertToData($formEl);
if (!data) return;
app.form.storeFormData(formId, data);
$formEl.trigger('form:storedata', data);
app.emit('formStoreData', $formEl[0], data);
}
$formEl.on('change submit', store);
},
destroy(formEl) {
const $formEl = $(formEl);
$formEl.off('change submit');
},
};
// Form To/From Data
function formToData(formEl) {
const app = this;
const $formEl = $(formEl).eq(0);
if ($formEl.length === 0) return undefined;
// Form data
const data = {};
// Skip input types
const skipTypes = ['submit', 'image', 'button', 'file'];
const skipNames = [];
$formEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
const name = $inputEl.attr('name');
const type = $inputEl.attr('type');
const tag = inputEl.nodeName.toLowerCase();
if (skipTypes.indexOf(type) >= 0) return;
if (skipNames.indexOf(name) >= 0 || !name) return;
if (tag === 'select' && $inputEl.prop('multiple')) {
skipNames.push(name);
data[name] = [];
$formEl.find(`select[name="${name}"] option`).each((index, el) => {
if (el.selected) data[name].push(el.value);
});
} else {
switch (type) {
case 'checkbox':
skipNames.push(name);
data[name] = [];
$formEl.find(`input[name="${name}"]`).each((index, el) => {
if (el.checked) data[name].push(el.value);
});
break;
case 'radio':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each((index, el) => {
if (el.checked) data[name] = el.value;
});
break;
default:
data[name] = $inputEl.val();
break;
}
}
});
$formEl.trigger('form:todata', data);
app.emit('formToData', $formEl[0], data);
return data;
}
function formFromData(formEl, formData) {
const app = this;
const $formEl = $(formEl).eq(0);
if (!$formEl.length) return;
let data = formData;
const formId = $formEl.attr('id');
if (!data && formId) {
data = app.form.getFormData(formId);
}
if (!data) return;
// Skip input types
const skipTypes = ['submit', 'image', 'button', 'file'];
const skipNames = [];
$formEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
const name = $inputEl.attr('name');
const type = $inputEl.attr('type');
const tag = inputEl.nodeName.toLowerCase();
if (typeof data[name] === 'undefined' || data[name] === null) return;
if (skipTypes.indexOf(type) >= 0) return;
if (skipNames.indexOf(name) >= 0 || !name) return;
if (tag === 'select' && $inputEl.prop('multiple')) {
skipNames.push(name);
$formEl.find(`select[name="${name}"] option`).each((index, el) => {
const selectEl = el;
if (data[name].indexOf(el.value) >= 0) selectEl.selected = true;
else selectEl.selected = false;
});
} else {
switch (type) {
case 'checkbox':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each((index, el) => {
const checkboxEl = el;
if (data[name].indexOf(el.value) >= 0) checkboxEl.checked = true;
else checkboxEl.checked = false;
});
break;
case 'radio':
skipNames.push(name);
$formEl.find(`input[name="${name}"]`).each((index, el) => {
const radioEl = el;
if (data[name] === el.value) radioEl.checked = true;
else radioEl.checked = false;
});
break;
default:
$inputEl.val(data[name]);
break;
}
}
if (tag === 'select' || tag === 'input' || tag === 'textarea') {
$inputEl.trigger('change', 'fromdata');
}
});
$formEl.trigger('form:fromdata', data);
app.emit('formFromData', $formEl[0], data);
}
function initAjaxForm() {
const app = this;
function onSubmitChange(e, fromData) {
const $formEl = $(this);
if (e.type === 'change' && !$formEl.hasClass('form-ajax-submit-onchange')) return;
if (e.type === 'submit') e.preventDefault();
if (e.type === 'change' && fromData === 'fromdata') return;
const method = ($formEl.attr('method') || 'GET').toUpperCase();
const contentType = $formEl.prop('enctype') || $formEl.attr('enctype');
const url = $formEl.attr('action');
if (!url) return;
let data;
if (method === 'POST') data = new window.FormData($formEl[0]);
else data = Utils.serializeObject(app.form.convertToData($formEl[0]));
const xhr = app.request({
method,
url,
contentType,
data,
beforeSend() {
$formEl.trigger('formajax:beforesend', data, xhr);
app.emit('formAjaxBeforeSend', $formEl[0], data, xhr);
},
error() {
$formEl.trigger('formajax:error', data, xhr);
app.emit('formAjaxError', $formEl[0], data, xhr);
},
complete() {
$formEl.trigger('formajax:complete', data, xhr);
app.emit('formAjaxComplete', $formEl[0], data, xhr);
},
success() {
$formEl.trigger('formajax:success', data, xhr);
app.emit('formAjaxSuccess', $formEl[0], data, xhr);
},
});
}
$(document).on('submit change', 'form.form-ajax-submit, form.form-ajax-submit-onchange', onSubmitChange);
}
var Form = {
name: 'form',
create() {
const app = this;
Utils.extend(app, {
form: {
data: {},
storeFormData: FormData$1.store.bind(app),
getFormData: FormData$1.get.bind(app),
removeFormData: FormData$1.remove.bind(app),
convertToData: formToData.bind(app),
fillFromData: formFromData.bind(app),
storage: {
init: FormStorage.init.bind(app),
destroy: FormStorage.destroy.bind(app),
},
},
});
},
on: {
init() {
const app = this;
initAjaxForm.call(app);
},
tabBeforeRemove(tabEl) {
const app = this;
$(tabEl).find('.form-store-data').each((index, formEl) => {
app.form.storage.destroy(formEl);
});
},
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.form-store-data').each((index, formEl) => {
app.form.storage.init(formEl);
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.form-store-data').each((index, formEl) => {
app.form.storage.destroy(formEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.form-store-data').each((index, formEl) => {
app.form.storage.init(formEl);
});
},
},
};
const Input = {
ignoreTypes: ['checkbox', 'button', 'submit', 'range', 'radio', 'image'],
createTextareaResizableShadow() {
const $shadowEl = $(document.createElement('textarea'));
$shadowEl.addClass('textarea-resizable-shadow');
$shadowEl.prop({
disabled: true,
readonly: true,
});
Input.textareaResizableShadow = $shadowEl;
},
textareaResizableShadow: undefined,
resizeTextarea(textareaEl) {
const app = this;
const $textareaEl = $(textareaEl);
if (!Input.textareaResizableShadow) {
Input.createTextareaResizableShadow();
}
const $shadowEl = Input.textareaResizableShadow;
if (!$textareaEl.length) return;
if (!$textareaEl.hasClass('resizable')) return;
if (Input.textareaResizableShadow.parents().length === 0) {
app.root.append($shadowEl);
}
const styles = window.getComputedStyle($textareaEl[0]);
('padding margin width font-size font-family font-style font-weight line-height font-variant text-transform letter-spacing border box-sizing display').split(' ').forEach((style) => {
let styleValue = styles[style];
if (('font-size line-height letter-spacing width').split(' ').indexOf(style) >= 0) {
styleValue = styleValue.replace(',', '.');
}
$shadowEl.css(style, styleValue);
});
const currentHeight = $textareaEl[0].clientHeight;
$shadowEl.val('');
const initialHeight = $shadowEl[0].scrollHeight;
$shadowEl.val($textareaEl.val());
$shadowEl.css('height', 0);
const scrollHeight = $shadowEl[0].scrollHeight;
if (currentHeight !== scrollHeight) {
if (scrollHeight > initialHeight) {
$textareaEl.css('height', `${scrollHeight}px`);
$textareaEl.trigger('textarea:resize', { initialHeight, currentHeight, scrollHeight });
} else if (scrollHeight < currentHeight) {
$textareaEl.css('height', '');
$textareaEl.trigger('textarea:resize', { initialHeight, currentHeight, scrollHeight });
}
}
},
validate(inputEl) {
const $inputEl = $(inputEl);
if (!$inputEl.length) return;
const $itemInputEl = $inputEl.parents('.item-input');
const validity = $inputEl[0].validity;
const validationMessage = $inputEl.dataset().errorMessage || $inputEl[0].validationMessage || '';
if (!validity) return;
if (!validity.valid) {
let $errorEl = $inputEl.nextAll('.item-input-error-message');
if (validationMessage) {
if ($errorEl.length === 0) {
$errorEl = $('<div class="item-input-error-message"></div>');
$errorEl.insertAfter($inputEl);
}
$errorEl.text(validationMessage);
}
if ($errorEl.length > 0) {
$itemInputEl.addClass('item-input-with-error-message');
}
$itemInputEl.addClass('item-input-invalid');
$inputEl.addClass('input-invalid');
} else {
$itemInputEl.removeClass('item-input-invalid item-input-with-error-message');
$inputEl.removeClass('input-invalid');
}
},
validateInputs(el) {
const app = this;
$(el).find('input, textarea, select').each((index, inputEl) => {
app.input.validate(inputEl);
});
},
focus(inputEl) {
const $inputEl = $(inputEl);
const type = $inputEl.attr('type');
if (Input.ignoreTypes.indexOf(type) >= 0) return;
const $itemInputEl = $inputEl.parents('.item-input');
$itemInputEl.addClass('item-input-focused');
$inputEl.addClass('input-focused');
},
blur(inputEl) {
$(inputEl).parents('.item-input').removeClass('item-input-focused');
$(inputEl).removeClass('input-focused');
},
checkEmptyState(inputEl) {
const $inputEl = $(inputEl);
const value = $inputEl.val();
const $itemInputEl = $inputEl.parents('.item-input');
if ((value && (typeof value === 'string' && value.trim() !== '')) || (Array.isArray(value) && value.length > 0)) {
$itemInputEl.addClass('item-input-with-value');
$inputEl.addClass('input-with-value');
$inputEl.trigger('input:notempty');
} else {
$itemInputEl.removeClass('item-input-with-value');
$inputEl.removeClass('input-with-value');
$inputEl.trigger('input:empty');
}
},
scrollIntoView(inputEl, duration = 0, centered) {
const $inputEl = $(inputEl);
const $scrollableEl = $inputEl.parents('.page-content, .panel').eq(0);
if (!$scrollableEl.length) {
return false;
}
const contentHeight = $scrollableEl[0].offsetHeight;
const contentScrollTop = $scrollableEl[0].scrollTop;
const contentPaddingTop = parseInt($scrollableEl.css('padding-top'), 10);
const contentPaddingBottom = parseInt($scrollableEl.css('padding-bottom'), 10);
const contentOffsetTop = $scrollableEl.offset().top - contentScrollTop;
const inputOffsetTop = $inputEl.offset().top - contentOffsetTop;
const inputHeight = $inputEl[0].offsetHeight;
const min = (inputOffsetTop + contentScrollTop) - contentPaddingTop;
const max = ((inputOffsetTop + contentScrollTop) - contentHeight) + contentPaddingBottom + inputHeight;
const centeredPosition = min + ((max - min) / 2);
if (contentScrollTop > min) {
$scrollableEl.scrollTop(centered ? centeredPosition : min, duration);
return true;
} else if (contentScrollTop < max) {
$scrollableEl.scrollTop(centered ? centeredPosition : max, duration);
return true;
}
return false;
},
init() {
const app = this;
Input.createTextareaResizableShadow();
function onFocus() {
const inputEl = this;
if (app.params.input.scrollIntoViewOnFocus) {
if (Device.android) {
$(window).once('resize', () => {
if (document && document.activeElement === inputEl) {
app.input.scrollIntoView(inputEl, app.params.input.scrollIntoViewCentered);
}
});
} else {
app.input.scrollIntoView(inputEl, app.params.input.scrollIntoViewCentered);
}
}
app.input.focus(inputEl);
}
function onBlur() {
const $inputEl = $(this);
const tag = $inputEl[0].nodeName.toLowerCase();
app.input.blur($inputEl);
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
app.input.validate($inputEl);
}
// Resize textarea
if (tag === 'textarea' && $inputEl.hasClass('resizable')) {
if (Input.textareaResizableShadow) Input.textareaResizableShadow.remove();
}
}
function onChange() {
const $inputEl = $(this);
const type = $inputEl.attr('type');
const tag = $inputEl[0].nodeName.toLowerCase();
if (Input.ignoreTypes.indexOf(type) >= 0) return;
// Check Empty State
app.input.checkEmptyState($inputEl);
// Check validation
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
app.input.validate($inputEl);
}
// Resize textarea
if (tag === 'textarea' && $inputEl.hasClass('resizable')) {
app.input.resizeTextarea($inputEl);
}
}
function onInvalid(e) {
const $inputEl = $(this);
if ($inputEl.dataset().validate || $inputEl.attr('validate') !== null) {
e.preventDefault();
app.input.validate($inputEl);
}
}
function clearInput() {
const $clicked = $(this);
const $inputEl = $clicked.siblings('input, textarea').eq(0);
const previousValue = $inputEl.val();
$inputEl
.val('')
.trigger('change')
.focus()
.trigger('input:clear', previousValue);
}
$(document).on('click', '.input-clear-button', clearInput);
$(document).on('change input', 'input, textarea, select', onChange, true);
$(document).on('focus', 'input, textarea, select', onFocus, true);
$(document).on('blur', 'input, textarea, select', onBlur, true);
$(document).on('invalid', 'input, textarea, select', onInvalid, true);
},
};
var Input$1 = {
name: 'input',
params: {
input: {
scrollIntoViewOnFocus: Device.android,
scrollIntoViewCentered: false,
},
},
create() {
const app = this;
Utils.extend(app, {
input: {
scrollIntoView: Input.scrollIntoView.bind(app),
focus: Input.focus.bind(app),
blur: Input.blur.bind(app),
validate: Input.validate.bind(app),
validateInputs: Input.validate.bind(app),
checkEmptyState: Input.checkEmptyState.bind(app),
resizeTextarea: Input.resizeTextarea.bind(app),
init: Input.init.bind(app),
},
});
},
on: {
init() {
const app = this;
app.input.init();
},
tabMounted(tabEl) {
const app = this;
const $tabEl = $(tabEl);
$tabEl.find('.item-input').each((itemInputIndex, itemInputEl) => {
const $itemInputEl = $(itemInputEl);
$itemInputEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
if (Input.ignoreTypes.indexOf($inputEl.attr('type')) >= 0) return;
app.input.checkEmptyState($inputEl);
});
});
$tabEl.find('textarea.resizable').each((textareaIndex, textareaEl) => {
app.input.resizeTextarea(textareaEl);
});
},
pageInit(page) {
const app = this;
const $pageEl = page.$el;
$pageEl.find('.item-input').each((itemInputIndex, itemInputEl) => {
const $itemInputEl = $(itemInputEl);
$itemInputEl.find('input, select, textarea').each((inputIndex, inputEl) => {
const $inputEl = $(inputEl);
if (Input.ignoreTypes.indexOf($inputEl.attr('type')) >= 0) return;
app.input.checkEmptyState($inputEl);
});
});
$pageEl.find('textarea.resizable').each((textareaIndex, textareaEl) => {
app.input.resizeTextarea(textareaEl);
});
},
},
};
var Checkbox = {
name: 'checkbox',
};
var Radio = {
name: 'radio',
};
class Toggle$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const toggle = this;
const defaults = {};
// Extend defaults with modules params
toggle.useModulesParams(defaults);
toggle.params = Utils.extend(defaults, params);
const el = toggle.params.el;
if (!el) return toggle;
const $el = $(el);
if ($el.length === 0) return toggle;
const $inputEl = $el.children('input[type="checkbox"]');
Utils.extend(toggle, {
app,
$el,
el: $el[0],
$inputEl,
inputEl: $inputEl[0],
disabled: $el.hasClass('disabled') || $inputEl.hasClass('disabled') || $inputEl.attr('disabled') || $inputEl[0].disabled,
});
Object.defineProperty(toggle, 'checked', {
enumerable: true,
configurable: true,
set(checked) {
if (!toggle || typeof toggle.$inputEl === 'undefined') return;
if (toggle.checked === checked) return;
$inputEl[0].checked = checked;
toggle.$inputEl.trigger('change');
},
get() {
return $inputEl[0].checked;
},
});
$el[0].f7Toggle = toggle;
let isTouched;
const touchesStart = {};
let isScrolling;
let touchesDiff;
let toggleWidth;
let touchStartTime;
let touchStartChecked;
function handleTouchStart(e) {
if (isTouched || toggle.disabled) return;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchesDiff = 0;
isTouched = true;
isScrolling = undefined;
touchStartTime = Utils.now();
touchStartChecked = toggle.checked;
toggleWidth = $el[0].offsetWidth;
Utils.nextTick(() => {
if (isTouched) {
$el.addClass('toggle-active-state');
}
});
}
function handleTouchMove(e) {
if (!isTouched || toggle.disabled) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
const inverter = app.rtl ? -1 : 1;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
touchesDiff = pageX - touchesStart.x;
let changed;
if (touchesDiff * inverter < 0 && Math.abs(touchesDiff) > toggleWidth / 3 && touchStartChecked) {
changed = true;
}
if (touchesDiff * inverter > 0 && Math.abs(touchesDiff) > toggleWidth / 3 && !touchStartChecked) {
changed = true;
}
if (changed) {
touchesStart.x = pageX;
toggle.checked = !touchStartChecked;
touchStartChecked = !touchStartChecked;
}
}
function handleTouchEnd() {
if (!isTouched || toggle.disabled) {
if (isScrolling) $el.removeClass('toggle-active-state');
isTouched = false;
return;
}
const inverter = app.rtl ? -1 : 1;
isTouched = false;
$el.removeClass('toggle-active-state');
let changed;
if ((Utils.now() - touchStartTime) < 300) {
if (touchesDiff * inverter < 0 && touchStartChecked) {
changed = true;
}
if (touchesDiff * inverter > 0 && !touchStartChecked) {
changed = true;
}
if (changed) {
toggle.checked = !touchStartChecked;
}
}
}
function handleInputChange() {
toggle.$el.trigger('toggle:change', toggle);
toggle.emit('local::change toggleChange', toggle);
}
toggle.attachEvents = function attachEvents() {
{
if (!Support$1.touch) return;
const passive = Support$1.passiveListener ? { passive: true } : false;
$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
}
toggle.$inputEl.on('change', handleInputChange);
};
toggle.detachEvents = function detachEvents() {
{
if (!Support$1.touch) return;
const passive = Support$1.passiveListener ? { passive: true } : false;
$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
}
toggle.$inputEl.off('change', handleInputChange);
};
// Install Modules
toggle.useModules();
// Init
toggle.init();
}
toggle() {
const toggle = this;
toggle.checked = !toggle.checked;
}
init() {
const toggle = this;
toggle.attachEvents();
}
destroy() {
let toggle = this;
toggle.$el.trigger('toggle:beforedestroy', toggle);
toggle.emit('local::beforeDestroy toggleBeforeDestroy', toggle);
delete toggle.$el[0].f7Toggle;
toggle.detachEvents();
Utils.deleteProps(toggle);
toggle = null;
}
}
var Toggle = {
name: 'toggle',
create() {
const app = this;
app.toggle = ConstructorMethods({
defaultSelector: '.toggle',
constructor: Toggle$1,
app,
domProp: 'f7Toggle',
});
},
static: {
Toggle: Toggle$1,
},
on: {
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.toggle-init').each((index, toggleEl) => app.toggle.create({ el: toggleEl }));
},
tabBeforeRemove(tabEl) {
$(tabEl).find('.toggle-init').each((index, toggleEl) => {
if (toggleEl.f7Toggle) toggleEl.f7Toggle.destroy();
});
},
pageInit(page) {
const app = this;
page.$el.find('.toggle-init').each((index, toggleEl) => app.toggle.create({ el: toggleEl }));
},
pageBeforeRemove(page) {
page.$el.find('.toggle-init').each((index, toggleEl) => {
if (toggleEl.f7Toggle) toggleEl.f7Toggle.destroy();
});
},
},
};
class Range$1 extends Framework7Class {
constructor(app, params) {
super(params, [app]);
const range = this;
const defaults = {
dual: false,
step: 1,
label: false,
};
// Extend defaults with modules params
range.useModulesParams(defaults);
range.params = Utils.extend(defaults, params);
const el = range.params.el;
if (!el) return range;
const $el = $(el);
if ($el.length === 0) return range;
const dataset = $el.dataset();
('step min max value').split(' ').forEach((paramName) => {
if (typeof params[paramName] === 'undefined' && typeof dataset[paramName] !== 'undefined') {
range.params[paramName] = parseFloat(dataset[paramName]);
}
});
('dual label').split(' ').forEach((paramName) => {
if (typeof params[paramName] === 'undefined' && typeof dataset[paramName] !== 'undefined') {
range.params[paramName] = dataset[paramName];
}
});
if (!range.params.value) {
if (typeof dataset.value !== 'undefined') range.params.value = dataset.value;
if (typeof dataset.valueLeft !== 'undefined' && typeof dataset.valueRight !== 'undefined') {
range.params.value = [parseFloat(dataset.valueLeft), parseFloat(dataset.valueRight)];
}
}
let $inputEl;
if (!range.params.dual) {
if (range.params.inputEl) {
$inputEl = $(range.params.inputEl);
} else if ($el.find('input[type="range"]').length) {
$inputEl = $el.find('input[type="range"]').eq(0);
}
}
Utils.extend(range, range.params, {
$el,
el: $el[0],
$inputEl,
inputEl: $inputEl ? $inputEl[0] : undefined,
});
if ($inputEl) {
('step min max').split(' ').forEach((paramName) => {
if (!params[paramName] && $inputEl.attr(paramName)) {
range.params[paramName] = parseFloat($inputEl.attr(paramName));
range[paramName] = parseFloat($inputEl.attr(paramName));
}
if (typeof $inputEl.val() !== 'undefined') {
range.params.value = parseFloat($inputEl.val());
range.value = parseFloat($inputEl.val());
}
});
}
// Dual
if (range.dual) {
$el.addClass('range-slider-dual');
}
if (range.label) {
$el.addClass('range-slider-label');
}
// Check for layout
const $barEl = $('<div class="range-bar"></div>');
const $barActiveEl = $('<div class="range-bar-active"></div>');
$barEl.append($barActiveEl);
// Create Knobs
const knobHTML = `
<div class="range-knob-wrap">
<div class="range-knob"></div>
${range.label ? '<div class="range-knob-label"></div>' : ''}
</div>
`;
const knobs = [$(knobHTML)];
const labels = [];
if (range.dual) {
knobs.push($(knobHTML));
}
$el.append($barEl);
knobs.forEach(($knobEl) => {
$el.append($knobEl);
});
// Labels
if (range.label) {
labels.push(knobs[0].find('.range-knob-label'));
if (range.dual) {
labels.push(knobs[1].find('.range-knob-label'));
}
}
Utils.extend(range, {
app,
knobs,
labels,
$barEl,
$barActiveEl,
});
$el[0].f7Range = range;
// Touch Events
let isTouched;
const touchesStart = {};
let isScrolling;
let rangeOffsetLeft;
let $touchedKnobEl;
let dualValueIndex;
function handleTouchStart(e) {
if (isTouched) return;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
isTouched = true;
isScrolling = undefined;
rangeOffsetLeft = $el.offset().left;
let progress;
if (range.app.rtl) {
progress = ((rangeOffsetLeft + range.rangeWidth) - touchesStart.x) / range.rangeWidth;
} else {
progress = (touchesStart.x - rangeOffsetLeft) / range.rangeWidth;
}
let newValue = (progress * (range.max - range.min)) + range.min;
if (range.dual) {
if (Math.abs(range.value[0] - newValue) < Math.abs(range.value[1] - newValue)) {
dualValueIndex = 0;
$touchedKnobEl = range.knobs[0];
newValue = [newValue, range.value[1]];
} else {
dualValueIndex = 1;
$touchedKnobEl = range.knobs[1];
newValue = [range.value[0], newValue];
}
} else {
$touchedKnobEl = range.knobs[0];
newValue = (progress * (range.max - range.min)) + range.min;
}
Utils.nextTick(() => {
if (isTouched) $touchedKnobEl.addClass('range-knob-active-state');
}, 70);
range.setValue(newValue);
}
function handleTouchMove(e) {
if (!isTouched) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
let progress;
if (range.app.rtl) {
progress = ((rangeOffsetLeft + range.rangeWidth) - pageX) / range.rangeWidth;
} else {
progress = (pageX - rangeOffsetLeft) / range.rangeWidth;
}
let newValue = (progress * (range.max - range.min)) + range.min;
if (range.dual) {
let leftValue;
let rightValue;
if (dualValueIndex === 0) {
leftValue = newValue;
rightValue = range.value[1];
if (leftValue > rightValue) {
rightValue = leftValue;
}
} else {
leftValue = range.value[0];
rightValue = newValue;
if (rightValue < leftValue) {
leftValue = rightValue;
}
}
newValue = [leftValue, rightValue];
}
range.setValue(newValue);
}
function handleTouchEnd() {
if (!isTouched) {
if (isScrolling) $touchedKnobEl.removeClass('range-knob-active-state');
isTouched = false;
return;
}
isTouched = false;
$touchedKnobEl.removeClass('range-knob-active-state');
}
function handleResize() {
range.calcSize();
range.layout();
}
range.attachEvents = function attachEvents() {
const passive = Support$1.passiveListener ? { passive: true } : false;
range.$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
app.on('tabShow', handleResize);
app.on('resize', handleResize);
};
range.detachEvents = function detachEvents() {
const passive = Support$1.passiveListener ? { passive: true } : false;
range.$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
app.off('tabShow', handleResize);
app.off('resize', handleResize);
};
// Install Modules
range.useModules();
// Init
range.init();
return range;
}
calcSize() {
const range = this;
const width = range.$el.outerWidth();
if (width === 0) return;
range.rangeWidth = width;
range.knobWidth = range.knobs[0].outerWidth();
}
layout() {
const range = this;
const {
app,
knobWidth,
rangeWidth,
min,
max,
knobs,
$barActiveEl,
value,
label,
labels,
} = range;
const positionProperty = app.rtl ? 'right' : 'left';
if (range.dual) {
const progress = [((value[0] - min) / (max - min)), ((value[1] - min) / (max - min))];
$barActiveEl.css({
[positionProperty]: `${progress[0] * 100}%`,
width: `${(progress[1] - progress[0]) * 100}%`,
});
knobs.forEach(($knobEl, knobIndex) => {
let leftPos = rangeWidth * progress[knobIndex];
const realLeft = (rangeWidth * progress[knobIndex]) - (knobWidth / 2);
if (realLeft < 0) leftPos = knobWidth / 2;
if ((realLeft + knobWidth) > rangeWidth) leftPos = rangeWidth - (knobWidth / 2);
$knobEl.css(positionProperty, `${leftPos}px`);
if (label) labels[knobIndex].text(value[knobIndex]);
});
} else {
const progress = ((value - min) / (max - min));
$barActiveEl.css('width', `${progress * 100}%`);
let leftPos = rangeWidth * progress;
const realLeft = (rangeWidth * progress) - (knobWidth / 2);
if (realLeft < 0) leftPos = knobWidth / 2;
if ((realLeft + knobWidth) > rangeWidth) leftPos = rangeWidth - (knobWidth / 2);
knobs[0].css(positionProperty, `${leftPos}px`);
if (label) labels[0].text(value);
}
if ((range.dual && value.indexOf(min) >= 0) || (!range.dual && value === min)) {
range.$el.addClass('range-slider-min');
} else {
range.$el.removeClass('range-slider-min');
}
if ((range.dual && value.indexOf(max) >= 0) || (!range.dual && value === max)) {
range.$el.addClass('range-slider-max');
} else {
range.$el.removeClass('range-slider-max');
}
}
setValue(newValue) {
const range = this;
const { step, min, max } = range;
if (range.dual) {
let newValues = newValue;
if (!Array.isArray(newValues)) newValues = [newValue, newValue];
if (newValue[0] > newValue[1]) {
newValues = [newValues[0], newValues[0]];
}
newValues = newValues.map(value => Math.max(Math.min(Math.round(value / step) * step, max), min));
if (newValues[0] === range.value[0] && newValues[1] === range.value[1]) {
return range;
}
newValues.forEach((value, valueIndex) => {
range.value[valueIndex] = value;
});
range.layout();
} else {
const value = Math.max(Math.min(Math.round(newValue / step) * step, max), min);
range.value = value;
range.layout();
}
// Events
range.$el.trigger('range:change', range, range.value);
if (range.$inputEl && !range.dual) {
range.$inputEl.val(range.value).trigger('input change');
}
range.emit('local::change rangeChange', range, range.value);
return range;
}
getValue() {
return this.value;
}
init() {
const range = this;
range.calcSize();
range.layout();
range.attachEvents();
return range;
}
destroy() {
let range = this;
range.$el.trigger('range:beforedestroy', range);
range.emit('local::beforeDestroy rangeBeforeDestroy', range);
delete range.$el[0].f7Range;
range.detachEvents();
Utils.deleteProps(range);
range = null;
}
}
var Range = {
name: 'range',
create() {
const app = this;
app.range = Utils.extend(
ConstructorMethods({
defaultSelector: '.range-slider',
constructor: Range$1,
app,
domProp: 'f7Range',
}),
{
getValue(el = '.range-slider') {
const range = app.range.get(el);
if (range) return range.getValue();
return undefined;
},
setValue(el = '.range-slider', value) {
const range = app.range.get(el);
if (range) return range.setValue(value);
return undefined;
},
}
);
},
static: {
Range: Range$1,
},
on: {
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.range-slider-init').each((index, rangeEl) => new Range$1(app, {
el: rangeEl,
}));
},
tabBeforeRemove(tabEl) {
$(tabEl).find('.range-slider-init').each((index, rangeEl) => {
if (rangeEl.f7Range) rangeEl.f7Range.destroy();
});
},
pageInit(page) {
const app = this;
page.$el.find('.range-slider-init').each((index, rangeEl) => new Range$1(app, {
el: rangeEl,
}));
},
pageBeforeRemove(page) {
page.$el.find('.range-slider-init').each((index, rangeEl) => {
if (rangeEl.f7Range) rangeEl.f7Range.destroy();
});
},
},
};
class SmartSelect$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const ss = this;
ss.app = app;
const defaults = Utils.extend({
on: {},
}, app.params.smartSelect);
const $el = $(params.el).eq(0);
if ($el.length === 0) return ss;
const $selectEl = $el.find('select').eq(0);
if ($selectEl.length === 0) return ss;
let $valueEl = $(params.valueEl);
if ($valueEl.length === 0) {
$valueEl = $('<div class="item-after"></div>');
$valueEl.insertAfter($el.find('.item-title'));
}
// Extend defaults with modules params
ss.useModulesParams(defaults);
// View
const view = $el.parents('.view').length && $el.parents('.view')[0].f7View;
if (!view) {
throw Error('Smart Select requires initialized View');
}
// Url
let url = params.url;
if (!url) {
if ($el.attr('href') && $el.attr('href') !== '#') url = $el.attr('href');
else url = `${$selectEl.attr('name').toLowerCase()}-select/`;
}
if (!url) url = ss.params.url;
const multiple = $selectEl[0].multiple;
const inputType = multiple ? 'checkbox' : 'radio';
const id = Utils.now();
Utils.extend(ss, {
params: Utils.extend(defaults, params),
$el,
el: $el[0],
$selectEl,
selectEl: $selectEl[0],
$valueEl,
valueEl: $valueEl[0],
url,
multiple,
inputType,
id,
view,
inputName: `${inputType}-${id}`,
selectName: $selectEl.attr('name'),
maxLength: $selectEl.attr('maxlength') || params.maxLength,
});
$el[0].f7SmartSelect = ss;
// Events
function onClick() {
ss.open();
}
function onChange() {
ss.setValue();
}
ss.attachEvents = function attachEvents() {
$el.on('click', onClick);
$el.on('change', 'input[type="checkbox"], input[type="radio"]', onChange);
};
ss.detachEvents = function detachEvents() {
$el.off('click', onClick);
$el.off('change', 'input[type="checkbox"], input[type="radio"]', onChange);
};
function handleInputChange() {
let optionEl;
let text;
const inputEl = this;
const value = inputEl.value;
let optionText = [];
let displayAs;
if (inputEl.type === 'checkbox') {
for (let i = 0; i < ss.selectEl.options.length; i += 1) {
optionEl = ss.selectEl.options[i];
if (optionEl.value === value) {
optionEl.selected = inputEl.checked;
}
if (optionEl.selected) {
displayAs = optionEl.dataset ? optionEl.dataset.displayAs : $(optionEl).data('display-value-as');
text = displayAs && typeof displayAs !== 'undefined' ? displayAs : optionEl.textContent;
optionText.push(text.trim());
}
}
if (ss.maxLength) {
ss.checkMaxLength();
}
} else {
optionEl = ss.$selectEl.find(`option[value="${value}"]`)[0];
displayAs = optionEl.dataset ? optionEl.dataset.displayAs : $(optionEl).data('display-as');
text = displayAs && typeof displayAs !== 'undefined' ? displayAs : optionEl.textContent;
optionText = [text];
ss.selectEl.value = value;
}
ss.$selectEl.trigger('change');
ss.$valueEl.text(optionText.join(', '));
if (ss.params.closeOnSelect && ss.inputType === 'radio') {
ss.close();
}
}
ss.attachInputsEvents = function attachInputsEvents() {
ss.$containerEl.on('change', 'input[type="checkbox"], input[type="radio"]', handleInputChange);
};
ss.detachInputsEvents = function detachInputsEvents() {
ss.$containerEl.off('change', 'input[type="checkbox"], input[type="radio"]', handleInputChange);
};
// Install Modules
ss.useModules();
// Init
ss.init();
return ss;
}
checkMaxLength() {
const ss = this;
const $containerEl = ss.$containerEl;
if (ss.selectEl.selectedOptions.length >= ss.maxLength) {
$containerEl.find('input[type="checkbox"]').each((index, inputEl) => {
if (!inputEl.checked) {
$(inputEl).parents('li').addClass('disabled');
} else {
$(inputEl).parents('li').removeClass('disabled');
}
});
} else {
$containerEl.find('.disabled').removeClass('disabled');
}
}
setValue(value) {
const ss = this;
let valueArray = [];
if (typeof value !== 'undefined') {
if (Array.isArray(value)) {
valueArray = value;
} else {
valueArray = [value];
}
} else {
ss.$selectEl.find('option').each((optionIndex, optionEl) => {
const $optionEl = $(optionEl);
if (optionEl.selected) {
const displayAs = optionEl.dataset ? optionEl.dataset.displayAs : $optionEl.data('display-value-as');
if (displayAs && typeof displayAs !== 'undefined') {
valueArray.push(displayAs);
} else {
valueArray.push(optionEl.textContent.trim());
}
}
});
}
ss.$valueEl.text(valueArray.join(', '));
}
getItemsData() {
const ss = this;
const items = [];
let previousGroupEl;
ss.$selectEl.find('option').each((index, optionEl) => {
const $optionEl = $(optionEl);
const optionData = $optionEl.dataset();
const optionImage = optionData.optionImage || ss.params.optionImage;
const optionIcon = optionData.optionIcon || ss.params.optionIcon;
const optionHasMedia = optionImage || optionIcon;
// if (material) optionHasMedia = optionImage || optionIcon;
const optionColor = optionData.optionColor;
let optionClassName = optionData.optionClass || '';
if ($optionEl[0].disabled) optionClassName += ' disabled';
const optionGroupEl = $optionEl.parent('optgroup')[0];
const optionGroupLabel = optionGroupEl && optionGroupEl.label;
let optionIsLabel = false;
if (optionGroupEl && optionGroupEl !== previousGroupEl) {
optionIsLabel = true;
previousGroupEl = optionGroupEl;
items.push({
groupLabel: optionGroupLabel,
isLabel: optionIsLabel,
});
}
items.push({
value: $optionEl[0].value,
text: $optionEl[0].textContent.trim(),
selected: $optionEl[0].selected,
groupEl: optionGroupEl,
groupLabel: optionGroupLabel,
image: optionImage,
icon: optionIcon,
color: optionColor,
className: optionClassName,
disabled: $optionEl[0].disabled,
id: ss.id,
hasMedia: optionHasMedia,
checkbox: ss.inputType === 'checkbox',
radio: ss.inputType === 'radio',
inputName: ss.inputName,
inputType: ss.inputType,
});
});
ss.items = items;
return items;
}
renderSearchbar() {
const ss = this;
if (ss.params.renderSearchbar) return ss.params.renderSearchbar.call(ss);
const searchbarHTML = `
<form class="searchbar">
<div class="searchbar-inner">
<div class="searchbar-input-wrap">
<input type="search" placeholder="${ss.params.searchbarPlaceholder}"/>
<i class="searchbar-icon"></i>
<span class="input-clear-button"></span>
</div>
<span class="searchbar-disable-button">${ss.params.searchbarDisableText}</span>
</div>
</form>
`;
return searchbarHTML;
}
renderItem(item, index) {
const ss = this;
if (ss.params.renderItem) return ss.params.renderItem.call(ss, item, index);
let itemHtml;
if (item.isLabel) {
itemHtml = `<li class="item-divider">${item.groupLabel}</li>`;
} else {
itemHtml = `
<li class="${item.className || ''}">
<label class="item-${item.inputType} item-content">
<input type="${item.inputType}" name="${item.inputName}" value="${item.value}" ${item.selected ? 'checked' : ''}/>
<i class="icon icon-${item.inputType}"></i>
${item.hasMedia ? `
<div class="item-media">
${item.icon ? `<i class="icon ${item.icon}"></i>` : ''}
${item.image ? `<img src="${item.image}">` : ''}
</div>
` : ''}
<div class="item-inner">
<div class="item-title${item.color ? ` color-${item.color}` : ''}">${item.text}</div>
</div>
</label>
</li>
`;
}
return itemHtml;
}
renderItems() {
const ss = this;
if (ss.params.renderItems) return ss.params.renderItems.call(ss, ss.items);
const itemsHtml = `
${ss.items.map((item, index) => `${ss.renderItem(item, index)}`).join('')}
`;
return itemsHtml;
}
renderPage() {
const ss = this;
if (ss.params.renderPage) return ss.params.renderPage.call(ss, ss.items);
let pageTitle = ss.params.pageTitle;
if (typeof pageTitle === 'undefined') {
pageTitle = ss.$el.find('.item-title').text().trim();
}
const pageHtml = `
<div class="page smart-select-page" data-name="smart-select-page" data-select-name="${ss.selectName}">
<div class="navbar ${ss.params.navbarColorTheme ? `color-theme-${ss.params.navbarColorTheme}` : ''}">
<div class="navbar-inner sliding ${ss.params.navbarColorTheme ? `color-theme-${ss.params.navbarColorTheme}` : ''}">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="ios-only">${ss.params.pageBackLinkText}</span>
</a>
</div>
${pageTitle ? `<div class="title">${pageTitle}</div>` : ''}
${ss.params.searchbar ? `<div class="subnavbar">${ss.renderSearchbar()}</div>` : ''}
</div>
</div>
${ss.params.searchbar ? '<div class="searchbar-backdrop"></div>' : ''}
<div class="page-content">
<div class="list smart-select-list-${ss.id} ${ss.params.virtualList ? ' virtual-list' : ''} ${ss.params.formColorTheme ? `color-theme-${ss.params.formColorTheme}` : ''}">
<ul>${!ss.params.virtualList && ss.renderItems(ss.items)}</ul>
</div>
</div>
</div>
`;
return pageHtml;
}
renderPopup() {
const ss = this;
if (ss.params.renderPopup) return ss.params.renderPopup.call(ss, ss.items);
let pageTitle = ss.params.pageTitle;
if (typeof pageTitle === 'undefined') {
pageTitle = ss.$el.find('.item-title').text().trim();
}
const popupHtml = `
<div class="popup smart-select-popup" data-select-name="${ss.selectName}">
<div class="view">
<div class="page smart-select-page ${ss.params.searchbar ? 'page-with-subnavbar' : ''}" data-name="smart-select-page">
<div class="navbar${ss.params.navbarColorTheme ? `theme-${ss.params.navbarColorTheme}` : ''}">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link popup-close">
<i class="icon icon-back"></i>
<span class="ios-only">${ss.params.popupCloseLinkText}</span>
</a>
</div>
${pageTitle ? `<div class="title">${pageTitle}</div>` : ''}
${ss.params.searchbar ? `<div class="subnavbar">${ss.renderSearchbar()}</div>` : ''}
</div>
</div>
${ss.params.searchbar ? '<div class="searchbar-backdrop"></div>' : ''}
<div class="page-content">
<div class="list smart-select-list-${ss.id} ${ss.params.virtualList ? ' virtual-list' : ''}${ss.params.formColorTheme ? `theme-${ss.params.formColorTheme}` : ''}">
<ul>${!ss.params.virtualList && ss.renderItems(ss.items)}</ul>
</div>
</div>
</div>
</div>
</div>
`;
return popupHtml;
}
renderSheet() {
const ss = this;
if (ss.params.renderSheet) return ss.params.renderSheet.call(ss, ss.items);
const sheetHtml = `
<div class="sheet-modal smart-select-sheet" data-select-name="${ss.selectName}">
<div class="toolbar ${ss.params.toolbarColorTheme ? `theme-${ss.params.toolbarColorTheme}` : ''}">
<div class="toolbar-inner">
<div class="left"></div>
<div class="right">
<a class="link sheet-close">${ss.params.sheetCloseLinkText}</a>
</div>
</div>
</div>
<div class="sheet-modal-inner">
<div class="page-content">
<div class="list smart-select-list-${ss.id} ${ss.params.virtualList ? ' virtual-list' : ''}${ss.params.formColorTheme ? `theme-${ss.params.formColorTheme}` : ''}">
<ul>${!ss.params.virtualList && ss.renderItems(ss.items)}</ul>
</div>
</div>
</div>
</div>
`;
return sheetHtml;
}
renderPopover() {
const ss = this;
if (ss.params.renderPopover) return ss.params.renderPopover.call(ss, ss.items);
const popoverHtml = `
<div class="popover smart-select-popover" data-select-name="${ss.selectName}">
<div class="popover-inner">
<div class="list smart-select-list-${ss.id} ${ss.params.virtualList ? ' virtual-list' : ''}${ss.params.formColorTheme ? `theme-${ss.params.formColorTheme}` : ''}">
<ul>${!ss.params.virtualList && ss.renderItems(ss.items)}</ul>
</div>
</div>
</div>
`;
return popoverHtml;
}
onOpen(type, containerEl) {
const ss = this;
const app = ss.app;
const $containerEl = $(containerEl);
ss.$containerEl = $containerEl;
ss.openedIn = type;
ss.opened = true;
// Init VL
if (ss.params.virtualList) {
ss.vl = app.virtualList.create({
el: $containerEl.find('.virtual-list'),
items: ss.items,
renderItem: ss.renderItem.bind(ss),
height: ss.params.virtualListHeight,
searchByItem(query, item) {
if (item.text && item.text.toLowerCase().indexOf(query.trim().toLowerCase()) >= 0) return true;
return false;
},
});
}
// Init SB
if (ss.params.searchbar) {
ss.searchbar = app.searchbar.create({
el: $containerEl.find('.searchbar'),
backdropEl: $containerEl.find('.searchbar-backdrop'),
searchContainer: `.smart-select-list-${ss.id}`,
searchIn: '.item-title',
});
}
// Check for max length
if (ss.maxLength) {
ss.checkMaxLength();
}
// Close on select
if (ss.params.closeOnSelect) {
ss.$containerEl.find(`input[type="radio"][name="${ss.inputName}"]:checked`).parents('label').once('click', () => {
ss.close();
});
}
// Attach input events
ss.attachInputsEvents();
ss.$el.trigger('smartselect:open', ss);
ss.emit('local::open smartSelectOpen', ss);
}
onOpened() {
const ss = this;
ss.$el.trigger('smartselect:opened', ss);
ss.emit('local::opened smartSelectOpened', ss);
}
onClose() {
const ss = this;
if (ss.destroyed) return;
// Destroy VL
if (ss.vl && ss.vl.destroy) {
ss.vl.destroy();
ss.vl = null;
delete ss.vl;
}
// Destroy SB
if (ss.searchbar && ss.searchbar.destroy) {
ss.searchbar.destroy();
ss.searchbar = null;
delete ss.searchbar;
}
// Detach events
ss.detachInputsEvents();
ss.$el.trigger('smartselect:close', ss);
ss.emit('local::close smartSelectClose', ss);
}
onClosed() {
const ss = this;
if (ss.destroyed) return;
ss.opened = false;
ss.$containerEl = null;
delete ss.$containerEl;
ss.$el.trigger('smartselect:closed', ss);
ss.emit('local::closed smartSelectClosed', ss);
}
openPage() {
const ss = this;
if (ss.opened) return ss;
ss.getItemsData();
const pageHtml = ss.renderPage(ss.items);
ss.view.router.navigate({
url: ss.url,
route: {
content: pageHtml,
path: ss.url,
on: {
pageBeforeIn(e, page) {
ss.onOpen('page', page.el);
},
pageAfterIn(e, page) {
ss.onOpened('page', page.el);
},
pageBeforeOut(e, page) {
ss.onClose('page', page.el);
},
pageAfterOut(e, page) {
ss.onClosed('page', page.el);
},
},
},
});
return ss;
}
openPopup() {
const ss = this;
if (ss.opened) return ss;
ss.getItemsData();
const popupHtml = ss.renderPopup(ss.items);
const popupParams = {
content: popupHtml,
on: {
popupOpen(popup) {
ss.onOpen('popup', popup.el);
},
popupOpened(popup) {
ss.onOpened('popup', popup.el);
},
popupClose(popup) {
ss.onClose('popup', popup.el);
},
popupClosed(popup) {
ss.onClosed('popup', popup.el);
},
},
};
if (ss.params.routableModals) {
ss.view.router.navigate({
url: ss.url,
route: {
path: ss.url,
popup: popupParams,
},
});
} else {
ss.modal = ss.app.popup.create(popupParams).open();
}
return ss;
}
openSheet() {
const ss = this;
if (ss.opened) return ss;
ss.getItemsData();
const sheetHtml = ss.renderSheet(ss.items);
const sheetParams = {
content: sheetHtml,
backdrop: false,
scrollToEl: ss.$el,
closeByOutsideClick: true,
on: {
sheetOpen(sheet) {
ss.onOpen('sheet', sheet.el);
},
sheetOpened(sheet) {
ss.onOpened('sheet', sheet.el);
},
sheetClose(sheet) {
ss.onClose('sheet', sheet.el);
},
sheetClosed(sheet) {
ss.onClosed('sheet', sheet.el);
},
},
};
if (ss.params.routableModals) {
ss.view.router.navigate({
url: ss.url,
route: {
path: ss.url,
sheet: sheetParams,
},
});
} else {
ss.modal = ss.app.sheet.create(sheetParams).open();
}
return ss;
}
openPopover() {
const ss = this;
if (ss.opened) return ss;
ss.getItemsData();
const popoverHtml = ss.renderPopover(ss.items);
const popoverParams = {
content: popoverHtml,
targetEl: ss.$el,
on: {
popoverOpen(popover) {
ss.onOpen('popover', popover.el);
},
popoverOpened(popover) {
ss.onOpened('popover', popover.el);
},
popoverClose(popover) {
ss.onClose('popover', popover.el);
},
popoverClosed(popover) {
ss.onClosed('popover', popover.el);
},
},
};
if (ss.params.routableModals) {
ss.view.router.navigate({
url: ss.url,
route: {
path: ss.url,
popover: popoverParams,
},
});
} else {
ss.modal = ss.app.popover.create(popoverParams).open();
}
return ss;
}
open(type) {
const ss = this;
if (ss.opened) return ss;
const openIn = type || ss.params.openIn;
ss[`open${openIn.split('').map((el, index) => {
if (index === 0) return el.toUpperCase();
return el;
}).join('')}`]();
return ss;
}
close() {
const ss = this;
if (!ss.opened) return ss;
if (ss.params.routableModals || ss.openedIn === 'page') {
ss.view.router.back();
} else {
ss.modal.once('modalClosed', () => {
Utils.nextTick(() => {
ss.modal.destroy();
delete ss.modal;
});
});
ss.modal.close();
}
return ss;
}
init() {
const ss = this;
ss.attachEvents();
ss.setValue();
}
destroy() {
const ss = this;
ss.emit('local::beforeDestroy smartSelectBeforeDestroy', ss);
ss.$el.trigger('smartselect:beforedestroy', ss);
ss.detachEvents();
delete ss.$el[0].f7SmartSelect;
Utils.deleteProps(ss);
ss.destroyed = true;
}
}
var SmartSelect = {
name: 'smartSelect',
params: {
smartSelect: {
el: undefined,
valueEl: undefined,
openIn: 'page', // or 'popup' or 'sheet' or 'popover'
pageTitle: undefined,
pageBackLinkText: 'Back',
popupCloseLinkText: 'Close',
sheetCloseLinkText: 'Done',
searchbar: false,
searchbarPlaceholder: 'Search',
searchbarDisableText: 'Cancel',
closeOnSelect: false,
virtualList: false,
virtualListHeight: undefined,
formColorTheme: undefined,
navbarColorTheme: undefined,
routableModals: true,
url: 'select/',
/*
Custom render functions
*/
renderPage: undefined,
renderPopup: undefined,
renderSheet: undefined,
renderPopover: undefined,
renderItems: undefined,
renderItem: undefined,
renderSearchbar: undefined,
},
},
static: {
SmartSelect: SmartSelect$1,
},
create() {
const app = this;
app.smartSelect = Utils.extend(
ConstructorMethods({
defaultSelector: '.smart-select',
constructor: SmartSelect$1,
app,
domProp: 'f7SmartSelect',
}),
{
open(smartSelectEl) {
const ss = app.smartSelect.get(smartSelectEl);
if (ss && ss.open) return ss.open();
return undefined;
},
close(smartSelectEl) {
const ss = app.smartSelect.get(smartSelectEl);
if (ss && ss.close) return ss.close();
return undefined;
},
}
);
},
on: {
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.smart-select-init').each((index, smartSelectEl) => {
app.smartSelect.create(Utils.extend({ el: smartSelectEl }, $(smartSelectEl).dataset()));
});
},
tabBeforeRemove(tabEl) {
$(tabEl).find('.smart-select-init').each((index, smartSelectEl) => {
if (smartSelectEl.f7SmartSelect && smartSelectEl.f7SmartSelect.destroy) {
smartSelectEl.f7SmartSelect.destroy();
}
});
},
pageInit(page) {
const app = this;
page.$el.find('.smart-select-init').each((index, smartSelectEl) => {
app.smartSelect.create(Utils.extend({ el: smartSelectEl }, $(smartSelectEl).dataset()));
});
},
pageBeforeRemove(page) {
page.$el.find('.smart-select-init').each((index, smartSelectEl) => {
if (smartSelectEl.f7SmartSelect && smartSelectEl.f7SmartSelect.destroy) {
smartSelectEl.f7SmartSelect.destroy();
}
});
},
},
clicks: {
'.smart-select': function open($clickedEl, data) {
const app = this;
if (!$clickedEl[0].f7SmartSelect) {
const ss = app.smartSelect.create(Utils.extend({ el: $clickedEl }, data));
ss.open();
}
},
},
};
var Grid = {
name: 'grid',
};
class Calendar$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const calendar = this;
calendar.params = Utils.extend({}, app.params.calendar, params);
let $containerEl;
if (calendar.params.containerEl) {
$containerEl = $(calendar.params.containerEl);
if ($containerEl.length === 0) return calendar;
}
let $inputEl;
if (calendar.params.inputEl) {
$inputEl = $(calendar.params.inputEl);
}
let view;
if ($inputEl) {
view = $inputEl.parents('.view').length && $inputEl.parents('.view')[0].f7View;
}
if (!view) view = app.views.main;
const isHorizontal = calendar.params.direction === 'horizontal';
let inverter = 1;
if (isHorizontal) {
inverter = app.rtl ? -1 : 1;
}
Utils.extend(calendar, {
app,
$containerEl,
containerEl: $containerEl && $containerEl[0],
inline: $containerEl && $containerEl.length > 0,
$inputEl,
inputEl: $inputEl && $inputEl[0],
initialized: false,
opened: false,
url: calendar.params.url,
isHorizontal,
inverter,
view,
animating: false,
});
function onInputClick() {
calendar.open();
}
function onInputFocus(e) {
e.preventDefault();
}
function onHtmlClick(e) {
const $targetEl = $(e.target);
if (calendar.isPopover()) return;
if (!calendar.opened) return;
if ($targetEl.closest('[class*="backdrop"]').length) return;
if ($inputEl && $inputEl.length > 0) {
if ($targetEl[0] !== $inputEl[0] && $targetEl.closest('.sheet-modal, .calendar-modal').length === 0) {
calendar.close();
}
} else if ($(e.target).closest('.sheet-modal, .calendar-modal').length === 0) {
calendar.close();
}
}
// Events
Utils.extend(calendar, {
attachInputEvents() {
calendar.$inputEl.on('click', onInputClick);
if (calendar.params.inputReadOnly) {
calendar.$inputEl.on('focus mousedown', onInputFocus);
}
},
detachInputEvents() {
calendar.$inputEl.off('click', onInputClick);
if (calendar.params.inputReadOnly) {
calendar.$inputEl.off('focus mousedown', onInputFocus);
}
},
attachHtmlEvents() {
app.on('click', onHtmlClick);
},
detachHtmlEvents() {
app.off('click', onHtmlClick);
},
});
calendar.attachCalendarEvents = function attachCalendarEvents() {
let allowItemClick = true;
let isTouched;
let isMoved;
let touchStartX;
let touchStartY;
let touchCurrentX;
let touchCurrentY;
let touchStartTime;
let touchEndTime;
let currentTranslate;
let wrapperWidth;
let wrapperHeight;
let percentage;
let touchesDiff;
let isScrolling;
const { $el, $wrapperEl } = calendar;
function handleTouchStart(e) {
if (isMoved || isTouched) return;
isTouched = true;
touchStartX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchCurrentX = touchStartX;
touchStartY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchCurrentY = touchStartY;
touchStartTime = (new Date()).getTime();
percentage = 0;
allowItemClick = true;
isScrolling = undefined;
currentTranslate = calendar.monthsTranslate;
}
function handleTouchMove(e) {
if (!isTouched) return;
const { isHorizontal: isH } = calendar;
touchCurrentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
touchCurrentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(touchCurrentY - touchStartY) > Math.abs(touchCurrentX - touchStartX));
}
if (isH && isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
if (calendar.animating) {
isTouched = false;
return;
}
allowItemClick = false;
if (!isMoved) {
// First move
isMoved = true;
wrapperWidth = $wrapperEl[0].offsetWidth;
wrapperHeight = $wrapperEl[0].offsetHeight;
$wrapperEl.transition(0);
}
touchesDiff = isH ? touchCurrentX - touchStartX : touchCurrentY - touchStartY;
percentage = touchesDiff / (isH ? wrapperWidth : wrapperHeight);
currentTranslate = ((calendar.monthsTranslate * calendar.inverter) + percentage) * 100;
// Transform wrapper
$wrapperEl.transform(`translate3d(${isH ? currentTranslate : 0}%, ${isH ? 0 : currentTranslate}%, 0)`);
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
touchEndTime = new Date().getTime();
if (touchEndTime - touchStartTime < 300) {
if (Math.abs(touchesDiff) < 10) {
calendar.resetMonth();
} else if (touchesDiff >= 10) {
if (app.rtl) calendar.nextMonth();
else calendar.prevMonth();
} else if (app.rtl) calendar.prevMonth();
else calendar.nextMonth();
} else if (percentage <= -0.5) {
if (app.rtl) calendar.prevMonth();
else calendar.nextMonth();
} else if (percentage >= 0.5) {
if (app.rtl) calendar.nextMonth();
else calendar.prevMonth();
} else {
calendar.resetMonth();
}
// Allow click
setTimeout(() => {
allowItemClick = true;
}, 100);
}
function handleDayClick(e) {
if (!allowItemClick) return;
let $dayEl = $(e.target).parents('.calendar-day');
if ($dayEl.length === 0 && $(e.target).hasClass('calendar-day')) {
$dayEl = $(e.target);
}
if ($dayEl.length === 0) return;
if ($dayEl.hasClass('calendar-day-disabled')) return;
if (!calendar.params.rangePicker) {
if ($dayEl.hasClass('calendar-day-next')) calendar.nextMonth();
if ($dayEl.hasClass('calendar-day-prev')) calendar.prevMonth();
}
const dateYear = $dayEl.attr('data-year');
const dateMonth = $dayEl.attr('data-month');
const dateDay = $dayEl.attr('data-day');
calendar.emit(
'local::dayClick calendarDayClick',
calendar,
$dayEl[0],
dateYear,
dateMonth,
dateDay
);
if (!$dayEl.hasClass('calendar-day-selected') || calendar.params.multiple || calendar.params.rangePicker) {
calendar.addValue(new Date(dateYear, dateMonth, dateDay, 0, 0, 0));
}
if (calendar.params.closeOnSelect) {
if (
(calendar.params.rangePicker && calendar.value.length === 2) ||
!calendar.params.rangePicker
) {
calendar.close();
}
}
}
function onNextMonthClick() {
calendar.nextMonth();
}
function onPrevMonthClick() {
calendar.prevMonth();
}
function onNextYearClick() {
calendar.nextYear();
}
function onPrevYearClick() {
calendar.prevYear();
}
const passiveListener = app.touchEvents.start === 'touchstart' && app.support.passiveListener ? { passive: true, capture: false } : false;
// Selectors clicks
$el.find('.calendar-prev-month-button').on('click', onPrevMonthClick);
$el.find('.calendar-next-month-button').on('click', onNextMonthClick);
$el.find('.calendar-prev-year-button').on('click', onPrevYearClick);
$el.find('.calendar-next-year-button').on('click', onNextYearClick);
// Day clicks
$wrapperEl.on('click', handleDayClick);
// Touch events
{
if (calendar.params.touchMove) {
$wrapperEl.on(app.touchEvents.start, handleTouchStart, passiveListener);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
}
}
calendar.detachCalendarEvents = function detachCalendarEvents() {
$el.find('.calendar-prev-month-button').off('click', onPrevMonthClick);
$el.find('.calendar-next-month-button').off('click', onNextMonthClick);
$el.find('.calendar-prev-year-button').off('click', onPrevYearClick);
$el.find('.calendar-next-year-button').off('click', onNextYearClick);
$wrapperEl.off('click', handleDayClick);
{
if (calendar.params.touchMove) {
$wrapperEl.off(app.touchEvents.start, handleTouchStart, passiveListener);
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
}
}
};
};
calendar.init();
return calendar;
}
initInput() {
const calendar = this;
if (!calendar.$inputEl) return;
if (calendar.params.inputReadOnly) calendar.$inputEl.prop('readOnly', true);
}
isPopover() {
const calendar = this;
const { app, modal, params } = calendar;
if (params.openIn === 'sheet') return false;
if (modal && modal.type !== 'popover') return false;
if (!calendar.inline && calendar.inputEl) {
if (params.openIn === 'popover') return true;
else if (app.device.ios) {
return !!app.device.ipad;
} else if (app.width >= 768) {
return true;
}
}
return false;
}
formatDate(d) {
const calendar = this;
const date = new Date(d);
const year = date.getFullYear();
const month = date.getMonth();
const month1 = month + 1;
const day = date.getDate();
const weekDay = date.getDay();
const { dateFormat, monthNames, monthNamesShort, dayNames, dayNamesShort } = calendar.params;
return dateFormat
.replace(/yyyy/g, year)
.replace(/yy/g, String(year).substring(2))
.replace(/mm/g, month1 < 10 ? `0${month1}` : month1)
.replace(/m(\W+)/g, `${month1}$1`)
.replace(/MM/g, monthNames[month])
.replace(/M(\W+)/g, `${monthNamesShort[month]}$1`)
.replace(/dd/g, day < 10 ? `0${day}` : day)
.replace(/d(\W+)/g, `${day}$1`)
.replace(/DD/g, dayNames[weekDay])
.replace(/D(\W+)/g, `${dayNamesShort[weekDay]}$1`);
}
formatValue() {
const calendar = this;
const { value } = calendar;
if (calendar.params.formatValue) {
return calendar.params.formatValue.call(calendar, value);
}
return value
.map(v => calendar.formatDate(v))
.join(calendar.params.rangePicker ? ' - ' : ', ');
}
addValue(newValue) {
const calendar = this;
const { multiple, rangePicker } = calendar.params;
if (multiple) {
if (!calendar.value) calendar.value = [];
let inValuesIndex;
for (let i = 0; i < calendar.value.length; i += 1) {
if (new Date(newValue).getTime() === new Date(calendar.value[i]).getTime()) {
inValuesIndex = i;
}
}
if (typeof inValuesIndex === 'undefined') {
calendar.value.push(newValue);
} else {
calendar.value.splice(inValuesIndex, 1);
}
calendar.updateValue();
} else if (rangePicker) {
if (!calendar.value) calendar.value = [];
if (calendar.value.length === 2 || calendar.value.length === 0) {
calendar.value = [];
}
if (calendar.value[0] !== newValue) calendar.value.push(newValue);
else calendar.value = [];
calendar.value.sort((a, b) => a - b);
calendar.updateValue();
} else {
calendar.value = [newValue];
calendar.updateValue();
}
}
setValue(values) {
const calendar = this;
calendar.value = values;
calendar.updateValue();
}
getValue() {
const calendar = this;
return calendar.value;
}
updateValue(onlyHeader) {
const calendar = this;
const {
$el,
$wrapperEl,
$inputEl,
value,
params,
} = calendar;
let i;
if ($el && $el.length > 0) {
$wrapperEl.find('.calendar-day-selected').removeClass('calendar-day-selected');
let valueDate;
if (params.rangePicker && value.length === 2) {
for (i = new Date(value[0]).getTime(); i <= new Date(value[1]).getTime(); i += 24 * 60 * 60 * 1000) {
valueDate = new Date(i);
$wrapperEl.find(`.calendar-day[data-date="${valueDate.getFullYear()}-${valueDate.getMonth()}-${valueDate.getDate()}"]`).addClass('calendar-day-selected');
}
} else {
for (i = 0; i < calendar.value.length; i += 1) {
valueDate = new Date(value[i]);
$wrapperEl.find(`.calendar-day[data-date="${valueDate.getFullYear()}-${valueDate.getMonth()}-${valueDate.getDate()}"]`).addClass('calendar-day-selected');
}
}
}
calendar.emit('local::change calendarChange', calendar, value);
if (($inputEl && $inputEl.length) || params.header) {
const inputValue = calendar.formatValue(value);
if (params.header && $el && $el.length) {
$el.find('.calendar-selected-date').text(inputValue);
}
if ($inputEl && $inputEl.length && !onlyHeader) {
$inputEl.val(inputValue);
$inputEl.trigger('change');
}
}
}
updateCurrentMonthYear(dir) {
const calendar = this;
const { $months, $el, params } = calendar;
if (typeof dir === 'undefined') {
calendar.currentMonth = parseInt($months.eq(1).attr('data-month'), 10);
calendar.currentYear = parseInt($months.eq(1).attr('data-year'), 10);
} else {
calendar.currentMonth = parseInt($months.eq(dir === 'next' ? ($months.length - 1) : 0).attr('data-month'), 10);
calendar.currentYear = parseInt($months.eq(dir === 'next' ? ($months.length - 1) : 0).attr('data-year'), 10);
}
$el.find('.current-month-value').text(params.monthNames[calendar.currentMonth]);
$el.find('.current-year-value').text(calendar.currentYear);
}
update() {
const calendar = this;
const { currentYear, currentMonth, $wrapperEl } = calendar;
const currentDate = new Date(currentYear, currentMonth);
const prevMonthHtml = calendar.renderMonth(currentDate, 'prev');
const currentMonthHtml = calendar.renderMonth(currentDate);
const nextMonthHtml = calendar.renderMonth(currentDate, 'next');
$wrapperEl
.html(`${prevMonthHtml}${currentMonthHtml}${nextMonthHtml}`)
.transform('translate3d(0,0,0)');
calendar.$months = $wrapperEl.find('.calendar-month');
calendar.monthsTranslate = 0;
calendar.setMonthsTranslate();
calendar.$months.each((index, monthEl) => {
calendar.emit(
'local::monthAdd calendarMonthAdd',
monthEl
);
});
}
onMonthChangeStart(dir) {
const calendar = this;
const { $months, currentYear, currentMonth } = calendar;
calendar.updateCurrentMonthYear(dir);
$months.removeClass('calendar-month-current calendar-month-prev calendar-month-next');
const currentIndex = dir === 'next' ? $months.length - 1 : 0;
$months.eq(currentIndex).addClass('calendar-month-current');
$months.eq(dir === 'next' ? currentIndex - 1 : currentIndex + 1).addClass(dir === 'next' ? 'calendar-month-prev' : 'calendar-month-next');
calendar.emit(
'local::monthYearChangeStart calendarMonthYearChangeStart',
calendar,
currentYear,
currentMonth
);
}
onMonthChangeEnd(dir, rebuildBoth) {
const calendar = this;
const { currentYear, currentMonth, $wrapperEl, monthsTranslate } = calendar;
calendar.animating = false;
let nextMonthHtml;
let prevMonthHtml;
let currentMonthHtml;
$wrapperEl
.find('.calendar-month:not(.calendar-month-prev):not(.calendar-month-current):not(.calendar-month-next)')
.remove();
if (typeof dir === 'undefined') {
dir = 'next'; // eslint-disable-line
rebuildBoth = true; // eslint-disable-line
}
if (!rebuildBoth) {
currentMonthHtml = calendar.renderMonth(new Date(currentYear, currentMonth), dir);
} else {
$wrapperEl.find('.calendar-month-next, .calendar-month-prev').remove();
prevMonthHtml = calendar.renderMonth(new Date(currentYear, currentMonth), 'prev');
nextMonthHtml = calendar.renderMonth(new Date(currentYear, currentMonth), 'next');
}
if (dir === 'next' || rebuildBoth) {
$wrapperEl.append(currentMonthHtml || nextMonthHtml);
}
if (dir === 'prev' || rebuildBoth) {
$wrapperEl.prepend(currentMonthHtml || prevMonthHtml);
}
const $months = $wrapperEl.find('.calendar-month');
calendar.$months = $months;
calendar.setMonthsTranslate(monthsTranslate);
calendar.emit(
'local::monthAdd calendarMonthAdd',
calendar,
dir === 'next' ? $months.eq($months.length - 1)[0] : $months.eq(0)[0]
);
calendar.emit(
'local::monthYearChangeEnd calendarMonthYearChangeEnd',
calendar,
currentYear,
currentMonth
);
}
setMonthsTranslate(translate) {
const calendar = this;
const { $months, isHorizontal: isH, inverter } = calendar;
// eslint-disable-next-line
translate = translate || calendar.monthsTranslate || 0;
if (typeof calendar.monthsTranslate === 'undefined') {
calendar.monthsTranslate = translate;
}
$months.removeClass('calendar-month-current calendar-month-prev calendar-month-next');
const prevMonthTranslate = -(translate + 1) * 100 * inverter;
const currentMonthTranslate = -translate * 100 * inverter;
const nextMonthTranslate = -(translate - 1) * 100 * inverter;
$months.eq(0)
.transform(`translate3d(${isH ? prevMonthTranslate : 0}%, ${isH ? 0 : prevMonthTranslate}%, 0)`)
.addClass('calendar-month-prev');
$months.eq(1)
.transform(`translate3d(${isH ? currentMonthTranslate : 0}%, ${isH ? 0 : currentMonthTranslate}%, 0)`)
.addClass('calendar-month-current');
$months.eq(2)
.transform(`translate3d(${isH ? nextMonthTranslate : 0}%, ${isH ? 0 : nextMonthTranslate}%, 0)`)
.addClass('calendar-month-next');
}
nextMonth(transition) {
const calendar = this;
const { params, $wrapperEl, inverter, isHorizontal: isH } = calendar;
if (typeof transition === 'undefined' || typeof transition === 'object') {
transition = ''; // eslint-disable-line
if (!params.animate) transition = 0; // eslint-disable-line
}
const nextMonth = parseInt(calendar.$months.eq(calendar.$months.length - 1).attr('data-month'), 10);
const nextYear = parseInt(calendar.$months.eq(calendar.$months.length - 1).attr('data-year'), 10);
const nextDate = new Date(nextYear, nextMonth);
const nextDateTime = nextDate.getTime();
const transitionEndCallback = !calendar.animating;
if (params.maxDate) {
if (nextDateTime > new Date(params.maxDate).getTime()) {
calendar.resetMonth();
return;
}
}
calendar.monthsTranslate -= 1;
if (nextMonth === calendar.currentMonth) {
const nextMonthTranslate = -(calendar.monthsTranslate) * 100 * inverter;
const nextMonthHtml = $(calendar.renderMonth(nextDateTime, 'next'))
.transform(`translate3d(${isH ? nextMonthTranslate : 0}%, ${isH ? 0 : nextMonthTranslate}%, 0)`)
.addClass('calendar-month-next');
$wrapperEl.append(nextMonthHtml[0]);
calendar.$months = $wrapperEl.find('.calendar-month');
calendar.emit(
'local::monthAdd calendarMonthAdd',
calendar.$months.eq(calendar.$months.length - 1)[0]
);
}
calendar.animating = true;
calendar.onMonthChangeStart('next');
const translate = (calendar.monthsTranslate * 100) * inverter;
$wrapperEl.transition(transition).transform(`translate3d(${isH ? translate : 0}%, ${isH ? 0 : translate}%, 0)`);
if (transitionEndCallback) {
$wrapperEl.transitionEnd(() => {
calendar.onMonthChangeEnd('next');
});
}
if (!params.animate) {
calendar.onMonthChangeEnd('next');
}
}
prevMonth(transition) {
const calendar = this;
const { params, $wrapperEl, inverter, isHorizontal: isH } = calendar;
if (typeof transition === 'undefined' || typeof transition === 'object') {
transition = ''; // eslint-disable-line
if (!params.animate) transition = 0; // eslint-disable-line
}
const prevMonth = parseInt(calendar.$months.eq(0).attr('data-month'), 10);
const prevYear = parseInt(calendar.$months.eq(0).attr('data-year'), 10);
const prevDate = new Date(prevYear, prevMonth + 1, -1);
const prevDateTime = prevDate.getTime();
const transitionEndCallback = !calendar.animating;
if (params.minDate) {
if (prevDateTime < new Date(params.minDate).getTime()) {
calendar.resetMonth();
return;
}
}
calendar.monthsTranslate += 1;
if (prevMonth === calendar.currentMonth) {
const prevMonthTranslate = -(calendar.monthsTranslate) * 100 * inverter;
const prevMonthHtml = $(calendar.renderMonth(prevDateTime, 'prev'))
.transform(`translate3d(${isH ? prevMonthTranslate : 0}%, ${isH ? 0 : prevMonthTranslate}%, 0)`)
.addClass('calendar-month-prev');
$wrapperEl.prepend(prevMonthHtml[0]);
calendar.$months = $wrapperEl.find('.calendar-month');
calendar.emit(
'local::monthAdd calendarMonthAdd',
calendar.$months.eq(0)[0]
);
}
calendar.animating = true;
calendar.onMonthChangeStart('prev');
const translate = (calendar.monthsTranslate * 100) * inverter;
$wrapperEl
.transition(transition)
.transform(`translate3d(${isH ? translate : 0}%, ${isH ? 0 : translate}%, 0)`);
if (transitionEndCallback) {
$wrapperEl.transitionEnd(() => {
calendar.onMonthChangeEnd('prev');
});
}
if (!params.animate) {
calendar.onMonthChangeEnd('prev');
}
}
resetMonth(transition = '') {
const calendar = this;
const { $wrapperEl, inverter, isHorizontal: isH, monthsTranslate } = calendar;
const translate = (monthsTranslate * 100) * inverter;
$wrapperEl
.transition(transition)
.transform(`translate3d(${isH ? translate : 0}%, ${isH ? 0 : translate}%, 0)`);
}
// eslint-disable-next-line
setYearMonth(year, month, transition) {
const calendar = this;
const { params, isHorizontal: isH, $wrapperEl, inverter } = calendar;
// eslint-disable-next-line
if (typeof year === 'undefined') year = calendar.currentYear;
// eslint-disable-next-line
if (typeof month === 'undefined') month = calendar.currentMonth;
if (typeof transition === 'undefined' || typeof transition === 'object') {
// eslint-disable-next-line
transition = '';
// eslint-disable-next-line
if (!params.animate) transition = 0;
}
let targetDate;
if (year < calendar.currentYear) {
targetDate = new Date(year, month + 1, -1).getTime();
} else {
targetDate = new Date(year, month).getTime();
}
if (params.maxDate && targetDate > new Date(params.maxDate).getTime()) {
return false;
}
if (params.minDate && targetDate < new Date(params.minDate).getTime()) {
return false;
}
const currentDate = new Date(calendar.currentYear, calendar.currentMonth).getTime();
const dir = targetDate > currentDate ? 'next' : 'prev';
const newMonthHTML = calendar.renderMonth(new Date(year, month));
calendar.monthsTranslate = calendar.monthsTranslate || 0;
const prevTranslate = calendar.monthsTranslate;
let monthTranslate;
const transitionEndCallback = !calendar.animating;
if (targetDate > currentDate) {
// To next
calendar.monthsTranslate -= 1;
if (!calendar.animating) calendar.$months.eq(calendar.$months.length - 1).remove();
$wrapperEl.append(newMonthHTML);
calendar.$months = $wrapperEl.find('.calendar-month');
monthTranslate = -(prevTranslate - 1) * 100 * inverter;
calendar.$months
.eq(calendar.$months.length - 1)
.transform(`translate3d(${isH ? monthTranslate : 0}%, ${isH ? 0 : monthTranslate}%, 0)`)
.addClass('calendar-month-next');
} else {
// To prev
calendar.monthsTranslate += 1;
if (!calendar.animating) calendar.$months.eq(0).remove();
$wrapperEl.prepend(newMonthHTML);
calendar.$months = $wrapperEl.find('.calendar-month');
monthTranslate = -(prevTranslate + 1) * 100 * inverter;
calendar.$months
.eq(0)
.transform(`translate3d(${isH ? monthTranslate : 0}%, ${isH ? 0 : monthTranslate}%, 0)`)
.addClass('calendar-month-prev');
}
calendar.emit(
'local::monthAdd calendarMonthAdd',
dir === 'next'
? calendar.$months.eq(calendar.$months.length - 1)[0]
: calendar.$months.eq(0)[0]
);
calendar.animating = true;
calendar.onMonthChangeStart(dir);
const wrapperTranslate = (calendar.monthsTranslate * 100) * inverter;
$wrapperEl
.transition(transition)
.transform(`translate3d(${isH ? wrapperTranslate : 0}%, ${isH ? 0 : wrapperTranslate}%, 0)`);
if (transitionEndCallback) {
$wrapperEl.transitionEnd(() => {
calendar.onMonthChangeEnd(dir, true);
});
}
if (!params.animate) {
calendar.onMonthChangeEnd(dir);
}
}
nextYear() {
const calendar = this;
calendar.setYearMonth(calendar.currentYear + 1);
}
prevYear() {
const calendar = this;
calendar.setYearMonth(calendar.currentYear - 1);
}
// eslint-disable-next-line
dateInRange(dayDate, range) {
let match = false;
let i;
if (!range) return false;
if (Array.isArray(range)) {
for (i = 0; i < range.length; i += 1) {
if (range[i].from || range[i].to) {
if (range[i].from && range[i].to) {
if ((dayDate <= new Date(range[i].to).getTime()) && (dayDate >= new Date(range[i].from).getTime())) {
match = true;
}
} else if (range[i].from) {
if (dayDate >= new Date(range[i].from).getTime()) {
match = true;
}
} else if (range[i].to) {
if (dayDate <= new Date(range[i].to).getTime()) {
match = true;
}
}
} else if (dayDate === new Date(range[i]).getTime()) {
match = true;
}
}
} else if (range.from || range.to) {
if (range.from && range.to) {
if ((dayDate <= new Date(range.to).getTime()) && (dayDate >= new Date(range.from).getTime())) {
match = true;
}
} else if (range.from) {
if (dayDate >= new Date(range.from).getTime()) {
match = true;
}
} else if (range.to) {
if (dayDate <= new Date(range.to).getTime()) {
match = true;
}
}
} else if (typeof range === 'function') {
match = range(new Date(dayDate));
}
return match;
}
// eslint-disable-next-line
daysInMonth(date) {
const d = new Date(date);
return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
}
renderMonths(date) {
const calendar = this;
if (calendar.params.renderMonths) {
return calendar.params.renderMonths.call(calendar, date);
}
return `
<div class="calendar-months-wrapper">
${calendar.renderMonth(date, 'prev')}
${calendar.renderMonth(date)}
${calendar.renderMonth(date, 'next')}
</div>
`.trim();
}
renderMonth(d, offset) {
const calendar = this;
const { params, value } = calendar;
if (params.renderMonth) {
return params.renderMonth.call(calendar, d, offset);
}
let date = new Date(d);
let year = date.getFullYear();
let month = date.getMonth();
if (offset === 'next') {
if (month === 11) date = new Date(year + 1, 0);
else date = new Date(year, month + 1, 1);
}
if (offset === 'prev') {
if (month === 0) date = new Date(year - 1, 11);
else date = new Date(year, month - 1, 1);
}
if (offset === 'next' || offset === 'prev') {
month = date.getMonth();
year = date.getFullYear();
}
const currentValues = [];
const today = new Date().setHours(0, 0, 0, 0);
const minDate = params.minDate ? new Date(params.minDate).getTime() : null;
const maxDate = params.maxDate ? new Date(params.maxDate).getTime() : null;
const rows = 6;
const cols = 7;
const daysInPrevMonth = calendar.daysInMonth(new Date(date.getFullYear(), date.getMonth()).getTime() - (10 * 24 * 60 * 60 * 1000));
const daysInMonth = calendar.daysInMonth(date);
const minDayNumber = params.firstDay === 6 ? 0 : 1;
let monthHtml = '';
let dayIndex = 0 + (params.firstDay - 1);
let disabled;
let hasEvent;
let firstDayOfMonthIndex = new Date(date.getFullYear(), date.getMonth()).getDay();
if (firstDayOfMonthIndex === 0) firstDayOfMonthIndex = 7;
if (value && value.length) {
for (let i = 0; i < value.length; i += 1) {
currentValues.push(new Date(value[i]).setHours(0, 0, 0, 0));
}
}
for (let row = 1; row <= rows; row += 1) {
let rowHtml = '';
for (let col = 1; col <= cols; col += 1) {
dayIndex += 1;
let dayDate;
let dayNumber = dayIndex - firstDayOfMonthIndex;
let addClass = '';
if (row === 1 && col === 1 && dayNumber > minDayNumber && params.firstDay !== 1) {
dayIndex -= 7;
dayNumber = dayIndex - firstDayOfMonthIndex;
}
const weekDayIndex = ((col - 1) + params.firstDay > 6)
? ((col - 1 - 7) + params.firstDay)
: ((col - 1) + params.firstDay);
if (dayNumber < 0) {
dayNumber = daysInPrevMonth + dayNumber + 1;
addClass += ' calendar-day-prev';
dayDate = new Date(month - 1 < 0 ? year - 1 : year, month - 1 < 0 ? 11 : month - 1, dayNumber).getTime();
} else {
dayNumber += 1;
if (dayNumber > daysInMonth) {
dayNumber -= daysInMonth;
addClass += ' calendar-day-next';
dayDate = new Date(month + 1 > 11 ? year + 1 : year, month + 1 > 11 ? 0 : month + 1, dayNumber).getTime();
} else {
dayDate = new Date(year, month, dayNumber).getTime();
}
}
// Today
if (dayDate === today) addClass += ' calendar-day-today';
// Selected
if (params.rangePicker && currentValues.length === 2) {
if (dayDate >= currentValues[0] && dayDate <= currentValues[1]) addClass += ' calendar-day-selected';
} else if (currentValues.indexOf(dayDate) >= 0) addClass += ' calendar-day-selected';
// Weekend
if (params.weekendDays.indexOf(weekDayIndex) >= 0) {
addClass += ' calendar-day-weekend';
}
// Has Events
hasEvent = false;
if (params.events) {
if (calendar.dateInRange(dayDate, params.events)) {
hasEvent = true;
}
}
if (hasEvent) {
addClass += ' calendar-day-has-events';
}
// Custom Ranges
if (params.rangesClasses) {
for (let k = 0; k < params.rangesClasses.length; k += 1) {
if (calendar.dateInRange(dayDate, params.rangesClasses[k].range)) {
addClass += ` ${params.rangesClasses[k].cssClass}`;
}
}
}
// Disabled
disabled = false;
if ((minDate && dayDate < minDate) || (maxDate && dayDate > maxDate)) {
disabled = true;
}
if (params.disabled) {
if (calendar.dateInRange(dayDate, params.disabled)) {
disabled = true;
}
}
if (disabled) {
addClass += ' calendar-day-disabled';
}
dayDate = new Date(dayDate);
const dayYear = dayDate.getFullYear();
const dayMonth = dayDate.getMonth();
rowHtml += `
<div data-year="${dayYear}" data-month="${dayMonth}" data-day="${dayNumber}" class="calendar-day${addClass}" data-date="${dayYear}-${dayMonth}-${dayNumber}">
<span>${dayNumber}</span>
</div>`.trim();
}
monthHtml += `<div class="calendar-row">${rowHtml}</div>`;
}
monthHtml = `<div class="calendar-month" data-year="${year}" data-month="${month}">${monthHtml}</div>`;
return monthHtml;
}
renderWeekHeader() {
const calendar = this;
if (calendar.params.renderWeekHeader) {
return calendar.params.renderWeekHeader.call(calendar);
}
const { params } = calendar;
let weekDaysHtml = '';
for (let i = 0; i < 7; i += 1) {
const dayIndex = (i + params.firstDay > 6)
? ((i - 7) + params.firstDay)
: (i + params.firstDay);
const dayName = params.dayNamesShort[dayIndex];
weekDaysHtml += `<div class="calendar-week-day">${dayName}</div>`;
}
return `
<div class="calendar-week-header">
${weekDaysHtml}
</div>
`.trim();
}
renderMonthSelector() {
const calendar = this;
const app = calendar.app;
if (calendar.params.renderMonthSelector) {
return calendar.params.renderMonthSelector.call(calendar);
}
let needsBlackIcon;
if (calendar.inline && calendar.$containerEl.closest('.theme-dark').length === 0) {
needsBlackIcon = true;
} else if (app.root.closest('.theme-dark').length === 0) {
needsBlackIcon = true;
}
const iconColor = app.theme === 'md' && needsBlackIcon ? 'color-black' : '';
return `
<div class="calendar-month-selector">
<a href="#" class="link icon-only calendar-prev-month-button">
<i class="icon icon-prev ${iconColor}"></i>
</a>
<span class="current-month-value"></span>
<a href="#" class="link icon-only calendar-next-month-button">
<i class="icon icon-next ${iconColor}"></i>
</a>
</div>
`.trim();
}
renderYearSelector() {
const calendar = this;
const app = calendar.app;
if (calendar.params.renderYearSelector) {
return calendar.params.renderYearSelector.call(calendar);
}
let needsBlackIcon;
if (calendar.inline && calendar.$containerEl.closest('.theme-dark').length === 0) {
needsBlackIcon = true;
} else if (app.root.closest('.theme-dark').length === 0) {
needsBlackIcon = true;
}
const iconColor = app.theme === 'md' && needsBlackIcon ? 'color-black' : '';
return `
<div class="calendar-year-selector">
<a href="#" class="link icon-only calendar-prev-year-button">
<i class="icon icon-prev ${iconColor}"></i>
</a>
<span class="current-year-value"></span>
<a href="#" class="link icon-only calendar-next-year-button">
<i class="icon icon-next ${iconColor}"></i>
</a>
</div>
`.trim();
}
renderHeader() {
const calendar = this;
if (calendar.params.renderHeader) {
return calendar.params.renderHeader.call(calendar);
}
return `
<div class="calendar-header">
<div class="calendar-selected-date">${calendar.params.headerPlaceholder}</div>
</div>
`.trim();
}
renderFooter() {
const calendar = this;
const app = calendar.app;
if (calendar.params.renderFooter) {
return calendar.params.renderFooter.call(calendar);
}
return `
<div class="calendar-footer">
<a href="#" class="${app.theme === 'md' ? 'button' : 'link'} calendar-close sheet-close popover-close">${calendar.params.toolbarCloseText}</a>
</div>
`.trim();
}
renderToolbar() {
const calendar = this;
if (calendar.params.renderToolbar) {
return calendar.params.renderToolbar.call(calendar, calendar);
}
return `
<div class="toolbar no-shadow">
<div class="toolbar-inner">
${calendar.renderMonthSelector()}
${calendar.renderYearSelector()}
</div>
</div>
`.trim();
}
// eslint-disable-next-line
renderInline() {
const calendar = this;
const { cssClass, toolbar, header, footer, rangePicker, weekHeader } = calendar.params;
const { value } = calendar;
const date = value && value.length ? value[0] : new Date().setHours(0, 0, 0);
const inlineHtml = `
<div class="calendar calendar-inline ${rangePicker ? 'calendar-range' : ''} ${cssClass || ''}">
${header ? calendar.renderHeader() : ''}
${toolbar ? calendar.renderToolbar() : ''}
${weekHeader ? calendar.renderWeekHeader() : ''}
<div class="calendar-months">
${calendar.renderMonths(date)}
</div>
${footer ? calendar.renderFooter() : ''}
</div>
`.trim();
return inlineHtml;
}
renderCustomModal() {
const calendar = this;
const { cssClass, toolbar, header, footer, rangePicker, weekHeader } = calendar.params;
const { value } = calendar;
const date = value && value.length ? value[0] : new Date().setHours(0, 0, 0);
const sheetHtml = `
<div class="calendar calendar-modal ${rangePicker ? 'calendar-range' : ''} ${cssClass || ''}">
${header ? calendar.renderHeader() : ''}
${toolbar ? calendar.renderToolbar() : ''}
${weekHeader ? calendar.renderWeekHeader() : ''}
<div class="calendar-months">
${calendar.renderMonths(date)}
</div>
${footer ? calendar.renderFooter() : ''}
</div>
`.trim();
return sheetHtml;
}
renderSheet() {
const calendar = this;
const { cssClass, toolbar, header, footer, rangePicker, weekHeader } = calendar.params;
const { value } = calendar;
const date = value && value.length ? value[0] : new Date().setHours(0, 0, 0);
const sheetHtml = `
<div class="sheet-modal calendar calendar-sheet ${rangePicker ? 'calendar-range' : ''} ${cssClass || ''}">
${header ? calendar.renderHeader() : ''}
${toolbar ? calendar.renderToolbar() : ''}
${weekHeader ? calendar.renderWeekHeader() : ''}
<div class="sheet-modal-inner calendar-months">
${calendar.renderMonths(date)}
</div>
${footer ? calendar.renderFooter() : ''}
</div>
`.trim();
return sheetHtml;
}
renderPopover() {
const calendar = this;
const { cssClass, toolbar, header, footer, rangePicker, weekHeader } = calendar.params;
const { value } = calendar;
const date = value && value.length ? value[0] : new Date().setHours(0, 0, 0);
const popoverHtml = `
<div class="popover calendar-popover">
<div class="popover-inner">
<div class="calendar ${rangePicker ? 'calendar-range' : ''} ${cssClass || ''}">
${header ? calendar.renderHeader() : ''}
${toolbar ? calendar.renderToolbar() : ''}
${weekHeader ? calendar.renderWeekHeader() : ''}
<div class="calendar-months">
${calendar.renderMonths(date)}
</div>
${footer ? calendar.renderFooter() : ''}
</div>
</div>
</div>
`.trim();
return popoverHtml;
}
render() {
const calendar = this;
const { params } = calendar;
if (params.render) return params.render.call(calendar);
if (!calendar.inline) {
let modalType = params.openIn;
if (modalType === 'auto') modalType = calendar.isPopover() ? 'popover' : 'sheet';
if (modalType === 'popover') return calendar.renderPopover();
else if (modalType === 'sheet') return calendar.renderSheet();
return calendar.renderCustomModal();
}
return calendar.renderInline();
}
onOpen() {
const calendar = this;
const { initialized, $el, app, $inputEl, inline, value, params } = calendar;
calendar.opened = true;
// Init main events
calendar.attachCalendarEvents();
const updateValue = !value && params.value;
// Set value
if (!initialized) {
if (value) calendar.setValue(value, 0);
else if (params.value) {
calendar.setValue(params.value, 0);
}
} else if (value) {
calendar.setValue(value, 0);
}
// Update current month and year
calendar.updateCurrentMonthYear();
// Set initial translate
calendar.monthsTranslate = 0;
calendar.setMonthsTranslate();
// Update input value
if (updateValue) calendar.updateValue();
else if (app.theme === 'md' && value) calendar.updateValue(true);
// Extra focus
if (!inline && $inputEl.length && app.theme === 'md') {
$inputEl.trigger('focus');
}
calendar.initialized = true;
calendar.$months.each((index, monthEl) => {
calendar.emit('local::monthAdd calendarMonthAdd', monthEl);
});
// Trigger events
if ($el) {
$el.trigger('calendar:open', calendar);
}
if ($inputEl) {
$inputEl.trigger('calendar:open', calendar);
}
calendar.emit('local::open calendarOpen', calendar);
}
onOpened() {
const calendar = this;
if (calendar.$el) {
calendar.$el.trigger('calendar:opened', calendar);
}
if (calendar.$inputEl) {
calendar.$inputEl.trigger('calendar:opened', calendar);
}
calendar.emit('local::opened calendarOpened', calendar);
}
onClose() {
const calendar = this;
const app = calendar.app;
if (calendar.$inputEl && app.theme === 'md') {
calendar.$inputEl.trigger('blur');
}
if (calendar.detachCalendarEvents) {
calendar.detachCalendarEvents();
}
if (calendar.$el) {
calendar.$el.trigger('calendar:close', calendar);
}
if (calendar.$inputEl) {
calendar.$inputEl.trigger('calendar:close', calendar);
}
calendar.emit('local::close calendarClose', calendar);
}
onClosed() {
const calendar = this;
calendar.opened = false;
if (!calendar.inline) {
Utils.nextTick(() => {
if (calendar.modal && calendar.modal.el && calendar.modal.destroy) {
if (!calendar.params.routableModals) {
calendar.modal.destroy();
}
}
delete calendar.modal;
});
}
if (calendar.$el) {
calendar.$el.trigger('calendar:closed', calendar);
}
if (calendar.$inputEl) {
calendar.$inputEl.trigger('calendar:closed', calendar);
}
calendar.emit('local::closed calendarClosed', calendar);
}
open() {
const calendar = this;
const { app, opened, inline, $inputEl, params } = calendar;
if (opened) return;
if (inline) {
calendar.$el = $(calendar.render());
calendar.$el[0].f7Calendar = calendar;
calendar.$wrapperEl = calendar.$el.find('.calendar-months-wrapper');
calendar.$months = calendar.$wrapperEl.find('.calendar-month');
calendar.$containerEl.append(calendar.$el);
calendar.onOpen();
calendar.onOpened();
return;
}
let modalType = params.openIn;
if (modalType === 'auto') {
modalType = calendar.isPopover() ? 'popover' : 'sheet';
}
const modalContent = calendar.render();
const modalParams = {
targetEl: $inputEl,
scrollToEl: calendar.params.scrollToInput ? $inputEl : undefined,
content: modalContent,
backdrop: modalType !== 'sheet',
on: {
open() {
const modal = this;
calendar.modal = modal;
calendar.$el = modalType === 'popover' ? modal.$el.find('.calendar') : modal.$el;
calendar.$wrapperEl = calendar.$el.find('.calendar-months-wrapper');
calendar.$months = calendar.$wrapperEl.find('.calendar-month');
calendar.$el[0].f7Calendar = calendar;
if (modalType === 'customModal') {
$(calendar.$el).find('.calendar-close').once('click', () => {
calendar.close();
});
}
calendar.onOpen();
},
opened() { calendar.onOpened(); },
close() { calendar.onClose(); },
closed() { calendar.onClosed(); },
},
};
if (calendar.params.routableModals) {
calendar.view.router.navigate({
url: calendar.url,
route: {
path: calendar.url,
[modalType]: modalParams,
},
});
} else {
calendar.modal = app[modalType].create(modalParams);
calendar.modal.open();
}
}
close() {
const calendar = this;
const { opened, inline } = calendar;
if (!opened) return;
if (inline) {
calendar.onClose();
calendar.onClosed();
return;
}
if (calendar.params.routableModals) {
calendar.view.router.back();
} else {
calendar.modal.close();
}
}
init() {
const calendar = this;
calendar.initInput();
if (calendar.inline) {
calendar.open();
calendar.emit('local::init calendarInit', calendar);
return;
}
if (!calendar.initialized && calendar.params.value) {
calendar.setValue(calendar.params.value);
}
// Attach input Events
if (calendar.$inputEl) {
calendar.attachInputEvents();
}
if (calendar.params.closeByOutsideClick) {
calendar.attachHtmlEvents();
}
calendar.emit('local::init calendarInit', calendar);
}
destroy() {
const calendar = this;
if (calendar.destroyed) return;
const { $el } = calendar;
calendar.emit('local::beforeDestroy calendarBeforeDestroy', calendar);
if ($el) $el.trigger('calendar:beforedestroy', calendar);
calendar.close();
// Detach Events
if (calendar.$inputEl) {
calendar.detachInputEvents();
}
if (calendar.params.closeByOutsideClick) {
calendar.detachHtmlEvents();
}
if ($el && $el.length) delete calendar.$el[0].f7Calendar;
Utils.deleteProps(calendar);
calendar.destroyed = true;
}
}
var Calendar = {
name: 'calendar',
static: {
Calendar: Calendar$1,
},
create() {
const app = this;
app.calendar = ConstructorMethods({
defaultSelector: '.calendar',
constructor: Calendar$1,
app,
domProp: 'f7Calendar',
});
app.calendar.close = function close(el = '.calendar') {
const $el = $(el);
if ($el.length === 0) return;
const calendar = $el[0].f7Calendar;
if (!calendar || (calendar && !calendar.opened)) return;
calendar.close();
};
},
params: {
calendar: {
// Calendar settings
monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
firstDay: 1, // First day of the week, Monday
weekendDays: [0, 6], // Sunday and Saturday
multiple: false,
rangePicker: false,
dateFormat: 'yyyy-mm-dd',
direction: 'horizontal', // or 'vertical'
minDate: null,
maxDate: null,
disabled: null, // dates range of disabled days
events: null, // dates range of days with events
rangesClasses: null, // array with custom classes date ranges
touchMove: true,
animate: true,
closeOnSelect: false,
monthSelector: true,
yearSelector: true,
weekHeader: true,
value: null,
// Common opener settings
containerEl: null,
openIn: 'auto', // or 'popover' or 'sheet' or 'customModal'
formatValue: null,
inputEl: null,
inputReadOnly: true,
closeByOutsideClick: true,
scrollToInput: true,
header: false,
headerPlaceholder: 'Select date',
footer: false,
toolbar: true,
toolbarCloseText: 'Done',
cssClass: null,
routableModals: true,
view: null,
url: 'date/',
// Render functions
renderWeekHeader: null,
renderMonths: null,
renderMonth: null,
renderMonthSelector: null,
renderYearSelector: null,
renderHeader: null,
renderFooter: null,
renderToolbar: null,
renderInline: null,
renderPopover: null,
renderSheet: null,
render: null,
},
},
};
var pickerColumn = function (colEl, updateItems) {
const picker = this;
const app = picker.app;
const $colEl = $(colEl);
const colIndex = $colEl.index();
const col = picker.cols[colIndex];
if (col.divider) return;
col.$el = $colEl;
col.el = $colEl[0];
col.$itemsEl = col.$el.find('.picker-items');
col.items = col.$itemsEl.find('.picker-item');
let itemHeight;
let itemsHeight;
let minTranslate;
let maxTranslate;
let animationFrameId;
function updateDuringScroll() {
animationFrameId = Utils.requestAnimationFrame(() => {
col.updateItems(undefined, undefined, 0);
updateDuringScroll();
});
}
col.replaceValues = function replaceColValues(values, displayValues) {
col.detachEvents();
col.values = values;
col.displayValues = displayValues;
col.$itemsEl.html(picker.renderColumn(col, true));
col.items = col.$itemsEl.find('.picker-item');
col.calcSize();
col.setValue(col.values[0], 0, true);
col.attachEvents();
};
col.calcSize = function calcColSize() {
if (picker.params.rotateEffect) {
col.$el.removeClass('picker-column-absolute');
if (!col.width) col.$el.css({ width: '' });
}
let colWidth = 0;
const colHeight = col.$el[0].offsetHeight;
itemHeight = col.items[0].offsetHeight;
itemsHeight = itemHeight * col.items.length;
minTranslate = ((colHeight / 2) - itemsHeight) + (itemHeight / 2);
maxTranslate = (colHeight / 2) - (itemHeight / 2);
if (col.width) {
colWidth = col.width;
if (parseInt(colWidth, 10) === colWidth) colWidth += 'px';
col.$el.css({ width: colWidth });
}
if (picker.params.rotateEffect) {
if (!col.width) {
col.items.each((index, itemEl) => {
const item = $(itemEl).children('span');
colWidth = Math.max(colWidth, item[0].offsetWidth);
});
col.$el.css({ width: `${colWidth + 2}px` });
}
col.$el.addClass('picker-column-absolute');
}
};
col.setValue = function setColValue(newValue, transition = '', valueCallbacks) {
const newActiveIndex = col.$itemsEl.find(`.picker-item[data-picker-value="${newValue}"]`).index();
if (typeof newActiveIndex === 'undefined' || newActiveIndex === -1) {
return;
}
const newTranslate = (-newActiveIndex * itemHeight) + maxTranslate;
// Update wrapper
col.$itemsEl.transition(transition);
col.$itemsEl.transform(`translate3d(0,${newTranslate}px,0)`);
// Watch items
if (picker.params.updateValuesOnMomentum && col.activeIndex && col.activeIndex !== newActiveIndex) {
Utils.cancelAnimationFrame(animationFrameId);
col.$itemsEl.transitionEnd(() => {
Utils.cancelAnimationFrame(animationFrameId);
});
updateDuringScroll();
}
// Update items
col.updateItems(newActiveIndex, newTranslate, transition, valueCallbacks);
};
col.updateItems = function updateColItems(activeIndex, translate, transition, valueCallbacks) {
if (typeof translate === 'undefined') {
// eslint-disable-next-line
translate = Utils.getTranslate(col.$itemsEl[0], 'y');
}
// eslint-disable-next-line
if (typeof activeIndex === 'undefined') activeIndex = -Math.round((translate - maxTranslate) / itemHeight);
// eslint-disable-next-line
if (activeIndex < 0) activeIndex = 0;
// eslint-disable-next-line
if (activeIndex >= col.items.length) activeIndex = col.items.length - 1;
const previousActiveIndex = col.activeIndex;
col.activeIndex = activeIndex;
col.$itemsEl.find('.picker-item-selected').removeClass('picker-item-selected');
col.items.transition(transition);
const selectedItem = col.items.eq(activeIndex).addClass('picker-item-selected').transform('');
// Set 3D rotate effect
if (picker.params.rotateEffect) {
col.items.each((index, itemEl) => {
const $itemEl = $(itemEl);
const itemOffsetTop = $itemEl.index() * itemHeight;
const translateOffset = maxTranslate - translate;
const itemOffset = itemOffsetTop - translateOffset;
const percentage = itemOffset / itemHeight;
const itemsFit = Math.ceil(col.height / itemHeight / 2) + 1;
let angle = (-18 * percentage);
if (angle > 180) angle = 180;
if (angle < -180) angle = -180;
if (Math.abs(percentage) > itemsFit) {
$itemEl.addClass('picker-item-far');
} else {
$itemEl.removeClass('picker-item-far');
}
$itemEl.transform(`translate3d(0, ${-translate + maxTranslate}px, ${picker.needsOriginFix ? -110 : 0}px) rotateX(${angle}deg)`);
});
}
if (valueCallbacks || typeof valueCallbacks === 'undefined') {
// Update values
col.value = selectedItem.attr('data-picker-value');
col.displayValue = col.displayValues ? col.displayValues[activeIndex] : col.value;
// On change callback
if (previousActiveIndex !== activeIndex) {
if (col.onChange) {
col.onChange(picker, col.value, col.displayValue);
}
picker.updateValue();
}
}
};
let allowItemClick = true;
let isTouched;
let isMoved;
let touchStartY;
let touchCurrentY;
let touchStartTime;
let touchEndTime;
let startTranslate;
let returnTo;
let currentTranslate;
let prevTranslate;
let velocityTranslate;
function handleTouchStart(e) {
if (isMoved || isTouched) return;
e.preventDefault();
isTouched = true;
touchStartY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
touchCurrentY = touchStartY;
touchStartTime = (new Date()).getTime();
allowItemClick = true;
startTranslate = Utils.getTranslate(col.$itemsEl[0], 'y');
currentTranslate = startTranslate;
}
function handleTouchMove(e) {
if (!isTouched) return;
e.preventDefault();
allowItemClick = false;
touchCurrentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (!isMoved) {
// First move
Utils.cancelAnimationFrame(animationFrameId);
isMoved = true;
startTranslate = Utils.getTranslate(col.$itemsEl[0], 'y');
currentTranslate = startTranslate;
col.$itemsEl.transition(0);
}
const diff = touchCurrentY - touchStartY;
currentTranslate = startTranslate + diff;
returnTo = undefined;
// Normalize translate
if (currentTranslate < minTranslate) {
currentTranslate = minTranslate - ((minTranslate - currentTranslate) ** 0.8);
returnTo = 'min';
}
if (currentTranslate > maxTranslate) {
currentTranslate = maxTranslate + ((currentTranslate - maxTranslate) ** 0.8);
returnTo = 'max';
}
// Transform wrapper
col.$itemsEl.transform(`translate3d(0,${currentTranslate}px,0)`);
// Update items
col.updateItems(undefined, currentTranslate, 0, picker.params.updateValuesOnTouchmove);
// Calc velocity
velocityTranslate = currentTranslate - prevTranslate || currentTranslate;
prevTranslate = currentTranslate;
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
col.$itemsEl.transition('');
if (returnTo) {
if (returnTo === 'min') {
col.$itemsEl.transform(`translate3d(0,${minTranslate}px,0)`);
} else col.$itemsEl.transform(`translate3d(0,${maxTranslate}px,0)`);
}
touchEndTime = new Date().getTime();
let newTranslate;
if (touchEndTime - touchStartTime > 300) {
newTranslate = currentTranslate;
} else {
newTranslate = currentTranslate + (velocityTranslate * picker.params.momentumRatio);
}
newTranslate = Math.max(Math.min(newTranslate, maxTranslate), minTranslate);
// Active Index
const activeIndex = -Math.floor((newTranslate - maxTranslate) / itemHeight);
// Normalize translate
if (!picker.params.freeMode) newTranslate = (-activeIndex * itemHeight) + maxTranslate;
// Transform wrapper
col.$itemsEl.transform(`translate3d(0,${parseInt(newTranslate, 10)}px,0)`);
// Update items
col.updateItems(activeIndex, newTranslate, '', true);
// Watch items
if (picker.params.updateValuesOnMomentum) {
updateDuringScroll();
col.$itemsEl.transitionEnd(() => {
Utils.cancelAnimationFrame(animationFrameId);
});
}
// Allow click
setTimeout(() => {
allowItemClick = true;
}, 100);
}
function handleClick() {
if (!allowItemClick) return;
Utils.cancelAnimationFrame(animationFrameId);
const value = $(this).attr('data-picker-value');
col.setValue(value);
}
const activeListener = app.support.passiveListener ? { passive: false, capture: false } : false;
col.attachEvents = function attachColEvents() {
col.$el.on(app.touchEvents.start, handleTouchStart, activeListener);
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
col.items.on('click', handleClick);
};
col.detachEvents = function detachColEvents() {
col.$el.off(app.touchEvents.start, handleTouchStart, activeListener);
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
col.items.off('click', handleClick);
};
col.init = function initCol() {
col.calcSize();
col.$itemsEl.transform(`translate3d(0,${maxTranslate}px,0)`).transition(0);
if (colIndex === 0) col.$el.addClass('picker-column-first');
if (colIndex === picker.cols.length - 1) col.$el.addClass('picker-column-last');
// Update items on init
if (updateItems) col.updateItems(0, maxTranslate, 0);
col.attachEvents();
};
col.destroy = function destroyCol() {
col.detachEvents();
};
col.init();
};
class Picker$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const picker = this;
picker.params = Utils.extend({}, app.params.picker, params);
let $containerEl;
if (picker.params.containerEl) {
$containerEl = $(picker.params.containerEl);
if ($containerEl.length === 0) return picker;
}
let $inputEl;
if (picker.params.inputEl) {
$inputEl = $(picker.params.inputEl);
}
let view;
if ($inputEl) {
view = $inputEl.parents('.view').length && $inputEl.parents('.view')[0].f7View;
}
if (!view) view = app.views.main;
Utils.extend(picker, {
app,
$containerEl,
containerEl: $containerEl && $containerEl[0],
inline: $containerEl && $containerEl.length > 0,
needsOriginFix: app.device.ios || ((window.navigator.userAgent.toLowerCase().indexOf('safari') >= 0 && window.navigator.userAgent.toLowerCase().indexOf('chrome') < 0) && !app.device.android),
cols: [],
$inputEl,
inputEl: $inputEl && $inputEl[0],
initialized: false,
opened: false,
url: picker.params.url,
view,
});
function onResize() {
picker.resizeCols();
}
function onInputClick() {
picker.open();
}
function onInputFocus(e) {
e.preventDefault();
}
function onHtmlClick(e) {
const $targetEl = $(e.target);
if (picker.isPopover()) return;
if (!picker.opened) return;
if ($targetEl.closest('[class*="backdrop"]').length) return;
if ($inputEl && $inputEl.length > 0) {
if ($targetEl[0] !== $inputEl[0] && $targetEl.closest('.sheet-modal').length === 0) {
picker.close();
}
} else if ($(e.target).closest('.sheet-modal').length === 0) {
picker.close();
}
}
// Events
Utils.extend(picker, {
attachResizeEvent() {
app.on('resize', onResize);
},
detachResizeEvent() {
app.off('resize', onResize);
},
attachInputEvents() {
picker.$inputEl.on('click', onInputClick);
if (picker.params.inputReadOnly) {
picker.$inputEl.on('focus mousedown', onInputFocus);
}
},
detachInputEvents() {
picker.$inputEl.off('click', onInputClick);
if (picker.params.inputReadOnly) {
picker.$inputEl.off('focus mousedown', onInputFocus);
}
},
attachHtmlEvents() {
app.on('click', onHtmlClick);
},
detachHtmlEvents() {
app.off('click', onHtmlClick);
},
});
picker.init();
return picker;
}
initInput() {
const picker = this;
if (!picker.$inputEl) return;
if (picker.params.inputReadOnly) picker.$inputEl.prop('readOnly', true);
}
resizeCols() {
const picker = this;
if (!picker.opened) return;
for (let i = 0; i < picker.cols.length; i += 1) {
if (!picker.cols[i].divider) {
picker.cols[i].calcSize();
picker.cols[i].setValue(picker.cols[i].value, 0, false);
}
}
}
isPopover() {
const picker = this;
const { app, modal, params } = picker;
if (params.openIn === 'sheet') return false;
if (modal && modal.type !== 'popover') return false;
if (!picker.inline && picker.inputEl) {
if (params.openIn === 'popover') return true;
else if (app.device.ios) {
return !!app.device.ipad;
} else if (app.width >= 768) {
return true;
}
}
return false;
}
formatValue() {
const picker = this;
const { value, displayValue } = picker;
if (picker.params.formatValue) {
return picker.params.formatValue.call(picker, value, displayValue);
}
return value.join(' ');
}
setValue(values, transition) {
const picker = this;
let valueIndex = 0;
if (picker.cols.length === 0) {
picker.value = values;
picker.updateValue(values);
return;
}
for (let i = 0; i < picker.cols.length; i += 1) {
if (picker.cols[i] && !picker.cols[i].divider) {
picker.cols[i].setValue(values[valueIndex], transition);
valueIndex += 1;
}
}
}
getValue() {
const picker = this;
return picker.value;
}
updateValue(forceValues) {
const picker = this;
const newValue = forceValues || [];
const newDisplayValue = [];
let column;
if (picker.cols.length === 0) {
const noDividerColumns = picker.params.cols.filter(c => !c.divider);
for (let i = 0; i < noDividerColumns.length; i += 1) {
column = noDividerColumns[i];
if (column.displayValues !== undefined && column.values !== undefined && column.values.indexOf(newValue[i]) !== -1) {
newDisplayValue.push(column.displayValues[column.values.indexOf(newValue[i])]);
} else {
newDisplayValue.push(newValue[i]);
}
}
} else {
for (let i = 0; i < picker.cols.length; i += 1) {
if (!picker.cols[i].divider) {
newValue.push(picker.cols[i].value);
newDisplayValue.push(picker.cols[i].displayValue);
}
}
}
if (newValue.indexOf(undefined) >= 0) {
return;
}
picker.value = newValue;
picker.displayValue = newDisplayValue;
if (picker.params.onChange) {
picker.emit('local::change pickerChange', picker, picker.value, picker.displayValue);
}
if (picker.inputEl) {
picker.$inputEl.val(picker.formatValue());
picker.$inputEl.trigger('change');
}
}
initColumn(colEl, updateItems) {
const picker = this;
pickerColumn.call(picker, colEl, updateItems);
}
// eslint-disable-next-line
destroyColumn(colEl) {
const picker = this;
const $colEl = $(colEl);
const index = $colEl.index();
if (picker.cols[index] && picker.cols[index].destroy) {
picker.cols[index].destroy();
}
}
renderToolbar() {
const picker = this;
if (picker.params.renderToolbar) return picker.params.renderToolbar.call(picker, picker);
return `
<div class="toolbar no-shadow">
<div class="toolbar-inner">
<div class="left"></div>
<div class="right">
<a href="#" class="link sheet-close popover-close">${picker.params.toolbarCloseText}</a>
</div>
</div>
</div>
`.trim();
}
// eslint-disable-next-line
renderColumn(col, onlyItems) {
const colClasses = `picker-column ${col.textAlign ? `picker-column-${col.textAlign}` : ''} ${col.cssClass || ''}`;
let columnHtml;
let columnItemsHtml;
if (col.divider) {
columnHtml = `
<div class="${colClasses} picker-column-divider">${col.content}</div>
`;
} else {
columnItemsHtml = col.values.map((value, index) => `
<div class="picker-item" data-picker-value="${value}">
<span>${col.displayValues ? col.displayValues[index] : value}</span>
</div>
`).join('');
columnHtml = `
<div class="${colClasses}">
<div class="picker-items">${columnItemsHtml}</div>
</div>
`;
}
return onlyItems ? columnItemsHtml.trim() : columnHtml.trim();
}
renderInline() {
const picker = this;
const { rotateEffect, cssClass, toolbar } = picker.params;
const inlineHtml = `
<div class="picker picker-inline ${rotateEffect ? 'picker-3d' : ''} ${cssClass || ''}">
${toolbar ? picker.renderToolbar() : ''}
<div class="picker-columns">
${picker.cols.map(col => picker.renderColumn(col)).join('')}
<div class="picker-center-highlight"></div>
</div>
</div>
`.trim();
return inlineHtml;
}
renderSheet() {
const picker = this;
const { rotateEffect, cssClass, toolbar } = picker.params;
const sheetHtml = `
<div class="sheet-modal picker picker-sheet ${rotateEffect ? 'picker-3d' : ''} ${cssClass || ''}">
${toolbar ? picker.renderToolbar() : ''}
<div class="sheet-modal-inner picker-columns">
${picker.cols.map(col => picker.renderColumn(col)).join('')}
<div class="picker-center-highlight"></div>
</div>
</div>
`.trim();
return sheetHtml;
}
renderPopover() {
const picker = this;
const { rotateEffect, cssClass, toolbar } = picker.params;
const popoverHtml = `
<div class="popover picker-popover">
<div class="popover-inner">
<div class="picker ${rotateEffect ? 'picker-3d' : ''} ${cssClass || ''}">
${toolbar ? picker.renderToolbar() : ''}
<div class="picker-columns">
${picker.cols.map(col => picker.renderColumn(col)).join('')}
<div class="picker-center-highlight"></div>
</div>
</div>
</div>
</div>
`.trim();
return popoverHtml;
}
render() {
const picker = this;
if (picker.params.render) return picker.params.render.call(picker);
if (!picker.inline) {
if (picker.isPopover()) return picker.renderPopover();
return picker.renderSheet();
}
return picker.renderInline();
}
onOpen() {
const picker = this;
const { initialized, $el, app, $inputEl, inline, value, params } = picker;
picker.opened = true;
// Init main events
picker.attachResizeEvent();
// Init cols
$el.find('.picker-column').each((index, colEl) => {
let updateItems = true;
if (
(!initialized && params.value) ||
(initialized && value)
) {
updateItems = false;
}
picker.initColumn(colEl, updateItems);
});
// Set value
if (!initialized) {
if (value) picker.setValue(value, 0);
else if (params.value) {
picker.setValue(params.value, 0);
}
} else if (value) {
picker.setValue(value, 0);
}
// Extra focus
if (!inline && $inputEl.length && app.theme === 'md') {
$inputEl.trigger('focus');
}
picker.initialized = true;
// Trigger events
if ($el) {
$el.trigger('picker:open', picker);
}
if ($inputEl) {
$inputEl.trigger('picker:open', picker);
}
picker.emit('local::open pickerOpen', picker);
}
onOpened() {
const picker = this;
if (picker.$el) {
picker.$el.trigger('picker:opened', picker);
}
if (picker.$inputEl) {
picker.$inputEl.trigger('picker:opened', picker);
}
picker.emit('local::opened pickerOpened', picker);
}
onClose() {
const picker = this;
const app = picker.app;
// Detach events
picker.detachResizeEvent();
picker.cols.forEach((col) => {
if (col.destroy) col.destroy();
});
if (picker.$inputEl && app.theme === 'md') {
picker.$inputEl.trigger('blur');
}
if (picker.$el) {
picker.$el.trigger('picker:close', picker);
}
if (picker.$inputEl) {
picker.$inputEl.trigger('picker:close', picker);
}
picker.emit('local::close pickerClose', picker);
}
onClosed() {
const picker = this;
picker.opened = false;
if (!picker.inline) {
Utils.nextTick(() => {
if (picker.modal && picker.modal.el && picker.modal.destroy) {
if (!picker.params.routableModals) {
picker.modal.destroy();
}
}
delete picker.modal;
});
}
if (picker.$el) {
picker.$el.trigger('picker:closed', picker);
}
if (picker.$inputEl) {
picker.$inputEl.trigger('picker:closed', picker);
}
picker.emit('local::closed pickerClosed', picker);
}
open() {
const picker = this;
const { app, opened, inline, $inputEl } = picker;
if (opened) return;
if (picker.cols.length === 0 && picker.params.cols.length) {
picker.params.cols.forEach((col) => {
picker.cols.push(col);
});
}
if (inline) {
picker.$el = $(picker.render());
picker.$el[0].f7Picker = picker;
picker.$containerEl.append(picker.$el);
picker.onOpen();
picker.onOpened();
return;
}
const isPopover = picker.isPopover();
const modalType = isPopover ? 'popover' : 'sheet';
const modalParams = {
targetEl: $inputEl,
scrollToEl: picker.params.scrollToInput ? $inputEl : undefined,
content: picker.render(),
backdrop: isPopover,
on: {
open() {
const modal = this;
picker.modal = modal;
picker.$el = isPopover ? modal.$el.find('.picker') : modal.$el;
picker.$el[0].f7Picker = picker;
picker.onOpen();
},
opened() { picker.onOpened(); },
close() { picker.onClose(); },
closed() { picker.onClosed(); },
},
};
if (picker.params.routableModals) {
picker.view.router.navigate({
url: picker.url,
route: {
path: picker.url,
[modalType]: modalParams,
},
});
} else {
picker.modal = app[modalType].create(modalParams);
picker.modal.open();
}
}
close() {
const picker = this;
const { opened, inline } = picker;
if (!opened) return;
if (inline) {
picker.onClose();
picker.onClosed();
return;
}
if (picker.params.routableModals) {
picker.view.router.back();
} else {
picker.modal.close();
}
}
init() {
const picker = this;
picker.initInput();
if (picker.inline) {
picker.open();
picker.emit('local::init pickerInit', picker);
return;
}
if (!picker.initialized && picker.params.value) {
picker.setValue(picker.params.value);
}
// Attach input Events
if (picker.$inputEl) {
picker.attachInputEvents();
}
if (picker.params.closeByOutsideClick) {
picker.attachHtmlEvents();
}
picker.emit('local::init pickerInit', picker);
}
destroy() {
const picker = this;
if (picker.destroyed) return;
const { $el } = picker;
picker.emit('local::beforeDestroy pickerBeforeDestroy', picker);
if ($el) $el.trigger('picker:beforedestroy', picker);
picker.close();
// Detach Events
if (picker.$inputEl) {
picker.detachInputEvents();
}
if (picker.params.closeByOutsideClick) {
picker.detachHtmlEvents();
}
if ($el && $el.length) delete picker.$el[0].f7Picker;
Utils.deleteProps(picker);
picker.destroyed = true;
}
}
var Picker = {
name: 'picker',
static: {
Picker: Picker$1,
},
create() {
const app = this;
app.picker = ConstructorMethods({
defaultSelector: '.picker',
constructor: Picker$1,
app,
domProp: 'f7Picker',
});
app.picker.close = function close(el = '.picker') {
const $el = $(el);
if ($el.length === 0) return;
const picker = $el[0].f7Picker;
if (!picker || (picker && !picker.opened)) return;
picker.close();
};
},
params: {
picker: {
// Picker settings
updateValuesOnMomentum: false,
updateValuesOnTouchmove: true,
rotateEffect: false,
momentumRatio: 7,
freeMode: false,
cols: [],
// Common opener settings
containerEl: null,
openIn: 'auto', // or 'popover' or 'sheet'
formatValue: null,
inputEl: null,
inputReadOnly: true,
closeByOutsideClick: true,
scrollToInput: true,
toolbar: true,
toolbarCloseText: 'Done',
cssClass: null,
routableModals: true,
view: null,
url: 'select/',
// Render functions
renderToolbar: null,
render: null,
},
},
};
const InfiniteScroll = {
handleScroll(el, e) {
const app = this;
const $el = $(el);
const scrollTop = $el[0].scrollTop;
const scrollHeight = $el[0].scrollHeight;
const height = $el[0].offsetHeight;
let distance = $el[0].getAttribute('data-infinite-distance');
const virtualListContainer = $el.find('.virtual-list');
let virtualList;
const onTop = $el.hasClass('infinite-scroll-top');
if (!distance) distance = 50;
if (typeof distance === 'string' && distance.indexOf('%') >= 0) {
distance = (parseInt(distance, 10) / 100) * height;
}
if (distance > height) distance = height;
if (onTop) {
if (scrollTop < distance) {
$el.trigger('infinite', e);
app.emit('infinite', $el[0], e);
}
} else if (scrollTop + height >= scrollHeight - distance) {
if (virtualListContainer.length > 0) {
virtualList = virtualListContainer.eq(-1)[0].f7VirtualList;
if (virtualList && !virtualList.reachEnd && !virtualList.params.updatableScroll) {
return;
}
}
$el.trigger('infinite', e);
app.emit('infinite', $el[0], e);
}
},
create(el) {
const $el = $(el);
const app = this;
$el.on('scroll', function handle(e) {
app.infiniteScroll.handle(this, e);
});
},
destroy(el) {
const $el = $(el);
$el.off('scroll');
},
};
var InfiniteScroll$1 = {
name: 'infiniteScroll',
create() {
const app = this;
Utils.extend(app, {
infiniteScroll: {
handle: InfiniteScroll.handleScroll.bind(app),
create: InfiniteScroll.create.bind(app),
destroy: InfiniteScroll.destroy.bind(app),
},
});
},
on: {
tabMounted(tabEl) {
const app = this;
const $tabEl = $(tabEl);
$tabEl.find('.infinite-scroll-content').each((index, el) => {
app.infiniteScroll.create(el);
});
},
tabBeforeRemove(tabEl) {
const $tabEl = $(tabEl);
const app = this;
$tabEl.find('.infinite-scroll-content').each((index, el) => {
app.infiniteScroll.destroy(el);
});
},
pageInit(page) {
const app = this;
page.$el.find('.infinite-scroll-content').each((index, el) => {
app.infiniteScroll.create(el);
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.infinite-scroll-content').each((index, el) => {
app.infiniteScroll.destroy(el);
});
},
},
};
class PullToRefresh$1 extends Framework7Class {
constructor(app, el) {
super({}, [app]);
const ptr = this;
const $el = $(el);
const $preloaderEl = $el.find('.ptr-preloader');
ptr.$el = $el;
ptr.el = $el[0];
ptr.app = app;
// Extend defaults with modules params
ptr.useModulesParams({});
const isMaterial = app.theme === 'md';
// Done
ptr.done = function done() {
const $transitionTarget = isMaterial ? $preloaderEl : $el;
$transitionTarget.transitionEnd(() => {
$el.removeClass('ptr-transitioning ptr-pull-up ptr-pull-down');
$el.trigger('ptr:done');
ptr.emit('local::done ptrDone', $el[0]);
});
$el.removeClass('ptr-refreshing').addClass('ptr-transitioning');
return ptr;
};
ptr.refresh = function refresh() {
if ($el.hasClass('ptr-refreshing')) return ptr;
$el.addClass('ptr-transitioning ptr-refreshing');
$el.trigger('ptr:refresh', ptr.done);
ptr.emit('local::refresh ptrRefresh', $el[0], ptr.done);
return ptr;
};
// Events handling
let touchId;
let isTouched;
let isMoved;
const touchesStart = {};
let isScrolling;
let touchesDiff;
let refresh = false;
let useTranslate = false;
let startTranslate = 0;
let translate;
let scrollTop;
let wasScrolled;
let triggerDistance;
let dynamicTriggerDistance;
let pullStarted;
let hasNavbar = false;
const $pageEl = $el.parents('.page');
if ($pageEl.find('.navbar').length > 0 || $pageEl.parents('.view').children('.navbar').length > 0) hasNavbar = true;
if ($pageEl.hasClass('no-navbar')) hasNavbar = false;
if (!hasNavbar) $el.addClass('ptr-no-navbar');
// Define trigger distance
if ($el.attr('data-ptr-distance')) {
dynamicTriggerDistance = true;
} else {
triggerDistance = isMaterial ? 66 : 44;
}
function handleTouchStart(e) {
if (isTouched) {
if (Device.os === 'android') {
if ('targetTouches' in e && e.targetTouches.length > 1) return;
} else return;
}
if ($el.hasClass('ptr-refreshing')) {
return;
}
if ($(e.target).closest('.sortable-handler').length) return;
isMoved = false;
pullStarted = false;
isTouched = true;
isScrolling = undefined;
wasScrolled = undefined;
if (e.type === 'touchstart') touchId = e.targetTouches[0].identifier;
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
}
function handleTouchMove(e) {
if (!isTouched) return;
let pageX;
let pageY;
let touch;
if (e.type === 'touchmove') {
if (touchId && e.touches) {
for (let i = 0; i < e.touches.length; i += 1) {
if (e.touches[i].identifier === touchId) {
touch = e.touches[i];
}
}
}
if (!touch) touch = e.targetTouches[0];
pageX = touch.pageX;
pageY = touch.pageY;
} else {
pageX = e.pageX;
pageY = e.pageY;
}
if (!pageX || !pageY) return;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
}
if (!isScrolling) {
isTouched = false;
return;
}
scrollTop = $el[0].scrollTop;
if (typeof wasScrolled === 'undefined' && scrollTop !== 0) wasScrolled = true;
if (!isMoved) {
$el.removeClass('ptr-transitioning');
if (scrollTop > $el[0].offsetHeight) {
isTouched = false;
return;
}
if (dynamicTriggerDistance) {
triggerDistance = $el.attr('data-ptr-distance');
if (triggerDistance.indexOf('%') >= 0) triggerDistance = ($el[0].offsetHeight * parseInt(triggerDistance, 10)) / 100;
}
startTranslate = $el.hasClass('ptr-refreshing') ? triggerDistance : 0;
if ($el[0].scrollHeight === $el[0].offsetHeight || Device.os !== 'ios' || isMaterial) {
useTranslate = true;
} else {
useTranslate = false;
}
}
isMoved = true;
touchesDiff = pageY - touchesStart.y;
if ((touchesDiff > 0 && scrollTop <= 0) || scrollTop < 0) {
// iOS 8 fix
if (Device.os === 'ios' && parseInt(Device.osVersion.split('.')[0], 10) > 7 && scrollTop === 0 && !wasScrolled) useTranslate = true;
if (useTranslate) {
e.preventDefault();
translate = (touchesDiff ** 0.85) + startTranslate;
if (isMaterial) {
$preloaderEl.transform(`translate3d(0,${translate}px,0)`)
.find('.ptr-arrow').transform(`rotate(${(180 * (touchesDiff / 66)) + 100}deg)`);
} else {
$el.transform(`translate3d(0,${translate}px,0)`);
}
}
if ((useTranslate && (touchesDiff ** 0.85) > triggerDistance) || (!useTranslate && touchesDiff >= triggerDistance * 2)) {
refresh = true;
$el.addClass('ptr-pull-up').removeClass('ptr-pull-down');
} else {
refresh = false;
$el.removeClass('ptr-pull-up').addClass('ptr-pull-down');
}
if (!pullStarted) {
$el.trigger('ptr:pullstart');
ptr.emit('local::pullStart ptrPullStart', $el[0]);
pullStarted = true;
}
$el.trigger('ptr:pullmove', {
event: e,
scrollTop,
translate,
touchesDiff,
});
ptr.emit('local::pullMove ptrPullMove', $el[0], {
event: e,
scrollTop,
translate,
touchesDiff,
});
} else {
pullStarted = false;
$el.removeClass('ptr-pull-up ptr-pull-down');
refresh = false;
}
}
function handleTouchEnd(e) {
if (e.type === 'touchend' && e.changedTouches && e.changedTouches.length > 0 && touchId) {
if (e.changedTouches[0].identifier !== touchId) {
isTouched = false;
isScrolling = false;
isMoved = false;
touchId = null;
return;
}
}
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
if (translate) {
$el.addClass('ptr-transitioning');
translate = 0;
}
if (isMaterial) {
$preloaderEl.transform('')
.find('.ptr-arrow').transform('');
} else {
$el.transform('');
}
if (refresh) {
$el.addClass('ptr-refreshing');
$el.trigger('ptr:refresh', ptr.done);
ptr.emit('local::refresh ptrRefresh', $el[0], ptr.done);
} else {
$el.removeClass('ptr-pull-down');
}
isTouched = false;
isMoved = false;
if (pullStarted) {
$el.trigger('ptr:pullend');
ptr.emit('local::pullEnd ptrPullEnd', $el[0]);
}
}
if (!$pageEl.length || !$el.length) return ptr;
$el[0].f7PullToRefresh = ptr;
// Events
ptr.attachEvents = function attachEvents() {
const passive = Support$1.passiveListener ? { passive: true } : false;
$el.on(app.touchEvents.start, handleTouchStart, passive);
app.on('touchmove', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
};
ptr.detachEvents = function detachEvents() {
const passive = Support$1.passiveListener ? { passive: true } : false;
$el.off(app.touchEvents.start, handleTouchStart, passive);
app.off('touchmove', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
};
// Install Modules
ptr.useModules();
// Init
ptr.init();
return ptr;
}
init() {
const ptr = this;
ptr.attachEvents();
}
destroy() {
let ptr = this;
ptr.emit('local::beforeDestroy ptrBeforeDestroy', ptr);
ptr.$el.trigger('ptr:beforedestroy', ptr);
delete ptr.el.f7PullToRefresh;
ptr.detachEvents();
Utils.deleteProps(ptr);
ptr = null;
}
}
var PullToRefresh = {
name: 'pullToRefresh',
create() {
const app = this;
app.ptr = Utils.extend(
ConstructorMethods({
defaultSelector: '.ptr-content',
constructor: PullToRefresh$1,
app,
domProp: 'f7PullToRefresh',
}),
{
done(el) {
const ptr = app.ptr.get(el);
if (ptr) return ptr.done();
return undefined;
},
refresh(el) {
const ptr = app.ptr.get(el);
if (ptr) return ptr.refresh();
return undefined;
},
}
);
},
static: {
PullToRefresh: PullToRefresh$1,
},
on: {
tabMounted(tabEl) {
const app = this;
const $tabEl = $(tabEl);
$tabEl.find('.ptr-content').each((index, el) => {
app.ptr.create(el);
});
},
tabBeforeRemove(tabEl) {
const $tabEl = $(tabEl);
const app = this;
$tabEl.find('.ptr-content').each((index, el) => {
app.ptr.destroy(el);
});
},
pageInit(page) {
const app = this;
page.$el.find('.ptr-content').each((index, el) => {
app.ptr.create(el);
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.ptr-content').each((index, el) => {
app.ptr.destroy(el);
});
},
},
};
const Lazy = {
destroy(pageEl) {
const $pageEl = $(pageEl).closest('.page');
if (!$pageEl.length) return;
if ($pageEl[0].f7LazyDestroy) {
$pageEl[0].f7LazyDestroy();
}
},
create(pageEl) {
const app = this;
const $pageEl = $(pageEl).closest('.page').eq(0);
// Lazy images
const lazyLoadImages = $pageEl.find('.lazy');
if (lazyLoadImages.length === 0 && !$pageEl.hasClass('lazy')) return;
// Placeholder
const placeholderSrc = app.params.lazy.placeholder;
if (placeholderSrc !== false) {
lazyLoadImages.each((index, lazyEl) => {
if ($(lazyEl).attr('data-src') && !$(lazyEl).attr('src')) $(lazyEl).attr('src', placeholderSrc);
});
}
// load image
const imagesSequence = [];
let imageIsLoading = false;
function onImageComplete(lazyEl) {
if (imagesSequence.indexOf(lazyEl) >= 0) {
imagesSequence.splice(imagesSequence.indexOf(lazyEl), 1);
}
imageIsLoading = false;
if (app.params.lazy.sequential && imagesSequence.length > 0) {
imageIsLoading = true;
app.lazy.loadImage(imagesSequence[0], onImageComplete);
}
}
function lazyHandler() {
app.lazy.load($pageEl, (lazyEl) => {
if (app.params.lazy.sequential && imageIsLoading) {
if (imagesSequence.indexOf(lazyEl) < 0) imagesSequence.push(lazyEl);
return;
}
imageIsLoading = true;
app.lazy.loadImage(lazyEl, onImageComplete);
});
}
function attachEvents() {
$pageEl[0].f7LazyAttached = true;
$pageEl.on('lazy', lazyHandler);
$pageEl.on('scroll', lazyHandler, true);
$pageEl.find('.tab').on('tab:mounted tab:show', lazyHandler);
app.on('resize', lazyHandler);
}
function detachEvents() {
$pageEl[0].f7LazyAttached = false;
delete $pageEl[0].f7LazyAttached;
$pageEl.off('lazy', lazyHandler);
$pageEl.off('scroll', lazyHandler, true);
$pageEl.find('.tab').off('tab:mounted tab:show', lazyHandler);
app.off('resize', lazyHandler);
}
// Store detach function
if (!$pageEl[0].f7LazyDestroy) {
$pageEl[0].f7LazyDestroy = detachEvents;
}
// Attach events
if (!$pageEl[0].f7LazyAttached) {
attachEvents();
}
// Run loader on page load/init
lazyHandler();
},
isInViewport(lazyEl) {
const app = this;
const rect = lazyEl.getBoundingClientRect();
const threshold = app.params.lazy.threshold || 0;
return (
rect.top >= (0 - threshold) &&
rect.left >= (0 - threshold) &&
rect.top <= (app.height + threshold) &&
rect.left <= (app.width + threshold)
);
},
loadImage(imageEl, callback) {
const app = this;
const $imageEl = $(imageEl);
const bg = $imageEl.attr('data-background');
const src = bg || $imageEl.attr('data-src');
if (!src) return;
function onLoad() {
$imageEl.removeClass('lazy').addClass('lazy-loaded');
if (bg) {
$imageEl.css('background-image', `url(${src})`);
} else {
$imageEl.attr('src', src);
}
if (callback) callback(imageEl);
$imageEl.trigger('lazy:loaded');
app.emit('lazyLoaded', $imageEl[0]);
}
function onError() {
$imageEl.removeClass('lazy').addClass('lazy-loaded');
if (bg) {
$imageEl.css('background-image', `url(${app.params.lazy.placeholder || ''})`);
} else {
$imageEl.attr('src', app.params.lazy.placeholder || '');
}
if (callback) callback(imageEl);
$imageEl.trigger('lazy:error');
app.emit('lazyError', $imageEl[0]);
}
const image = new window.Image();
image.onload = onLoad;
image.onerror = onError;
image.src = src;
$imageEl.removeAttr('data-src').removeAttr('data-background');
// Add loaded callback and events
$imageEl.trigger('lazy:load');
app.emit('lazyLoad', $imageEl[0]);
},
load(pageEl, callback) {
const app = this;
let $pageEl = $(pageEl);
if (!$pageEl.hasClass('page')) $pageEl = $pageEl.parents('.page').eq(0);
if ($pageEl.length === 0) {
return;
}
$pageEl.find('.lazy').each((index, lazyEl) => {
const $lazyEl = $(lazyEl);
if ($lazyEl.parents('.tab:not(.tab-active)').length > 0) {
return;
}
if (app.lazy.isInViewport(lazyEl)) {
if (callback) callback(lazyEl);
else app.lazy.loadImage(lazyEl);
}
});
},
};
var Lazy$1 = {
name: 'lazy',
params: {
lazy: {
placeholder: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEXCwsK592mkAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==',
threshold: 0,
sequential: true,
},
},
create() {
const app = this;
Utils.extend(app, {
lazy: {
create: Lazy.create.bind(app),
destroy: Lazy.destroy.bind(app),
loadImage: Lazy.loadImage.bind(app),
load: Lazy.load.bind(app),
isInViewport: Lazy.isInViewport.bind(app),
},
});
},
on: {
pageInit(page) {
const app = this;
if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) {
app.lazy.create(page.$el);
}
},
pageAfterIn(page) {
const app = this;
if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) {
app.lazy.create(page.$el);
}
},
pageBeforeRemove(page) {
const app = this;
if (page.$el.find('.lazy').length > 0 || page.$el.hasClass('lazy')) {
app.lazy.destroy(page.$el);
}
},
tabMounted(tabEl) {
const app = this;
const $tabEl = $(tabEl);
if ($tabEl.find('.lazy').length > 0 || $tabEl.hasClass('lazy')) {
app.lazy.create($tabEl);
}
},
tabBeforeRemove(tabEl) {
const app = this;
const $tabEl = $(tabEl);
if ($tabEl.find('.lazy').length > 0 || $tabEl.hasClass('lazy')) {
app.lazy.destroy($tabEl);
}
},
},
};
class DataTable$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const table = this;
const defaults = {
};
// Extend defaults with modules params
table.useModulesParams(defaults);
table.params = Utils.extend(defaults, params);
// El
const $el = $(table.params.el);
if ($el.length === 0) return undefined;
table.$el = $el;
table.el = $el[0];
if (table.$el[0].f7DataTable) {
const instance = table.$el[0].f7DataTable;
table.destroy();
return instance;
}
table.$el[0].f7DataTable = table;
Utils.extend(table, {
collapsible: $el.hasClass('data-table-collapsible'),
// Headers
$headerEl: $el.find('.data-table-header'),
$headerSelectedEl: $el.find('.data-table-header-selected'),
});
// Events
function handleChange(e) {
if (e.detail && e.detail.sentByF7DataTable) {
// Scripted event, don't do anything
return;
}
const $inputEl = $(this);
const checked = $inputEl[0].checked;
const columnIndex = $inputEl.parents('td,th').index();
if ($inputEl.parents('thead').length > 0) {
if (columnIndex === 0) {
$el
.find('tbody tr')[checked ? 'addClass' : 'removeClass']('data-table-row-selected');
}
$el
.find(`tbody tr td:nth-child(${columnIndex + 1}) input`)
.prop('checked', checked)
.trigger('change', { sentByF7DataTable: true });
} else {
if (columnIndex === 0) {
$inputEl.parents('tr')[checked ? 'addClass' : 'removeClass']('data-table-row-selected');
}
if (!checked) {
$el.find(`thead .checkbox-cell:nth-child(${columnIndex + 1}) input[type="checkbox"]`).prop('checked', false);
} else if ($el.find(`tbody .checkbox-cell:nth-child(${columnIndex + 1}) input[type="checkbox"]:checked`).length === $el.find('tbody tr').length) {
$el.find(`thead .checkbox-cell:nth-child(${columnIndex + 1}) input[type="checkbox"]`).prop('checked', true).trigger('change', { sentByF7DataTable: true });
}
}
table.checkSelectedHeader();
}
function handleSortableClick() {
const $cellEl = $(this);
const isActive = $cellEl.hasClass('sortable-cell-active');
let currentSort;
if (isActive) {
currentSort = $cellEl.hasClass('sortable-desc') ? 'desc' : 'asc';
$cellEl.removeClass('sortable-desc sortable-asc').addClass(`sortable-${currentSort === 'desc' ? 'asc' : 'desc'}`);
} else {
$el.find('thead .sortable-cell-active').removeClass('sortable-cell-active');
$cellEl.addClass('sortable-cell-active');
}
}
table.attachEvents = function attachEvents() {
table.$el.on('change', '.checkbox-cell input[type="checkbox"]', handleChange);
table.$el.find('thead .sortable-cell').on('click', handleSortableClick);
};
table.detachEvents = function detachEvents() {
table.$el.off('change', '.checkbox-cell input[type="checkbox"]', handleChange);
table.$el.find('thead .sortable-cell').off('click', handleSortableClick);
};
// Install Modules
table.useModules();
// Init
table.init();
return table;
}
setCollapsibleLabels() {
const table = this;
if (!table.collapsible) return;
table.$el.find('tbody td:not(.checkbox-cell)').each((index, el) => {
const $el = $(el);
const elIndex = $el.index();
const collpsibleTitle = $el.attr('data-collapsible-title');
if (!collpsibleTitle && collpsibleTitle !== '') {
$el.attr('data-collapsible-title', table.$el.find('thead th').eq(elIndex).text());
}
});
}
checkSelectedHeader() {
const table = this;
if (table.$headerEl.length > 0 && table.$headerSelectedEl.length > 0) {
const checkedItems = table.$el.find('tbody .checkbox-cell input:checked').length;
table.$el[checkedItems > 0 ? 'addClass' : 'removeClass']('data-table-has-checked');
table.$headerSelectedEl.find('.data-table-selected-count').text(checkedItems);
}
}
init() {
const table = this;
table.attachEvents();
table.setCollapsibleLabels();
table.checkSelectedHeader();
}
destroy() {
let table = this;
table.$el.trigger('datatable:beforedestroy', table);
table.emit('local::beforeDestroy datatableBeforeDestroy', table);
table.attachEvents();
table.$el[0].f7DataTable = null;
delete table.$el[0].f7DataTable;
Utils.deleteProps(table);
table = null;
}
}
var DataTable = {
name: 'dataTable',
static: {
DataTable: DataTable$1,
},
create() {
const app = this;
app.dataTable = ConstructorMethods({
defaultSelector: '.data-table',
constructor: DataTable$1,
app,
domProp: 'f7DataTable',
});
},
on: {
tabBeforeRemove(tabEl) {
const app = this;
$(tabEl).find('.data-table-init').each((index, tableEl) => {
app.dataTable.destroy(tableEl);
});
},
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.data-table-init').each((index, tableEl) => {
app.dataTable.create({ el: tableEl });
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.data-table-init').each((index, tableEl) => {
app.dataTable.destroy(tableEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.data-table-init').each((index, tableEl) => {
app.dataTable.create({ el: tableEl });
});
},
},
clicks: {
},
};
const Fab = {
morphOpen(fabEl, targetEl) {
const app = this;
const $fabEl = $(fabEl);
const $targetEl = $(targetEl);
if ($targetEl.length === 0) return;
$targetEl.transition(0).addClass('fab-morph-target-visible');
const target = {
width: $targetEl[0].offsetWidth,
height: $targetEl[0].offsetHeight,
offset: $targetEl.offset(),
borderRadius: $targetEl.css('border-radius'),
zIndex: $targetEl.css('z-index'),
};
const fab = {
width: $fabEl[0].offsetWidth,
height: $fabEl[0].offsetHeight,
offset: $fabEl.offset(),
translateX: Utils.getTranslate($fabEl[0], 'x'),
translateY: Utils.getTranslate($fabEl[0], 'y'),
};
$fabEl[0].f7FabMorphData = {
$targetEl,
target,
fab,
};
const diffX = (fab.offset.left + (fab.width / 2)) -
(target.offset.left + (target.width / 2)) -
fab.translateX;
const diffY = (fab.offset.top + (fab.height / 2)) -
(target.offset.top + (target.height / 2)) -
fab.translateY;
const scaleX = target.width / fab.width;
const scaleY = target.height / fab.height;
let borderRadius = Math.ceil(parseInt(target.borderRadius, 10) / Math.max(scaleX, scaleY));
if (borderRadius > 0) borderRadius += 2;
$fabEl[0].f7FabMorphResizeHandler = function resizeHandler() {
$fabEl.transition(0).transform('');
$targetEl.transition(0);
target.width = $targetEl[0].offsetWidth;
target.height = $targetEl[0].offsetHeight;
target.offset = $targetEl.offset();
fab.offset = $fabEl.offset();
const diffXNew = (fab.offset.left + (fab.width / 2)) -
(target.offset.left + (target.width / 2)) -
fab.translateX;
const diffYNew = (fab.offset.top + (fab.height / 2)) -
(target.offset.top + (target.height / 2)) -
fab.translateY;
const scaleXNew = target.width / fab.width;
const scaleYNew = target.height / fab.height;
$fabEl.transform(`translate3d(${-diffXNew}px, ${-diffYNew}px, 0) scale(${scaleXNew}, ${scaleYNew})`);
};
$targetEl
.css('opacity', 0)
.transform(`scale(${1 / scaleX}, ${1 / scaleY})`);
$fabEl
.addClass('fab-opened')
.css('z-index', target.zIndex - 1)
.transform(`translate3d(${-diffX}px, ${-diffY}px, 0)`);
$fabEl.transitionEnd(() => {
$targetEl.transition('');
Utils.nextTick(() => {
$targetEl.css('opacity', 1).transform('scale(1,1)');
});
$fabEl.transform(`translate3d(${-diffX}px, ${-diffY}px, 0) scale(${scaleX}, ${scaleY})`)
.css('border-radius', `${borderRadius}px`)
.css('box-shadow', 'none');
app.on('resize', $fabEl[0].f7FabMorphResizeHandler);
if ($targetEl.parents('.page-content').length > 0) {
$targetEl.parents('.page-content').on('scroll', $fabEl[0].f7FabMorphResizeHandler);
}
});
},
morphClose(fabEl) {
const app = this;
const $fabEl = $(fabEl);
const morphData = $fabEl[0].f7FabMorphData;
if (!morphData) return;
const { $targetEl, target, fab } = morphData;
if ($targetEl.length === 0) return;
const diffX = (fab.offset.left + (fab.width / 2)) -
(target.offset.left + (target.width / 2)) -
fab.translateX;
const diffY = (fab.offset.top + (fab.height / 2)) -
(target.offset.top + (target.height / 2)) -
fab.translateY;
const scaleX = target.width / fab.width;
const scaleY = target.height / fab.height;
app.off('resize', $fabEl[0].f7FabMorphResizeHandler);
if ($targetEl.parents('.page-content').length > 0) {
$targetEl.parents('.page-content').off('scroll', $fabEl[0].f7FabMorphResizeHandler);
}
$targetEl
.css('opacity', 0)
.transform(`scale(${1 / scaleX}, ${1 / scaleY})`);
$fabEl
.transition('')
.css('box-shadow', '')
.css('border-radius', '')
.transform(`translate3d(${-diffX}px, ${-diffY}px, 0)`);
$fabEl.transitionEnd(() => {
$fabEl
.css('z-index', '')
.removeClass('fab-opened')
.transform('');
Utils.nextTick(() => {
$fabEl.transitionEnd(() => {
$targetEl
.removeClass('fab-morph-target-visible')
.css('opacity', '')
.transform('')
.transition('');
});
});
});
},
open(fabEl, targetEl) {
const app = this;
const $fabEl = $(fabEl).eq(0);
const $buttonsEl = $fabEl.find('.fab-buttons');
if (!$fabEl.length) return;
if ($fabEl.hasClass('fab-opened')) return;
if (!$buttonsEl.length && !$fabEl.hasClass('fab-morph')) return;
if (app.fab.openedEl) {
if (app.fab.openedEl === $fabEl[0]) return;
app.fab.close(app.fab.openedEl);
}
app.fab.openedEl = $fabEl[0];
if ($fabEl.hasClass('fab-morph')) {
app.fab.morphOpen($fabEl, targetEl || $fabEl.attr('data-morph-to'));
} else {
$fabEl.addClass('fab-opened');
}
$fabEl.trigger('fab:open');
},
close(fabEl = '.fab-opened') {
const app = this;
const $fabEl = $(fabEl).eq(0);
const $buttonsEl = $fabEl.find('.fab-buttons');
if (!$fabEl.length) return;
if (!$fabEl.hasClass('fab-opened')) return;
if (!$buttonsEl.length && !$fabEl.hasClass('fab-morph')) return;
app.fab.openedEl = null;
if ($fabEl.hasClass('fab-morph')) {
app.fab.morphClose($fabEl);
} else {
$fabEl.removeClass('fab-opened');
}
$fabEl.trigger('fab:close');
},
toggle(fabEl) {
const app = this;
const $fabEl = $(fabEl);
if (!$fabEl.hasClass('fab-opened')) app.fab.open(fabEl);
else app.fab.close(fabEl);
},
};
var Fab$1 = {
name: 'fab',
create() {
const app = this;
Utils.extend(app, {
fab: {
openedEl: null,
morphOpen: Fab.morphOpen.bind(app),
morphClose: Fab.morphClose.bind(app),
open: Fab.open.bind(app),
close: Fab.close.bind(app),
toggle: Fab.toggle.bind(app),
},
});
},
clicks: {
'.fab > a': function open($clickedEl) {
const app = this;
app.fab.toggle($clickedEl.parents('.fab'));
},
'.fab-open': function open($clickedEl, data = {}) {
const app = this;
app.fab.open(data.fab);
},
'.fab-close': function close($clickedEl, data = {}) {
const app = this;
app.fab.close(data.fab);
},
},
};
class Searchbar$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const sb = this;
const defaults = {
el: undefined,
inputEl: undefined,
disableButton: true,
disableButtonEl: undefined,
backdropEl: undefined,
searchContainer: undefined, // container to search, HTMLElement or CSS selector
searchItem: 'li', // single item selector, CSS selector
searchIn: undefined, // where to search in item, CSS selector
ignore: '.searchbar-ignore',
foundEl: '.searchbar-found',
notFoundEl: '.searchbar-not-found',
hideOnEnableEl: '.searchbar-hide-on-enable',
hideOnSearchEl: '.searchbar-hide-on-search',
backdrop: true,
removeDiacritics: true,
customSearch: false,
hideDividers: true,
hideGroups: true,
disableOnBackdropClick: true,
expandable: false,
};
// Extend defaults with modules params
sb.useModulesParams(defaults);
sb.params = Utils.extend(defaults, params);
const $el = $(sb.params.el);
if ($el.length === 0) return sb;
$el[0].f7Searchbar = sb;
let $pageEl;
let $navbarEl;
if ($el.parents('.page').length > 0) {
$pageEl = $el.parents('.page');
} else {
$navbarEl = $el.parents('.navbar-inner');
if ($navbarEl.length > 0) {
if ($navbarEl[0].f7Page) {
$pageEl = $navbarEl[0].f7Page.$el;
} else {
const $currentPageEl = $el.parents('.view').find('.page-current');
if ($currentPageEl[0] && $currentPageEl[0].f7Page && $currentPageEl[0].f7Page.navbarEl === $navbarEl[0]) {
$pageEl = $currentPageEl;
}
}
}
}
let $foundEl;
if (params.foundEl) {
$foundEl = $(params.foundEl);
} else if (typeof sb.params.foundEl === 'string' && $pageEl) {
$foundEl = $pageEl.find(sb.params.foundEl);
}
let $notFoundEl;
if (params.notFoundEl) {
$notFoundEl = $(params.notFoundEl);
} else if (typeof sb.params.notFoundEl === 'string' && $pageEl) {
$notFoundEl = $pageEl.find(sb.params.notFoundEl);
}
let $hideOnEnableEl;
if (params.hideOnEnableEl) {
$hideOnEnableEl = $(params.hideOnEnableEl);
} else if (typeof sb.params.hideOnEnableEl === 'string' && $pageEl) {
$hideOnEnableEl = $pageEl.find(sb.params.hideOnEnableEl);
}
let $hideOnSearchEl;
if (params.hideOnSearchEl) {
$hideOnSearchEl = $(params.hideOnSearchEl);
} else if (typeof sb.params.hideOnSearchEl === 'string' && $pageEl) {
$hideOnSearchEl = $pageEl.find(sb.params.hideOnSearchEl);
}
let $backdropEl;
if (sb.params.backdrop) {
if (sb.params.backdropEl) {
$backdropEl = $(sb.params.backdropEl);
} else if ($pageEl && $pageEl.length > 0) {
$backdropEl = $pageEl.find('.searchbar-backdrop');
} else {
$backdropEl = $el.siblings('.searchbar-backdrop');
}
if ($backdropEl.length === 0) {
$backdropEl = $('<div class="searchbar-backdrop"></div>');
if ($pageEl && $pageEl.length) {
if ($el.parents($pageEl).length > 0 && $navbarEl && $el.parents($navbarEl).length === 0) {
$backdropEl.insertBefore($el);
} else {
$backdropEl.insertBefore($pageEl.find('.page-content').eq(0));
}
} else {
$backdropEl.insertBefore($el);
}
}
}
let $searchContainer;
if (sb.params.searchContainer) {
$searchContainer = $(sb.params.searchContainer);
}
let $inputEl;
if (sb.params.inputEl) {
$inputEl = $(sb.params.inputEl);
} else {
$inputEl = $el.find('input[type="search"]').eq(0);
}
let $disableButtonEl;
if (sb.params.disableButton) {
if (sb.params.disableButtonEl) {
$disableButtonEl = $(sb.params.disableButtonEl);
} else {
$disableButtonEl = $el.find('.searchbar-disable-button');
}
}
Utils.extend(sb, {
app,
view: app.views.get($el.parents('.view')),
$el,
el: $el[0],
$backdropEl,
backdropEl: $backdropEl && $backdropEl[0],
$searchContainer,
searchContainer: $searchContainer && $searchContainer[0],
$inputEl,
inputEl: $inputEl[0],
$disableButtonEl,
disableButtonEl: $disableButtonEl[0],
disableButtonHasMargin: false,
$pageEl,
pageEl: $pageEl && $pageEl[0],
$navbarEl,
navbarEl: $navbarEl && $navbarEl[0],
$foundEl,
foundEl: $foundEl && $foundEl[0],
$notFoundEl,
notFoundEl: $notFoundEl && $notFoundEl[0],
$hideOnEnableEl,
hideOnEnableEl: $hideOnEnableEl && $hideOnEnableEl[0],
$hideOnSearchEl,
hideOnSearchEl: $hideOnSearchEl && $hideOnSearchEl[0],
previousQuery: '',
query: '',
isVirtualList: $searchContainer && $searchContainer.hasClass('virtual-list'),
virtualList: undefined,
enabled: false,
expandable: sb.params.expandable || $el.hasClass('searchbar-expandable'),
});
// Events
function preventSubmit(e) {
e.preventDefault();
}
function onInputFocus(e) {
sb.enable(e);
sb.$el.addClass('searchbar-focused');
}
function onInputBlur() {
sb.$el.removeClass('searchbar-focused');
}
function onInputChange() {
const value = sb.$inputEl.val().trim();
if (
(
(sb.$searchContainer && sb.$searchContainer.length > 0) &&
(sb.params.searchIn || sb.isVirtualList || sb.params.searchIn === sb.params.searchItem)
) ||
sb.params.customSearch
) {
sb.search(value, true);
}
}
function onInputClear(e, previousValue) {
sb.$el.trigger('searchbar:clear', previousValue);
sb.emit('local::clear searchbarClear', sb, previousValue);
}
function disableOnClick(e) {
sb.disable(e);
}
function onPageBeforeOut() {
if (!sb || (sb && !sb.$el)) return;
if (sb.enabled) {
sb.$el.removeClass('searchbar-enabled');
}
}
function onPageBeforeIn() {
if (!sb || (sb && !sb.$el)) return;
if (sb.enabled) {
sb.$el.addClass('searchbar-enabled');
}
}
sb.attachEvents = function attachEvents() {
$el.on('submit', preventSubmit);
if (sb.params.disableButton) {
sb.$disableButtonEl.on('click', disableOnClick);
}
if (sb.params.disableOnBackdropClick && sb.$backdropEl) {
sb.$backdropEl.on('click', disableOnClick);
}
if (sb.expandable && app.theme === 'ios' && sb.view && $navbarEl && sb.$pageEl) {
sb.$pageEl.on('page:beforeout', onPageBeforeOut);
sb.$pageEl.on('page:beforein', onPageBeforeIn);
}
sb.$inputEl.on('focus', onInputFocus);
sb.$inputEl.on('blur', onInputBlur);
sb.$inputEl.on('change input compositionend', onInputChange);
sb.$inputEl.on('input:clear', onInputClear);
};
sb.detachEvents = function detachEvents() {
$el.off('submit', preventSubmit);
if (sb.params.disableButton) {
sb.$disableButtonEl.off('click', disableOnClick);
}
if (sb.params.disableOnBackdropClick && sb.$backdropEl) {
sb.$backdropEl.off('click', disableOnClick);
}
if (sb.expandable && app.theme === 'ios' && sb.view && $navbarEl && sb.$pageEl) {
sb.$pageEl.on('page:beforeout', onPageBeforeOut);
sb.$pageEl.on('page:beforein', onPageBeforeIn);
}
sb.$inputEl.off('focus', onInputFocus);
sb.$inputEl.off('blur', onInputBlur);
sb.$inputEl.off('change input compositionend', onInputChange);
sb.$inputEl.off('input:clear', onInputClear);
};
// Install Modules
sb.useModules();
// Init
sb.init();
return sb;
}
clear(e) {
const sb = this;
if (!sb.query && e && $(e.target).hasClass('searchbar-clear')) {
sb.disable();
return sb;
}
const previousQuery = sb.value;
sb.$inputEl.val('').trigger('change').focus();
sb.$el.trigger('searchbar:clear', previousQuery);
sb.emit('local::clear searchbarClear', sb, previousQuery);
return sb;
}
setDisableButtonMargin() {
const sb = this;
if (sb.expandable) return;
const app = sb.app;
sb.$disableButtonEl.transition(0).show();
sb.$disableButtonEl.css(`margin-${app.rtl ? 'left' : 'right'}`, `${-sb.disableButtonEl.offsetWidth}px`);
/* eslint no-underscore-dangle: ["error", { "allow": ["_clientLeft"] }] */
sb._clientLeft = sb.$disableButtonEl[0].clientLeft;
sb.$disableButtonEl.transition('');
sb.disableButtonHasMargin = true;
}
enable(setFocus) {
const sb = this;
if (sb.enabled) return sb;
const app = sb.app;
sb.enabled = true;
function enable() {
if (sb.$backdropEl && ((sb.$searchContainer && sb.$searchContainer.length) || sb.params.customSearch) && !sb.$el.hasClass('searchbar-enabled') && !sb.query) {
sb.backdropShow();
}
sb.$el.addClass('searchbar-enabled');
if (!sb.expandable && sb.$disableButtonEl && sb.$disableButtonEl.length > 0 && app.theme === 'ios') {
if (!sb.disableButtonHasMargin) {
sb.setDisableButtonMargin();
}
sb.$disableButtonEl.css(`margin-${app.rtl ? 'left' : 'right'}`, '0px');
}
if (sb.$hideOnEnableEl) sb.$hideOnEnableEl.hide();
sb.$el.trigger('searchbar:enable');
sb.emit('local::enable searchbarEnable', sb);
}
let needsFocus = false;
if (setFocus === true) {
if (document.activeElement !== sb.inputEl) {
needsFocus = true;
}
}
const isIos = app.device.ios && app.theme === 'ios';
if (isIos) {
if (sb.expandable) {
if (needsFocus) sb.$inputEl.focus();
enable();
} else {
if (needsFocus) sb.$inputEl.focus();
if (setFocus && (setFocus.type === 'focus' || setFocus === true)) {
Utils.nextTick(() => {
enable();
}, 400);
} else {
enable();
}
}
} else {
if (needsFocus) sb.$inputEl.focus();
if (app.theme === 'md' && sb.expandable) {
sb.$el.parents('.navbar-inner').scrollLeft(0);
}
enable();
}
return sb;
}
disable() {
const sb = this;
if (!sb.enabled) return sb;
const app = sb.app;
sb.$inputEl.val('').trigger('change');
sb.$el.removeClass('searchbar-enabled');
sb.$el.removeClass('searchbar-focused');
if (!sb.expandable && sb.$disableButtonEl && sb.$disableButtonEl.length > 0 && app.theme === 'ios') {
sb.$disableButtonEl.css(`margin-${app.rtl ? 'left' : 'right'}`, `${-sb.disableButtonEl.offsetWidth}px`);
}
if (sb.$backdropEl && ((sb.$searchContainer && sb.$searchContainer.length) || sb.params.customSearch)) {
sb.backdropHide();
}
sb.enabled = false;
sb.$inputEl.blur();
if (sb.$hideOnEnableEl) sb.$hideOnEnableEl.show();
sb.$el.trigger('searchbar:disable');
sb.emit('local::disable searchbarDisable', sb);
return sb;
}
toggle() {
const sb = this;
if (sb.enabled) sb.disable();
else sb.enable(true);
return sb;
}
backdropShow() {
const sb = this;
if (sb.$backdropEl) {
sb.$backdropEl.addClass('searchbar-backdrop-in');
}
return sb;
}
backdropHide() {
const sb = this;
if (sb.$backdropEl) {
sb.$backdropEl.removeClass('searchbar-backdrop-in');
}
return sb;
}
search(query, internal) {
const sb = this;
if (sb.previousQuery && query.trim() === sb.previousQuery) return sb;
if (typeof (sb.previousQuery) !== 'undefined' && sb.previousQuery.trim() === '' && query.trim() === '') return sb;
sb.previousQuery = query.trim();
if (!internal) {
if (!sb.enabled) {
sb.enable();
}
sb.$inputEl.val(query);
}
sb.query = query;
sb.value = query;
const { $searchContainer, $el, $backdropEl, $foundEl, $notFoundEl, $hideOnSearchEl, isVirtualList } = sb;
// Hide on search element
if (query.length > 0 && $hideOnSearchEl) {
$hideOnSearchEl.hide();
} else if ($hideOnSearchEl) {
$hideOnSearchEl.show();
}
// Add active/inactive classes on overlay
if (query.length === 0) {
if ($searchContainer && $searchContainer.length && $el.hasClass('searchbar-enabled') && $backdropEl) sb.backdropShow();
} else if ($searchContainer && $searchContainer.length && $el.hasClass('searchbar-enabled')) {
sb.backdropHide();
}
if (sb.params.customSearch) {
$el.trigger('searchbar:search', query, sb.previousQuery);
sb.emit('local::search searchbarSearch', sb, query, sb.previousQuery);
return sb;
}
let foundItems = [];
let vlQuery;
if (isVirtualList) {
sb.virtualList = $searchContainer[0].f7VirtualList;
if (query.trim() === '') {
sb.virtualList.resetFilter();
if ($notFoundEl) $notFoundEl.hide();
if ($foundEl) $foundEl.show();
return sb;
}
vlQuery = sb.params.removeDiacritics ? Utils.removeDiacritics(query) : query;
if (sb.virtualList.params.searchAll) {
foundItems = sb.virtualList.params.searchAll(vlQuery, sb.virtualList.items) || [];
} else if (sb.virtualList.params.searchByItem) {
for (let i = 0; i < sb.virtualList.items.length; i += 1) {
if (sb.virtualList.params.searchByItem(vlQuery, sb.virtualList.params.items[i], i)) {
foundItems.push(i);
}
}
}
} else {
let values;
if (sb.params.removeDiacritics) values = Utils.removeDiacritics(query.trim().toLowerCase()).split(' ');
else {
values = query.trim().toLowerCase().split(' ');
}
$searchContainer.find(sb.params.searchItem).removeClass('hidden-by-searchbar').each((itemIndex, itemEl) => {
const $itemEl = $(itemEl);
let compareWithText = [];
let $searchIn = sb.params.searchIn ? $itemEl.find(sb.params.searchIn) : $itemEl;
if (sb.params.searchIn === sb.params.searchItem) {
$searchIn = $itemEl;
}
$searchIn.each((searchInIndex, searchInEl) => {
let itemText = $(searchInEl).text().trim().toLowerCase();
if (sb.params.removeDiacritics) itemText = Utils.removeDiacritics(itemText);
compareWithText.push(itemText);
});
compareWithText = compareWithText.join(' ');
let wordsMatch = 0;
for (let i = 0; i < values.length; i += 1) {
if (compareWithText.indexOf(values[i]) >= 0) wordsMatch += 1;
}
if (wordsMatch !== values.length && !(sb.params.ignore && $itemEl.is(sb.params.ignore))) {
$itemEl.addClass('hidden-by-searchbar');
} else {
foundItems.push($itemEl[0]);
}
});
if (sb.params.hideDividers) {
$searchContainer.find('.item-divider, .list-group-title').each((titleIndex, titleEl) => {
const $titleEl = $(titleEl);
const $nextElements = $titleEl.nextAll('li');
let hide = true;
for (let i = 0; i < $nextElements.length; i += 1) {
const $nextEl = $nextElements.eq(i);
if ($nextEl.hasClass('list-group-title') || $nextEl.hasClass('item-divider')) break;
if (!$nextEl.hasClass('hidden-by-searchbar')) {
hide = false;
}
}
const ignore = sb.params.ignore && $titleEl.is(sb.params.ignore);
if (hide && !ignore) $titleEl.addClass('hidden-by-searchbar');
else $titleEl.removeClass('hidden-by-searchbar');
});
}
if (sb.params.hideGroups) {
$searchContainer.find('.list-group').each((groupIndex, groupEl) => {
const $groupEl = $(groupEl);
const ignore = sb.params.ignore && $groupEl.is(sb.params.ignore);
const notHidden = $groupEl.find('li:not(.hidden-by-searchbar)');
if (notHidden.length === 0 && !ignore) {
$groupEl.addClass('hidden-by-searchbar');
} else {
$groupEl.removeClass('hidden-by-searchbar');
}
});
}
}
if (foundItems.length === 0) {
if ($notFoundEl) $notFoundEl.show();
if ($foundEl) $foundEl.hide();
} else {
if ($notFoundEl) $notFoundEl.hide();
if ($foundEl) $foundEl.show();
}
if (isVirtualList && sb.virtualList) {
sb.virtualList.filterItems(foundItems);
}
$el.trigger('searchbar:search', query, sb.previousQuery, foundItems);
sb.emit('local::search searchbarSearch', sb, query, sb.previousQuery, foundItems);
return sb;
}
init() {
const sb = this;
sb.attachEvents();
}
destroy() {
const sb = this;
sb.emit('local::beforeDestroy searchbarBeforeDestroy', sb);
sb.$el.trigger('searchbar:beforedestroy', sb);
sb.detachEvents();
delete sb.$el.f7Searchbar;
Utils.deleteProps(sb);
}
}
var Searchbar = {
name: 'searchbar',
static: {
Searchbar: Searchbar$1,
},
create() {
const app = this;
app.searchbar = ConstructorMethods({
defaultSelector: '.searchbar',
constructor: Searchbar$1,
app,
domProp: 'f7Searchbar',
addMethods: 'clear enable disable toggle search'.split(' '),
});
},
on: {
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.searchbar-init').each((index, searchbarEl) => {
const $searchbarEl = $(searchbarEl);
app.searchbar.create(Utils.extend($searchbarEl.dataset(), { el: searchbarEl }));
});
},
tabBeforeRemove(tabEl) {
$(tabEl).find('.searchbar-init').each((index, searchbarEl) => {
if (searchbarEl.f7Searchbar && searchbarEl.f7Searchbar.destroy) {
searchbarEl.f7Searchbar.destroy();
}
});
},
pageInit(page) {
const app = this;
page.$el.find('.searchbar-init').each((index, searchbarEl) => {
const $searchbarEl = $(searchbarEl);
app.searchbar.create(Utils.extend($searchbarEl.dataset(), { el: searchbarEl }));
});
if (app.theme === 'ios' && page.view && page.view.router.separateNavbar && page.$navbarEl && page.$navbarEl.length > 0) {
page.$navbarEl.find('.searchbar-init').each((index, searchbarEl) => {
const $searchbarEl = $(searchbarEl);
app.searchbar.create(Utils.extend($searchbarEl.dataset(), { el: searchbarEl }));
});
}
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.searchbar-init').each((index, searchbarEl) => {
if (searchbarEl.f7Searchbar && searchbarEl.f7Searchbar.destroy) {
searchbarEl.f7Searchbar.destroy();
}
});
if (app.theme === 'ios' && page.view && page.view.router.separateNavbar && page.$navbarEl && page.$navbarEl.length > 0) {
page.$navbarEl.find('.searchbar-init').each((index, searchbarEl) => {
if (searchbarEl.f7Searchbar && searchbarEl.f7Searchbar.destroy) {
searchbarEl.f7Searchbar.destroy();
}
});
}
},
},
clicks: {
'.searchbar-clear': function clear($clickedEl, data = {}) {
const app = this;
const sb = app.searchbar.get(data.searchbar);
if (sb) sb.clear();
},
'.searchbar-enable': function enable($clickedEl, data = {}) {
const app = this;
const sb = app.searchbar.get(data.searchbar);
if (sb) sb.enable(true);
},
'.searchbar-disable': function disable($clickedEl, data = {}) {
const app = this;
const sb = app.searchbar.get(data.searchbar);
if (sb) sb.disable();
},
'.searchbar-toggle': function toggle($clickedEl, data = {}) {
const app = this;
const sb = app.searchbar.get(data.searchbar);
if (sb) sb.toggle();
},
},
};
class Messages$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const m = this;
const defaults = {
autoLayout: true,
messages: [],
newMessagesFirst: false,
scrollMessages: true,
scrollMessagesOnEdge: true,
firstMessageRule: undefined,
lastMessageRule: undefined,
tailMessageRule: undefined,
sameNameMessageRule: undefined,
sameHeaderMessageRule: undefined,
sameFooterMessageRule: undefined,
sameAvatarMessageRule: undefined,
customClassMessageRule: undefined,
renderMessage: undefined,
};
// Extend defaults with modules params
m.useModulesParams(defaults);
m.params = Utils.extend(defaults, params);
const $el = $(params.el).eq(0);
if ($el.length === 0) return m;
$el[0].f7Messages = m;
const $pageContentEl = $el.closest('.page-content').eq(0);
Utils.extend(m, {
messages: m.params.messages,
$el,
el: $el[0],
$pageContentEl,
pageContentEl: $pageContentEl[0],
});
// Install Modules
m.useModules();
// Init
m.init();
return m;
}
// eslint-disable-next-line
getMessageData(messageEl) {
const $messageEl = $(messageEl);
const data = {
name: $messageEl.find('.message-name').html(),
header: $messageEl.find('.message-header').html(),
textHeader: $messageEl.find('.message-text-header').html(),
textFooter: $messageEl.find('.message-text-footer').html(),
footer: $messageEl.find('.message-footer').html(),
isTitle: $messageEl.hasClass('messages-title'),
type: $messageEl.hasClass('message-sent') ? 'sent' : 'received',
text: $messageEl.find('.message-text').html(),
image: $messageEl.find('.message-image').html(),
imageSrc: $messageEl.find('.message-image img').attr('src'),
typing: $messageEl.hasClass('message-typing'),
};
if (data.isTitle) {
data.text = $messageEl.html();
}
if (data.text && data.textHeader) {
data.text = data.text.replace(`<div class="message-text-header">${data.textHeader}</div>`, '');
}
if (data.text && data.textFooter) {
data.text = data.text.replace(`<div class="message-text-footer">${data.textFooter}</div>`, '');
}
let avatar = $messageEl.find('.message-avatar').css('background-image');
if (avatar === 'none' || avatar === '') avatar = undefined;
if (avatar && typeof avatar === 'string') {
avatar = avatar.replace('url(', '').replace(')', '').replace(/"/g, '').replace(/'/g, '');
} else {
avatar = undefined;
}
data.avatar = avatar;
return data;
}
getMessagesData() {
const m = this;
const data = [];
m.$el.find('.message, .messages-title').each((index, messageEl) => {
data.push(m.getMessageData(messageEl));
});
return data;
}
renderMessage(messageToRender) {
const m = this;
const message = Utils.extend({
type: 'sent',
}, messageToRender);
if (m.params.renderMessage) {
return m.params.renderMessage.call(m, message);
}
if (message.isTitle) {
return `<div class="messages-title">${message.text}</div>`;
}
return `
<div class="message message-${message.type} ${message.isTyping ? 'message-typing' : ''}">
${message.avatar ? `
<div class="message-avatar" style="background-image:url(${message.avatar})"></div>
` : ''}
<div class="message-content">
${message.name ? `<div class="message-name">${message.name}</div>` : ''}
${message.header ? `<div class="message-header">${message.header}</div>` : ''}
<div class="message-bubble">
${message.textHeader ? `<div class="message-text-header">${message.textHeader}</div>` : ''}
${message.image ? `<div class="message-image">${message.image}</div>` : ''}
${message.imageSrc && !message.image ? `<div class="message-image"><img src="${message.imageSrc}"></div>` : ''}
${message.text || message.isTyping ? `<div class="message-text">${message.text || ''}${message.isTyping ? '<div class="message-typing-indicator"><div></div><div></div><div></div></div>' : ''}</div>` : ''}
${message.textFooter ? `<div class="message-text-footer">${message.textFooter}</div>` : ''}
</div>
${message.footer ? `<div class="message-footer">${message.footer}</div>` : ''}
</div>
</div>
`;
}
renderMessages(messagesToRender = this.messages, method = this.params.newMessagesFirst ? 'prepend' : 'append') {
const m = this;
const html = messagesToRender.map(message => m.renderMessage(message)).join('');
m.$el[method](html);
}
isFirstMessage(...args) {
const m = this;
if (m.params.firstMessageRule) return m.params.firstMessageRule(...args);
return false;
}
isLastMessage(...args) {
const m = this;
if (m.params.lastMessageRule) return m.params.lastMessageRule(...args);
return false;
}
isTailMessage(...args) {
const m = this;
if (m.params.tailMessageRule) return m.params.tailMessageRule(...args);
return false;
}
isSameNameMessage(...args) {
const m = this;
if (m.params.sameNameMessageRule) return m.params.sameNameMessageRule(...args);
return false;
}
isSameHeaderMessage(...args) {
const m = this;
if (m.params.sameHeaderMessageRule) return m.params.sameHeaderMessageRule(...args);
return false;
}
isSameFooterMessage(...args) {
const m = this;
if (m.params.sameFooterMessageRule) return m.params.sameFooterMessageRule(...args);
return false;
}
isSameAvatarMessage(...args) {
const m = this;
if (m.params.sameAvatarMessageRule) return m.params.sameAvatarMessageRule(...args);
return false;
}
isCustomClassMessage(...args) {
const m = this;
if (m.params.customClassMessageRule) return m.params.customClassMessageRule(...args);
return undefined;
}
layout() {
const m = this;
m.$el.find('.message, .messages-title').each((index, messageEl) => {
const $messageEl = $(messageEl);
if (!m.messages) {
m.messages = m.getMessagesData();
}
const classes = [];
const message = m.messages[index];
const previousMessage = m.messages[index - 1];
const nextMessage = m.messages[index + 1];
if (m.isFirstMessage(message, previousMessage, nextMessage)) {
classes.push('message-first');
}
if (m.isLastMessage(message, previousMessage, nextMessage)) {
classes.push('message-last');
}
if (m.isTailMessage(message, previousMessage, nextMessage)) {
classes.push('message-tail');
}
if (m.isSameNameMessage(message, previousMessage, nextMessage)) {
classes.push('message-same-name');
}
if (m.isSameHeaderMessage(message, previousMessage, nextMessage)) {
classes.push('message-same-header');
}
if (m.isSameFooterMessage(message, previousMessage, nextMessage)) {
classes.push('message-same-footer');
}
if (m.isSameAvatarMessage(message, previousMessage, nextMessage)) {
classes.push('message-same-avatar');
}
let customMessageClasses = m.isCustomClassMessage(message, previousMessage, nextMessage);
if (customMessageClasses && customMessageClasses.length) {
if (typeof customMessageClasses === 'string') {
customMessageClasses = customMessageClasses.split(' ');
}
customMessageClasses.forEach((customClass) => {
classes.push(customClass);
});
}
$messageEl.removeClass('message-first message-last message-tail message-same-name message-same-header message-same-footer message-same-avatar');
classes.forEach((className) => {
$messageEl.addClass(className);
});
});
}
clear() {
const m = this;
m.messages = [];
m.$el.html('');
}
removeMessage(messageToRemove, layout = true) {
const m = this;
// Index or El
let index;
let $el;
if (typeof messageToRemove === 'number') {
index = messageToRemove;
$el = m.$el.find('.message, .messages-title').eq(index);
} else if (m.messages && m.messages.indexOf(messageToRemove) >= 0) {
index = m.messages.indexOf(messageToRemove);
$el = m.$el.children().eq(index);
} else {
$el = $(messageToRemove);
index = $el.index();
}
if ($el.length === 0) {
return m;
}
$el.remove();
m.messages.splice(index, 1);
if (m.params.autoLayout && layout) m.layout();
return m;
}
removeMessages(messagesToRemove, layout = true) {
const m = this;
if (Array.isArray(messagesToRemove)) {
const messagesToRemoveEls = [];
messagesToRemove.forEach((messageToRemoveIndex) => {
messagesToRemoveEls.push(m.$el.find('.message, .messages-title').eq(messageToRemoveIndex));
});
messagesToRemoveEls.forEach((messageToRemove) => {
m.removeMessage(messageToRemove, false);
});
} else {
$(messagesToRemove).each((index, messageToRemove) => {
m.removeMessage(messageToRemove, false);
});
}
if (m.params.autoLayout && layout) m.layout();
return m;
}
addMessage(...args) {
const m = this;
let messageToAdd;
let animate;
let method;
if (typeof args[1] === 'boolean') {
[messageToAdd, animate, method] = args;
} else {
[messageToAdd, method, animate] = args;
}
if (typeof animate === 'undefined') {
animate = true;
}
if (typeof method === 'undefined') {
method = m.params.newMessagesFirst ? 'prepend' : 'append';
}
return m.addMessages([messageToAdd], animate, method);
}
addMessages(...args) {
const m = this;
let messagesToAdd;
let animate;
let method;
if (typeof args[1] === 'boolean') {
[messagesToAdd, animate, method] = args;
} else {
[messagesToAdd, method, animate] = args;
}
if (typeof animate === 'undefined') {
animate = true;
}
if (typeof method === 'undefined') {
method = m.params.newMessagesFirst ? 'prepend' : 'append';
}
// Define scroll positions before new messages added
const scrollHeightBefore = m.pageContentEl.scrollHeight;
const heightBefore = m.pageContentEl.offsetHeight;
const scrollBefore = m.pageContentEl.scrollTop;
// Add message to DOM and data
let messagesHTML = '';
const typingMessage = m.messages.filter(el => el.isTyping)[0];
messagesToAdd.forEach((messageToAdd) => {
if (typingMessage) {
if (method === 'append') {
m.messages.splice(m.messages.indexOf(typingMessage), 0, messageToAdd);
} else {
m.messages.splice(m.messages.indexOf(typingMessage) + 1, 0, messageToAdd);
}
} else {
m.messages[method === 'append' ? 'push' : 'unshift'](messageToAdd);
}
messagesHTML += m.renderMessage(messageToAdd);
});
const $messagesEls = $(messagesHTML);
if (animate) {
if (method === 'append' && !m.params.newMessagesFirst) {
$messagesEls.addClass('message-appear-from-bottom');
}
if (method === 'prepend' && m.params.newMessagesFirst) {
$messagesEls.addClass('message-appear-from-top');
}
}
if (typingMessage) {
if (method === 'append') {
$messagesEls.insertBefore(m.$el.find('.message-typing'));
} else {
$messagesEls.insertAfter(m.$el.find('.message-typing'));
}
} else {
m.$el[method]($messagesEls);
}
// Layout
if (m.params.autoLayout) m.layout();
if (method === 'prepend' && !typingMessage) {
m.pageContentEl.scrollTop = scrollBefore + (m.pageContentEl.scrollHeight - scrollHeightBefore);
}
if (m.params.scrollMessages && ((method === 'append' && !m.params.newMessagesFirst) || (method === 'prepend' && m.params.newMessagesFirst && !typingMessage))) {
if (m.params.scrollMessagesOnEdge) {
let onEdge = false;
if (m.params.newMessagesFirst && scrollBefore === 0) {
onEdge = true;
}
if (!m.params.newMessagesFirst && (scrollBefore - (scrollHeightBefore - heightBefore) >= -10)) {
onEdge = true;
}
if (onEdge) m.scroll(animate ? undefined : 0);
} else {
m.scroll(animate ? undefined : 0);
}
}
return m;
}
showTyping(message = {}) {
const m = this;
const typingMessage = m.messages.filter(el => el.isTyping)[0];
if (typingMessage) {
m.removeMessage(m.messages.indexOf(typingMessage));
}
m.addMessage(Utils.extend({
type: 'received',
isTyping: true,
}, message));
return m;
}
hideTyping() {
const m = this;
let typingMessageIndex;
let typingFound;
m.messages.forEach((message, index) => {
if (message.isTyping) typingMessageIndex = index;
});
if (typeof typingMessageIndex !== 'undefined') {
if (m.$el.find('.message').eq(typingMessageIndex).hasClass('message-typing')) {
typingFound = true;
m.removeMessage(typingMessageIndex);
}
}
if (!typingFound) {
const $typingMessageEl = m.$el.find('.message-typing');
if ($typingMessageEl.length) {
m.removeMessage($typingMessageEl);
}
}
return m;
}
scroll(duration = 300, scrollTop) {
const m = this;
const currentScroll = m.pageContentEl.scrollTop;
let newScrollTop;
if (typeof scrollTop !== 'undefined') newScrollTop = scrollTop;
else {
newScrollTop = m.params.newMessagesFirst ? 0 : m.pageContentEl.scrollHeight - m.pageContentEl.offsetHeight;
if (newScrollTop === currentScroll) return m;
}
m.$pageContentEl.scrollTop(newScrollTop, duration);
return m;
}
init() {
const m = this;
if (!m.messages || m.messages.length === 0) {
m.messages = m.getMessagesData();
}
if (m.params.messages && m.params.messages.length) {
m.renderMessages();
}
if (m.params.autoLayout) m.layout();
if (m.params.scrollMessages) m.scroll(0);
}
destroy() {
const m = this;
m.emit('local::beforeDestroy messagesBeforeDestroy', m);
m.$el.trigger('messages:beforedestroy', m);
m.$el[0].f7Messages = null;
delete m.$el[0].f7Messages;
Utils.deleteProps(m);
}
}
var Messages = {
name: 'messages',
static: {
Messages: Messages$1,
},
create() {
const app = this;
app.messages = ConstructorMethods({
defaultSelector: '.messages',
constructor: Messages$1,
app,
domProp: 'f7Messages',
addMethods: 'renderMessages layout scroll clear removeMessage removeMessages addMessage addMessages'.split(' '),
});
},
on: {
tabBeforeRemove(tabEl) {
const app = this;
$(tabEl).find('.messages-init').each((index, messagesEl) => {
app.messages.destroy(messagesEl);
});
},
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.messages-init').each((index, messagesEl) => {
app.messages.create({ el: messagesEl });
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.messages-init').each((index, messagesEl) => {
app.messages.destroy(messagesEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.messages-init').each((index, messagesEl) => {
app.messages.create({ el: messagesEl });
});
},
},
clicks: {
},
};
class Messagebar$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const messagebar = this;
const defaults = {
top: false,
topOffset: 0,
bottomOffset: 0,
attachments: [],
renderAttachments: undefined,
renderAttachment: undefined,
maxHeight: null,
resizePage: true,
};
// Extend defaults with modules params
messagebar.useModulesParams(defaults);
messagebar.params = Utils.extend(defaults, params);
// El
const $el = $(messagebar.params.el);
if ($el.length === 0) return messagebar;
$el[0].f7Messagebar = messagebar;
// Page and PageContent
const $pageEl = $el.parents('.page').eq(0);
const $pageContentEl = $pageEl.find('.page-content').eq(0);
// Area
const $areaEl = $el.find('.messagebar-area');
// Textarea
let $textareaEl;
if (messagebar.params.textareaEl) {
$textareaEl = $(messagebar.params.textareaEl);
} else {
$textareaEl = $el.find('textarea');
}
// Attachments & Library
const $attachmentsEl = $el.find('.messagebar-attachments');
const $sheetEl = $el.find('.messagebar-sheet');
if (messagebar.params.top) {
$el.addClass('messagebar-top');
}
Utils.extend(messagebar, {
$el,
el: $el[0],
$areaEl,
areaEl: $areaEl[0],
$textareaEl,
textareaEl: $textareaEl[0],
$attachmentsEl,
attachmentsEl: $attachmentsEl[0],
attachmentsVisible: $attachmentsEl.hasClass('messagebar-attachments-visible'),
$sheetEl,
sheetEl: $sheetEl[0],
sheetVisible: $sheetEl.hasClass('messagebar-sheet-visible'),
$pageEl,
pageEl: $pageEl[0],
$pageContentEl,
pageContentEl: $pageContentEl,
top: $el.hasClass('messagebar-top') || messagebar.params.top,
attachments: [],
});
// Events
function onAppResize() {
if (messagebar.params.resizePage) {
messagebar.resizePage();
}
}
function onSubmit(e) {
e.preventDefault();
}
function onAttachmentClick(e) {
const index = $(this).index();
if ($(e.target).closest('.messagebar-attachment-delete').length) {
$(this).trigger('messagebar:attachmentdelete', index);
messagebar.emit('local::attachmentDelete messagebarAttachmentDelete', messagebar, this, index);
} else {
$(this).trigger('messagebar:attachmentclick', index);
messagebar.emit('local::attachmentClick messagebarAttachmentClick', messagebar, this, index);
}
}
function onTextareaChange() {
messagebar.checkEmptyState();
messagebar.$el.trigger('messagebar:change');
messagebar.emit('local::change messagebarChange', messagebar);
}
function onTextareaFocus() {
messagebar.sheetHide();
messagebar.$el.trigger('messagebar:focus');
messagebar.emit('local::focus messagebarFocus', messagebar);
}
function onTextareaBlur() {
messagebar.$el.trigger('messagebar:blur');
messagebar.emit('local::blur messagebarBlur', messagebar);
}
messagebar.attachEvents = function attachEvents() {
$el.on('textarea:resize', onAppResize);
$el.on('submit', onSubmit);
$el.on('click', '.messagebar-attachment', onAttachmentClick);
$textareaEl.on('change input', onTextareaChange);
$textareaEl.on('focus', onTextareaFocus);
$textareaEl.on('blur', onTextareaBlur);
app.on('resize', onAppResize);
};
messagebar.detachEvents = function detachEvents() {
$el.off('textarea:resize', onAppResize);
$el.off('submit', onSubmit);
$el.off('click', '.messagebar-attachment', onAttachmentClick);
$textareaEl.off('change input', onTextareaChange);
$textareaEl.off('focus', onTextareaFocus);
$textareaEl.off('blur', onTextareaBlur);
app.off('resize', onAppResize);
};
// Install Modules
messagebar.useModules();
// Init
messagebar.init();
return messagebar;
}
focus() {
const messagebar = this;
messagebar.$textareaEl.focus();
return messagebar;
}
blur() {
const messagebar = this;
messagebar.$textareaEl.blur();
return messagebar;
}
clear() {
const messagebar = this;
messagebar.$textareaEl.val('').trigger('change');
return messagebar;
}
getValue() {
const messagebar = this;
return messagebar.$textareaEl.val().trim();
}
setValue(value) {
const messagebar = this;
messagebar.$textareaEl.val(value).trigger('change');
return messagebar;
}
setPlaceholder(placeholder) {
const messagebar = this;
messagebar.$textareaEl.attr('placeholder', placeholder);
return messagebar;
}
resizePage() {
const messagebar = this;
const {
params,
$el,
top,
$pageEl,
$pageContentEl,
$areaEl,
$textareaEl,
$sheetEl,
$attachmentsEl,
} = messagebar;
const elHeight = $el[0].offsetHeight;
let maxHeight = params.maxHeight;
if (top) {
/*
Disable at the moment
const requiredPaddingTop = elHeight + params.topOffset;
const currentPaddingTop = parseInt($pageContentEl.css('padding-top'), 10);
if (requiredPaddingTop !== currentPaddingTop) {
if (!maxHeight) {
maxHeight = $pageEl[0].offsetHeight - currentPaddingTop - $sheetEl.outerHeight() - $attachmentsEl.outerHeight() - parseInt($areaEl.css('margin-top'), 10) - parseInt($areaEl.css('margin-bottom'), 10);
}
$textareaEl.css('max-height', `${maxHeight}px`);
$pageContentEl.css('padding-top', `${requiredPaddingTop}px`);
$el.trigger('messagebar:resizePage');
messagebar.emit('local::resizepage messagebarResizePage');
}
*/
} else {
const currentPaddingBottom = parseInt($pageContentEl.css('padding-bottom'), 10);
const requiredPaddingBottom = elHeight + params.bottomOffset;
if (requiredPaddingBottom !== currentPaddingBottom && $pageContentEl.length) {
const currentPaddingTop = parseInt($pageContentEl.css('padding-top'), 10);
const pageScrollHeight = $pageContentEl[0].scrollHeight;
const pageOffsetHeight = $pageContentEl[0].offsetHeight;
const pageScrollTop = $pageContentEl[0].scrollTop;
const scrollOnBottom = (pageScrollTop === pageScrollHeight - pageOffsetHeight);
if (!maxHeight) {
maxHeight = $pageEl[0].offsetHeight - currentPaddingTop - $sheetEl.outerHeight() - $attachmentsEl.outerHeight() - parseInt($areaEl.css('margin-top'), 10) - parseInt($areaEl.css('margin-bottom'), 10);
}
$textareaEl.css('max-height', `${maxHeight}px`);
$pageContentEl.css('padding-bottom', `${requiredPaddingBottom}px`);
if (scrollOnBottom) {
$pageContentEl.scrollTop($pageContentEl[0].scrollHeight - pageOffsetHeight);
}
$el.trigger('messagebar:resizepage');
messagebar.emit('local::resizePage messagebarResizePage', messagebar);
}
}
}
checkEmptyState() {
const messagebar = this;
const { $el, $textareaEl } = messagebar;
const value = $textareaEl.val().trim();
if (value && value.length) {
$el.addClass('messagebar-with-value');
} else {
$el.removeClass('messagebar-with-value');
}
}
attachmentsCreate(innerHTML = '') {
const messagebar = this;
const $attachmentsEl = $(`<div class="messagebar-attachments">${innerHTML}</div>`);
$attachmentsEl.insertBefore(messagebar.$textareaEl);
Utils.extend(messagebar, {
$attachmentsEl,
attachmentsEl: $attachmentsEl[0],
});
return messagebar;
}
attachmentsShow(innerHTML = '') {
const messagebar = this;
messagebar.$attachmentsEl = messagebar.$el.find('.messagebar-attachments');
if (messagebar.$attachmentsEl.length === 0) {
messagebar.attachmentsCreate(innerHTML);
}
messagebar.$el.addClass('messagebar-attachments-visible');
messagebar.attachmentsVisible = true;
if (messagebar.params.resizePage) {
messagebar.resizePage();
}
return messagebar;
}
attachmentsHide() {
const messagebar = this;
messagebar.$el.removeClass('messagebar-attachments-visible');
messagebar.attachmentsVisible = false;
if (messagebar.params.resizePage) {
messagebar.resizePage();
}
return messagebar;
}
attachmentsToggle() {
const messagebar = this;
if (messagebar.attachmentsVisible) {
messagebar.attachmentsHide();
} else {
messagebar.attachmentsShow();
}
return messagebar;
}
renderAttachment(attachment) {
const messagebar = this;
if (messagebar.params.renderAttachment) {
return messagebar.params.renderAttachment.call(messagebar, attachment);
}
return `
<div class="messagebar-attachment">
<img src="${attachment}">
<span class="messagebar-attachment-delete"></span>
</div>
`;
}
renderAttachments() {
const messagebar = this;
let html;
if (messagebar.params.renderAttachments) {
html = messagebar.params.renderAttachments.call(messagebar, messagebar.attachments);
} else {
html = `${messagebar.attachments.map(attachment => messagebar.renderAttachment(attachment)).join('')}`;
}
if (messagebar.$attachmentsEl.length === 0) {
messagebar.attachmentsCreate(html);
} else {
messagebar.$attachmentsEl.html(html);
}
}
sheetCreate(innerHTML = '') {
const messagebar = this;
const $sheetEl = $(`<div class="messagebar-sheet">${innerHTML}</div>`);
messagebar.$el.append($sheetEl);
Utils.extend(messagebar, {
$sheetEl,
sheetEl: $sheetEl[0],
});
return messagebar;
}
sheetShow(innerHTML = '') {
const messagebar = this;
messagebar.$sheetEl = messagebar.$el.find('.messagebar-sheet');
if (messagebar.$sheetEl.length === 0) {
messagebar.sheetCreate(innerHTML);
}
messagebar.$el.addClass('messagebar-sheet-visible');
messagebar.sheetVisible = true;
if (messagebar.params.resizePage) {
messagebar.resizePage();
}
return messagebar;
}
sheetHide() {
const messagebar = this;
messagebar.$el.removeClass('messagebar-sheet-visible');
messagebar.sheetVisible = false;
if (messagebar.params.resizePage) {
messagebar.resizePage();
}
return messagebar;
}
sheetToggle() {
const messagebar = this;
if (messagebar.sheetVisible) {
messagebar.sheetHide();
} else {
messagebar.sheetShow();
}
return messagebar;
}
init() {
const messagebar = this;
messagebar.attachEvents();
messagebar.checkEmptyState();
return messagebar;
}
destroy() {
const messagebar = this;
messagebar.emit('local::beforeDestroy messagebarBeforeDestroy', messagebar);
messagebar.$el.trigger('messagebar:beforedestroy', messagebar);
messagebar.detachEvents();
messagebar.$el[0].f7Messagebar = null;
delete messagebar.$el[0].f7Messagebar;
Utils.deleteProps(messagebar);
}
}
var Messagebar = {
name: 'messagebar',
static: {
Messagebar: Messagebar$1,
},
create() {
const app = this;
app.messagebar = ConstructorMethods({
defaultSelector: '.messagebar',
constructor: Messagebar$1,
app,
domProp: 'f7Messagebar',
addMethods: 'clear getValue setValue setPlaceholder resizePage focus blur attachmentsCreate attachmentsShow attachmentsHide attachmentsToggle renderAttachments sheetCreate sheetShow sheetHide sheetToggle'.split(' '),
});
},
on: {
tabBeforeRemove(tabEl) {
const app = this;
$(tabEl).find('.messagebar-init').each((index, messagebarEl) => {
app.messagebar.destroy(messagebarEl);
});
},
tabMounted(tabEl) {
const app = this;
$(tabEl).find('.messagebar-init').each((index, messagebarEl) => {
app.messagebar.create(Utils.extend({ el: messagebarEl }, $(messagebarEl).dataset()));
});
},
pageBeforeRemove(page) {
const app = this;
page.$el.find('.messagebar-init').each((index, messagebarEl) => {
app.messagebar.destroy(messagebarEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.messagebar-init').each((index, messagebarEl) => {
app.messagebar.create(Utils.extend({ el: messagebarEl }, $(messagebarEl).dataset()));
});
},
},
};
var updateSize = function () {
const swiper = this;
let width;
let height;
const $el = swiper.$el;
if (typeof swiper.params.width !== 'undefined') {
width = swiper.params.width;
} else {
width = $el[0].clientWidth;
}
if (typeof swiper.params.height !== 'undefined') {
height = swiper.params.height;
} else {
height = $el[0].clientHeight;
}
if ((width === 0 && swiper.isHorizontal()) || (height === 0 && swiper.isVertical())) {
return;
}
// Subtract paddings
width = width - parseInt($el.css('padding-left'), 10) - parseInt($el.css('padding-right'), 10);
height = height - parseInt($el.css('padding-top'), 10) - parseInt($el.css('padding-bottom'), 10);
Utils.extend(swiper, {
width,
height,
size: swiper.isHorizontal() ? width : height,
});
};
var updateSlides = function () {
const swiper = this;
const params = swiper.params;
const { $wrapperEl, size: swiperSize, rtl, wrongRTL } = swiper;
const slides = $wrapperEl.children(`.${swiper.params.slideClass}`);
const isVirtual = swiper.virtual && params.virtual.enabled;
const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;
let snapGrid = [];
const slidesGrid = [];
const slidesSizesGrid = [];
let offsetBefore = params.slidesOffsetBefore;
if (typeof offsetBefore === 'function') {
offsetBefore = params.slidesOffsetBefore.call(swiper);
}
let offsetAfter = params.slidesOffsetAfter;
if (typeof offsetAfter === 'function') {
offsetAfter = params.slidesOffsetAfter.call(swiper);
}
const previousSlidesLength = slidesLength;
const previousSnapGridLength = swiper.snapGrid.length;
const previousSlidesGridLength = swiper.snapGrid.length;
let spaceBetween = params.spaceBetween;
let slidePosition = -offsetBefore;
let prevSlideSize = 0;
let index = 0;
if (typeof swiperSize === 'undefined') {
return;
}
if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
spaceBetween = (parseFloat(spaceBetween.replace('%', '')) / 100) * swiperSize;
}
swiper.virtualSize = -spaceBetween;
// reset margins
if (rtl) slides.css({ marginLeft: '', marginTop: '' });
else slides.css({ marginRight: '', marginBottom: '' });
let slidesNumberEvenToRows;
if (params.slidesPerColumn > 1) {
if (Math.floor(slidesLength / params.slidesPerColumn) === slidesLength / swiper.params.slidesPerColumn) {
slidesNumberEvenToRows = slidesLength;
} else {
slidesNumberEvenToRows = Math.ceil(slidesLength / params.slidesPerColumn) * params.slidesPerColumn;
}
if (params.slidesPerView !== 'auto' && params.slidesPerColumnFill === 'row') {
slidesNumberEvenToRows = Math.max(slidesNumberEvenToRows, params.slidesPerView * params.slidesPerColumn);
}
}
// Calc slides
let slideSize;
const slidesPerColumn = params.slidesPerColumn;
const slidesPerRow = slidesNumberEvenToRows / slidesPerColumn;
const numFullColumns = slidesPerRow - ((params.slidesPerColumn * slidesPerRow) - slidesLength);
for (let i = 0; i < slidesLength; i += 1) {
slideSize = 0;
const slide = slides.eq(i);
if (params.slidesPerColumn > 1) {
// Set slides order
let newSlideOrderIndex;
let column;
let row;
if (params.slidesPerColumnFill === 'column') {
column = Math.floor(i / slidesPerColumn);
row = i - (column * slidesPerColumn);
if (column > numFullColumns || (column === numFullColumns && row === slidesPerColumn - 1)) {
row += 1;
if (row >= slidesPerColumn) {
row = 0;
column += 1;
}
}
newSlideOrderIndex = column + ((row * slidesNumberEvenToRows) / slidesPerColumn);
slide
.css({
'-webkit-box-ordinal-group': newSlideOrderIndex,
'-moz-box-ordinal-group': newSlideOrderIndex,
'-ms-flex-order': newSlideOrderIndex,
'-webkit-order': newSlideOrderIndex,
order: newSlideOrderIndex,
});
} else {
row = Math.floor(i / slidesPerRow);
column = i - (row * slidesPerRow);
}
slide
.css(
`margin-${swiper.isHorizontal() ? 'top' : 'left'}`,
(row !== 0 && params.spaceBetween) && (`${params.spaceBetween}px`)
)
.attr('data-swiper-column', column)
.attr('data-swiper-row', row);
}
if (slide.css('display') === 'none') continue; // eslint-disable-line
if (params.slidesPerView === 'auto') {
slideSize = swiper.isHorizontal() ? slide.outerWidth(true) : slide.outerHeight(true);
if (params.roundLengths) slideSize = Math.floor(slideSize);
} else {
slideSize = (swiperSize - ((params.slidesPerView - 1) * spaceBetween)) / params.slidesPerView;
if (params.roundLengths) slideSize = Math.floor(slideSize);
if (slides[i]) {
if (swiper.isHorizontal()) {
slides[i].style.width = `${slideSize}px`;
} else {
slides[i].style.height = `${slideSize}px`;
}
}
}
if (slides[i]) {
slides[i].swiperSlideSize = slideSize;
}
slidesSizesGrid.push(slideSize);
if (params.centeredSlides) {
slidePosition = slidePosition + (slideSize / 2) + (prevSlideSize / 2) + spaceBetween;
if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - (swiperSize / 2) - spaceBetween;
if (i === 0) slidePosition = slidePosition - (swiperSize / 2) - spaceBetween;
if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
if ((index) % params.slidesPerGroup === 0) snapGrid.push(slidePosition);
slidesGrid.push(slidePosition);
} else {
if ((index) % params.slidesPerGroup === 0) snapGrid.push(slidePosition);
slidesGrid.push(slidePosition);
slidePosition = slidePosition + slideSize + spaceBetween;
}
swiper.virtualSize += slideSize + spaceBetween;
prevSlideSize = slideSize;
index += 1;
}
swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;
let newSlidesGrid;
if (
rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {
$wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
}
if (!Support$1.flexbox || params.setWrapperSize) {
if (swiper.isHorizontal()) $wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
else $wrapperEl.css({ height: `${swiper.virtualSize + params.spaceBetween}px` });
}
if (params.slidesPerColumn > 1) {
swiper.virtualSize = (slideSize + params.spaceBetween) * slidesNumberEvenToRows;
swiper.virtualSize = Math.ceil(swiper.virtualSize / params.slidesPerColumn) - params.spaceBetween;
if (swiper.isHorizontal()) $wrapperEl.css({ width: `${swiper.virtualSize + params.spaceBetween}px` });
else $wrapperEl.css({ height: `${swiper.virtualSize + params.spaceBetween}px` });
if (params.centeredSlides) {
newSlidesGrid = [];
for (let i = 0; i < snapGrid.length; i += 1) {
if (snapGrid[i] < swiper.virtualSize + snapGrid[0]) newSlidesGrid.push(snapGrid[i]);
}
snapGrid = newSlidesGrid;
}
}
// Remove last grid elements depending on width
if (!params.centeredSlides) {
newSlidesGrid = [];
for (let i = 0; i < snapGrid.length; i += 1) {
if (snapGrid[i] <= swiper.virtualSize - swiperSize) {
newSlidesGrid.push(snapGrid[i]);
}
}
snapGrid = newSlidesGrid;
if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
snapGrid.push(swiper.virtualSize - swiperSize);
}
}
if (snapGrid.length === 0) snapGrid = [0];
if (params.spaceBetween !== 0) {
if (swiper.isHorizontal()) {
if (rtl) slides.css({ marginLeft: `${spaceBetween}px` });
else slides.css({ marginRight: `${spaceBetween}px` });
} else slides.css({ marginBottom: `${spaceBetween}px` });
}
Utils.extend(swiper, {
slides,
snapGrid,
slidesGrid,
slidesSizesGrid,
});
if (slidesLength !== previousSlidesLength) {
swiper.emit('slidesLengthChange');
}
if (snapGrid.length !== previousSnapGridLength) {
swiper.emit('snapGridLengthChange');
}
if (slidesGrid.length !== previousSlidesGridLength) {
swiper.emit('slidesGridLengthChange');
}
if (params.watchSlidesProgress || params.watchSlidesVisibility) {
swiper.updateSlidesOffset();
}
};
var updateAutoHeight = function () {
const swiper = this;
const activeSlides = [];
let newHeight = 0;
let i;
// Find slides currently in view
if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {
for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
const index = swiper.activeIndex + i;
if (index > swiper.slides.length) break;
activeSlides.push(swiper.slides.eq(index)[0]);
}
} else {
activeSlides.push(swiper.slides.eq(swiper.activeIndex)[0]);
}
// Find new height from highest slide in view
for (i = 0; i < activeSlides.length; i += 1) {
if (typeof activeSlides[i] !== 'undefined') {
const height = activeSlides[i].offsetHeight;
newHeight = height > newHeight ? height : newHeight;
}
}
// Update Height
if (newHeight) swiper.$wrapperEl.css('height', `${newHeight}px`);
};
var updateSlidesOffset = function () {
const swiper = this;
const slides = swiper.slides;
for (let i = 0; i < slides.length; i += 1) {
slides[i].swiperSlideOffset = swiper.isHorizontal() ? slides[i].offsetLeft : slides[i].offsetTop;
}
};
var updateSlidesProgress = function (translate = this.translate || 0) {
const swiper = this;
const params = swiper.params;
const { slides, rtl } = swiper;
if (slides.length === 0) return;
if (typeof slides[0].swiperSlideOffset === 'undefined') swiper.updateSlidesOffset();
let offsetCenter = -translate;
if (rtl) offsetCenter = translate;
// Visible Slides
slides.removeClass(params.slideVisibleClass);
for (let i = 0; i < slides.length; i += 1) {
const slide = slides[i];
const slideProgress =
(
(offsetCenter + (params.centeredSlides ? swiper.minTranslate() : 0)) - slide.swiperSlideOffset
) / (slide.swiperSlideSize + params.spaceBetween);
if (params.watchSlidesVisibility) {
const slideBefore = -(offsetCenter - slide.swiperSlideOffset);
const slideAfter = slideBefore + swiper.slidesSizesGrid[i];
const isVisible =
(slideBefore >= 0 && slideBefore < swiper.size) ||
(slideAfter > 0 && slideAfter <= swiper.size) ||
(slideBefore <= 0 && slideAfter >= swiper.size);
if (isVisible) {
slides.eq(i).addClass(params.slideVisibleClass);
}
}
slide.progress = rtl ? -slideProgress : slideProgress;
}
};
var updateProgress = function (translate = this.translate || 0) {
const swiper = this;
const params = swiper.params;
const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
let { progress, isBeginning, isEnd } = swiper;
const wasBeginning = isBeginning;
const wasEnd = isEnd;
if (translatesDiff === 0) {
progress = 0;
isBeginning = true;
isEnd = true;
} else {
progress = (translate - swiper.minTranslate()) / (translatesDiff);
isBeginning = progress <= 0;
isEnd = progress >= 1;
}
Utils.extend(swiper, {
progress,
isBeginning,
isEnd,
});
if (params.watchSlidesProgress || params.watchSlidesVisibility) swiper.updateSlidesProgress(translate);
if (isBeginning && !wasBeginning) {
swiper.emit('reachBeginning toEdge');
}
if (isEnd && !wasEnd) {
swiper.emit('reachEnd toEdge');
}
if ((wasBeginning && !isBeginning) || (wasEnd && !isEnd)) {
swiper.emit('fromEdge');
}
swiper.emit('progress', progress);
};
var updateSlidesClasses = function () {
const swiper = this;
const { slides, params, $wrapperEl, activeIndex, realIndex } = swiper;
const isVirtual = swiper.virtual && params.virtual.enabled;
slides.removeClass(`${params.slideActiveClass} ${params.slideNextClass} ${params.slidePrevClass} ${params.slideDuplicateActiveClass} ${params.slideDuplicateNextClass} ${params.slideDuplicatePrevClass}`);
let activeSlide;
if (isVirtual) {
activeSlide = swiper.$wrapperEl.find(`.${params.slideClass}[data-swiper-slide-index="${activeIndex}"]`);
} else {
activeSlide = slides.eq(activeIndex);
}
// Active classes
activeSlide.addClass(params.slideActiveClass);
if (params.loop) {
// Duplicate to all looped slides
if (activeSlide.hasClass(params.slideDuplicateClass)) {
$wrapperEl
.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${realIndex}"]`)
.addClass(params.slideDuplicateActiveClass);
} else {
$wrapperEl
.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${realIndex}"]`)
.addClass(params.slideDuplicateActiveClass);
}
}
// Next Slide
let nextSlide = activeSlide.nextAll(`.${params.slideClass}`).eq(0).addClass(params.slideNextClass);
if (params.loop && nextSlide.length === 0) {
nextSlide = slides.eq(0);
nextSlide.addClass(params.slideNextClass);
}
// Prev Slide
let prevSlide = activeSlide.prevAll(`.${params.slideClass}`).eq(0).addClass(params.slidePrevClass);
if (params.loop && prevSlide.length === 0) {
prevSlide = slides.eq(-1);
prevSlide.addClass(params.slidePrevClass);
}
if (params.loop) {
// Duplicate to all looped slides
if (nextSlide.hasClass(params.slideDuplicateClass)) {
$wrapperEl
.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${nextSlide.attr('data-swiper-slide-index')}"]`)
.addClass(params.slideDuplicateNextClass);
} else {
$wrapperEl
.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${nextSlide.attr('data-swiper-slide-index')}"]`)
.addClass(params.slideDuplicateNextClass);
}
if (prevSlide.hasClass(params.slideDuplicateClass)) {
$wrapperEl
.children(`.${params.slideClass}:not(.${params.slideDuplicateClass})[data-swiper-slide-index="${prevSlide.attr('data-swiper-slide-index')}"]`)
.addClass(params.slideDuplicatePrevClass);
} else {
$wrapperEl
.children(`.${params.slideClass}.${params.slideDuplicateClass}[data-swiper-slide-index="${prevSlide.attr('data-swiper-slide-index')}"]`)
.addClass(params.slideDuplicatePrevClass);
}
}
};
var updateActiveIndex = function (newActiveIndex) {
const swiper = this;
const translate = swiper.rtl ? swiper.translate : -swiper.translate;
const { slidesGrid, snapGrid, params, activeIndex: previousIndex, realIndex: previousRealIndex, snapIndex: previousSnapIndex } = swiper;
let activeIndex = newActiveIndex;
let snapIndex;
if (typeof activeIndex === 'undefined') {
for (let i = 0; i < slidesGrid.length; i += 1) {
if (typeof slidesGrid[i + 1] !== 'undefined') {
if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1] - ((slidesGrid[i + 1] - slidesGrid[i]) / 2)) {
activeIndex = i;
} else if (translate >= slidesGrid[i] && translate < slidesGrid[i + 1]) {
activeIndex = i + 1;
}
} else if (translate >= slidesGrid[i]) {
activeIndex = i;
}
}
// Normalize slideIndex
if (params.normalizeSlideIndex) {
if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;
}
}
if (snapGrid.indexOf(translate) >= 0) {
snapIndex = snapGrid.indexOf(translate);
} else {
snapIndex = Math.floor(activeIndex / params.slidesPerGroup);
}
if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
if (activeIndex === previousIndex) {
if (snapIndex !== previousSnapIndex) {
swiper.snapIndex = snapIndex;
swiper.emit('snapIndexChange');
}
return;
}
// Get real index
const realIndex = parseInt(swiper.slides.eq(activeIndex).attr('data-swiper-slide-index') || activeIndex, 10);
Utils.extend(swiper, {
snapIndex,
realIndex,
previousIndex,
activeIndex,
});
swiper.emit('activeIndexChange');
swiper.emit('snapIndexChange');
if (previousRealIndex !== realIndex) {
swiper.emit('realIndexChange');
}
swiper.emit('slideChange');
};
var updateClickedSlide = function (e) {
const swiper = this;
const params = swiper.params;
const slide = $(e.target).closest(`.${params.slideClass}`)[0];
let slideFound = false;
if (slide) {
for (let i = 0; i < swiper.slides.length; i += 1) {
if (swiper.slides[i] === slide) slideFound = true;
}
}
if (slide && slideFound) {
swiper.clickedSlide = slide;
if (swiper.virtual && swiper.params.virtual.enabled) {
swiper.clickedIndex = parseInt($(slide).attr('data-swiper-slide-index'), 10);
} else {
swiper.clickedIndex = $(slide).index();
}
} else {
swiper.clickedSlide = undefined;
swiper.clickedIndex = undefined;
return;
}
if (params.slideToClickedSlide && swiper.clickedIndex !== undefined && swiper.clickedIndex !== swiper.activeIndex) {
swiper.slideToClickedSlide();
}
};
var update = {
updateSize,
updateSlides,
updateAutoHeight,
updateSlidesOffset,
updateSlidesProgress,
updateProgress,
updateSlidesClasses,
updateActiveIndex,
updateClickedSlide,
};
var getTranslate = function (axis = this.isHorizontal() ? 'x' : 'y') {
const swiper = this;
const { params, rtl, translate, $wrapperEl } = swiper;
if (params.virtualTranslate) {
return rtl ? -translate : translate;
}
let currentTranslate = Utils.getTranslate($wrapperEl[0], axis);
if (rtl) currentTranslate = -currentTranslate;
return currentTranslate || 0;
};
var setTranslate = function (translate, byController) {
const swiper = this;
const { rtl, params, $wrapperEl, progress } = swiper;
let x = 0;
let y = 0;
const z = 0;
if (swiper.isHorizontal()) {
x = rtl ? -translate : translate;
} else {
y = translate;
}
if (params.roundLengths) {
x = Math.floor(x);
y = Math.floor(y);
}
if (!params.virtualTranslate) {
if (Support$1.transforms3d) $wrapperEl.transform(`translate3d(${x}px, ${y}px, ${z}px)`);
else $wrapperEl.transform(`translate(${x}px, ${y}px)`);
}
swiper.translate = swiper.isHorizontal() ? x : y;
// Check if we need to update progress
let newProgress;
const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
if (translatesDiff === 0) {
newProgress = 0;
} else {
newProgress = (translate - swiper.minTranslate()) / (translatesDiff);
}
if (newProgress !== progress) {
swiper.updateProgress(translate);
}
swiper.emit('setTranslate', swiper.translate, byController);
};
var minTranslate = function () {
return (-this.snapGrid[0]);
};
var maxTranslate = function () {
return (-this.snapGrid[this.snapGrid.length - 1]);
};
var translate = {
getTranslate,
setTranslate,
minTranslate,
maxTranslate,
};
var setTransition = function (duration, byController) {
const swiper = this;
swiper.$wrapperEl.transition(duration);
swiper.emit('setTransition', duration, byController);
};
var transitionStart = function (runCallbacks = true) {
const swiper = this;
const { activeIndex, params, previousIndex } = swiper;
if (params.autoHeight) {
swiper.updateAutoHeight();
}
swiper.emit('transitionStart');
if (!runCallbacks) return;
if (activeIndex !== previousIndex) {
swiper.emit('slideChangeTransitionStart');
if (activeIndex > previousIndex) {
swiper.emit('slideNextTransitionStart');
} else {
swiper.emit('slidePrevTransitionStart');
}
}
};
var transitionEnd = function (runCallbacks = true) {
const swiper = this;
const { activeIndex, previousIndex } = swiper;
swiper.animating = false;
swiper.setTransition(0);
swiper.emit('transitionEnd');
if (runCallbacks) {
if (activeIndex !== previousIndex) {
swiper.emit('slideChangeTransitionEnd');
if (activeIndex > previousIndex) {
swiper.emit('slideNextTransitionEnd');
} else {
swiper.emit('slidePrevTransitionEnd');
}
}
}
};
var transition = {
setTransition,
transitionStart,
transitionEnd,
};
const Browser = (function Browser() {
function isIE9() {
// create temporary DIV
const div = document.createElement('div');
// add content to tmp DIV which is wrapped into the IE HTML conditional statement
div.innerHTML = '<!--[if lte IE 9]><i></i><![endif]-->';
// return true / false value based on what will browser render
return div.getElementsByTagName('i').length === 1;
}
function isSafari() {
const ua = window.navigator.userAgent.toLowerCase();
return (ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0 && ua.indexOf('android') < 0);
}
return {
isSafari: isSafari(),
isUiWebView: /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i.test(window.navigator.userAgent),
ie: window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
ieTouch: (window.navigator.msPointerEnabled && window.navigator.msMaxTouchPoints > 1) ||
(window.navigator.pointerEnabled && window.navigator.maxTouchPoints > 1),
lteIE9: isIE9(),
};
}());
var slideTo = function (index = 0, speed = this.params.speed, runCallbacks = true, internal) {
const swiper = this;
let slideIndex = index;
if (slideIndex < 0) slideIndex = 0;
const { params, snapGrid, slidesGrid, previousIndex, activeIndex, rtl, $wrapperEl } = swiper;
let snapIndex = Math.floor(slideIndex / params.slidesPerGroup);
if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
if ((activeIndex || params.initialSlide || 0) === (previousIndex || 0) && runCallbacks) {
swiper.emit('beforeSlideChangeStart');
}
const translate = -snapGrid[snapIndex];
// Update progress
swiper.updateProgress(translate);
// Normalize slideIndex
if (params.normalizeSlideIndex) {
for (let i = 0; i < slidesGrid.length; i += 1) {
if (-Math.floor(translate * 100) >= Math.floor(slidesGrid[i] * 100)) {
slideIndex = i;
}
}
}
// Directions locks
if (!swiper.allowSlideNext && translate < swiper.translate && translate < swiper.minTranslate()) {
return false;
}
if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
if ((activeIndex || 0) !== slideIndex) return false;
}
// Update Index
if ((rtl && -translate === swiper.translate) || (!rtl && translate === swiper.translate)) {
swiper.updateActiveIndex(slideIndex);
// Update Height
if (params.autoHeight) {
swiper.updateAutoHeight();
}
swiper.updateSlidesClasses();
if (params.effect !== 'slide') {
swiper.setTranslate(translate);
}
return false;
}
if (speed === 0 || Browser.lteIE9) {
swiper.setTransition(0);
swiper.setTranslate(translate);
swiper.updateActiveIndex(slideIndex);
swiper.updateSlidesClasses();
swiper.emit('beforeTransitionStart', speed, internal);
swiper.transitionStart(runCallbacks);
swiper.transitionEnd(runCallbacks);
} else {
swiper.setTransition(speed);
swiper.setTranslate(translate);
swiper.updateActiveIndex(slideIndex);
swiper.updateSlidesClasses();
swiper.emit('beforeTransitionStart', speed, internal);
swiper.transitionStart(runCallbacks);
if (!swiper.animating) {
swiper.animating = true;
$wrapperEl.transitionEnd(() => {
if (!swiper || swiper.destroyed) return;
swiper.transitionEnd(runCallbacks);
});
}
}
return true;
};
/* eslint no-unused-vars: "off" */
var slideNext = function (speed = this.params.speed, runCallbacks = true, internal) {
const swiper = this;
const { params, animating } = swiper;
if (params.loop) {
if (animating) return false;
swiper.loopFix();
// eslint-disable-next-line
swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
return swiper.slideTo(swiper.activeIndex + params.slidesPerGroup, speed, runCallbacks, internal);
}
return swiper.slideTo(swiper.activeIndex + params.slidesPerGroup, speed, runCallbacks, internal);
};
/* eslint no-unused-vars: "off" */
var slidePrev = function (speed = this.params.speed, runCallbacks = true, internal) {
const swiper = this;
const { params, animating } = swiper;
if (params.loop) {
if (animating) return false;
swiper.loopFix();
// eslint-disable-next-line
swiper._clientLeft = swiper.$wrapperEl[0].clientLeft;
return swiper.slideTo(swiper.activeIndex - 1, speed, runCallbacks, internal);
}
return swiper.slideTo(swiper.activeIndex - 1, speed, runCallbacks, internal);
};
/* eslint no-unused-vars: "off" */
var slideReset = function (speed = this.params.speed, runCallbacks = true, internal) {
const swiper = this;
return swiper.slideTo(swiper.activeIndex, speed, runCallbacks, internal);
};
var slideToClickedSlide = function () {
const swiper = this;
const { params, $wrapperEl } = swiper;
const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
let slideToIndex = swiper.clickedIndex;
let realIndex;
if (params.loop) {
if (swiper.animating) return;
realIndex = parseInt($(swiper.clickedSlide).attr('data-swiper-slide-index'), 10);
if (params.centeredSlides) {
if (
(slideToIndex < swiper.loopedSlides - (slidesPerView / 2)) ||
(slideToIndex > (swiper.slides.length - swiper.loopedSlides) + (slidesPerView / 2))
) {
swiper.loopFix();
slideToIndex = $wrapperEl
.children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`)
.eq(0)
.index();
Utils.nextTick(() => {
swiper.slideTo(slideToIndex);
});
} else {
swiper.slideTo(slideToIndex);
}
} else if (slideToIndex > swiper.slides.length - slidesPerView) {
swiper.loopFix();
slideToIndex = $wrapperEl
.children(`.${params.slideClass}[data-swiper-slide-index="${realIndex}"]:not(.${params.slideDuplicateClass})`)
.eq(0)
.index();
Utils.nextTick(() => {
swiper.slideTo(slideToIndex);
});
} else {
swiper.slideTo(slideToIndex);
}
} else {
swiper.slideTo(slideToIndex);
}
};
var slide = {
slideTo,
slideNext,
slidePrev,
slideReset,
slideToClickedSlide,
};
var loopCreate = function () {
const swiper = this;
const { params, $wrapperEl } = swiper;
// Remove duplicated slides
$wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}`).remove();
let slides = $wrapperEl.children(`.${params.slideClass}`);
if (params.loopFillGroupWithBlank) {
const blankSlidesNum = params.slidesPerGroup - (slides.length % params.slidesPerGroup);
if (blankSlidesNum !== params.slidesPerGroup) {
for (let i = 0; i < blankSlidesNum; i += 1) {
const blankNode = $(document.createElement('div')).addClass(`${params.slideClass} ${params.slideBlankClass}`);
$wrapperEl.append(blankNode);
}
slides = $wrapperEl.children(`.${params.slideClass}`);
}
}
if (params.slidesPerView === 'auto' && !params.loopedSlides) params.loopedSlides = slides.length;
swiper.loopedSlides = parseInt(params.loopedSlides || params.slidesPerView, 10);
swiper.loopedSlides += params.loopAdditionalSlides;
if (swiper.loopedSlides > slides.length) {
swiper.loopedSlides = slides.length;
}
const prependSlides = [];
const appendSlides = [];
slides.each((index, el) => {
const slide = $(el);
if (index < swiper.loopedSlides) appendSlides.push(el);
if (index < slides.length && index >= slides.length - swiper.loopedSlides) prependSlides.push(el);
slide.attr('data-swiper-slide-index', index);
});
for (let i = 0; i < appendSlides.length; i += 1) {
$wrapperEl.append($(appendSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
}
for (let i = prependSlides.length - 1; i >= 0; i -= 1) {
$wrapperEl.prepend($(prependSlides[i].cloneNode(true)).addClass(params.slideDuplicateClass));
}
};
var loopFix = function () {
const swiper = this;
const { params, activeIndex, slides, loopedSlides, allowSlidePrev, allowSlideNext } = swiper;
let newIndex;
swiper.allowSlidePrev = true;
swiper.allowSlideNext = true;
// Fix For Negative Oversliding
if (activeIndex < loopedSlides) {
newIndex = (slides.length - (loopedSlides * 3)) + activeIndex;
newIndex += loopedSlides;
swiper.slideTo(newIndex, 0, false, true);
} else if ((params.slidesPerView === 'auto' && activeIndex >= loopedSlides * 2) || (activeIndex > slides.length - (params.slidesPerView * 2))) {
// Fix For Positive Oversliding
newIndex = -slides.length + activeIndex + loopedSlides;
newIndex += loopedSlides;
swiper.slideTo(newIndex, 0, false, true);
}
swiper.allowSlidePrev = allowSlidePrev;
swiper.allowSlideNext = allowSlideNext;
};
var loopDestroy = function () {
const swiper = this;
const { $wrapperEl, params, slides } = swiper;
$wrapperEl.children(`.${params.slideClass}.${params.slideDuplicateClass}`).remove();
slides.removeAttr('data-swiper-slide-index');
};
var loop = {
loopCreate,
loopFix,
loopDestroy,
};
var setGrabCursor = function (moving) {
const swiper = this;
if (Support$1.touch || !swiper.params.simulateTouch) return;
const el = swiper.el;
el.style.cursor = 'move';
el.style.cursor = moving ? '-webkit-grabbing' : '-webkit-grab';
el.style.cursor = moving ? '-moz-grabbin' : '-moz-grab';
el.style.cursor = moving ? 'grabbing' : 'grab';
};
var unsetGrabCursor = function () {
const swiper = this;
if (Support$1.touch) return;
swiper.el.style.cursor = '';
};
var grabCursor = {
setGrabCursor,
unsetGrabCursor,
};
var appendSlide = function (slides) {
const swiper = this;
const { $wrapperEl, params } = swiper;
if (params.loop) {
swiper.loopDestroy();
}
if (typeof slides === 'object' && 'length' in slides) {
for (let i = 0; i < slides.length; i += 1) {
if (slides[i]) $wrapperEl.append(slides[i]);
}
} else {
$wrapperEl.append(slides);
}
if (params.loop) {
swiper.loopCreate();
}
if (!(params.observer && Support$1.observer)) {
swiper.update();
}
};
var prependSlide = function (slides) {
const swiper = this;
const { params, $wrapperEl, activeIndex } = swiper;
if (params.loop) {
swiper.loopDestroy();
}
let newActiveIndex = activeIndex + 1;
if (typeof slides === 'object' && 'length' in slides) {
for (let i = 0; i < slides.length; i += 1) {
if (slides[i]) $wrapperEl.prepend(slides[i]);
}
newActiveIndex = activeIndex + slides.length;
} else {
$wrapperEl.prepend(slides);
}
if (params.loop) {
swiper.loopCreate();
}
if (!(params.observer && Support$1.observer)) {
swiper.update();
}
swiper.slideTo(newActiveIndex, 0, false);
};
var removeSlide = function (slidesIndexes) {
const swiper = this;
const { params, $wrapperEl, activeIndex } = swiper;
if (params.loop) {
swiper.loopDestroy();
swiper.slides = $wrapperEl.children(`.${params.slideClass}`);
}
let newActiveIndex = activeIndex;
let indexToRemove;
if (typeof slidesIndexes === 'object' && 'length' in slidesIndexes) {
for (let i = 0; i < slidesIndexes.length; i += 1) {
indexToRemove = slidesIndexes[i];
if (swiper.slides[indexToRemove]) swiper.slides.eq(indexToRemove).remove();
if (indexToRemove < newActiveIndex) newActiveIndex -= 1;
}
newActiveIndex = Math.max(newActiveIndex, 0);
} else {
indexToRemove = slidesIndexes;
if (swiper.slides[indexToRemove]) swiper.slides.eq(indexToRemove).remove();
if (indexToRemove < newActiveIndex) newActiveIndex -= 1;
newActiveIndex = Math.max(newActiveIndex, 0);
}
if (params.loop) {
swiper.loopCreate();
}
if (!(params.observer && Support$1.observer)) {
swiper.update();
}
if (params.loop) {
swiper.slideTo(newActiveIndex + swiper.loopedSlides, 0, false);
} else {
swiper.slideTo(newActiveIndex, 0, false);
}
};
var removeAllSlides = function () {
const swiper = this;
const slidesIndexes = [];
for (let i = 0; i < swiper.slides.length; i += 1) {
slidesIndexes.push(i);
}
swiper.removeSlide(slidesIndexes);
};
var manipulation = {
appendSlide,
prependSlide,
removeSlide,
removeAllSlides,
};
var onTouchStart = function (event) {
const swiper = this;
const data = swiper.touchEventsData;
const { params, touches } = swiper;
let e = event;
if (e.originalEvent) e = e.originalEvent;
data.isTouchEvent = e.type === 'touchstart';
if (!data.isTouchEvent && 'which' in e && e.which === 3) return;
if (data.isTouched && data.isMoved) return;
if (params.noSwiping && $(e.target).closest(`.${params.noSwipingClass}`)[0]) {
swiper.allowClick = true;
return;
}
if (params.swipeHandler) {
if (!$(e).closest(params.swipeHandler)[0]) return;
}
touches.currentX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touches.currentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
const startX = touches.currentX;
const startY = touches.currentY;
// Do NOT start if iOS edge swipe is detected. Otherwise iOS app (UIWebView) cannot swipe-to-go-back anymore
if (
Device.ios &&
!Device.cordova &&
params.iOSEdgeSwipeDetection &&
(startX <= params.iOSEdgeSwipeThreshold) &&
(startX >= window.screen.width - params.iOSEdgeSwipeThreshold)
) {
return;
}
Utils.extend(data, {
isTouched: true,
isMoved: false,
allowTouchCallbacks: true,
isScrolling: undefined,
startMoving: undefined,
});
touches.startX = startX;
touches.startY = startY;
data.touchStartTime = Utils.now();
swiper.allowClick = true;
swiper.updateSize();
swiper.swipeDirection = undefined;
if (params.threshold > 0) data.allowThresholdMove = false;
if (e.type !== 'touchstart') {
let preventDefault = true;
if ($(e.target).is(data.formElements)) preventDefault = false;
if (document.activeElement && $(document.activeElement).is(data.formElements)) {
document.activeElement.blur();
}
if (preventDefault && swiper.allowTouchMove) {
e.preventDefault();
}
}
swiper.emit('touchStart', e);
};
var onTouchMove = function (event) {
const swiper = this;
const data = swiper.touchEventsData;
const { params, touches, rtl } = swiper;
let e = event;
if (e.originalEvent) e = e.originalEvent;
if (data.isTouchEvent && e.type === 'mousemove') return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (e.preventedByNestedSwiper) {
touches.startX = pageX;
touches.startY = pageY;
return;
}
if (!swiper.allowTouchMove) {
// isMoved = true;
swiper.allowClick = false;
if (data.isTouched) {
Utils.extend(touches, {
startX: pageX,
startY: pageY,
currentX: pageX,
currentY: pageY,
});
data.touchStartTime = Utils.now();
}
return;
}
if (data.isTouchEvent && params.touchReleaseOnEdges && !params.loop) {
if (swiper.isVertical()) {
// Vertical
if (
(pageY < touches.startY && swiper.translate <= swiper.maxTranslate()) ||
(pageY > touches.startY && swiper.translate >= swiper.minTranslate())
) {
data.isTouched = false;
data.isMoved = false;
return;
}
} else if (
(pageX < touches.startX && swiper.translate <= swiper.maxTranslate()) ||
(pageX > touches.startX && swiper.translate >= swiper.minTranslate())
) {
return;
}
}
if (data.isTouchEvent && document.activeElement) {
if (e.target === document.activeElement && $(e.target).is(data.formElements)) {
data.isMoved = true;
swiper.allowClick = false;
return;
}
}
if (data.allowTouchCallbacks) {
swiper.emit('touchMove', e);
}
if (e.targetTouches && e.targetTouches.length > 1) return;
touches.currentX = pageX;
touches.currentY = pageY;
const diffX = touches.currentX - touches.startX;
const diffY = touches.currentY - touches.startY;
if (typeof data.isScrolling === 'undefined') {
let touchAngle;
if ((swiper.isHorizontal() && touches.currentY === touches.startY) || (swiper.isVertical() && touches.currentX === touches.startX)) {
data.isScrolling = false;
} else {
// eslint-disable-next-line
if ((diffX * diffX) + (diffY * diffY) >= 25) {
touchAngle = (Math.atan2(Math.abs(diffY), Math.abs(diffX)) * 180) / Math.PI;
data.isScrolling = swiper.isHorizontal() ? touchAngle > params.touchAngle : (90 - touchAngle > params.touchAngle);
}
}
}
if (data.isScrolling) {
swiper.emit('touchMoveOpposite', e);
}
if (typeof startMoving === 'undefined') {
if (touches.currentX !== touches.startX || touches.currentY !== touches.startY) {
data.startMoving = true;
}
}
if (!data.isTouched) return;
if (data.isScrolling) {
data.isTouched = false;
return;
}
if (!data.startMoving) {
return;
}
swiper.allowClick = false;
e.preventDefault();
if (params.touchMoveStopPropagation && !params.nested) {
e.stopPropagation();
}
if (!data.isMoved) {
if (params.loop) {
swiper.loopFix();
}
data.startTranslate = swiper.getTranslate();
swiper.setTransition(0);
if (swiper.animating) {
swiper.$wrapperEl.trigger('webkitTransitionEnd transitionend');
}
data.allowMomentumBounce = false;
// Grab Cursor
if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
swiper.setGrabCursor(true);
}
swiper.emit('sliderFirstMove', e);
}
swiper.emit('sliderMove', e);
data.isMoved = true;
let diff = swiper.isHorizontal() ? diffX : diffY;
touches.diff = diff;
diff *= params.touchRatio;
if (rtl) diff = -diff;
swiper.swipeDirection = diff > 0 ? 'prev' : 'next';
data.currentTranslate = diff + data.startTranslate;
let disableParentSwiper = true;
let resistanceRatio = params.resistanceRatio;
if (params.touchReleaseOnEdges) {
resistanceRatio = 0;
}
if ((diff > 0 && data.currentTranslate > swiper.minTranslate())) {
disableParentSwiper = false;
if (params.resistance) data.currentTranslate = (swiper.minTranslate() - 1) + ((-swiper.minTranslate() + data.startTranslate + diff) ** resistanceRatio);
} else if (diff < 0 && data.currentTranslate < swiper.maxTranslate()) {
disableParentSwiper = false;
if (params.resistance) data.currentTranslate = (swiper.maxTranslate() + 1) - ((swiper.maxTranslate() - data.startTranslate - diff) ** resistanceRatio);
}
if (disableParentSwiper) {
e.preventedByNestedSwiper = true;
}
// Directions locks
if (!swiper.allowSlideNext && swiper.swipeDirection === 'next' && data.currentTranslate < data.startTranslate) {
data.currentTranslate = data.startTranslate;
}
if (!swiper.allowSlidePrev && swiper.swipeDirection === 'prev' && data.currentTranslate > data.startTranslate) {
data.currentTranslate = data.startTranslate;
}
// Threshold
if (params.threshold > 0) {
if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
if (!data.allowThresholdMove) {
data.allowThresholdMove = true;
touches.startX = touches.currentX;
touches.startY = touches.currentY;
data.currentTranslate = data.startTranslate;
touches.diff = swiper.isHorizontal() ? touches.currentX - touches.startX : touches.currentY - touches.startY;
return;
}
} else {
data.currentTranslate = data.startTranslate;
return;
}
}
if (!params.followFinger) return;
// Update active index in free mode
if (params.freeMode || params.watchSlidesProgress || params.watchSlidesVisibility) {
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
}
if (params.freeMode) {
// Velocity
if (data.velocities.length === 0) {
data.velocities.push({
position: touches[swiper.isHorizontal() ? 'startX' : 'startY'],
time: data.touchStartTime,
});
}
data.velocities.push({
position: touches[swiper.isHorizontal() ? 'currentX' : 'currentY'],
time: Utils.now(),
});
}
// Update progress
swiper.updateProgress(data.currentTranslate);
// Update translate
swiper.setTranslate(data.currentTranslate);
};
var onTouchEnd = function (event) {
const swiper = this;
const data = swiper.touchEventsData;
const { params, touches, rtl, $wrapperEl, slidesGrid, snapGrid } = swiper;
let e = event;
if (e.originalEvent) e = e.originalEvent;
if (data.allowTouchCallbacks) {
swiper.emit('touchEnd', e);
}
data.allowTouchCallbacks = false;
if (!data.isTouched) return;
// Return Grab Cursor
if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
swiper.setGrabCursor(false);
}
// Time diff
const touchEndTime = Utils.now();
const timeDiff = touchEndTime - data.touchStartTime;
// Tap, doubleTap, Click
if (swiper.allowClick) {
swiper.updateClickedSlide(e);
swiper.emit('tap', e);
if (timeDiff < 300 && (touchEndTime - data.lastClickTime) > 300) {
if (data.clickTimeout) clearTimeout(data.clickTimeout);
data.clickTimeout = Utils.nextTick(() => {
if (!swiper || swiper.destroyed) return;
swiper.emit('click', e);
}, 300);
}
if (timeDiff < 300 && (touchEndTime - data.lastClickTime) < 300) {
if (data.clickTimeout) clearTimeout(data.clickTimeout);
swiper.emit('doubleTap', e);
}
}
data.lastClickTime = Utils.now();
Utils.nextTick(() => {
if (!swiper.destroyed) swiper.allowClick = true;
});
if (!data.isTouched || !data.isMoved || !swiper.swipeDirection || touches.diff === 0 || data.currentTranslate === data.startTranslate) {
data.isTouched = false;
data.isMoved = false;
return;
}
data.isTouched = false;
data.isMoved = false;
let currentPos;
if (params.followFinger) {
currentPos = rtl ? swiper.translate : -swiper.translate;
} else {
currentPos = -data.currentTranslate;
}
if (params.freeMode) {
if (currentPos < -swiper.minTranslate()) {
swiper.slideTo(swiper.activeIndex);
return;
} else if (currentPos > -swiper.maxTranslate()) {
if (swiper.slides.length < snapGrid.length) {
swiper.slideTo(snapGrid.length - 1);
} else {
swiper.slideTo(swiper.slides.length - 1);
}
return;
}
if (params.freeModeMomentum) {
if (data.velocities.length > 1) {
const lastMoveEvent = data.velocities.pop();
const velocityEvent = data.velocities.pop();
const distance = lastMoveEvent.position - velocityEvent.position;
const time = lastMoveEvent.time - velocityEvent.time;
swiper.velocity = distance / time;
swiper.velocity /= 2;
if (Math.abs(swiper.velocity) < params.freeModeMinimumVelocity) {
swiper.velocity = 0;
}
// this implies that the user stopped moving a finger then released.
// There would be no events with distance zero, so the last event is stale.
if (time > 150 || (Utils.now() - lastMoveEvent.time) > 300) {
swiper.velocity = 0;
}
} else {
swiper.velocity = 0;
}
swiper.velocity *= params.freeModeMomentumVelocityRatio;
data.velocities.length = 0;
let momentumDuration = 1000 * params.freeModeMomentumRatio;
const momentumDistance = swiper.velocity * momentumDuration;
let newPosition = swiper.translate + momentumDistance;
if (rtl) newPosition = -newPosition;
let doBounce = false;
let afterBouncePosition;
const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeModeMomentumBounceRatio;
if (newPosition < swiper.maxTranslate()) {
if (params.freeModeMomentumBounce) {
if (newPosition + swiper.maxTranslate() < -bounceAmount) {
newPosition = swiper.maxTranslate() - bounceAmount;
}
afterBouncePosition = swiper.maxTranslate();
doBounce = true;
data.allowMomentumBounce = true;
} else {
newPosition = swiper.maxTranslate();
}
} else if (newPosition > swiper.minTranslate()) {
if (params.freeModeMomentumBounce) {
if (newPosition - swiper.minTranslate() > bounceAmount) {
newPosition = swiper.minTranslate() + bounceAmount;
}
afterBouncePosition = swiper.minTranslate();
doBounce = true;
data.allowMomentumBounce = true;
} else {
newPosition = swiper.minTranslate();
}
} else if (params.freeModeSticky) {
let nextSlide;
for (let j = 0; j < snapGrid.length; j += 1) {
if (snapGrid[j] > -newPosition) {
nextSlide = j;
break;
}
}
if (Math.abs(snapGrid[nextSlide] - newPosition) < Math.abs(snapGrid[nextSlide - 1] - newPosition) || swiper.swipeDirection === 'next') {
newPosition = snapGrid[nextSlide];
} else {
newPosition = snapGrid[nextSlide - 1];
}
newPosition = -newPosition;
}
// Fix duration
if (swiper.velocity !== 0) {
if (rtl) {
momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity);
} else {
momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity);
}
} else if (params.freeModeSticky) {
swiper.slideReset();
return;
}
if (params.freeModeMomentumBounce && doBounce) {
swiper.updateProgress(afterBouncePosition);
swiper.setTransition(momentumDuration);
swiper.setTranslate(newPosition);
swiper.transitionStart();
swiper.animating = true;
$wrapperEl.transitionEnd(() => {
if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return;
swiper.emit('momentumBounce');
swiper.setTransition(params.speed);
swiper.setTranslate(afterBouncePosition);
$wrapperEl.transitionEnd(() => {
if (!swiper || swiper.destroyed) return;
swiper.transitionEnd();
});
});
} else if (swiper.velocity) {
swiper.updateProgress(newPosition);
swiper.setTransition(momentumDuration);
swiper.setTranslate(newPosition);
swiper.transitionStart();
if (!swiper.animating) {
swiper.animating = true;
$wrapperEl.transitionEnd(() => {
if (!swiper || swiper.destroyed) return;
swiper.transitionEnd();
});
}
} else {
swiper.updateProgress(newPosition);
}
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
}
if (!params.freeModeMomentum || timeDiff >= params.longSwipesMs) {
swiper.updateProgress();
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
}
return;
}
// Find current slide
let stopIndex = 0;
let groupSize = swiper.slidesSizesGrid[0];
for (let i = 0; i < slidesGrid.length; i += params.slidesPerGroup) {
if (typeof slidesGrid[i + params.slidesPerGroup] !== 'undefined') {
if (currentPos >= slidesGrid[i] && currentPos < slidesGrid[i + params.slidesPerGroup]) {
stopIndex = i;
groupSize = slidesGrid[i + params.slidesPerGroup] - slidesGrid[i];
}
} else if (currentPos >= slidesGrid[i]) {
stopIndex = i;
groupSize = slidesGrid[slidesGrid.length - 1] - slidesGrid[slidesGrid.length - 2];
}
}
// Find current slide size
const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
if (timeDiff > params.longSwipesMs) {
// Long touches
if (!params.longSwipes) {
swiper.slideTo(swiper.activeIndex);
return;
}
if (swiper.swipeDirection === 'next') {
if (ratio >= params.longSwipesRatio) swiper.slideTo(stopIndex + params.slidesPerGroup);
else swiper.slideTo(stopIndex);
}
if (swiper.swipeDirection === 'prev') {
if (ratio > (1 - params.longSwipesRatio)) swiper.slideTo(stopIndex + params.slidesPerGroup);
else swiper.slideTo(stopIndex);
}
} else {
// Short swipes
if (!params.shortSwipes) {
swiper.slideTo(swiper.activeIndex);
return;
}
if (swiper.swipeDirection === 'next') {
swiper.slideTo(stopIndex + params.slidesPerGroup);
}
if (swiper.swipeDirection === 'prev') {
swiper.slideTo(stopIndex);
}
}
};
var onResize = function () {
const swiper = this;
const { params, el } = swiper;
if (el && el.offsetWidth === 0) return;
// Breakpoints
if (params.breakpoints) {
swiper.setBreakpoint();
}
// Save locks
const { allowSlideNext, allowSlidePrev } = swiper;
// Disable locks on resize
swiper.allowSlideNext = true;
swiper.allowSlidePrev = true;
swiper.updateSize();
swiper.updateSlides();
if (params.freeMode) {
const newTranslate = Math.min(Math.max(swiper.translate, swiper.maxTranslate()), swiper.minTranslate());
swiper.setTranslate(newTranslate);
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
if (params.autoHeight) {
swiper.updateAutoHeight();
}
} else {
swiper.updateSlidesClasses();
if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
swiper.slideTo(swiper.slides.length - 1, 0, false, true);
} else {
swiper.slideTo(swiper.activeIndex, 0, false, true);
}
}
// Return locks after resize
swiper.allowSlidePrev = allowSlidePrev;
swiper.allowSlideNext = allowSlideNext;
};
var onClick = function (e) {
const swiper = this;
if (!swiper.allowClick) {
if (swiper.params.preventClicks) e.preventDefault();
if (swiper.params.preventClicksPropagation && swiper.animating) {
e.stopPropagation();
e.stopImmediatePropagation();
}
}
};
function attachEvents() {
const swiper = this;
const { params, touchEvents, el, wrapperEl } = swiper;
{
swiper.onTouchStart = onTouchStart.bind(swiper);
swiper.onTouchMove = onTouchMove.bind(swiper);
swiper.onTouchEnd = onTouchEnd.bind(swiper);
}
swiper.onClick = onClick.bind(swiper);
const target = params.touchEventsTarget === 'container' ? el : wrapperEl;
const capture = !!params.nested;
// Touch Events
{
if (Browser.ie) {
target.addEventListener(touchEvents.start, swiper.onTouchStart, false);
(Support$1.touch ? target : document).addEventListener(touchEvents.move, swiper.onTouchMove, capture);
(Support$1.touch ? target : document).addEventListener(touchEvents.end, swiper.onTouchEnd, false);
} else {
if (Support$1.touch) {
const passiveListener = touchEvents.start === 'touchstart' && Support$1.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
target.addEventListener(touchEvents.start, swiper.onTouchStart, passiveListener);
target.addEventListener(touchEvents.move, swiper.onTouchMove, Support$1.passiveListener ? { passive: false, capture } : capture);
target.addEventListener(touchEvents.end, swiper.onTouchEnd, passiveListener);
}
if ((params.simulateTouch && !Device.ios && !Device.android) || (params.simulateTouch && !Support$1.touch && Device.ios)) {
target.addEventListener('mousedown', swiper.onTouchStart, false);
document.addEventListener('mousemove', swiper.onTouchMove, capture);
document.addEventListener('mouseup', swiper.onTouchEnd, false);
}
}
// Prevent Links Clicks
if (params.preventClicks || params.preventClicksPropagation) {
target.addEventListener('click', swiper.onClick, true);
}
}
// Resize handler
swiper.on('resize observerUpdate', onResize);
}
function detachEvents() {
const swiper = this;
const { params, touchEvents, el, wrapperEl } = swiper;
const target = params.touchEventsTarget === 'container' ? el : wrapperEl;
const capture = !!params.nested;
// Touch Events
{
if (Browser.ie) {
target.removeEventListener(touchEvents.start, swiper.onTouchStart, false);
(Support$1.touch ? target : document).removeEventListener(touchEvents.move, swiper.onTouchMove, capture);
(Support$1.touch ? target : document).removeEventListener(touchEvents.end, swiper.onTouchEnd, false);
} else {
if (Support$1.touch) {
const passiveListener = touchEvents.start === 'onTouchStart' && Support$1.passiveListener && params.passiveListeners ? { passive: true, capture: false } : false;
target.removeEventListener(touchEvents.start, swiper.onTouchStart, passiveListener);
target.removeEventListener(touchEvents.move, swiper.onTouchMove, capture);
target.removeEventListener(touchEvents.end, swiper.onTouchEnd, passiveListener);
}
if ((params.simulateTouch && !Device.ios && !Device.android) || (params.simulateTouch && !Support$1.touch && Device.ios)) {
target.removeEventListener('mousedown', swiper.onTouchStart, false);
document.removeEventListener('mousemove', swiper.onTouchMove, capture);
document.removeEventListener('mouseup', swiper.onTouchEnd, false);
}
}
// Prevent Links Clicks
if (params.preventClicks || params.preventClicksPropagation) {
target.removeEventListener('click', swiper.onClick, true);
}
}
// Resize handler
swiper.off('resize observerUpdate', onResize);
}
var events = {
attachEvents,
detachEvents,
};
var setBreakpoint = function () {
const swiper = this;
const { activeIndex, loopedSlides = 0, params } = swiper;
const breakpoints = params.breakpoints;
if (!breakpoints || (breakpoints && Object.keys(breakpoints).length === 0)) return;
// Set breakpoint for window width and update parameters
const breakpoint = swiper.getBreakpoint(breakpoints);
if (breakpoint && swiper.currentBreakpoint !== breakpoint) {
const breakPointsParams = breakpoint in breakpoints ? breakpoints[breakpoint] : swiper.originalParams;
const needsReLoop = params.loop && (breakPointsParams.slidesPerView !== params.slidesPerView);
Utils.extend(swiper.params, breakPointsParams);
Utils.extend(swiper, {
allowTouchMove: swiper.params.allowTouchMove,
allowSlideNext: swiper.params.allowSlideNext,
allowSlidePrev: swiper.params.allowSlidePrev,
});
swiper.currentBreakpoint = breakpoint;
if (needsReLoop) {
swiper.loopDestroy();
swiper.loopCreate();
swiper.updateSlides();
swiper.slideTo((activeIndex - loopedSlides) + swiper.loopedSlides, 0, false);
}
swiper.emit('breakpoint', breakPointsParams);
}
};
var getBreakpoint = function (breakpoints) {
// Get breakpoint for window width
if (!breakpoints) return undefined;
let breakpoint = false;
const points = [];
Object.keys(breakpoints).forEach((point) => {
points.push(point);
});
points.sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
for (let i = 0; i < points.length; i += 1) {
const point = points[i];
if (point >= window.innerWidth && !breakpoint) {
breakpoint = point;
}
}
return breakpoint || 'max';
};
var breakpoints = { setBreakpoint, getBreakpoint };
var addClasses = function () {
const swiper = this;
const { classNames, params, rtl, $el } = swiper;
const suffixes = [];
suffixes.push(params.direction);
if (params.freeMode) {
suffixes.push('free-mode');
}
if (!Support$1.flexbox) {
suffixes.push('no-flexbox');
}
if (params.autoHeight) {
suffixes.push('autoheight');
}
if (rtl) {
suffixes.push('rtl');
}
if (params.slidesPerColumn > 1) {
suffixes.push('multirow');
}
if (Device.android) {
suffixes.push('android');
}
if (Device.ios) {
suffixes.push('ios');
}
// WP8 Touch Events Fix
if (window.navigator.pointerEnabled || window.navigator.msPointerEnabled) {
suffixes.push(`wp8-${params.direction}`);
}
suffixes.forEach((suffix) => {
classNames.push(params.containerModifierClass + suffix);
});
$el.addClass(classNames.join(' '));
};
var removeClasses = function () {
const swiper = this;
const { $el, classNames } = swiper;
$el.removeClass(classNames.join(' '));
};
var classes = { addClasses, removeClasses };
var loadImage = function (imageEl, src, srcset, sizes, checkForComplete, callback) {
let image;
function onReady() {
if (callback) callback();
}
if (!imageEl.complete || !checkForComplete) {
if (src) {
image = new window.Image();
image.onload = onReady;
image.onerror = onReady;
if (sizes) {
image.sizes = sizes;
}
if (srcset) {
image.srcset = srcset;
}
if (src) {
image.src = src;
}
} else {
onReady();
}
} else {
// image already loaded...
onReady();
}
};
var preloadImages = function () {
const swiper = this;
swiper.imagesToLoad = swiper.$el.find('img');
function onReady() {
if (typeof swiper === 'undefined' || swiper === null || !swiper || swiper.destroyed) return;
if (swiper.imagesLoaded !== undefined) swiper.imagesLoaded += 1;
if (swiper.imagesLoaded === swiper.imagesToLoad.length) {
if (swiper.params.updateOnImagesReady) swiper.update();
swiper.emit('imagesReady');
}
}
for (let i = 0; i < swiper.imagesToLoad.length; i += 1) {
const imageEl = swiper.imagesToLoad[i];
swiper.loadImage(
imageEl,
imageEl.currentSrc || imageEl.getAttribute('src'),
imageEl.srcset || imageEl.getAttribute('srcset'),
imageEl.sizes || imageEl.getAttribute('sizes'),
true,
onReady
);
}
};
var images = {
loadImage,
preloadImages,
};
var defaults = {
init: true,
direction: 'horizontal',
touchEventsTarget: 'container',
initialSlide: 0,
speed: 300,
// To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
iOSEdgeSwipeDetection: false,
iOSEdgeSwipeThreshold: 20,
// Free mode
freeMode: false,
freeModeMomentum: true,
freeModeMomentumRatio: 1,
freeModeMomentumBounce: true,
freeModeMomentumBounceRatio: 1,
freeModeMomentumVelocityRatio: 1,
freeModeSticky: false,
freeModeMinimumVelocity: 0.02,
// Autoheight
autoHeight: false,
// Set wrapper width
setWrapperSize: false,
// Virtual Translate
virtualTranslate: false,
// Effects
effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
// Breakpoints
breakpoints: undefined,
// Slides grid
spaceBetween: 0,
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerColumnFill: 'column',
slidesPerGroup: 1,
centeredSlides: false,
slidesOffsetBefore: 0, // in px
slidesOffsetAfter: 0, // in px
normalizeSlideIndex: true,
// Round length
roundLengths: false,
// Touches
touchRatio: 1,
touchAngle: 45,
simulateTouch: true,
shortSwipes: true,
longSwipes: true,
longSwipesRatio: 0.5,
longSwipesMs: 300,
followFinger: true,
allowTouchMove: true,
threshold: 0,
touchMoveStopPropagation: true,
touchReleaseOnEdges: false,
// Unique Navigation Elements
uniqueNavElements: true,
// Resistance
resistance: true,
resistanceRatio: 0.85,
// Progress
watchSlidesProgress: false,
watchSlidesVisibility: false,
// Cursor
grabCursor: false,
// Clicks
preventClicks: true,
preventClicksPropagation: true,
slideToClickedSlide: false,
// Images
preloadImages: true,
updateOnImagesReady: true,
// loop
loop: false,
loopAdditionalSlides: 0,
loopedSlides: null,
loopFillGroupWithBlank: false,
// Swiping/no swiping
allowSlidePrev: true,
allowSlideNext: true,
swipeHandler: null, // '.swipe-handler',
noSwiping: true,
noSwipingClass: 'swiper-no-swiping',
// Passive Listeners
passiveListeners: true,
// NS
containerModifierClass: 'swiper-container-', // NEW
slideClass: 'swiper-slide',
slideBlankClass: 'swiper-slide-invisible-blank',
slideActiveClass: 'swiper-slide-active',
slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
slideVisibleClass: 'swiper-slide-visible',
slideDuplicateClass: 'swiper-slide-duplicate',
slideNextClass: 'swiper-slide-next',
slideDuplicateNextClass: 'swiper-slide-duplicate-next',
slidePrevClass: 'swiper-slide-prev',
slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
wrapperClass: 'swiper-wrapper',
// Callbacks
runCallbacksOnInit: true,
};
const prototypes = {
update,
translate,
transition,
slide,
loop,
grabCursor,
manipulation,
events,
breakpoints,
classes,
images,
};
const extendedDefaults = {};
class Swiper$2 extends Framework7Class {
constructor(...args) {
let el;
let params;
if (args.length === 1 && args[0].constructor && args[0].constructor === Object) {
params = args[0];
} else {
[el, params] = args;
}
if (!params) params = {};
params = Utils.extend({}, params);
if (el && !params.el) params.el = el;
super(params);
Object.keys(prototypes).forEach((prototypeGroup) => {
Object.keys(prototypes[prototypeGroup]).forEach((protoMethod) => {
if (!Swiper$2.prototype[protoMethod]) {
Swiper$2.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
}
});
});
// Swiper Instance
const swiper = this;
if (typeof swiper.modules === 'undefined') {
swiper.modules = {};
}
Object.keys(swiper.modules).forEach((moduleName) => {
const module = swiper.modules[moduleName];
if (module.params) {
const moduleParamName = Object.keys(module.params)[0];
const moduleParams = module.params[moduleParamName];
if (typeof moduleParams !== 'object') return;
if (!(moduleParamName in params && 'enabled' in moduleParams)) return;
if (params[moduleParamName] === true) {
params[moduleParamName] = { enabled: true };
}
if (
typeof params[moduleParamName] === 'object' &&
!('enabled' in params[moduleParamName])
) {
params[moduleParamName].enabled = true;
}
if (!params[moduleParamName]) params[moduleParamName] = { enabled: false };
}
});
// Extend defaults with modules params
const swiperParams = Utils.extend({}, defaults);
swiper.useModulesParams(swiperParams);
// Extend defaults with passed params
swiper.params = Utils.extend({}, swiperParams, extendedDefaults, params);
swiper.originalParams = Utils.extend({}, swiper.params);
swiper.passedParams = Utils.extend({}, params);
// Find el
const $el = $(swiper.params.el);
el = $el[0];
if (!el) {
return undefined;
}
if ($el.length > 1) {
const swipers = [];
$el.each((index, containerEl) => {
const newParams = Utils.extend({}, params, { el: containerEl });
swipers.push(new Swiper$2(newParams));
});
return swipers;
}
el.swiper = swiper;
$el.data('swiper', swiper);
// Find Wrapper
const $wrapperEl = $el.children(`.${swiper.params.wrapperClass}`);
// Extend Swiper
Utils.extend(swiper, {
$el,
el,
$wrapperEl,
wrapperEl: $wrapperEl[0],
// Classes
classNames: [],
// Slides
slides: $(),
slidesGrid: [],
snapGrid: [],
slidesSizesGrid: [],
// isDirection
isHorizontal() {
return swiper.params.direction === 'horizontal';
},
isVertical() {
return swiper.params.direction === 'vertical';
},
// RTL
rtl: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
wrongRTL: $wrapperEl.css('display') === '-webkit-box',
// Indexes
activeIndex: 0,
realIndex: 0,
//
isBeginning: true,
isEnd: false,
// Props
translate: 0,
progress: 0,
velocity: 0,
animating: false,
// Locks
allowSlideNext: swiper.params.allowSlideNext,
allowSlidePrev: swiper.params.allowSlidePrev,
// Touch Events
touchEvents: (function touchEvents() {
const touch = ['touchstart', 'touchmove', 'touchend'];
let desktop = ['mousedown', 'mousemove', 'mouseup'];
if (window.navigator.pointerEnabled) {
desktop = ['pointerdown', 'pointermove', 'pointerup'];
} else if (window.navigator.msPointerEnabled) {
desktop = ['MSPointerDown', 'MsPointerMove', 'MsPointerUp'];
}
return {
start: Support$1.touch || !swiper.params.simulateTouch ? touch[0] : desktop[0],
move: Support$1.touch || !swiper.params.simulateTouch ? touch[1] : desktop[1],
end: Support$1.touch || !swiper.params.simulateTouch ? touch[2] : desktop[2],
};
}()),
touchEventsData: {
isTouched: undefined,
isMoved: undefined,
allowTouchCallbacks: undefined,
touchStartTime: undefined,
isScrolling: undefined,
currentTranslate: undefined,
startTranslate: undefined,
allowThresholdMove: undefined,
// Form elements to match
formElements: 'input, select, option, textarea, button, video',
// Last click time
lastClickTime: Utils.now(),
clickTimeout: undefined,
// Velocities
velocities: [],
allowMomentumBounce: undefined,
isTouchEvent: undefined,
startMoving: undefined,
},
// Clicks
allowClick: true,
// Touches
allowTouchMove: swiper.params.allowTouchMove,
touches: {
startX: 0,
startY: 0,
currentX: 0,
currentY: 0,
diff: 0,
},
// Images
imagesToLoad: [],
imagesLoaded: 0,
});
// Install Modules
swiper.useModules();
// Init
if (swiper.params.init) {
swiper.init();
}
// Return app instance
return swiper;
}
slidesPerViewDynamic() {
const swiper = this;
const { params, slides, slidesGrid, size: swiperSize, activeIndex } = swiper;
let spv = 1;
if (params.centeredSlides) {
let slideSize = slides[activeIndex].swiperSlideSize;
let breakLoop;
for (let i = activeIndex + 1; i < slides.length; i += 1) {
if (slides[i] && !breakLoop) {
slideSize += slides[i].swiperSlideSize;
spv += 1;
if (slideSize > swiperSize) breakLoop = true;
}
}
for (let i = activeIndex - 1; i >= 0; i -= 1) {
if (slides[i] && !breakLoop) {
slideSize += slides[i].swiperSlideSize;
spv += 1;
if (slideSize > swiperSize) breakLoop = true;
}
}
} else {
for (let i = activeIndex + 1; i < slides.length; i += 1) {
if (slidesGrid[i] - slidesGrid[activeIndex] < swiperSize) {
spv += 1;
}
}
}
return spv;
}
update() {
const swiper = this;
if (!swiper || swiper.destroyed) return;
swiper.updateSize();
swiper.updateSlides();
swiper.updateProgress();
swiper.updateSlidesClasses();
let newTranslate;
function setTranslate() {
newTranslate = Math.min(Math.max(swiper.translate, swiper.maxTranslate()), swiper.minTranslate());
swiper.setTranslate(newTranslate);
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
}
let translated;
if (swiper.params.freeMode) {
setTranslate();
if (swiper.params.autoHeight) {
swiper.updateAutoHeight();
}
} else {
if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
} else {
translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
}
if (!translated) {
setTranslate();
}
}
swiper.emit('update');
}
init() {
const swiper = this;
if (swiper.initialized) return;
swiper.emit('beforeInit');
// Set breakpoint
if (swiper.params.breakpoints) {
swiper.setBreakpoint();
}
// Add Classes
swiper.addClasses();
// Create loop
if (swiper.params.loop) {
swiper.loopCreate();
}
// Update size
swiper.updateSize();
// Update slides
swiper.updateSlides();
// Set Grab Cursor
if (swiper.params.grabCursor) {
swiper.setGrabCursor();
}
if (swiper.params.preloadImages) {
swiper.preloadImages();
}
// Slide To Initial Slide
if (swiper.params.loop) {
swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit);
} else {
swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit);
}
// Attach events
swiper.attachEvents();
// Init Flag
swiper.initialized = true;
// Emit
swiper.emit('init');
}
destroy(deleteInstance = true, cleanStyles = true) {
const swiper = this;
const { params, $el, $wrapperEl, slides } = swiper;
swiper.emit('beforeDestroy');
// Init Flag
swiper.initialized = false;
// Detach events
swiper.detachEvents();
// Destroy loop
if (params.loop) {
swiper.loopDestroy();
}
// Cleanup styles
if (cleanStyles) {
swiper.removeClasses();
$el.removeAttr('style');
$wrapperEl.removeAttr('style');
if (slides && slides.length) {
slides
.removeClass([
params.slideVisibleClass,
params.slideActiveClass,
params.slideNextClass,
params.slidePrevClass,
].join(' '))
.removeAttr('style')
.removeAttr('data-swiper-slide-index')
.removeAttr('data-swiper-column')
.removeAttr('data-swiper-row');
}
}
swiper.emit('destroy');
// Detach emitter events
Object.keys(swiper.eventsListeners).forEach((eventName) => {
swiper.off(eventName);
});
if (deleteInstance !== false) {
swiper.$el[0].swiper = null;
swiper.$el.data('swiper', null);
Utils.deleteProps(swiper);
}
swiper.destroyed = true;
}
static extendDefaults(newDefaults) {
Utils.extend(extendedDefaults, newDefaults);
}
static get extendedDefaults() {
return extendedDefaults;
}
static get defaults() {
return defaults;
}
static get Class() {
return Framework7Class;
}
static get $() {
return $;
}
}
var Device$4 = {
name: 'device',
proto: {
device: Device,
},
static: {
device: Device,
},
};
var Support$4 = {
name: 'support',
proto: {
support: Support$1,
},
static: {
support: Support$1,
},
};
var Browser$2 = {
name: 'browser',
proto: {
browser: Browser,
},
static: {
browser: Browser,
},
};
var Resize$1 = {
name: 'resize',
create() {
const swiper = this;
Utils.extend(swiper, {
resize: {
resizeHandler() {
if (!swiper || !swiper.initialized) return;
swiper.emit('resize');
},
orientationChangeHandler() {
if (!swiper || !swiper.initialized) return;
swiper.emit('orientationchange');
},
},
});
},
on: {
init() {
const swiper = this;
// Emit resize
window.addEventListener('resize', swiper.resize.resizeHandler);
// Emit orientationchange
window.addEventListener('orientationchange', swiper.resize.orientationChangeHandler);
},
destroy() {
const swiper = this;
window.removeEventListener('resize', swiper.resize.resizeHandler);
window.removeEventListener('orientationchange', swiper.resize.orientationChangeHandler);
},
},
};
const Observer = {
func: window.MutationObserver || window.WebkitMutationObserver,
attach(target, options = {}) {
const swiper = this;
const ObserverFunc = Observer.func;
const observer = new ObserverFunc((mutations) => {
mutations.forEach((mutation) => {
swiper.emit('observerUpdate', mutation);
});
});
observer.observe(target, {
attributes: typeof options.attributes === 'undefined' ? true : options.attributes,
childList: typeof options.childList === 'undefined' ? true : options.childList,
characterData: typeof options.characterData === 'undefined' ? true : options.characterData,
});
swiper.observer.observers.push(observer);
},
init() {
const swiper = this;
if (!Support$1.observer || !swiper.params.observer) return;
if (swiper.params.observeParents) {
const containerParents = swiper.$el.parents();
for (let i = 0; i < containerParents.length; i += 1) {
swiper.observer.attach(containerParents[i]);
}
}
// Observe container
swiper.observer.attach(swiper.$el[0], { childList: false });
// Observe wrapper
swiper.observer.attach(swiper.$wrapperEl[0], { attributes: false });
},
destroy() {
const swiper = this;
swiper.observer.observers.forEach((observer) => {
observer.disconnect();
});
swiper.observer.observers = [];
},
};
var Observer$1 = {
name: 'observer',
params: {
observer: false,
observeParents: false,
},
create() {
const swiper = this;
Utils.extend(swiper, {
observer: {
init: Observer.init.bind(swiper),
attach: Observer.attach.bind(swiper),
destroy: Observer.destroy.bind(swiper),
observers: [],
},
});
},
on: {
init() {
const swiper = this;
swiper.observer.init();
},
destroy() {
const swiper = this;
swiper.observer.destroy();
},
},
};
const Virtual = {
update(force) {
const swiper = this;
const { slidesPerView, slidesPerGroup, centeredSlides } = swiper.params;
const {
from: previousFrom,
to: previousTo,
slides,
slidesGrid: previousSlidesGrid,
renderSlide,
offset: previousOffset,
} = swiper.virtual;
swiper.updateActiveIndex();
const activeIndex = swiper.activeIndex || 0;
let offsetProp;
if (swiper.rtl && swiper.isHorizontal()) offsetProp = 'right';
else offsetProp = swiper.isHorizontal() ? 'left' : 'top';
let slidesAfter;
let slidesBefore;
if (centeredSlides) {
slidesAfter = Math.floor(slidesPerView / 2) + slidesPerGroup;
slidesBefore = Math.floor(slidesPerView / 2) + slidesPerGroup;
} else {
slidesAfter = slidesPerView + (slidesPerGroup - 1);
slidesBefore = slidesPerGroup;
}
const from = Math.max((activeIndex || 0) - slidesBefore, 0);
const to = Math.min((activeIndex || 0) + slidesAfter, slides.length - 1);
const offset = (swiper.slidesGrid[from] || 0) - (swiper.slidesGrid[0] || 0);
Utils.extend(swiper.virtual, {
from,
to,
offset,
slidesGrid: swiper.slidesGrid,
});
function onRendered() {
swiper.updateSlides();
swiper.updateProgress();
swiper.updateSlidesClasses();
if (swiper.lazy && swiper.params.lazy.enabled) {
swiper.lazy.load();
}
}
if (previousFrom === from && previousTo === to && !force) {
if (swiper.slidesGrid !== previousSlidesGrid && offset !== previousOffset) {
swiper.slides.css(offsetProp, `${offset}px`);
}
swiper.updateProgress();
return;
}
if (swiper.params.virtual.renderExternal) {
swiper.params.virtual.renderExternal.call(swiper, {
offset,
from,
to,
slides: (function getSlides() {
const slidesToRender = [];
for (let i = from; i <= to; i += 1) {
slidesToRender.push(slides[i]);
}
return slidesToRender;
}()),
});
onRendered();
return;
}
const prependIndexes = [];
const appendIndexes = [];
if (force) {
swiper.$wrapperEl.find(`.${swiper.params.slideClass}`).remove();
} else {
for (let i = previousFrom; i <= previousTo; i += 1) {
if (i < from || i > to) {
swiper.$wrapperEl.find(`.${swiper.params.slideClass}[data-swiper-slide-index="${i}"]`).remove();
}
}
}
for (let i = 0; i < slides.length; i += 1) {
if (i >= from && i <= to) {
if (typeof previousTo === 'undefined' || force) {
appendIndexes.push(i);
} else {
if (i > previousTo) appendIndexes.push(i);
if (i < previousFrom) prependIndexes.push(i);
}
}
}
appendIndexes.forEach((index) => {
swiper.$wrapperEl.append(renderSlide(slides[index], index));
});
prependIndexes.sort((a, b) => a < b).forEach((index) => {
swiper.$wrapperEl.prepend(renderSlide(slides[index], index));
});
swiper.$wrapperEl.children('.swiper-slide').css(offsetProp, `${offset}px`);
onRendered();
},
renderSlide(slide, index) {
const swiper = this;
const params = swiper.params.virtual;
if (params.cache && swiper.virtual.cache[index]) {
return swiper.virtual.cache[index];
}
const $slideEl = params.renderSlide
? $(params.renderSlide.call(swiper, slide, index))
: $(`<div class="${swiper.params.slideClass}" data-swiper-slide-index="${index}">${slide}</div>`);
if (!$slideEl.attr('data-swiper-slide-index')) $slideEl.attr('data-swiper-slide-index', index);
if (params.cache) swiper.virtual.cache[index] = $slideEl;
return $slideEl;
},
appendSlide(slide) {
const swiper = this;
swiper.virtual.slides.push(slide);
swiper.virtual.update(true);
},
prependSlide(slide) {
const swiper = this;
swiper.virtual.slides.unshift(slide);
if (swiper.params.virtual.cache) {
const cache = swiper.virtual.cache;
const newCache = {};
Object.keys(cache).forEach((cachedIndex) => {
newCache[cachedIndex + 1] = cache[cachedIndex];
});
swiper.virtual.cache = newCache;
}
swiper.virtual.update(true);
swiper.slideNext(0);
},
};
var Virtual$1 = {
name: 'virtual',
params: {
virtual: {
enabled: false,
slides: [],
cache: true,
renderSlide: null,
renderExternal: null,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
virtual: {
update: Virtual.update.bind(swiper),
appendSlide: Virtual.appendSlide.bind(swiper),
prependSlide: Virtual.prependSlide.bind(swiper),
renderSlide: Virtual.renderSlide.bind(swiper),
slides: swiper.params.virtual.slides,
cache: {},
},
});
},
on: {
beforeInit() {
const swiper = this;
if (!swiper.params.virtual.enabled) return;
swiper.classNames.push(`${swiper.params.containerModifierClass}virtual`);
const overwriteParams = {
watchSlidesProgress: true,
};
Utils.extend(swiper.params, overwriteParams);
Utils.extend(swiper.originalParams, overwriteParams);
swiper.virtual.update();
},
setTranslate() {
const swiper = this;
if (!swiper.params.virtual.enabled) return;
swiper.virtual.update();
},
},
};
const Navigation = {
update() {
// Update Navigation Buttons
const swiper = this;
const params = swiper.params.navigation;
if (swiper.params.loop) return;
const { $nextEl, $prevEl } = swiper.navigation;
if ($prevEl && $prevEl.length > 0) {
if (swiper.isBeginning) {
$prevEl.addClass(params.disabledClass);
} else {
$prevEl.removeClass(params.disabledClass);
}
}
if ($nextEl && $nextEl.length > 0) {
if (swiper.isEnd) {
$nextEl.addClass(params.disabledClass);
} else {
$nextEl.removeClass(params.disabledClass);
}
}
},
init() {
const swiper = this;
const params = swiper.params.navigation;
if (!(params.nextEl || params.prevEl)) return;
let $nextEl;
let $prevEl;
if (params.nextEl) {
$nextEl = $(params.nextEl);
if (
swiper.params.uniqueNavElements &&
typeof params.nextEl === 'string' &&
$nextEl.length > 1 &&
swiper.$el.find(params.nextEl).length === 1
) {
$nextEl = swiper.$el.find(params.nextEl);
}
}
if (params.prevEl) {
$prevEl = $(params.prevEl);
if (
swiper.params.uniqueNavElements &&
typeof params.prevEl === 'string' &&
$prevEl.length > 1 &&
swiper.$el.find(params.prevEl).length === 1
) {
$prevEl = swiper.$el.find(params.prevEl);
}
}
if ($nextEl && $nextEl.length > 0) {
$nextEl.on('click', (e) => {
e.preventDefault();
if (swiper.isEnd && !swiper.params.loop) return;
swiper.slideNext();
});
}
if ($prevEl && $prevEl.length > 0) {
$prevEl.on('click', (e) => {
e.preventDefault();
if (swiper.isBeginning && !swiper.params.loop) return;
swiper.slidePrev();
});
}
Utils.extend(swiper.navigation, {
$nextEl,
nextEl: $nextEl && $nextEl[0],
$prevEl,
prevEl: $prevEl && $prevEl[0],
});
},
destroy() {
const swiper = this;
const { $nextEl, $prevEl } = swiper.navigation;
if ($nextEl && $nextEl.length) {
$nextEl.off('click');
$nextEl.removeClass(swiper.params.navigation.disabledClass);
}
if ($prevEl && $prevEl.length) {
$prevEl.off('click');
$prevEl.removeClass(swiper.params.navigation.disabledClass);
}
},
};
var Navigation$1 = {
name: 'navigation',
params: {
navigation: {
nextEl: null,
prevEl: null,
hideOnClick: false,
disabledClass: 'swiper-button-disabled',
hiddenClass: 'swiper-button-hidden',
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
navigation: {
init: Navigation.init.bind(swiper),
update: Navigation.update.bind(swiper),
destroy: Navigation.destroy.bind(swiper),
},
});
},
on: {
init() {
const swiper = this;
swiper.navigation.init();
swiper.navigation.update();
},
toEdge() {
const swiper = this;
swiper.navigation.update();
},
fromEdge() {
const swiper = this;
swiper.navigation.update();
},
destroy() {
const swiper = this;
swiper.navigation.destroy();
},
click(e) {
const swiper = this;
const { $nextEl, $prevEl } = swiper.navigation;
if (
swiper.params.navigation.hideOnClick &&
!$(e.target).is($prevEl) &&
!$(e.target).is($nextEl)
) {
if ($nextEl) $nextEl.toggleClass(swiper.params.navigation.hiddenClass);
if ($prevEl) $prevEl.toggleClass(swiper.params.navigation.hiddenClass);
}
},
},
};
const Pagination = {
update() {
// Render || Update Pagination bullets/items
const swiper = this;
const rtl = swiper.rtl;
const params = swiper.params.pagination;
if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
const $el = swiper.pagination.$el;
// Current/Total
let current;
const total = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
if (swiper.params.loop) {
current = Math.ceil((swiper.activeIndex - swiper.loopedSlides) / swiper.params.slidesPerGroup);
if (current > slidesLength - 1 - (swiper.loopedSlides * 2)) {
current -= (slidesLength - (swiper.loopedSlides * 2));
}
if (current > total - 1) current -= total;
if (current < 0 && swiper.params.paginationType !== 'bullets') current = total + current;
} else if (typeof swiper.snapIndex !== 'undefined') {
current = swiper.snapIndex;
} else {
current = swiper.activeIndex || 0;
}
// Types
if (params.type === 'bullets' && swiper.pagination.bullets && swiper.pagination.bullets.length > 0) {
const bullets = swiper.pagination.bullets;
if (params.dynamicBullets) {
swiper.pagination.bulletSize = bullets.eq(0)[swiper.isHorizontal() ? 'outerWidth' : 'outerHeight'](true);
$el.css(swiper.isHorizontal() ? 'width' : 'height', `${swiper.pagination.bulletSize * 5}px`);
}
bullets.removeClass(`${params.bulletActiveClass} ${params.bulletActiveClass}-next ${params.bulletActiveClass}-next-next ${params.bulletActiveClass}-prev ${params.bulletActiveClass}-prev-prev`);
if ($el.length > 1) {
bullets.each((index, bullet) => {
const $bullet = $(bullet);
if ($bullet.index() === current) {
$bullet.addClass(params.bulletActiveClass);
if (params.dynamicBullets) {
$bullet
.prev()
.addClass(`${params.bulletActiveClass}-prev`)
.prev()
.addClass(`${params.bulletActiveClass}-prev-prev`);
$bullet
.next()
.addClass(`${params.bulletActiveClass}-next`)
.next()
.addClass(`${params.bulletActiveClass}-next-next`);
}
}
});
} else {
const $bullet = bullets.eq(current);
$bullet.addClass(params.bulletActiveClass);
if (params.dynamicBullets) {
$bullet
.prev()
.addClass(`${params.bulletActiveClass}-prev`)
.prev()
.addClass(`${params.bulletActiveClass}-prev-prev`);
$bullet
.next()
.addClass(`${params.bulletActiveClass}-next`)
.next()
.addClass(`${params.bulletActiveClass}-next-next`);
}
}
if (params.dynamicBullets) {
const dynamicBulletsLength = Math.min(bullets.length, 5);
const bulletsOffset = (((swiper.pagination.bulletSize * dynamicBulletsLength) - (swiper.pagination.bulletSize)) / 2) - (current * swiper.pagination.bulletSize);
const offsetProp = rtl ? 'right' : 'left';
bullets.css(swiper.isHorizontal() ? offsetProp : 'top', `${bulletsOffset}px`);
}
}
if (params.type === 'fraction') {
$el.find(`.${params.currentClass}`).text(current + 1);
$el.find(`.${params.totalClass}`).text(total);
}
if (params.type === 'progressbar') {
const scale = (current + 1) / total;
let scaleX = scale;
let scaleY = 1;
if (!swiper.isHorizontal()) {
scaleY = scale;
scaleX = 1;
}
$el.find(`.${params.progressbarFillClass}`).transform(`translate3d(0,0,0) scaleX(${scaleX}) scaleY(${scaleY})`).transition(swiper.params.speed);
}
if (params.type === 'custom' && params.renderCustom) {
$el.html(params.renderCustom(swiper, current + 1, total));
swiper.emit('paginationRender', swiper, $el[0]);
} else {
swiper.emit('paginationUpdate', swiper, $el[0]);
}
},
render() {
// Render Container
const swiper = this;
const params = swiper.params.pagination;
if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
const slidesLength = swiper.virtual && swiper.params.virtual.enabled ? swiper.virtual.slides.length : swiper.slides.length;
const $el = swiper.pagination.$el;
let paginationHTML = '';
if (params.type === 'bullets') {
const numberOfBullets = swiper.params.loop ? Math.ceil((slidesLength - (swiper.loopedSlides * 2)) / swiper.params.slidesPerGroup) : swiper.snapGrid.length;
for (let i = 0; i < numberOfBullets; i += 1) {
if (params.renderBullet) {
paginationHTML += params.renderBullet.call(swiper, i, params.bulletClass);
} else {
paginationHTML += `<${params.bulletElement} class="${params.bulletClass}"></${params.bulletElement}>`;
}
}
$el.html(paginationHTML);
swiper.pagination.bullets = $el.find(`.${params.bulletClass}`);
}
if (params.type === 'fraction') {
if (params.renderFraction) {
paginationHTML = params.renderFraction.call(swiper, params.currentClass, params.totalClass);
} else {
paginationHTML =
`<span class="${params.currentClass}"></span>` +
' / ' +
`<span class="${params.totalClass}"></span>`;
}
$el.html(paginationHTML);
}
if (params.type === 'progressbar') {
if (params.renderProgressbar) {
paginationHTML = params.renderProgressbar.call(swiper, params.progressbarFillClass);
} else {
paginationHTML = `<span class="${params.progressbarFillClass}"></span>`;
}
$el.html(paginationHTML);
}
if (params.type !== 'custom') {
swiper.emit('paginationRender', swiper.pagination.$el[0]);
}
},
init() {
const swiper = this;
const params = swiper.params.pagination;
if (!params.el) return;
let $el = $(params.el);
if ($el.length === 0) return;
if (
swiper.params.uniqueNavElements &&
typeof params.el === 'string' &&
$el.length > 1 &&
swiper.$el.find(params.el).length === 1
) {
$el = swiper.$el.find(params.el);
}
if (params.type === 'bullets' && params.clickable) {
$el.addClass(params.clickableClass);
}
$el.addClass(params.modifierClass + params.type);
if (params.type === 'bullets' && params.dynamicBullets) {
$el.addClass(`${params.modifierClass}${params.type}-dynamic`);
}
if (params.clickable) {
$el.on('click', `.${params.bulletClass}`, function onClick(e) {
e.preventDefault();
let index = $(this).index() * swiper.params.slidesPerGroup;
if (swiper.params.loop) index += swiper.loopedSlides;
swiper.slideTo(index);
});
}
Utils.extend(swiper.pagination, {
$el,
el: $el[0],
});
},
destroy() {
const swiper = this;
const params = swiper.params.pagination;
if (!params.el || !swiper.pagination.el || !swiper.pagination.$el || swiper.pagination.$el.length === 0) return;
const $el = swiper.pagination.$el;
$el.removeClass(params.hiddenClass);
$el.removeClass(params.modifierClass + params.type);
if (swiper.pagination.bullets) swiper.pagination.bullets.removeClass(params.bulletActiveClass);
if (params.clickable) {
$el.off('click', `.${params.bulletClass}`);
}
},
};
var Pagination$1 = {
name: 'pagination',
params: {
pagination: {
el: null,
bulletElement: 'span',
clickable: false,
hideOnClick: false,
renderBullet: null,
renderProgressbar: null,
renderFraction: null,
renderCustom: null,
type: 'bullets', // 'bullets' or 'progressbar' or 'fraction' or 'custom'
dynamicBullets: false,
bulletClass: 'swiper-pagination-bullet',
bulletActiveClass: 'swiper-pagination-bullet-active',
modifierClass: 'swiper-pagination-', // NEW
currentClass: 'swiper-pagination-current',
totalClass: 'swiper-pagination-total',
hiddenClass: 'swiper-pagination-hidden',
progressbarFillClass: 'swiper-pagination-progressbar-fill',
clickableClass: 'swiper-pagination-clickable', // NEW
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
pagination: {
init: Pagination.init.bind(swiper),
render: Pagination.render.bind(swiper),
update: Pagination.update.bind(swiper),
destroy: Pagination.destroy.bind(swiper),
},
});
},
on: {
init() {
const swiper = this;
swiper.pagination.init();
swiper.pagination.render();
swiper.pagination.update();
},
activeIndexChange() {
const swiper = this;
if (swiper.params.loop) {
swiper.pagination.update();
} else if (typeof swiper.snapIndex === 'undefined') {
swiper.pagination.update();
}
},
snapIndexChange() {
const swiper = this;
if (!swiper.params.loop) {
swiper.pagination.update();
}
},
slidesLengthChange() {
const swiper = this;
if (swiper.params.loop) {
swiper.pagination.render();
swiper.pagination.update();
}
},
snapGridLengthChange() {
const swiper = this;
if (!swiper.params.loop) {
swiper.pagination.render();
swiper.pagination.update();
}
},
destroy() {
const swiper = this;
swiper.pagination.destroy();
},
click(e) {
const swiper = this;
if (
swiper.params.pagination.el &&
swiper.params.pagination.hideOnClick &&
swiper.pagination.$el.length > 0 &&
!$(e.target).hasClass(swiper.params.pagination.bulletClass)
) {
swiper.pagination.$el.toggleClass(swiper.params.pagination.hiddenClass);
}
},
},
};
const Scrollbar = {
setTranslate() {
const swiper = this;
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
const { scrollbar, rtl, progress } = swiper;
const { dragSize, trackSize, $dragEl, $el } = scrollbar;
const params = swiper.params.scrollbar;
let newSize = dragSize;
let newPos = (trackSize - dragSize) * progress;
if (rtl && swiper.isHorizontal()) {
newPos = -newPos;
if (newPos > 0) {
newSize = dragSize - newPos;
newPos = 0;
} else if (-newPos + dragSize > trackSize) {
newSize = trackSize + newPos;
}
} else if (newPos < 0) {
newSize = dragSize + newPos;
newPos = 0;
} else if (newPos + dragSize > trackSize) {
newSize = trackSize - newPos;
}
if (swiper.isHorizontal()) {
if (Support$1.transforms3d) {
$dragEl.transform(`translate3d(${newPos}px, 0, 0)`);
} else {
$dragEl.transform(`translateX(${newPos}px)`);
}
$dragEl[0].style.width = `${newSize}px`;
} else {
if (Support$1.transforms3d) {
$dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);
} else {
$dragEl.transform(`translateY(${newPos}px)`);
}
$dragEl[0].style.height = `${newSize}px`;
}
if (params.hide) {
clearTimeout(swiper.scrollbar.timeout);
$el[0].style.opacity = 1;
swiper.scrollbar.timeout = setTimeout(() => {
$el[0].style.opacity = 0;
$el.transition(400);
}, 1000);
}
},
setTransition(duration) {
const swiper = this;
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
swiper.scrollbar.$dragEl.transition(duration);
},
updateSize() {
const swiper = this;
if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
const { scrollbar } = swiper;
const { $dragEl, $el } = scrollbar;
$dragEl[0].style.width = '';
$dragEl[0].style.height = '';
const trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;
const divider = swiper.size / swiper.virtualSize;
const moveDivider = divider * (trackSize / swiper.size);
let dragSize;
if (swiper.params.scrollbar.dragSize === 'auto') {
dragSize = trackSize * divider;
} else {
dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
}
if (swiper.isHorizontal()) {
$dragEl[0].style.width = `${dragSize}px`;
} else {
$dragEl[0].style.height = `${dragSize}px`;
}
if (divider >= 1) {
$el[0].style.display = 'none';
} else {
$el[0].style.display = '';
}
if (swiper.params.scrollbarHide) {
$el[0].style.opacity = 0;
}
Utils.extend(scrollbar, {
trackSize,
divider,
moveDivider,
dragSize,
});
},
setDragPosition(e) {
const swiper = this;
const { scrollbar } = swiper;
const { $el, dragSize, trackSize } = scrollbar;
let pointerPosition;
if (swiper.isHorizontal()) {
pointerPosition = ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageX : e.pageX || e.clientX);
} else {
pointerPosition = ((e.type === 'touchstart' || e.type === 'touchmove') ? e.targetTouches[0].pageY : e.pageY || e.clientY);
}
let positionRatio;
positionRatio = ((pointerPosition) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top'] - (dragSize / 2)) / (trackSize - dragSize);
positionRatio = Math.max(Math.min(positionRatio, 1), 0);
if (swiper.rtl) {
positionRatio = 1 - positionRatio;
}
const position = swiper.minTranslate() + ((swiper.maxTranslate() - swiper.minTranslate()) * positionRatio);
swiper.updateProgress(position);
swiper.setTranslate(position);
swiper.updateActiveIndex();
swiper.updateSlidesClasses();
},
onDragStart(e) {
const swiper = this;
const params = swiper.params.scrollbar;
const { scrollbar, $wrapperEl } = swiper;
const { $el, $dragEl } = scrollbar;
swiper.scrollbar.isTouched = true;
e.preventDefault();
e.stopPropagation();
$wrapperEl.transition(100);
$dragEl.transition(100);
scrollbar.setDragPosition(e);
clearTimeout(swiper.scrollbar.dragTimeout);
$el.transition(0);
if (params.hide) {
$el.css('opacity', 1);
}
swiper.emit('scrollbarDragStart', e);
},
onDragMove(e) {
const swiper = this;
const { scrollbar, $wrapperEl } = swiper;
const { $el, $dragEl } = scrollbar;
if (!swiper.scrollbar.isTouched) return;
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
scrollbar.setDragPosition(e);
$wrapperEl.transition(0);
$el.transition(0);
$dragEl.transition(0);
swiper.emit('scrollbarDragMove', e);
},
onDragEnd(e) {
const swiper = this;
const params = swiper.params.scrollbar;
const { scrollbar } = swiper;
const { $el } = scrollbar;
if (!swiper.scrollbar.isTouched) return;
swiper.scrollbar.isTouched = false;
if (params.hide) {
clearTimeout(swiper.scrollbar.dragTimeout);
swiper.scrollbar.dragTimeout = Utils.nextTick(() => {
$el.css('opacity', 0);
$el.transition(400);
}, 1000);
}
swiper.emit('scrollbarDragEnd', e);
if (params.snapOnRelease) {
swiper.slideReset();
}
},
enableDraggable() {
const swiper = this;
if (!swiper.params.scrollbar.el) return;
const { scrollbar } = swiper;
const $el = scrollbar.$el;
const target = Support$1.touch ? $el[0] : document;
$el.on(swiper.scrollbar.dragEvents.start, swiper.scrollbar.onDragStart);
$(target).on(swiper.scrollbar.dragEvents.move, swiper.scrollbar.onDragMove);
$(target).on(swiper.scrollbar.dragEvents.end, swiper.scrollbar.onDragEnd);
},
disableDraggable() {
const swiper = this;
if (!swiper.params.scrollbar.el) return;
const { scrollbar } = swiper;
const $el = scrollbar.$el;
const target = Support$1.touch ? $el[0] : document;
$el.off(swiper.scrollbar.dragEvents.start);
$(target).off(swiper.scrollbar.dragEvents.move);
$(target).off(swiper.scrollbar.dragEvents.end);
},
init() {
const swiper = this;
if (!swiper.params.scrollbar.el) return;
const { scrollbar, $el: $swiperEl, touchEvents } = swiper;
const params = swiper.params.scrollbar;
let $el = $(params.el);
if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {
$el = $swiperEl.find(params.el);
}
let $dragEl = $el.find('.swiper-scrollbar-drag');
if ($dragEl.length === 0) {
$dragEl = $('<div class="swiper-scrollbar-drag"></div>');
$el.append($dragEl);
}
swiper.scrollbar.dragEvents = (function dragEvents() {
if ((swiper.params.simulateTouch === false && !Support$1.touch)) {
return {
start: 'mousedown',
move: 'mousemove',
end: 'mouseup',
};
}
return touchEvents;
}());
Utils.extend(scrollbar, {
$el,
el: $el[0],
$dragEl,
dragEl: $dragEl[0],
});
if (params.draggable) {
scrollbar.enableDraggable();
}
},
destroy() {
const swiper = this;
swiper.scrollbar.disableDraggable();
},
};
var Scrollbar$1 = {
name: 'scrollbar',
params: {
scrollbar: {
el: null,
dragSize: 'auto',
hide: false,
draggable: false,
snapOnRelease: true,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
scrollbar: {
init: Scrollbar.init.bind(swiper),
destroy: Scrollbar.destroy.bind(swiper),
updateSize: Scrollbar.updateSize.bind(swiper),
setTranslate: Scrollbar.setTranslate.bind(swiper),
setTransition: Scrollbar.setTransition.bind(swiper),
enableDraggable: Scrollbar.enableDraggable.bind(swiper),
disableDraggable: Scrollbar.disableDraggable.bind(swiper),
setDragPosition: Scrollbar.setDragPosition.bind(swiper),
onDragStart: Scrollbar.onDragStart.bind(swiper),
onDragMove: Scrollbar.onDragMove.bind(swiper),
onDragEnd: Scrollbar.onDragEnd.bind(swiper),
isTouched: false,
timeout: null,
dragTimeout: null,
},
});
},
on: {
init() {
const swiper = this;
swiper.scrollbar.init();
swiper.scrollbar.updateSize();
swiper.scrollbar.setTranslate();
},
update() {
const swiper = this;
swiper.scrollbar.updateSize();
},
resize() {
const swiper = this;
swiper.scrollbar.updateSize();
},
observerUpdate() {
const swiper = this;
swiper.scrollbar.updateSize();
},
setTranslate() {
const swiper = this;
swiper.scrollbar.setTranslate();
},
setTransition(duration) {
const swiper = this;
swiper.scrollbar.setTransition(duration);
},
destroy() {
const swiper = this;
swiper.scrollbar.destroy();
},
},
};
const Parallax = {
setTransform(el, progress) {
const swiper = this;
const { rtl } = swiper;
const $el = $(el);
const rtlFactor = rtl ? -1 : 1;
const p = $el.attr('data-swiper-parallax') || '0';
let x = $el.attr('data-swiper-parallax-x');
let y = $el.attr('data-swiper-parallax-y');
const scale = $el.attr('data-swiper-parallax-scale');
const opacity = $el.attr('data-swiper-parallax-opacity');
if (x || y) {
x = x || '0';
y = y || '0';
} else if (swiper.isHorizontal()) {
x = p;
y = '0';
} else {
y = p;
x = '0';
}
if ((x).indexOf('%') >= 0) {
x = `${parseInt(x, 10) * progress * rtlFactor}%`;
} else {
x = `${x * progress * rtlFactor}px`;
}
if ((y).indexOf('%') >= 0) {
y = `${parseInt(y, 10) * progress}%`;
} else {
y = `${y * progress}px`;
}
if (typeof opacity !== 'undefined' && opacity !== null) {
const currentOpacity = opacity - ((opacity - 1) * (1 - Math.abs(progress)));
$el[0].style.opacity = currentOpacity;
}
if (typeof scale === 'undefined' || scale === null) {
$el.transform(`translate3d(${x}, ${y}, 0px)`);
} else {
const currentScale = scale - ((scale - 1) * (1 - Math.abs(progress)));
$el.transform(`translate3d(${x}, ${y}, 0px) scale(${currentScale})`);
}
},
setTranslate() {
const swiper = this;
const { $el, slides, progress, snapGrid } = swiper;
$el.children('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]')
.each((index, el) => {
swiper.parallax.setTransform(el, progress);
});
slides.each((slideIndex, slideEl) => {
let slideProgress = slideEl.progress;
if (swiper.params.slidesPerGroup > 1 && swiper.params.slidesPerView !== 'auto') {
slideProgress += Math.ceil(slideIndex / 2) - (progress * (snapGrid.length - 1));
}
slideProgress = Math.min(Math.max(slideProgress, -1), 1);
$(slideEl).find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]')
.each((index, el) => {
swiper.parallax.setTransform(el, slideProgress);
});
});
},
setTransition(duration = this.params.speed) {
const swiper = this;
const { $el } = swiper;
$el.find('[data-swiper-parallax], [data-swiper-parallax-x], [data-swiper-parallax-y]')
.each((index, parallaxEl) => {
const $parallaxEl = $(parallaxEl);
let parallaxDuration = parseInt($parallaxEl.attr('data-swiper-parallax-duration'), 10) || duration;
if (duration === 0) parallaxDuration = 0;
$parallaxEl.transition(parallaxDuration);
});
},
};
var Parallax$1 = {
name: 'parallax',
params: {
parallax: {
enabled: false,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
parallax: {
setTransform: Parallax.setTransform.bind(swiper),
setTranslate: Parallax.setTranslate.bind(swiper),
setTransition: Parallax.setTransition.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
swiper.params.watchSlidesProgress = true;
},
init() {
const swiper = this;
if (!swiper.params.parallax) return;
swiper.parallax.setTranslate();
},
setTranslate() {
const swiper = this;
if (!swiper.params.parallax) return;
swiper.parallax.setTranslate();
},
setTransition(duration) {
const swiper = this;
if (!swiper.params.parallax) return;
swiper.parallax.setTransition(duration);
},
},
};
const Zoom = {
// Calc Scale From Multi-touches
getDistanceBetweenTouches(e) {
if (e.targetTouches.length < 2) return 1;
const x1 = e.targetTouches[0].pageX;
const y1 = e.targetTouches[0].pageY;
const x2 = e.targetTouches[1].pageX;
const y2 = e.targetTouches[1].pageY;
const distance = Math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2));
return distance;
},
// Events
onGestureStart(e) {
const swiper = this;
const params = swiper.params.zoom;
const zoom = swiper.zoom;
const { gesture } = zoom;
zoom.fakeGestureTouched = false;
zoom.fakeGestureMoved = false;
if (!Support$1.gestures) {
if (e.type !== 'touchstart' || (e.type === 'touchstart' && e.targetTouches.length < 2)) {
return;
}
zoom.fakeGestureTouched = true;
gesture.scaleStart = Zoom.getDistanceBetweenTouches(e);
}
if (!gesture.$slideEl || !gesture.$slideEl.length) {
gesture.$slideEl = $(this);
if (gesture.$slideEl.length === 0) gesture.$slideEl = swiper.slides.eq(swiper.activeIndex);
gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas');
gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
gesture.maxRatio = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
if (gesture.$imageWrapEl.length === 0) {
gesture.$imageEl = undefined;
return;
}
}
gesture.$imageEl.transition(0);
swiper.zoom.isScaling = true;
},
onGestureChange(e) {
const swiper = this;
const params = swiper.params.zoom;
const zoom = swiper.zoom;
const { gesture } = zoom;
if (!Support$1.gestures) {
if (e.type !== 'touchmove' || (e.type === 'touchmove' && e.targetTouches.length < 2)) {
return;
}
zoom.fakeGestureMoved = true;
gesture.scaleMove = Zoom.getDistanceBetweenTouches(e);
}
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
if (Support$1.gestures) {
swiper.zoom.scale = e.scale * zoom.currentScale;
} else {
zoom.scale = (gesture.scaleMove / gesture.scaleStart) * zoom.currentScale;
}
if (zoom.scale > gesture.maxRatio) {
zoom.scale = (gesture.maxRatio - 1) + (((zoom.scale - gesture.maxRatio) + 1) ** 0.5);
}
if (zoom.scale < params.minRatio) {
zoom.scale = (params.minRatio + 1) - (((params.minRatio - zoom.scale) + 1) ** 0.5);
}
gesture.$imageEl.transform(`translate3d(0,0,0) scale(${zoom.scale})`);
},
onGestureEnd(e) {
const swiper = this;
const params = swiper.params.zoom;
const zoom = swiper.zoom;
const { gesture } = zoom;
if (!Support$1.gestures) {
if (!zoom.fakeGestureTouched || !zoom.fakeGestureMoved) {
return;
}
if (e.type !== 'touchend' || (e.type === 'touchend' && e.changedTouches.length < 2 && !Device.android)) {
return;
}
zoom.fakeGestureTouched = false;
zoom.fakeGestureMoved = false;
}
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
zoom.scale = Math.max(Math.min(zoom.scale, gesture.maxRatio), params.minRatio);
gesture.$imageEl.transition(swiper.params.speed).transform(`translate3d(0,0,0) scale(${zoom.scale})`);
zoom.currentScale = zoom.scale;
zoom.isScaling = false;
if (zoom.scale === 1) gesture.$slideEl = undefined;
},
onTouchStart(e) {
const swiper = this;
const zoom = swiper.zoom;
const { gesture, image } = zoom;
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
if (image.isTouched) return;
if (Device.android) e.preventDefault();
image.isTouched = true;
image.touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
image.touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
},
onTouchMove(e) {
const swiper = this;
const zoom = swiper.zoom;
const { gesture, image, velocity } = zoom;
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
swiper.allowClick = false;
if (!image.isTouched || !gesture.$slideEl) return;
if (!image.isMoved) {
image.width = gesture.$imageEl[0].offsetWidth;
image.height = gesture.$imageEl[0].offsetHeight;
image.startX = Utils.getTranslate(gesture.$imageWrapEl[0], 'x') || 0;
image.startY = Utils.getTranslate(gesture.$imageWrapEl[0], 'y') || 0;
gesture.slideWidth = gesture.$slideEl[0].offsetWidth;
gesture.slideHeight = gesture.$slideEl[0].offsetHeight;
gesture.$imageWrapEl.transition(0);
if (swiper.rtl) image.startX = -image.startX;
if (swiper.rtl) image.startY = -image.startY;
}
// Define if we need image drag
const scaledWidth = image.width * zoom.scale;
const scaledHeight = image.height * zoom.scale;
if (scaledWidth < gesture.slideWidth && scaledHeight < gesture.slideHeight) return;
image.minX = Math.min(((gesture.slideWidth / 2) - (scaledWidth / 2)), 0);
image.maxX = -image.minX;
image.minY = Math.min(((gesture.slideHeight / 2) - (scaledHeight / 2)), 0);
image.maxY = -image.minY;
image.touchesCurrent.x = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
image.touchesCurrent.y = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (!image.isMoved && !zoom.isScaling) {
if (
swiper.isHorizontal() &&
(
(Math.floor(image.minX) === Math.floor(image.startX) && image.touchesCurrent.x < image.touchesStart.x) ||
(Math.floor(image.maxX) === Math.floor(image.startX) && image.touchesCurrent.x > image.touchesStart.x)
)
) {
image.isTouched = false;
return;
} else if (
!swiper.isHorizontal() &&
(
(Math.floor(image.minY) === Math.floor(image.startY) && image.touchesCurrent.y < image.touchesStart.y) ||
(Math.floor(image.maxY) === Math.floor(image.startY) && image.touchesCurrent.y > image.touchesStart.y)
)
) {
image.isTouched = false;
return;
}
}
e.preventDefault();
e.stopPropagation();
image.isMoved = true;
image.currentX = (image.touchesCurrent.x - image.touchesStart.x) + image.startX;
image.currentY = (image.touchesCurrent.y - image.touchesStart.y) + image.startY;
if (image.currentX < image.minX) {
image.currentX = (image.minX + 1) - (((image.minX - image.currentX) + 1) ** 0.8);
}
if (image.currentX > image.maxX) {
image.currentX = (image.maxX - 1) + (((image.currentX - image.maxX) + 1) ** 0.8);
}
if (image.currentY < image.minY) {
image.currentY = (image.minY + 1) - (((image.minY - image.currentY) + 1) ** 0.8);
}
if (image.currentY > image.maxY) {
image.currentY = (image.maxY - 1) + (((image.currentY - image.maxY) + 1) ** 0.8);
}
// Velocity
if (!velocity.prevPositionX) velocity.prevPositionX = image.touchesCurrent.x;
if (!velocity.prevPositionY) velocity.prevPositionY = image.touchesCurrent.y;
if (!velocity.prevTime) velocity.prevTime = Date.now();
velocity.x = (image.touchesCurrent.x - velocity.prevPositionX) / (Date.now() - velocity.prevTime) / 2;
velocity.y = (image.touchesCurrent.y - velocity.prevPositionY) / (Date.now() - velocity.prevTime) / 2;
if (Math.abs(image.touchesCurrent.x - velocity.prevPositionX) < 2) velocity.x = 0;
if (Math.abs(image.touchesCurrent.y - velocity.prevPositionY) < 2) velocity.y = 0;
velocity.prevPositionX = image.touchesCurrent.x;
velocity.prevPositionY = image.touchesCurrent.y;
velocity.prevTime = Date.now();
gesture.$imageWrapEl.transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);
},
onTouchEnd() {
const swiper = this;
const zoom = swiper.zoom;
const { gesture, image, velocity } = zoom;
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
if (!image.isTouched || !image.isMoved) {
image.isTouched = false;
image.isMoved = false;
return;
}
image.isTouched = false;
image.isMoved = false;
let momentumDurationX = 300;
let momentumDurationY = 300;
const momentumDistanceX = velocity.x * momentumDurationX;
const newPositionX = image.currentX + momentumDistanceX;
const momentumDistanceY = velocity.y * momentumDurationY;
const newPositionY = image.currentY + momentumDistanceY;
// Fix duration
if (velocity.x !== 0) momentumDurationX = Math.abs((newPositionX - image.currentX) / velocity.x);
if (velocity.y !== 0) momentumDurationY = Math.abs((newPositionY - image.currentY) / velocity.y);
const momentumDuration = Math.max(momentumDurationX, momentumDurationY);
image.currentX = newPositionX;
image.currentY = newPositionY;
// Define if we need image drag
const scaledWidth = image.width * zoom.scale;
const scaledHeight = image.height * zoom.scale;
image.minX = Math.min(((gesture.slideWidth / 2) - (scaledWidth / 2)), 0);
image.maxX = -image.minX;
image.minY = Math.min(((gesture.slideHeight / 2) - (scaledHeight / 2)), 0);
image.maxY = -image.minY;
image.currentX = Math.max(Math.min(image.currentX, image.maxX), image.minX);
image.currentY = Math.max(Math.min(image.currentY, image.maxY), image.minY);
gesture.$imageWrapEl.transition(momentumDuration).transform(`translate3d(${image.currentX}px, ${image.currentY}px,0)`);
},
onTransitionEnd() {
const swiper = this;
const zoom = swiper.zoom;
const { gesture } = zoom;
if (gesture.$slideEl && swiper.previousIndex !== swiper.activeIndex) {
gesture.$imageEl.transform('translate3d(0,0,0) scale(1)');
gesture.$imageWrapEl.transform('translate3d(0,0,0)');
gesture.$slideEl = undefined;
gesture.$imageEl = undefined;
gesture.$imageWrapEl = undefined;
zoom.scale = 1;
zoom.currentScale = 1;
}
},
// Toggle Zoom
toggle(e) {
const swiper = this;
const zoom = swiper.zoom;
if (zoom.scale && zoom.scale !== 1) {
// Zoom Out
zoom.out();
} else {
// Zoom In
zoom.in(e);
}
},
in(e) {
const swiper = this;
const zoom = swiper.zoom;
const params = swiper.params.zoom;
const { gesture, image } = zoom;
if (!gesture.$slideEl) {
gesture.$slideEl = swiper.clickedSlide ? $(swiper.clickedSlide) : swiper.slides.eq(swiper.activeIndex);
gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas');
gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
}
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
gesture.$slideEl.addClass(`${params.zoomedSlideClass}`);
let touchX;
let touchY;
let offsetX;
let offsetY;
let diffX;
let diffY;
let translateX;
let translateY;
let imageWidth;
let imageHeight;
let scaledWidth;
let scaledHeight;
let translateMinX;
let translateMinY;
let translateMaxX;
let translateMaxY;
let slideWidth;
let slideHeight;
if (typeof image.touchesStart.x === 'undefined' && e) {
touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX;
touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY;
} else {
touchX = image.touchesStart.x;
touchY = image.touchesStart.y;
}
zoom.scale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
zoom.currentScale = gesture.$imageWrapEl.attr('data-swiper-zoom') || params.maxRatio;
if (e) {
slideWidth = gesture.$slideEl[0].offsetWidth;
slideHeight = gesture.$slideEl[0].offsetHeight;
offsetX = gesture.$slideEl.offset().left;
offsetY = gesture.$slideEl.offset().top;
diffX = (offsetX + (slideWidth / 2)) - touchX;
diffY = (offsetY + (slideHeight / 2)) - touchY;
imageWidth = gesture.$imageEl[0].offsetWidth;
imageHeight = gesture.$imageEl[0].offsetHeight;
scaledWidth = imageWidth * zoom.scale;
scaledHeight = imageHeight * zoom.scale;
translateMinX = Math.min(((slideWidth / 2) - (scaledWidth / 2)), 0);
translateMinY = Math.min(((slideHeight / 2) - (scaledHeight / 2)), 0);
translateMaxX = -translateMinX;
translateMaxY = -translateMinY;
translateX = diffX * zoom.scale;
translateY = diffY * zoom.scale;
if (translateX < translateMinX) {
translateX = translateMinX;
}
if (translateX > translateMaxX) {
translateX = translateMaxX;
}
if (translateY < translateMinY) {
translateY = translateMinY;
}
if (translateY > translateMaxY) {
translateY = translateMaxY;
}
} else {
translateX = 0;
translateY = 0;
}
gesture.$imageWrapEl.transition(300).transform(`translate3d(${translateX}px, ${translateY}px,0)`);
gesture.$imageEl.transition(300).transform(`translate3d(0,0,0) scale(${zoom.scale})`);
},
out() {
const swiper = this;
const zoom = swiper.zoom;
const params = swiper.params.zoom;
const { gesture } = zoom;
if (!gesture.$slideEl) {
gesture.$slideEl = swiper.clickedSlide ? $(swiper.clickedSlide) : swiper.slides.eq(swiper.activeIndex);
gesture.$imageEl = gesture.$slideEl.find('img, svg, canvas');
gesture.$imageWrapEl = gesture.$imageEl.parent(`.${params.containerClass}`);
}
if (!gesture.$imageEl || gesture.$imageEl.length === 0) return;
zoom.scale = 1;
zoom.currentScale = 1;
gesture.$imageWrapEl.transition(300).transform('translate3d(0,0,0)');
gesture.$imageEl.transition(300).transform('translate3d(0,0,0) scale(1)');
gesture.$slideEl.removeClass(`${params.zoomedSlideClass}`);
gesture.$slideEl = undefined;
},
// Attach/Detach Events
enable() {
const swiper = this;
const zoom = swiper.zoom;
if (zoom.enabled) return;
zoom.enabled = true;
const slides = swiper.slides;
const passiveListener = swiper.touchEvents.start === 'touchstart' && Support$1.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false;
// Scale image
if (Support$1.gestures) {
slides.on('gesturestart', zoom.onGestureStart, passiveListener);
slides.on('gesturechange', zoom.onGestureChange, passiveListener);
slides.on('gestureend', zoom.onGestureEnd, passiveListener);
} else if (swiper.touchEvents.start === 'touchstart') {
slides.on(swiper.touchEvents.start, zoom.onGestureStart, passiveListener);
slides.on(swiper.touchEvents.move, zoom.onGestureChange, passiveListener);
slides.on(swiper.touchEvents.end, zoom.onGestureEnd, passiveListener);
}
// Move image
swiper.slides.each((index, slideEl) => {
const $slideEl = $(slideEl);
if ($slideEl.find(`.${swiper.params.zoom.containerClass}`).length > 0) {
$slideEl.on(swiper.touchEvents.move, zoom.onTouchMove);
}
});
},
disable() {
const swiper = this;
const zoom = swiper.zoom;
if (!zoom.enabled) return;
swiper.zoom.enabled = false;
const slides = swiper.slides;
const passiveListener = swiper.touchEvents.start === 'touchstart' && Support$1.passiveListener && swiper.params.passiveListeners ? { passive: true, capture: false } : false;
// Scale image
if (Support$1.gestures) {
slides.off('gesturestart', zoom.onGestureStart, passiveListener);
slides.off('gesturechange', zoom.onGestureChange, passiveListener);
slides.off('gestureend', zoom.onGestureEnd, passiveListener);
} else if (swiper.touchEvents.start === 'touchstart') {
slides.off(swiper.touchEvents.start, zoom.onGestureStart, passiveListener);
slides.off(swiper.touchEvents.move, zoom.onGestureChange, passiveListener);
slides.off(swiper.touchEvents.end, zoom.onGestureEnd, passiveListener);
}
// Move image
swiper.slides.each((index, slideEl) => {
const $slideEl = $(slideEl);
if ($slideEl.find(`.${swiper.params.zoom.containerClass}`).length > 0) {
$slideEl.off(swiper.touchEvents.move, zoom.onTouchMove);
}
});
},
};
var Zoom$1 = {
name: 'zoom',
params: {
zoom: {
enabled: false,
maxRatio: 3,
minRatio: 1,
toggle: true,
containerClass: 'swiper-zoom-container',
zoomedSlideClass: 'swiper-slide-zoomed',
},
},
create() {
const swiper = this;
const zoom = {
enabled: false,
scale: 1,
currentScale: 1,
isScaling: false,
gesture: {
$slideEl: undefined,
slideWidth: undefined,
slideHeight: undefined,
$imageEl: undefined,
$imageWrapEl: undefined,
maxRatio: 3,
},
image: {
isTouched: undefined,
isMoved: undefined,
currentX: undefined,
currentY: undefined,
minX: undefined,
minY: undefined,
maxX: undefined,
maxY: undefined,
width: undefined,
height: undefined,
startX: undefined,
startY: undefined,
touchesStart: {},
touchesCurrent: {},
},
velocity: {
x: undefined,
y: undefined,
prevPositionX: undefined,
prevPositionY: undefined,
prevTime: undefined,
},
};
('onGestureStart onGestureChange onGestureEnd onTouchStart onTouchMove onTouchEnd onTransitionEnd toggle enable disable in out').split(' ').forEach((methodName) => {
zoom[methodName] = Zoom[methodName].bind(swiper);
});
Utils.extend(swiper, {
zoom,
});
},
on: {
init() {
const swiper = this;
if (swiper.params.zoom.enabled) {
swiper.zoom.enable();
}
},
destroy() {
const swiper = this;
swiper.zoom.disable();
},
touchStart(e) {
const swiper = this;
if (!swiper.zoom.enabled) return;
swiper.zoom.onTouchStart(e);
},
touchEnd(e) {
const swiper = this;
if (!swiper.zoom.enabled) return;
swiper.zoom.onTouchEnd(e);
},
doubleTap(e) {
const swiper = this;
if (swiper.params.zoom.enabled && swiper.zoom.enabled && swiper.params.zoom.toggle) {
swiper.zoom.toggle(e);
}
},
transitionEnd() {
const swiper = this;
if (swiper.zoom.enabled && swiper.params.zoom.enabled) {
swiper.zoom.onTransitionEnd();
}
},
},
};
const Lazy$2 = {
loadInSlide(index, loadInDuplicate = true) {
const swiper = this;
const params = swiper.params.lazy;
if (typeof index === 'undefined') return;
if (swiper.slides.length === 0) return;
const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
const $slideEl = isVirtual
? swiper.$wrapperEl.children(`.${swiper.params.slideClass}[data-swiper-slide-index="${index}"]`)
: swiper.slides.eq(index);
let $images = $slideEl.find(`.${params.elementClass}:not(.${params.loadedClass}):not(.${params.loadingClass})`);
if ($slideEl.hasClass(params.elementClass) && !$slideEl.hasClass(params.loadedClass) && !$slideEl.hasClass(params.loadingClass)) {
$images = $images.add($slideEl[0]);
}
if ($images.length === 0) return;
$images.each((imageIndex, imageEl) => {
const $imageEl = $(imageEl);
$imageEl.addClass(params.loadingClass);
const background = $imageEl.attr('data-background');
const src = $imageEl.attr('data-src');
const srcset = $imageEl.attr('data-srcset');
const sizes = $imageEl.attr('data-sizes');
swiper.loadImage($imageEl[0], (src || background), srcset, sizes, false, () => {
if (typeof swiper === 'undefined' || swiper === null || !swiper || (swiper && !swiper.params) || swiper.destroyed) return;
if (background) {
$imageEl.css('background-image', `url("${background}")`);
$imageEl.removeAttr('data-background');
} else {
if (srcset) {
$imageEl.attr('srcset', srcset);
$imageEl.removeAttr('data-srcset');
}
if (sizes) {
$imageEl.attr('sizes', sizes);
$imageEl.removeAttr('data-sizes');
}
if (src) {
$imageEl.attr('src', src);
$imageEl.removeAttr('data-src');
}
}
$imageEl.addClass(params.loadedClass).removeClass(params.loadingClass);
$slideEl.find(`.${params.preloaderClass}`).remove();
if (swiper.params.loop && loadInDuplicate) {
const slideOriginalIndex = $slideEl.attr('data-swiper-slide-index');
if ($slideEl.hasClass(swiper.params.slideDuplicateClass)) {
const originalSlide = swiper.$wrapperEl.children(`[data-swiper-slide-index="${slideOriginalIndex}"]:not(.${swiper.params.slideDuplicateClass})`);
swiper.lazy.loadInSlide(originalSlide.index(), false);
} else {
const duplicatedSlide = swiper.$wrapperEl.children(`.${swiper.params.slideDuplicateClass}[data-swiper-slide-index="${slideOriginalIndex}"]`);
swiper.lazy.loadInSlide(duplicatedSlide.index(), false);
}
}
swiper.emit('lazyImageReady', $slideEl[0], $imageEl[0]);
});
swiper.emit('lazyImageLoad', $slideEl[0], $imageEl[0]);
});
},
load() {
const swiper = this;
const { $wrapperEl, params: swiperParams, slides, activeIndex } = swiper;
const isVirtual = swiper.virtual && swiperParams.virtual.enabled;
const params = swiperParams.lazy;
let slidesPerView = swiperParams.slidesPerView;
if (slidesPerView === 'auto') {
slidesPerView = 0;
}
function slideExist(index) {
if (isVirtual) {
if ($wrapperEl.children(`.${swiperParams.slideClass}[data-swiper-slide-index="${index}"]`).length) {
return true;
}
} else if (slides[index]) return true;
return false;
}
function slideIndex(slideEl) {
if (isVirtual) {
return $(slideEl).attr('data-swiper-slide-index');
}
return $(slideEl).index();
}
if (!swiper.lazy.initialImageLoaded) swiper.lazy.initialImageLoaded = true;
if (swiper.params.watchSlidesVisibility) {
$wrapperEl.children(`.${swiperParams.slideVisibleClass}`).each((elIndex, slideEl) => {
const index = isVirtual ? $(slideEl).attr('data-swiper-slide-index') : $(slideEl).index();
swiper.lazy.loadInSlide(index);
});
} else if (slidesPerView > 1) {
for (let i = activeIndex; i < activeIndex + slidesPerView; i += 1) {
if (slideExist(i)) swiper.lazy.loadInSlide(i);
}
} else {
swiper.lazy.loadInSlide(activeIndex);
}
if (params.loadPrevNext) {
if (slidesPerView > 1 || (params.loadPrevNextAmount && params.loadPrevNextAmount > 1)) {
const amount = params.loadPrevNextAmount;
const spv = slidesPerView;
const maxIndex = Math.min(activeIndex + spv + Math.max(amount, spv), slides.length);
const minIndex = Math.max(activeIndex - Math.max(spv, amount), 0);
// Next Slides
for (let i = activeIndex + slidesPerView; i < maxIndex; i += 1) {
if (slideExist(i)) swiper.lazy.loadInSlide(i);
}
// Prev Slides
for (let i = minIndex; i < activeIndex; i += 1) {
if (slideExist(i)) swiper.lazy.loadInSlide(i);
}
} else {
const nextSlide = $wrapperEl.children(`.${swiperParams.slideNextClass}`);
if (nextSlide.length > 0) swiper.lazy.loadInSlide(slideIndex(nextSlide));
const prevSlide = $wrapperEl.children(`.${swiperParams.slidePrevClass}`);
if (prevSlide.length > 0) swiper.lazy.loadInSlide(slideIndex(prevSlide));
}
}
},
};
var Lazy$3 = {
name: 'lazy',
params: {
lazy: {
enabled: false,
loadPrevNext: false,
loadPrevNextAmount: 1,
loadOnTransitionStart: false,
elementClass: 'swiper-lazy',
loadingClass: 'swiper-lazy-loading',
loadedClass: 'swiper-lazy-loaded',
preloaderClass: 'swiper-lazy-preloader',
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
lazy: {
initialImageLoaded: false,
load: Lazy$2.load.bind(swiper),
loadInSlide: Lazy$2.loadInSlide.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
if (swiper.params.lazy.enabled && swiper.params.preloadImages) {
swiper.params.preloadImages = false;
}
},
init() {
const swiper = this;
if (swiper.params.lazy.enabled && !swiper.params.loop && swiper.params.initialSlide === 0) {
swiper.lazy.load();
}
},
scroll() {
const swiper = this;
if (swiper.params.freeMode && !swiper.params.freeModeSticky) {
swiper.lazy.load();
}
},
resize() {
const swiper = this;
if (swiper.params.lazy.enabled) {
swiper.lazy.load();
}
},
scrollbarDragMove() {
const swiper = this;
if (swiper.params.lazy.enabled) {
swiper.lazy.load();
}
},
transitionStart() {
const swiper = this;
if (swiper.params.lazy.enabled) {
if (swiper.params.lazy.loadOnTransitionStart || (!swiper.params.lazy.loadOnTransitionStart && !swiper.lazy.initialImageLoaded)) {
swiper.lazy.load();
}
}
},
transitionEnd() {
const swiper = this;
if (swiper.params.lazy.enabled && !swiper.params.lazy.loadOnTransitionStart) {
swiper.lazy.load();
}
},
},
};
/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
const Controller = {
LinearSpline(x, y) {
const binarySearch = (function search() {
let maxIndex;
let minIndex;
let guess;
return (array, val) => {
minIndex = -1;
maxIndex = array.length;
while (maxIndex - minIndex > 1) {
guess = maxIndex + minIndex >> 1;
if (array[guess] <= val) {
minIndex = guess;
} else {
maxIndex = guess;
}
}
return maxIndex;
};
}());
this.x = x;
this.y = y;
this.lastIndex = x.length - 1;
// Given an x value (x2), return the expected y2 value:
// (x1,y1) is the known point before given value,
// (x3,y3) is the known point after given value.
let i1;
let i3;
this.interpolate = function interpolate(x2) {
if (!x2) return 0;
// Get the indexes of x1 and x3 (the array indexes before and after given x2):
i3 = binarySearch(this.x, x2);
i1 = i3 - 1;
// We have our indexes i1 & i3, so we can calculate already:
// y2 := ((x2−x1) × (y3−y1)) ÷ (x3−x1) + y1
return (((x2 - this.x[i1]) * (this.y[i3] - this.y[i1])) / (this.x[i3] - this.x[i1])) + this.y[i1];
};
return this;
},
// xxx: for now i will just save one spline function to to
getInterpolateFunction(c) {
const swiper = this;
if (!swiper.controller.spline) {
swiper.controller.spline = swiper.params.loop ?
new Controller.LinearSpline(swiper.slidesGrid, c.slidesGrid) :
new Controller.LinearSpline(swiper.snapGrid, c.snapGrid);
}
},
setTranslate(setTranslate, byController) {
const swiper = this;
const controlled = swiper.controller.control;
let multiplier;
let controlledTranslate;
function setControlledTranslate(c) {
// this will create an Interpolate function based on the snapGrids
// x is the Grid of the scrolled scroller and y will be the controlled scroller
// it makes sense to create this only once and recall it for the interpolation
// the function does a lot of value caching for performance
const translate = c.rtl && c.params.direction === 'horizontal' ? -swiper.translate : swiper.translate;
if (swiper.params.controller.by === 'slide') {
swiper.controller.getInterpolateFunction(c);
// i am not sure why the values have to be multiplicated this way, tried to invert the snapGrid
// but it did not work out
controlledTranslate = -swiper.controller.spline.interpolate(-translate);
}
if (!controlledTranslate || swiper.params.controller.by === 'container') {
multiplier = (c.maxTranslate() - c.minTranslate()) / (swiper.maxTranslate() - swiper.minTranslate());
controlledTranslate = ((translate - swiper.minTranslate()) * multiplier) + c.minTranslate();
}
if (swiper.params.controller.inverse) {
controlledTranslate = c.maxTranslate() - controlledTranslate;
}
c.updateProgress(controlledTranslate);
c.setTranslate(controlledTranslate, swiper);
c.updateActiveIndex();
c.updateSlidesClasses();
}
if (Array.isArray(controlled)) {
for (let i = 0; i < controlled.length; i += 1) {
if (controlled[i] !== byController && controlled[i] instanceof Swiper$2) {
setControlledTranslate(controlled[i]);
}
}
} else if (controlled instanceof Swiper$2 && byController !== controlled) {
setControlledTranslate(controlled);
}
},
setTransition(duration, byController) {
const swiper = this;
const controlled = swiper.controller.control;
let i;
function setControlledTransition(c) {
c.setTransition(duration, swiper);
if (duration !== 0) {
c.transitionStart();
c.$wrapperEl.transitionEnd(() => {
if (!controlled) return;
if (c.params.loop && swiper.params.controller.by === 'slide') {
c.loopFix();
}
c.transitionEnd();
});
}
}
if (Array.isArray(controlled)) {
for (i = 0; i < controlled.length; i += 1) {
if (controlled[i] !== byController && controlled[i] instanceof Swiper$2) {
setControlledTransition(controlled[i]);
}
}
} else if (controlled instanceof Swiper$2 && byController !== controlled) {
setControlledTransition(controlled);
}
},
};
var Controller$1 = {
name: 'controller',
params: {
controller: {
control: undefined,
inverse: false,
by: 'slide', // or 'container'
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
controller: {
control: swiper.params.controller.control,
getInterpolateFunction: Controller.getInterpolateFunction.bind(swiper),
setTranslate: Controller.setTranslate.bind(swiper),
setTransition: Controller.setTransition.bind(swiper),
},
});
},
on: {
update() {
const swiper = this;
if (!swiper.controller.control) return;
if (swiper.controller.spline) {
swiper.controller.spline = undefined;
delete swiper.controller.spline;
}
},
resize() {
const swiper = this;
if (!swiper.controller.control) return;
if (swiper.controller.spline) {
swiper.controller.spline = undefined;
delete swiper.controller.spline;
}
},
observerUpdate() {
const swiper = this;
if (!swiper.controller.control) return;
if (swiper.controller.spline) {
swiper.controller.spline = undefined;
delete swiper.controller.spline;
}
},
setTranslate(translate, byController) {
const swiper = this;
if (!swiper.controller.control) return;
swiper.controller.setTranslate(translate, byController);
},
setTransition(duration, byController) {
const swiper = this;
if (!swiper.controller.control) return;
swiper.controller.setTransition(duration, byController);
},
},
};
const a11y = {
makeElFocusable($el) {
$el.attr('tabIndex', '0');
return $el;
},
addElRole($el, role) {
$el.attr('role', role);
return $el;
},
addElLabel($el, label) {
$el.attr('aria-label', label);
return $el;
},
disableEl($el) {
$el.attr('aria-disabled', true);
return $el;
},
enableEl($el) {
$el.attr('aria-disabled', false);
return $el;
},
onEnterKey(e) {
const swiper = this;
const params = swiper.params.a11y;
if (e.keyCode !== 13) return;
const $targetEl = $(e.target);
if (swiper.navigation && swiper.navigation.$nextEl && $targetEl.is(swiper.navigation.$nextEl)) {
if (!(swiper.isEnd && !swiper.params.loop)) {
swiper.slideNext();
}
if (swiper.isEnd) {
swiper.a11y.notify(params.lastSlideMessage);
} else {
swiper.a11y.notify(params.nextSlideMessage);
}
}
if (swiper.navigation && swiper.navigation.$prevEl && $targetEl.is(swiper.navigation.$prevEl)) {
if (!(swiper.isBeginning && !swiper.params.loop)) {
swiper.slidePrev();
}
if (swiper.isBeginning) {
swiper.a11y.notify(params.firstSlideMessage);
} else {
swiper.a11y.notify(params.prevSlideMessage);
}
}
if (swiper.pagination && $targetEl.is(`.${swiper.params.pagination.bulletClass}`)) {
$targetEl[0].click();
}
},
notify(message) {
const swiper = this;
const notification = swiper.a11y.liveRegion;
if (notification.length === 0) return;
notification.html('');
notification.html(message);
},
updateNavigation() {
const swiper = this;
if (swiper.params.loop) return;
const { $nextEl, $prevEl } = swiper.navigation;
if ($prevEl && $prevEl.length > 0) {
if (swiper.isBeginning) {
swiper.a11y.disableEl($prevEl);
} else {
swiper.a11y.enableEl($prevEl);
}
}
if ($nextEl && $nextEl.length > 0) {
if (swiper.isEnd) {
swiper.a11y.disableEl($nextEl);
} else {
swiper.a11y.enableEl($nextEl);
}
}
},
updatePagination() {
const swiper = this;
const params = swiper.params.a11y;
if (swiper.pagination && swiper.params.pagination.clickable && swiper.pagination.bullets && swiper.pagination.bullets.length) {
swiper.pagination.bullets.each((bulletIndex, bulletEl) => {
const $bulletEl = $(bulletEl);
swiper.a11y.makeElFocusable($bulletEl);
swiper.a11y.addElRole($bulletEl, 'button');
swiper.a11y.addElLabel($bulletEl, params.paginationBulletMessage.replace(/{{index}}/, $bulletEl.index() + 1));
});
}
},
init() {
const swiper = this;
swiper.$el.append(swiper.a11y.liveRegion);
// Navigation
const params = swiper.params.a11y;
let $nextEl;
let $prevEl;
if (swiper.navigation && swiper.navigation.$nextEl) {
$nextEl = swiper.navigation.$nextEl;
}
if (swiper.navigation && swiper.navigation.$prevEl) {
$prevEl = swiper.navigation.$prevEl;
}
if ($nextEl) {
swiper.a11y.makeElFocusable($nextEl);
swiper.a11y.addElRole($nextEl, 'button');
swiper.a11y.addElLabel($nextEl, params.nextSlideMessage);
$nextEl.on('keydown', swiper.a11y.onEnterKey);
}
if ($prevEl) {
swiper.a11y.makeElFocusable($prevEl);
swiper.a11y.addElRole($prevEl, 'button');
swiper.a11y.addElLabel($prevEl, params.prevSlideMessage);
$prevEl.on('keydown', swiper.a11y.onEnterKey);
}
// Pagination
if (swiper.pagination && swiper.params.pagination.clickable && swiper.pagination.bullets && swiper.pagination.bullets.length) {
swiper.pagination.$el.on('keydown', `.${swiper.params.pagination.bulletClass}`, swiper.a11y.onEnterKey);
}
},
destroy() {
const swiper = this;
if (swiper.a11y.liveRegion && swiper.a11y.liveRegion.length > 0) swiper.a11y.liveRegion.remove();
let $nextEl;
let $prevEl;
if (swiper.navigation && swiper.navigation.$nextEl) {
$nextEl = swiper.navigation.$nextEl;
}
if (swiper.navigation && swiper.navigation.$prevEl) {
$prevEl = swiper.navigation.$prevEl;
}
if ($nextEl) {
$nextEl.off('keydown', swiper.a11y.onEnterKey);
}
if ($prevEl) {
$prevEl.off('keydown', swiper.a11y.onEnterKey);
}
// Pagination
if (swiper.pagination && swiper.params.pagination.clickable && swiper.pagination.bullets && swiper.pagination.bullets.length) {
swiper.pagination.$el.off('keydown', `.${swiper.params.pagination.bulletClass}`, swiper.a11y.onEnterKey);
}
},
};
var A11y = {
name: 'a11y',
params: {
a11y: {
enabled: false,
notificationClass: 'swiper-notification',
prevSlideMessage: 'Previous slide',
nextSlideMessage: 'Next slide',
firstSlideMessage: 'This is the first slide',
lastSlideMessage: 'This is the last slide',
paginationBulletMessage: 'Go to slide {{index}}',
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
a11y: {
liveRegion: $(`<span class="${swiper.params.a11y.notificationClass}" aria-live="assertive" aria-atomic="true"></span>`),
},
});
Object.keys(a11y).forEach((methodName) => {
swiper.a11y[methodName] = a11y[methodName].bind(swiper);
});
},
on: {
init() {
const swiper = this;
if (!swiper.params.a11y.enabled) return;
swiper.a11y.init();
swiper.a11y.updateNavigation();
},
toEdge() {
const swiper = this;
if (!swiper.params.a11y.enabled) return;
swiper.a11y.updateNavigation();
},
fromEdge() {
const swiper = this;
if (!swiper.params.a11y.enabled) return;
swiper.a11y.updateNavigation();
},
paginationUpdate() {
const swiper = this;
if (!swiper.params.a11y.enabled) return;
swiper.a11y.updatePagination();
},
destroy() {
const swiper = this;
if (!swiper.params.a11y.enabled) return;
swiper.a11y.destroy();
},
},
};
const Autoplay = {
run() {
const swiper = this;
const $activeSlideEl = swiper.slides.eq(swiper.activeIndex);
let delay = swiper.params.autoplay.delay;
if ($activeSlideEl.attr('data-swiper-autoplay')) {
delay = $activeSlideEl.attr('data-swiper-autoplay') || swiper.params.autoplay.delay;
}
swiper.autoplay.timeout = Utils.nextTick(() => {
if (swiper.params.loop) {
swiper.loopFix();
swiper.slideNext(swiper.params.speed, true, true);
swiper.emit('autoplay');
} else if (!swiper.isEnd) {
swiper.slideNext(swiper.params.speed, true, true);
swiper.emit('autoplay');
} else if (!swiper.params.autoplay.stopOnLastSlide) {
swiper.slideTo(0, swiper.params.speed, true, true);
swiper.emit('autoplay');
} else {
swiper.autoplay.stop();
}
}, delay);
},
start() {
const swiper = this;
if (typeof swiper.autoplay.timeout !== 'undefined') return false;
if (swiper.autoplay.running) return false;
swiper.autoplay.running = true;
swiper.emit('autoplayStart');
swiper.autoplay.run();
return true;
},
stop() {
const swiper = this;
if (!swiper.autoplay.running) return false;
if (typeof swiper.autoplay.timeout === 'undefined') return false;
if (swiper.autoplay.timeout) {
clearTimeout(swiper.autoplay.timeout);
swiper.autoplay.timeout = undefined;
}
swiper.autoplay.running = false;
swiper.emit('autoplayStop');
return true;
},
pause(speed) {
const swiper = this;
if (!swiper.autoplay.running) return;
if (swiper.autoplay.paused) return;
if (swiper.autoplay.timeout) clearTimeout(swiper.autoplay.timeout);
swiper.autoplay.paused = true;
if (speed === 0) {
swiper.autoplay.paused = false;
swiper.autoplay.run();
} else {
swiper.$wrapperEl.transitionEnd(() => {
if (!swiper || swiper.destroyed) return;
swiper.autoplay.paused = false;
if (!swiper.autoplay.running) {
swiper.autoplay.stop();
} else {
swiper.autoplay.run();
}
});
}
},
};
var Autoplay$1 = {
name: 'autoplay',
params: {
autoplay: {
enabled: false,
delay: 3000,
disableOnInteraction: true,
stopOnLastSlide: false,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
autoplay: {
running: false,
paused: false,
run: Autoplay.run.bind(swiper),
start: Autoplay.start.bind(swiper),
stop: Autoplay.stop.bind(swiper),
pause: Autoplay.pause.bind(swiper),
},
});
},
on: {
init() {
const swiper = this;
if (swiper.params.autoplay.enabled) {
swiper.autoplay.start();
}
},
beforeTransitionStart(speed, internal) {
const swiper = this;
if (swiper.autoplay.running) {
if (internal || !swiper.params.autoplay.disableOnInteraction) {
swiper.autoplay.pause(speed);
} else {
swiper.autoplay.stop();
}
}
},
sliderFirstMove() {
const swiper = this;
if (swiper.autoplay.running) {
if (swiper.params.autoplay.disableOnInteraction) {
swiper.autoplay.stop();
} else {
swiper.autoplay.pause();
}
}
},
destroy() {
const swiper = this;
if (swiper.autoplay.running) {
swiper.autoplay.stop();
}
},
},
};
const Fade = {
setTranslate() {
const swiper = this;
const { slides } = swiper;
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = swiper.slides.eq(i);
const offset = $slideEl[0].swiperSlideOffset;
let tx = -offset;
if (!swiper.params.virtualTranslate) tx -= swiper.translate;
let ty = 0;
if (!swiper.isHorizontal()) {
ty = tx;
tx = 0;
}
const slideOpacity = swiper.params.fadeEffect.crossFade ?
Math.max(1 - Math.abs($slideEl[0].progress), 0) :
1 + Math.min(Math.max($slideEl[0].progress, -1), 0);
$slideEl
.css({
opacity: slideOpacity,
})
.transform(`translate3d(${tx}px, ${ty}px, 0px)`);
}
},
setTransition(duration) {
const swiper = this;
const { slides, $wrapperEl } = swiper;
slides.transition(duration);
if (swiper.params.virtualTranslate && duration !== 0) {
let eventTriggered = false;
slides.transitionEnd(() => {
if (eventTriggered) return;
if (!swiper || swiper.destroyed) return;
eventTriggered = true;
swiper.animating = false;
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
for (let i = 0; i < triggerEvents.length; i += 1) {
$wrapperEl.trigger(triggerEvents[i]);
}
});
}
},
};
var EffectFade = {
name: 'effect-fade',
params: {
fadeEffect: {
crossFade: false,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
fadeEffect: {
setTranslate: Fade.setTranslate.bind(swiper),
setTransition: Fade.setTransition.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
if (swiper.params.effect !== 'fade') return;
swiper.classNames.push(`${swiper.params.containerModifierClass}fade`);
const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
spaceBetween: 0,
virtualTranslate: true,
};
Utils.extend(swiper.params, overwriteParams);
Utils.extend(swiper.originalParams, overwriteParams);
},
setTranslate() {
const swiper = this;
if (swiper.params.effect !== 'fade') return;
swiper.fadeEffect.setTranslate();
},
setTransition(duration) {
const swiper = this;
if (swiper.params.effect !== 'fade') return;
swiper.fadeEffect.setTransition(duration);
},
},
};
const Cube = {
setTranslate() {
const swiper = this;
const { $el, $wrapperEl, slides, width: swiperWidth, height: swiperHeight, rtl, size: swiperSize } = swiper;
const params = swiper.params.cubeEffect;
const isHorizontal = swiper.isHorizontal();
const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
let wrapperRotate = 0;
let $cubeShadowEl;
if (params.shadow) {
if (isHorizontal) {
$cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow');
if ($cubeShadowEl.length === 0) {
$cubeShadowEl = $('<div class="swiper-cube-shadow"></div>');
$wrapperEl.append($cubeShadowEl);
}
$cubeShadowEl.css({ height: `${swiperWidth}px` });
} else {
$cubeShadowEl = $el.find('.swiper-cube-shadow');
if ($cubeShadowEl.length === 0) {
$cubeShadowEl = $('<div class="swiper-cube-shadow"></div>');
$el.append($cubeShadowEl);
}
}
}
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = slides.eq(i);
let slideIndex = i;
if (isVirtual) {
slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10);
}
let slideAngle = slideIndex * 90;
let round = Math.floor(slideAngle / 360);
if (rtl) {
slideAngle = -slideAngle;
round = Math.floor(-slideAngle / 360);
}
const progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
let tx = 0;
let ty = 0;
let tz = 0;
if (slideIndex % 4 === 0) {
tx = -round * 4 * swiperSize;
tz = 0;
} else if ((slideIndex - 1) % 4 === 0) {
tx = 0;
tz = -round * 4 * swiperSize;
} else if ((slideIndex - 2) % 4 === 0) {
tx = swiperSize + (round * 4 * swiperSize);
tz = swiperSize;
} else if ((slideIndex - 3) % 4 === 0) {
tx = -swiperSize;
tz = (3 * swiperSize) + (swiperSize * 4 * round);
}
if (rtl) {
tx = -tx;
}
if (!isHorizontal) {
ty = tx;
tx = 0;
}
const transform = `rotateX(${isHorizontal ? 0 : -slideAngle}deg) rotateY(${isHorizontal ? slideAngle : 0}deg) translate3d(${tx}px, ${ty}px, ${tz}px)`;
if (progress <= 1 && progress > -1) {
wrapperRotate = (slideIndex * 90) + (progress * 90);
if (rtl) wrapperRotate = (-slideIndex * 90) - (progress * 90);
}
$slideEl.transform(transform);
if (params.slideShadows) {
// Set shadows
let shadowBefore = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');
let shadowAfter = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');
if (shadowBefore.length === 0) {
shadowBefore = $(`<div class="swiper-slide-shadow-${isHorizontal ? 'left' : 'top'}"></div>`);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = $(`<div class="swiper-slide-shadow-${isHorizontal ? 'right' : 'bottom'}"></div>`);
$slideEl.append(shadowAfter);
}
if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
}
}
$wrapperEl.css({
'-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`,
'-moz-transform-origin': `50% 50% -${swiperSize / 2}px`,
'-ms-transform-origin': `50% 50% -${swiperSize / 2}px`,
'transform-origin': `50% 50% -${swiperSize / 2}px`,
});
if (params.shadow) {
if (isHorizontal) {
$cubeShadowEl.transform(`translate3d(0px, ${(swiperWidth / 2) + params.shadowOffset}px, ${-swiperWidth / 2}px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})`);
} else {
const shadowAngle = Math.abs(wrapperRotate) - (Math.floor(Math.abs(wrapperRotate) / 90) * 90);
const multiplier = 1.5 - (
(Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2) +
(Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2)
);
const scale1 = params.shadowScale;
const scale2 = params.shadowScale / multiplier;
const offset = params.shadowOffset;
$cubeShadowEl.transform(`scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${(swiperHeight / 2) + offset}px, ${-swiperHeight / 2 / scale2}px) rotateX(-90deg)`);
}
}
const zFactor = (Browser.isSafari || Browser.isUiWebView) ? (-swiperSize / 2) : 0;
$wrapperEl
.transform(`translate3d(0px,0,${zFactor}px) rotateX(${swiper.isHorizontal() ? 0 : wrapperRotate}deg) rotateY(${swiper.isHorizontal() ? -wrapperRotate : 0}deg)`);
},
setTransition(duration) {
const swiper = this;
const { $el, slides } = swiper;
slides
.transition(duration)
.find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left')
.transition(duration);
if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) {
$el.find('.swiper-cube-shadow').transition(duration);
}
},
};
var EffectCube = {
name: 'effect-cube',
params: {
cubeEffect: {
slideShadows: true,
shadow: true,
shadowOffset: 20,
shadowScale: 0.94,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
cubeEffect: {
setTranslate: Cube.setTranslate.bind(swiper),
setTransition: Cube.setTransition.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
if (swiper.params.effect !== 'cube') return;
swiper.classNames.push(`${swiper.params.containerModifierClass}cube`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
resistanceRatio: 0,
spaceBetween: 0,
centeredSlides: false,
virtualTranslate: true,
};
Utils.extend(swiper.params, overwriteParams);
Utils.extend(swiper.originalParams, overwriteParams);
},
setTranslate() {
const swiper = this;
if (swiper.params.effect !== 'cube') return;
swiper.cubeEffect.setTranslate();
},
setTransition(duration) {
const swiper = this;
if (swiper.params.effect !== 'cube') return;
swiper.cubeEffect.setTransition(duration);
},
},
};
const Flip = {
setTranslate() {
const swiper = this;
const { slides } = swiper;
for (let i = 0; i < slides.length; i += 1) {
const $slideEl = slides.eq(i);
let progress = $slideEl[0].progress;
if (swiper.params.flipEffect.limitRotation) {
progress = Math.max(Math.min($slideEl[0].progress, 1), -1);
}
const offset = $slideEl[0].swiperSlideOffset;
const rotate = -180 * progress;
let rotateY = rotate;
let rotateX = 0;
let tx = -offset;
let ty = 0;
if (!swiper.isHorizontal()) {
ty = tx;
tx = 0;
rotateX = -rotateY;
rotateY = 0;
} else if (swiper.rtl) {
rotateY = -rotateY;
}
$slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length;
if (swiper.params.flipEffect.slideShadows) {
// Set shadows
let shadowBefore = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');
let shadowAfter = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');
if (shadowBefore.length === 0) {
shadowBefore = $(`<div class="swiper-slide-shadow-${swiper.isHorizontal() ? 'left' : 'top'}"></div>`);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = $(`<div class="swiper-slide-shadow-${swiper.isHorizontal() ? 'right' : 'bottom'}"></div>`);
$slideEl.append(shadowAfter);
}
if (shadowBefore.length) shadowBefore[0].style.opacity = Math.max(-progress, 0);
if (shadowAfter.length) shadowAfter[0].style.opacity = Math.max(progress, 0);
}
$slideEl
.transform(`translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`);
}
},
setTransition(duration) {
const swiper = this;
const { slides, activeIndex, $wrapperEl } = swiper;
slides
.transition(duration)
.find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left')
.transition(duration);
if (swiper.params.virtualTranslate && duration !== 0) {
let eventTriggered = false;
// eslint-disable-next-line
slides.eq(activeIndex).transitionEnd(function onTransitionEnd() {
if (eventTriggered) return;
if (!swiper || swiper.destroyed) return;
// if (!$(this).hasClass(swiper.params.slideActiveClass)) return;
eventTriggered = true;
swiper.animating = false;
const triggerEvents = ['webkitTransitionEnd', 'transitionend'];
for (let i = 0; i < triggerEvents.length; i += 1) {
$wrapperEl.trigger(triggerEvents[i]);
}
});
}
},
};
var EffectFlip = {
name: 'effect-flip',
params: {
flipEffect: {
slideShadows: true,
limitRotation: true,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
flipEffect: {
setTranslate: Flip.setTranslate.bind(swiper),
setTransition: Flip.setTransition.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
if (swiper.params.effect !== 'flip') return;
swiper.classNames.push(`${swiper.params.containerModifierClass}flip`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
const overwriteParams = {
slidesPerView: 1,
slidesPerColumn: 1,
slidesPerGroup: 1,
watchSlidesProgress: true,
spaceBetween: 0,
virtualTranslate: true,
};
Utils.extend(swiper.params, overwriteParams);
Utils.extend(swiper.originalParams, overwriteParams);
},
setTranslate() {
const swiper = this;
if (swiper.params.effect !== 'flip') return;
swiper.flipEffect.setTranslate();
},
setTransition(duration) {
const swiper = this;
if (swiper.params.effect !== 'flip') return;
swiper.flipEffect.setTransition(duration);
},
},
};
const Coverflow = {
setTranslate() {
const swiper = this;
const { width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid } = swiper;
const params = swiper.params.coverflowEffect;
const isHorizontal = swiper.isHorizontal();
const transform = swiper.translate;
const center = isHorizontal ? -transform + (swiperWidth / 2) : -transform + (swiperHeight / 2);
const rotate = isHorizontal ? params.rotate : -params.rotate;
const translate = params.depth;
// Each slide offset from center
for (let i = 0, length = slides.length; i < length; i += 1) {
const $slideEl = slides.eq(i);
const slideSize = slidesSizesGrid[i];
const slideOffset = $slideEl[0].swiperSlideOffset;
const offsetMultiplier = ((center - slideOffset - (slideSize / 2)) / slideSize) * params.modifier;
let rotateY = isHorizontal ? rotate * offsetMultiplier : 0;
let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier;
// var rotateZ = 0
let translateZ = -translate * Math.abs(offsetMultiplier);
let translateY = isHorizontal ? 0 : params.stretch * (offsetMultiplier);
let translateX = isHorizontal ? params.stretch * (offsetMultiplier) : 0;
// Fix for ultra small values
if (Math.abs(translateX) < 0.001) translateX = 0;
if (Math.abs(translateY) < 0.001) translateY = 0;
if (Math.abs(translateZ) < 0.001) translateZ = 0;
if (Math.abs(rotateY) < 0.001) rotateY = 0;
if (Math.abs(rotateX) < 0.001) rotateX = 0;
const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
$slideEl.transform(slideTransform);
$slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
if (params.slideShadows) {
// Set shadows
let $shadowBeforeEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');
let $shadowAfterEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');
if ($shadowBeforeEl.length === 0) {
$shadowBeforeEl = $(`<div class="swiper-slide-shadow-${isHorizontal ? 'left' : 'top'}"></div>`);
$slideEl.append($shadowBeforeEl);
}
if ($shadowAfterEl.length === 0) {
$shadowAfterEl = $(`<div class="swiper-slide-shadow-${isHorizontal ? 'right' : 'bottom'}"></div>`);
$slideEl.append($shadowAfterEl);
}
if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;
if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = (-offsetMultiplier) > 0 ? -offsetMultiplier : 0;
}
}
// Set correct perspective for IE10
if (Browser.ie) {
const ws = $wrapperEl[0].style;
ws.perspectiveOrigin = `${center}px 50%`;
}
},
setTransition(duration) {
const swiper = this;
swiper.slides
.transition(duration)
.find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left')
.transition(duration);
},
};
var EffectCoverflow = {
name: 'effect-coverflow',
params: {
coverflowEffect: {
rotate: 50,
stretch: 0,
depth: 100,
modifier: 1,
slideShadows: true,
},
},
create() {
const swiper = this;
Utils.extend(swiper, {
coverflowEffect: {
setTranslate: Coverflow.setTranslate.bind(swiper),
setTransition: Coverflow.setTransition.bind(swiper),
},
});
},
on: {
beforeInit() {
const swiper = this;
if (swiper.params.effect !== 'coverflow') return;
swiper.classNames.push(`${swiper.params.containerModifierClass}coverflow`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
swiper.params.watchSlidesProgress = true;
swiper.originalParams.watchSlidesProgress = true;
},
setTranslate() {
const swiper = this;
if (swiper.params.effect !== 'coverflow') return;
swiper.coverflowEffect.setTranslate();
},
setTransition(duration) {
const swiper = this;
if (swiper.params.effect !== 'coverflow') return;
swiper.coverflowEffect.setTransition(duration);
},
},
};
// Swiper Class
// Core Modules
// Components
Swiper$2.use([
Device$4,
Browser$2,
Support$4,
Resize$1,
Observer$1,
Virtual$1,
Navigation$1,
Pagination$1,
Scrollbar$1,
Parallax$1,
Zoom$1,
Lazy$3,
Controller$1,
A11y,
Autoplay$1,
EffectFade,
EffectCube,
EffectFlip,
EffectCoverflow,
]);
function initSwipers(swiperEl) {
const app = this;
const $swiperEl = $(swiperEl);
if ($swiperEl.length === 0) return;
if ($swiperEl[0].swiper) return;
let initialSlide;
let params = {};
let isTabs;
let isRoutableTabs;
if ($swiperEl.hasClass('tabs-swipeable-wrap')) {
$swiperEl
.addClass('swiper-container')
.children('.tabs')
.addClass('swiper-wrapper')
.children('.tab')
.addClass('swiper-slide');
initialSlide = $swiperEl.children('.tabs').children('.tab-active').index();
isTabs = true;
isRoutableTabs = $swiperEl.find('.tabs-routable').length > 0;
}
if ($swiperEl.attr('data-swiper')) {
params = JSON.parse($swiperEl.attr('data-swiper'));
} else {
params = $swiperEl.dataset();
Object.keys(params).forEach((key) => {
const value = params[key];
if (typeof value === 'string' && value.indexOf('{') === 0 && value.indexOf('}') > 0) {
try {
params[key] = JSON.parse(value);
} catch (e) {
// not JSON
}
}
});
}
if (typeof params.initialSlide === 'undefined' && typeof initialSlide !== 'undefined') {
params.initialSlide = initialSlide;
}
const swiper = app.swiper.create($swiperEl[0], params);
if (isTabs) {
swiper.on('slideChange', () => {
if (isRoutableTabs) {
let view = app.views.get($swiperEl.parents('.view'));
if (!view) view = app.views.main;
const router = view.router;
const tabRoute = router.findTabRoute(swiper.slides.eq(swiper.activeIndex)[0]);
if (tabRoute) router.navigate(tabRoute.path);
} else {
app.tab.show({
tabEl: swiper.slides.eq(swiper.activeIndex),
});
}
});
}
}
var Swiper = {
name: 'swiper',
static: {
Swiper: Swiper$2,
},
create() {
const app = this;
app.swiper = ConstructorMethods({
defaultSelector: '.swiper-container',
constructor: Swiper$2,
domProp: 'swiper',
});
},
on: {
pageBeforeRemove(page) {
const app = this;
page.$el.find('.swiper-init, .tabs-swipeable-wrap').each((index, swiperEl) => {
app.swiper.destroy(swiperEl);
});
},
pageMounted(page) {
const app = this;
page.$el.find('.tabs-swipeable-wrap').each((index, swiperEl) => {
initSwipers.call(app, swiperEl);
});
},
pageInit(page) {
const app = this;
page.$el.find('.swiper-init, .tabs-swipeable-wrap').each((index, swiperEl) => {
initSwipers.call(app, swiperEl);
});
},
pageReinit(page) {
const app = this;
page.$el.find('.swiper-init, .tabs-swipeable-wrap').each((index, swiperEl) => {
const swiper = app.swiper.get(swiperEl);
if (swiper && swiper.update) swiper.update();
});
},
},
};
/* eslint indent: ["off"] */
class PhotoBrowser$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const pb = this;
pb.app = app;
const defaults = Utils.extend({
on: {},
}, app.params.photoBrowser);
// Extend defaults with modules params
pb.useModulesParams(defaults);
pb.params = Utils.extend(defaults, params);
Utils.extend(pb, {
exposed: false,
opened: false,
activeIndex: pb.params.swiper.initialSlide,
url: pb.params.url,
view: pb.params.view || app.views.main,
swipeToClose: {
allow: true,
isTouched: false,
diff: undefined,
start: undefined,
current: undefined,
started: false,
activeSlide: undefined,
timeStart: undefined,
},
});
// Install Modules
pb.useModules();
// Init
pb.init();
}
onSlideChange(swiper) {
const pb = this;
pb.activeIndex = swiper.activeIndex;
let current = swiper.activeIndex + 1;
let total = pb.params.virtualSlides ? pb.params.photos.length : swiper.slides.length;
if (swiper.params.loop) {
total -= 2;
current -= swiper.loopedSlides;
if (current < 1) current = total + current;
if (current > total) current -= total;
}
const $activeSlideEl = pb.params.virtualSlides
? swiper.$wrapperEl.find(`.swiper-slide[data-swiper-slide-index="${swiper.activeIndex}"]`)
: swiper.slides.eq(swiper.activeIndex);
const $previousSlideEl = pb.params.virtualSlides
? swiper.$wrapperEl.find(`.swiper-slide[data-swiper-slide-index="${swiper.previousIndex}"]`)
: swiper.slides.eq(swiper.previousIndex);
let $currentEl = pb.$el.find('.photo-browser-current');
let $totalEl = pb.$el.find('.photo-browser-total');
if (pb.params.type === 'page' && pb.params.navbar && $currentEl.length === 0 && pb.app.theme === 'ios') {
const navbarEl = pb.app.navbar.getElByPage(pb.$el);
if (navbarEl) {
$currentEl = $(navbarEl).find('.photo-browser-current');
$totalEl = $(navbarEl).find('.photo-browser-total');
}
}
$currentEl.text(current);
$totalEl.text(total);
// Update captions
if (pb.captions.length > 0) {
const captionIndex = swiper.params.loop ? $activeSlideEl.attr('data-swiper-slide-index') : pb.activeIndex;
pb.$captionsContainerEl.find('.photo-browser-caption-active').removeClass('photo-browser-caption-active');
pb.$captionsContainerEl.find(`[data-caption-index="${captionIndex}"]`).addClass('photo-browser-caption-active');
}
// Stop Video
const previousSlideVideo = $previousSlideEl.find('video');
if (previousSlideVideo.length > 0) {
if ('pause' in previousSlideVideo[0]) previousSlideVideo[0].pause();
}
}
onTouchStart() {
const pb = this;
const swipeToClose = pb.swipeToClose;
if (!swipeToClose.allow) return;
swipeToClose.isTouched = true;
}
onTouchMove(e) {
const pb = this;
const swipeToClose = pb.swipeToClose;
if (!swipeToClose.isTouched) return;
if (!swipeToClose.started) {
swipeToClose.started = true;
swipeToClose.start = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (pb.params.virtualSlides) {
swipeToClose.activeSlide = pb.swiper.$wrapperEl.children('.swiper-slide-active');
} else {
swipeToClose.activeSlide = pb.swiper.slides.eq(pb.swiper.activeIndex);
}
swipeToClose.timeStart = Utils.now();
}
e.preventDefault();
swipeToClose.current = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
swipeToClose.diff = swipeToClose.start - swipeToClose.current;
const opacity = 1 - (Math.abs(swipeToClose.diff) / 300);
const color = pb.exposed || pb.params.theme === 'dark' ? 0 : 255;
swipeToClose.activeSlide.transform(`translate3d(0,${-swipeToClose.diff}px,0)`);
pb.swiper.$el.css('background-color', `rgba(${color}, ${color}, ${color}, ${opacity})`).transition(0);
}
onTouchEnd() {
const pb = this;
const swipeToClose = pb.swipeToClose;
swipeToClose.isTouched = false;
if (!swipeToClose.started) {
swipeToClose.started = false;
return;
}
swipeToClose.started = false;
swipeToClose.allow = false;
const diff = Math.abs(swipeToClose.diff);
const timeDiff = (new Date()).getTime() - swipeToClose.timeStart;
if ((timeDiff < 300 && diff > 20) || (timeDiff >= 300 && diff > 100)) {
Utils.nextTick(() => {
if (pb.$el) {
if (swipeToClose.diff < 0) pb.$el.addClass('swipe-close-to-bottom');
else pb.$el.addClass('swipe-close-to-top');
}
pb.emit('local::swipeToClose', pb);
pb.close();
swipeToClose.allow = true;
});
return;
}
if (diff !== 0) {
swipeToClose.activeSlide.addClass('photo-browser-transitioning').transitionEnd(() => {
swipeToClose.allow = true;
swipeToClose.activeSlide.removeClass('photo-browser-transitioning');
});
} else {
swipeToClose.allow = true;
}
pb.swiper.$el.transition('').css('background-color', '');
swipeToClose.activeSlide.transform('');
}
// Render Functions
renderNavbar() {
const pb = this;
if (pb.params.renderNavbar) return pb.params.renderNavbar.call(pb);
let iconsColor = pb.params.iconsColor;
if (!pb.params.iconsColor && pb.params.theme === 'dark') iconsColor = 'white';
const backLinkText = pb.app.theme === 'ios' && pb.params.backLinkText ? pb.params.backLinkText : '';
const isPopup = pb.params.type !== 'page';
const navbarHtml = `
<div class="navbar">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link ${isPopup ? 'popup-close' : ''} ${!backLinkText ? 'icon-only' : ''} ${!isPopup ? 'back' : ''}" ${isPopup ? 'data-popup=".photo-browser-popup"' : ''}>
<i class="icon icon-back ${iconsColor ? `color-${iconsColor}` : ''}"></i>
${backLinkText ? `<span>${backLinkText}</span>` : ''}
</a>
</div>
<div class="title">
<span class="photo-browser-current"></span>
<span class="photo-browser-of">${pb.params.navbarOfText}</span>
<span class="photo-browser-total"></span>
</div>
<div class="right"></div>
</div>
</div>
`.trim();
return navbarHtml;
}
renderToolbar() {
const pb = this;
if (pb.params.renderToolbar) return pb.params.renderToolbar.call(pb);
let iconsColor = pb.params.iconsColor;
if (!pb.params.iconsColor && pb.params.theme === 'dark') iconsColor = 'white';
const toolbarHtml = `
<div class="toolbar tabbar toolbar-bottom-md">
<div class="toolbar-inner">
<a href="#" class="link photo-browser-prev">
<i class="icon icon-back ${iconsColor ? `color-${iconsColor}` : ''}"></i>
</a>
<a href="#" class="link photo-browser-next">
<i class="icon icon-forward ${iconsColor ? `color-${iconsColor}` : ''}"></i>
</a>
</div>
</div>
`.trim();
return toolbarHtml;
}
renderCaption(caption, index) {
const pb = this;
if (pb.params.renderCaption) return pb.params.renderCaption.call(pb, caption, index);
const captionHtml = `
<div class="photo-browser-caption" data-caption-index="${index}">
${caption}
</div>
`.trim();
return captionHtml;
}
renderObject(photo, index) {
const pb = this;
if (pb.params.renderObject) return pb.params.renderObject.call(pb, photo, index);
const objHtml = `
<div class="photo-browser-slide photo-browser-object-slide swiper-slide" data-swiper-slide-index="${index}">${photo.html ? photo.html : photo}</div>
`;
return objHtml;
}
renderLazyPhoto(photo, index) {
const pb = this;
if (pb.params.renderLazyPhoto) return pb.params.renderLazyPhoto.call(pb, photo, index);
const photoHtml = `
<div class="photo-browser-slide photo-browser-slide-lazy swiper-slide" data-swiper-slide-index="${index}">
<div class="preloader swiper-lazy-preloader ${pb.params.theme === 'dark' ? 'color-white' : ''}">${pb.app.theme === 'md' ? Utils.mdPreloaderContent : ''}</div>
<span class="swiper-zoom-container">
<img data-src="${photo.url ? photo.url : photo}" class="swiper-lazy">
</span>
</div>
`.trim();
return photoHtml;
}
renderPhoto(photo, index) {
const pb = this;
if (pb.params.renderPhoto) return pb.params.renderPhoto.call(pb, photo, index);
const photoHtml = `
<div class="photo-browser-slide swiper-slide" data-swiper-slide-index="${index}">
<span class="swiper-zoom-container">
<img src="${photo.url ? photo.url : photo}">
</span>
</div>
`.trim();
return photoHtml;
}
render() {
const pb = this;
if (pb.params.render) return pb.params.render.call(pb, pb.params);
const html = `
<div class="photo-browser photo-browser-${pb.params.theme}">
<div class="view">
<div class="page photo-browser-page photo-browser-page-${pb.params.theme} no-toolbar ${!pb.params.navbar ? 'no-navbar' : ''}" data-name="photo-browser-page">
${pb.params.navbar ? pb.renderNavbar() : ''}
${pb.params.toolbar ? pb.renderToolbar() : ''}
<div class="photo-browser-captions photo-browser-captions-${pb.params.captionsTheme || pb.params.theme}">
${pb.params.photos.map((photo, index) => {
if (photo.caption) return pb.renderCaption(photo.caption, index);
return '';
}).join(' ')}
</div>
<div class="photo-browser-swiper-container swiper-container">
<div class="photo-browser-swiper-wrapper swiper-wrapper">
${pb.params.virtualSlides ? '' : pb.params.photos.map((photo, index) => {
if (photo.html || ((typeof photo === 'string' || photo instanceof String) && photo.indexOf('<') >= 0 && photo.indexOf('>') >= 0)) {
return pb.renderObject(photo, index);
} else if (pb.params.swiper.lazy === true || (pb.params.swiper.lazy && pb.params.swiper.lazy.enabled)) {
return pb.renderLazyPhoto(photo, index);
}
return pb.renderPhoto(photo, index);
}).join(' ')}
</div>
</div>
</div>
</div>
</div>
`.trim();
return html;
}
renderStandalone() {
const pb = this;
if (pb.params.renderStandalone) return pb.params.renderStandalone.call(pb);
const standaloneHtml = `<div class="popup photo-browser-popup photo-browser-standalone popup-tablet-fullscreen">${pb.render()}</div>`;
return standaloneHtml;
}
renderPage() {
const pb = this;
if (pb.params.renderPage) return pb.params.renderPage.call(pb);
const pageHtml = pb.render();
return pageHtml;
}
renderPopup() {
const pb = this;
if (pb.params.renderPopup) return pb.params.renderPopup.call(pb);
const popupHtml = `<div class="popup photo-browser-popup">${pb.render()}</div>`;
return popupHtml;
}
// Callbacks
onOpen(type, el) {
const pb = this;
const app = pb.app;
const $el = $(el);
$el[0].f7PhotoBrowser = pb;
pb.$el = $el;
pb.el = $el[0];
pb.openedIn = type;
pb.opened = true;
pb.$swiperContainerEl = pb.$el.find('.photo-browser-swiper-container');
pb.$swiperWrapperEl = pb.$el.find('.photo-browser-swiper-wrapper');
pb.slides = pb.$el.find('.photo-browser-slide');
pb.$captionsContainerEl = pb.$el.find('.photo-browser-captions');
pb.captions = pb.$el.find('.photo-browser-caption');
// Init Swiper
const swiperParams = Utils.extend({}, pb.params.swiper, {
initialSlide: pb.activeIndex,
on: {
tap(e) {
pb.emit('local::tap', e);
},
click(e) {
if (pb.params.exposition) {
pb.expositionToggle();
}
pb.emit('local::click', e);
},
doubleTap(e) {
pb.emit('local::doubleTap', e);
},
slideChange(...args) {
const swiper = this;
pb.onSlideChange(swiper);
pb.emit('local::slideChange', ...args);
},
transitionStart(...args) {
pb.emit('local::transitionStart', ...args);
},
transitionEnd(...args) {
pb.emit('local::transitionEnd', ...args);
},
slideChangeStart(...args) {
pb.emit('local::slideChangeTransitionStart', ...args);
},
slideChangeEnd(...args) {
pb.emit('local::slideChangeTransitionEnd', ...args);
},
lazyImageLoad(...args) {
pb.emit('local::lazyImageLoad', ...args);
},
lazyImageReady(...args) {
const slideEl = args[0];
$(slideEl).removeClass('photo-browser-slide-lazy');
pb.emit('local::lazyImageReady', ...args);
},
},
});
if (pb.params.swipeToClose && pb.params.type !== 'page') {
Utils.extend(swiperParams.on, {
touchStart(e) {
pb.onTouchStart(e);
pb.emit('local::touchStart', e);
},
touchMoveOpposite(e) {
pb.onTouchMove(e);
pb.emit('local::touchMoveOpposite', e);
},
touchEnd(e) {
pb.onTouchEnd(e);
pb.emit('local::touchEnd', e);
},
});
}
if (pb.params.virtualSlides) {
Utils.extend(swiperParams, {
virtual: {
slides: pb.params.photos,
renderSlide(photo, index) {
if (photo.html || ((typeof photo === 'string' || photo instanceof String) && photo.indexOf('<') >= 0 && photo.indexOf('>') >= 0)) {
return pb.renderObject(photo, index);
} else if (pb.params.swiper.lazy === true || (pb.params.swiper.lazy && pb.params.swiper.lazy.enabled)) {
return pb.renderLazyPhoto(photo, index);
}
return pb.renderPhoto(photo, index);
},
},
});
}
pb.swiper = app.swiper.create(pb.$swiperContainerEl, swiperParams);
if (pb.activeIndex === 0) {
pb.onSlideChange(pb.swiper);
}
if (pb.$el) {
pb.$el.trigger('photobrowser:open');
}
pb.emit('local::open photoBrowserOpen', pb);
}
onOpened() {
const pb = this;
if (pb.$el) {
pb.$el.trigger('photobrowser:opened');
}
pb.emit('local::opened photoBrowserOpened', pb);
}
onClose() {
const pb = this;
if (pb.destroyed) return;
// Destroy Swiper
if (pb.swiper && pb.swiper.destroy) {
pb.swiper.destroy(true, false);
pb.swiper = null;
delete pb.swiper;
}
if (pb.$el) {
pb.$el.trigger('photobrowser:close');
}
pb.emit('local::close photoBrowserClose', pb);
}
onClosed() {
const pb = this;
if (pb.destroyed) return;
pb.opened = false;
pb.$el = null;
pb.el = null;
delete pb.$el;
delete pb.el;
if (pb.$el) {
pb.$el.trigger('photobrowser:closed');
}
pb.emit('local::closed photoBrowserClosed', pb);
}
// Open
openPage() {
const pb = this;
if (pb.opened) return pb;
const pageHtml = pb.renderPage();
pb.view.router.navigate({
url: pb.url,
route: {
content: pageHtml,
path: pb.url,
on: {
pageBeforeIn(e, page) {
pb.view.$el.addClass(`with-photo-browser-page with-photo-browser-page-${pb.params.theme}`);
pb.onOpen('page', page.el);
},
pageAfterIn(e, page) {
pb.onOpened('page', page.el);
},
pageBeforeOut(e, page) {
pb.view.$el.removeClass(`with-photo-browser-page with-photo-browser-page-exposed with-photo-browser-page-${pb.params.theme}`);
pb.onClose('page', page.el);
},
pageAfterOut(e, page) {
pb.onClosed('page', page.el);
},
},
},
});
return pb;
}
openStandalone() {
const pb = this;
if (pb.opened) return pb;
const standaloneHtml = pb.renderStandalone();
const popupParams = {
backdrop: false,
content: standaloneHtml,
on: {
popupOpen(popup) {
pb.onOpen('popup', popup.el);
},
popupOpened(popup) {
pb.onOpened('popup', popup.el);
},
popupClose(popup) {
pb.onClose('popup', popup.el);
},
popupClosed(popup) {
pb.onClosed('popup', popup.el);
},
},
};
if (pb.params.routableModals) {
pb.view.router.navigate({
url: pb.url,
route: {
path: pb.url,
popup: popupParams,
},
});
} else {
pb.modal = pb.app.popup.create(popupParams).open();
}
return pb;
}
openPopup() {
const pb = this;
if (pb.opened) return pb;
const popupHtml = pb.renderPopup();
const popupParams = {
content: popupHtml,
on: {
popupOpen(popup) {
pb.onOpen('popup', popup.el);
},
popupOpened(popup) {
pb.onOpened('popup', popup.el);
},
popupClose(popup) {
pb.onClose('popup', popup.el);
},
popupClosed(popup) {
pb.onClosed('popup', popup.el);
},
},
};
if (pb.params.routableModals) {
pb.view.router.navigate({
url: pb.url,
route: {
path: pb.url,
popup: popupParams,
},
});
} else {
pb.modal = pb.app.popup.create(popupParams).open();
}
return pb;
}
// Exposition
expositionEnable() {
const pb = this;
if (pb.params.type === 'page') {
pb.view.$el.addClass('with-photo-browser-page-exposed');
}
if (pb.$el) pb.$el.addClass('photo-browser-exposed');
if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.addClass('photo-browser-captions-exposed');
pb.exposed = true;
return pb;
}
expositionDisable() {
const pb = this;
if (pb.params.type === 'page') {
pb.view.$el.removeClass('with-photo-browser-page-exposed');
}
if (pb.$el) pb.$el.removeClass('photo-browser-exposed');
if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.removeClass('photo-browser-captions-exposed');
pb.exposed = false;
return pb;
}
expositionToggle() {
const pb = this;
if (pb.params.type === 'page') {
pb.view.$el.toggleClass('with-photo-browser-page-exposed');
}
if (pb.$el) pb.$el.toggleClass('photo-browser-exposed');
if (pb.params.expositionHideCaptions) pb.$captionsContainerEl.toggleClass('photo-browser-captions-exposed');
pb.exposed = !pb.exposed;
return pb;
}
open(index) {
const pb = this;
const type = pb.params.type;
if (pb.opened) {
if (pb.swiper && typeof index !== 'undefined') {
pb.swiper.slideTo(parseInt(index, 10));
}
return pb;
} else if (typeof index !== 'undefined') {
pb.activeIndex = index;
}
if (type === 'standalone') {
pb.openStandalone();
}
if (type === 'page') {
pb.openPage();
}
if (type === 'popup') {
pb.openPopup();
}
return pb;
}
close() {
const pb = this;
if (!pb.opened) return pb;
if (pb.params.routableModals || pb.openedIn === 'page') {
if (pb.view) pb.view.router.back();
} else {
pb.modal.once('modalClosed', () => {
Utils.nextTick(() => {
pb.modal.destroy();
delete pb.modal;
});
});
pb.modal.close();
}
return pb;
}
// eslint-disable-next-line
init() {}
destroy() {
let pb = this;
pb.emit('local::beforeDestroy photoBrowserBeforeDestroy', pb);
if (pb.$el) {
pb.$el.trigger('photobrowser:beforedestroy');
delete pb.$el[0].f7PhotoBrowser;
}
Utils.deleteProps(pb);
pb = null;
}
}
var PhotoBrowser = {
name: 'photoBrowser',
params: {
photoBrowser: {
photos: [],
exposition: true,
expositionHideCaptions: false,
type: 'standalone',
navbar: true,
toolbar: true,
theme: 'light',
captionsTheme: undefined,
iconsColor: undefined,
swipeToClose: true,
backLinkText: 'Close',
navbarOfText: 'of',
view: undefined,
url: 'photos/',
routableModals: true,
virtualSlides: true,
renderNavbar: undefined,
renderToolbar: undefined,
renderCaption: undefined,
renderObject: undefined,
renderLazyPhoto: undefined,
renderPhoto: undefined,
renderPage: undefined,
renderPopup: undefined,
renderStandalone: undefined,
swiper: {
initialSlide: 0,
spaceBetween: 20,
speed: 300,
loop: false,
preloadImages: true,
navigation: {
nextEl: '.photo-browser-next',
prevEl: '.photo-browser-prev',
},
zoom: {
enabled: true,
maxRatio: 3,
minRatio: 1,
},
lazy: {
enabled: true,
},
},
},
},
create() {
const app = this;
app.photoBrowser = ConstructorMethods({
defaultSelector: '.photo-browser',
constructor: PhotoBrowser$1,
app,
domProp: 'f7PhotoBrowser',
});
},
static: {
PhotoBrowser: PhotoBrowser$1,
},
};
class Notification$1 extends Modal$1 {
constructor(app, params) {
const extendedParams = Utils.extend({
on: {},
}, app.params.notification, params);
// Extends with open/close Modal methods;
super(app, extendedParams);
const notification = this;
notification.app = app;
notification.params = extendedParams;
const {
icon,
title,
titleRightText,
subtitle,
text,
closeButton,
closeTimeout,
cssClass,
closeOnClick,
} = notification.params;
let $el;
if (!notification.params.el) {
// Find Element
const notificationHtml = notification.render({
icon,
title,
titleRightText,
subtitle,
text,
closeButton,
cssClass,
});
$el = $(notificationHtml);
} else {
$el = $(notification.params.el);
}
if ($el && $el.length > 0 && $el[0].f7Modal) {
return $el[0].f7Modal;
}
if ($el.length === 0) {
return notification.destroy();
}
Utils.extend(notification, {
$el,
el: $el[0],
type: 'notification',
});
$el[0].f7Modal = notification;
if (closeButton) {
$el.find('.notification-close-button').on('click', () => {
notification.close();
});
}
$el.on('click', (e) => {
if (closeButton && $(e.target).closest('.notification-close-button').length) {
return;
}
notification.emit('local::click notificationClick', notification);
if (closeOnClick) notification.close();
});
notification.on('beforeDestroy', () => {
$el.off('click');
});
/* Touch Events */
let isTouched;
let isMoved;
let isScrolling;
let touchesDiff;
let touchStartTime;
let notificationHeight;
const touchesStart = {};
function handleTouchStart(e) {
if (isTouched) return;
isTouched = true;
isMoved = false;
isScrolling = undefined;
touchStartTime = Utils.now();
touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX;
touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
}
function handleTouchMove(e) {
if (!isTouched) return;
const pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX;
const pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) < Math.abs(pageX - touchesStart.x));
}
if (isScrolling) {
isTouched = false;
return;
}
e.preventDefault();
if (!isMoved) {
notification.$el.removeClass('notification-transitioning');
notification.$el.transition(0);
notificationHeight = notification.$el[0].offsetHeight / 2;
}
isMoved = true;
touchesDiff = (pageY - touchesStart.y);
let newTranslate = touchesDiff;
if (touchesDiff > 0) {
newTranslate = touchesDiff ** 0.8;
}
notification.$el.transform(`translate3d(0, ${newTranslate}px, 0)`);
}
function handleTouchEnd() {
if (!isTouched || !isMoved) {
isTouched = false;
isMoved = false;
return;
}
isTouched = false;
isMoved = false;
if (touchesDiff === 0) {
return;
}
const timeDiff = Utils.now() - touchStartTime;
notification.$el.transition('');
notification.$el.addClass('notification-transitioning');
notification.$el.transform('');
if (
(touchesDiff < -10 && timeDiff < 300) ||
(-touchesDiff >= notificationHeight / 1)
) {
notification.close();
}
}
function attachTouchEvents() {
{
notification.$el.on(app.touchEvents.start, handleTouchStart, { passive: true });
app.on('touchmove:active', handleTouchMove);
app.on('touchend:passive', handleTouchEnd);
}
}
function detachTouchEvents() {
{
notification.$el.off(app.touchEvents.start, handleTouchStart, { passive: true });
app.off('touchmove:active', handleTouchMove);
app.off('touchend:passive', handleTouchEnd);
}
}
let timeoutId;
function closeOnTimeout() {
timeoutId = Utils.nextTick(() => {
if (isTouched && isMoved) {
closeOnTimeout();
return;
}
notification.close();
}, closeTimeout);
}
notification.on('open', () => {
if (notification.params.swipeToClose) {
attachTouchEvents();
}
$('.notification.modal-in').each((index, openedEl) => {
const notificationInstance = app.notification.get(openedEl);
if (openedEl !== notification.el && notificationInstance) {
notificationInstance.close();
}
});
if (closeTimeout) {
closeOnTimeout();
}
});
notification.on('close beforeDestroy', () => {
if (notification.params.swipeToClose) {
detachTouchEvents();
}
window.clearTimeout(timeoutId);
});
return notification;
}
render() {
const notification = this;
if (notification.params.render) return notification.params.render.call(notification, notification);
const { icon, title, titleRightText, subtitle, text, closeButton, cssClass } = notification.params;
return `
<div class="notification ${cssClass || ''}">
<div class="notification-header">
${icon ? `<div class="notification-icon">${icon}</div>` : ''}
${title ? `<div class="notification-title">${title}</div>` : ''}
${titleRightText ? `<div class="notification-title-right-text">${titleRightText}</div>` : ''}
${closeButton ? '<span class="notification-close-button"></span>' : ''}
</div>
<div class="notification-content">
${subtitle ? `<div class="notification-subtitle">${subtitle}</div>` : ''}
${text ? `<div class="notification-text">${text}</div>` : ''}
</div>
</div>
`.trim();
}
}
var Notification = {
name: 'notification',
static: {
Notification: Notification$1,
},
create() {
const app = this;
app.notification = Utils.extend(
{},
ModalMethods({
app,
constructor: Notification$1,
defaultSelector: '.notification.modal-in',
})
);
},
params: {
notification: {
icon: null,
title: null,
titleRightText: null,
subtitle: null,
text: null,
closeButton: false,
closeTimeout: null,
closeOnClick: false,
swipeToClose: true,
cssClass: null,
render: null,
},
},
};
/* eslint "no-useless-escape": "off" */
class Autocomplete$1 extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const ac = this;
ac.app = app;
const defaults = Utils.extend({
on: {},
}, app.params.autocomplete);
// Extend defaults with modules params
ac.useModulesParams(defaults);
ac.params = Utils.extend(defaults, params);
let $openerEl;
if (ac.params.openerEl) {
$openerEl = $(ac.params.openerEl);
if ($openerEl.length) $openerEl[0].f7Autocomplete = ac;
}
let $inputEl;
if (ac.params.inputEl) {
$inputEl = $(ac.params.inputEl);
if ($inputEl.length) $inputEl[0].f7Autocomplete = ac;
}
let view;
if (ac.params.view) {
view = ac.params.view;
} else if ($openerEl || $inputEl) {
view = app.views.get($openerEl || $inputEl);
}
if (!view) view = app.views.main;
const id = Utils.now();
let url = params.url;
if (!url && $openerEl && $openerEl.length) {
if ($openerEl.attr('href')) url = $openerEl.attr('href');
else if ($openerEl.find('a').length > 0) {
url = $openerEl.find('a').attr('href');
}
}
if (!url || url === '#' || url === '') url = ac.params.url;
const inputType = ac.params.multiple ? 'checkbox' : 'radio';
Utils.extend(ac, {
$openerEl,
openerEl: $openerEl && $openerEl[0],
$inputEl,
inputEl: $inputEl && $inputEl[0],
id,
view,
url,
value: ac.params.value || [],
inputType,
inputName: `${inputType}-${id}`,
$modalEl: undefined,
$dropdownEl: undefined,
});
let previousQuery = '';
function onInputChange() {
let query = ac.$inputEl.val().trim();
if (!ac.params.source) return;
ac.params.source.call(ac, query, (items) => {
let itemsHTML = '';
const limit = ac.params.limit ? Math.min(ac.params.limit, items.length) : items.length;
ac.items = items;
let regExp;
if (ac.params.highlightMatches) {
query = query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
regExp = new RegExp(`(${query})`, 'i');
}
let firstValue;
let firstItem;
for (let i = 0; i < limit; i += 1) {
const itemValue = typeof items[i] === 'object' ? items[i][ac.params.valueProperty] : items[i];
const itemText = typeof items[i] === 'object' ? items[i][ac.params.textProperty] : items[i];
if (i === 0) {
firstValue = itemValue;
firstItem = ac.items[i];
}
itemsHTML += ac.renderItem({
value: itemValue,
text: ac.params.highlightMatches ? itemText.replace(regExp, '<b>$1</b>') : itemText,
}, i);
}
if (itemsHTML === '' && query === '' && ac.params.dropdownPlaceholderText) {
itemsHTML += ac.renderItem({
placeholder: true,
text: ac.params.dropdownPlaceholderText,
});
}
ac.$dropdownEl.find('ul').html(itemsHTML);
if (ac.params.typeahead) {
if (!firstValue || !firstItem) {
return;
}
if (firstValue.toLowerCase().indexOf(query.toLowerCase()) !== 0) {
return;
}
if (previousQuery.toLowerCase() === query.toLowerCase()) {
ac.value = [];
return;
}
if (previousQuery.toLowerCase().indexOf(query.toLowerCase()) === 0) {
previousQuery = query;
ac.value = [];
return;
}
$inputEl.val(firstValue);
$inputEl[0].setSelectionRange(query.length, firstValue.length);
const previousValue = typeof ac.value[0] === 'object' ? ac.value[0][ac.params.valueProperty] : ac.value[0];
if (!previousValue || firstValue.toLowerCase() !== previousValue.toLowerCase()) {
ac.value = [firstItem];
ac.emit('local::change autocompleteChange', [firstItem]);
}
}
previousQuery = query;
});
}
function onPageInputChange() {
const input = this;
const value = input.value;
const isValues = $(input).parents('.autocomplete-values').length > 0;
let item;
let itemValue;
let aValue;
if (isValues) {
if (ac.inputType === 'checkbox' && !input.checked) {
for (let i = 0; i < ac.value.length; i += 1) {
aValue = typeof ac.value[i] === 'string' ? ac.value[i] : ac.value[i][ac.params.valueProperty];
if (aValue === value || aValue * 1 === value * 1) {
ac.value.splice(i, 1);
}
}
ac.updateValues();
ac.emit('local::change autocompleteChange', ac.value);
}
return;
}
// Find Related Item
for (let i = 0; i < ac.items.length; i += 1) {
itemValue = typeof ac.items[i] === 'object' ? ac.items[i][ac.params.valueProperty] : ac.items[i];
if (itemValue === value || itemValue * 1 === value * 1) item = ac.items[i];
}
if (ac.inputType === 'radio') {
ac.value = [item];
} else if (input.checked) {
ac.value.push(item);
} else {
for (let i = 0; i < ac.value.length; i += 1) {
aValue = typeof ac.value[i] === 'object' ? ac.value[i][ac.params.valueProperty] : ac.value[i];
if (aValue === value || aValue * 1 === value * 1) {
ac.value.splice(i, 1);
}
}
}
// Update Values Block
ac.updateValues();
// On Select Callback
if (((ac.inputType === 'radio' && input.checked) || ac.inputType === 'checkbox')) {
ac.emit('local::change autocompleteChange', ac.value);
}
}
function onHtmlClick(e) {
const $targetEl = $(e.target);
if ($targetEl.is(ac.$inputEl[0]) || ($targetEl.closest(ac.$dropdownEl[0]).length)) return;
ac.close();
}
function onOpenerClick() {
ac.open();
}
function onInputFocus() {
ac.open();
}
function onInputBlur() {
if (ac.$dropdownEl.find('label.active-state').length > 0) return;
ac.close();
}
function onResize() {
ac.positionDropDown();
}
function onKeyDown(e) {
if (ac.opened && e.keyCode === 13) {
e.preventDefault();
ac.$inputEl.blur();
}
}
function onDropdownclick() {
const $clickedEl = $(this);
let clickedItem;
for (let i = 0; i < ac.items.length; i += 1) {
const itemValue = typeof ac.items[i] === 'object' ? ac.items[i][ac.params.valueProperty] : ac.items[i];
const value = $clickedEl.attr('data-value');
if (itemValue === value || itemValue * 1 === value * 1) {
clickedItem = ac.items[i];
}
}
if (ac.params.updateInputValueOnSelect) {
ac.$inputEl.val(typeof clickedItem === 'object' ? clickedItem[ac.params.valueProperty] : clickedItem);
ac.$inputEl.trigger('input change');
}
ac.value = [clickedItem];
ac.emit('local::change autocompleteChange', [clickedItem]);
ac.close();
}
ac.attachEvents = function attachEvents() {
if (ac.params.openIn !== 'dropdown' && ac.$openerEl) {
ac.$openerEl.on('click', onOpenerClick);
}
if (ac.params.openIn === 'dropdown' && ac.$inputEl) {
ac.$inputEl.on('focus', onInputFocus);
ac.$inputEl.on('input', onInputChange);
if (app.device.android) {
$('html').on('click', onHtmlClick);
} else {
ac.$inputEl.on('blur', onInputBlur);
}
if (ac.params.typeahead) {
ac.$inputEl.on('keydown', onKeyDown);
}
}
};
ac.detachEvents = function attachEvents() {
if (ac.params.openIn !== 'dropdown' && ac.$openerEl) {
ac.$openerEl.off('click', onOpenerClick);
}
if (ac.params.openIn === 'dropdown' && ac.$inputEl) {
ac.$inputEl.off('focus', onInputFocus);
ac.$inputEl.off('input', onInputChange);
if (app.device.android) {
$('html').off('click', onHtmlClick);
} else {
ac.$inputEl.off('blur', onInputBlur);
}
if (ac.params.typeahead) {
ac.$inputEl.off('keydown', onKeyDown);
}
}
};
ac.attachDropdownEvents = function attachDropdownEvents() {
ac.$dropdownEl.on('click', 'label', onDropdownclick);
app.on('resize', onResize);
};
ac.detachDropdownEvents = function detachDropdownEvents() {
ac.$dropdownEl.off('click', 'label', onDropdownclick);
app.off('resize', onResize);
};
ac.attachPageEvents = function attachPageEvents() {
ac.$el.on('change', 'input[type="radio"], input[type="checkbox"]', onPageInputChange);
if (ac.params.closeOnSelect && !ac.params.multiple) {
ac.$el.once('click', '.list label', () => {
Utils.nextTick(() => {
ac.close();
});
});
}
};
ac.detachPageEvents = function detachPageEvents() {
ac.$el.off('change', 'input[type="radio"], input[type="checkbox"]', onPageInputChange);
};
// Install Modules
ac.useModules();
// Init
ac.init();
return ac;
}
positionDropDown() {
const ac = this;
const { $inputEl, app, $dropdownEl } = ac;
const $pageContentEl = $inputEl.parents('.page-content');
if ($pageContentEl.length === 0) return;
const inputOffset = $inputEl.offset();
const inputOffsetWidth = $inputEl[0].offsetWidth;
const inputOffsetHeight = $inputEl[0].offsetHeight;
const $listEl = $inputEl.parents('.list');
const listOffset = $listEl.offset();
const paddingBottom = parseInt($pageContentEl.css('padding-top'), 10);
const listOffsetLeft = $listEl.length > 0 ? listOffset.left - $listEl.parent().offset().left : 0;
const inputOffsetLeft = inputOffset.left - ($listEl.length > 0 ? listOffset.left : 0) - (app.rtl ? 0 : 0);
const inputOffsetTop = inputOffset.top - ($pageContentEl.offset().top - $pageContentEl[0].scrollTop);
const maxHeight = $pageContentEl[0].scrollHeight - paddingBottom - (inputOffsetTop + $pageContentEl[0].scrollTop) - $inputEl[0].offsetHeight;
const paddingProp = app.rtl ? 'padding-right' : 'padding-left';
let paddingValue;
if ($listEl.length && !ac.params.expandInput) {
paddingValue = (app.rtl ? $listEl[0].offsetWidth - inputOffsetLeft - inputOffsetWidth : inputOffsetLeft) - (app.theme === 'md' ? 16 : 15);
}
$dropdownEl.css({
left: `${$listEl.length > 0 ? listOffsetLeft : inputOffsetLeft}px`,
top: `${inputOffsetTop + $pageContentEl[0].scrollTop + inputOffsetHeight}px`,
width: `${$listEl.length > 0 ? $listEl[0].offsetWidth : inputOffsetWidth}px`,
});
$dropdownEl.children('.autocomplete-dropdown-inner').css({
maxHeight: `${maxHeight}px`,
[paddingProp]: $listEl.length > 0 && !ac.params.expandInput ? `${paddingValue}px` : '',
});
}
focus() {
const ac = this;
ac.$el.find('input[type=search]').focus();
}
source(query) {
const ac = this;
if (!ac.params.source) return;
const { $el } = ac;
ac.params.source.call(ac, query, (items) => {
let itemsHTML = '';
const limit = ac.params.limit ? Math.min(ac.params.limit, items.length) : items.length;
ac.items = items;
for (let i = 0; i < limit; i += 1) {
let selected = false;
const itemValue = typeof items[i] === 'object' ? items[i][ac.params.valueProperty] : items[i];
for (let j = 0; j < ac.value.length; j += 1) {
const aValue = typeof ac.value[j] === 'object' ? ac.value[j][ac.params.valueProperty] : ac.value[j];
if (aValue === itemValue || aValue * 1 === itemValue * 1) selected = true;
}
itemsHTML += ac.renderItem({
value: itemValue,
text: typeof items[i] === 'object' ? items[i][ac.params.textProperty] : items[i],
inputType: ac.inputType,
id: ac.id,
inputName: ac.inputName,
selected,
}, i);
}
$el.find('.autocomplete-found ul').html(itemsHTML);
if (items.length === 0) {
if (query.length !== 0) {
$el.find('.autocomplete-not-found').show();
$el.find('.autocomplete-found, .autocomplete-values').hide();
} else {
$el.find('.autocomplete-values').show();
$el.find('.autocomplete-found, .autocomplete-not-found').hide();
}
} else {
$el.find('.autocomplete-found').show();
$el.find('.autocomplete-not-found, .autocomplete-values').hide();
}
});
}
updateValues() {
const ac = this;
let valuesHTML = '';
for (let i = 0; i < ac.value.length; i += 1) {
valuesHTML += ac.renderItem({
value: typeof ac.value[i] === 'object' ? ac.value[i][ac.params.valueProperty] : ac.value[i],
text: typeof ac.value[i] === 'object' ? ac.value[i][ac.params.textProperty] : ac.value[i],
inputType: ac.inputType,
id: ac.id,
inputName: `${ac.inputName}-checked}`,
selected: true,
}, i);
}
ac.$el.find('.autocomplete-values ul').html(valuesHTML);
}
preloaderHide() {
const ac = this;
if (ac.params.openIn === 'dropdown' && ac.$dropdownEl) {
ac.$dropdownEl.find('.autocomplete-preloader').removeClass('autocomplete-preloader-visible');
} else {
$('.autocomplete-preloader').removeClass('autocomplete-preloader-visible');
}
}
preloaderShow() {
const ac = this;
if (ac.params.openIn === 'dropdown' && ac.$dropdownEl) {
ac.$dropdownEl.find('.autocomplete-preloader').addClass('autocomplete-preloader-visible');
} else {
$('.autocomplete-preloader').addClass('autocomplete-preloader-visible');
}
}
renderPreloader() {
const ac = this;
return `
<div class="autocomplete-preloader preloader ${ac.params.preloaderColor ? `color-${ac.params.preloaderColor}` : ''}">${ac.app.theme === 'md' ? Utils.mdPreloaderContent : ''}</div>
`.trim();
}
renderSearchbar() {
const ac = this;
if (ac.params.renderSearchbar) return ac.params.renderSearchbar.call(ac);
const searchbarHTML = `
<form class="searchbar">
<div class="searchbar-inner">
<div class="searchbar-input-wrap">
<input type="search" placeholder="${ac.params.searchbarPlaceholder}"/>
<i class="searchbar-icon"></i>
<span class="input-clear-button"></span>
</div>
<span class="searchbar-disable-button">${ac.params.searchbarDisableText}</span>
</div>
</form>
`.trim();
return searchbarHTML;
}
renderItem(item, index) {
const ac = this;
if (ac.params.renderItem) return ac.params.renderItem.call(ac, item, index);
let itemHtml;
if (ac.params.openIn !== 'dropdown') {
itemHtml = `
<li>
<label class="item-${item.inputType} item-content">
<input type="${item.inputType}" name="${item.inputName}" value="${item.value}" ${item.selected ? 'checked' : ''}>
<i class="icon icon-${item.inputType}"></i>
<div class="item-inner">
<div class="item-title">${item.text}</div>
</div>
</label>
</li>
`;
} else if (!item.placeholder) {
// Dropdown
itemHtml = `
<li>
<label class="item-radio item-content" data-value="${item.value}">
<div class="item-inner">
<div class="item-title">${item.text}</div>
</div>
</label>
</li>
`;
} else {
// Dropwdown placeholder
itemHtml = `
<li class="autocomplete-dropdown-placeholder">
<div class="item-content">
<div class="item-inner">
<div class="item-title">${item.text}</div>
</div>
</label>
</li>
`;
}
return itemHtml.trim();
}
renderNavbar() {
const ac = this;
if (ac.params.renderNavbar) return ac.params.renderNavbar.call(ac);
let pageTitle = ac.params.pageTitle;
if (typeof pageTitle === 'undefined' && ac.$openerEl && ac.$openerEl.length) {
pageTitle = ac.$openerEl.find('.item-title').text().trim();
}
const navbarHtml = `
<div class="navbar ${ac.params.navbarColorTheme ? `color-theme-${ac.params.navbarColorTheme}` : ''}">
<div class="navbar-inner ${ac.params.navbarColorTheme ? `color-theme-${ac.params.navbarColorTheme}` : ''}">
<div class="left sliding">
<a href="#" class="link ${ac.params.openIn === 'page' ? 'back' : 'popup-close'}">
<i class="icon icon-back"></i>
<span class="ios-only">${ac.params.openIn === 'page' ? ac.params.pageBackLinkText : ac.params.popupCloseLinkText}</span>
</a>
</div>
${pageTitle ? `<div class="title sliding">${pageTitle}</div>` : ''}
${ac.params.preloader ? `
<div class="right">
${ac.renderPreloader()}
</div>
` : ''}
<div class="subnavbar sliding">${ac.renderSearchbar()}</div>
</div>
</div>
`.trim();
return navbarHtml;
}
renderDropdown() {
const ac = this;
if (ac.params.renderDropdown) return ac.params.renderDropdown.call(ac, ac.items);
const dropdownHtml = `
<div class="autocomplete-dropdown">
<div class="autocomplete-dropdown-inner">
<div class="list ${!ac.params.expandInput ? 'no-ios-edge' : ''}">
<ul></ul>
</div>
</div>
${ac.params.preloader ? ac.renderPreloader() : ''}
</div>
`.trim();
return dropdownHtml;
}
renderPage() {
const ac = this;
if (ac.params.renderPage) return ac.params.renderPage.call(ac, ac.items);
const pageHtml = `
<div class="page page-with-subnavbar autocomplete-page" data-name="autocomplete-page">
${ac.renderNavbar()}
<div class="searchbar-backdrop"></div>
<div class="page-content">
<div class="list autocomplete-list autocomplete-found autocomplete-list-${ac.id} ${ac.params.formColorTheme ? `color-theme-${ac.params.formColorTheme}` : ''}">
<ul></ul>
</div>
<div class="list autocomplete-not-found">
<ul>
<li class="item-content"><div class="item-inner"><div class="item-title">${ac.params.notFoundText}</div></div></li>
</ul>
</div>
<div class="list autocomplete-values">
<ul></ul>
</div>
</div>
</div>
`.trim();
return pageHtml;
}
renderPopup() {
const ac = this;
if (ac.params.renderPopup) return ac.params.renderPopup.call(ac, ac.items);
const popupHtml = `
<div class="popup autocomplete-popup">
<div class="view">
${ac.renderPage()};
</div>
</div>
`.trim();
return popupHtml;
}
onOpen(type, el) {
const ac = this;
const app = ac.app;
const $el = $(el);
ac.$el = $el;
ac.el = $el[0];
ac.openedIn = type;
ac.opened = true;
if (ac.params.openIn === 'dropdown') {
ac.attachDropdownEvents();
ac.$dropdownEl.addClass('autocomplete-dropdown-in');
ac.$inputEl.trigger('input');
} else {
// Init SB
let $searchbarEl = $el.find('.searchbar');
if (ac.params.openIn === 'page' && app.theme === 'ios' && $searchbarEl.length === 0) {
$searchbarEl = $(app.navbar.getElByPage($el)).find('.searchbar');
}
ac.searchbar = app.searchbar.create({
el: $searchbarEl,
backdropEl: $el.find('.searchbar-backdrop'),
customSearch: true,
on: {
searchbarSearch(query) {
if (query.length === 0 && ac.searchbar.enabled) {
ac.searchbar.backdropShow();
} else {
ac.searchbar.backdropHide();
}
ac.source(query);
},
},
});
// Attach page events
ac.attachPageEvents();
// Update Values On Page Init
ac.updateValues();
// Source on load
if (ac.params.requestSourceOnOpen) ac.source('');
}
ac.emit('local::open autocompleteOpen', ac);
}
onOpened() {
const ac = this;
if (ac.params.openIn !== 'dropdown' && ac.params.autoFocus) {
ac.autoFocus();
}
ac.emit('local::opened autocompleteOpened', ac);
}
onClose() {
const ac = this;
if (ac.destroyed) return;
// Destroy SB
if (ac.searchbar && ac.searchbar.destroy) {
ac.searchbar.destroy();
ac.searchbar = null;
delete ac.searchbar;
}
if (ac.params.openIn === 'dropdown') {
ac.detachDropdownEvents();
ac.$dropdownEl.removeClass('autocomplete-dropdown-in').remove();
ac.$inputEl.parents('.item-content-dropdown-expanded').removeClass('item-content-dropdown-expanded');
} else {
ac.detachPageEvents();
}
ac.emit('local::close autocompleteClose', ac);
}
onClosed() {
const ac = this;
if (ac.destroyed) return;
ac.opened = false;
ac.$el = null;
ac.el = null;
delete ac.$el;
delete ac.el;
ac.emit('local::closed autocompleteClosed', ac);
}
openPage() {
const ac = this;
if (ac.opened) return ac;
const pageHtml = ac.renderPage();
ac.view.router.navigate({
url: ac.url,
route: {
content: pageHtml,
path: ac.url,
on: {
pageBeforeIn(e, page) {
ac.onOpen('page', page.el);
},
pageAfterIn(e, page) {
ac.onOpened('page', page.el);
},
pageBeforeOut(e, page) {
ac.onClose('page', page.el);
},
pageAfterOut(e, page) {
ac.onClosed('page', page.el);
},
},
options: {
animate: ac.params.animate,
},
},
});
return ac;
}
openPopup() {
const ac = this;
if (ac.opened) return ac;
const popupHtml = ac.renderPopup();
const popupParams = {
content: popupHtml,
animate: ac.params.animate,
on: {
popupOpen(popup) {
ac.onOpen('popup', popup.el);
},
popupOpened(popup) {
ac.onOpened('popup', popup.el);
},
popupClose(popup) {
ac.onClose('popup', popup.el);
},
popupClosed(popup) {
ac.onClosed('popup', popup.el);
},
},
};
if (ac.params.routableModals) {
ac.view.router.navigate({
url: ac.url,
route: {
path: ac.url,
popup: popupParams,
},
});
} else {
ac.modal = ac.app.popup.create(popupParams).open(ac.params.animate);
}
return ac;
}
openDropdown() {
const ac = this;
if (!ac.$dropdownEl) {
ac.$dropdownEl = $(ac.renderDropdown());
}
const $listEl = ac.$inputEl.parents('.list');
if ($listEl.length && ac.$inputEl.parents('.item-content').length > 0 && ac.params.expandInput) {
ac.$inputEl.parents('.item-content').addClass('item-content-dropdown-expanded');
}
ac.positionDropDown();
const $pageContentEl = ac.$inputEl.parents('.page-content');
if (ac.params.dropdownel) {
$(ac.params.dropdownel).append(ac.$dropdownEl);
} else if ($pageContentEl.length === 0) {
ac.$dropdownEl.insertAfter(ac.$inputEl);
} else {
$pageContentEl.append(ac.$dropdownEl);
}
ac.onOpen('dropdown', ac.$dropdownEl);
ac.onOpened('dropdown', ac.$dropdownEl);
}
open() {
const ac = this;
if (ac.opened) return ac;
const openIn = ac.params.openIn;
ac[`open${openIn.split('').map((el, index) => {
if (index === 0) return el.toUpperCase();
return el;
}).join('')}`]();
return ac;
}
close() {
const ac = this;
if (!ac.opened) return ac;
if (ac.params.openIn === 'dropdown') {
ac.onClose();
ac.onClosed();
} else if (ac.params.routableModals || ac.openedIn === 'page') {
ac.view.router.back({ animate: ac.params.animate });
} else {
ac.modal.once('modalClosed', () => {
Utils.nextTick(() => {
ac.modal.destroy();
delete ac.modal;
});
});
ac.modal.close();
}
return ac;
}
init() {
const ac = this;
ac.attachEvents();
}
destroy() {
const ac = this;
ac.emit('local::beforeDestroy autocompleteBeforeDestroy', ac);
ac.detachEvents();
if (ac.$inputEl && ac.$inputEl[0]) {
delete ac.$inputEl[0].f7Autocomplete;
}
if (ac.$openerEl && ac.$openerEl[0]) {
delete ac.$openerEl[0].f7Autocomplete;
}
Utils.deleteProps(ac);
ac.destroyed = true;
}
}
var Autocomplete = {
name: 'autocomplete',
params: {
autocomplete: {
openerEl: undefined,
inputEl: undefined,
view: undefined,
// DropDown
dropdownContainerEl: undefined,
dropdownPlaceholderText: undefined,
typeahead: false,
highlightMatches: true,
expandInput: false,
updateInputValueOnSelect: true,
value: undefined,
multiple: false,
source: undefined,
limit: undefined,
valueProperty: 'id',
textProperty: 'text',
openIn: 'page', // or 'popup' or 'dropdown'
pageBackLinkText: 'Back',
popupCloseLinkText: 'Close',
pageTitle: undefined,
searchbarPlaceholder: 'Search...',
searchbarDisableText: 'Cancel',
animate: true,
autoFocus: false,
closeOnSelect: false,
notFoundText: 'Nothing found',
requestSourceOnOpen: false,
// Preloader
preloaderColor: undefined,
preloader: false,
// Colors
formColorTheme: undefined,
navbarColorTheme: undefined,
// Routing
routableModals: true,
url: 'select/',
// Custom render functions
renderDropdown: undefined,
renderPage: undefined,
renderPopup: undefined,
renderItem: undefined,
renderSearchbar: undefined,
renderNavbar: undefined,
},
},
static: {
Autocomplete: Autocomplete$1,
},
create() {
const app = this;
app.autocomplete = Utils.extend(
ConstructorMethods({
defaultSelector: undefined,
constructor: Autocomplete$1,
app,
domProp: 'f7Autocomplete',
}),
{
open(autocompleteEl) {
const ac = app.autocomplete.get(autocompleteEl);
if (ac && ac.open) return ac.open();
return undefined;
},
close(autocompleteEl) {
const ac = app.autocomplete.get(autocompleteEl);
if (ac && ac.close) return ac.close();
return undefined;
},
}
);
},
};
class ViAd extends Framework7Class {
constructor(app, params = {}) {
super(params, [app]);
const vi = this;
if (!window.vi) {
throw new Error('f7:vi SDK not found.');
}
let orientation;
if (typeof window.orientation !== 'undefined') {
orientation = window.orientation === -90 || window.orientation === 90 ? 'horizontal' : 'vertical';
}
const defaults = Utils.extend(
{},
app.params.vi,
{
appId: app.id,
appVer: app.version,
language: app.language,
width: app.width,
height: app.height,
os: Device.os,
osVersion: Device.osVersion,
orientation,
}
);
// Extend defaults with modules params
vi.useModulesParams(defaults);
vi.params = Utils.extend(defaults, params);
const adParams = {};
const skipParams = ('on autoplay fallbackOverlay fallbackOverlayText enabled').split(' ');
Object.keys(vi.params).forEach((paramName) => {
if (skipParams.indexOf(paramName) >= 0) return;
const paramValue = vi.params[paramName];
if ([null, undefined].indexOf(paramValue) >= 0) return;
adParams[paramName] = paramValue;
});
if (!vi.params.appId) {
throw new Error('Framework7:"app.id" is required to display an ad. Make sure you have specified it on app initialization.');
}
if (!vi.params.placementId) {
throw new Error('Framework7:"placementId" is required to display an ad.');
}
function onResize() {
const $viFrame = $('iframe#viAd');
if ($viFrame.length === 0) return;
$viFrame
.css({
width: `${app.width}px`,
height: `${app.height}px`,
});
}
function removeOverlay() {
if (!vi.$overlayEl) return;
vi.$overlayEl.off('click touchstart');
vi.$overlayEl.remove();
}
function createOverlay(videoEl) {
if (!videoEl) return;
vi.$overlayEl = $(`
<div class="vi-overlay no-fastclick">
${vi.params.fallbackOverlayText ? `<div class="vi-overlay-text">${vi.params.fallbackOverlayText}</div>` : ''}
<div class="vi-overlay-play-button"></div>
</div>
`.trim());
let touchStartTime;
vi.$overlayEl.on('touchstart', () => {
touchStartTime = Utils.now();
});
vi.$overlayEl.on('click', () => {
const timeDiff = Utils.now() - touchStartTime;
if (timeDiff > 300) return;
if (videoEl) {
videoEl.play();
removeOverlay();
return;
}
vi.start();
removeOverlay();
});
app.root.append(vi.$overlayEl);
}
// Create ad
vi.ad = new window.vi.Ad(adParams);
Utils.extend(vi.ad, {
onAdReady() {
app.on('resize', onResize);
vi.emit('local::ready');
if (vi.params.autoplay) {
vi.start();
}
},
onAdStarted() {
vi.emit('local::started');
},
onAdClick(targetUrl) {
vi.emit('local::click', targetUrl);
},
onAdImpression() {
vi.emit('local::impression');
},
onAdStopped(reason) {
app.off('resize', onResize);
removeOverlay();
vi.emit('local::stopped', reason);
if (reason === 'complete') {
vi.emit('local::complete');
vi.emit('local::completed');
}
if (reason === 'userexit') {
vi.emit('local::userexit');
}
vi.destroyed = true;
},
onAutoPlayFailed(reason, videoEl) {
vi.emit('local::autoplayFailed', reason, videoEl);
if (reason && reason.name && reason.name.indexOf('NotAllowedError') !== -1 && vi.params.fallbackOverlay) {
createOverlay(videoEl);
}
},
onAdError(msg) {
removeOverlay();
app.off('resize', onResize);
vi.emit('local::error', msg);
vi.destroyed = true;
},
});
vi.init();
Utils.extend(vi, {
app,
});
}
start() {
const vi = this;
if (vi.destroyed) return;
if (vi.ad) vi.ad.startAd();
}
pause() {
const vi = this;
if (vi.destroyed) return;
if (vi.ad) vi.ad.pauseAd();
}
resume() {
const vi = this;
if (vi.destroyed) return;
if (vi.ad) vi.ad.resumeAd();
}
stop() {
const vi = this;
if (vi.destroyed) return;
if (vi.ad) vi.ad.stopAd();
}
init() {
const vi = this;
if (vi.destroyed) return;
if (vi.ad) vi.ad.initAd();
}
destroy() {
const vi = this;
vi.destroyed = true;
vi.emit('local::beforeDestroy');
Utils.deleteProps(vi);
}
}
var Vi = {
name: 'vi',
params: {
vi: {
enabled: false,
autoplay: true,
fallbackOverlay: true,
fallbackOverlayText: 'Please watch this ad',
showMute: true,
startMuted: (Device.ios || Device.android) && !Device.cordova,
appId: null,
appVer: null,
language: null,
width: null,
height: null,
placementId: 'pltd4o7ibb9rc653x14',
placementType: 'interstitial',
videoSlot: null,
showProgress: true,
showBranding: true,
os: null,
osVersion: null,
orientation: null,
age: null,
gender: null,
advertiserId: null,
latitude: null,
longitude: null,
accuracy: null,
storeId: null,
ip: null,
manufacturer: null,
model: null,
connectionType: null,
connectionProvider: null,
},
},
create() {
const app = this;
app.vi = {
sdkReady: false,
createAd(adParams) {
return new ViAd(app, adParams);
},
loadSdk() {
if (app.vi.skdReady) return;
const script = document.createElement('script');
script.onload = function onload() {
app.emit('viSdkReady');
app.vi.skdReady = true;
};
script.src = 'http://c.vi-serve.com/viadshtml/vi.min.js';
$('head').append(script);
},
};
},
on: {
init() {
const app = this;
if (app.params.vi.enabled || (app.passedParams.vi && app.passedParams.vi.enabled !== false)) app.vi.loadSdk();
},
},
};
var Typography = {
name: 'typography',
};
// F7 Class
// Core Modules
// Core Components
// Install Core Modules & Components
Framework7$1.use([
Device$2,
Support,
Utils$2,
Resize,
Request,
Touch,
Clicks,
Router,
History$2,
Storage$1,
Statusbar$1,
View$2,
Navbar$1,
Toolbar$1,
Subnavbar,
TouchRipple$$1,
Modal,
Dialog,
Popup,
LoginScreen,
Popover,
Actions,
Sheet,
Toast,
Preloader$1,
Progressbar$1,
Sortable$1,
Swipeout$1,
Accordion$1,
VirtualList,
Timeline,
Tabs,
Panel,
Card,
Chip,
Form,
Input$1,
Checkbox,
Radio,
Toggle,
Range,
SmartSelect,
Grid,
Calendar,
Picker,
InfiniteScroll$1,
PullToRefresh,
Lazy$1,
DataTable,
Fab$1,
Searchbar,
Messages,
Messagebar,
Swiper,
PhotoBrowser,
Notification,
Autocomplete,
Vi,
Typography
]);
export default Framework7$1;