' + tipuesearch_string_4;
+ else
+ l +=
+ '
' +
+ p.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
+ " " +
+ tipuesearch_string_5;
+ if (n.showTime)
+ (l +=
+ " (" +
+ ((new Date().getTime() - startTimer) / 1e3).toFixed(2) +
+ " " +
+ tipuesearch_string_14 +
+ ")"),
+ (n.showTime = !1);
+ if (((l += "
"), n.showRelated && c)) {
+ var E = "";
+ w = 0;
+ for (g = 0; g < tipuesearch_related.Related.length; g++)
+ if (h == tipuesearch_related.Related[g].search) {
+ if (
+ (w ||
+ (l +=
+ '
"));
+ }
+ s &&
+ (l +=
+ '
' +
+ tipuesearch_string_2 +
+ " " +
+ h +
+ ". " +
+ tipuesearch_string_3 +
+ '
' +
+ y +
+ " "),
+ d.sort(function(e, t) {
+ return t.score - e.score;
+ });
+ var I = 0;
+ n.imageZoom &&
+ (l +=
+ '
');
+ for (g = 0; g < d.length; g++) {
+ if (I >= o && I < n.show + o) {
+ if (
+ ((l += '
'),
+ (l +=
+ '
"),
+ n.debug &&
+ (l +=
+ '
Score: ' +
+ d[g].score +
+ "
"),
+ n.showURL)
+ ) {
+ var A = d[g].url.toLowerCase();
+ 0 == A.indexOf("http://") && (A = A.slice(7)),
+ (l +=
+ '
");
+ }
+ if (
+ (d[g].img &&
+ (n.imageZoom
+ ? (l +=
+ '
')
+ : (l +=
+ '
')),
+ d[g].desc)
+ ) {
+ var S = d[g].desc;
+ if (n.showContext) {
+ f = h.split(" ");
+ var O = d[g].desc.toLowerCase().indexOf(f[0]);
+ if (O > n.contextStart) {
+ var D = S.substr(O - n.contextBuffer),
+ k = D.indexOf(" ");
+ (D = S.substr(O - n.contextBuffer + k)),
+ (D = e.trim(D)).length > n.contextLength &&
+ (S = "... " + D);
+ }
+ }
+ if (c) {
+ f = h.split(" ");
+ for (w = 0; w < f.length; w++)
+ if (n.highlightTerms) {
+ var H = new RegExp("(" + f[w] + ")", "gi");
+ S = S.replace(H, "
$1");
+ }
+ } else if (n.highlightTerms) {
+ H = new RegExp("(" + h + ")", "gi");
+ S = S.replace(
+ H,
+ '$1 '
+ );
+ }
+ var R = "",
+ F = S.split(" ");
+ if (F.length < n.descriptiveWords) R = S;
+ else for (w = 0; w < n.descriptiveWords; w++) R += F[w] + " ";
+ "." != (R = e.trim(R)).charAt(R.length - 1) && (R += " ..."),
+ (l +=
+ '' +
+ (R = (R = R.replace(
+ /h0011/g,
+ 'span class="tipue_search_content_bold"'
+ )).replace(/h0012/g, "/span")) +
+ "
");
+ }
+ d[g].note &&
+ (l +=
+ '' + d[g].note + "
"),
+ (l += " ");
+ }
+ I++;
+ }
+ if (p > n.show) {
+ var P = Math.ceil(p / n.show),
+ N = o / n.show;
+ if (
+ (n.footerPages < 3 && (n.footerPages = 3),
+ (l +=
+ '");
+ }
+ } else
+ l +=
+ '
' + tipuesearch_string_8 + "
";
+ } else u ? (l += '
' + tipuesearch_string_8 + " " + tipuesearch_string_9 + "
") : 1 == n.minimumLength ? (l += '
' + tipuesearch_string_11 + "
") : (l += '
' + tipuesearch_string_12 + " " + n.minimumLength + " " + tipuesearch_string_13 + "
");
+ e("#tipue_search_content")
+ .hide()
+ .html(l)
+ .slideDown(200),
+ e("#tipue_search_replaced").click(function() {
+ r(0, !1);
+ }),
+ e(".tipue_search_related_btn").click(function() {
+ e("#tipue_search_input").val(e(this).attr("id")), r(0, !0);
+ }),
+ e(".tipue_search_image_zoom").click(function() {
+ e("#tipue_search_image_modal").fadeIn(300),
+ e("#tipue_search_zoom_img").attr("src", this.src);
+ var t = e(this).attr("data-url");
+ e("#tipue_search_zoom_url").attr("href", t);
+ var n =
+ this.alt +
+ '
";
+ e("#tipue_search_zoom_text").html(n);
+ }),
+ e(".tipue_search_image_close").click(function() {
+ e("#tipue_search_image_modal").fadeOut(300);
+ }),
+ e(".tipue_search_foot_box").click(function() {
+ var t = e(this)
+ .attr("id")
+ .split("_");
+ r(parseInt(t[0]), t[1]);
+ });
+ }
+ n.newWindow && (i = ' target="_blank"'),
+ o("q") && (e("#tipue_search_input").val(o("q")), r(0, !0)),
+ e(this).keyup(function(e) {
+ "13" == e.keyCode && r(0, !0);
+ });
+ });
+ };
+})(jQuery),
+ (function(e, t) {
+ "object" == typeof exports && "undefined" != typeof module
+ ? t()
+ : "function" == typeof define && define.amd
+ ? define(t)
+ : t();
+ })(0, function() {
+ "use strict";
+ var e =
+ "function" == typeof Symbol && "symbol" == typeof Symbol.iterator
+ ? function(e) {
+ return typeof e;
+ }
+ : function(e) {
+ return e &&
+ "function" == typeof Symbol &&
+ e.constructor === Symbol &&
+ e !== Symbol.prototype
+ ? "symbol"
+ : typeof e;
+ },
+ t = function(e, t) {
+ if (!(e instanceof t))
+ throw new TypeError("Cannot call a class as a function");
+ },
+ n = (function() {
+ function e(e, t) {
+ for (var n = 0; n < t.length; n++) {
+ var i = t[n];
+ (i.enumerable = i.enumerable || !1),
+ (i.configurable = !0),
+ "value" in i && (i.writable = !0),
+ Object.defineProperty(e, i.key, i);
+ }
+ }
+ return function(t, n, i) {
+ return n && e(t.prototype, n), i && e(t, i), t;
+ };
+ })(),
+ i = function(e, t) {
+ if ("function" != typeof t && null !== t)
+ throw new TypeError(
+ "Super expression must either be null or a function, not " +
+ typeof t
+ );
+ (e.prototype = Object.create(t && t.prototype, {
+ constructor: {
+ value: e,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ })),
+ t &&
+ (Object.setPrototypeOf
+ ? Object.setPrototypeOf(e, t)
+ : (e.__proto__ = t));
+ },
+ o = function(e, t) {
+ if (!e)
+ throw new ReferenceError(
+ "this hasn't been initialised - super() hasn't been called"
+ );
+ return !t || ("object" != typeof t && "function" != typeof t) ? e : t;
+ };
+ !(function(t, n) {
+ var i = t.document,
+ o = t.Object,
+ r = (function(e) {
+ var t,
+ n,
+ i,
+ r,
+ a = /^[A-Z]+[a-z]/,
+ l = function(e, t) {
+ (t = t.toLowerCase()) in s ||
+ ((s[e] = (s[e] || []).concat(t)),
+ (s[t] = s[t.toUpperCase()] = e));
+ },
+ s = (o.create || o)(null),
+ u = {};
+ for (n in e)
+ for (r in e[n])
+ for (i = e[n][r], s[r] = i, t = 0; t < i.length; t++)
+ s[i[t].toLowerCase()] = s[i[t].toUpperCase()] = r;
+ return (
+ (u.get = function(e) {
+ return "string" == typeof e
+ ? s[e] || (a.test(e) ? [] : "")
+ : (function(e) {
+ var t,
+ n = [];
+ for (t in s) e.test(t) && n.push(t);
+ return n;
+ })(e);
+ }),
+ (u.set = function(e, t) {
+ return a.test(e) ? l(e, t) : l(t, e), u;
+ }),
+ u
+ );
+ })({
+ collections: {
+ HTMLAllCollection: ["all"],
+ HTMLCollection: ["forms"],
+ HTMLFormControlsCollection: ["elements"],
+ HTMLOptionsCollection: ["options"]
+ },
+ elements: {
+ Element: ["element"],
+ HTMLAnchorElement: ["a"],
+ HTMLAppletElement: ["applet"],
+ HTMLAreaElement: ["area"],
+ HTMLAttachmentElement: ["attachment"],
+ HTMLAudioElement: ["audio"],
+ HTMLBRElement: ["br"],
+ HTMLBaseElement: ["base"],
+ HTMLBodyElement: ["body"],
+ HTMLButtonElement: ["button"],
+ HTMLCanvasElement: ["canvas"],
+ HTMLContentElement: ["content"],
+ HTMLDListElement: ["dl"],
+ HTMLDataElement: ["data"],
+ HTMLDataListElement: ["datalist"],
+ HTMLDetailsElement: ["details"],
+ HTMLDialogElement: ["dialog"],
+ HTMLDirectoryElement: ["dir"],
+ HTMLDivElement: ["div"],
+ HTMLDocument: ["document"],
+ HTMLElement: [
+ "element",
+ "abbr",
+ "address",
+ "article",
+ "aside",
+ "b",
+ "bdi",
+ "bdo",
+ "cite",
+ "code",
+ "command",
+ "dd",
+ "dfn",
+ "dt",
+ "em",
+ "figcaption",
+ "figure",
+ "footer",
+ "header",
+ "i",
+ "kbd",
+ "mark",
+ "nav",
+ "noscript",
+ "rp",
+ "rt",
+ "ruby",
+ "s",
+ "samp",
+ "section",
+ "small",
+ "strong",
+ "sub",
+ "summary",
+ "sup",
+ "u",
+ "var",
+ "wbr"
+ ],
+ HTMLEmbedElement: ["embed"],
+ HTMLFieldSetElement: ["fieldset"],
+ HTMLFontElement: ["font"],
+ HTMLFormElement: ["form"],
+ HTMLFrameElement: ["frame"],
+ HTMLFrameSetElement: ["frameset"],
+ HTMLHRElement: ["hr"],
+ HTMLHeadElement: ["head"],
+ HTMLHeadingElement: ["h1", "h2", "h3", "h4", "h5", "h6"],
+ HTMLHtmlElement: ["html"],
+ HTMLIFrameElement: ["iframe"],
+ HTMLImageElement: ["img"],
+ HTMLInputElement: ["input"],
+ HTMLKeygenElement: ["keygen"],
+ HTMLLIElement: ["li"],
+ HTMLLabelElement: ["label"],
+ HTMLLegendElement: ["legend"],
+ HTMLLinkElement: ["link"],
+ HTMLMapElement: ["map"],
+ HTMLMarqueeElement: ["marquee"],
+ HTMLMediaElement: ["media"],
+ HTMLMenuElement: ["menu"],
+ HTMLMenuItemElement: ["menuitem"],
+ HTMLMetaElement: ["meta"],
+ HTMLMeterElement: ["meter"],
+ HTMLModElement: ["del", "ins"],
+ HTMLOListElement: ["ol"],
+ HTMLObjectElement: ["object"],
+ HTMLOptGroupElement: ["optgroup"],
+ HTMLOptionElement: ["option"],
+ HTMLOutputElement: ["output"],
+ HTMLParagraphElement: ["p"],
+ HTMLParamElement: ["param"],
+ HTMLPictureElement: ["picture"],
+ HTMLPreElement: ["pre"],
+ HTMLProgressElement: ["progress"],
+ HTMLQuoteElement: ["blockquote", "q", "quote"],
+ HTMLScriptElement: ["script"],
+ HTMLSelectElement: ["select"],
+ HTMLShadowElement: ["shadow"],
+ HTMLSlotElement: ["slot"],
+ HTMLSourceElement: ["source"],
+ HTMLSpanElement: ["span"],
+ HTMLStyleElement: ["style"],
+ HTMLTableCaptionElement: ["caption"],
+ HTMLTableCellElement: ["td", "th"],
+ HTMLTableColElement: ["col", "colgroup"],
+ HTMLTableElement: ["table"],
+ HTMLTableRowElement: ["tr"],
+ HTMLTableSectionElement: ["thead", "tbody", "tfoot"],
+ HTMLTemplateElement: ["template"],
+ HTMLTextAreaElement: ["textarea"],
+ HTMLTimeElement: ["time"],
+ HTMLTitleElement: ["title"],
+ HTMLTrackElement: ["track"],
+ HTMLUListElement: ["ul"],
+ HTMLUnknownElement: ["unknown", "vhgroupv", "vkeygen"],
+ HTMLVideoElement: ["video"]
+ },
+ nodes: {
+ Attr: ["node"],
+ Audio: ["audio"],
+ CDATASection: ["node"],
+ CharacterData: ["node"],
+ Comment: ["#comment"],
+ Document: ["#document"],
+ DocumentFragment: ["#document-fragment"],
+ DocumentType: ["node"],
+ HTMLDocument: ["#document"],
+ Image: ["img"],
+ Option: ["option"],
+ ProcessingInstruction: ["node"],
+ ShadowRoot: ["#shadow-root"],
+ Text: ["#text"],
+ XMLDocument: ["xml"]
+ }
+ });
+ "object" !== (void 0 === n ? "undefined" : e(n)) &&
+ (n = { type: n || "auto" });
+ var a,
+ l,
+ s,
+ u,
+ c,
+ p,
+ d,
+ m,
+ h,
+ f = "registerElement",
+ g = "__" + f + ((1e5 * t.Math.random()) >> 0),
+ v = "addEventListener",
+ w = "attached",
+ y = "Callback",
+ b = "detached",
+ _ = "extends",
+ x = "attributeChanged" + y,
+ C = "connected" + y,
+ T = "disconnected" + y,
+ L = "created" + y,
+ E = "ADDITION",
+ M = "REMOVAL",
+ I = "DOMAttrModified",
+ A = "DOMContentLoaded",
+ S = "<",
+ O = "=",
+ D = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,
+ k = [
+ "ANNOTATION-XML",
+ "COLOR-PROFILE",
+ "FONT-FACE",
+ "FONT-FACE-SRC",
+ "FONT-FACE-URI",
+ "FONT-FACE-FORMAT",
+ "FONT-FACE-NAME",
+ "MISSING-GLYPH"
+ ],
+ H = [],
+ R = [],
+ F = "",
+ P = i.documentElement,
+ N =
+ H.indexOf ||
+ function(e) {
+ for (var t = this.length; t-- && this[t] !== e; );
+ return t;
+ },
+ z = o.prototype,
+ Z = z.hasOwnProperty,
+ U = z.isPrototypeOf,
+ B = o.defineProperty,
+ K = [],
+ V = o.getOwnPropertyDescriptor,
+ W = o.getOwnPropertyNames,
+ q = o.getPrototypeOf,
+ j = o.setPrototypeOf,
+ G = !!o.__proto__,
+ Y = "__dreCEv1",
+ X = t.customElements,
+ $ =
+ !/^force/.test(n.type) && !!(X && X.define && X.get && X.whenDefined),
+ Q = o.create || o,
+ J =
+ t.Map ||
+ function() {
+ var e,
+ t = [],
+ n = [];
+ return {
+ get: function(e) {
+ return n[N.call(t, e)];
+ },
+ set: function(i, o) {
+ (e = N.call(t, i)) < 0 ? (n[t.push(i) - 1] = o) : (n[e] = o);
+ }
+ };
+ },
+ ee =
+ t.Promise ||
+ function(e) {
+ var t = [],
+ n = !1,
+ i = {
+ catch: function() {
+ return i;
+ },
+ then: function(e) {
+ return t.push(e), n && setTimeout(o, 1), i;
+ }
+ };
+ function o(e) {
+ for (n = !0; t.length; ) t.shift()(e);
+ }
+ return e(o), i;
+ },
+ te = !1,
+ ne = Q(null),
+ ie = Q(null),
+ oe = new J(),
+ re = function(e) {
+ return e.toLowerCase();
+ },
+ ae =
+ o.create ||
+ function e(t) {
+ return t ? ((e.prototype = t), new e()) : this;
+ },
+ le =
+ j ||
+ (G
+ ? function(e, t) {
+ return (e.__proto__ = t), e;
+ }
+ : W && V
+ ? (function() {
+ function e(e, t) {
+ for (var n, i = W(t), o = 0, r = i.length; o < r; o++)
+ (n = i[o]), Z.call(e, n) || B(e, n, V(t, n));
+ }
+ return function(t, n) {
+ do {
+ e(t, n);
+ } while ((n = q(n)) && !U.call(n, t));
+ return t;
+ };
+ })()
+ : function(e, t) {
+ for (var n in t) e[n] = t[n];
+ return e;
+ }),
+ se = t.MutationObserver || t.WebKitMutationObserver,
+ ue = (t.HTMLElement || t.Element || t.Node).prototype,
+ ce = !U.call(ue, P),
+ pe = ce
+ ? function(e, t, n) {
+ return (e[t] = n.value), e;
+ }
+ : B,
+ de = ce
+ ? function(e) {
+ return 1 === e.nodeType;
+ }
+ : function(e) {
+ return U.call(ue, e);
+ },
+ me = ce && [],
+ he = ue.attachShadow,
+ fe = ue.cloneNode,
+ ge = ue.dispatchEvent,
+ ve = ue.getAttribute,
+ we = ue.hasAttribute,
+ ye = ue.removeAttribute,
+ be = ue.setAttribute,
+ _e = i.createElement,
+ xe = _e,
+ Ce = se && { attributes: !0, characterData: !0, attributeOldValue: !0 },
+ Te =
+ se ||
+ function(e) {
+ (Ae = !1), P.removeEventListener(I, Te);
+ },
+ Le = 0,
+ Ee = f in i && !/^force-all/.test(n.type),
+ Me = !0,
+ Ie = !1,
+ Ae = !0,
+ Se = !0,
+ Oe = !0;
+ function De() {
+ var e = a.splice(0, a.length);
+ for (Le = 0; e.length; ) e.shift().call(null, e.shift());
+ }
+ function ke(e, t) {
+ for (var n = 0, i = e.length; n < i; n++) Ke(e[n], t);
+ }
+ function He(e) {
+ return function(t) {
+ de(t) && (Ke(t, e), F.length && ke(t.querySelectorAll(F), e));
+ };
+ }
+ function Re(e) {
+ var t = ve.call(e, "is"),
+ n = e.nodeName.toUpperCase(),
+ i = N.call(H, t ? O + t.toUpperCase() : S + n);
+ return t && -1 < i && !Fe(n, t) ? -1 : i;
+ }
+ function Fe(e, t) {
+ return -1 < F.indexOf(e + '[is="' + t + '"]');
+ }
+ function Pe(e) {
+ var t = e.currentTarget,
+ n = e.attrChange,
+ i = e.attrName,
+ o = e.target,
+ r = e[E] || 2,
+ a = e[M] || 3;
+ !Oe ||
+ (o && o !== t) ||
+ !t[x] ||
+ "style" === i ||
+ (e.prevValue === e.newValue &&
+ ("" !== e.newValue || (n !== r && n !== a))) ||
+ t[x](i, n === r ? null : e.prevValue, n === a ? null : e.newValue);
+ }
+ function Ne(e) {
+ var t = He(e);
+ return function(e) {
+ a.push(t, e.target), Le && clearTimeout(Le), (Le = setTimeout(De, 1));
+ };
+ }
+ function ze(e) {
+ Se && ((Se = !1), e.currentTarget.removeEventListener(A, ze)),
+ F.length &&
+ ke((e.target || i).querySelectorAll(F), e.detail === b ? b : w),
+ ce &&
+ (function() {
+ for (var e, t = 0, n = me.length; t < n; t++)
+ (e = me[t]),
+ P.contains(e) || (n--, me.splice(t--, 1), Ke(e, b));
+ })();
+ }
+ function Ze(e, t) {
+ be.call(this, e, t), l.call(this, { target: this });
+ }
+ function Ue(e, t) {
+ le(e, t),
+ c
+ ? c.observe(e, Ce)
+ : (Ae &&
+ ((e.setAttribute = Ze),
+ (e[g] = u(e)),
+ e[v]("DOMSubtreeModified", l)),
+ e[v](I, Pe)),
+ e[L] && Oe && ((e.created = !0), e[L](), (e.created = !1));
+ }
+ function Be(e) {
+ throw new Error("A " + e + " type is already registered");
+ }
+ function Ke(e, t) {
+ var n,
+ i,
+ o = Re(e);
+ -1 < o &&
+ (d(e, R[o]),
+ (o = 0),
+ t !== w || e[w]
+ ? t !== b ||
+ e[b] ||
+ ((e[w] = !1), (e[b] = !0), (i = "disconnected"), (o = 1))
+ : ((e[b] = !1),
+ (e[w] = !0),
+ (i = "connected"),
+ (o = 1),
+ ce && N.call(me, e) < 0 && me.push(e)),
+ o && (n = e[t + y] || e[i + y]) && n.call(e));
+ }
+ function Ve() {}
+ function We(e, t, n) {
+ var o = (n && n[_]) || "",
+ r = t.prototype,
+ a = ae(r),
+ l = t.observedAttributes || K,
+ s = { prototype: a };
+ pe(a, L, {
+ value: function() {
+ if (te) te = !1;
+ else if (!this[Y]) {
+ (this[Y] = !0), new t(this), r[L] && r[L].call(this);
+ var e = ne[oe.get(t)];
+ (!$ || e.create.length > 1) && Ge(this);
+ }
+ }
+ }),
+ pe(a, x, {
+ value: function(e) {
+ -1 < N.call(l, e) && r[x].apply(this, arguments);
+ }
+ }),
+ r[C] && pe(a, "attachedCallback", { value: r[C] }),
+ r[T] && pe(a, "detachedCallback", { value: r[T] }),
+ o && (s[_] = o),
+ (e = e.toUpperCase()),
+ (ne[e] = { constructor: t, create: o ? [o, re(e)] : [e] }),
+ oe.set(t, e),
+ i[f](e.toLowerCase(), s),
+ Ye(e),
+ ie[e].r();
+ }
+ function qe(e) {
+ var t = ne[e.toUpperCase()];
+ return t && t.constructor;
+ }
+ function je(e) {
+ return "string" == typeof e ? e : (e && e.is) || "";
+ }
+ function Ge(e) {
+ for (var t, n = e[x], i = n ? e.attributes : K, o = i.length; o--; )
+ (t = i[o]),
+ n.call(e, t.name || t.nodeName, null, t.value || t.nodeValue);
+ }
+ function Ye(e) {
+ return (
+ (e = e.toUpperCase()) in ie ||
+ ((ie[e] = {}),
+ (ie[e].p = new ee(function(t) {
+ ie[e].r = t;
+ }))),
+ ie[e].p
+ );
+ }
+ function Xe() {
+ X && delete t.customElements,
+ B(t, "customElements", { configurable: !0, value: new Ve() }),
+ B(t, "CustomElementRegistry", { configurable: !0, value: Ve });
+ for (
+ var e = function(e) {
+ var n = t[e];
+ if (n) {
+ (t[e] = function(e) {
+ var t, o;
+ return (
+ e || (e = this),
+ e[Y] ||
+ ((te = !0),
+ (t = ne[oe.get(e.constructor)]),
+ ((e = (o = $ && 1 === t.create.length)
+ ? Reflect.construct(n, K, t.constructor)
+ : i.createElement.apply(i, t.create))[Y] = !0),
+ (te = !1),
+ o || Ge(e)),
+ e
+ );
+ }),
+ (t[e].prototype = n.prototype);
+ try {
+ n.prototype.constructor = t[e];
+ } catch (i) {
+ B(n, Y, { value: t[e] });
+ }
+ }
+ },
+ n = r.get(/^HTML[A-Z]*[a-z]/),
+ o = n.length;
+ o--;
+ e(n[o])
+ );
+ (i.createElement = function(e, t) {
+ var n = je(t);
+ return n ? xe.call(this, e, re(n)) : xe.call(this, e);
+ }),
+ Ee || ((Ie = !0), i[f](""));
+ }
+ if (
+ (se &&
+ (((h = i.createElement("div")).innerHTML = "
"),
+ new se(function(e, t) {
+ if (
+ e[0] &&
+ "childList" == e[0].type &&
+ !e[0].removedNodes[0].childNodes.length
+ ) {
+ var n = (h = V(ue, "innerHTML")) && h.set;
+ n &&
+ B(ue, "innerHTML", {
+ set: function(e) {
+ for (; this.lastChild; ) this.removeChild(this.lastChild);
+ n.call(this, e);
+ }
+ });
+ }
+ t.disconnect(), (h = null);
+ }).observe(h, { childList: !0, subtree: !0 }),
+ (h.innerHTML = "")),
+ Ee ||
+ (j || G
+ ? ((d = function(e, t) {
+ U.call(t, e) || Ue(e, t);
+ }),
+ (m = Ue))
+ : (m = d = function(e, t) {
+ e[g] || ((e[g] = o(!0)), Ue(e, t));
+ }),
+ ce
+ ? ((Ae = !1),
+ (function() {
+ var e = V(ue, v),
+ t = e.value,
+ n = function(e) {
+ var t = new CustomEvent(I, { bubbles: !0 });
+ (t.attrName = e),
+ (t.prevValue = ve.call(this, e)),
+ (t.newValue = null),
+ (t[M] = t.attrChange = 2),
+ ye.call(this, e),
+ ge.call(this, t);
+ },
+ i = function(e, t) {
+ var n = we.call(this, e),
+ i = n && ve.call(this, e),
+ o = new CustomEvent(I, { bubbles: !0 });
+ be.call(this, e, t),
+ (o.attrName = e),
+ (o.prevValue = n ? i : null),
+ (o.newValue = t),
+ n
+ ? (o.MODIFICATION = o.attrChange = 1)
+ : (o[E] = o.attrChange = 0),
+ ge.call(this, o);
+ },
+ o = function(e) {
+ var t,
+ n = e.currentTarget,
+ i = n[g],
+ o = e.propertyName;
+ i.hasOwnProperty(o) &&
+ ((i = i[o]),
+ ((t = new CustomEvent(I, { bubbles: !0 })).attrName =
+ i.name),
+ (t.prevValue = i.value || null),
+ (t.newValue = i.value = n[o] || null),
+ null == t.prevValue
+ ? (t[E] = t.attrChange = 0)
+ : (t.MODIFICATION = t.attrChange = 1),
+ ge.call(n, t));
+ };
+ (e.value = function(e, r, a) {
+ e === I &&
+ this[x] &&
+ this.setAttribute !== i &&
+ ((this[g] = {
+ className: { name: "class", value: this.className }
+ }),
+ (this.setAttribute = i),
+ (this.removeAttribute = n),
+ t.call(this, "propertychange", o)),
+ t.call(this, e, r, a);
+ }),
+ B(ue, v, e);
+ })())
+ : se ||
+ (P[v](I, Te),
+ P.setAttribute(g, 1),
+ P.removeAttribute(g),
+ Ae &&
+ ((l = function(e) {
+ var t, n, i;
+ if (this === e.target) {
+ for (i in ((t = this[g]), (this[g] = n = u(this)), n)) {
+ if (!(i in t)) return s(0, this, i, t[i], n[i], E);
+ if (n[i] !== t[i])
+ return s(1, this, i, t[i], n[i], "MODIFICATION");
+ }
+ for (i in t)
+ if (!(i in n)) return s(2, this, i, t[i], n[i], M);
+ }
+ }),
+ (s = function(e, t, n, i, o, r) {
+ var a = {
+ attrChange: e,
+ currentTarget: t,
+ attrName: n,
+ prevValue: i,
+ newValue: o
+ };
+ (a[r] = e), Pe(a);
+ }),
+ (u = function(e) {
+ for (
+ var t, n, i = {}, o = e.attributes, r = 0, a = o.length;
+ r < a;
+ r++
+ )
+ "setAttribute" !== (n = (t = o[r]).name) &&
+ (i[n] = t.value);
+ return i;
+ }))),
+ (i[f] = function(e, t) {
+ if (
+ ((n = e.toUpperCase()),
+ Me &&
+ ((Me = !1),
+ se
+ ? ((c = (function(e, t) {
+ function n(e, t) {
+ for (var n = 0, i = e.length; n < i; t(e[n++]));
+ }
+ return new se(function(i) {
+ for (var o, r, a, l = 0, s = i.length; l < s; l++)
+ "childList" === (o = i[l]).type
+ ? (n(o.addedNodes, e), n(o.removedNodes, t))
+ : ((r = o.target),
+ Oe &&
+ r[x] &&
+ "style" !== o.attributeName &&
+ (a = ve.call(r, o.attributeName)) !==
+ o.oldValue &&
+ r[x](o.attributeName, o.oldValue, a));
+ });
+ })(He(w), He(b))),
+ (p = function(e) {
+ return c.observe(e, { childList: !0, subtree: !0 }), e;
+ })(i),
+ he &&
+ (ue.attachShadow = function() {
+ return p(he.apply(this, arguments));
+ }))
+ : ((a = []),
+ i[v]("DOMNodeInserted", Ne(w)),
+ i[v]("DOMNodeRemoved", Ne(b))),
+ i[v](A, ze),
+ i[v]("readystatechange", ze),
+ (ue.cloneNode = function(e) {
+ var t = fe.call(this, !!e),
+ n = Re(t);
+ return (
+ -1 < n && m(t, R[n]),
+ e &&
+ F.length &&
+ (function(e) {
+ for (var t, n = 0, i = e.length; n < i; n++)
+ (t = e[n]), m(t, R[Re(t)]);
+ })(t.querySelectorAll(F)),
+ t
+ );
+ })),
+ Ie)
+ )
+ return (Ie = !1);
+ if (
+ (-2 < N.call(H, O + n) + N.call(H, S + n) && Be(e),
+ !D.test(n) || -1 < N.call(k, n))
+ )
+ throw new Error("The type " + e + " is invalid");
+ var n,
+ o,
+ r = function() {
+ return s ? i.createElement(u, n) : i.createElement(u);
+ },
+ l = t || z,
+ s = Z.call(l, _),
+ u = s ? t[_].toUpperCase() : n;
+ return (
+ s && -1 < N.call(H, S + u) && Be(u),
+ (o = H.push((s ? O : S) + n) - 1),
+ (F = F.concat(
+ F.length ? "," : "",
+ s ? u + '[is="' + e.toLowerCase() + '"]' : u
+ )),
+ (r.prototype = R[o] = Z.call(l, "prototype")
+ ? l.prototype
+ : ae(ue)),
+ F.length && ke(i.querySelectorAll(F), w),
+ r
+ );
+ }),
+ (i.createElement = xe = function(e, t) {
+ var n = je(t),
+ o = n ? _e.call(i, e, re(n)) : _e.call(i, e),
+ r = "" + e,
+ a = N.call(H, (n ? O : S) + (n || r).toUpperCase()),
+ l = -1 < a;
+ return (
+ n &&
+ (o.setAttribute("is", (n = n.toLowerCase())),
+ l && (l = Fe(r.toUpperCase(), n))),
+ (Oe = !i.createElement.innerHTMLHelper),
+ l && m(o, R[a]),
+ o
+ );
+ })),
+ (Ve.prototype = {
+ constructor: Ve,
+ define: $
+ ? function(e, t, n) {
+ if (n) We(e, t, n);
+ else {
+ var i = e.toUpperCase();
+ (ne[i] = { constructor: t, create: [i] }),
+ oe.set(t, i),
+ X.define(e, t);
+ }
+ }
+ : We,
+ get: $
+ ? function(e) {
+ return X.get(e) || qe(e);
+ }
+ : qe,
+ whenDefined: $
+ ? function(e) {
+ return ee.race([X.whenDefined(e), Ye(e)]);
+ }
+ : Ye
+ }),
+ !X || /^force/.test(n.type))
+ )
+ Xe();
+ else if (!n.noBuiltIn)
+ try {
+ !(function(e, n, o) {
+ if (
+ ((n[_] = "a"),
+ ((e.prototype = ae(HTMLAnchorElement.prototype)).constructor = e),
+ t.customElements.define(o, e, n),
+ ve.call(i.createElement("a", { is: o }), "is") !== o ||
+ ($ && ve.call(new e(), "is") !== o))
+ )
+ throw n;
+ })(
+ function e() {
+ return Reflect.construct(HTMLAnchorElement, [], e);
+ },
+ {},
+ "document-register-element-a"
+ );
+ } catch (e) {
+ Xe();
+ }
+ if (!n.noBuiltIn)
+ try {
+ _e.call(i, "a", "a");
+ } catch (e) {
+ re = function(e) {
+ return { is: e.toLowerCase() };
+ };
+ }
+ })(window);
+ var r = function(e) {
+ return e.toLocaleString("en");
+ },
+ a = (function(e) {
+ function r(e) {
+ var n;
+ return (
+ t(this, r),
+ ((n = o(
+ this,
+ (r.__proto__ || Object.getPrototypeOf(r)).call(this, e)
+ )),
+ (e = n)).init(),
+ o(n, e)
+ );
+ }
+ return i(r, e), n(r, [{ key: "init", value: function() {} }]), r;
+ })(HTMLElement),
+ l = (function(e) {
+ function l() {
+ return (
+ t(this, l),
+ o(
+ this,
+ (l.__proto__ || Object.getPrototypeOf(l)).apply(this, arguments)
+ )
+ );
+ }
+ return (
+ i(l, a),
+ n(
+ l,
+ [
+ {
+ key: "connectedCallback",
+ value: function() {
+ var e = this;
+ if (!this._connected) {
+ this.classList.add("loading"),
+ (this.style.display = "block"),
+ (this.innerHTML =
+ '\n
\n
\n
\n
\n \n \n \n \n \n \n \n \n \n
\n \n ' +
+ (5, new Array(5).fill(void 0))
+ .map(function(e) {
+ return ' ';
+ })
+ .join("") +
+ "\n \n \n
\n "),
+ (this._styleRootElement = this.querySelector(
+ ".style-root"
+ )),
+ (this._countElement = this.querySelector(".count")),
+ this._updateRootColor(),
+ (this._totalClaps = 0);
+ var t,
+ n,
+ i,
+ o,
+ a = void 0;
+ (this._initialClapCount = new Promise(function(e) {
+ return (a = e);
+ })),
+ (this._bufferedClaps = 0),
+ (this._updateClaps =
+ ((t = function() {
+ if (e._totalClaps < 10) {
+ var t = Math.min(
+ e._bufferedClaps,
+ 10 - e._totalClaps
+ );
+ (n = e.api),
+ (i = t),
+ (o = e.url),
+ fetch(
+ n + "/update-claps" + (o ? "?url=" + o : ""),
+ {
+ method: "POST",
+ headers: { "Content-Type": "text/plain" },
+ body: JSON.stringify(i + ",3.3.0")
+ }
+ ).then(function(e) {
+ return e.text();
+ }),
+ (e._totalClaps += t),
+ (e._bufferedClaps = 0);
+ }
+ var n, i, o;
+ }),
+ 2e3,
+ (n = null),
+ function() {
+ var e = this,
+ i = arguments;
+ clearTimeout(n),
+ (n = setTimeout(function() {
+ return t.apply(e, i);
+ }, 2e3));
+ })),
+ this.addEventListener("mousedown", function(t) {
+ if (
+ 0 === t.button &&
+ (e.classList.add("clapped"),
+ !e.classList.contains("clap-limit-exceeded"))
+ ) {
+ var n,
+ i,
+ o =
+ Number(
+ e._countElement.innerHTML.replace(",", "")
+ ) + 1;
+ e.dispatchEvent(
+ new CustomEvent("clapped", {
+ bubbles: !0,
+ detail: { clapCount: o }
+ })
+ ),
+ (i = "clap"),
+ (n = e).classList.remove(i),
+ setTimeout(function() {
+ n.classList.add(i);
+ }, 100),
+ setTimeout(function() {
+ n.classList.remove(i);
+ }, 1e3),
+ e._bufferedClaps++,
+ e._updateClaps(),
+ setTimeout(function() {
+ e._countElement.innerHTML = r(o);
+ }, 250),
+ e.multiclap
+ ? e._bufferedClaps + e._totalClaps >= 10 &&
+ e.classList.add("clap-limit-exceeded")
+ : e.classList.add("clap-limit-exceeded");
+ }
+ }),
+ ((i = this.api),
+ (o = this.url),
+ fetch(i + "/get-claps" + (o ? "?url=" + o : ""), {
+ headers: { "Content-Type": "text/plain" }
+ }).then(function(e) {
+ return e.text();
+ })).then(function(t) {
+ e.classList.remove("loading");
+ var n = Number(t);
+ a(n), n > 0 && (e._countElement.innerHTML = r(n));
+ }),
+ (this._connected = !0);
+ }
+ }
+ },
+ {
+ key: "attributeChangedCallback",
+ value: function(e, t, n) {
+ this._updateRootColor();
+ }
+ },
+ {
+ key: "_updateRootColor",
+ value: function() {
+ if (this._styleRootElement) {
+ var e = this.getAttribute("color") || "green",
+ t = this._styleRootElement.style;
+ (t.fill = e), (t.stroke = e), (t.color = e);
+ }
+ }
+ },
+ {
+ key: "initialClapCount",
+ get: function() {
+ return this._initialClapCount;
+ }
+ },
+ {
+ key: "color",
+ get: function() {
+ return this.getAttribute("color");
+ },
+ set: function(e) {
+ e
+ ? this.setAttribute("color", e)
+ : this.removeAttribute("color"),
+ this._updateRootColor();
+ }
+ },
+ {
+ key: "api",
+ set: function(e) {
+ e ? this.setAttribute("api", e) : this.removeAttribute("api");
+ },
+ get: function() {
+ return (
+ this.getAttribute("api") ||
+ "https://api.applause-button.com"
+ );
+ }
+ },
+ {
+ key: "url",
+ set: function(e) {
+ e ? this.setAttribute("url", e) : this.removeAttribute("url"),
+ this._updateRootColor();
+ },
+ get: function() {
+ return this.getAttribute("url");
+ }
+ },
+ {
+ key: "multiclap",
+ get: function() {
+ return "true" === this.getAttribute("multiclap");
+ },
+ set: function(e) {
+ e
+ ? this.setAttribute("multiclap", e ? "true" : "false")
+ : this.removeAttribute("multiclap");
+ }
+ }
+ ],
+ [
+ {
+ key: "observedAttributes",
+ get: function() {
+ return ["color"];
+ }
+ }
+ ]
+ ),
+ l
+ );
+ })();
+ customElements.define("applause-button", l);
+ }),
+ /*! PhotoSwipe - v4.1.3 - 2019-01-08
+ * http://photoswipe.com
+ * Copyright (c) 2019 Dmitry Semenov; */
+ (function(e, t) {
+ "function" == typeof define && define.amd
+ ? define(t)
+ : "object" == typeof exports
+ ? (module.exports = t())
+ : (e.PhotoSwipe = t());
+ })(this, function() {
+ "use strict";
+ return function(e, t, n, i) {
+ var o = {
+ features: null,
+ bind: function(e, t, n, i) {
+ var o = (i ? "remove" : "add") + "EventListener";
+ t = t.split(" ");
+ for (var r = 0; r < t.length; r++) t[r] && e[o](t[r], n, !1);
+ },
+ isArray: function(e) {
+ return e instanceof Array;
+ },
+ createEl: function(e, t) {
+ var n = document.createElement(t || "div");
+ return e && (n.className = e), n;
+ },
+ getScrollY: function() {
+ var e = window.pageYOffset;
+ return void 0 !== e ? e : document.documentElement.scrollTop;
+ },
+ unbind: function(e, t, n) {
+ o.bind(e, t, n, !0);
+ },
+ removeClass: function(e, t) {
+ var n = new RegExp("(\\s|^)" + t + "(\\s|$)");
+ e.className = e.className
+ .replace(n, " ")
+ .replace(/^\s\s*/, "")
+ .replace(/\s\s*$/, "");
+ },
+ addClass: function(e, t) {
+ o.hasClass(e, t) || (e.className += (e.className ? " " : "") + t);
+ },
+ hasClass: function(e, t) {
+ return (
+ e.className &&
+ new RegExp("(^|\\s)" + t + "(\\s|$)").test(e.className)
+ );
+ },
+ getChildByClass: function(e, t) {
+ for (var n = e.firstChild; n; ) {
+ if (o.hasClass(n, t)) return n;
+ n = n.nextSibling;
+ }
+ },
+ arraySearch: function(e, t, n) {
+ for (var i = e.length; i--; ) if (e[i][n] === t) return i;
+ return -1;
+ },
+ extend: function(e, t, n) {
+ for (var i in t)
+ if (t.hasOwnProperty(i)) {
+ if (n && e.hasOwnProperty(i)) continue;
+ e[i] = t[i];
+ }
+ },
+ easing: {
+ sine: {
+ out: function(e) {
+ return Math.sin(e * (Math.PI / 2));
+ },
+ inOut: function(e) {
+ return -(Math.cos(Math.PI * e) - 1) / 2;
+ }
+ },
+ cubic: {
+ out: function(e) {
+ return --e * e * e + 1;
+ }
+ }
+ },
+ detectFeatures: function() {
+ if (o.features) return o.features;
+ var e = o.createEl().style,
+ t = "",
+ n = {};
+ if (
+ ((n.oldIE = document.all && !document.addEventListener),
+ (n.touch = "ontouchstart" in window),
+ window.requestAnimationFrame &&
+ ((n.raf = window.requestAnimationFrame),
+ (n.caf = window.cancelAnimationFrame)),
+ (n.pointerEvent =
+ !!window.PointerEvent || navigator.msPointerEnabled),
+ !n.pointerEvent)
+ ) {
+ var i = navigator.userAgent;
+ if (/iP(hone|od)/.test(navigator.platform)) {
+ var r = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
+ r &&
+ r.length > 0 &&
+ (r = parseInt(r[1], 10)) >= 1 &&
+ r < 8 &&
+ (n.isOldIOSPhone = !0);
+ }
+ var a = i.match(/Android\s([0-9\.]*)/),
+ l = a ? a[1] : 0;
+ (l = parseFloat(l)) >= 1 &&
+ (l < 4.4 && (n.isOldAndroid = !0), (n.androidVersion = l)),
+ (n.isMobileOpera = /opera mini|opera mobi/i.test(i));
+ }
+ for (
+ var s,
+ u,
+ c = ["transform", "perspective", "animationName"],
+ p = ["", "webkit", "Moz", "ms", "O"],
+ d = 0;
+ d < 4;
+ d++
+ ) {
+ t = p[d];
+ for (var m = 0; m < 3; m++)
+ (s = c[m]),
+ (u = t + (t ? s.charAt(0).toUpperCase() + s.slice(1) : s)),
+ !n[s] && u in e && (n[s] = u);
+ t &&
+ !n.raf &&
+ ((t = t.toLowerCase()),
+ (n.raf = window[t + "RequestAnimationFrame"]),
+ n.raf &&
+ (n.caf =
+ window[t + "CancelAnimationFrame"] ||
+ window[t + "CancelRequestAnimationFrame"]));
+ }
+ if (!n.raf) {
+ var h = 0;
+ (n.raf = function(e) {
+ var t = new Date().getTime(),
+ n = Math.max(0, 16 - (t - h)),
+ i = window.setTimeout(function() {
+ e(t + n);
+ }, n);
+ return (h = t + n), i;
+ }),
+ (n.caf = function(e) {
+ clearTimeout(e);
+ });
+ }
+ return (
+ (n.svg =
+ !!document.createElementNS &&
+ !!document.createElementNS("http://www.w3.org/2000/svg", "svg")
+ .createSVGRect),
+ (o.features = n),
+ n
+ );
+ }
+ };
+ o.detectFeatures(),
+ o.features.oldIE &&
+ (o.bind = function(e, t, n, i) {
+ t = t.split(" ");
+ for (
+ var o,
+ r = (i ? "detach" : "attach") + "Event",
+ a = function() {
+ n.handleEvent.call(n);
+ },
+ l = 0;
+ l < t.length;
+ l++
+ )
+ if ((o = t[l]))
+ if ("object" == typeof n && n.handleEvent) {
+ if (i) {
+ if (!n["oldIE" + o]) return !1;
+ } else n["oldIE" + o] = a;
+ e[r]("on" + o, n["oldIE" + o]);
+ } else e[r]("on" + o, n);
+ });
+ var r = this,
+ a = {
+ allowPanToNext: !0,
+ spacing: 0.12,
+ bgOpacity: 1,
+ mouseUsed: !1,
+ loop: !0,
+ pinchToClose: !0,
+ closeOnScroll: !0,
+ closeOnVerticalDrag: !0,
+ verticalDragRange: 0.75,
+ hideAnimationDuration: 333,
+ showAnimationDuration: 333,
+ showHideOpacity: !1,
+ focus: !0,
+ escKey: !0,
+ arrowKeys: !0,
+ mainScrollEndFriction: 0.35,
+ panEndFriction: 0.35,
+ isClickableElement: function(e) {
+ return "A" === e.tagName;
+ },
+ getDoubleTapZoom: function(e, t) {
+ return e ? 1 : t.initialZoomLevel < 0.7 ? 1 : 1.33;
+ },
+ maxSpreadZoom: 1.33,
+ modal: !0,
+ scaleMode: "fit"
+ };
+ o.extend(a, i);
+ var l,
+ s,
+ u,
+ c,
+ p,
+ d,
+ m,
+ h,
+ f,
+ g,
+ v,
+ w,
+ y,
+ b,
+ _,
+ x,
+ C,
+ T,
+ L,
+ E,
+ M,
+ I,
+ A,
+ S,
+ O,
+ D,
+ k,
+ H,
+ R,
+ F,
+ P,
+ N,
+ z,
+ Z,
+ U,
+ B,
+ K,
+ V,
+ W,
+ q,
+ j,
+ G,
+ Y,
+ X,
+ $,
+ Q,
+ J,
+ ee,
+ te,
+ ne,
+ ie,
+ oe,
+ re,
+ ae,
+ le,
+ se,
+ ue = { x: 0, y: 0 },
+ ce = { x: 0, y: 0 },
+ pe = { x: 0, y: 0 },
+ de = {},
+ me = 0,
+ he = {},
+ fe = { x: 0, y: 0 },
+ ge = 0,
+ ve = !0,
+ we = [],
+ ye = {},
+ be = !1,
+ _e = function(e, t) {
+ o.extend(r, t.publicMethods), we.push(e);
+ },
+ xe = function(e) {
+ var t = Ut();
+ return e > t - 1 ? e - t : e < 0 ? t + e : e;
+ },
+ Ce = {},
+ Te = function(e, t) {
+ return Ce[e] || (Ce[e] = []), Ce[e].push(t);
+ },
+ Le = function(e) {
+ var t = Ce[e];
+ if (t) {
+ var n = Array.prototype.slice.call(arguments);
+ n.shift();
+ for (var i = 0; i < t.length; i++) t[i].apply(r, n);
+ }
+ },
+ Ee = function() {
+ return new Date().getTime();
+ },
+ Me = function(e) {
+ (ae = e), (r.bg.style.opacity = e * a.bgOpacity);
+ },
+ Ie = function(e, t, n, i, o) {
+ (!be || (o && o !== r.currItem)) &&
+ (i /= o ? o.fitRatio : r.currItem.fitRatio),
+ (e[I] = w + t + "px, " + n + "px" + y + " scale(" + i + ")");
+ },
+ Ae = function(e) {
+ te &&
+ (e &&
+ (g > r.currItem.fitRatio
+ ? be || (Xt(r.currItem, !1, !0), (be = !0))
+ : be && (Xt(r.currItem), (be = !1))),
+ Ie(te, pe.x, pe.y, g));
+ },
+ Se = function(e) {
+ e.container &&
+ Ie(
+ e.container.style,
+ e.initialPosition.x,
+ e.initialPosition.y,
+ e.initialZoomLevel,
+ e
+ );
+ },
+ Oe = function(e, t) {
+ t[I] = w + e + "px, 0px" + y;
+ },
+ De = function(e, t) {
+ if (!a.loop && t) {
+ var n = c + (fe.x * me - e) / fe.x,
+ i = Math.round(e - ct.x);
+ ((n < 0 && i > 0) || (n >= Ut() - 1 && i < 0)) &&
+ (e = ct.x + i * a.mainScrollEndFriction);
+ }
+ (ct.x = e), Oe(e, p);
+ },
+ ke = function(e, t) {
+ var n = pt[e] - he[e];
+ return ce[e] + ue[e] + n - n * (t / v);
+ },
+ He = function(e, t) {
+ (e.x = t.x), (e.y = t.y), t.id && (e.id = t.id);
+ },
+ Re = function(e) {
+ (e.x = Math.round(e.x)), (e.y = Math.round(e.y));
+ },
+ Fe = null,
+ Pe = function() {
+ Fe &&
+ (o.unbind(document, "mousemove", Pe),
+ o.addClass(e, "pswp--has_mouse"),
+ (a.mouseUsed = !0),
+ Le("mouseUsed")),
+ (Fe = setTimeout(function() {
+ Fe = null;
+ }, 100));
+ },
+ Ne = function(e, t) {
+ var n = qt(r.currItem, de, e);
+ return t && (ee = n), n;
+ },
+ ze = function(e) {
+ return e || (e = r.currItem), e.initialZoomLevel;
+ },
+ Ze = function(e) {
+ return e || (e = r.currItem), e.w > 0 ? a.maxSpreadZoom : 1;
+ },
+ Ue = function(e, t, n, i) {
+ return i === r.currItem.initialZoomLevel
+ ? ((n[e] = r.currItem.initialPosition[e]), !0)
+ : ((n[e] = ke(e, i)),
+ n[e] > t.min[e]
+ ? ((n[e] = t.min[e]), !0)
+ : n[e] < t.max[e] && ((n[e] = t.max[e]), !0));
+ },
+ Be = function(e) {
+ var t = "";
+ a.escKey && 27 === e.keyCode
+ ? (t = "close")
+ : a.arrowKeys &&
+ (37 === e.keyCode
+ ? (t = "prev")
+ : 39 === e.keyCode && (t = "next")),
+ t &&
+ (e.ctrlKey ||
+ e.altKey ||
+ e.shiftKey ||
+ e.metaKey ||
+ (e.preventDefault ? e.preventDefault() : (e.returnValue = !1),
+ r[t]()));
+ },
+ Ke = function(e) {
+ e && (G || j || ne || K) && (e.preventDefault(), e.stopPropagation());
+ },
+ Ve = function() {
+ r.setScrollOffset(0, o.getScrollY());
+ },
+ We = {},
+ qe = 0,
+ je = function(e) {
+ We[e] && (We[e].raf && D(We[e].raf), qe--, delete We[e]);
+ },
+ Ge = function(e) {
+ We[e] && je(e), We[e] || (qe++, (We[e] = {}));
+ },
+ Ye = function() {
+ for (var e in We) We.hasOwnProperty(e) && je(e);
+ },
+ Xe = function(e, t, n, i, o, r, a) {
+ var l,
+ s = Ee();
+ Ge(e);
+ var u = function() {
+ if (We[e]) {
+ if ((l = Ee() - s) >= i) return je(e), r(n), void (a && a());
+ r((n - t) * o(l / i) + t), (We[e].raf = O(u));
+ }
+ };
+ u();
+ },
+ $e = {
+ shout: Le,
+ listen: Te,
+ viewportSize: de,
+ options: a,
+ isMainScrollAnimating: function() {
+ return ne;
+ },
+ getZoomLevel: function() {
+ return g;
+ },
+ getCurrentIndex: function() {
+ return c;
+ },
+ isDragging: function() {
+ return W;
+ },
+ isZooming: function() {
+ return Q;
+ },
+ setScrollOffset: function(e, t) {
+ (he.x = e), (F = he.y = t), Le("updateScrollOffset", he);
+ },
+ applyZoomPan: function(e, t, n, i) {
+ (pe.x = t), (pe.y = n), (g = e), Ae(i);
+ },
+ init: function() {
+ if (!l && !s) {
+ var n;
+ (r.framework = o),
+ (r.template = e),
+ (r.bg = o.getChildByClass(e, "pswp__bg")),
+ (k = e.className),
+ (l = !0),
+ (P = o.detectFeatures()),
+ (O = P.raf),
+ (D = P.caf),
+ (I = P.transform),
+ (R = P.oldIE),
+ (r.scrollWrap = o.getChildByClass(e, "pswp__scroll-wrap")),
+ (r.container = o.getChildByClass(
+ r.scrollWrap,
+ "pswp__container"
+ )),
+ (p = r.container.style),
+ (r.itemHolders = x = [
+ { el: r.container.children[0], wrap: 0, index: -1 },
+ { el: r.container.children[1], wrap: 0, index: -1 },
+ { el: r.container.children[2], wrap: 0, index: -1 }
+ ]),
+ (x[0].el.style.display = x[2].el.style.display = "none"),
+ (function() {
+ if (I) {
+ var t = P.perspective && !S;
+ return (
+ (w = "translate" + (t ? "3d(" : "(")),
+ void (y = P.perspective ? ", 0px)" : ")")
+ );
+ }
+ (I = "left"),
+ o.addClass(e, "pswp--ie"),
+ (Oe = function(e, t) {
+ t.left = e + "px";
+ }),
+ (Se = function(e) {
+ var t = e.fitRatio > 1 ? 1 : e.fitRatio,
+ n = e.container.style,
+ i = t * e.w,
+ o = t * e.h;
+ (n.width = i + "px"),
+ (n.height = o + "px"),
+ (n.left = e.initialPosition.x + "px"),
+ (n.top = e.initialPosition.y + "px");
+ }),
+ (Ae = function() {
+ if (te) {
+ var e = te,
+ t = r.currItem,
+ n = t.fitRatio > 1 ? 1 : t.fitRatio,
+ i = n * t.w,
+ o = n * t.h;
+ (e.width = i + "px"),
+ (e.height = o + "px"),
+ (e.left = pe.x + "px"),
+ (e.top = pe.y + "px");
+ }
+ });
+ })(),
+ (f = {
+ resize: r.updateSize,
+ orientationchange: function() {
+ clearTimeout(N),
+ (N = setTimeout(function() {
+ de.x !== r.scrollWrap.clientWidth && r.updateSize();
+ }, 500));
+ },
+ scroll: Ve,
+ keydown: Be,
+ click: Ke
+ });
+ var i = P.isOldIOSPhone || P.isOldAndroid || P.isMobileOpera;
+ for (
+ (P.animationName && P.transform && !i) ||
+ (a.showAnimationDuration = a.hideAnimationDuration = 0),
+ n = 0;
+ n < we.length;
+ n++
+ )
+ r["init" + we[n]]();
+ if (t) (r.ui = new t(r, o)).init();
+ Le("firstUpdate"),
+ (c = c || a.index || 0),
+ (isNaN(c) || c < 0 || c >= Ut()) && (c = 0),
+ (r.currItem = Zt(c)),
+ (P.isOldIOSPhone || P.isOldAndroid) && (ve = !1),
+ e.setAttribute("aria-hidden", "false"),
+ a.modal &&
+ (ve
+ ? (e.style.position = "fixed")
+ : ((e.style.position = "absolute"),
+ (e.style.top = o.getScrollY() + "px"))),
+ void 0 === F && (Le("initialLayout"), (F = H = o.getScrollY()));
+ var u = "pswp--open ";
+ for (
+ a.mainClass && (u += a.mainClass + " "),
+ a.showHideOpacity && (u += "pswp--animate_opacity "),
+ u += S ? "pswp--touch" : "pswp--notouch",
+ u += P.animationName ? " pswp--css_animation" : "",
+ u += P.svg ? " pswp--svg" : "",
+ o.addClass(e, u),
+ r.updateSize(),
+ d = -1,
+ ge = null,
+ n = 0;
+ n < 3;
+ n++
+ )
+ Oe((n + d) * fe.x, x[n].el.style);
+ R || o.bind(r.scrollWrap, h, r),
+ Te("initialZoomInEnd", function() {
+ r.setContent(x[0], c - 1),
+ r.setContent(x[2], c + 1),
+ (x[0].el.style.display = x[2].el.style.display = "block"),
+ a.focus && e.focus(),
+ o.bind(document, "keydown", r),
+ P.transform && o.bind(r.scrollWrap, "click", r),
+ a.mouseUsed || o.bind(document, "mousemove", Pe),
+ o.bind(window, "resize scroll orientationchange", r),
+ Le("bindEvents");
+ }),
+ r.setContent(x[1], c),
+ r.updateCurrItem(),
+ Le("afterInit"),
+ ve ||
+ (b = setInterval(function() {
+ qe ||
+ W ||
+ Q ||
+ g !== r.currItem.initialZoomLevel ||
+ r.updateSize();
+ }, 1e3)),
+ o.addClass(e, "pswp--visible");
+ }
+ },
+ close: function() {
+ l &&
+ ((l = !1),
+ (s = !0),
+ Le("close"),
+ o.unbind(window, "resize scroll orientationchange", r),
+ o.unbind(window, "scroll", f.scroll),
+ o.unbind(document, "keydown", r),
+ o.unbind(document, "mousemove", Pe),
+ P.transform && o.unbind(r.scrollWrap, "click", r),
+ W && o.unbind(window, m, r),
+ clearTimeout(N),
+ Le("unbindEvents"),
+ Bt(r.currItem, null, !0, r.destroy));
+ },
+ destroy: function() {
+ Le("destroy"),
+ Ft && clearTimeout(Ft),
+ e.setAttribute("aria-hidden", "true"),
+ (e.className = k),
+ b && clearInterval(b),
+ o.unbind(r.scrollWrap, h, r),
+ o.unbind(window, "scroll", r),
+ ht(),
+ Ye(),
+ (Ce = null);
+ },
+ panTo: function(e, t, n) {
+ n ||
+ (e > ee.min.x ? (e = ee.min.x) : e < ee.max.x && (e = ee.max.x),
+ t > ee.min.y ? (t = ee.min.y) : t < ee.max.y && (t = ee.max.y)),
+ (pe.x = e),
+ (pe.y = t),
+ Ae();
+ },
+ handleEvent: function(e) {
+ (e = e || window.event), f[e.type] && f[e.type](e);
+ },
+ goTo: function(e) {
+ var t = (e = xe(e)) - c;
+ (ge = t),
+ (c = e),
+ (r.currItem = Zt(c)),
+ (me -= t),
+ De(fe.x * me),
+ Ye(),
+ (ne = !1),
+ r.updateCurrItem();
+ },
+ next: function() {
+ r.goTo(c + 1);
+ },
+ prev: function() {
+ r.goTo(c - 1);
+ },
+ updateCurrZoomItem: function(e) {
+ if ((e && Le("beforeChange", 0), x[1].el.children.length)) {
+ var t = x[1].el.children[0];
+ te = o.hasClass(t, "pswp__zoom-wrap") ? t.style : null;
+ } else te = null;
+ (ee = r.currItem.bounds),
+ (v = g = r.currItem.initialZoomLevel),
+ (pe.x = ee.center.x),
+ (pe.y = ee.center.y),
+ e && Le("afterChange");
+ },
+ invalidateCurrItems: function() {
+ _ = !0;
+ for (var e = 0; e < 3; e++)
+ x[e].item && (x[e].item.needsUpdate = !0);
+ },
+ updateCurrItem: function(e) {
+ if (0 !== ge) {
+ var t,
+ n = Math.abs(ge);
+ if (!(e && n < 2)) {
+ (r.currItem = Zt(c)),
+ (be = !1),
+ Le("beforeChange", ge),
+ n >= 3 && ((d += ge + (ge > 0 ? -3 : 3)), (n = 3));
+ for (var i = 0; i < n; i++)
+ ge > 0
+ ? ((t = x.shift()),
+ (x[2] = t),
+ d++,
+ Oe((d + 2) * fe.x, t.el.style),
+ r.setContent(t, c - n + i + 1 + 1))
+ : ((t = x.pop()),
+ x.unshift(t),
+ d--,
+ Oe(d * fe.x, t.el.style),
+ r.setContent(t, c + n - i - 1 - 1));
+ if (te && 1 === Math.abs(ge)) {
+ var o = Zt(C);
+ o.initialZoomLevel !== g && (qt(o, de), Xt(o), Se(o));
+ }
+ (ge = 0), r.updateCurrZoomItem(), (C = c), Le("afterChange");
+ }
+ }
+ },
+ updateSize: function(t) {
+ if (!ve && a.modal) {
+ var n = o.getScrollY();
+ if (
+ (F !== n && ((e.style.top = n + "px"), (F = n)),
+ !t && ye.x === window.innerWidth && ye.y === window.innerHeight)
+ )
+ return;
+ (ye.x = window.innerWidth),
+ (ye.y = window.innerHeight),
+ (e.style.height = ye.y + "px");
+ }
+ if (
+ ((de.x = r.scrollWrap.clientWidth),
+ (de.y = r.scrollWrap.clientHeight),
+ Ve(),
+ (fe.x = de.x + Math.round(de.x * a.spacing)),
+ (fe.y = de.y),
+ De(fe.x * me),
+ Le("beforeResize"),
+ void 0 !== d)
+ ) {
+ for (var i, l, s, u = 0; u < 3; u++)
+ (i = x[u]),
+ Oe((u + d) * fe.x, i.el.style),
+ (s = c + u - 1),
+ a.loop && Ut() > 2 && (s = xe(s)),
+ (l = Zt(s)) && (_ || l.needsUpdate || !l.bounds)
+ ? (r.cleanSlide(l),
+ r.setContent(i, s),
+ 1 === u && ((r.currItem = l), r.updateCurrZoomItem(!0)),
+ (l.needsUpdate = !1))
+ : -1 === i.index && s >= 0 && r.setContent(i, s),
+ l && l.container && (qt(l, de), Xt(l), Se(l));
+ _ = !1;
+ }
+ (v = g = r.currItem.initialZoomLevel),
+ (ee = r.currItem.bounds) &&
+ ((pe.x = ee.center.x), (pe.y = ee.center.y), Ae(!0)),
+ Le("resize");
+ },
+ zoomTo: function(e, t, n, i, r) {
+ t &&
+ ((v = g),
+ (pt.x = Math.abs(t.x) - pe.x),
+ (pt.y = Math.abs(t.y) - pe.y),
+ He(ce, pe));
+ var a = Ne(e, !1),
+ l = {};
+ Ue("x", a, l, e), Ue("y", a, l, e);
+ var s = g,
+ u = pe.x,
+ c = pe.y;
+ Re(l);
+ var p = function(t) {
+ 1 === t
+ ? ((g = e), (pe.x = l.x), (pe.y = l.y))
+ : ((g = (e - s) * t + s),
+ (pe.x = (l.x - u) * t + u),
+ (pe.y = (l.y - c) * t + c)),
+ r && r(t),
+ Ae(1 === t);
+ };
+ n ? Xe("customZoomTo", 0, 1, n, i || o.easing.sine.inOut, p) : p(1);
+ }
+ },
+ Qe = {},
+ Je = {},
+ et = {},
+ tt = {},
+ nt = {},
+ it = [],
+ ot = {},
+ rt = [],
+ at = {},
+ lt = 0,
+ st = { x: 0, y: 0 },
+ ut = 0,
+ ct = { x: 0, y: 0 },
+ pt = { x: 0, y: 0 },
+ dt = { x: 0, y: 0 },
+ mt = function(e, t) {
+ return (
+ (at.x = Math.abs(e.x - t.x)),
+ (at.y = Math.abs(e.y - t.y)),
+ Math.sqrt(at.x * at.x + at.y * at.y)
+ );
+ },
+ ht = function() {
+ Y && (D(Y), (Y = null));
+ },
+ ft = function() {
+ W && ((Y = O(ft)), At());
+ },
+ gt = function(e, t) {
+ return (
+ !(!e || e === document) &&
+ !(
+ e.getAttribute("class") &&
+ e.getAttribute("class").indexOf("pswp__scroll-wrap") > -1
+ ) &&
+ (t(e) ? e : gt(e.parentNode, t))
+ );
+ },
+ vt = {},
+ wt = function(e, t) {
+ return (
+ (vt.prevent = !gt(e.target, a.isClickableElement)),
+ Le("preventDragEvent", e, t, vt),
+ vt.prevent
+ );
+ },
+ yt = function(e, t) {
+ return (t.x = e.pageX), (t.y = e.pageY), (t.id = e.identifier), t;
+ },
+ bt = function(e, t, n) {
+ (n.x = 0.5 * (e.x + t.x)), (n.y = 0.5 * (e.y + t.y));
+ },
+ _t = function() {
+ var e = pe.y - r.currItem.initialPosition.y;
+ return 1 - Math.abs(e / (de.y / 2));
+ },
+ xt = {},
+ Ct = {},
+ Tt = [],
+ Lt = function(e) {
+ for (; Tt.length > 0; ) Tt.pop();
+ return (
+ A
+ ? ((se = 0),
+ it.forEach(function(e) {
+ 0 === se ? (Tt[0] = e) : 1 === se && (Tt[1] = e), se++;
+ }))
+ : e.type.indexOf("touch") > -1
+ ? e.touches &&
+ e.touches.length > 0 &&
+ ((Tt[0] = yt(e.touches[0], xt)),
+ e.touches.length > 1 && (Tt[1] = yt(e.touches[1], Ct)))
+ : ((xt.x = e.pageX),
+ (xt.y = e.pageY),
+ (xt.id = ""),
+ (Tt[0] = xt)),
+ Tt
+ );
+ },
+ Et = function(e, t) {
+ var n,
+ i,
+ o,
+ l,
+ s = pe[e] + t[e],
+ u = t[e] > 0,
+ c = ct.x + t.x,
+ p = ct.x - ot.x;
+ if (
+ ((n = s > ee.min[e] || s < ee.max[e] ? a.panEndFriction : 1),
+ (s = pe[e] + t[e] * n),
+ (a.allowPanToNext || g === r.currItem.initialZoomLevel) &&
+ (te
+ ? "h" !== ie ||
+ "x" !== e ||
+ j ||
+ (u
+ ? (s > ee.min[e] &&
+ ((n = a.panEndFriction),
+ ee.min[e] - s,
+ (i = ee.min[e] - ce[e])),
+ (i <= 0 || p < 0) && Ut() > 1
+ ? ((l = c), p < 0 && c > ot.x && (l = ot.x))
+ : ee.min.x !== ee.max.x && (o = s))
+ : (s < ee.max[e] &&
+ ((n = a.panEndFriction),
+ s - ee.max[e],
+ (i = ce[e] - ee.max[e])),
+ (i <= 0 || p > 0) && Ut() > 1
+ ? ((l = c), p > 0 && c < ot.x && (l = ot.x))
+ : ee.min.x !== ee.max.x && (o = s)))
+ : (l = c),
+ "x" === e))
+ )
+ return (
+ void 0 !== l && (De(l, !0), (X = l !== ot.x)),
+ ee.min.x !== ee.max.x &&
+ (void 0 !== o ? (pe.x = o) : X || (pe.x += t.x * n)),
+ void 0 !== l
+ );
+ ne || X || (g > r.currItem.fitRatio && (pe[e] += t[e] * n));
+ },
+ Mt = function(e) {
+ if (!("mousedown" === e.type && e.button > 0))
+ if (zt) e.preventDefault();
+ else if (!V || "mousedown" !== e.type) {
+ if ((wt(e, !0) && e.preventDefault(), Le("pointerDown"), A)) {
+ var t = o.arraySearch(it, e.pointerId, "id");
+ t < 0 && (t = it.length),
+ (it[t] = { x: e.pageX, y: e.pageY, id: e.pointerId });
+ }
+ var n = Lt(e),
+ i = n.length;
+ ($ = null),
+ Ye(),
+ (W && 1 !== i) ||
+ ((W = oe = !0),
+ o.bind(window, m, r),
+ (B = le = re = K = X = G = q = j = !1),
+ (ie = null),
+ Le("firstTouchStart", n),
+ He(ce, pe),
+ (ue.x = ue.y = 0),
+ He(tt, n[0]),
+ He(nt, tt),
+ (ot.x = fe.x * me),
+ (rt = [{ x: tt.x, y: tt.y }]),
+ (Z = z = Ee()),
+ Ne(g, !0),
+ ht(),
+ ft()),
+ !Q &&
+ i > 1 &&
+ !ne &&
+ !X &&
+ ((v = g),
+ (j = !1),
+ (Q = q = !0),
+ (ue.y = ue.x = 0),
+ He(ce, pe),
+ He(Qe, n[0]),
+ He(Je, n[1]),
+ bt(Qe, Je, dt),
+ (pt.x = Math.abs(dt.x) - pe.x),
+ (pt.y = Math.abs(dt.y) - pe.y),
+ (J = mt(Qe, Je)));
+ }
+ },
+ It = function(e) {
+ if ((e.preventDefault(), A)) {
+ var t = o.arraySearch(it, e.pointerId, "id");
+ if (t > -1) {
+ var n = it[t];
+ (n.x = e.pageX), (n.y = e.pageY);
+ }
+ }
+ if (W) {
+ var i = Lt(e);
+ if (ie || G || Q) $ = i;
+ else if (ct.x !== fe.x * me) ie = "h";
+ else {
+ var r = Math.abs(i[0].x - tt.x) - Math.abs(i[0].y - tt.y);
+ Math.abs(r) >= 10 && ((ie = r > 0 ? "h" : "v"), ($ = i));
+ }
+ }
+ },
+ At = function() {
+ if ($) {
+ var e = $.length;
+ if (0 !== e)
+ if (
+ (He(Qe, $[0]),
+ (et.x = Qe.x - tt.x),
+ (et.y = Qe.y - tt.y),
+ Q && e > 1)
+ ) {
+ if (
+ ((tt.x = Qe.x),
+ (tt.y = Qe.y),
+ !et.x &&
+ !et.y &&
+ (function(e, t) {
+ return e.x === t.x && e.y === t.y;
+ })($[1], Je))
+ )
+ return;
+ He(Je, $[1]), j || ((j = !0), Le("zoomGestureStarted"));
+ var t = mt(Qe, Je),
+ n = Ht(t);
+ n >
+ r.currItem.initialZoomLevel +
+ r.currItem.initialZoomLevel / 15 && (le = !0);
+ var i = 1,
+ o = ze(),
+ l = Ze();
+ if (n < o)
+ if (
+ a.pinchToClose &&
+ !le &&
+ v <= r.currItem.initialZoomLevel
+ ) {
+ var s = 1 - (o - n) / (o / 1.2);
+ Me(s), Le("onPinchClose", s), (re = !0);
+ } else
+ (i = (o - n) / o) > 1 && (i = 1), (n = o - i * (o / 3));
+ else
+ n > l &&
+ ((i = (n - l) / (6 * o)) > 1 && (i = 1), (n = l + i * o));
+ i < 0 && (i = 0),
+ t,
+ bt(Qe, Je, st),
+ (ue.x += st.x - dt.x),
+ (ue.y += st.y - dt.y),
+ He(dt, st),
+ (pe.x = ke("x", n)),
+ (pe.y = ke("y", n)),
+ (B = n > g),
+ (g = n),
+ Ae();
+ } else {
+ if (!ie) return;
+ if (
+ (oe &&
+ ((oe = !1),
+ Math.abs(et.x) >= 10 && (et.x -= $[0].x - nt.x),
+ Math.abs(et.y) >= 10 && (et.y -= $[0].y - nt.y)),
+ (tt.x = Qe.x),
+ (tt.y = Qe.y),
+ 0 === et.x && 0 === et.y)
+ )
+ return;
+ if (
+ "v" === ie &&
+ a.closeOnVerticalDrag &&
+ "fit" === a.scaleMode &&
+ g === r.currItem.initialZoomLevel
+ ) {
+ (ue.y += et.y), (pe.y += et.y);
+ var u = _t();
+ return (K = !0), Le("onVerticalDrag", u), Me(u), void Ae();
+ }
+ !(function(e, t, n) {
+ if (e - Z > 50) {
+ var i = rt.length > 2 ? rt.shift() : {};
+ (i.x = t), (i.y = n), rt.push(i), (Z = e);
+ }
+ })(Ee(), Qe.x, Qe.y),
+ (G = !0),
+ (ee = r.currItem.bounds),
+ Et("x", et) || (Et("y", et), Re(pe), Ae());
+ }
+ }
+ },
+ St = function(e) {
+ if (P.isOldAndroid) {
+ if (V && "mouseup" === e.type) return;
+ e.type.indexOf("touch") > -1 &&
+ (clearTimeout(V),
+ (V = setTimeout(function() {
+ V = 0;
+ }, 600)));
+ }
+ var t;
+ if ((Le("pointerUp"), wt(e, !1) && e.preventDefault(), A)) {
+ var n = o.arraySearch(it, e.pointerId, "id");
+ if (n > -1)
+ if (((t = it.splice(n, 1)[0]), navigator.msPointerEnabled)) {
+ (t.type = { 4: "mouse", 2: "touch", 3: "pen" }[e.pointerType]),
+ t.type || (t.type = e.pointerType || "mouse");
+ } else t.type = e.pointerType || "mouse";
+ }
+ var i,
+ l = Lt(e),
+ s = l.length;
+ if (("mouseup" === e.type && (s = 0), 2 === s)) return ($ = null), !0;
+ 1 === s && He(nt, l[0]),
+ 0 !== s ||
+ ie ||
+ ne ||
+ (t ||
+ ("mouseup" === e.type
+ ? (t = { x: e.pageX, y: e.pageY, type: "mouse" })
+ : e.changedTouches &&
+ e.changedTouches[0] &&
+ (t = {
+ x: e.changedTouches[0].pageX,
+ y: e.changedTouches[0].pageY,
+ type: "touch"
+ })),
+ Le("touchRelease", e, t));
+ var u = -1;
+ if (
+ (0 === s &&
+ ((W = !1),
+ o.unbind(window, m, r),
+ ht(),
+ Q ? (u = 0) : -1 !== ut && (u = Ee() - ut)),
+ (ut = 1 === s ? Ee() : -1),
+ (i = -1 !== u && u < 150 ? "zoom" : "swipe"),
+ Q &&
+ s < 2 &&
+ ((Q = !1),
+ 1 === s && (i = "zoomPointerUp"),
+ Le("zoomGestureEnded")),
+ ($ = null),
+ G || j || ne || K)
+ )
+ if ((Ye(), U || (U = Ot()), U.calculateSwipeSpeed("x"), K)) {
+ if (_t() < a.verticalDragRange) r.close();
+ else {
+ var c = pe.y,
+ p = ae;
+ Xe("verticalDrag", 0, 1, 300, o.easing.cubic.out, function(e) {
+ (pe.y = (r.currItem.initialPosition.y - c) * e + c),
+ Me((1 - p) * e + p),
+ Ae();
+ }),
+ Le("onVerticalDrag", 1);
+ }
+ } else {
+ if ((X || ne) && 0 === s) {
+ if (kt(i, U)) return;
+ i = "zoomPointerUp";
+ }
+ ne ||
+ ("swipe" === i ? !X && g > r.currItem.fitRatio && Dt(U) : Rt());
+ }
+ },
+ Ot = function() {
+ var e,
+ t,
+ n = {
+ lastFlickOffset: {},
+ lastFlickDist: {},
+ lastFlickSpeed: {},
+ slowDownRatio: {},
+ slowDownRatioReverse: {},
+ speedDecelerationRatio: {},
+ speedDecelerationRatioAbs: {},
+ distanceOffset: {},
+ backAnimDestination: {},
+ backAnimStarted: {},
+ calculateSwipeSpeed: function(i) {
+ rt.length > 1
+ ? ((e = Ee() - Z + 50), (t = rt[rt.length - 2][i]))
+ : ((e = Ee() - z), (t = nt[i])),
+ (n.lastFlickOffset[i] = tt[i] - t),
+ (n.lastFlickDist[i] = Math.abs(n.lastFlickOffset[i])),
+ n.lastFlickDist[i] > 20
+ ? (n.lastFlickSpeed[i] = n.lastFlickOffset[i] / e)
+ : (n.lastFlickSpeed[i] = 0),
+ Math.abs(n.lastFlickSpeed[i]) < 0.1 &&
+ (n.lastFlickSpeed[i] = 0),
+ (n.slowDownRatio[i] = 0.95),
+ (n.slowDownRatioReverse[i] = 1 - n.slowDownRatio[i]),
+ (n.speedDecelerationRatio[i] = 1);
+ },
+ calculateOverBoundsAnimOffset: function(e, t) {
+ n.backAnimStarted[e] ||
+ (pe[e] > ee.min[e]
+ ? (n.backAnimDestination[e] = ee.min[e])
+ : pe[e] < ee.max[e] &&
+ (n.backAnimDestination[e] = ee.max[e]),
+ void 0 !== n.backAnimDestination[e] &&
+ ((n.slowDownRatio[e] = 0.7),
+ (n.slowDownRatioReverse[e] = 1 - n.slowDownRatio[e]),
+ n.speedDecelerationRatioAbs[e] < 0.05 &&
+ ((n.lastFlickSpeed[e] = 0),
+ (n.backAnimStarted[e] = !0),
+ Xe(
+ "bounceZoomPan" + e,
+ pe[e],
+ n.backAnimDestination[e],
+ t || 300,
+ o.easing.sine.out,
+ function(t) {
+ (pe[e] = t), Ae();
+ }
+ ))));
+ },
+ calculateAnimOffset: function(e) {
+ n.backAnimStarted[e] ||
+ ((n.speedDecelerationRatio[e] =
+ n.speedDecelerationRatio[e] *
+ (n.slowDownRatio[e] +
+ n.slowDownRatioReverse[e] -
+ (n.slowDownRatioReverse[e] * n.timeDiff) / 10)),
+ (n.speedDecelerationRatioAbs[e] = Math.abs(
+ n.lastFlickSpeed[e] * n.speedDecelerationRatio[e]
+ )),
+ (n.distanceOffset[e] =
+ n.lastFlickSpeed[e] *
+ n.speedDecelerationRatio[e] *
+ n.timeDiff),
+ (pe[e] += n.distanceOffset[e]));
+ },
+ panAnimLoop: function() {
+ if (
+ We.zoomPan &&
+ ((We.zoomPan.raf = O(n.panAnimLoop)),
+ (n.now = Ee()),
+ (n.timeDiff = n.now - n.lastNow),
+ (n.lastNow = n.now),
+ n.calculateAnimOffset("x"),
+ n.calculateAnimOffset("y"),
+ Ae(),
+ n.calculateOverBoundsAnimOffset("x"),
+ n.calculateOverBoundsAnimOffset("y"),
+ n.speedDecelerationRatioAbs.x < 0.05 &&
+ n.speedDecelerationRatioAbs.y < 0.05)
+ )
+ return (
+ (pe.x = Math.round(pe.x)),
+ (pe.y = Math.round(pe.y)),
+ Ae(),
+ void je("zoomPan")
+ );
+ }
+ };
+ return n;
+ },
+ Dt = function(e) {
+ if (
+ (e.calculateSwipeSpeed("y"),
+ (ee = r.currItem.bounds),
+ (e.backAnimDestination = {}),
+ (e.backAnimStarted = {}),
+ Math.abs(e.lastFlickSpeed.x) <= 0.05 &&
+ Math.abs(e.lastFlickSpeed.y) <= 0.05)
+ )
+ return (
+ (e.speedDecelerationRatioAbs.x = e.speedDecelerationRatioAbs.y = 0),
+ e.calculateOverBoundsAnimOffset("x"),
+ e.calculateOverBoundsAnimOffset("y"),
+ !0
+ );
+ Ge("zoomPan"), (e.lastNow = Ee()), e.panAnimLoop();
+ },
+ kt = function(e, t) {
+ var n, i, l;
+ if ((ne || (lt = c), "swipe" === e)) {
+ var s = tt.x - nt.x,
+ u = t.lastFlickDist.x < 10;
+ s > 30 && (u || t.lastFlickOffset.x > 20)
+ ? (i = -1)
+ : s < -30 && (u || t.lastFlickOffset.x < -20) && (i = 1);
+ }
+ i &&
+ ((c += i) < 0
+ ? ((c = a.loop ? Ut() - 1 : 0), (l = !0))
+ : c >= Ut() && ((c = a.loop ? 0 : Ut() - 1), (l = !0)),
+ (l && !a.loop) || ((ge += i), (me -= i), (n = !0)));
+ var p,
+ d = fe.x * me,
+ m = Math.abs(d - ct.x);
+ return (
+ n || d > ct.x == t.lastFlickSpeed.x > 0
+ ? ((p =
+ Math.abs(t.lastFlickSpeed.x) > 0
+ ? m / Math.abs(t.lastFlickSpeed.x)
+ : 333),
+ (p = Math.min(p, 400)),
+ (p = Math.max(p, 250)))
+ : (p = 333),
+ lt === c && (n = !1),
+ (ne = !0),
+ Le("mainScrollAnimStart"),
+ Xe("mainScroll", ct.x, d, p, o.easing.cubic.out, De, function() {
+ Ye(),
+ (ne = !1),
+ (lt = -1),
+ (n || lt !== c) && r.updateCurrItem(),
+ Le("mainScrollAnimComplete");
+ }),
+ n && r.updateCurrItem(!0),
+ n
+ );
+ },
+ Ht = function(e) {
+ return (1 / J) * e * v;
+ },
+ Rt = function() {
+ var e = g,
+ t = ze(),
+ n = Ze();
+ g < t ? (e = t) : g > n && (e = n);
+ var i,
+ a = ae;
+ return re && !B && !le && g < t
+ ? (r.close(), !0)
+ : (re &&
+ (i = function(e) {
+ Me((1 - a) * e + a);
+ }),
+ r.zoomTo(e, 0, 200, o.easing.cubic.out, i),
+ !0);
+ };
+ _e("Gestures", {
+ publicMethods: {
+ initGestures: function() {
+ var e = function(e, t, n, i, o) {
+ (T = e + t), (L = e + n), (E = e + i), (M = o ? e + o : "");
+ };
+ (A = P.pointerEvent) && P.touch && (P.touch = !1),
+ A
+ ? navigator.msPointerEnabled
+ ? e("MSPointer", "Down", "Move", "Up", "Cancel")
+ : e("pointer", "down", "move", "up", "cancel")
+ : P.touch
+ ? (e("touch", "start", "move", "end", "cancel"), (S = !0))
+ : e("mouse", "down", "move", "up"),
+ (m = L + " " + E + " " + M),
+ (h = T),
+ A &&
+ !S &&
+ (S =
+ navigator.maxTouchPoints > 1 ||
+ navigator.msMaxTouchPoints > 1),
+ (r.likelyTouchDevice = S),
+ (f[T] = Mt),
+ (f[L] = It),
+ (f[E] = St),
+ M && (f[M] = f[E]),
+ P.touch &&
+ ((h += " mousedown"),
+ (m += " mousemove mouseup"),
+ (f.mousedown = f[T]),
+ (f.mousemove = f[L]),
+ (f.mouseup = f[E])),
+ S || (a.allowPanToNext = !1);
+ }
+ }
+ });
+ var Ft,
+ Pt,
+ Nt,
+ zt,
+ Zt,
+ Ut,
+ Bt = function(t, n, i, l) {
+ var s;
+ Ft && clearTimeout(Ft),
+ (zt = !0),
+ (Nt = !0),
+ t.initialLayout
+ ? ((s = t.initialLayout), (t.initialLayout = null))
+ : (s = a.getThumbBoundsFn && a.getThumbBoundsFn(c));
+ var p = i ? a.hideAnimationDuration : a.showAnimationDuration,
+ d = function() {
+ je("initialZoom"),
+ i
+ ? (r.template.removeAttribute("style"),
+ r.bg.removeAttribute("style"))
+ : (Me(1),
+ n && (n.style.display = "block"),
+ o.addClass(e, "pswp--animated-in"),
+ Le("initialZoom" + (i ? "OutEnd" : "InEnd"))),
+ l && l(),
+ (zt = !1);
+ };
+ if (!p || !s || void 0 === s.x)
+ return (
+ Le("initialZoom" + (i ? "Out" : "In")),
+ (g = t.initialZoomLevel),
+ He(pe, t.initialPosition),
+ Ae(),
+ (e.style.opacity = i ? 0 : 1),
+ Me(1),
+ void (p
+ ? setTimeout(function() {
+ d();
+ }, p)
+ : d())
+ );
+ var m, h;
+ (m = u),
+ (h = !r.currItem.src || r.currItem.loadError || a.showHideOpacity),
+ t.miniImg && (t.miniImg.style.webkitBackfaceVisibility = "hidden"),
+ i ||
+ ((g = s.w / t.w),
+ (pe.x = s.x),
+ (pe.y = s.y - H),
+ (r[h ? "template" : "bg"].style.opacity = 0.001),
+ Ae()),
+ Ge("initialZoom"),
+ i && !m && o.removeClass(e, "pswp--animated-in"),
+ h &&
+ (i
+ ? o[(m ? "remove" : "add") + "Class"](
+ e,
+ "pswp--animate_opacity"
+ )
+ : setTimeout(function() {
+ o.addClass(e, "pswp--animate_opacity");
+ }, 30)),
+ (Ft = setTimeout(
+ function() {
+ if ((Le("initialZoom" + (i ? "Out" : "In")), i)) {
+ var n = s.w / t.w,
+ r = { x: pe.x, y: pe.y },
+ a = g,
+ l = ae,
+ u = function(t) {
+ 1 === t
+ ? ((g = n), (pe.x = s.x), (pe.y = s.y - F))
+ : ((g = (n - a) * t + a),
+ (pe.x = (s.x - r.x) * t + r.x),
+ (pe.y = (s.y - F - r.y) * t + r.y)),
+ Ae(),
+ h ? (e.style.opacity = 1 - t) : Me(l - t * l);
+ };
+ m
+ ? Xe("initialZoom", 0, 1, p, o.easing.cubic.out, u, d)
+ : (u(1), (Ft = setTimeout(d, p + 20)));
+ } else
+ (g = t.initialZoomLevel),
+ He(pe, t.initialPosition),
+ Ae(),
+ Me(1),
+ h ? (e.style.opacity = 1) : Me(1),
+ (Ft = setTimeout(d, p + 20));
+ },
+ i ? 25 : 90
+ ));
+ },
+ Kt = {},
+ Vt = [],
+ Wt = {
+ index: 0,
+ errorMsg:
+ '
',
+ forceProgressiveLoading: !1,
+ preload: [1, 1],
+ getNumItemsFn: function() {
+ return Pt.length;
+ }
+ },
+ qt = function(e, t, n) {
+ if (e.src && !e.loadError) {
+ var i = !n;
+ if (
+ (i &&
+ (e.vGap || (e.vGap = { top: 0, bottom: 0 }),
+ Le("parseVerticalMargin", e)),
+ (Kt.x = t.x),
+ (Kt.y = t.y - e.vGap.top - e.vGap.bottom),
+ i)
+ ) {
+ var o = Kt.x / e.w,
+ r = Kt.y / e.h;
+ e.fitRatio = o < r ? o : r;
+ var l = a.scaleMode;
+ "orig" === l ? (n = 1) : "fit" === l && (n = e.fitRatio),
+ n > 1 && (n = 1),
+ (e.initialZoomLevel = n),
+ e.bounds ||
+ (e.bounds = {
+ center: { x: 0, y: 0 },
+ max: { x: 0, y: 0 },
+ min: { x: 0, y: 0 }
+ });
+ }
+ if (!n) return;
+ return (
+ (function(e, t, n) {
+ var i = e.bounds;
+ (i.center.x = Math.round((Kt.x - t) / 2)),
+ (i.center.y = Math.round((Kt.y - n) / 2) + e.vGap.top),
+ (i.max.x = t > Kt.x ? Math.round(Kt.x - t) : i.center.x),
+ (i.max.y =
+ n > Kt.y ? Math.round(Kt.y - n) + e.vGap.top : i.center.y),
+ (i.min.x = t > Kt.x ? 0 : i.center.x),
+ (i.min.y = n > Kt.y ? e.vGap.top : i.center.y);
+ })(e, e.w * n, e.h * n),
+ i &&
+ n === e.initialZoomLevel &&
+ (e.initialPosition = e.bounds.center),
+ e.bounds
+ );
+ }
+ return (
+ (e.w = e.h = 0),
+ (e.initialZoomLevel = e.fitRatio = 1),
+ (e.bounds = {
+ center: { x: 0, y: 0 },
+ max: { x: 0, y: 0 },
+ min: { x: 0, y: 0 }
+ }),
+ (e.initialPosition = e.bounds.center),
+ e.bounds
+ );
+ },
+ jt = function(e, t, n, i, o, a) {
+ t.loadError ||
+ (i &&
+ ((t.imageAppended = !0),
+ Xt(t, i, t === r.currItem && be),
+ n.appendChild(i),
+ a &&
+ setTimeout(function() {
+ t &&
+ t.loaded &&
+ t.placeholder &&
+ ((t.placeholder.style.display = "none"),
+ (t.placeholder = null));
+ }, 500)));
+ },
+ Gt = function(e) {
+ (e.loading = !0), (e.loaded = !1);
+ var t = (e.img = o.createEl("pswp__img", "img")),
+ n = function() {
+ (e.loading = !1),
+ (e.loaded = !0),
+ e.loadComplete ? e.loadComplete(e) : (e.img = null),
+ (t.onload = t.onerror = null),
+ (t = null);
+ };
+ return (
+ (t.onload = n),
+ (t.onerror = function() {
+ (e.loadError = !0), n();
+ }),
+ (t.src = e.src),
+ t
+ );
+ },
+ Yt = function(e, t) {
+ if (e.src && e.loadError && e.container)
+ return (
+ t && (e.container.innerHTML = ""),
+ (e.container.innerHTML = a.errorMsg.replace("%url%", e.src)),
+ !0
+ );
+ },
+ Xt = function(e, t, n) {
+ if (e.src) {
+ t || (t = e.container.lastChild);
+ var i = n ? e.w : Math.round(e.w * e.fitRatio),
+ o = n ? e.h : Math.round(e.h * e.fitRatio);
+ e.placeholder &&
+ !e.loaded &&
+ ((e.placeholder.style.width = i + "px"),
+ (e.placeholder.style.height = o + "px")),
+ (t.style.width = i + "px"),
+ (t.style.height = o + "px");
+ }
+ },
+ $t = function() {
+ if (Vt.length) {
+ for (var e, t = 0; t < Vt.length; t++)
+ (e = Vt[t]).holder.index === e.index &&
+ jt(e.index, e.item, e.baseDiv, e.img, 0, e.clearPlaceholder);
+ Vt = [];
+ }
+ };
+ _e("Controller", {
+ publicMethods: {
+ lazyLoadItem: function(e) {
+ e = xe(e);
+ var t = Zt(e);
+ t &&
+ ((!t.loaded && !t.loading) || _) &&
+ (Le("gettingData", e, t), t.src && Gt(t));
+ },
+ initController: function() {
+ o.extend(a, Wt, !0),
+ (r.items = Pt = n),
+ (Zt = r.getItemAt),
+ (Ut = a.getNumItemsFn),
+ a.loop,
+ Ut() < 3 && (a.loop = !1),
+ Te("beforeChange", function(e) {
+ var t,
+ n = a.preload,
+ i = null === e || e >= 0,
+ o = Math.min(n[0], Ut()),
+ l = Math.min(n[1], Ut());
+ for (t = 1; t <= (i ? l : o); t++) r.lazyLoadItem(c + t);
+ for (t = 1; t <= (i ? o : l); t++) r.lazyLoadItem(c - t);
+ }),
+ Te("initialLayout", function() {
+ r.currItem.initialLayout =
+ a.getThumbBoundsFn && a.getThumbBoundsFn(c);
+ }),
+ Te("mainScrollAnimComplete", $t),
+ Te("initialZoomInEnd", $t),
+ Te("destroy", function() {
+ for (var e, t = 0; t < Pt.length; t++)
+ (e = Pt[t]).container && (e.container = null),
+ e.placeholder && (e.placeholder = null),
+ e.img && (e.img = null),
+ e.preloader && (e.preloader = null),
+ e.loadError && (e.loaded = e.loadError = !1);
+ Vt = null;
+ });
+ },
+ getItemAt: function(e) {
+ return e >= 0 && void 0 !== Pt[e] && Pt[e];
+ },
+ allowProgressiveImg: function() {
+ return (
+ a.forceProgressiveLoading ||
+ !S ||
+ a.mouseUsed ||
+ screen.width > 1200
+ );
+ },
+ setContent: function(e, t) {
+ a.loop && (t = xe(t));
+ var n = r.getItemAt(e.index);
+ n && (n.container = null);
+ var i,
+ s = r.getItemAt(t);
+ if (s) {
+ Le("gettingData", t, s), (e.index = t), (e.item = s);
+ var u = (s.container = o.createEl("pswp__zoom-wrap"));
+ if (
+ (!s.src &&
+ s.html &&
+ (s.html.tagName
+ ? u.appendChild(s.html)
+ : (u.innerHTML = s.html)),
+ Yt(s),
+ qt(s, de),
+ !s.src || s.loadError || s.loaded)
+ )
+ s.src &&
+ !s.loadError &&
+ (((i = o.createEl("pswp__img", "img")).style.opacity = 1),
+ (i.src = s.src),
+ Xt(s, i),
+ jt(0, s, u, i));
+ else {
+ if (
+ ((s.loadComplete = function(n) {
+ if (l) {
+ if (e && e.index === t) {
+ if (Yt(n, !0))
+ return (
+ (n.loadComplete = n.img = null),
+ qt(n, de),
+ Se(n),
+ void (e.index === c && r.updateCurrZoomItem())
+ );
+ n.imageAppended
+ ? !zt &&
+ n.placeholder &&
+ ((n.placeholder.style.display = "none"),
+ (n.placeholder = null))
+ : P.transform && (ne || zt)
+ ? Vt.push({
+ item: n,
+ baseDiv: u,
+ img: n.img,
+ index: t,
+ holder: e,
+ clearPlaceholder: !0
+ })
+ : jt(0, n, u, n.img, 0, !0);
+ }
+ (n.loadComplete = null),
+ (n.img = null),
+ Le("imageLoadComplete", t, n);
+ }
+ }),
+ o.features.transform)
+ ) {
+ var p = "pswp__img pswp__img--placeholder";
+ p += s.msrc ? "" : " pswp__img--placeholder--blank";
+ var d = o.createEl(p, s.msrc ? "img" : "");
+ s.msrc && (d.src = s.msrc),
+ Xt(s, d),
+ u.appendChild(d),
+ (s.placeholder = d);
+ }
+ s.loading || Gt(s),
+ r.allowProgressiveImg() &&
+ (!Nt && P.transform
+ ? Vt.push({
+ item: s,
+ baseDiv: u,
+ img: s.img,
+ index: t,
+ holder: e
+ })
+ : jt(0, s, u, s.img, 0, !0));
+ }
+ Nt || t !== c ? Se(s) : ((te = u.style), Bt(s, i || s.img)),
+ (e.el.innerHTML = ""),
+ e.el.appendChild(u);
+ } else e.el.innerHTML = "";
+ },
+ cleanSlide: function(e) {
+ e.img && (e.img.onload = e.img.onerror = null),
+ (e.loaded = e.loading = e.img = e.imageAppended = !1);
+ }
+ }
+ });
+ var Qt,
+ Jt,
+ en = {},
+ tn = function(e, t, n) {
+ var i = document.createEvent("CustomEvent"),
+ o = {
+ origEvent: e,
+ target: e.target,
+ releasePoint: t,
+ pointerType: n || "touch"
+ };
+ i.initCustomEvent("pswpTap", !0, !0, o), e.target.dispatchEvent(i);
+ };
+ _e("Tap", {
+ publicMethods: {
+ initTap: function() {
+ Te("firstTouchStart", r.onTapStart),
+ Te("touchRelease", r.onTapRelease),
+ Te("destroy", function() {
+ (en = {}), (Qt = null);
+ });
+ },
+ onTapStart: function(e) {
+ e.length > 1 && (clearTimeout(Qt), (Qt = null));
+ },
+ onTapRelease: function(e, t) {
+ var n, i;
+ if (t && !G && !q && !qe) {
+ var r = t;
+ if (
+ Qt &&
+ (clearTimeout(Qt),
+ (Qt = null),
+ (n = r),
+ (i = en),
+ Math.abs(n.x - i.x) < 25 && Math.abs(n.y - i.y) < 25)
+ )
+ return void Le("doubleTap", r);
+ if ("mouse" === t.type) return void tn(e, t, "mouse");
+ if (
+ "BUTTON" === e.target.tagName.toUpperCase() ||
+ o.hasClass(e.target, "pswp__single-tap")
+ )
+ return void tn(e, t);
+ He(en, r),
+ (Qt = setTimeout(function() {
+ tn(e, t), (Qt = null);
+ }, 300));
+ }
+ }
+ }
+ }),
+ _e("DesktopZoom", {
+ publicMethods: {
+ initDesktopZoom: function() {
+ R ||
+ (S
+ ? Te("mouseUsed", function() {
+ r.setupDesktopZoom();
+ })
+ : r.setupDesktopZoom(!0));
+ },
+ setupDesktopZoom: function(t) {
+ Jt = {};
+ var n = "wheel mousewheel DOMMouseScroll";
+ Te("bindEvents", function() {
+ o.bind(e, n, r.handleMouseWheel);
+ }),
+ Te("unbindEvents", function() {
+ Jt && o.unbind(e, n, r.handleMouseWheel);
+ }),
+ (r.mouseZoomedIn = !1);
+ var i,
+ a = function() {
+ r.mouseZoomedIn &&
+ (o.removeClass(e, "pswp--zoomed-in"),
+ (r.mouseZoomedIn = !1)),
+ g < 1
+ ? o.addClass(e, "pswp--zoom-allowed")
+ : o.removeClass(e, "pswp--zoom-allowed"),
+ l();
+ },
+ l = function() {
+ i && (o.removeClass(e, "pswp--dragging"), (i = !1));
+ };
+ Te("resize", a),
+ Te("afterChange", a),
+ Te("pointerDown", function() {
+ r.mouseZoomedIn &&
+ ((i = !0), o.addClass(e, "pswp--dragging"));
+ }),
+ Te("pointerUp", l),
+ t || a();
+ },
+ handleMouseWheel: function(e) {
+ if (g <= r.currItem.fitRatio)
+ return (
+ a.modal &&
+ (!a.closeOnScroll || qe || W
+ ? e.preventDefault()
+ : I && Math.abs(e.deltaY) > 2 && ((u = !0), r.close())),
+ !0
+ );
+ if ((e.stopPropagation(), (Jt.x = 0), "deltaX" in e))
+ 1 === e.deltaMode
+ ? ((Jt.x = 18 * e.deltaX), (Jt.y = 18 * e.deltaY))
+ : ((Jt.x = e.deltaX), (Jt.y = e.deltaY));
+ else if ("wheelDelta" in e)
+ e.wheelDeltaX && (Jt.x = -0.16 * e.wheelDeltaX),
+ e.wheelDeltaY
+ ? (Jt.y = -0.16 * e.wheelDeltaY)
+ : (Jt.y = -0.16 * e.wheelDelta);
+ else {
+ if (!("detail" in e)) return;
+ Jt.y = e.detail;
+ }
+ Ne(g, !0);
+ var t = pe.x - Jt.x,
+ n = pe.y - Jt.y;
+ (a.modal ||
+ (t <= ee.min.x &&
+ t >= ee.max.x &&
+ n <= ee.min.y &&
+ n >= ee.max.y)) &&
+ e.preventDefault(),
+ r.panTo(t, n);
+ },
+ toggleDesktopZoom: function(t) {
+ t = t || { x: de.x / 2 + he.x, y: de.y / 2 + he.y };
+ var n = a.getDoubleTapZoom(!0, r.currItem),
+ i = g === n;
+ (r.mouseZoomedIn = !i),
+ r.zoomTo(i ? r.currItem.initialZoomLevel : n, t, 333),
+ o[(i ? "remove" : "add") + "Class"](e, "pswp--zoomed-in");
+ }
+ }
+ });
+ var nn,
+ on,
+ rn,
+ an,
+ ln,
+ sn,
+ un,
+ cn,
+ pn,
+ dn,
+ mn,
+ hn,
+ fn = { history: !0, galleryUID: 1 },
+ gn = function() {
+ return mn.hash.substring(1);
+ },
+ vn = function() {
+ nn && clearTimeout(nn), rn && clearTimeout(rn);
+ },
+ wn = function() {
+ var e = gn(),
+ t = {};
+ if (e.length < 5) return t;
+ var n,
+ i = e.split("&");
+ for (n = 0; n < i.length; n++)
+ if (i[n]) {
+ var o = i[n].split("=");
+ o.length < 2 || (t[o[0]] = o[1]);
+ }
+ if (a.galleryPIDs) {
+ var r = t.pid;
+ for (t.pid = 0, n = 0; n < Pt.length; n++)
+ if (Pt[n].pid === r) {
+ t.pid = n;
+ break;
+ }
+ } else t.pid = parseInt(t.pid, 10) - 1;
+ return t.pid < 0 && (t.pid = 0), t;
+ },
+ yn = function() {
+ if ((rn && clearTimeout(rn), qe || W)) rn = setTimeout(yn, 500);
+ else {
+ an ? clearTimeout(on) : (an = !0);
+ var e = c + 1,
+ t = Zt(c);
+ t.hasOwnProperty("pid") && (e = t.pid);
+ var n = un + "&gid=" + a.galleryUID + "&pid=" + e;
+ cn || (-1 === mn.hash.indexOf(n) && (dn = !0));
+ var i = mn.href.split("#")[0] + "#" + n;
+ hn
+ ? "#" + n !== window.location.hash &&
+ history[cn ? "replaceState" : "pushState"](
+ "",
+ document.title,
+ i
+ )
+ : cn
+ ? mn.replace(i)
+ : (mn.hash = n),
+ (cn = !0),
+ (on = setTimeout(function() {
+ an = !1;
+ }, 60));
+ }
+ };
+ _e("History", {
+ publicMethods: {
+ initHistory: function() {
+ if ((o.extend(a, fn, !0), a.history)) {
+ (mn = window.location),
+ (dn = !1),
+ (pn = !1),
+ (cn = !1),
+ (un = gn()),
+ (hn = "pushState" in history),
+ un.indexOf("gid=") > -1 &&
+ (un = (un = un.split("&gid=")[0]).split("?gid=")[0]),
+ Te("afterChange", r.updateURL),
+ Te("unbindEvents", function() {
+ o.unbind(window, "hashchange", r.onHashChange);
+ });
+ var e = function() {
+ (sn = !0),
+ pn ||
+ (dn
+ ? history.back()
+ : un
+ ? (mn.hash = un)
+ : hn
+ ? history.pushState(
+ "",
+ document.title,
+ mn.pathname + mn.search
+ )
+ : (mn.hash = "")),
+ vn();
+ };
+ Te("unbindEvents", function() {
+ u && e();
+ }),
+ Te("destroy", function() {
+ sn || e();
+ }),
+ Te("firstUpdate", function() {
+ c = wn().pid;
+ });
+ var t = un.indexOf("pid=");
+ t > -1 &&
+ "&" === (un = un.substring(0, t)).slice(-1) &&
+ (un = un.slice(0, -1)),
+ setTimeout(function() {
+ l && o.bind(window, "hashchange", r.onHashChange);
+ }, 40);
+ }
+ },
+ onHashChange: function() {
+ if (gn() === un) return (pn = !0), void r.close();
+ an || ((ln = !0), r.goTo(wn().pid), (ln = !1));
+ },
+ updateURL: function() {
+ vn(), ln || (cn ? (nn = setTimeout(yn, 800)) : yn());
+ }
+ }
+ }),
+ o.extend(r, $e);
+ };
+ }),
+ /*! PhotoSwipe Default UI - 4.1.3 - 2019-01-08
+ * http://photoswipe.com
+ * Copyright (c) 2019 Dmitry Semenov; */
+ (function(e, t) {
+ "function" == typeof define && define.amd
+ ? define(t)
+ : "object" == typeof exports
+ ? (module.exports = t())
+ : (e.PhotoSwipeUI_Default = t());
+ })(this, function() {
+ "use strict";
+ return function(e, t) {
+ var n,
+ i,
+ o,
+ r,
+ a,
+ l,
+ s,
+ u,
+ c,
+ p,
+ d,
+ m,
+ h,
+ f,
+ g,
+ v,
+ w,
+ y,
+ b = this,
+ _ = !1,
+ x = !0,
+ C = !0,
+ T = {
+ barsSize: { top: 44, bottom: "auto" },
+ closeElClasses: ["item", "caption", "zoom-wrap", "ui", "top-bar"],
+ timeToIdle: 4e3,
+ timeToIdleOutside: 1e3,
+ loadingIndicatorDelay: 1e3,
+ addCaptionHTMLFn: function(e, t) {
+ return e.title
+ ? ((t.children[0].innerHTML = e.title), !0)
+ : ((t.children[0].innerHTML = ""), !1);
+ },
+ closeEl: !0,
+ captionEl: !0,
+ fullscreenEl: !0,
+ zoomEl: !0,
+ shareEl: !0,
+ counterEl: !0,
+ arrowEl: !0,
+ preloaderEl: !0,
+ tapToClose: !1,
+ tapToToggleControls: !0,
+ clickToCloseNonZoomable: !0,
+ shareButtons: [
+ {
+ id: "facebook",
+ label: "Share on Facebook",
+ url: "https://www.facebook.com/sharer/sharer.php?u={{url}}"
+ },
+ {
+ id: "twitter",
+ label: "Tweet",
+ url: "https://twitter.com/intent/tweet?text={{text}}&url={{url}}"
+ },
+ {
+ id: "pinterest",
+ label: "Pin it",
+ url:
+ "http://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}"
+ },
+ {
+ id: "download",
+ label: "Download image",
+ url: "{{raw_image_url}}",
+ download: !0
+ }
+ ],
+ getImageURLForShare: function() {
+ return e.currItem.src || "";
+ },
+ getPageURLForShare: function() {
+ return window.location.href;
+ },
+ getTextForShare: function() {
+ return e.currItem.title || "";
+ },
+ indexIndicatorSep: " / ",
+ fitControlsWidth: 1200
+ },
+ L = function(e) {
+ if (v) return !0;
+ (e = e || window.event), g.timeToIdle && g.mouseUsed && !c && H();
+ for (
+ var n,
+ i,
+ o = (e.target || e.srcElement).getAttribute("class") || "",
+ r = 0;
+ r < N.length;
+ r++
+ )
+ (n = N[r]).onTap &&
+ o.indexOf("pswp__" + n.name) > -1 &&
+ (n.onTap(), (i = !0));
+ if (i) {
+ e.stopPropagation && e.stopPropagation(), (v = !0);
+ var a = t.features.isOldAndroid ? 600 : 30;
+ setTimeout(function() {
+ v = !1;
+ }, a);
+ }
+ },
+ E = function(e, n, i) {
+ t[(i ? "add" : "remove") + "Class"](e, "pswp__" + n);
+ },
+ M = function() {
+ var e = 1 === g.getNumItemsFn();
+ e !== f && (E(i, "ui--one-slide", e), (f = e));
+ },
+ I = function() {
+ E(s, "share-modal--hidden", C);
+ },
+ A = function() {
+ return (
+ (C = !C)
+ ? (t.removeClass(s, "pswp__share-modal--fade-in"),
+ setTimeout(function() {
+ C && I();
+ }, 300))
+ : (I(),
+ setTimeout(function() {
+ C || t.addClass(s, "pswp__share-modal--fade-in");
+ }, 30)),
+ C || O(),
+ !1
+ );
+ },
+ S = function(t) {
+ var n = (t = t || window.event).target || t.srcElement;
+ return (
+ e.shout("shareLinkClick", t, n),
+ !!n.href &&
+ (!!n.hasAttribute("download") ||
+ (window.open(
+ n.href,
+ "pswp_share",
+ "scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left=" +
+ (window.screen ? Math.round(screen.width / 2 - 275) : 100)
+ ),
+ C || A(),
+ !1))
+ );
+ },
+ O = function() {
+ for (var e, t, n, i, o = "", r = 0; r < g.shareButtons.length; r++)
+ (e = g.shareButtons[r]),
+ (t = g.getImageURLForShare(e)),
+ (n = g.getPageURLForShare(e)),
+ (i = g.getTextForShare(e)),
+ (o +=
+ '
" +
+ e.label +
+ " "),
+ g.parseShareButtonOut && (o = g.parseShareButtonOut(e, o));
+ (s.children[0].innerHTML = o), (s.children[0].onclick = S);
+ },
+ D = function(e) {
+ for (var n = 0; n < g.closeElClasses.length; n++)
+ if (t.hasClass(e, "pswp__" + g.closeElClasses[n])) return !0;
+ },
+ k = 0,
+ H = function() {
+ clearTimeout(y), (k = 0), c && b.setIdle(!1);
+ },
+ R = function(e) {
+ var t = (e = e || window.event).relatedTarget || e.toElement;
+ (t && "HTML" !== t.nodeName) ||
+ (clearTimeout(y),
+ (y = setTimeout(function() {
+ b.setIdle(!0);
+ }, g.timeToIdleOutside)));
+ },
+ F = function(e) {
+ m !== e && (E(d, "preloader--active", !e), (m = e));
+ },
+ P = function(n) {
+ var a = n.vGap;
+ if (
+ !e.likelyTouchDevice ||
+ g.mouseUsed ||
+ screen.width > g.fitControlsWidth
+ ) {
+ var l = g.barsSize;
+ if (g.captionEl && "auto" === l.bottom)
+ if (
+ (r ||
+ ((r = t.createEl(
+ "pswp__caption pswp__caption--fake"
+ )).appendChild(t.createEl("pswp__caption__center")),
+ i.insertBefore(r, o),
+ t.addClass(i, "pswp__ui--fit")),
+ g.addCaptionHTMLFn(n, r, !0))
+ ) {
+ var s = r.clientHeight;
+ a.bottom = parseInt(s, 10) || 44;
+ } else a.bottom = l.top;
+ else a.bottom = "auto" === l.bottom ? 0 : l.bottom;
+ a.top = l.top;
+ } else a.top = a.bottom = 0;
+ },
+ N = [
+ {
+ name: "caption",
+ option: "captionEl",
+ onInit: function(e) {
+ o = e;
+ }
+ },
+ {
+ name: "share-modal",
+ option: "shareEl",
+ onInit: function(e) {
+ s = e;
+ },
+ onTap: function() {
+ A();
+ }
+ },
+ {
+ name: "button--share",
+ option: "shareEl",
+ onInit: function(e) {
+ l = e;
+ },
+ onTap: function() {
+ A();
+ }
+ },
+ {
+ name: "button--zoom",
+ option: "zoomEl",
+ onTap: e.toggleDesktopZoom
+ },
+ {
+ name: "counter",
+ option: "counterEl",
+ onInit: function(e) {
+ a = e;
+ }
+ },
+ { name: "button--close", option: "closeEl", onTap: e.close },
+ { name: "button--arrow--left", option: "arrowEl", onTap: e.prev },
+ { name: "button--arrow--right", option: "arrowEl", onTap: e.next },
+ {
+ name: "button--fs",
+ option: "fullscreenEl",
+ onTap: function() {
+ n.isFullscreen() ? n.exit() : n.enter();
+ }
+ },
+ {
+ name: "preloader",
+ option: "preloaderEl",
+ onInit: function(e) {
+ d = e;
+ }
+ }
+ ];
+ (b.init = function() {
+ var a;
+ t.extend(e.options, T, !0),
+ (g = e.options),
+ (i = t.getChildByClass(e.scrollWrap, "pswp__ui")),
+ (p = e.listen)("onVerticalDrag", function(e) {
+ x && e < 0.95
+ ? b.hideControls()
+ : !x && e >= 0.95 && b.showControls();
+ }),
+ p("onPinchClose", function(e) {
+ x && e < 0.9
+ ? (b.hideControls(), (a = !0))
+ : a && !x && e > 0.9 && b.showControls();
+ }),
+ p("zoomGestureEnded", function() {
+ (a = !1) && !x && b.showControls();
+ }),
+ p("beforeChange", b.update),
+ p("doubleTap", function(t) {
+ var n = e.currItem.initialZoomLevel;
+ e.getZoomLevel() !== n
+ ? e.zoomTo(n, t, 333)
+ : e.zoomTo(g.getDoubleTapZoom(!1, e.currItem), t, 333);
+ }),
+ p("preventDragEvent", function(e, t, n) {
+ var i = e.target || e.srcElement;
+ i &&
+ i.getAttribute("class") &&
+ e.type.indexOf("mouse") > -1 &&
+ (i.getAttribute("class").indexOf("__caption") > 0 ||
+ /(SMALL|STRONG|EM)/i.test(i.tagName)) &&
+ (n.prevent = !1);
+ }),
+ p("bindEvents", function() {
+ t.bind(i, "pswpTap click", L),
+ t.bind(e.scrollWrap, "pswpTap", b.onGlobalTap),
+ e.likelyTouchDevice ||
+ t.bind(e.scrollWrap, "mouseover", b.onMouseOver);
+ }),
+ p("unbindEvents", function() {
+ C || A(),
+ w && clearInterval(w),
+ t.unbind(document, "mouseout", R),
+ t.unbind(document, "mousemove", H),
+ t.unbind(i, "pswpTap click", L),
+ t.unbind(e.scrollWrap, "pswpTap", b.onGlobalTap),
+ t.unbind(e.scrollWrap, "mouseover", b.onMouseOver),
+ n &&
+ (t.unbind(document, n.eventK, b.updateFullscreen),
+ n.isFullscreen() && ((g.hideAnimationDuration = 0), n.exit()),
+ (n = null));
+ }),
+ p("destroy", function() {
+ g.captionEl &&
+ (r && i.removeChild(r), t.removeClass(o, "pswp__caption--empty")),
+ s && (s.children[0].onclick = null),
+ t.removeClass(i, "pswp__ui--over-close"),
+ t.addClass(i, "pswp__ui--hidden"),
+ b.setIdle(!1);
+ }),
+ g.showAnimationDuration || t.removeClass(i, "pswp__ui--hidden"),
+ p("initialZoomIn", function() {
+ g.showAnimationDuration && t.removeClass(i, "pswp__ui--hidden");
+ }),
+ p("initialZoomOut", function() {
+ t.addClass(i, "pswp__ui--hidden");
+ }),
+ p("parseVerticalMargin", P),
+ (function() {
+ var e,
+ n,
+ o,
+ r = function(i) {
+ if (i)
+ for (var r = i.length, a = 0; a < r; a++) {
+ (e = i[a]), (n = e.className);
+ for (var l = 0; l < N.length; l++)
+ (o = N[l]),
+ n.indexOf("pswp__" + o.name) > -1 &&
+ (g[o.option]
+ ? (t.removeClass(e, "pswp__element--disabled"),
+ o.onInit && o.onInit(e))
+ : t.addClass(e, "pswp__element--disabled"));
+ }
+ };
+ r(i.children);
+ var a = t.getChildByClass(i, "pswp__top-bar");
+ a && r(a.children);
+ })(),
+ g.shareEl && l && s && (C = !0),
+ M(),
+ g.timeToIdle &&
+ p("mouseUsed", function() {
+ t.bind(document, "mousemove", H),
+ t.bind(document, "mouseout", R),
+ (w = setInterval(function() {
+ 2 == ++k && b.setIdle(!0);
+ }, g.timeToIdle / 2));
+ }),
+ g.fullscreenEl &&
+ !t.features.isOldAndroid &&
+ (n || (n = b.getFullscreenAPI()),
+ n
+ ? (t.bind(document, n.eventK, b.updateFullscreen),
+ b.updateFullscreen(),
+ t.addClass(e.template, "pswp--supports-fs"))
+ : t.removeClass(e.template, "pswp--supports-fs")),
+ g.preloaderEl &&
+ (F(!0),
+ p("beforeChange", function() {
+ clearTimeout(h),
+ (h = setTimeout(function() {
+ e.currItem && e.currItem.loading
+ ? (!e.allowProgressiveImg() ||
+ (e.currItem.img && !e.currItem.img.naturalWidth)) &&
+ F(!1)
+ : F(!0);
+ }, g.loadingIndicatorDelay));
+ }),
+ p("imageLoadComplete", function(t, n) {
+ e.currItem === n && F(!0);
+ }));
+ }),
+ (b.setIdle = function(e) {
+ (c = e), E(i, "ui--idle", e);
+ }),
+ (b.update = function() {
+ x && e.currItem
+ ? (b.updateIndexIndicator(),
+ g.captionEl &&
+ (g.addCaptionHTMLFn(e.currItem, o),
+ E(o, "caption--empty", !e.currItem.title)),
+ (_ = !0))
+ : (_ = !1),
+ C || A(),
+ M();
+ }),
+ (b.updateFullscreen = function(i) {
+ i &&
+ setTimeout(function() {
+ e.setScrollOffset(0, t.getScrollY());
+ }, 50),
+ t[(n.isFullscreen() ? "add" : "remove") + "Class"](
+ e.template,
+ "pswp--fs"
+ );
+ }),
+ (b.updateIndexIndicator = function() {
+ g.counterEl &&
+ (a.innerHTML =
+ e.getCurrentIndex() +
+ 1 +
+ g.indexIndicatorSep +
+ g.getNumItemsFn());
+ }),
+ (b.onGlobalTap = function(n) {
+ var i = (n = n || window.event).target || n.srcElement;
+ if (!v)
+ if (n.detail && "mouse" === n.detail.pointerType) {
+ if (D(i)) return void e.close();
+ t.hasClass(i, "pswp__img") &&
+ (1 === e.getZoomLevel() &&
+ e.getZoomLevel() <= e.currItem.fitRatio
+ ? g.clickToCloseNonZoomable && e.close()
+ : e.toggleDesktopZoom(n.detail.releasePoint));
+ } else if (
+ (g.tapToToggleControls &&
+ (x ? b.hideControls() : b.showControls()),
+ g.tapToClose && (t.hasClass(i, "pswp__img") || D(i)))
+ )
+ return void e.close();
+ }),
+ (b.onMouseOver = function(e) {
+ var t = (e = e || window.event).target || e.srcElement;
+ E(i, "ui--over-close", D(t));
+ }),
+ (b.hideControls = function() {
+ t.addClass(i, "pswp__ui--hidden"), (x = !1);
+ }),
+ (b.showControls = function() {
+ (x = !0), _ || b.update(), t.removeClass(i, "pswp__ui--hidden");
+ }),
+ (b.supportsFullscreen = function() {
+ var e = document;
+ return !!(
+ e.exitFullscreen ||
+ e.mozCancelFullScreen ||
+ e.webkitExitFullscreen ||
+ e.msExitFullscreen
+ );
+ }),
+ (b.getFullscreenAPI = function() {
+ var t,
+ n = document.documentElement,
+ i = "fullscreenchange";
+ return (
+ n.requestFullscreen
+ ? (t = {
+ enterK: "requestFullscreen",
+ exitK: "exitFullscreen",
+ elementK: "fullscreenElement",
+ eventK: i
+ })
+ : n.mozRequestFullScreen
+ ? (t = {
+ enterK: "mozRequestFullScreen",
+ exitK: "mozCancelFullScreen",
+ elementK: "mozFullScreenElement",
+ eventK: "moz" + i
+ })
+ : n.webkitRequestFullscreen
+ ? (t = {
+ enterK: "webkitRequestFullscreen",
+ exitK: "webkitExitFullscreen",
+ elementK: "webkitFullscreenElement",
+ eventK: "webkit" + i
+ })
+ : n.msRequestFullscreen &&
+ (t = {
+ enterK: "msRequestFullscreen",
+ exitK: "msExitFullscreen",
+ elementK: "msFullscreenElement",
+ eventK: "MSFullscreenChange"
+ }),
+ t &&
+ ((t.enter = function() {
+ if (
+ ((u = g.closeOnScroll),
+ (g.closeOnScroll = !1),
+ "webkitRequestFullscreen" !== this.enterK)
+ )
+ return e.template[this.enterK]();
+ e.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT);
+ }),
+ (t.exit = function() {
+ return (g.closeOnScroll = u), document[this.exitK]();
+ }),
+ (t.isFullscreen = function() {
+ return document[this.elementK];
+ })),
+ t
+ );
+ });
+ };
+ });
+var initPhotoSwipeFromDOM = function(e) {
+ for (
+ var t = function(e) {
+ (e = e || window.event).preventDefault
+ ? e.preventDefault()
+ : (e.returnValue = !1);
+ var t = (function e(t, n) {
+ return t && (n(t) ? t : e(t.parentNode, n));
+ })(e.target || e.srcElement, function(e) {
+ return e.tagName && "FIGURE" === e.tagName.toUpperCase();
+ });
+ if (t) {
+ for (
+ var i,
+ o = t.parentNode,
+ r = t.parentNode.childNodes,
+ a = r.length,
+ l = 0,
+ s = 0;
+ s < a;
+ s++
+ )
+ if (1 === r[s].nodeType) {
+ if (r[s] === t) {
+ i = l;
+ break;
+ }
+ l++;
+ }
+ return i >= 0 && n(i, o), !1;
+ }
+ },
+ n = function(e, t, n, i) {
+ var o,
+ r,
+ a = document.querySelectorAll(".pswp")[0];
+ if (
+ ((r = (function(e) {
+ for (
+ var t, n, i, o, r = e.childNodes, a = r.length, l = [], s = 0;
+ s < a;
+ s++
+ )
+ 1 === (t = r[s]).nodeType &&
+ ((i = (n = t.children[0]).getAttribute("data-size").split("x")),
+ (o = {
+ src: n.getAttribute("href"),
+ w: parseInt(i[0], 10),
+ h: parseInt(i[1], 10)
+ }),
+ t.children.length > 1 && (o.title = t.children[1].innerHTML),
+ n.children.length > 0 &&
+ (o.msrc = n.children[0].getAttribute("src")),
+ (o.el = t),
+ l.push(o));
+ return l;
+ })(t)),
+ (o = {
+ galleryUID: t.getAttribute("data-pswp-uid"),
+ getThumbBoundsFn: function(e) {
+ var t = r[e].el.getElementsByTagName("img")[0],
+ n = window.pageYOffset || document.documentElement.scrollTop,
+ i = t.getBoundingClientRect();
+ return { x: i.left, y: i.top + n, w: i.width };
+ }
+ }),
+ i)
+ )
+ if (o.galleryPIDs) {
+ for (var l = 0; l < r.length; l++)
+ if (r[l].pid == e) {
+ o.index = l;
+ break;
+ }
+ } else o.index = parseInt(e, 10) - 1;
+ else o.index = parseInt(e, 10);
+ isNaN(o.index) ||
+ (n && (o.showAnimationDuration = 0),
+ new PhotoSwipe(a, PhotoSwipeUI_Default, r, o).init());
+ },
+ i = document.querySelectorAll(e),
+ o = 0,
+ r = i.length;
+ o < r;
+ o++
+ )
+ i[o].setAttribute("data-pswp-uid", o + 1), (i[o].onclick = t);
+ var a = (function() {
+ var e = window.location.hash.substring(1),
+ t = {};
+ if (e.length < 5) return t;
+ for (var n = e.split("&"), i = 0; i < n.length; i++)
+ if (n[i]) {
+ var o = n[i].split("=");
+ o.length < 2 || (t[o[0]] = o[1]);
+ }
+ return t.gid && (t.gid = parseInt(t.gid, 10)), t;
+ })();
+ a.pid && a.gid && n(a.pid, i[a.gid - 1], !0, !0);
+};
+initPhotoSwipeFromDOM(".photoswipe-gallery");
diff --git a/static/photoswipe/default-skin/default-skin.css b/static/photoswipe/default-skin/default-skin.css
new file mode 100644
index 00000000..a9ea56bf
--- /dev/null
+++ b/static/photoswipe/default-skin/default-skin.css
@@ -0,0 +1,571 @@
+/*! PhotoSwipe Default UI CSS by Dmitry Semenov | photoswipe.com | MIT license */
+/*
+
+ Contents:
+
+ 1. Buttons
+ 2. Share modal and links
+ 3. Index indicator ("1 of X" counter)
+ 4. Caption
+ 5. Loading indicator
+ 6. Additional styles (root element, top bar, idle state, hidden state, etc.)
+
+*/
+/*
+
+ 1. Buttons
+
+ */
+/*
css reset */
+.pswp__button {
+ width: 44px;
+ height: 44px;
+ position: relative;
+ background: none;
+ cursor: pointer;
+ overflow: visible;
+ -webkit-appearance: none;
+ display: block;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ float: right;
+ opacity: 0.75;
+ -webkit-transition: opacity 0.2s;
+ transition: opacity 0.2s;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.pswp__button:focus,
+.pswp__button:hover {
+ opacity: 1;
+}
+.pswp__button:active {
+ outline: none;
+ opacity: 0.9;
+}
+.pswp__button::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+/* pswp__ui--over-close class it added when mouse is over element that should close gallery */
+.pswp__ui--over-close .pswp__button--close {
+ opacity: 1;
+}
+
+.pswp__button,
+.pswp__button--arrow--left:before,
+.pswp__button--arrow--right:before {
+ background: url(default-skin.png) 0 0 no-repeat;
+ background-size: 264px 88px;
+ width: 44px;
+ height: 44px;
+}
+
+@media (-webkit-min-device-pixel-ratio: 1.1),
+ (-webkit-min-device-pixel-ratio: 1.09375),
+ (min-resolution: 105dpi),
+ (min-resolution: 1.1dppx) {
+ /* Serve SVG sprite if browser supports SVG and resolution is more than 105dpi */
+ .pswp--svg .pswp__button,
+ .pswp--svg .pswp__button--arrow--left:before,
+ .pswp--svg .pswp__button--arrow--right:before {
+ background-image: url(default-skin.svg);
+ }
+ .pswp--svg .pswp__button--arrow--left,
+ .pswp--svg .pswp__button--arrow--right {
+ background: none;
+ }
+}
+
+.pswp__button--close {
+ background-position: 0 -44px;
+}
+
+.pswp__button--share {
+ background-position: -44px -44px;
+}
+
+.pswp__button--fs {
+ display: none;
+}
+
+.pswp--supports-fs .pswp__button--fs {
+ display: block;
+}
+
+.pswp--fs .pswp__button--fs {
+ background-position: -44px 0;
+}
+
+.pswp__button--zoom {
+ display: none;
+ background-position: -88px 0;
+}
+
+.pswp--zoom-allowed .pswp__button--zoom {
+ display: block;
+}
+
+.pswp--zoomed-in .pswp__button--zoom {
+ background-position: -132px 0;
+}
+
+/* no arrows on touch screens */
+.pswp--touch .pswp__button--arrow--left,
+.pswp--touch .pswp__button--arrow--right {
+ visibility: hidden;
+}
+
+/*
+ Arrow buttons hit area
+ (icon is added to :before pseudo-element)
+*/
+.pswp__button--arrow--left,
+.pswp__button--arrow--right {
+ background: none;
+ top: 50%;
+ margin-top: -50px;
+ width: 70px;
+ height: 100px;
+ position: absolute;
+}
+
+.pswp__button--arrow--left {
+ left: 0;
+}
+
+.pswp__button--arrow--right {
+ right: 0;
+}
+
+.pswp__button--arrow--left:before,
+.pswp__button--arrow--right:before {
+ content: "";
+ top: 35px;
+ background-color: rgba(0, 0, 0, 0.3);
+ height: 30px;
+ width: 32px;
+ position: absolute;
+}
+
+.pswp__button--arrow--left:before {
+ left: 6px;
+ background-position: -138px -44px;
+}
+
+.pswp__button--arrow--right:before {
+ right: 6px;
+ background-position: -94px -44px;
+}
+
+/*
+
+ 2. Share modal/popup and links
+
+ */
+.pswp__counter,
+.pswp__share-modal {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.pswp__share-modal {
+ display: block;
+ background: rgba(0, 0, 0, 0.5);
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ padding: 10px;
+ position: absolute;
+ z-index: 1600;
+ opacity: 0;
+ -webkit-transition: opacity 0.25s ease-out;
+ transition: opacity 0.25s ease-out;
+ -webkit-backface-visibility: hidden;
+ will-change: opacity;
+}
+
+.pswp__share-modal--hidden {
+ display: none;
+}
+
+.pswp__share-tooltip {
+ z-index: 1620;
+ position: absolute;
+ background: #fff;
+ top: 56px;
+ border-radius: 2px;
+ display: block;
+ width: auto;
+ right: 44px;
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25);
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25);
+ -webkit-transform: translateY(6px);
+ -ms-transform: translateY(6px);
+ transform: translateY(6px);
+ -webkit-transition: -webkit-transform 0.25s;
+ transition: transform 0.25s;
+ -webkit-backface-visibility: hidden;
+ will-change: transform;
+}
+.pswp__share-tooltip a {
+ display: block;
+ padding: 8px 12px;
+ color: #000;
+ text-decoration: none;
+ font-size: 14px;
+ line-height: 18px;
+}
+.pswp__share-tooltip a:hover {
+ text-decoration: none;
+ color: #000;
+}
+.pswp__share-tooltip a:first-child {
+ /* round corners on the first/last list item */
+ border-radius: 2px 2px 0 0;
+}
+.pswp__share-tooltip a:last-child {
+ border-radius: 0 0 2px 2px;
+}
+
+.pswp__share-modal--fade-in {
+ opacity: 1;
+}
+.pswp__share-modal--fade-in .pswp__share-tooltip {
+ -webkit-transform: translateY(0);
+ -ms-transform: translateY(0);
+ transform: translateY(0);
+}
+
+/* increase size of share links on touch devices */
+.pswp--touch .pswp__share-tooltip a {
+ padding: 16px 12px;
+}
+
+a.pswp__share--facebook:before {
+ content: "";
+ display: block;
+ width: 0;
+ height: 0;
+ position: absolute;
+ top: -12px;
+ right: 15px;
+ border: 6px solid transparent;
+ border-bottom-color: #fff;
+ -webkit-pointer-events: none;
+ -moz-pointer-events: none;
+ pointer-events: none;
+}
+
+a.pswp__share--facebook:hover {
+ background: #3e5c9a;
+ color: #fff;
+}
+a.pswp__share--facebook:hover:before {
+ border-bottom-color: #3e5c9a;
+}
+
+a.pswp__share--twitter:hover {
+ background: #55acee;
+ color: #fff;
+}
+
+a.pswp__share--pinterest:hover {
+ background: #ccc;
+ color: #ce272d;
+}
+
+a.pswp__share--download:hover {
+ background: #ddd;
+}
+
+/*
+
+ 3. Index indicator ("1 of X" counter)
+
+ */
+.pswp__counter {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 44px;
+ font-size: 13px;
+ line-height: 44px;
+ color: #fff;
+ opacity: 0.75;
+ padding: 0 10px;
+}
+
+/*
+
+ 4. Caption
+
+ */
+.pswp__caption {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ min-height: 44px;
+}
+.pswp__caption small {
+ font-size: 11px;
+ color: #bbb;
+}
+
+.pswp__caption__center {
+ text-align: left;
+ max-width: 420px;
+ margin: 0 auto;
+ font-size: 13px;
+ padding: 10px;
+ line-height: 20px;
+ color: #ccc;
+}
+
+.pswp__caption--empty {
+ display: none;
+}
+
+/* Fake caption element, used to calculate height of next/prev image */
+.pswp__caption--fake {
+ visibility: hidden;
+}
+
+/*
+
+ 5. Loading indicator (preloader)
+
+ You can play with it here - http://codepen.io/dimsemenov/pen/yyBWoR
+
+ */
+.pswp__preloader {
+ width: 44px;
+ height: 44px;
+ position: absolute;
+ top: 0;
+ left: 50%;
+ margin-left: -22px;
+ opacity: 0;
+ -webkit-transition: opacity 0.25s ease-out;
+ transition: opacity 0.25s ease-out;
+ will-change: opacity;
+ direction: ltr;
+}
+
+.pswp__preloader__icn {
+ width: 20px;
+ height: 20px;
+ margin: 12px;
+}
+
+.pswp__preloader--active {
+ opacity: 1;
+}
+.pswp__preloader--active .pswp__preloader__icn {
+ /* We use .gif in browsers that don't support CSS animation */
+ background: url(preloader.gif) 0 0 no-repeat;
+}
+
+.pswp--css_animation .pswp__preloader--active {
+ opacity: 1;
+}
+.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn {
+ -webkit-animation: clockwise 500ms linear infinite;
+ animation: clockwise 500ms linear infinite;
+}
+.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut {
+ -webkit-animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite;
+ animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite;
+}
+
+.pswp--css_animation .pswp__preloader__icn {
+ background: none;
+ opacity: 0.75;
+ width: 14px;
+ height: 14px;
+ position: absolute;
+ left: 15px;
+ top: 15px;
+ margin: 0;
+}
+
+.pswp--css_animation .pswp__preloader__cut {
+ /*
+ The idea of animating inner circle is based on Polymer ("material") loading indicator
+ by Keanu Lee https://blog.keanulee.com/2014/10/20/the-tale-of-three-spinners.html
+ */
+ position: relative;
+ width: 7px;
+ height: 14px;
+ overflow: hidden;
+}
+
+.pswp--css_animation .pswp__preloader__donut {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 14px;
+ height: 14px;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background: none;
+ margin: 0;
+}
+
+@media screen and (max-width: 1024px) {
+ .pswp__preloader {
+ position: relative;
+ left: auto;
+ top: auto;
+ margin: 0;
+ float: right;
+ }
+}
+
+@-webkit-keyframes clockwise {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes clockwise {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes donut-rotate {
+ 0% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+ 50% {
+ -webkit-transform: rotate(-140deg);
+ transform: rotate(-140deg);
+ }
+ 100% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+}
+
+@keyframes donut-rotate {
+ 0% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+ 50% {
+ -webkit-transform: rotate(-140deg);
+ transform: rotate(-140deg);
+ }
+ 100% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+}
+
+/*
+
+ 6. Additional styles
+
+ */
+/* root element of UI */
+.pswp__ui {
+ -webkit-font-smoothing: auto;
+ visibility: visible;
+ opacity: 1;
+ z-index: 1550;
+}
+
+/* top black bar with buttons and "1 of X" indicator */
+.pswp__top-bar {
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 44px;
+ width: 100%;
+}
+
+.pswp__caption,
+.pswp__top-bar,
+.pswp--has_mouse .pswp__button--arrow--left,
+.pswp--has_mouse .pswp__button--arrow--right {
+ -webkit-backface-visibility: hidden;
+ will-change: opacity;
+ -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+ transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+}
+
+/* pswp--has_mouse class is added only when two subsequent mousemove events occur */
+.pswp--has_mouse .pswp__button--arrow--left,
+.pswp--has_mouse .pswp__button--arrow--right {
+ visibility: visible;
+}
+
+.pswp__top-bar,
+.pswp__caption {
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+/* pswp__ui--fit class is added when main image "fits" between top bar and bottom bar (caption) */
+.pswp__ui--fit .pswp__top-bar,
+.pswp__ui--fit .pswp__caption {
+ background-color: rgba(0, 0, 0, 0.3);
+}
+
+/* pswp__ui--idle class is added when mouse isn't moving for several seconds (JS option timeToIdle) */
+.pswp__ui--idle .pswp__top-bar {
+ opacity: 0;
+}
+
+.pswp__ui--idle .pswp__button--arrow--left,
+.pswp__ui--idle .pswp__button--arrow--right {
+ opacity: 0;
+}
+
+/*
+ pswp__ui--hidden class is added when controls are hidden
+ e.g. when user taps to toggle visibility of controls
+*/
+.pswp__ui--hidden .pswp__top-bar,
+.pswp__ui--hidden .pswp__caption,
+.pswp__ui--hidden .pswp__button--arrow--left,
+.pswp__ui--hidden .pswp__button--arrow--right {
+ /* Force paint & create composition layer for controls. */
+ opacity: 0.001;
+}
+
+/* pswp__ui--one-slide class is added when there is just one item in gallery */
+.pswp__ui--one-slide .pswp__button--arrow--left,
+.pswp__ui--one-slide .pswp__button--arrow--right,
+.pswp__ui--one-slide .pswp__counter {
+ display: none;
+}
+
+.pswp__element--disabled {
+ display: none !important;
+}
+
+.pswp--minimal--dark .pswp__top-bar {
+ background: none;
+}
diff --git a/static/photoswipe/default-skin/default-skin.png b/static/photoswipe/default-skin/default-skin.png
new file mode 100644
index 00000000..441c502c
Binary files /dev/null and b/static/photoswipe/default-skin/default-skin.png differ
diff --git a/static/photoswipe/default-skin/default-skin.svg b/static/photoswipe/default-skin/default-skin.svg
new file mode 100644
index 00000000..9d5f0c6a
--- /dev/null
+++ b/static/photoswipe/default-skin/default-skin.svg
@@ -0,0 +1 @@
+default-skin 2
\ No newline at end of file
diff --git a/static/photoswipe/default-skin/preloader.gif b/static/photoswipe/default-skin/preloader.gif
new file mode 100644
index 00000000..b8faa697
Binary files /dev/null and b/static/photoswipe/default-skin/preloader.gif differ
diff --git a/static/photoswipe/photoswipe-array-from-dom.js b/static/photoswipe/photoswipe-array-from-dom.js
new file mode 100644
index 00000000..9322d32d
--- /dev/null
+++ b/static/photoswipe/photoswipe-array-from-dom.js
@@ -0,0 +1,203 @@
+var initPhotoSwipeFromDOM = function(gallerySelector) {
+ // parse slide data (url, title, size ...) from DOM elements
+ // (children of gallerySelector)
+ var parseThumbnailElements = function(el) {
+ var thumbElements = el.childNodes,
+ numNodes = thumbElements.length,
+ items = [],
+ figureEl,
+ linkEl,
+ size,
+ item;
+
+ for (var i = 0; i < numNodes; i++) {
+ figureEl = thumbElements[i]; // element
+
+ // include only element nodes
+ if (figureEl.nodeType !== 1) {
+ continue;
+ }
+
+ linkEl = figureEl.children[0]; // element
+
+ size = linkEl.getAttribute("data-size").split("x");
+
+ // create slide object
+ item = {
+ src: linkEl.getAttribute("href"),
+ w: parseInt(size[0], 10),
+ h: parseInt(size[1], 10)
+ };
+
+ if (figureEl.children.length > 1) {
+ // content
+ item.title = figureEl.children[1].innerHTML;
+ }
+
+ if (linkEl.children.length > 0) {
+ // thumbnail element, retrieving thumbnail url
+ item.msrc = linkEl.children[0].getAttribute("src");
+ }
+
+ item.el = figureEl; // save link to element for getThumbBoundsFn
+ items.push(item);
+ }
+
+ return items;
+ };
+
+ // find nearest parent element
+ var closest = function closest(el, fn) {
+ return el && (fn(el) ? el : closest(el.parentNode, fn));
+ };
+
+ // triggers when user clicks on thumbnail
+ var onThumbnailsClick = function(e) {
+ e = e || window.event;
+ e.preventDefault ? e.preventDefault() : (e.returnValue = false);
+
+ var eTarget = e.target || e.srcElement;
+
+ // find root element of slide
+ var clickedListItem = closest(eTarget, function(el) {
+ return el.tagName && el.tagName.toUpperCase() === "FIGURE";
+ });
+
+ if (!clickedListItem) {
+ return;
+ }
+
+ // find index of clicked item by looping through all child nodes
+ // alternatively, you may define index via data- attribute
+ var clickedGallery = clickedListItem.parentNode,
+ childNodes = clickedListItem.parentNode.childNodes,
+ numChildNodes = childNodes.length,
+ nodeIndex = 0,
+ index;
+
+ for (var i = 0; i < numChildNodes; i++) {
+ if (childNodes[i].nodeType !== 1) {
+ continue;
+ }
+
+ if (childNodes[i] === clickedListItem) {
+ index = nodeIndex;
+ break;
+ }
+ nodeIndex++;
+ }
+
+ if (index >= 0) {
+ // open PhotoSwipe if valid index found
+ openPhotoSwipe(index, clickedGallery);
+ }
+ return false;
+ };
+
+ // parse picture index and gallery index from URL (#&pid=1&gid=2)
+ var photoswipeParseHash = function() {
+ var hash = window.location.hash.substring(1),
+ params = {};
+
+ if (hash.length < 5) {
+ return params;
+ }
+
+ var vars = hash.split("&");
+ for (var i = 0; i < vars.length; i++) {
+ if (!vars[i]) {
+ continue;
+ }
+ var pair = vars[i].split("=");
+ if (pair.length < 2) {
+ continue;
+ }
+ params[pair[0]] = pair[1];
+ }
+
+ if (params.gid) {
+ params.gid = parseInt(params.gid, 10);
+ }
+
+ return params;
+ };
+
+ var openPhotoSwipe = function(
+ index,
+ galleryElement,
+ disableAnimation,
+ fromURL
+ ) {
+ var pswpElement = document.querySelectorAll(".pswp")[0],
+ gallery,
+ options,
+ items;
+
+ items = parseThumbnailElements(galleryElement);
+
+ // define options (if needed)
+ options = {
+ // define gallery index (for URL)
+ galleryUID: galleryElement.getAttribute("data-pswp-uid"),
+
+ getThumbBoundsFn: function(index) {
+ // See Options -> getThumbBoundsFn section of documentation for more info
+ var thumbnail = items[index].el.getElementsByTagName("img")[0], // find thumbnail
+ pageYScroll =
+ window.pageYOffset || document.documentElement.scrollTop,
+ rect = thumbnail.getBoundingClientRect();
+
+ return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
+ }
+ };
+
+ // PhotoSwipe opened from URL
+ if (fromURL) {
+ if (options.galleryPIDs) {
+ // parse real index when custom PIDs are used
+ // http://photoswipe.com/documentation/faq.html#custom-pid-in-url
+ for (var j = 0; j < items.length; j++) {
+ if (items[j].pid == index) {
+ options.index = j;
+ break;
+ }
+ }
+ } else {
+ // in URL indexes start from 1
+ options.index = parseInt(index, 10) - 1;
+ }
+ } else {
+ options.index = parseInt(index, 10);
+ }
+
+ // exit if index not found
+ if (isNaN(options.index)) {
+ return;
+ }
+
+ if (disableAnimation) {
+ options.showAnimationDuration = 0;
+ }
+
+ // Pass data to PhotoSwipe and initialize it
+ gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
+ gallery.init();
+ };
+
+ // loop through all gallery elements and bind events
+ var galleryElements = document.querySelectorAll(gallerySelector);
+
+ for (var i = 0, l = galleryElements.length; i < l; i++) {
+ galleryElements[i].setAttribute("data-pswp-uid", i + 1);
+ galleryElements[i].onclick = onThumbnailsClick;
+ }
+
+ // Parse URL and open gallery if it contains #&pid=3&gid=1
+ var hashData = photoswipeParseHash();
+ if (hashData.pid && hashData.gid) {
+ openPhotoSwipe(hashData.pid, galleryElements[hashData.gid - 1], true, true);
+ }
+};
+
+// execute above function
+initPhotoSwipeFromDOM(".photoswipe-gallery");
diff --git a/static/photoswipe/photoswipe-ui-default.js b/static/photoswipe/photoswipe-ui-default.js
new file mode 100644
index 00000000..bd5b5886
--- /dev/null
+++ b/static/photoswipe/photoswipe-ui-default.js
@@ -0,0 +1,875 @@
+/*! PhotoSwipe Default UI - 4.1.3 - 2019-01-08
+ * http://photoswipe.com
+ * Copyright (c) 2019 Dmitry Semenov; */
+/**
+ *
+ * UI on top of main sliding area (caption, arrows, close button, etc.).
+ * Built just using public methods/properties of PhotoSwipe.
+ *
+ */
+(function(root, factory) {
+ if (typeof define === "function" && define.amd) {
+ define(factory);
+ } else if (typeof exports === "object") {
+ module.exports = factory();
+ } else {
+ root.PhotoSwipeUI_Default = factory();
+ }
+})(this, function() {
+ "use strict";
+
+ var PhotoSwipeUI_Default = function(pswp, framework) {
+ var ui = this;
+ var _overlayUIUpdated = false,
+ _controlsVisible = true,
+ _fullscrenAPI,
+ _controls,
+ _captionContainer,
+ _fakeCaptionContainer,
+ _indexIndicator,
+ _shareButton,
+ _shareModal,
+ _shareModalHidden = true,
+ _initalCloseOnScrollValue,
+ _isIdle,
+ _listen,
+ _loadingIndicator,
+ _loadingIndicatorHidden,
+ _loadingIndicatorTimeout,
+ _galleryHasOneSlide,
+ _options,
+ _defaultUIOptions = {
+ barsSize: { top: 44, bottom: "auto" },
+ closeElClasses: ["item", "caption", "zoom-wrap", "ui", "top-bar"],
+ timeToIdle: 4000,
+ timeToIdleOutside: 1000,
+ loadingIndicatorDelay: 1000, // 2s
+
+ addCaptionHTMLFn: function(item, captionEl /*, isFake */) {
+ if (!item.title) {
+ captionEl.children[0].innerHTML = "";
+ return false;
+ }
+ captionEl.children[0].innerHTML = item.title;
+ return true;
+ },
+
+ closeEl: true,
+ captionEl: true,
+ fullscreenEl: true,
+ zoomEl: true,
+ shareEl: true,
+ counterEl: true,
+ arrowEl: true,
+ preloaderEl: true,
+
+ tapToClose: false,
+ tapToToggleControls: true,
+
+ clickToCloseNonZoomable: true,
+
+ shareButtons: [
+ {
+ id: "facebook",
+ label: "Share on Facebook",
+ url: "https://www.facebook.com/sharer/sharer.php?u={{url}}"
+ },
+ {
+ id: "twitter",
+ label: "Tweet",
+ url: "https://twitter.com/intent/tweet?text={{text}}&url={{url}}"
+ },
+ {
+ id: "pinterest",
+ label: "Pin it",
+ url:
+ "http://www.pinterest.com/pin/create/button/" +
+ "?url={{url}}&media={{image_url}}&description={{text}}"
+ },
+ {
+ id: "download",
+ label: "Download image",
+ url: "{{raw_image_url}}",
+ download: true
+ }
+ ],
+ getImageURLForShare: function(/* shareButtonData */) {
+ return pswp.currItem.src || "";
+ },
+ getPageURLForShare: function(/* shareButtonData */) {
+ return window.location.href;
+ },
+ getTextForShare: function(/* shareButtonData */) {
+ return pswp.currItem.title || "";
+ },
+
+ indexIndicatorSep: " / ",
+ fitControlsWidth: 1200
+ },
+ _blockControlsTap,
+ _blockControlsTapTimeout;
+
+ var _onControlsTap = function(e) {
+ if (_blockControlsTap) {
+ return true;
+ }
+
+ e = e || window.event;
+
+ if (_options.timeToIdle && _options.mouseUsed && !_isIdle) {
+ // reset idle timer
+ _onIdleMouseMove();
+ }
+
+ var target = e.target || e.srcElement,
+ uiElement,
+ clickedClass = target.getAttribute("class") || "",
+ found;
+
+ for (var i = 0; i < _uiElements.length; i++) {
+ uiElement = _uiElements[i];
+ if (
+ uiElement.onTap &&
+ clickedClass.indexOf("pswp__" + uiElement.name) > -1
+ ) {
+ uiElement.onTap();
+ found = true;
+ }
+ }
+
+ if (found) {
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ }
+ _blockControlsTap = true;
+
+ // Some versions of Android don't prevent ghost click event
+ // when preventDefault() was called on touchstart and/or touchend.
+ //
+ // This happens on v4.3, 4.2, 4.1,
+ // older versions strangely work correctly,
+ // but just in case we add delay on all of them)
+ var tapDelay = framework.features.isOldAndroid ? 600 : 30;
+ _blockControlsTapTimeout = setTimeout(function() {
+ _blockControlsTap = false;
+ }, tapDelay);
+ }
+ },
+ _fitControlsInViewport = function() {
+ return (
+ !pswp.likelyTouchDevice ||
+ _options.mouseUsed ||
+ screen.width > _options.fitControlsWidth
+ );
+ },
+ _togglePswpClass = function(el, cName, add) {
+ framework[(add ? "add" : "remove") + "Class"](el, "pswp__" + cName);
+ },
+ // add class when there is just one item in the gallery
+ // (by default it hides left/right arrows and 1ofX counter)
+ _countNumItems = function() {
+ var hasOneSlide = _options.getNumItemsFn() === 1;
+
+ if (hasOneSlide !== _galleryHasOneSlide) {
+ _togglePswpClass(_controls, "ui--one-slide", hasOneSlide);
+ _galleryHasOneSlide = hasOneSlide;
+ }
+ },
+ _toggleShareModalClass = function() {
+ _togglePswpClass(_shareModal, "share-modal--hidden", _shareModalHidden);
+ },
+ _toggleShareModal = function() {
+ _shareModalHidden = !_shareModalHidden;
+
+ if (!_shareModalHidden) {
+ _toggleShareModalClass();
+ setTimeout(function() {
+ if (!_shareModalHidden) {
+ framework.addClass(_shareModal, "pswp__share-modal--fade-in");
+ }
+ }, 30);
+ } else {
+ framework.removeClass(_shareModal, "pswp__share-modal--fade-in");
+ setTimeout(function() {
+ if (_shareModalHidden) {
+ _toggleShareModalClass();
+ }
+ }, 300);
+ }
+
+ if (!_shareModalHidden) {
+ _updateShareURLs();
+ }
+ return false;
+ },
+ _openWindowPopup = function(e) {
+ e = e || window.event;
+ var target = e.target || e.srcElement;
+
+ pswp.shout("shareLinkClick", e, target);
+
+ if (!target.href) {
+ return false;
+ }
+
+ if (target.hasAttribute("download")) {
+ return true;
+ }
+
+ window.open(
+ target.href,
+ "pswp_share",
+ "scrollbars=yes,resizable=yes,toolbar=no," +
+ "location=yes,width=550,height=420,top=100,left=" +
+ (window.screen ? Math.round(screen.width / 2 - 275) : 100)
+ );
+
+ if (!_shareModalHidden) {
+ _toggleShareModal();
+ }
+
+ return false;
+ },
+ _updateShareURLs = function() {
+ var shareButtonOut = "",
+ shareButtonData,
+ shareURL,
+ image_url,
+ page_url,
+ share_text;
+
+ for (var i = 0; i < _options.shareButtons.length; i++) {
+ shareButtonData = _options.shareButtons[i];
+
+ image_url = _options.getImageURLForShare(shareButtonData);
+ page_url = _options.getPageURLForShare(shareButtonData);
+ share_text = _options.getTextForShare(shareButtonData);
+
+ shareURL = shareButtonData.url
+ .replace("{{url}}", encodeURIComponent(page_url))
+ .replace("{{image_url}}", encodeURIComponent(image_url))
+ .replace("{{raw_image_url}}", image_url)
+ .replace("{{text}}", encodeURIComponent(share_text));
+
+ shareButtonOut +=
+ '" +
+ shareButtonData.label +
+ " ";
+
+ if (_options.parseShareButtonOut) {
+ shareButtonOut = _options.parseShareButtonOut(
+ shareButtonData,
+ shareButtonOut
+ );
+ }
+ }
+ _shareModal.children[0].innerHTML = shareButtonOut;
+ _shareModal.children[0].onclick = _openWindowPopup;
+ },
+ _hasCloseClass = function(target) {
+ for (var i = 0; i < _options.closeElClasses.length; i++) {
+ if (
+ framework.hasClass(target, "pswp__" + _options.closeElClasses[i])
+ ) {
+ return true;
+ }
+ }
+ },
+ _idleInterval,
+ _idleTimer,
+ _idleIncrement = 0,
+ _onIdleMouseMove = function() {
+ clearTimeout(_idleTimer);
+ _idleIncrement = 0;
+ if (_isIdle) {
+ ui.setIdle(false);
+ }
+ },
+ _onMouseLeaveWindow = function(e) {
+ e = e ? e : window.event;
+ var from = e.relatedTarget || e.toElement;
+ if (!from || from.nodeName === "HTML") {
+ clearTimeout(_idleTimer);
+ _idleTimer = setTimeout(function() {
+ ui.setIdle(true);
+ }, _options.timeToIdleOutside);
+ }
+ },
+ _setupFullscreenAPI = function() {
+ if (_options.fullscreenEl && !framework.features.isOldAndroid) {
+ if (!_fullscrenAPI) {
+ _fullscrenAPI = ui.getFullscreenAPI();
+ }
+ if (_fullscrenAPI) {
+ framework.bind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
+ ui.updateFullscreen();
+ framework.addClass(pswp.template, "pswp--supports-fs");
+ } else {
+ framework.removeClass(pswp.template, "pswp--supports-fs");
+ }
+ }
+ },
+ _setupLoadingIndicator = function() {
+ // Setup loading indicator
+ if (_options.preloaderEl) {
+ _toggleLoadingIndicator(true);
+
+ _listen("beforeChange", function() {
+ clearTimeout(_loadingIndicatorTimeout);
+
+ // display loading indicator with delay
+ _loadingIndicatorTimeout = setTimeout(function() {
+ if (pswp.currItem && pswp.currItem.loading) {
+ if (
+ !pswp.allowProgressiveImg() ||
+ (pswp.currItem.img && !pswp.currItem.img.naturalWidth)
+ ) {
+ // show preloader if progressive loading is not enabled,
+ // or image width is not defined yet (because of slow connection)
+ _toggleLoadingIndicator(false);
+ // items-controller.js function allowProgressiveImg
+ }
+ } else {
+ _toggleLoadingIndicator(true); // hide preloader
+ }
+ }, _options.loadingIndicatorDelay);
+ });
+ _listen("imageLoadComplete", function(index, item) {
+ if (pswp.currItem === item) {
+ _toggleLoadingIndicator(true);
+ }
+ });
+ }
+ },
+ _toggleLoadingIndicator = function(hide) {
+ if (_loadingIndicatorHidden !== hide) {
+ _togglePswpClass(_loadingIndicator, "preloader--active", !hide);
+ _loadingIndicatorHidden = hide;
+ }
+ },
+ _applyNavBarGaps = function(item) {
+ var gap = item.vGap;
+
+ if (_fitControlsInViewport()) {
+ var bars = _options.barsSize;
+ if (_options.captionEl && bars.bottom === "auto") {
+ if (!_fakeCaptionContainer) {
+ _fakeCaptionContainer = framework.createEl(
+ "pswp__caption pswp__caption--fake"
+ );
+ _fakeCaptionContainer.appendChild(
+ framework.createEl("pswp__caption__center")
+ );
+ _controls.insertBefore(_fakeCaptionContainer, _captionContainer);
+ framework.addClass(_controls, "pswp__ui--fit");
+ }
+ if (_options.addCaptionHTMLFn(item, _fakeCaptionContainer, true)) {
+ var captionSize = _fakeCaptionContainer.clientHeight;
+ gap.bottom = parseInt(captionSize, 10) || 44;
+ } else {
+ gap.bottom = bars.top; // if no caption, set size of bottom gap to size of top
+ }
+ } else {
+ gap.bottom = bars.bottom === "auto" ? 0 : bars.bottom;
+ }
+
+ // height of top bar is static, no need to calculate it
+ gap.top = bars.top;
+ } else {
+ gap.top = gap.bottom = 0;
+ }
+ },
+ _setupIdle = function() {
+ // Hide controls when mouse is used
+ if (_options.timeToIdle) {
+ _listen("mouseUsed", function() {
+ framework.bind(document, "mousemove", _onIdleMouseMove);
+ framework.bind(document, "mouseout", _onMouseLeaveWindow);
+
+ _idleInterval = setInterval(function() {
+ _idleIncrement++;
+ if (_idleIncrement === 2) {
+ ui.setIdle(true);
+ }
+ }, _options.timeToIdle / 2);
+ });
+ }
+ },
+ _setupHidingControlsDuringGestures = function() {
+ // Hide controls on vertical drag
+ _listen("onVerticalDrag", function(now) {
+ if (_controlsVisible && now < 0.95) {
+ ui.hideControls();
+ } else if (!_controlsVisible && now >= 0.95) {
+ ui.showControls();
+ }
+ });
+
+ // Hide controls when pinching to close
+ var pinchControlsHidden;
+ _listen("onPinchClose", function(now) {
+ if (_controlsVisible && now < 0.9) {
+ ui.hideControls();
+ pinchControlsHidden = true;
+ } else if (pinchControlsHidden && !_controlsVisible && now > 0.9) {
+ ui.showControls();
+ }
+ });
+
+ _listen("zoomGestureEnded", function() {
+ pinchControlsHidden = false;
+ if (pinchControlsHidden && !_controlsVisible) {
+ ui.showControls();
+ }
+ });
+ };
+
+ var _uiElements = [
+ {
+ name: "caption",
+ option: "captionEl",
+ onInit: function(el) {
+ _captionContainer = el;
+ }
+ },
+ {
+ name: "share-modal",
+ option: "shareEl",
+ onInit: function(el) {
+ _shareModal = el;
+ },
+ onTap: function() {
+ _toggleShareModal();
+ }
+ },
+ {
+ name: "button--share",
+ option: "shareEl",
+ onInit: function(el) {
+ _shareButton = el;
+ },
+ onTap: function() {
+ _toggleShareModal();
+ }
+ },
+ {
+ name: "button--zoom",
+ option: "zoomEl",
+ onTap: pswp.toggleDesktopZoom
+ },
+ {
+ name: "counter",
+ option: "counterEl",
+ onInit: function(el) {
+ _indexIndicator = el;
+ }
+ },
+ {
+ name: "button--close",
+ option: "closeEl",
+ onTap: pswp.close
+ },
+ {
+ name: "button--arrow--left",
+ option: "arrowEl",
+ onTap: pswp.prev
+ },
+ {
+ name: "button--arrow--right",
+ option: "arrowEl",
+ onTap: pswp.next
+ },
+ {
+ name: "button--fs",
+ option: "fullscreenEl",
+ onTap: function() {
+ if (_fullscrenAPI.isFullscreen()) {
+ _fullscrenAPI.exit();
+ } else {
+ _fullscrenAPI.enter();
+ }
+ }
+ },
+ {
+ name: "preloader",
+ option: "preloaderEl",
+ onInit: function(el) {
+ _loadingIndicator = el;
+ }
+ }
+ ];
+
+ var _setupUIElements = function() {
+ var item, classAttr, uiElement;
+
+ var loopThroughChildElements = function(sChildren) {
+ if (!sChildren) {
+ return;
+ }
+
+ var l = sChildren.length;
+ for (var i = 0; i < l; i++) {
+ item = sChildren[i];
+ classAttr = item.className;
+
+ for (var a = 0; a < _uiElements.length; a++) {
+ uiElement = _uiElements[a];
+
+ if (classAttr.indexOf("pswp__" + uiElement.name) > -1) {
+ if (_options[uiElement.option]) {
+ // if element is not disabled from options
+
+ framework.removeClass(item, "pswp__element--disabled");
+ if (uiElement.onInit) {
+ uiElement.onInit(item);
+ }
+
+ //item.style.display = 'block';
+ } else {
+ framework.addClass(item, "pswp__element--disabled");
+ //item.style.display = 'none';
+ }
+ }
+ }
+ }
+ };
+ loopThroughChildElements(_controls.children);
+
+ var topBar = framework.getChildByClass(_controls, "pswp__top-bar");
+ if (topBar) {
+ loopThroughChildElements(topBar.children);
+ }
+ };
+
+ ui.init = function() {
+ // extend options
+ framework.extend(pswp.options, _defaultUIOptions, true);
+
+ // create local link for fast access
+ _options = pswp.options;
+
+ // find pswp__ui element
+ _controls = framework.getChildByClass(pswp.scrollWrap, "pswp__ui");
+
+ // create local link
+ _listen = pswp.listen;
+
+ _setupHidingControlsDuringGestures();
+
+ // update controls when slides change
+ _listen("beforeChange", ui.update);
+
+ // toggle zoom on double-tap
+ _listen("doubleTap", function(point) {
+ var initialZoomLevel = pswp.currItem.initialZoomLevel;
+ if (pswp.getZoomLevel() !== initialZoomLevel) {
+ pswp.zoomTo(initialZoomLevel, point, 333);
+ } else {
+ pswp.zoomTo(
+ _options.getDoubleTapZoom(false, pswp.currItem),
+ point,
+ 333
+ );
+ }
+ });
+
+ // Allow text selection in caption
+ _listen("preventDragEvent", function(e, isDown, preventObj) {
+ var t = e.target || e.srcElement;
+ if (
+ t &&
+ t.getAttribute("class") &&
+ e.type.indexOf("mouse") > -1 &&
+ (t.getAttribute("class").indexOf("__caption") > 0 ||
+ /(SMALL|STRONG|EM)/i.test(t.tagName))
+ ) {
+ preventObj.prevent = false;
+ }
+ });
+
+ // bind events for UI
+ _listen("bindEvents", function() {
+ framework.bind(_controls, "pswpTap click", _onControlsTap);
+ framework.bind(pswp.scrollWrap, "pswpTap", ui.onGlobalTap);
+
+ if (!pswp.likelyTouchDevice) {
+ framework.bind(pswp.scrollWrap, "mouseover", ui.onMouseOver);
+ }
+ });
+
+ // unbind events for UI
+ _listen("unbindEvents", function() {
+ if (!_shareModalHidden) {
+ _toggleShareModal();
+ }
+
+ if (_idleInterval) {
+ clearInterval(_idleInterval);
+ }
+ framework.unbind(document, "mouseout", _onMouseLeaveWindow);
+ framework.unbind(document, "mousemove", _onIdleMouseMove);
+ framework.unbind(_controls, "pswpTap click", _onControlsTap);
+ framework.unbind(pswp.scrollWrap, "pswpTap", ui.onGlobalTap);
+ framework.unbind(pswp.scrollWrap, "mouseover", ui.onMouseOver);
+
+ if (_fullscrenAPI) {
+ framework.unbind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
+ if (_fullscrenAPI.isFullscreen()) {
+ _options.hideAnimationDuration = 0;
+ _fullscrenAPI.exit();
+ }
+ _fullscrenAPI = null;
+ }
+ });
+
+ // clean up things when gallery is destroyed
+ _listen("destroy", function() {
+ if (_options.captionEl) {
+ if (_fakeCaptionContainer) {
+ _controls.removeChild(_fakeCaptionContainer);
+ }
+ framework.removeClass(_captionContainer, "pswp__caption--empty");
+ }
+
+ if (_shareModal) {
+ _shareModal.children[0].onclick = null;
+ }
+ framework.removeClass(_controls, "pswp__ui--over-close");
+ framework.addClass(_controls, "pswp__ui--hidden");
+ ui.setIdle(false);
+ });
+
+ if (!_options.showAnimationDuration) {
+ framework.removeClass(_controls, "pswp__ui--hidden");
+ }
+ _listen("initialZoomIn", function() {
+ if (_options.showAnimationDuration) {
+ framework.removeClass(_controls, "pswp__ui--hidden");
+ }
+ });
+ _listen("initialZoomOut", function() {
+ framework.addClass(_controls, "pswp__ui--hidden");
+ });
+
+ _listen("parseVerticalMargin", _applyNavBarGaps);
+
+ _setupUIElements();
+
+ if (_options.shareEl && _shareButton && _shareModal) {
+ _shareModalHidden = true;
+ }
+
+ _countNumItems();
+
+ _setupIdle();
+
+ _setupFullscreenAPI();
+
+ _setupLoadingIndicator();
+ };
+
+ ui.setIdle = function(isIdle) {
+ _isIdle = isIdle;
+ _togglePswpClass(_controls, "ui--idle", isIdle);
+ };
+
+ ui.update = function() {
+ // Don't update UI if it's hidden
+ if (_controlsVisible && pswp.currItem) {
+ ui.updateIndexIndicator();
+
+ if (_options.captionEl) {
+ _options.addCaptionHTMLFn(pswp.currItem, _captionContainer);
+
+ _togglePswpClass(
+ _captionContainer,
+ "caption--empty",
+ !pswp.currItem.title
+ );
+ }
+
+ _overlayUIUpdated = true;
+ } else {
+ _overlayUIUpdated = false;
+ }
+
+ if (!_shareModalHidden) {
+ _toggleShareModal();
+ }
+
+ _countNumItems();
+ };
+
+ ui.updateFullscreen = function(e) {
+ if (e) {
+ // some browsers change window scroll position during the fullscreen
+ // so PhotoSwipe updates it just in case
+ setTimeout(function() {
+ pswp.setScrollOffset(0, framework.getScrollY());
+ }, 50);
+ }
+
+ // toogle pswp--fs class on root element
+ framework[(_fullscrenAPI.isFullscreen() ? "add" : "remove") + "Class"](
+ pswp.template,
+ "pswp--fs"
+ );
+ };
+
+ ui.updateIndexIndicator = function() {
+ if (_options.counterEl) {
+ _indexIndicator.innerHTML =
+ pswp.getCurrentIndex() +
+ 1 +
+ _options.indexIndicatorSep +
+ _options.getNumItemsFn();
+ }
+ };
+
+ ui.onGlobalTap = function(e) {
+ e = e || window.event;
+ var target = e.target || e.srcElement;
+
+ if (_blockControlsTap) {
+ return;
+ }
+
+ if (e.detail && e.detail.pointerType === "mouse") {
+ // close gallery if clicked outside of the image
+ if (_hasCloseClass(target)) {
+ pswp.close();
+ return;
+ }
+
+ if (framework.hasClass(target, "pswp__img")) {
+ if (
+ pswp.getZoomLevel() === 1 &&
+ pswp.getZoomLevel() <= pswp.currItem.fitRatio
+ ) {
+ if (_options.clickToCloseNonZoomable) {
+ pswp.close();
+ }
+ } else {
+ pswp.toggleDesktopZoom(e.detail.releasePoint);
+ }
+ }
+ } else {
+ // tap anywhere (except buttons) to toggle visibility of controls
+ if (_options.tapToToggleControls) {
+ if (_controlsVisible) {
+ ui.hideControls();
+ } else {
+ ui.showControls();
+ }
+ }
+
+ // tap to close gallery
+ if (
+ _options.tapToClose &&
+ (framework.hasClass(target, "pswp__img") || _hasCloseClass(target))
+ ) {
+ pswp.close();
+ return;
+ }
+ }
+ };
+ ui.onMouseOver = function(e) {
+ e = e || window.event;
+ var target = e.target || e.srcElement;
+
+ // add class when mouse is over an element that should close the gallery
+ _togglePswpClass(_controls, "ui--over-close", _hasCloseClass(target));
+ };
+
+ ui.hideControls = function() {
+ framework.addClass(_controls, "pswp__ui--hidden");
+ _controlsVisible = false;
+ };
+
+ ui.showControls = function() {
+ _controlsVisible = true;
+ if (!_overlayUIUpdated) {
+ ui.update();
+ }
+ framework.removeClass(_controls, "pswp__ui--hidden");
+ };
+
+ ui.supportsFullscreen = function() {
+ var d = document;
+ return !!(
+ d.exitFullscreen ||
+ d.mozCancelFullScreen ||
+ d.webkitExitFullscreen ||
+ d.msExitFullscreen
+ );
+ };
+
+ ui.getFullscreenAPI = function() {
+ var dE = document.documentElement,
+ api,
+ tF = "fullscreenchange";
+
+ if (dE.requestFullscreen) {
+ api = {
+ enterK: "requestFullscreen",
+ exitK: "exitFullscreen",
+ elementK: "fullscreenElement",
+ eventK: tF
+ };
+ } else if (dE.mozRequestFullScreen) {
+ api = {
+ enterK: "mozRequestFullScreen",
+ exitK: "mozCancelFullScreen",
+ elementK: "mozFullScreenElement",
+ eventK: "moz" + tF
+ };
+ } else if (dE.webkitRequestFullscreen) {
+ api = {
+ enterK: "webkitRequestFullscreen",
+ exitK: "webkitExitFullscreen",
+ elementK: "webkitFullscreenElement",
+ eventK: "webkit" + tF
+ };
+ } else if (dE.msRequestFullscreen) {
+ api = {
+ enterK: "msRequestFullscreen",
+ exitK: "msExitFullscreen",
+ elementK: "msFullscreenElement",
+ eventK: "MSFullscreenChange"
+ };
+ }
+
+ if (api) {
+ api.enter = function() {
+ // disable close-on-scroll in fullscreen
+ _initalCloseOnScrollValue = _options.closeOnScroll;
+ _options.closeOnScroll = false;
+
+ if (this.enterK === "webkitRequestFullscreen") {
+ pswp.template[this.enterK](Element.ALLOW_KEYBOARD_INPUT);
+ } else {
+ return pswp.template[this.enterK]();
+ }
+ };
+ api.exit = function() {
+ _options.closeOnScroll = _initalCloseOnScrollValue;
+
+ return document[this.exitK]();
+ };
+ api.isFullscreen = function() {
+ return document[this.elementK];
+ };
+ }
+
+ return api;
+ };
+ };
+ return PhotoSwipeUI_Default;
+});
diff --git a/static/photoswipe/photoswipe.css b/static/photoswipe/photoswipe.css
new file mode 100644
index 00000000..371c7511
--- /dev/null
+++ b/static/photoswipe/photoswipe.css
@@ -0,0 +1,202 @@
+/*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */
+/*
+ Styles for basic PhotoSwipe functionality (sliding area, open/close transitions)
+*/
+/* pswp = photoswipe */
+.pswp {
+ display: none;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ overflow: hidden;
+ -ms-touch-action: none;
+ touch-action: none;
+ z-index: 1500;
+ -webkit-text-size-adjust: 100%;
+ /* create separate layer, to avoid paint on window.onscroll in webkit/blink */
+ -webkit-backface-visibility: hidden;
+ outline: none;
+}
+.pswp * {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.pswp img {
+ max-width: none;
+}
+
+/* style is added when JS option showHideOpacity is set to true */
+.pswp--animate_opacity {
+ /* 0.001, because opacity:0 doesn't trigger Paint action, which causes lag at start of transition */
+ opacity: 0.001;
+ will-change: opacity;
+ /* for open/close transition */
+ -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+ transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+}
+
+.pswp--open {
+ display: block;
+}
+
+.pswp--zoom-allowed .pswp__img {
+ /* autoprefixer: off */
+ cursor: -webkit-zoom-in;
+ cursor: -moz-zoom-in;
+ cursor: zoom-in;
+}
+
+.pswp--zoomed-in .pswp__img {
+ /* autoprefixer: off */
+ cursor: -webkit-grab;
+ cursor: -moz-grab;
+ cursor: grab;
+}
+
+.pswp--dragging .pswp__img {
+ /* autoprefixer: off */
+ cursor: -webkit-grabbing;
+ cursor: -moz-grabbing;
+ cursor: grabbing;
+}
+
+/*
+ Background is added as a separate element.
+ As animating opacity is much faster than animating rgba() background-color.
+*/
+.pswp__bg {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background: #000;
+ opacity: 0;
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ -webkit-backface-visibility: hidden;
+ will-change: opacity;
+}
+
+.pswp__scroll-wrap {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.pswp__container,
+.pswp__zoom-wrap {
+ -ms-touch-action: none;
+ touch-action: none;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+}
+
+/* Prevent selection and tap highlights */
+.pswp__container,
+.pswp__img {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-touch-callout: none;
+}
+
+.pswp__zoom-wrap {
+ position: absolute;
+ width: 100%;
+ -webkit-transform-origin: left top;
+ -ms-transform-origin: left top;
+ transform-origin: left top;
+ /* for open/close transition */
+ -webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
+ transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
+}
+
+.pswp__bg {
+ will-change: opacity;
+ /* for open/close transition */
+ -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+ transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
+}
+
+.pswp--animated-in .pswp__bg,
+.pswp--animated-in .pswp__zoom-wrap {
+ -webkit-transition: none;
+ transition: none;
+}
+
+.pswp__container,
+.pswp__zoom-wrap {
+ -webkit-backface-visibility: hidden;
+}
+
+.pswp__item {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ overflow: hidden;
+}
+
+.pswp__img {
+ position: absolute;
+ width: auto;
+ height: auto;
+ top: 0;
+ left: 0;
+}
+
+/*
+ stretched thumbnail or div placeholder element (see below)
+ style is added to avoid flickering in webkit/blink when layers overlap
+*/
+.pswp__img--placeholder {
+ -webkit-backface-visibility: hidden;
+}
+
+/*
+ div element that matches size of large image
+ large image loads on top of it
+*/
+.pswp__img--placeholder--blank {
+ background: #222;
+}
+
+.pswp--ie .pswp__img {
+ width: 100% !important;
+ height: auto !important;
+ left: 0;
+ top: 0;
+}
+
+/*
+ Error message appears when image is not loaded
+ (JS option errorMsg controls markup)
+*/
+.pswp__error-msg {
+ position: absolute;
+ left: 0;
+ top: 50%;
+ width: 100%;
+ text-align: center;
+ font-size: 14px;
+ line-height: 16px;
+ margin-top: -8px;
+ color: #ccc;
+}
+
+.pswp__error-msg a {
+ color: #ccc;
+ text-decoration: underline;
+}
diff --git a/static/photoswipe/photoswipe.js b/static/photoswipe/photoswipe.js
new file mode 100644
index 00000000..05ae9f72
--- /dev/null
+++ b/static/photoswipe/photoswipe.js
@@ -0,0 +1,3847 @@
+/*! PhotoSwipe - v4.1.3 - 2019-01-08
+ * http://photoswipe.com
+ * Copyright (c) 2019 Dmitry Semenov; */
+(function(root, factory) {
+ if (typeof define === "function" && define.amd) {
+ define(factory);
+ } else if (typeof exports === "object") {
+ module.exports = factory();
+ } else {
+ root.PhotoSwipe = factory();
+ }
+})(this, function() {
+ "use strict";
+ var PhotoSwipe = function(template, UiClass, items, options) {
+ /*>>framework-bridge*/
+ /**
+ *
+ * Set of generic functions used by gallery.
+ *
+ * You're free to modify anything here as long as functionality is kept.
+ *
+ */
+ var framework = {
+ features: null,
+ bind: function(target, type, listener, unbind) {
+ var methodName = (unbind ? "remove" : "add") + "EventListener";
+ type = type.split(" ");
+ for (var i = 0; i < type.length; i++) {
+ if (type[i]) {
+ target[methodName](type[i], listener, false);
+ }
+ }
+ },
+ isArray: function(obj) {
+ return obj instanceof Array;
+ },
+ createEl: function(classes, tag) {
+ var el = document.createElement(tag || "div");
+ if (classes) {
+ el.className = classes;
+ }
+ return el;
+ },
+ getScrollY: function() {
+ var yOffset = window.pageYOffset;
+ return yOffset !== undefined
+ ? yOffset
+ : document.documentElement.scrollTop;
+ },
+ unbind: function(target, type, listener) {
+ framework.bind(target, type, listener, true);
+ },
+ removeClass: function(el, className) {
+ var reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
+ el.className = el.className
+ .replace(reg, " ")
+ .replace(/^\s\s*/, "")
+ .replace(/\s\s*$/, "");
+ },
+ addClass: function(el, className) {
+ if (!framework.hasClass(el, className)) {
+ el.className += (el.className ? " " : "") + className;
+ }
+ },
+ hasClass: function(el, className) {
+ return (
+ el.className &&
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(el.className)
+ );
+ },
+ getChildByClass: function(parentEl, childClassName) {
+ var node = parentEl.firstChild;
+ while (node) {
+ if (framework.hasClass(node, childClassName)) {
+ return node;
+ }
+ node = node.nextSibling;
+ }
+ },
+ arraySearch: function(array, value, key) {
+ var i = array.length;
+ while (i--) {
+ if (array[i][key] === value) {
+ return i;
+ }
+ }
+ return -1;
+ },
+ extend: function(o1, o2, preventOverwrite) {
+ for (var prop in o2) {
+ if (o2.hasOwnProperty(prop)) {
+ if (preventOverwrite && o1.hasOwnProperty(prop)) {
+ continue;
+ }
+ o1[prop] = o2[prop];
+ }
+ }
+ },
+ easing: {
+ sine: {
+ out: function(k) {
+ return Math.sin(k * (Math.PI / 2));
+ },
+ inOut: function(k) {
+ return -(Math.cos(Math.PI * k) - 1) / 2;
+ }
+ },
+ cubic: {
+ out: function(k) {
+ return --k * k * k + 1;
+ }
+ }
+ /*
+ elastic: {
+ out: function ( k ) {
+
+ var s, a = 0.1, p = 0.4;
+ if ( k === 0 ) return 0;
+ if ( k === 1 ) return 1;
+ if ( !a || a < 1 ) { a = 1; s = p / 4; }
+ else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
+ return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
+
+ },
+ },
+ back: {
+ out: function ( k ) {
+ var s = 1.70158;
+ return --k * k * ( ( s + 1 ) * k + s ) + 1;
+ }
+ }
+ */
+ },
+
+ /**
+ *
+ * @return {object}
+ *
+ * {
+ * raf : request animation frame function
+ * caf : cancel animation frame function
+ * transfrom : transform property key (with vendor), or null if not supported
+ * oldIE : IE8 or below
+ * }
+ *
+ */
+ detectFeatures: function() {
+ if (framework.features) {
+ return framework.features;
+ }
+ var helperEl = framework.createEl(),
+ helperStyle = helperEl.style,
+ vendor = "",
+ features = {};
+
+ // IE8 and below
+ features.oldIE = document.all && !document.addEventListener;
+
+ features.touch = "ontouchstart" in window;
+
+ if (window.requestAnimationFrame) {
+ features.raf = window.requestAnimationFrame;
+ features.caf = window.cancelAnimationFrame;
+ }
+
+ features.pointerEvent =
+ !!window.PointerEvent || navigator.msPointerEnabled;
+
+ // fix false-positive detection of old Android in new IE
+ // (IE11 ua string contains "Android 4.0")
+
+ if (!features.pointerEvent) {
+ var ua = navigator.userAgent;
+
+ // Detect if device is iPhone or iPod and if it's older than iOS 8
+ // http://stackoverflow.com/a/14223920
+ //
+ // This detection is made because of buggy top/bottom toolbars
+ // that don't trigger window.resize event.
+ // For more info refer to _isFixedPosition variable in core.js
+
+ if (/iP(hone|od)/.test(navigator.platform)) {
+ var v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
+ if (v && v.length > 0) {
+ v = parseInt(v[1], 10);
+ if (v >= 1 && v < 8) {
+ features.isOldIOSPhone = true;
+ }
+ }
+ }
+
+ // Detect old Android (before KitKat)
+ // due to bugs related to position:fixed
+ // http://stackoverflow.com/questions/7184573/pick-up-the-android-version-in-the-browser-by-javascript
+
+ var match = ua.match(/Android\s([0-9\.]*)/);
+ var androidversion = match ? match[1] : 0;
+ androidversion = parseFloat(androidversion);
+ if (androidversion >= 1) {
+ if (androidversion < 4.4) {
+ features.isOldAndroid = true; // for fixed position bug & performance
+ }
+ features.androidVersion = androidversion; // for touchend bug
+ }
+ features.isMobileOpera = /opera mini|opera mobi/i.test(ua);
+
+ // p.s. yes, yes, UA sniffing is bad, propose your solution for above bugs.
+ }
+
+ var styleChecks = ["transform", "perspective", "animationName"],
+ vendors = ["", "webkit", "Moz", "ms", "O"],
+ styleCheckItem,
+ styleName;
+
+ for (var i = 0; i < 4; i++) {
+ vendor = vendors[i];
+
+ for (var a = 0; a < 3; a++) {
+ styleCheckItem = styleChecks[a];
+
+ // uppercase first letter of property name, if vendor is present
+ styleName =
+ vendor +
+ (vendor
+ ? styleCheckItem.charAt(0).toUpperCase() +
+ styleCheckItem.slice(1)
+ : styleCheckItem);
+
+ if (!features[styleCheckItem] && styleName in helperStyle) {
+ features[styleCheckItem] = styleName;
+ }
+ }
+
+ if (vendor && !features.raf) {
+ vendor = vendor.toLowerCase();
+ features.raf = window[vendor + "RequestAnimationFrame"];
+ if (features.raf) {
+ features.caf =
+ window[vendor + "CancelAnimationFrame"] ||
+ window[vendor + "CancelRequestAnimationFrame"];
+ }
+ }
+ }
+
+ if (!features.raf) {
+ var lastTime = 0;
+ features.raf = function(fn) {
+ var currTime = new Date().getTime();
+ var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+ var id = window.setTimeout(function() {
+ fn(currTime + timeToCall);
+ }, timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ features.caf = function(id) {
+ clearTimeout(id);
+ };
+ }
+
+ // Detect SVG support
+ features.svg =
+ !!document.createElementNS &&
+ !!document.createElementNS("http://www.w3.org/2000/svg", "svg")
+ .createSVGRect;
+
+ framework.features = features;
+
+ return features;
+ }
+ };
+
+ framework.detectFeatures();
+
+ // Override addEventListener for old versions of IE
+ if (framework.features.oldIE) {
+ framework.bind = function(target, type, listener, unbind) {
+ type = type.split(" ");
+
+ var methodName = (unbind ? "detach" : "attach") + "Event",
+ evName,
+ _handleEv = function() {
+ listener.handleEvent.call(listener);
+ };
+
+ for (var i = 0; i < type.length; i++) {
+ evName = type[i];
+ if (evName) {
+ if (typeof listener === "object" && listener.handleEvent) {
+ if (!unbind) {
+ listener["oldIE" + evName] = _handleEv;
+ } else {
+ if (!listener["oldIE" + evName]) {
+ return false;
+ }
+ }
+
+ target[methodName]("on" + evName, listener["oldIE" + evName]);
+ } else {
+ target[methodName]("on" + evName, listener);
+ }
+ }
+ }
+ };
+ }
+
+ /*>>framework-bridge*/
+
+ /*>>core*/
+ //function(template, UiClass, items, options)
+
+ var self = this;
+
+ /**
+ * Static vars, don't change unless you know what you're doing.
+ */
+ var DOUBLE_TAP_RADIUS = 25,
+ NUM_HOLDERS = 3;
+
+ /**
+ * Options
+ */
+ var _options = {
+ allowPanToNext: true,
+ spacing: 0.12,
+ bgOpacity: 1,
+ mouseUsed: false,
+ loop: true,
+ pinchToClose: true,
+ closeOnScroll: true,
+ closeOnVerticalDrag: true,
+ verticalDragRange: 0.75,
+ hideAnimationDuration: 333,
+ showAnimationDuration: 333,
+ showHideOpacity: false,
+ focus: true,
+ escKey: true,
+ arrowKeys: true,
+ mainScrollEndFriction: 0.35,
+ panEndFriction: 0.35,
+ isClickableElement: function(el) {
+ return el.tagName === "A";
+ },
+ getDoubleTapZoom: function(isMouseClick, item) {
+ if (isMouseClick) {
+ return 1;
+ } else {
+ return item.initialZoomLevel < 0.7 ? 1 : 1.33;
+ }
+ },
+ maxSpreadZoom: 1.33,
+ modal: true,
+
+ // not fully implemented yet
+ scaleMode: "fit" // TODO
+ };
+ framework.extend(_options, options);
+
+ /**
+ * Private helper variables & functions
+ */
+
+ var _getEmptyPoint = function() {
+ return { x: 0, y: 0 };
+ };
+
+ var _isOpen,
+ _isDestroying,
+ _closedByScroll,
+ _currentItemIndex,
+ _containerStyle,
+ _containerShiftIndex,
+ _currPanDist = _getEmptyPoint(),
+ _startPanOffset = _getEmptyPoint(),
+ _panOffset = _getEmptyPoint(),
+ _upMoveEvents, // drag move, drag end & drag cancel events array
+ _downEvents, // drag start events array
+ _globalEventHandlers,
+ _viewportSize = {},
+ _currZoomLevel,
+ _startZoomLevel,
+ _translatePrefix,
+ _translateSufix,
+ _updateSizeInterval,
+ _itemsNeedUpdate,
+ _currPositionIndex = 0,
+ _offset = {},
+ _slideSize = _getEmptyPoint(), // size of slide area, including spacing
+ _itemHolders,
+ _prevItemIndex,
+ _indexDiff = 0, // difference of indexes since last content update
+ _dragStartEvent,
+ _dragMoveEvent,
+ _dragEndEvent,
+ _dragCancelEvent,
+ _transformKey,
+ _pointerEventEnabled,
+ _isFixedPosition = true,
+ _likelyTouchDevice,
+ _modules = [],
+ _requestAF,
+ _cancelAF,
+ _initalClassName,
+ _initalWindowScrollY,
+ _oldIE,
+ _currentWindowScrollY,
+ _features,
+ _windowVisibleSize = {},
+ _renderMaxResolution = false,
+ _orientationChangeTimeout,
+ // Registers PhotoSWipe module (History, Controller ...)
+ _registerModule = function(name, module) {
+ framework.extend(self, module.publicMethods);
+ _modules.push(name);
+ },
+ _getLoopedId = function(index) {
+ var numSlides = _getNumItems();
+ if (index > numSlides - 1) {
+ return index - numSlides;
+ } else if (index < 0) {
+ return numSlides + index;
+ }
+ return index;
+ },
+ // Micro bind/trigger
+ _listeners = {},
+ _listen = function(name, fn) {
+ if (!_listeners[name]) {
+ _listeners[name] = [];
+ }
+ return _listeners[name].push(fn);
+ },
+ _shout = function(name) {
+ var listeners = _listeners[name];
+
+ if (listeners) {
+ var args = Array.prototype.slice.call(arguments);
+ args.shift();
+
+ for (var i = 0; i < listeners.length; i++) {
+ listeners[i].apply(self, args);
+ }
+ }
+ },
+ _getCurrentTime = function() {
+ return new Date().getTime();
+ },
+ _applyBgOpacity = function(opacity) {
+ _bgOpacity = opacity;
+ self.bg.style.opacity = opacity * _options.bgOpacity;
+ },
+ _applyZoomTransform = function(styleObj, x, y, zoom, item) {
+ if (!_renderMaxResolution || (item && item !== self.currItem)) {
+ zoom = zoom / (item ? item.fitRatio : self.currItem.fitRatio);
+ }
+
+ styleObj[_transformKey] =
+ _translatePrefix +
+ x +
+ "px, " +
+ y +
+ "px" +
+ _translateSufix +
+ " scale(" +
+ zoom +
+ ")";
+ },
+ _applyCurrentZoomPan = function(allowRenderResolution) {
+ if (_currZoomElementStyle) {
+ if (allowRenderResolution) {
+ if (_currZoomLevel > self.currItem.fitRatio) {
+ if (!_renderMaxResolution) {
+ _setImageSize(self.currItem, false, true);
+ _renderMaxResolution = true;
+ }
+ } else {
+ if (_renderMaxResolution) {
+ _setImageSize(self.currItem);
+ _renderMaxResolution = false;
+ }
+ }
+ }
+
+ _applyZoomTransform(
+ _currZoomElementStyle,
+ _panOffset.x,
+ _panOffset.y,
+ _currZoomLevel
+ );
+ }
+ },
+ _applyZoomPanToItem = function(item) {
+ if (item.container) {
+ _applyZoomTransform(
+ item.container.style,
+ item.initialPosition.x,
+ item.initialPosition.y,
+ item.initialZoomLevel,
+ item
+ );
+ }
+ },
+ _setTranslateX = function(x, elStyle) {
+ elStyle[_transformKey] =
+ _translatePrefix + x + "px, 0px" + _translateSufix;
+ },
+ _moveMainScroll = function(x, dragging) {
+ if (!_options.loop && dragging) {
+ var newSlideIndexOffset =
+ _currentItemIndex +
+ (_slideSize.x * _currPositionIndex - x) / _slideSize.x,
+ delta = Math.round(x - _mainScrollPos.x);
+
+ if (
+ (newSlideIndexOffset < 0 && delta > 0) ||
+ (newSlideIndexOffset >= _getNumItems() - 1 && delta < 0)
+ ) {
+ x = _mainScrollPos.x + delta * _options.mainScrollEndFriction;
+ }
+ }
+
+ _mainScrollPos.x = x;
+ _setTranslateX(x, _containerStyle);
+ },
+ _calculatePanOffset = function(axis, zoomLevel) {
+ var m = _midZoomPoint[axis] - _offset[axis];
+ return (
+ _startPanOffset[axis] +
+ _currPanDist[axis] +
+ m -
+ m * (zoomLevel / _startZoomLevel)
+ );
+ },
+ _equalizePoints = function(p1, p2) {
+ p1.x = p2.x;
+ p1.y = p2.y;
+ if (p2.id) {
+ p1.id = p2.id;
+ }
+ },
+ _roundPoint = function(p) {
+ p.x = Math.round(p.x);
+ p.y = Math.round(p.y);
+ },
+ _mouseMoveTimeout = null,
+ _onFirstMouseMove = function() {
+ // Wait until mouse move event is fired at least twice during 100ms
+ // We do this, because some mobile browsers trigger it on touchstart
+ if (_mouseMoveTimeout) {
+ framework.unbind(document, "mousemove", _onFirstMouseMove);
+ framework.addClass(template, "pswp--has_mouse");
+ _options.mouseUsed = true;
+ _shout("mouseUsed");
+ }
+ _mouseMoveTimeout = setTimeout(function() {
+ _mouseMoveTimeout = null;
+ }, 100);
+ },
+ _bindEvents = function() {
+ framework.bind(document, "keydown", self);
+
+ if (_features.transform) {
+ // don't bind click event in browsers that don't support transform (mostly IE8)
+ framework.bind(self.scrollWrap, "click", self);
+ }
+
+ if (!_options.mouseUsed) {
+ framework.bind(document, "mousemove", _onFirstMouseMove);
+ }
+
+ framework.bind(window, "resize scroll orientationchange", self);
+
+ _shout("bindEvents");
+ },
+ _unbindEvents = function() {
+ framework.unbind(window, "resize scroll orientationchange", self);
+ framework.unbind(window, "scroll", _globalEventHandlers.scroll);
+ framework.unbind(document, "keydown", self);
+ framework.unbind(document, "mousemove", _onFirstMouseMove);
+
+ if (_features.transform) {
+ framework.unbind(self.scrollWrap, "click", self);
+ }
+
+ if (_isDragging) {
+ framework.unbind(window, _upMoveEvents, self);
+ }
+
+ clearTimeout(_orientationChangeTimeout);
+
+ _shout("unbindEvents");
+ },
+ _calculatePanBounds = function(zoomLevel, update) {
+ var bounds = _calculateItemSize(
+ self.currItem,
+ _viewportSize,
+ zoomLevel
+ );
+ if (update) {
+ _currPanBounds = bounds;
+ }
+ return bounds;
+ },
+ _getMinZoomLevel = function(item) {
+ if (!item) {
+ item = self.currItem;
+ }
+ return item.initialZoomLevel;
+ },
+ _getMaxZoomLevel = function(item) {
+ if (!item) {
+ item = self.currItem;
+ }
+ return item.w > 0 ? _options.maxSpreadZoom : 1;
+ },
+ // Return true if offset is out of the bounds
+ _modifyDestPanOffset = function(
+ axis,
+ destPanBounds,
+ destPanOffset,
+ destZoomLevel
+ ) {
+ if (destZoomLevel === self.currItem.initialZoomLevel) {
+ destPanOffset[axis] = self.currItem.initialPosition[axis];
+ return true;
+ } else {
+ destPanOffset[axis] = _calculatePanOffset(axis, destZoomLevel);
+
+ if (destPanOffset[axis] > destPanBounds.min[axis]) {
+ destPanOffset[axis] = destPanBounds.min[axis];
+ return true;
+ } else if (destPanOffset[axis] < destPanBounds.max[axis]) {
+ destPanOffset[axis] = destPanBounds.max[axis];
+ return true;
+ }
+ }
+ return false;
+ },
+ _setupTransforms = function() {
+ if (_transformKey) {
+ // setup 3d transforms
+ var allow3dTransform = _features.perspective && !_likelyTouchDevice;
+ _translatePrefix = "translate" + (allow3dTransform ? "3d(" : "(");
+ _translateSufix = _features.perspective ? ", 0px)" : ")";
+ return;
+ }
+
+ // Override zoom/pan/move functions in case old browser is used (most likely IE)
+ // (so they use left/top/width/height, instead of CSS transform)
+
+ _transformKey = "left";
+ framework.addClass(template, "pswp--ie");
+
+ _setTranslateX = function(x, elStyle) {
+ elStyle.left = x + "px";
+ };
+ _applyZoomPanToItem = function(item) {
+ var zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
+ s = item.container.style,
+ w = zoomRatio * item.w,
+ h = zoomRatio * item.h;
+
+ s.width = w + "px";
+ s.height = h + "px";
+ s.left = item.initialPosition.x + "px";
+ s.top = item.initialPosition.y + "px";
+ };
+ _applyCurrentZoomPan = function() {
+ if (_currZoomElementStyle) {
+ var s = _currZoomElementStyle,
+ item = self.currItem,
+ zoomRatio = item.fitRatio > 1 ? 1 : item.fitRatio,
+ w = zoomRatio * item.w,
+ h = zoomRatio * item.h;
+
+ s.width = w + "px";
+ s.height = h + "px";
+
+ s.left = _panOffset.x + "px";
+ s.top = _panOffset.y + "px";
+ }
+ };
+ },
+ _onKeyDown = function(e) {
+ var keydownAction = "";
+ if (_options.escKey && e.keyCode === 27) {
+ keydownAction = "close";
+ } else if (_options.arrowKeys) {
+ if (e.keyCode === 37) {
+ keydownAction = "prev";
+ } else if (e.keyCode === 39) {
+ keydownAction = "next";
+ }
+ }
+
+ if (keydownAction) {
+ // don't do anything if special key pressed to prevent from overriding default browser actions
+ // e.g. in Chrome on Mac cmd+arrow-left returns to previous page
+ if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ self[keydownAction]();
+ }
+ }
+ },
+ _onGlobalClick = function(e) {
+ if (!e) {
+ return;
+ }
+
+ // don't allow click event to pass through when triggering after drag or some other gesture
+ if (
+ _moved ||
+ _zoomStarted ||
+ _mainScrollAnimating ||
+ _verticalDragInitiated
+ ) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ },
+ _updatePageScrollOffset = function() {
+ self.setScrollOffset(0, framework.getScrollY());
+ };
+
+ // Micro animation engine
+ var _animations = {},
+ _numAnimations = 0,
+ _stopAnimation = function(name) {
+ if (_animations[name]) {
+ if (_animations[name].raf) {
+ _cancelAF(_animations[name].raf);
+ }
+ _numAnimations--;
+ delete _animations[name];
+ }
+ },
+ _registerStartAnimation = function(name) {
+ if (_animations[name]) {
+ _stopAnimation(name);
+ }
+ if (!_animations[name]) {
+ _numAnimations++;
+ _animations[name] = {};
+ }
+ },
+ _stopAllAnimations = function() {
+ for (var prop in _animations) {
+ if (_animations.hasOwnProperty(prop)) {
+ _stopAnimation(prop);
+ }
+ }
+ },
+ _animateProp = function(
+ name,
+ b,
+ endProp,
+ d,
+ easingFn,
+ onUpdate,
+ onComplete
+ ) {
+ var startAnimTime = _getCurrentTime(),
+ t;
+ _registerStartAnimation(name);
+
+ var animloop = function() {
+ if (_animations[name]) {
+ t = _getCurrentTime() - startAnimTime; // time diff
+ //b - beginning (start prop)
+ //d - anim duration
+
+ if (t >= d) {
+ _stopAnimation(name);
+ onUpdate(endProp);
+ if (onComplete) {
+ onComplete();
+ }
+ return;
+ }
+ onUpdate((endProp - b) * easingFn(t / d) + b);
+
+ _animations[name].raf = _requestAF(animloop);
+ }
+ };
+ animloop();
+ };
+
+ var publicMethods = {
+ // make a few local variables and functions public
+ shout: _shout,
+ listen: _listen,
+ viewportSize: _viewportSize,
+ options: _options,
+
+ isMainScrollAnimating: function() {
+ return _mainScrollAnimating;
+ },
+ getZoomLevel: function() {
+ return _currZoomLevel;
+ },
+ getCurrentIndex: function() {
+ return _currentItemIndex;
+ },
+ isDragging: function() {
+ return _isDragging;
+ },
+ isZooming: function() {
+ return _isZooming;
+ },
+ setScrollOffset: function(x, y) {
+ _offset.x = x;
+ _currentWindowScrollY = _offset.y = y;
+ _shout("updateScrollOffset", _offset);
+ },
+ applyZoomPan: function(zoomLevel, panX, panY, allowRenderResolution) {
+ _panOffset.x = panX;
+ _panOffset.y = panY;
+ _currZoomLevel = zoomLevel;
+ _applyCurrentZoomPan(allowRenderResolution);
+ },
+
+ init: function() {
+ if (_isOpen || _isDestroying) {
+ return;
+ }
+
+ var i;
+
+ self.framework = framework; // basic functionality
+ self.template = template; // root DOM element of PhotoSwipe
+ self.bg = framework.getChildByClass(template, "pswp__bg");
+
+ _initalClassName = template.className;
+ _isOpen = true;
+
+ _features = framework.detectFeatures();
+ _requestAF = _features.raf;
+ _cancelAF = _features.caf;
+ _transformKey = _features.transform;
+ _oldIE = _features.oldIE;
+
+ self.scrollWrap = framework.getChildByClass(
+ template,
+ "pswp__scroll-wrap"
+ );
+ self.container = framework.getChildByClass(
+ self.scrollWrap,
+ "pswp__container"
+ );
+
+ _containerStyle = self.container.style; // for fast access
+
+ // Objects that hold slides (there are only 3 in DOM)
+ self.itemHolders = _itemHolders = [
+ { el: self.container.children[0], wrap: 0, index: -1 },
+ { el: self.container.children[1], wrap: 0, index: -1 },
+ { el: self.container.children[2], wrap: 0, index: -1 }
+ ];
+
+ // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)
+ _itemHolders[0].el.style.display = _itemHolders[2].el.style.display =
+ "none";
+
+ _setupTransforms();
+
+ // Setup global events
+ _globalEventHandlers = {
+ resize: self.updateSize,
+
+ // Fixes: iOS 10.3 resize event
+ // does not update scrollWrap.clientWidth instantly after resize
+ // https://github.com/dimsemenov/PhotoSwipe/issues/1315
+ orientationchange: function() {
+ clearTimeout(_orientationChangeTimeout);
+ _orientationChangeTimeout = setTimeout(function() {
+ if (_viewportSize.x !== self.scrollWrap.clientWidth) {
+ self.updateSize();
+ }
+ }, 500);
+ },
+ scroll: _updatePageScrollOffset,
+ keydown: _onKeyDown,
+ click: _onGlobalClick
+ };
+
+ // disable show/hide effects on old browsers that don't support CSS animations or transforms,
+ // old IOS, Android and Opera mobile. Blackberry seems to work fine, even older models.
+ var oldPhone =
+ _features.isOldIOSPhone ||
+ _features.isOldAndroid ||
+ _features.isMobileOpera;
+ if (!_features.animationName || !_features.transform || oldPhone) {
+ _options.showAnimationDuration = _options.hideAnimationDuration = 0;
+ }
+
+ // init modules
+ for (i = 0; i < _modules.length; i++) {
+ self["init" + _modules[i]]();
+ }
+
+ // init
+ if (UiClass) {
+ var ui = (self.ui = new UiClass(self, framework));
+ ui.init();
+ }
+
+ _shout("firstUpdate");
+ _currentItemIndex = _currentItemIndex || _options.index || 0;
+ // validate index
+ if (
+ isNaN(_currentItemIndex) ||
+ _currentItemIndex < 0 ||
+ _currentItemIndex >= _getNumItems()
+ ) {
+ _currentItemIndex = 0;
+ }
+ self.currItem = _getItemAt(_currentItemIndex);
+
+ if (_features.isOldIOSPhone || _features.isOldAndroid) {
+ _isFixedPosition = false;
+ }
+
+ template.setAttribute("aria-hidden", "false");
+ if (_options.modal) {
+ if (!_isFixedPosition) {
+ template.style.position = "absolute";
+ template.style.top = framework.getScrollY() + "px";
+ } else {
+ template.style.position = "fixed";
+ }
+ }
+
+ if (_currentWindowScrollY === undefined) {
+ _shout("initialLayout");
+ _currentWindowScrollY = _initalWindowScrollY = framework.getScrollY();
+ }
+
+ // add classes to root element of PhotoSwipe
+ var rootClasses = "pswp--open ";
+ if (_options.mainClass) {
+ rootClasses += _options.mainClass + " ";
+ }
+ if (_options.showHideOpacity) {
+ rootClasses += "pswp--animate_opacity ";
+ }
+ rootClasses += _likelyTouchDevice ? "pswp--touch" : "pswp--notouch";
+ rootClasses += _features.animationName ? " pswp--css_animation" : "";
+ rootClasses += _features.svg ? " pswp--svg" : "";
+ framework.addClass(template, rootClasses);
+
+ self.updateSize();
+
+ // initial update
+ _containerShiftIndex = -1;
+ _indexDiff = null;
+ for (i = 0; i < NUM_HOLDERS; i++) {
+ _setTranslateX(
+ (i + _containerShiftIndex) * _slideSize.x,
+ _itemHolders[i].el.style
+ );
+ }
+
+ if (!_oldIE) {
+ framework.bind(self.scrollWrap, _downEvents, self); // no dragging for old IE
+ }
+
+ _listen("initialZoomInEnd", function() {
+ self.setContent(_itemHolders[0], _currentItemIndex - 1);
+ self.setContent(_itemHolders[2], _currentItemIndex + 1);
+
+ _itemHolders[0].el.style.display = _itemHolders[2].el.style.display =
+ "block";
+
+ if (_options.focus) {
+ // focus causes layout,
+ // which causes lag during the animation,
+ // that's why we delay it untill the initial zoom transition ends
+ template.focus();
+ }
+
+ _bindEvents();
+ });
+
+ // set content for center slide (first time)
+ self.setContent(_itemHolders[1], _currentItemIndex);
+
+ self.updateCurrItem();
+
+ _shout("afterInit");
+
+ if (!_isFixedPosition) {
+ // On all versions of iOS lower than 8.0, we check size of viewport every second.
+ //
+ // This is done to detect when Safari top & bottom bars appear,
+ // as this action doesn't trigger any events (like resize).
+ //
+ // On iOS8 they fixed this.
+ //
+ // 10 Nov 2014: iOS 7 usage ~40%. iOS 8 usage 56%.
+
+ _updateSizeInterval = setInterval(function() {
+ if (
+ !_numAnimations &&
+ !_isDragging &&
+ !_isZooming &&
+ _currZoomLevel === self.currItem.initialZoomLevel
+ ) {
+ self.updateSize();
+ }
+ }, 1000);
+ }
+
+ framework.addClass(template, "pswp--visible");
+ },
+
+ // Close the gallery, then destroy it
+ close: function() {
+ if (!_isOpen) {
+ return;
+ }
+
+ _isOpen = false;
+ _isDestroying = true;
+ _shout("close");
+ _unbindEvents();
+
+ _showOrHide(self.currItem, null, true, self.destroy);
+ },
+
+ // destroys the gallery (unbinds events, cleans up intervals and timeouts to avoid memory leaks)
+ destroy: function() {
+ _shout("destroy");
+
+ if (_showOrHideTimeout) {
+ clearTimeout(_showOrHideTimeout);
+ }
+
+ template.setAttribute("aria-hidden", "true");
+ template.className = _initalClassName;
+
+ if (_updateSizeInterval) {
+ clearInterval(_updateSizeInterval);
+ }
+
+ framework.unbind(self.scrollWrap, _downEvents, self);
+
+ // we unbind scroll event at the end, as closing animation may depend on it
+ framework.unbind(window, "scroll", self);
+
+ _stopDragUpdateLoop();
+
+ _stopAllAnimations();
+
+ _listeners = null;
+ },
+
+ /**
+ * Pan image to position
+ * @param {Number} x
+ * @param {Number} y
+ * @param {Boolean} force Will ignore bounds if set to true.
+ */
+ panTo: function(x, y, force) {
+ if (!force) {
+ if (x > _currPanBounds.min.x) {
+ x = _currPanBounds.min.x;
+ } else if (x < _currPanBounds.max.x) {
+ x = _currPanBounds.max.x;
+ }
+
+ if (y > _currPanBounds.min.y) {
+ y = _currPanBounds.min.y;
+ } else if (y < _currPanBounds.max.y) {
+ y = _currPanBounds.max.y;
+ }
+ }
+
+ _panOffset.x = x;
+ _panOffset.y = y;
+ _applyCurrentZoomPan();
+ },
+
+ handleEvent: function(e) {
+ e = e || window.event;
+ if (_globalEventHandlers[e.type]) {
+ _globalEventHandlers[e.type](e);
+ }
+ },
+
+ goTo: function(index) {
+ index = _getLoopedId(index);
+
+ var diff = index - _currentItemIndex;
+ _indexDiff = diff;
+
+ _currentItemIndex = index;
+ self.currItem = _getItemAt(_currentItemIndex);
+ _currPositionIndex -= diff;
+
+ _moveMainScroll(_slideSize.x * _currPositionIndex);
+
+ _stopAllAnimations();
+ _mainScrollAnimating = false;
+
+ self.updateCurrItem();
+ },
+ next: function() {
+ self.goTo(_currentItemIndex + 1);
+ },
+ prev: function() {
+ self.goTo(_currentItemIndex - 1);
+ },
+
+ // update current zoom/pan objects
+ updateCurrZoomItem: function(emulateSetContent) {
+ if (emulateSetContent) {
+ _shout("beforeChange", 0);
+ }
+
+ // itemHolder[1] is middle (current) item
+ if (_itemHolders[1].el.children.length) {
+ var zoomElement = _itemHolders[1].el.children[0];
+ if (framework.hasClass(zoomElement, "pswp__zoom-wrap")) {
+ _currZoomElementStyle = zoomElement.style;
+ } else {
+ _currZoomElementStyle = null;
+ }
+ } else {
+ _currZoomElementStyle = null;
+ }
+
+ _currPanBounds = self.currItem.bounds;
+ _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
+
+ _panOffset.x = _currPanBounds.center.x;
+ _panOffset.y = _currPanBounds.center.y;
+
+ if (emulateSetContent) {
+ _shout("afterChange");
+ }
+ },
+
+ invalidateCurrItems: function() {
+ _itemsNeedUpdate = true;
+ for (var i = 0; i < NUM_HOLDERS; i++) {
+ if (_itemHolders[i].item) {
+ _itemHolders[i].item.needsUpdate = true;
+ }
+ }
+ },
+
+ updateCurrItem: function(beforeAnimation) {
+ if (_indexDiff === 0) {
+ return;
+ }
+
+ var diffAbs = Math.abs(_indexDiff),
+ tempHolder;
+
+ if (beforeAnimation && diffAbs < 2) {
+ return;
+ }
+
+ self.currItem = _getItemAt(_currentItemIndex);
+ _renderMaxResolution = false;
+
+ _shout("beforeChange", _indexDiff);
+
+ if (diffAbs >= NUM_HOLDERS) {
+ _containerShiftIndex +=
+ _indexDiff + (_indexDiff > 0 ? -NUM_HOLDERS : NUM_HOLDERS);
+ diffAbs = NUM_HOLDERS;
+ }
+ for (var i = 0; i < diffAbs; i++) {
+ if (_indexDiff > 0) {
+ tempHolder = _itemHolders.shift();
+ _itemHolders[NUM_HOLDERS - 1] = tempHolder; // move first to last
+
+ _containerShiftIndex++;
+ _setTranslateX(
+ (_containerShiftIndex + 2) * _slideSize.x,
+ tempHolder.el.style
+ );
+ self.setContent(
+ tempHolder,
+ _currentItemIndex - diffAbs + i + 1 + 1
+ );
+ } else {
+ tempHolder = _itemHolders.pop();
+ _itemHolders.unshift(tempHolder); // move last to first
+
+ _containerShiftIndex--;
+ _setTranslateX(
+ _containerShiftIndex * _slideSize.x,
+ tempHolder.el.style
+ );
+ self.setContent(
+ tempHolder,
+ _currentItemIndex + diffAbs - i - 1 - 1
+ );
+ }
+ }
+
+ // reset zoom/pan on previous item
+ if (_currZoomElementStyle && Math.abs(_indexDiff) === 1) {
+ var prevItem = _getItemAt(_prevItemIndex);
+ if (prevItem.initialZoomLevel !== _currZoomLevel) {
+ _calculateItemSize(prevItem, _viewportSize);
+ _setImageSize(prevItem);
+ _applyZoomPanToItem(prevItem);
+ }
+ }
+
+ // reset diff after update
+ _indexDiff = 0;
+
+ self.updateCurrZoomItem();
+
+ _prevItemIndex = _currentItemIndex;
+
+ _shout("afterChange");
+ },
+
+ updateSize: function(force) {
+ if (!_isFixedPosition && _options.modal) {
+ var windowScrollY = framework.getScrollY();
+ if (_currentWindowScrollY !== windowScrollY) {
+ template.style.top = windowScrollY + "px";
+ _currentWindowScrollY = windowScrollY;
+ }
+ if (
+ !force &&
+ _windowVisibleSize.x === window.innerWidth &&
+ _windowVisibleSize.y === window.innerHeight
+ ) {
+ return;
+ }
+ _windowVisibleSize.x = window.innerWidth;
+ _windowVisibleSize.y = window.innerHeight;
+
+ //template.style.width = _windowVisibleSize.x + 'px';
+ template.style.height = _windowVisibleSize.y + "px";
+ }
+
+ _viewportSize.x = self.scrollWrap.clientWidth;
+ _viewportSize.y = self.scrollWrap.clientHeight;
+
+ _updatePageScrollOffset();
+
+ _slideSize.x =
+ _viewportSize.x + Math.round(_viewportSize.x * _options.spacing);
+ _slideSize.y = _viewportSize.y;
+
+ _moveMainScroll(_slideSize.x * _currPositionIndex);
+
+ _shout("beforeResize"); // even may be used for example to switch image sources
+
+ // don't re-calculate size on inital size update
+ if (_containerShiftIndex !== undefined) {
+ var holder, item, hIndex;
+
+ for (var i = 0; i < NUM_HOLDERS; i++) {
+ holder = _itemHolders[i];
+ _setTranslateX(
+ (i + _containerShiftIndex) * _slideSize.x,
+ holder.el.style
+ );
+
+ hIndex = _currentItemIndex + i - 1;
+
+ if (_options.loop && _getNumItems() > 2) {
+ hIndex = _getLoopedId(hIndex);
+ }
+
+ // update zoom level on items and refresh source (if needsUpdate)
+ item = _getItemAt(hIndex);
+
+ // re-render gallery item if `needsUpdate`,
+ // or doesn't have `bounds` (entirely new slide object)
+ if (
+ item &&
+ (_itemsNeedUpdate || item.needsUpdate || !item.bounds)
+ ) {
+ self.cleanSlide(item);
+
+ self.setContent(holder, hIndex);
+
+ // if "center" slide
+ if (i === 1) {
+ self.currItem = item;
+ self.updateCurrZoomItem(true);
+ }
+
+ item.needsUpdate = false;
+ } else if (holder.index === -1 && hIndex >= 0) {
+ // add content first time
+ self.setContent(holder, hIndex);
+ }
+ if (item && item.container) {
+ _calculateItemSize(item, _viewportSize);
+ _setImageSize(item);
+ _applyZoomPanToItem(item);
+ }
+ }
+ _itemsNeedUpdate = false;
+ }
+
+ _startZoomLevel = _currZoomLevel = self.currItem.initialZoomLevel;
+ _currPanBounds = self.currItem.bounds;
+
+ if (_currPanBounds) {
+ _panOffset.x = _currPanBounds.center.x;
+ _panOffset.y = _currPanBounds.center.y;
+ _applyCurrentZoomPan(true);
+ }
+
+ _shout("resize");
+ },
+
+ // Zoom current item to
+ zoomTo: function(destZoomLevel, centerPoint, speed, easingFn, updateFn) {
+ /*
+ if(destZoomLevel === 'fit') {
+ destZoomLevel = self.currItem.fitRatio;
+ } else if(destZoomLevel === 'fill') {
+ destZoomLevel = self.currItem.fillRatio;
+ }
+ */
+
+ if (centerPoint) {
+ _startZoomLevel = _currZoomLevel;
+ _midZoomPoint.x = Math.abs(centerPoint.x) - _panOffset.x;
+ _midZoomPoint.y = Math.abs(centerPoint.y) - _panOffset.y;
+ _equalizePoints(_startPanOffset, _panOffset);
+ }
+
+ var destPanBounds = _calculatePanBounds(destZoomLevel, false),
+ destPanOffset = {};
+
+ _modifyDestPanOffset("x", destPanBounds, destPanOffset, destZoomLevel);
+ _modifyDestPanOffset("y", destPanBounds, destPanOffset, destZoomLevel);
+
+ var initialZoomLevel = _currZoomLevel;
+ var initialPanOffset = {
+ x: _panOffset.x,
+ y: _panOffset.y
+ };
+
+ _roundPoint(destPanOffset);
+
+ var onUpdate = function(now) {
+ if (now === 1) {
+ _currZoomLevel = destZoomLevel;
+ _panOffset.x = destPanOffset.x;
+ _panOffset.y = destPanOffset.y;
+ } else {
+ _currZoomLevel =
+ (destZoomLevel - initialZoomLevel) * now + initialZoomLevel;
+ _panOffset.x =
+ (destPanOffset.x - initialPanOffset.x) * now + initialPanOffset.x;
+ _panOffset.y =
+ (destPanOffset.y - initialPanOffset.y) * now + initialPanOffset.y;
+ }
+
+ if (updateFn) {
+ updateFn(now);
+ }
+
+ _applyCurrentZoomPan(now === 1);
+ };
+
+ if (speed) {
+ _animateProp(
+ "customZoomTo",
+ 0,
+ 1,
+ speed,
+ easingFn || framework.easing.sine.inOut,
+ onUpdate
+ );
+ } else {
+ onUpdate(1);
+ }
+ }
+ };
+
+ /*>>core*/
+
+ /*>>gestures*/
+ /**
+ * Mouse/touch/pointer event handlers.
+ *
+ * separated from @core.js for readability
+ */
+
+ var MIN_SWIPE_DISTANCE = 30,
+ DIRECTION_CHECK_OFFSET = 10; // amount of pixels to drag to determine direction of swipe
+
+ var _gestureStartTime,
+ _gestureCheckSpeedTime,
+ // pool of objects that are used during dragging of zooming
+ p = {}, // first point
+ p2 = {}, // second point (for zoom gesture)
+ delta = {},
+ _currPoint = {},
+ _startPoint = {},
+ _currPointers = [],
+ _startMainScrollPos = {},
+ _releaseAnimData,
+ _posPoints = [], // array of points during dragging, used to determine type of gesture
+ _tempPoint = {},
+ _isZoomingIn,
+ _verticalDragInitiated,
+ _oldAndroidTouchEndTimeout,
+ _currZoomedItemIndex = 0,
+ _centerPoint = _getEmptyPoint(),
+ _lastReleaseTime = 0,
+ _isDragging, // at least one pointer is down
+ _isMultitouch, // at least two _pointers are down
+ _zoomStarted, // zoom level changed during zoom gesture
+ _moved,
+ _dragAnimFrame,
+ _mainScrollShifted,
+ _currentPoints, // array of current touch points
+ _isZooming,
+ _currPointsDistance,
+ _startPointsDistance,
+ _currPanBounds,
+ _mainScrollPos = _getEmptyPoint(),
+ _currZoomElementStyle,
+ _mainScrollAnimating, // true, if animation after swipe gesture is running
+ _midZoomPoint = _getEmptyPoint(),
+ _currCenterPoint = _getEmptyPoint(),
+ _direction,
+ _isFirstMove,
+ _opacityChanged,
+ _bgOpacity,
+ _wasOverInitialZoom,
+ _isEqualPoints = function(p1, p2) {
+ return p1.x === p2.x && p1.y === p2.y;
+ },
+ _isNearbyPoints = function(touch0, touch1) {
+ return (
+ Math.abs(touch0.x - touch1.x) < DOUBLE_TAP_RADIUS &&
+ Math.abs(touch0.y - touch1.y) < DOUBLE_TAP_RADIUS
+ );
+ },
+ _calculatePointsDistance = function(p1, p2) {
+ _tempPoint.x = Math.abs(p1.x - p2.x);
+ _tempPoint.y = Math.abs(p1.y - p2.y);
+ return Math.sqrt(
+ _tempPoint.x * _tempPoint.x + _tempPoint.y * _tempPoint.y
+ );
+ },
+ _stopDragUpdateLoop = function() {
+ if (_dragAnimFrame) {
+ _cancelAF(_dragAnimFrame);
+ _dragAnimFrame = null;
+ }
+ },
+ _dragUpdateLoop = function() {
+ if (_isDragging) {
+ _dragAnimFrame = _requestAF(_dragUpdateLoop);
+ _renderMovement();
+ }
+ },
+ _canPan = function() {
+ return !(
+ _options.scaleMode === "fit" &&
+ _currZoomLevel === self.currItem.initialZoomLevel
+ );
+ },
+ // find the closest parent DOM element
+ _closestElement = function(el, fn) {
+ if (!el || el === document) {
+ return false;
+ }
+
+ // don't search elements above pswp__scroll-wrap
+ if (
+ el.getAttribute("class") &&
+ el.getAttribute("class").indexOf("pswp__scroll-wrap") > -1
+ ) {
+ return false;
+ }
+
+ if (fn(el)) {
+ return el;
+ }
+
+ return _closestElement(el.parentNode, fn);
+ },
+ _preventObj = {},
+ _preventDefaultEventBehaviour = function(e, isDown) {
+ _preventObj.prevent = !_closestElement(
+ e.target,
+ _options.isClickableElement
+ );
+
+ _shout("preventDragEvent", e, isDown, _preventObj);
+ return _preventObj.prevent;
+ },
+ _convertTouchToPoint = function(touch, p) {
+ p.x = touch.pageX;
+ p.y = touch.pageY;
+ p.id = touch.identifier;
+ return p;
+ },
+ _findCenterOfPoints = function(p1, p2, pCenter) {
+ pCenter.x = (p1.x + p2.x) * 0.5;
+ pCenter.y = (p1.y + p2.y) * 0.5;
+ },
+ _pushPosPoint = function(time, x, y) {
+ if (time - _gestureCheckSpeedTime > 50) {
+ var o = _posPoints.length > 2 ? _posPoints.shift() : {};
+ o.x = x;
+ o.y = y;
+ _posPoints.push(o);
+ _gestureCheckSpeedTime = time;
+ }
+ },
+ _calculateVerticalDragOpacityRatio = function() {
+ var yOffset = _panOffset.y - self.currItem.initialPosition.y; // difference between initial and current position
+ return 1 - Math.abs(yOffset / (_viewportSize.y / 2));
+ },
+ // points pool, reused during touch events
+ _ePoint1 = {},
+ _ePoint2 = {},
+ _tempPointsArr = [],
+ _tempCounter,
+ _getTouchPoints = function(e) {
+ // clean up previous points, without recreating array
+ while (_tempPointsArr.length > 0) {
+ _tempPointsArr.pop();
+ }
+
+ if (!_pointerEventEnabled) {
+ if (e.type.indexOf("touch") > -1) {
+ if (e.touches && e.touches.length > 0) {
+ _tempPointsArr[0] = _convertTouchToPoint(e.touches[0], _ePoint1);
+ if (e.touches.length > 1) {
+ _tempPointsArr[1] = _convertTouchToPoint(
+ e.touches[1],
+ _ePoint2
+ );
+ }
+ }
+ } else {
+ _ePoint1.x = e.pageX;
+ _ePoint1.y = e.pageY;
+ _ePoint1.id = "";
+ _tempPointsArr[0] = _ePoint1; //_ePoint1;
+ }
+ } else {
+ _tempCounter = 0;
+ // we can use forEach, as pointer events are supported only in modern browsers
+ _currPointers.forEach(function(p) {
+ if (_tempCounter === 0) {
+ _tempPointsArr[0] = p;
+ } else if (_tempCounter === 1) {
+ _tempPointsArr[1] = p;
+ }
+ _tempCounter++;
+ });
+ }
+ return _tempPointsArr;
+ },
+ _panOrMoveMainScroll = function(axis, delta) {
+ var panFriction,
+ overDiff = 0,
+ newOffset = _panOffset[axis] + delta[axis],
+ startOverDiff,
+ dir = delta[axis] > 0,
+ newMainScrollPosition = _mainScrollPos.x + delta.x,
+ mainScrollDiff = _mainScrollPos.x - _startMainScrollPos.x,
+ newPanPos,
+ newMainScrollPos;
+
+ // calculate fdistance over the bounds and friction
+ if (
+ newOffset > _currPanBounds.min[axis] ||
+ newOffset < _currPanBounds.max[axis]
+ ) {
+ panFriction = _options.panEndFriction;
+ // Linear increasing of friction, so at 1/4 of viewport it's at max value.
+ // Looks not as nice as was expected. Left for history.
+ // panFriction = (1 - (_panOffset[axis] + delta[axis] + panBounds.min[axis]) / (_viewportSize[axis] / 4) );
+ } else {
+ panFriction = 1;
+ }
+
+ newOffset = _panOffset[axis] + delta[axis] * panFriction;
+
+ // move main scroll or start panning
+ if (
+ _options.allowPanToNext ||
+ _currZoomLevel === self.currItem.initialZoomLevel
+ ) {
+ if (!_currZoomElementStyle) {
+ newMainScrollPos = newMainScrollPosition;
+ } else if (_direction === "h" && axis === "x" && !_zoomStarted) {
+ if (dir) {
+ if (newOffset > _currPanBounds.min[axis]) {
+ panFriction = _options.panEndFriction;
+ overDiff = _currPanBounds.min[axis] - newOffset;
+ startOverDiff =
+ _currPanBounds.min[axis] - _startPanOffset[axis];
+ }
+
+ // drag right
+ if (
+ (startOverDiff <= 0 || mainScrollDiff < 0) &&
+ _getNumItems() > 1
+ ) {
+ newMainScrollPos = newMainScrollPosition;
+ if (
+ mainScrollDiff < 0 &&
+ newMainScrollPosition > _startMainScrollPos.x
+ ) {
+ newMainScrollPos = _startMainScrollPos.x;
+ }
+ } else {
+ if (_currPanBounds.min.x !== _currPanBounds.max.x) {
+ newPanPos = newOffset;
+ }
+ }
+ } else {
+ if (newOffset < _currPanBounds.max[axis]) {
+ panFriction = _options.panEndFriction;
+ overDiff = newOffset - _currPanBounds.max[axis];
+ startOverDiff =
+ _startPanOffset[axis] - _currPanBounds.max[axis];
+ }
+
+ if (
+ (startOverDiff <= 0 || mainScrollDiff > 0) &&
+ _getNumItems() > 1
+ ) {
+ newMainScrollPos = newMainScrollPosition;
+
+ if (
+ mainScrollDiff > 0 &&
+ newMainScrollPosition < _startMainScrollPos.x
+ ) {
+ newMainScrollPos = _startMainScrollPos.x;
+ }
+ } else {
+ if (_currPanBounds.min.x !== _currPanBounds.max.x) {
+ newPanPos = newOffset;
+ }
+ }
+ }
+
+ //
+ }
+
+ if (axis === "x") {
+ if (newMainScrollPos !== undefined) {
+ _moveMainScroll(newMainScrollPos, true);
+ if (newMainScrollPos === _startMainScrollPos.x) {
+ _mainScrollShifted = false;
+ } else {
+ _mainScrollShifted = true;
+ }
+ }
+
+ if (_currPanBounds.min.x !== _currPanBounds.max.x) {
+ if (newPanPos !== undefined) {
+ _panOffset.x = newPanPos;
+ } else if (!_mainScrollShifted) {
+ _panOffset.x += delta.x * panFriction;
+ }
+ }
+
+ return newMainScrollPos !== undefined;
+ }
+ }
+
+ if (!_mainScrollAnimating) {
+ if (!_mainScrollShifted) {
+ if (_currZoomLevel > self.currItem.fitRatio) {
+ _panOffset[axis] += delta[axis] * panFriction;
+ }
+ }
+ }
+ },
+ // Pointerdown/touchstart/mousedown handler
+ _onDragStart = function(e) {
+ // Allow dragging only via left mouse button.
+ // As this handler is not added in IE8 - we ignore e.which
+ //
+ // http://www.quirksmode.org/js/events_properties.html
+ // https://developer.mozilla.org/en-US/docs/Web/API/event.button
+ if (e.type === "mousedown" && e.button > 0) {
+ return;
+ }
+
+ if (_initialZoomRunning) {
+ e.preventDefault();
+ return;
+ }
+
+ if (_oldAndroidTouchEndTimeout && e.type === "mousedown") {
+ return;
+ }
+
+ if (_preventDefaultEventBehaviour(e, true)) {
+ e.preventDefault();
+ }
+
+ _shout("pointerDown");
+
+ if (_pointerEventEnabled) {
+ var pointerIndex = framework.arraySearch(
+ _currPointers,
+ e.pointerId,
+ "id"
+ );
+ if (pointerIndex < 0) {
+ pointerIndex = _currPointers.length;
+ }
+ _currPointers[pointerIndex] = {
+ x: e.pageX,
+ y: e.pageY,
+ id: e.pointerId
+ };
+ }
+
+ var startPointsList = _getTouchPoints(e),
+ numPoints = startPointsList.length;
+
+ _currentPoints = null;
+
+ _stopAllAnimations();
+
+ // init drag
+ if (!_isDragging || numPoints === 1) {
+ _isDragging = _isFirstMove = true;
+ framework.bind(window, _upMoveEvents, self);
+
+ _isZoomingIn = _wasOverInitialZoom = _opacityChanged = _verticalDragInitiated = _mainScrollShifted = _moved = _isMultitouch = _zoomStarted = false;
+
+ _direction = null;
+
+ _shout("firstTouchStart", startPointsList);
+
+ _equalizePoints(_startPanOffset, _panOffset);
+
+ _currPanDist.x = _currPanDist.y = 0;
+ _equalizePoints(_currPoint, startPointsList[0]);
+ _equalizePoints(_startPoint, _currPoint);
+
+ //_equalizePoints(_startMainScrollPos, _mainScrollPos);
+ _startMainScrollPos.x = _slideSize.x * _currPositionIndex;
+
+ _posPoints = [
+ {
+ x: _currPoint.x,
+ y: _currPoint.y
+ }
+ ];
+
+ _gestureCheckSpeedTime = _gestureStartTime = _getCurrentTime();
+
+ //_mainScrollAnimationEnd(true);
+ _calculatePanBounds(_currZoomLevel, true);
+
+ // Start rendering
+ _stopDragUpdateLoop();
+ _dragUpdateLoop();
+ }
+
+ // init zoom
+ if (
+ !_isZooming &&
+ numPoints > 1 &&
+ !_mainScrollAnimating &&
+ !_mainScrollShifted
+ ) {
+ _startZoomLevel = _currZoomLevel;
+ _zoomStarted = false; // true if zoom changed at least once
+
+ _isZooming = _isMultitouch = true;
+ _currPanDist.y = _currPanDist.x = 0;
+
+ _equalizePoints(_startPanOffset, _panOffset);
+
+ _equalizePoints(p, startPointsList[0]);
+ _equalizePoints(p2, startPointsList[1]);
+
+ _findCenterOfPoints(p, p2, _currCenterPoint);
+
+ _midZoomPoint.x = Math.abs(_currCenterPoint.x) - _panOffset.x;
+ _midZoomPoint.y = Math.abs(_currCenterPoint.y) - _panOffset.y;
+ _currPointsDistance = _startPointsDistance = _calculatePointsDistance(
+ p,
+ p2
+ );
+ }
+ },
+ // Pointermove/touchmove/mousemove handler
+ _onDragMove = function(e) {
+ e.preventDefault();
+
+ if (_pointerEventEnabled) {
+ var pointerIndex = framework.arraySearch(
+ _currPointers,
+ e.pointerId,
+ "id"
+ );
+ if (pointerIndex > -1) {
+ var p = _currPointers[pointerIndex];
+ p.x = e.pageX;
+ p.y = e.pageY;
+ }
+ }
+
+ if (_isDragging) {
+ var touchesList = _getTouchPoints(e);
+ if (!_direction && !_moved && !_isZooming) {
+ if (_mainScrollPos.x !== _slideSize.x * _currPositionIndex) {
+ // if main scroll position is shifted – direction is always horizontal
+ _direction = "h";
+ } else {
+ var diff =
+ Math.abs(touchesList[0].x - _currPoint.x) -
+ Math.abs(touchesList[0].y - _currPoint.y);
+ // check the direction of movement
+ if (Math.abs(diff) >= DIRECTION_CHECK_OFFSET) {
+ _direction = diff > 0 ? "h" : "v";
+ _currentPoints = touchesList;
+ }
+ }
+ } else {
+ _currentPoints = touchesList;
+ }
+ }
+ },
+ //
+ _renderMovement = function() {
+ if (!_currentPoints) {
+ return;
+ }
+
+ var numPoints = _currentPoints.length;
+
+ if (numPoints === 0) {
+ return;
+ }
+
+ _equalizePoints(p, _currentPoints[0]);
+
+ delta.x = p.x - _currPoint.x;
+ delta.y = p.y - _currPoint.y;
+
+ if (_isZooming && numPoints > 1) {
+ // Handle behaviour for more than 1 point
+
+ _currPoint.x = p.x;
+ _currPoint.y = p.y;
+
+ // check if one of two points changed
+ if (!delta.x && !delta.y && _isEqualPoints(_currentPoints[1], p2)) {
+ return;
+ }
+
+ _equalizePoints(p2, _currentPoints[1]);
+
+ if (!_zoomStarted) {
+ _zoomStarted = true;
+ _shout("zoomGestureStarted");
+ }
+
+ // Distance between two points
+ var pointsDistance = _calculatePointsDistance(p, p2);
+
+ var zoomLevel = _calculateZoomLevel(pointsDistance);
+
+ // slightly over the of initial zoom level
+ if (
+ zoomLevel >
+ self.currItem.initialZoomLevel + self.currItem.initialZoomLevel / 15
+ ) {
+ _wasOverInitialZoom = true;
+ }
+
+ // Apply the friction if zoom level is out of the bounds
+ var zoomFriction = 1,
+ minZoomLevel = _getMinZoomLevel(),
+ maxZoomLevel = _getMaxZoomLevel();
+
+ if (zoomLevel < minZoomLevel) {
+ if (
+ _options.pinchToClose &&
+ !_wasOverInitialZoom &&
+ _startZoomLevel <= self.currItem.initialZoomLevel
+ ) {
+ // fade out background if zooming out
+ var minusDiff = minZoomLevel - zoomLevel;
+ var percent = 1 - minusDiff / (minZoomLevel / 1.2);
+
+ _applyBgOpacity(percent);
+ _shout("onPinchClose", percent);
+ _opacityChanged = true;
+ } else {
+ zoomFriction = (minZoomLevel - zoomLevel) / minZoomLevel;
+ if (zoomFriction > 1) {
+ zoomFriction = 1;
+ }
+ zoomLevel = minZoomLevel - zoomFriction * (minZoomLevel / 3);
+ }
+ } else if (zoomLevel > maxZoomLevel) {
+ // 1.5 - extra zoom level above the max. E.g. if max is x6, real max 6 + 1.5 = 7.5
+ zoomFriction = (zoomLevel - maxZoomLevel) / (minZoomLevel * 6);
+ if (zoomFriction > 1) {
+ zoomFriction = 1;
+ }
+ zoomLevel = maxZoomLevel + zoomFriction * minZoomLevel;
+ }
+
+ if (zoomFriction < 0) {
+ zoomFriction = 0;
+ }
+
+ // distance between touch points after friction is applied
+ _currPointsDistance = pointsDistance;
+
+ // _centerPoint - The point in the middle of two pointers
+ _findCenterOfPoints(p, p2, _centerPoint);
+
+ // paning with two pointers pressed
+ _currPanDist.x += _centerPoint.x - _currCenterPoint.x;
+ _currPanDist.y += _centerPoint.y - _currCenterPoint.y;
+ _equalizePoints(_currCenterPoint, _centerPoint);
+
+ _panOffset.x = _calculatePanOffset("x", zoomLevel);
+ _panOffset.y = _calculatePanOffset("y", zoomLevel);
+
+ _isZoomingIn = zoomLevel > _currZoomLevel;
+ _currZoomLevel = zoomLevel;
+ _applyCurrentZoomPan();
+ } else {
+ // handle behaviour for one point (dragging or panning)
+
+ if (!_direction) {
+ return;
+ }
+
+ if (_isFirstMove) {
+ _isFirstMove = false;
+
+ // subtract drag distance that was used during the detection direction
+
+ if (Math.abs(delta.x) >= DIRECTION_CHECK_OFFSET) {
+ delta.x -= _currentPoints[0].x - _startPoint.x;
+ }
+
+ if (Math.abs(delta.y) >= DIRECTION_CHECK_OFFSET) {
+ delta.y -= _currentPoints[0].y - _startPoint.y;
+ }
+ }
+
+ _currPoint.x = p.x;
+ _currPoint.y = p.y;
+
+ // do nothing if pointers position hasn't changed
+ if (delta.x === 0 && delta.y === 0) {
+ return;
+ }
+
+ if (_direction === "v" && _options.closeOnVerticalDrag) {
+ if (!_canPan()) {
+ _currPanDist.y += delta.y;
+ _panOffset.y += delta.y;
+
+ var opacityRatio = _calculateVerticalDragOpacityRatio();
+
+ _verticalDragInitiated = true;
+ _shout("onVerticalDrag", opacityRatio);
+
+ _applyBgOpacity(opacityRatio);
+ _applyCurrentZoomPan();
+ return;
+ }
+ }
+
+ _pushPosPoint(_getCurrentTime(), p.x, p.y);
+
+ _moved = true;
+ _currPanBounds = self.currItem.bounds;
+
+ var mainScrollChanged = _panOrMoveMainScroll("x", delta);
+ if (!mainScrollChanged) {
+ _panOrMoveMainScroll("y", delta);
+
+ _roundPoint(_panOffset);
+ _applyCurrentZoomPan();
+ }
+ }
+ },
+ // Pointerup/pointercancel/touchend/touchcancel/mouseup event handler
+ _onDragRelease = function(e) {
+ if (_features.isOldAndroid) {
+ if (_oldAndroidTouchEndTimeout && e.type === "mouseup") {
+ return;
+ }
+
+ // on Android (v4.1, 4.2, 4.3 & possibly older)
+ // ghost mousedown/up event isn't preventable via e.preventDefault,
+ // which causes fake mousedown event
+ // so we block mousedown/up for 600ms
+ if (e.type.indexOf("touch") > -1) {
+ clearTimeout(_oldAndroidTouchEndTimeout);
+ _oldAndroidTouchEndTimeout = setTimeout(function() {
+ _oldAndroidTouchEndTimeout = 0;
+ }, 600);
+ }
+ }
+
+ _shout("pointerUp");
+
+ if (_preventDefaultEventBehaviour(e, false)) {
+ e.preventDefault();
+ }
+
+ var releasePoint;
+
+ if (_pointerEventEnabled) {
+ var pointerIndex = framework.arraySearch(
+ _currPointers,
+ e.pointerId,
+ "id"
+ );
+
+ if (pointerIndex > -1) {
+ releasePoint = _currPointers.splice(pointerIndex, 1)[0];
+
+ if (navigator.msPointerEnabled) {
+ var MSPOINTER_TYPES = {
+ 4: "mouse", // event.MSPOINTER_TYPE_MOUSE
+ 2: "touch", // event.MSPOINTER_TYPE_TOUCH
+ 3: "pen" // event.MSPOINTER_TYPE_PEN
+ };
+ releasePoint.type = MSPOINTER_TYPES[e.pointerType];
+
+ if (!releasePoint.type) {
+ releasePoint.type = e.pointerType || "mouse";
+ }
+ } else {
+ releasePoint.type = e.pointerType || "mouse";
+ }
+ }
+ }
+
+ var touchList = _getTouchPoints(e),
+ gestureType,
+ numPoints = touchList.length;
+
+ if (e.type === "mouseup") {
+ numPoints = 0;
+ }
+
+ // Do nothing if there were 3 touch points or more
+ if (numPoints === 2) {
+ _currentPoints = null;
+ return true;
+ }
+
+ // if second pointer released
+ if (numPoints === 1) {
+ _equalizePoints(_startPoint, touchList[0]);
+ }
+
+ // pointer hasn't moved, send "tap release" point
+ if (numPoints === 0 && !_direction && !_mainScrollAnimating) {
+ if (!releasePoint) {
+ if (e.type === "mouseup") {
+ releasePoint = { x: e.pageX, y: e.pageY, type: "mouse" };
+ } else if (e.changedTouches && e.changedTouches[0]) {
+ releasePoint = {
+ x: e.changedTouches[0].pageX,
+ y: e.changedTouches[0].pageY,
+ type: "touch"
+ };
+ }
+ }
+
+ _shout("touchRelease", e, releasePoint);
+ }
+
+ // Difference in time between releasing of two last touch points (zoom gesture)
+ var releaseTimeDiff = -1;
+
+ // Gesture completed, no pointers left
+ if (numPoints === 0) {
+ _isDragging = false;
+ framework.unbind(window, _upMoveEvents, self);
+
+ _stopDragUpdateLoop();
+
+ if (_isZooming) {
+ // Two points released at the same time
+ releaseTimeDiff = 0;
+ } else if (_lastReleaseTime !== -1) {
+ releaseTimeDiff = _getCurrentTime() - _lastReleaseTime;
+ }
+ }
+ _lastReleaseTime = numPoints === 1 ? _getCurrentTime() : -1;
+
+ if (releaseTimeDiff !== -1 && releaseTimeDiff < 150) {
+ gestureType = "zoom";
+ } else {
+ gestureType = "swipe";
+ }
+
+ if (_isZooming && numPoints < 2) {
+ _isZooming = false;
+
+ // Only second point released
+ if (numPoints === 1) {
+ gestureType = "zoomPointerUp";
+ }
+ _shout("zoomGestureEnded");
+ }
+
+ _currentPoints = null;
+ if (
+ !_moved &&
+ !_zoomStarted &&
+ !_mainScrollAnimating &&
+ !_verticalDragInitiated
+ ) {
+ // nothing to animate
+ return;
+ }
+
+ _stopAllAnimations();
+
+ if (!_releaseAnimData) {
+ _releaseAnimData = _initDragReleaseAnimationData();
+ }
+
+ _releaseAnimData.calculateSwipeSpeed("x");
+
+ if (_verticalDragInitiated) {
+ var opacityRatio = _calculateVerticalDragOpacityRatio();
+
+ if (opacityRatio < _options.verticalDragRange) {
+ self.close();
+ } else {
+ var initalPanY = _panOffset.y,
+ initialBgOpacity = _bgOpacity;
+
+ _animateProp(
+ "verticalDrag",
+ 0,
+ 1,
+ 300,
+ framework.easing.cubic.out,
+ function(now) {
+ _panOffset.y =
+ (self.currItem.initialPosition.y - initalPanY) * now +
+ initalPanY;
+
+ _applyBgOpacity(
+ (1 - initialBgOpacity) * now + initialBgOpacity
+ );
+ _applyCurrentZoomPan();
+ }
+ );
+
+ _shout("onVerticalDrag", 1);
+ }
+
+ return;
+ }
+
+ // main scroll
+ if ((_mainScrollShifted || _mainScrollAnimating) && numPoints === 0) {
+ var itemChanged = _finishSwipeMainScrollGesture(
+ gestureType,
+ _releaseAnimData
+ );
+ if (itemChanged) {
+ return;
+ }
+ gestureType = "zoomPointerUp";
+ }
+
+ // prevent zoom/pan animation when main scroll animation runs
+ if (_mainScrollAnimating) {
+ return;
+ }
+
+ // Complete simple zoom gesture (reset zoom level if it's out of the bounds)
+ if (gestureType !== "swipe") {
+ _completeZoomGesture();
+ return;
+ }
+
+ // Complete pan gesture if main scroll is not shifted, and it's possible to pan current image
+ if (!_mainScrollShifted && _currZoomLevel > self.currItem.fitRatio) {
+ _completePanGesture(_releaseAnimData);
+ }
+ },
+ // Returns object with data about gesture
+ // It's created only once and then reused
+ _initDragReleaseAnimationData = function() {
+ // temp local vars
+ var lastFlickDuration, tempReleasePos;
+
+ // s = this
+ var s = {
+ lastFlickOffset: {},
+ lastFlickDist: {},
+ lastFlickSpeed: {},
+ slowDownRatio: {},
+ slowDownRatioReverse: {},
+ speedDecelerationRatio: {},
+ speedDecelerationRatioAbs: {},
+ distanceOffset: {},
+ backAnimDestination: {},
+ backAnimStarted: {},
+ calculateSwipeSpeed: function(axis) {
+ if (_posPoints.length > 1) {
+ lastFlickDuration =
+ _getCurrentTime() - _gestureCheckSpeedTime + 50;
+ tempReleasePos = _posPoints[_posPoints.length - 2][axis];
+ } else {
+ lastFlickDuration = _getCurrentTime() - _gestureStartTime; // total gesture duration
+ tempReleasePos = _startPoint[axis];
+ }
+ s.lastFlickOffset[axis] = _currPoint[axis] - tempReleasePos;
+ s.lastFlickDist[axis] = Math.abs(s.lastFlickOffset[axis]);
+ if (s.lastFlickDist[axis] > 20) {
+ s.lastFlickSpeed[axis] =
+ s.lastFlickOffset[axis] / lastFlickDuration;
+ } else {
+ s.lastFlickSpeed[axis] = 0;
+ }
+ if (Math.abs(s.lastFlickSpeed[axis]) < 0.1) {
+ s.lastFlickSpeed[axis] = 0;
+ }
+
+ s.slowDownRatio[axis] = 0.95;
+ s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
+ s.speedDecelerationRatio[axis] = 1;
+ },
+
+ calculateOverBoundsAnimOffset: function(axis, speed) {
+ if (!s.backAnimStarted[axis]) {
+ if (_panOffset[axis] > _currPanBounds.min[axis]) {
+ s.backAnimDestination[axis] = _currPanBounds.min[axis];
+ } else if (_panOffset[axis] < _currPanBounds.max[axis]) {
+ s.backAnimDestination[axis] = _currPanBounds.max[axis];
+ }
+
+ if (s.backAnimDestination[axis] !== undefined) {
+ s.slowDownRatio[axis] = 0.7;
+ s.slowDownRatioReverse[axis] = 1 - s.slowDownRatio[axis];
+ if (s.speedDecelerationRatioAbs[axis] < 0.05) {
+ s.lastFlickSpeed[axis] = 0;
+ s.backAnimStarted[axis] = true;
+
+ _animateProp(
+ "bounceZoomPan" + axis,
+ _panOffset[axis],
+ s.backAnimDestination[axis],
+ speed || 300,
+ framework.easing.sine.out,
+ function(pos) {
+ _panOffset[axis] = pos;
+ _applyCurrentZoomPan();
+ }
+ );
+ }
+ }
+ }
+ },
+
+ // Reduces the speed by slowDownRatio (per 10ms)
+ calculateAnimOffset: function(axis) {
+ if (!s.backAnimStarted[axis]) {
+ s.speedDecelerationRatio[axis] =
+ s.speedDecelerationRatio[axis] *
+ (s.slowDownRatio[axis] +
+ s.slowDownRatioReverse[axis] -
+ (s.slowDownRatioReverse[axis] * s.timeDiff) / 10);
+
+ s.speedDecelerationRatioAbs[axis] = Math.abs(
+ s.lastFlickSpeed[axis] * s.speedDecelerationRatio[axis]
+ );
+ s.distanceOffset[axis] =
+ s.lastFlickSpeed[axis] *
+ s.speedDecelerationRatio[axis] *
+ s.timeDiff;
+ _panOffset[axis] += s.distanceOffset[axis];
+ }
+ },
+
+ panAnimLoop: function() {
+ if (_animations.zoomPan) {
+ _animations.zoomPan.raf = _requestAF(s.panAnimLoop);
+
+ s.now = _getCurrentTime();
+ s.timeDiff = s.now - s.lastNow;
+ s.lastNow = s.now;
+
+ s.calculateAnimOffset("x");
+ s.calculateAnimOffset("y");
+
+ _applyCurrentZoomPan();
+
+ s.calculateOverBoundsAnimOffset("x");
+ s.calculateOverBoundsAnimOffset("y");
+
+ if (
+ s.speedDecelerationRatioAbs.x < 0.05 &&
+ s.speedDecelerationRatioAbs.y < 0.05
+ ) {
+ // round pan position
+ _panOffset.x = Math.round(_panOffset.x);
+ _panOffset.y = Math.round(_panOffset.y);
+ _applyCurrentZoomPan();
+
+ _stopAnimation("zoomPan");
+ return;
+ }
+ }
+ }
+ };
+ return s;
+ },
+ _completePanGesture = function(animData) {
+ // calculate swipe speed for Y axis (paanning)
+ animData.calculateSwipeSpeed("y");
+
+ _currPanBounds = self.currItem.bounds;
+
+ animData.backAnimDestination = {};
+ animData.backAnimStarted = {};
+
+ // Avoid acceleration animation if speed is too low
+ if (
+ Math.abs(animData.lastFlickSpeed.x) <= 0.05 &&
+ Math.abs(animData.lastFlickSpeed.y) <= 0.05
+ ) {
+ animData.speedDecelerationRatioAbs.x = animData.speedDecelerationRatioAbs.y = 0;
+
+ // Run pan drag release animation. E.g. if you drag image and release finger without momentum.
+ animData.calculateOverBoundsAnimOffset("x");
+ animData.calculateOverBoundsAnimOffset("y");
+ return true;
+ }
+
+ // Animation loop that controls the acceleration after pan gesture ends
+ _registerStartAnimation("zoomPan");
+ animData.lastNow = _getCurrentTime();
+ animData.panAnimLoop();
+ },
+ _finishSwipeMainScrollGesture = function(gestureType, _releaseAnimData) {
+ var itemChanged;
+ if (!_mainScrollAnimating) {
+ _currZoomedItemIndex = _currentItemIndex;
+ }
+
+ var itemsDiff;
+
+ if (gestureType === "swipe") {
+ var totalShiftDist = _currPoint.x - _startPoint.x,
+ isFastLastFlick = _releaseAnimData.lastFlickDist.x < 10;
+
+ // if container is shifted for more than MIN_SWIPE_DISTANCE,
+ // and last flick gesture was in right direction
+ if (
+ totalShiftDist > MIN_SWIPE_DISTANCE &&
+ (isFastLastFlick || _releaseAnimData.lastFlickOffset.x > 20)
+ ) {
+ // go to prev item
+ itemsDiff = -1;
+ } else if (
+ totalShiftDist < -MIN_SWIPE_DISTANCE &&
+ (isFastLastFlick || _releaseAnimData.lastFlickOffset.x < -20)
+ ) {
+ // go to next item
+ itemsDiff = 1;
+ }
+ }
+
+ var nextCircle;
+
+ if (itemsDiff) {
+ _currentItemIndex += itemsDiff;
+
+ if (_currentItemIndex < 0) {
+ _currentItemIndex = _options.loop ? _getNumItems() - 1 : 0;
+ nextCircle = true;
+ } else if (_currentItemIndex >= _getNumItems()) {
+ _currentItemIndex = _options.loop ? 0 : _getNumItems() - 1;
+ nextCircle = true;
+ }
+
+ if (!nextCircle || _options.loop) {
+ _indexDiff += itemsDiff;
+ _currPositionIndex -= itemsDiff;
+ itemChanged = true;
+ }
+ }
+
+ var animateToX = _slideSize.x * _currPositionIndex;
+ var animateToDist = Math.abs(animateToX - _mainScrollPos.x);
+ var finishAnimDuration;
+
+ if (
+ !itemChanged &&
+ animateToX > _mainScrollPos.x !==
+ _releaseAnimData.lastFlickSpeed.x > 0
+ ) {
+ // "return to current" duration, e.g. when dragging from slide 0 to -1
+ finishAnimDuration = 333;
+ } else {
+ finishAnimDuration =
+ Math.abs(_releaseAnimData.lastFlickSpeed.x) > 0
+ ? animateToDist / Math.abs(_releaseAnimData.lastFlickSpeed.x)
+ : 333;
+
+ finishAnimDuration = Math.min(finishAnimDuration, 400);
+ finishAnimDuration = Math.max(finishAnimDuration, 250);
+ }
+
+ if (_currZoomedItemIndex === _currentItemIndex) {
+ itemChanged = false;
+ }
+
+ _mainScrollAnimating = true;
+
+ _shout("mainScrollAnimStart");
+
+ _animateProp(
+ "mainScroll",
+ _mainScrollPos.x,
+ animateToX,
+ finishAnimDuration,
+ framework.easing.cubic.out,
+ _moveMainScroll,
+ function() {
+ _stopAllAnimations();
+ _mainScrollAnimating = false;
+ _currZoomedItemIndex = -1;
+
+ if (itemChanged || _currZoomedItemIndex !== _currentItemIndex) {
+ self.updateCurrItem();
+ }
+
+ _shout("mainScrollAnimComplete");
+ }
+ );
+
+ if (itemChanged) {
+ self.updateCurrItem(true);
+ }
+
+ return itemChanged;
+ },
+ _calculateZoomLevel = function(touchesDistance) {
+ return (1 / _startPointsDistance) * touchesDistance * _startZoomLevel;
+ },
+ // Resets zoom if it's out of bounds
+ _completeZoomGesture = function() {
+ var destZoomLevel = _currZoomLevel,
+ minZoomLevel = _getMinZoomLevel(),
+ maxZoomLevel = _getMaxZoomLevel();
+
+ if (_currZoomLevel < minZoomLevel) {
+ destZoomLevel = minZoomLevel;
+ } else if (_currZoomLevel > maxZoomLevel) {
+ destZoomLevel = maxZoomLevel;
+ }
+
+ var destOpacity = 1,
+ onUpdate,
+ initialOpacity = _bgOpacity;
+
+ if (
+ _opacityChanged &&
+ !_isZoomingIn &&
+ !_wasOverInitialZoom &&
+ _currZoomLevel < minZoomLevel
+ ) {
+ //_closedByScroll = true;
+ self.close();
+ return true;
+ }
+
+ if (_opacityChanged) {
+ onUpdate = function(now) {
+ _applyBgOpacity(
+ (destOpacity - initialOpacity) * now + initialOpacity
+ );
+ };
+ }
+
+ self.zoomTo(
+ destZoomLevel,
+ 0,
+ 200,
+ framework.easing.cubic.out,
+ onUpdate
+ );
+ return true;
+ };
+
+ _registerModule("Gestures", {
+ publicMethods: {
+ initGestures: function() {
+ // helper function that builds touch/pointer/mouse events
+ var addEventNames = function(pref, down, move, up, cancel) {
+ _dragStartEvent = pref + down;
+ _dragMoveEvent = pref + move;
+ _dragEndEvent = pref + up;
+ if (cancel) {
+ _dragCancelEvent = pref + cancel;
+ } else {
+ _dragCancelEvent = "";
+ }
+ };
+
+ _pointerEventEnabled = _features.pointerEvent;
+ if (_pointerEventEnabled && _features.touch) {
+ // we don't need touch events, if browser supports pointer events
+ _features.touch = false;
+ }
+
+ if (_pointerEventEnabled) {
+ if (navigator.msPointerEnabled) {
+ // IE10 pointer events are case-sensitive
+ addEventNames("MSPointer", "Down", "Move", "Up", "Cancel");
+ } else {
+ addEventNames("pointer", "down", "move", "up", "cancel");
+ }
+ } else if (_features.touch) {
+ addEventNames("touch", "start", "move", "end", "cancel");
+ _likelyTouchDevice = true;
+ } else {
+ addEventNames("mouse", "down", "move", "up");
+ }
+
+ _upMoveEvents =
+ _dragMoveEvent + " " + _dragEndEvent + " " + _dragCancelEvent;
+ _downEvents = _dragStartEvent;
+
+ if (_pointerEventEnabled && !_likelyTouchDevice) {
+ _likelyTouchDevice =
+ navigator.maxTouchPoints > 1 || navigator.msMaxTouchPoints > 1;
+ }
+ // make variable public
+ self.likelyTouchDevice = _likelyTouchDevice;
+
+ _globalEventHandlers[_dragStartEvent] = _onDragStart;
+ _globalEventHandlers[_dragMoveEvent] = _onDragMove;
+ _globalEventHandlers[_dragEndEvent] = _onDragRelease; // the Kraken
+
+ if (_dragCancelEvent) {
+ _globalEventHandlers[_dragCancelEvent] =
+ _globalEventHandlers[_dragEndEvent];
+ }
+
+ // Bind mouse events on device with detected hardware touch support, in case it supports multiple types of input.
+ if (_features.touch) {
+ _downEvents += " mousedown";
+ _upMoveEvents += " mousemove mouseup";
+ _globalEventHandlers.mousedown =
+ _globalEventHandlers[_dragStartEvent];
+ _globalEventHandlers.mousemove =
+ _globalEventHandlers[_dragMoveEvent];
+ _globalEventHandlers.mouseup = _globalEventHandlers[_dragEndEvent];
+ }
+
+ if (!_likelyTouchDevice) {
+ // don't allow pan to next slide from zoomed state on Desktop
+ _options.allowPanToNext = false;
+ }
+ }
+ }
+ });
+
+ /*>>gestures*/
+
+ /*>>show-hide-transition*/
+ /**
+ * show-hide-transition.js:
+ *
+ * Manages initial opening or closing transition.
+ *
+ * If you're not planning to use transition for gallery at all,
+ * you may set options hideAnimationDuration and showAnimationDuration to 0,
+ * and just delete startAnimation function.
+ *
+ */
+
+ var _showOrHideTimeout,
+ _showOrHide = function(item, img, out, completeFn) {
+ if (_showOrHideTimeout) {
+ clearTimeout(_showOrHideTimeout);
+ }
+
+ _initialZoomRunning = true;
+ _initialContentSet = true;
+
+ // dimensions of small thumbnail {x:,y:,w:}.
+ // Height is optional, as calculated based on large image.
+ var thumbBounds;
+ if (item.initialLayout) {
+ thumbBounds = item.initialLayout;
+ item.initialLayout = null;
+ } else {
+ thumbBounds =
+ _options.getThumbBoundsFn &&
+ _options.getThumbBoundsFn(_currentItemIndex);
+ }
+
+ var duration = out
+ ? _options.hideAnimationDuration
+ : _options.showAnimationDuration;
+
+ var onComplete = function() {
+ _stopAnimation("initialZoom");
+ if (!out) {
+ _applyBgOpacity(1);
+ if (img) {
+ img.style.display = "block";
+ }
+ framework.addClass(template, "pswp--animated-in");
+ _shout("initialZoom" + (out ? "OutEnd" : "InEnd"));
+ } else {
+ self.template.removeAttribute("style");
+ self.bg.removeAttribute("style");
+ }
+
+ if (completeFn) {
+ completeFn();
+ }
+ _initialZoomRunning = false;
+ };
+
+ // if bounds aren't provided, just open gallery without animation
+ if (!duration || !thumbBounds || thumbBounds.x === undefined) {
+ _shout("initialZoom" + (out ? "Out" : "In"));
+
+ _currZoomLevel = item.initialZoomLevel;
+ _equalizePoints(_panOffset, item.initialPosition);
+ _applyCurrentZoomPan();
+
+ template.style.opacity = out ? 0 : 1;
+ _applyBgOpacity(1);
+
+ if (duration) {
+ setTimeout(function() {
+ onComplete();
+ }, duration);
+ } else {
+ onComplete();
+ }
+
+ return;
+ }
+
+ var startAnimation = function() {
+ var closeWithRaf = _closedByScroll,
+ fadeEverything =
+ !self.currItem.src ||
+ self.currItem.loadError ||
+ _options.showHideOpacity;
+
+ // apply hw-acceleration to image
+ if (item.miniImg) {
+ item.miniImg.style.webkitBackfaceVisibility = "hidden";
+ }
+
+ if (!out) {
+ _currZoomLevel = thumbBounds.w / item.w;
+ _panOffset.x = thumbBounds.x;
+ _panOffset.y = thumbBounds.y - _initalWindowScrollY;
+
+ self[fadeEverything ? "template" : "bg"].style.opacity = 0.001;
+ _applyCurrentZoomPan();
+ }
+
+ _registerStartAnimation("initialZoom");
+
+ if (out && !closeWithRaf) {
+ framework.removeClass(template, "pswp--animated-in");
+ }
+
+ if (fadeEverything) {
+ if (out) {
+ framework[(closeWithRaf ? "remove" : "add") + "Class"](
+ template,
+ "pswp--animate_opacity"
+ );
+ } else {
+ setTimeout(function() {
+ framework.addClass(template, "pswp--animate_opacity");
+ }, 30);
+ }
+ }
+
+ _showOrHideTimeout = setTimeout(
+ function() {
+ _shout("initialZoom" + (out ? "Out" : "In"));
+
+ if (!out) {
+ // "in" animation always uses CSS transitions (instead of rAF).
+ // CSS transition work faster here,
+ // as developer may also want to animate other things,
+ // like ui on top of sliding area, which can be animated just via CSS
+
+ _currZoomLevel = item.initialZoomLevel;
+ _equalizePoints(_panOffset, item.initialPosition);
+ _applyCurrentZoomPan();
+ _applyBgOpacity(1);
+
+ if (fadeEverything) {
+ template.style.opacity = 1;
+ } else {
+ _applyBgOpacity(1);
+ }
+
+ _showOrHideTimeout = setTimeout(onComplete, duration + 20);
+ } else {
+ // "out" animation uses rAF only when PhotoSwipe is closed by browser scroll, to recalculate position
+ var destZoomLevel = thumbBounds.w / item.w,
+ initialPanOffset = {
+ x: _panOffset.x,
+ y: _panOffset.y
+ },
+ initialZoomLevel = _currZoomLevel,
+ initalBgOpacity = _bgOpacity,
+ onUpdate = function(now) {
+ if (now === 1) {
+ _currZoomLevel = destZoomLevel;
+ _panOffset.x = thumbBounds.x;
+ _panOffset.y = thumbBounds.y - _currentWindowScrollY;
+ } else {
+ _currZoomLevel =
+ (destZoomLevel - initialZoomLevel) * now +
+ initialZoomLevel;
+ _panOffset.x =
+ (thumbBounds.x - initialPanOffset.x) * now +
+ initialPanOffset.x;
+ _panOffset.y =
+ (thumbBounds.y -
+ _currentWindowScrollY -
+ initialPanOffset.y) *
+ now +
+ initialPanOffset.y;
+ }
+
+ _applyCurrentZoomPan();
+ if (fadeEverything) {
+ template.style.opacity = 1 - now;
+ } else {
+ _applyBgOpacity(initalBgOpacity - now * initalBgOpacity);
+ }
+ };
+
+ if (closeWithRaf) {
+ _animateProp(
+ "initialZoom",
+ 0,
+ 1,
+ duration,
+ framework.easing.cubic.out,
+ onUpdate,
+ onComplete
+ );
+ } else {
+ onUpdate(1);
+ _showOrHideTimeout = setTimeout(onComplete, duration + 20);
+ }
+ }
+ },
+ out ? 25 : 90
+ ); // Main purpose of this delay is to give browser time to paint and
+ // create composite layers of PhotoSwipe UI parts (background, controls, caption, arrows).
+ // Which avoids lag at the beginning of scale transition.
+ };
+ startAnimation();
+ };
+
+ /*>>show-hide-transition*/
+
+ /*>>items-controller*/
+ /**
+ *
+ * Controller manages gallery items, their dimensions, and their content.
+ *
+ */
+
+ var _items,
+ _tempPanAreaSize = {},
+ _imagesToAppendPool = [],
+ _initialContentSet,
+ _initialZoomRunning,
+ _controllerDefaultOptions = {
+ index: 0,
+ errorMsg:
+ '',
+ forceProgressiveLoading: false, // TODO
+ preload: [1, 1],
+ getNumItemsFn: function() {
+ return _items.length;
+ }
+ };
+
+ var _getItemAt,
+ _getNumItems,
+ _initialIsLoop,
+ _getZeroBounds = function() {
+ return {
+ center: { x: 0, y: 0 },
+ max: { x: 0, y: 0 },
+ min: { x: 0, y: 0 }
+ };
+ },
+ _calculateSingleItemPanBounds = function(
+ item,
+ realPanElementW,
+ realPanElementH
+ ) {
+ var bounds = item.bounds;
+
+ // position of element when it's centered
+ bounds.center.x = Math.round(
+ (_tempPanAreaSize.x - realPanElementW) / 2
+ );
+ bounds.center.y =
+ Math.round((_tempPanAreaSize.y - realPanElementH) / 2) +
+ item.vGap.top;
+
+ // maximum pan position
+ bounds.max.x =
+ realPanElementW > _tempPanAreaSize.x
+ ? Math.round(_tempPanAreaSize.x - realPanElementW)
+ : bounds.center.x;
+
+ bounds.max.y =
+ realPanElementH > _tempPanAreaSize.y
+ ? Math.round(_tempPanAreaSize.y - realPanElementH) + item.vGap.top
+ : bounds.center.y;
+
+ // minimum pan position
+ bounds.min.x =
+ realPanElementW > _tempPanAreaSize.x ? 0 : bounds.center.x;
+ bounds.min.y =
+ realPanElementH > _tempPanAreaSize.y
+ ? item.vGap.top
+ : bounds.center.y;
+ },
+ _calculateItemSize = function(item, viewportSize, zoomLevel) {
+ if (item.src && !item.loadError) {
+ var isInitial = !zoomLevel;
+
+ if (isInitial) {
+ if (!item.vGap) {
+ item.vGap = { top: 0, bottom: 0 };
+ }
+ // allows overriding vertical margin for individual items
+ _shout("parseVerticalMargin", item);
+ }
+
+ _tempPanAreaSize.x = viewportSize.x;
+ _tempPanAreaSize.y =
+ viewportSize.y - item.vGap.top - item.vGap.bottom;
+
+ if (isInitial) {
+ var hRatio = _tempPanAreaSize.x / item.w;
+ var vRatio = _tempPanAreaSize.y / item.h;
+
+ item.fitRatio = hRatio < vRatio ? hRatio : vRatio;
+ //item.fillRatio = hRatio > vRatio ? hRatio : vRatio;
+
+ var scaleMode = _options.scaleMode;
+
+ if (scaleMode === "orig") {
+ zoomLevel = 1;
+ } else if (scaleMode === "fit") {
+ zoomLevel = item.fitRatio;
+ }
+
+ if (zoomLevel > 1) {
+ zoomLevel = 1;
+ }
+
+ item.initialZoomLevel = zoomLevel;
+
+ if (!item.bounds) {
+ // reuse bounds object
+ item.bounds = _getZeroBounds();
+ }
+ }
+
+ if (!zoomLevel) {
+ return;
+ }
+
+ _calculateSingleItemPanBounds(
+ item,
+ item.w * zoomLevel,
+ item.h * zoomLevel
+ );
+
+ if (isInitial && zoomLevel === item.initialZoomLevel) {
+ item.initialPosition = item.bounds.center;
+ }
+
+ return item.bounds;
+ } else {
+ item.w = item.h = 0;
+ item.initialZoomLevel = item.fitRatio = 1;
+ item.bounds = _getZeroBounds();
+ item.initialPosition = item.bounds.center;
+
+ // if it's not image, we return zero bounds (content is not zoomable)
+ return item.bounds;
+ }
+ },
+ _appendImage = function(
+ index,
+ item,
+ baseDiv,
+ img,
+ preventAnimation,
+ keepPlaceholder
+ ) {
+ if (item.loadError) {
+ return;
+ }
+
+ if (img) {
+ item.imageAppended = true;
+ _setImageSize(
+ item,
+ img,
+ item === self.currItem && _renderMaxResolution
+ );
+
+ baseDiv.appendChild(img);
+
+ if (keepPlaceholder) {
+ setTimeout(function() {
+ if (item && item.loaded && item.placeholder) {
+ item.placeholder.style.display = "none";
+ item.placeholder = null;
+ }
+ }, 500);
+ }
+ }
+ },
+ _preloadImage = function(item) {
+ item.loading = true;
+ item.loaded = false;
+ var img = (item.img = framework.createEl("pswp__img", "img"));
+ var onComplete = function() {
+ item.loading = false;
+ item.loaded = true;
+
+ if (item.loadComplete) {
+ item.loadComplete(item);
+ } else {
+ item.img = null; // no need to store image object
+ }
+ img.onload = img.onerror = null;
+ img = null;
+ };
+ img.onload = onComplete;
+ img.onerror = function() {
+ item.loadError = true;
+ onComplete();
+ };
+
+ img.src = item.src; // + '?a=' + Math.random();
+
+ return img;
+ },
+ _checkForError = function(item, cleanUp) {
+ if (item.src && item.loadError && item.container) {
+ if (cleanUp) {
+ item.container.innerHTML = "";
+ }
+
+ item.container.innerHTML = _options.errorMsg.replace(
+ "%url%",
+ item.src
+ );
+ return true;
+ }
+ },
+ _setImageSize = function(item, img, maxRes) {
+ if (!item.src) {
+ return;
+ }
+
+ if (!img) {
+ img = item.container.lastChild;
+ }
+
+ var w = maxRes ? item.w : Math.round(item.w * item.fitRatio),
+ h = maxRes ? item.h : Math.round(item.h * item.fitRatio);
+
+ if (item.placeholder && !item.loaded) {
+ item.placeholder.style.width = w + "px";
+ item.placeholder.style.height = h + "px";
+ }
+
+ img.style.width = w + "px";
+ img.style.height = h + "px";
+ },
+ _appendImagesPool = function() {
+ if (_imagesToAppendPool.length) {
+ var poolItem;
+
+ for (var i = 0; i < _imagesToAppendPool.length; i++) {
+ poolItem = _imagesToAppendPool[i];
+ if (poolItem.holder.index === poolItem.index) {
+ _appendImage(
+ poolItem.index,
+ poolItem.item,
+ poolItem.baseDiv,
+ poolItem.img,
+ false,
+ poolItem.clearPlaceholder
+ );
+ }
+ }
+ _imagesToAppendPool = [];
+ }
+ };
+
+ _registerModule("Controller", {
+ publicMethods: {
+ lazyLoadItem: function(index) {
+ index = _getLoopedId(index);
+ var item = _getItemAt(index);
+
+ if (!item || ((item.loaded || item.loading) && !_itemsNeedUpdate)) {
+ return;
+ }
+
+ _shout("gettingData", index, item);
+
+ if (!item.src) {
+ return;
+ }
+
+ _preloadImage(item);
+ },
+ initController: function() {
+ framework.extend(_options, _controllerDefaultOptions, true);
+ self.items = _items = items;
+ _getItemAt = self.getItemAt;
+ _getNumItems = _options.getNumItemsFn; //self.getNumItems;
+
+ _initialIsLoop = _options.loop;
+ if (_getNumItems() < 3) {
+ _options.loop = false; // disable loop if less then 3 items
+ }
+
+ _listen("beforeChange", function(diff) {
+ var p = _options.preload,
+ isNext = diff === null ? true : diff >= 0,
+ preloadBefore = Math.min(p[0], _getNumItems()),
+ preloadAfter = Math.min(p[1], _getNumItems()),
+ i;
+
+ for (i = 1; i <= (isNext ? preloadAfter : preloadBefore); i++) {
+ self.lazyLoadItem(_currentItemIndex + i);
+ }
+ for (i = 1; i <= (isNext ? preloadBefore : preloadAfter); i++) {
+ self.lazyLoadItem(_currentItemIndex - i);
+ }
+ });
+
+ _listen("initialLayout", function() {
+ self.currItem.initialLayout =
+ _options.getThumbBoundsFn &&
+ _options.getThumbBoundsFn(_currentItemIndex);
+ });
+
+ _listen("mainScrollAnimComplete", _appendImagesPool);
+ _listen("initialZoomInEnd", _appendImagesPool);
+
+ _listen("destroy", function() {
+ var item;
+ for (var i = 0; i < _items.length; i++) {
+ item = _items[i];
+ // remove reference to DOM elements, for GC
+ if (item.container) {
+ item.container = null;
+ }
+ if (item.placeholder) {
+ item.placeholder = null;
+ }
+ if (item.img) {
+ item.img = null;
+ }
+ if (item.preloader) {
+ item.preloader = null;
+ }
+ if (item.loadError) {
+ item.loaded = item.loadError = false;
+ }
+ }
+ _imagesToAppendPool = null;
+ });
+ },
+
+ getItemAt: function(index) {
+ if (index >= 0) {
+ return _items[index] !== undefined ? _items[index] : false;
+ }
+ return false;
+ },
+
+ allowProgressiveImg: function() {
+ // 1. Progressive image loading isn't working on webkit/blink
+ // when hw-acceleration (e.g. translateZ) is applied to IMG element.
+ // That's why in PhotoSwipe parent element gets zoom transform, not image itself.
+ //
+ // 2. Progressive image loading sometimes blinks in webkit/blink when applying animation to parent element.
+ // That's why it's disabled on touch devices (mainly because of swipe transition)
+ //
+ // 3. Progressive image loading sometimes doesn't work in IE (up to 11).
+
+ // Don't allow progressive loading on non-large touch devices
+ return (
+ _options.forceProgressiveLoading ||
+ !_likelyTouchDevice ||
+ _options.mouseUsed ||
+ screen.width > 1200
+ );
+ // 1200 - to eliminate touch devices with large screen (like Chromebook Pixel)
+ },
+
+ setContent: function(holder, index) {
+ if (_options.loop) {
+ index = _getLoopedId(index);
+ }
+
+ var prevItem = self.getItemAt(holder.index);
+ if (prevItem) {
+ prevItem.container = null;
+ }
+
+ var item = self.getItemAt(index),
+ img;
+
+ if (!item) {
+ holder.el.innerHTML = "";
+ return;
+ }
+
+ // allow to override data
+ _shout("gettingData", index, item);
+
+ holder.index = index;
+ holder.item = item;
+
+ // base container DIV is created only once for each of 3 holders
+ var baseDiv = (item.container = framework.createEl(
+ "pswp__zoom-wrap"
+ ));
+
+ if (!item.src && item.html) {
+ if (item.html.tagName) {
+ baseDiv.appendChild(item.html);
+ } else {
+ baseDiv.innerHTML = item.html;
+ }
+ }
+
+ _checkForError(item);
+
+ _calculateItemSize(item, _viewportSize);
+
+ if (item.src && !item.loadError && !item.loaded) {
+ item.loadComplete = function(item) {
+ // gallery closed before image finished loading
+ if (!_isOpen) {
+ return;
+ }
+
+ // check if holder hasn't changed while image was loading
+ if (holder && holder.index === index) {
+ if (_checkForError(item, true)) {
+ item.loadComplete = item.img = null;
+ _calculateItemSize(item, _viewportSize);
+ _applyZoomPanToItem(item);
+
+ if (holder.index === _currentItemIndex) {
+ // recalculate dimensions
+ self.updateCurrZoomItem();
+ }
+ return;
+ }
+ if (!item.imageAppended) {
+ if (
+ _features.transform &&
+ (_mainScrollAnimating || _initialZoomRunning)
+ ) {
+ _imagesToAppendPool.push({
+ item: item,
+ baseDiv: baseDiv,
+ img: item.img,
+ index: index,
+ holder: holder,
+ clearPlaceholder: true
+ });
+ } else {
+ _appendImage(
+ index,
+ item,
+ baseDiv,
+ item.img,
+ _mainScrollAnimating || _initialZoomRunning,
+ true
+ );
+ }
+ } else {
+ // remove preloader & mini-img
+ if (!_initialZoomRunning && item.placeholder) {
+ item.placeholder.style.display = "none";
+ item.placeholder = null;
+ }
+ }
+ }
+
+ item.loadComplete = null;
+ item.img = null; // no need to store image element after it's added
+
+ _shout("imageLoadComplete", index, item);
+ };
+
+ if (framework.features.transform) {
+ var placeholderClassName = "pswp__img pswp__img--placeholder";
+ placeholderClassName += item.msrc
+ ? ""
+ : " pswp__img--placeholder--blank";
+
+ var placeholder = framework.createEl(
+ placeholderClassName,
+ item.msrc ? "img" : ""
+ );
+ if (item.msrc) {
+ placeholder.src = item.msrc;
+ }
+
+ _setImageSize(item, placeholder);
+
+ baseDiv.appendChild(placeholder);
+ item.placeholder = placeholder;
+ }
+
+ if (!item.loading) {
+ _preloadImage(item);
+ }
+
+ if (self.allowProgressiveImg()) {
+ // just append image
+ if (!_initialContentSet && _features.transform) {
+ _imagesToAppendPool.push({
+ item: item,
+ baseDiv: baseDiv,
+ img: item.img,
+ index: index,
+ holder: holder
+ });
+ } else {
+ _appendImage(index, item, baseDiv, item.img, true, true);
+ }
+ }
+ } else if (item.src && !item.loadError) {
+ // image object is created every time, due to bugs of image loading & delay when switching images
+ img = framework.createEl("pswp__img", "img");
+ img.style.opacity = 1;
+ img.src = item.src;
+ _setImageSize(item, img);
+ _appendImage(index, item, baseDiv, img, true);
+ }
+
+ if (!_initialContentSet && index === _currentItemIndex) {
+ _currZoomElementStyle = baseDiv.style;
+ _showOrHide(item, img || item.img);
+ } else {
+ _applyZoomPanToItem(item);
+ }
+
+ holder.el.innerHTML = "";
+ holder.el.appendChild(baseDiv);
+ },
+
+ cleanSlide: function(item) {
+ if (item.img) {
+ item.img.onload = item.img.onerror = null;
+ }
+ item.loaded = item.loading = item.img = item.imageAppended = false;
+ }
+ }
+ });
+
+ /*>>items-controller*/
+
+ /*>>tap*/
+ /**
+ * tap.js:
+ *
+ * Displatches tap and double-tap events.
+ *
+ */
+
+ var tapTimer,
+ tapReleasePoint = {},
+ _dispatchTapEvent = function(origEvent, releasePoint, pointerType) {
+ var e = document.createEvent("CustomEvent"),
+ eDetail = {
+ origEvent: origEvent,
+ target: origEvent.target,
+ releasePoint: releasePoint,
+ pointerType: pointerType || "touch"
+ };
+
+ e.initCustomEvent("pswpTap", true, true, eDetail);
+ origEvent.target.dispatchEvent(e);
+ };
+
+ _registerModule("Tap", {
+ publicMethods: {
+ initTap: function() {
+ _listen("firstTouchStart", self.onTapStart);
+ _listen("touchRelease", self.onTapRelease);
+ _listen("destroy", function() {
+ tapReleasePoint = {};
+ tapTimer = null;
+ });
+ },
+ onTapStart: function(touchList) {
+ if (touchList.length > 1) {
+ clearTimeout(tapTimer);
+ tapTimer = null;
+ }
+ },
+ onTapRelease: function(e, releasePoint) {
+ if (!releasePoint) {
+ return;
+ }
+
+ if (!_moved && !_isMultitouch && !_numAnimations) {
+ var p0 = releasePoint;
+ if (tapTimer) {
+ clearTimeout(tapTimer);
+ tapTimer = null;
+
+ // Check if taped on the same place
+ if (_isNearbyPoints(p0, tapReleasePoint)) {
+ _shout("doubleTap", p0);
+ return;
+ }
+ }
+
+ if (releasePoint.type === "mouse") {
+ _dispatchTapEvent(e, releasePoint, "mouse");
+ return;
+ }
+
+ var clickedTagName = e.target.tagName.toUpperCase();
+ // avoid double tap delay on buttons and elements that have class pswp__single-tap
+ if (
+ clickedTagName === "BUTTON" ||
+ framework.hasClass(e.target, "pswp__single-tap")
+ ) {
+ _dispatchTapEvent(e, releasePoint);
+ return;
+ }
+
+ _equalizePoints(tapReleasePoint, p0);
+
+ tapTimer = setTimeout(function() {
+ _dispatchTapEvent(e, releasePoint);
+ tapTimer = null;
+ }, 300);
+ }
+ }
+ }
+ });
+
+ /*>>tap*/
+
+ /*>>desktop-zoom*/
+ /**
+ *
+ * desktop-zoom.js:
+ *
+ * - Binds mousewheel event for paning zoomed image.
+ * - Manages "dragging", "zoomed-in", "zoom-out" classes.
+ * (which are used for cursors and zoom icon)
+ * - Adds toggleDesktopZoom function.
+ *
+ */
+
+ var _wheelDelta;
+
+ _registerModule("DesktopZoom", {
+ publicMethods: {
+ initDesktopZoom: function() {
+ if (_oldIE) {
+ // no zoom for old IE (<=8)
+ return;
+ }
+
+ if (_likelyTouchDevice) {
+ // if detected hardware touch support, we wait until mouse is used,
+ // and only then apply desktop-zoom features
+ _listen("mouseUsed", function() {
+ self.setupDesktopZoom();
+ });
+ } else {
+ self.setupDesktopZoom(true);
+ }
+ },
+
+ setupDesktopZoom: function(onInit) {
+ _wheelDelta = {};
+
+ var events = "wheel mousewheel DOMMouseScroll";
+
+ _listen("bindEvents", function() {
+ framework.bind(template, events, self.handleMouseWheel);
+ });
+
+ _listen("unbindEvents", function() {
+ if (_wheelDelta) {
+ framework.unbind(template, events, self.handleMouseWheel);
+ }
+ });
+
+ self.mouseZoomedIn = false;
+
+ var hasDraggingClass,
+ updateZoomable = function() {
+ if (self.mouseZoomedIn) {
+ framework.removeClass(template, "pswp--zoomed-in");
+ self.mouseZoomedIn = false;
+ }
+ if (_currZoomLevel < 1) {
+ framework.addClass(template, "pswp--zoom-allowed");
+ } else {
+ framework.removeClass(template, "pswp--zoom-allowed");
+ }
+ removeDraggingClass();
+ },
+ removeDraggingClass = function() {
+ if (hasDraggingClass) {
+ framework.removeClass(template, "pswp--dragging");
+ hasDraggingClass = false;
+ }
+ };
+
+ _listen("resize", updateZoomable);
+ _listen("afterChange", updateZoomable);
+ _listen("pointerDown", function() {
+ if (self.mouseZoomedIn) {
+ hasDraggingClass = true;
+ framework.addClass(template, "pswp--dragging");
+ }
+ });
+ _listen("pointerUp", removeDraggingClass);
+
+ if (!onInit) {
+ updateZoomable();
+ }
+ },
+
+ handleMouseWheel: function(e) {
+ if (_currZoomLevel <= self.currItem.fitRatio) {
+ if (_options.modal) {
+ if (!_options.closeOnScroll || _numAnimations || _isDragging) {
+ e.preventDefault();
+ } else if (_transformKey && Math.abs(e.deltaY) > 2) {
+ // close PhotoSwipe
+ // if browser supports transforms & scroll changed enough
+ _closedByScroll = true;
+ self.close();
+ }
+ }
+ return true;
+ }
+
+ // allow just one event to fire
+ e.stopPropagation();
+
+ // https://developer.mozilla.org/en-US/docs/Web/Events/wheel
+ _wheelDelta.x = 0;
+
+ if ("deltaX" in e) {
+ if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {
+ // 18 - average line height
+ _wheelDelta.x = e.deltaX * 18;
+ _wheelDelta.y = e.deltaY * 18;
+ } else {
+ _wheelDelta.x = e.deltaX;
+ _wheelDelta.y = e.deltaY;
+ }
+ } else if ("wheelDelta" in e) {
+ if (e.wheelDeltaX) {
+ _wheelDelta.x = -0.16 * e.wheelDeltaX;
+ }
+ if (e.wheelDeltaY) {
+ _wheelDelta.y = -0.16 * e.wheelDeltaY;
+ } else {
+ _wheelDelta.y = -0.16 * e.wheelDelta;
+ }
+ } else if ("detail" in e) {
+ _wheelDelta.y = e.detail;
+ } else {
+ return;
+ }
+
+ _calculatePanBounds(_currZoomLevel, true);
+
+ var newPanX = _panOffset.x - _wheelDelta.x,
+ newPanY = _panOffset.y - _wheelDelta.y;
+
+ // only prevent scrolling in nonmodal mode when not at edges
+ if (
+ _options.modal ||
+ (newPanX <= _currPanBounds.min.x &&
+ newPanX >= _currPanBounds.max.x &&
+ newPanY <= _currPanBounds.min.y &&
+ newPanY >= _currPanBounds.max.y)
+ ) {
+ e.preventDefault();
+ }
+
+ // TODO: use rAF instead of mousewheel?
+ self.panTo(newPanX, newPanY);
+ },
+
+ toggleDesktopZoom: function(centerPoint) {
+ centerPoint = centerPoint || {
+ x: _viewportSize.x / 2 + _offset.x,
+ y: _viewportSize.y / 2 + _offset.y
+ };
+
+ var doubleTapZoomLevel = _options.getDoubleTapZoom(
+ true,
+ self.currItem
+ );
+ var zoomOut = _currZoomLevel === doubleTapZoomLevel;
+
+ self.mouseZoomedIn = !zoomOut;
+
+ self.zoomTo(
+ zoomOut ? self.currItem.initialZoomLevel : doubleTapZoomLevel,
+ centerPoint,
+ 333
+ );
+ framework[(!zoomOut ? "add" : "remove") + "Class"](
+ template,
+ "pswp--zoomed-in"
+ );
+ }
+ }
+ });
+
+ /*>>desktop-zoom*/
+
+ /*>>history*/
+ /**
+ *
+ * history.js:
+ *
+ * - Back button to close gallery.
+ *
+ * - Unique URL for each slide: example.com/&pid=1&gid=3
+ * (where PID is picture index, and GID and gallery index)
+ *
+ * - Switch URL when slides change.
+ *
+ */
+
+ var _historyDefaultOptions = {
+ history: true,
+ galleryUID: 1
+ };
+
+ var _historyUpdateTimeout,
+ _hashChangeTimeout,
+ _hashAnimCheckTimeout,
+ _hashChangedByScript,
+ _hashChangedByHistory,
+ _hashReseted,
+ _initialHash,
+ _historyChanged,
+ _closedFromURL,
+ _urlChangedOnce,
+ _windowLoc,
+ _supportsPushState,
+ _getHash = function() {
+ return _windowLoc.hash.substring(1);
+ },
+ _cleanHistoryTimeouts = function() {
+ if (_historyUpdateTimeout) {
+ clearTimeout(_historyUpdateTimeout);
+ }
+
+ if (_hashAnimCheckTimeout) {
+ clearTimeout(_hashAnimCheckTimeout);
+ }
+ },
+ // pid - Picture index
+ // gid - Gallery index
+ _parseItemIndexFromURL = function() {
+ var hash = _getHash(),
+ params = {};
+
+ if (hash.length < 5) {
+ // pid=1
+ return params;
+ }
+
+ var i,
+ vars = hash.split("&");
+ for (i = 0; i < vars.length; i++) {
+ if (!vars[i]) {
+ continue;
+ }
+ var pair = vars[i].split("=");
+ if (pair.length < 2) {
+ continue;
+ }
+ params[pair[0]] = pair[1];
+ }
+ if (_options.galleryPIDs) {
+ // detect custom pid in hash and search for it among the items collection
+ var searchfor = params.pid;
+ params.pid = 0; // if custom pid cannot be found, fallback to the first item
+ for (i = 0; i < _items.length; i++) {
+ if (_items[i].pid === searchfor) {
+ params.pid = i;
+ break;
+ }
+ }
+ } else {
+ params.pid = parseInt(params.pid, 10) - 1;
+ }
+ if (params.pid < 0) {
+ params.pid = 0;
+ }
+ return params;
+ },
+ _updateHash = function() {
+ if (_hashAnimCheckTimeout) {
+ clearTimeout(_hashAnimCheckTimeout);
+ }
+
+ if (_numAnimations || _isDragging) {
+ // changing browser URL forces layout/paint in some browsers, which causes noticable lag during animation
+ // that's why we update hash only when no animations running
+ _hashAnimCheckTimeout = setTimeout(_updateHash, 500);
+ return;
+ }
+
+ if (_hashChangedByScript) {
+ clearTimeout(_hashChangeTimeout);
+ } else {
+ _hashChangedByScript = true;
+ }
+
+ var pid = _currentItemIndex + 1;
+ var item = _getItemAt(_currentItemIndex);
+ if (item.hasOwnProperty("pid")) {
+ // carry forward any custom pid assigned to the item
+ pid = item.pid;
+ }
+ var newHash =
+ _initialHash +
+ "&" +
+ "gid=" +
+ _options.galleryUID +
+ "&" +
+ "pid=" +
+ pid;
+
+ if (!_historyChanged) {
+ if (_windowLoc.hash.indexOf(newHash) === -1) {
+ _urlChangedOnce = true;
+ }
+ // first time - add new hisory record, then just replace
+ }
+
+ var newURL = _windowLoc.href.split("#")[0] + "#" + newHash;
+
+ if (_supportsPushState) {
+ if ("#" + newHash !== window.location.hash) {
+ history[_historyChanged ? "replaceState" : "pushState"](
+ "",
+ document.title,
+ newURL
+ );
+ }
+ } else {
+ if (_historyChanged) {
+ _windowLoc.replace(newURL);
+ } else {
+ _windowLoc.hash = newHash;
+ }
+ }
+
+ _historyChanged = true;
+ _hashChangeTimeout = setTimeout(function() {
+ _hashChangedByScript = false;
+ }, 60);
+ };
+
+ _registerModule("History", {
+ publicMethods: {
+ initHistory: function() {
+ framework.extend(_options, _historyDefaultOptions, true);
+
+ if (!_options.history) {
+ return;
+ }
+
+ _windowLoc = window.location;
+ _urlChangedOnce = false;
+ _closedFromURL = false;
+ _historyChanged = false;
+ _initialHash = _getHash();
+ _supportsPushState = "pushState" in history;
+
+ if (_initialHash.indexOf("gid=") > -1) {
+ _initialHash = _initialHash.split("&gid=")[0];
+ _initialHash = _initialHash.split("?gid=")[0];
+ }
+
+ _listen("afterChange", self.updateURL);
+ _listen("unbindEvents", function() {
+ framework.unbind(window, "hashchange", self.onHashChange);
+ });
+
+ var returnToOriginal = function() {
+ _hashReseted = true;
+ if (!_closedFromURL) {
+ if (_urlChangedOnce) {
+ history.back();
+ } else {
+ if (_initialHash) {
+ _windowLoc.hash = _initialHash;
+ } else {
+ if (_supportsPushState) {
+ // remove hash from url without refreshing it or scrolling to top
+ history.pushState(
+ "",
+ document.title,
+ _windowLoc.pathname + _windowLoc.search
+ );
+ } else {
+ _windowLoc.hash = "";
+ }
+ }
+ }
+ }
+
+ _cleanHistoryTimeouts();
+ };
+
+ _listen("unbindEvents", function() {
+ if (_closedByScroll) {
+ // if PhotoSwipe is closed by scroll, we go "back" before the closing animation starts
+ // this is done to keep the scroll position
+ returnToOriginal();
+ }
+ });
+ _listen("destroy", function() {
+ if (!_hashReseted) {
+ returnToOriginal();
+ }
+ });
+ _listen("firstUpdate", function() {
+ _currentItemIndex = _parseItemIndexFromURL().pid;
+ });
+
+ var index = _initialHash.indexOf("pid=");
+ if (index > -1) {
+ _initialHash = _initialHash.substring(0, index);
+ if (_initialHash.slice(-1) === "&") {
+ _initialHash = _initialHash.slice(0, -1);
+ }
+ }
+
+ setTimeout(function() {
+ if (_isOpen) {
+ // hasn't destroyed yet
+ framework.bind(window, "hashchange", self.onHashChange);
+ }
+ }, 40);
+ },
+ onHashChange: function() {
+ if (_getHash() === _initialHash) {
+ _closedFromURL = true;
+ self.close();
+ return;
+ }
+ if (!_hashChangedByScript) {
+ _hashChangedByHistory = true;
+ self.goTo(_parseItemIndexFromURL().pid);
+ _hashChangedByHistory = false;
+ }
+ },
+ updateURL: function() {
+ // Delay the update of URL, to avoid lag during transition,
+ // and to not to trigger actions like "refresh page sound" or "blinking favicon" to often
+
+ _cleanHistoryTimeouts();
+
+ if (_hashChangedByHistory) {
+ return;
+ }
+
+ if (!_historyChanged) {
+ _updateHash(); // first time
+ } else {
+ _historyUpdateTimeout = setTimeout(_updateHash, 800);
+ }
+ }
+ }
+ });
+
+ /*>>history*/
+ framework.extend(self, publicMethods);
+ };
+ return PhotoSwipe;
+});
diff --git a/templates/_includes/photoswipe.html b/templates/_includes/photoswipe.html
new file mode 100644
index 00000000..6ed2b37d
--- /dev/null
+++ b/templates/_includes/photoswipe.html
@@ -0,0 +1,67 @@
+
+
+
diff --git a/templates/article.html b/templates/article.html
index 1b5ff576..e2cc0097 100644
--- a/templates/article.html
+++ b/templates/article.html
@@ -144,6 +144,7 @@ Tags
+{% include '_includes/photoswipe.html' %}
{% endblock content %}
{% block script %}
diff --git a/templates/page.html b/templates/page.html
index e3eb4d43..95dfca12 100644
--- a/templates/page.html
+++ b/templates/page.html
@@ -47,6 +47,7 @@