vendor: 5,362 bytes, lines 1-3
1// source --> https://vicasol.es/wp-content/plugins/fancybox-for-wordpress/assets/js/purify.min.js?ver=1.3.4 2/*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE */ 3!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=b(Array.prototype.forEach),m=b(Array.prototype.pop),p=b(Array.prototype.push),f=b(String.prototype.toLowerCase),d=b(String.prototype.toString),h=b(String.prototype.match),g=b(String.prototype.replace),T=b(String.prototype.indexOf),y=b(String.prototype.trim),E=b(Object.prototype.hasOwnProperty),_=b(RegExp.prototype.test),A=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return s(N,t)});var N;function b(e){return function(t){for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return c(e,t,o)}}function S(e,o){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:f;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function R(e){for(let t=0;t<e.length;t++){E(e,t)||(e[t]=null)}return e}function w(t){const n=l(null);for(const[o,r]of e(t)){E(t,o)&&(Array.isArray(r)?n[o]=R(r):r&&"object"==typeof r&&r.constructor===Object?n[o]=w(r):n[o]=r)}return n}function C(e,t){for(;null!==e;){const n=r(e,t);if(n){if(n.get)return b(n.get);if("function"==typeof n.value)return b(n.value)}e=o(e)}return function(){return null}}const L=i(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),D=i(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),v=i(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),O=i(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),x=i(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),k=i(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),M=i(["#text"]),I=i(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","
3spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns","slot"]),U=i(["accent-height","accumulate","additive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),P=i(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),F=i(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),H=a(/\{\{[\w\W]*|[\w\W]*\}\}/gm),z=a(/<%[\w\W]*|[\w\W]*%>/gm),B=a(/\${[\w\W]*}/gm),W=a(/^data-[\-\w.\u00B7-\uFFFF]/),G=a(/^aria-[\-\w]+$/),Y=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),j=a(/^(?:\w+script|data):/i),X=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),q=a(/^html$/i),$=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var K=Object.freeze({__proto__:null,MUSTACHE_EXPR:H,ERB_EXPR:z,TMPLIT_EXPR:B,DATA_ATTR:W,ARIA_ATTR:G,IS_ALLOWED_URI:Y,IS_SCRIPT_OR_DATA:j,ATTR_WHITESPACE:X,DOCTYPE_NAME:q,CUSTOM_ELEMENT:$});const V=1,Z=3,J=7,Q=8,ee=9,te=function(){return"undefined"==typeof window?null:window};var ne=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:te();const o=e=>t(e);if(o.version="3.1.6",o.removed=[],!n||!n.document||n.document.nodeType!==ee)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:b,Element:R,NodeFilter:H,NamedNodeMap:z=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:B,DOMParser:W,trustedTypes:G}=n,j=R.prototype,X=C(j,"cloneNode"),$=C(j,"remove"),ne=C(j,"nextSibling"),oe=C(j,"childNodes"),re=C(j,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let ie,ae="";const{implementation:le,createNodeIterator:ce,createDocumentFragment:se,getElementsByTagName:ue}=r,{importNode:me}=a;let pe={};o.isSupported="function"==typeof e&&"function"==typeof re&&le&&void 0!==le.createHTMLDocument;const{MUSTACHE_EXPR:fe,ERB_EXPR:de,TMPLIT_EXPR:he,DATA_ATTR:ge,ARIA_ATTR:Te,IS_SCRIPT_OR_DATA:ye,ATTR_WHITESPACE:Ee,CUSTOM_ELEMENT:_e}=K;let{IS_ALLOWED_URI:Ae}=K,Ne=null;const be=S({},[...L,...D,...v,...x,...M]);let Se=null;const Re=S({},[...I,...U,...P,...F]);let we=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ce=null,Le=null,De=!0,ve=!0,Oe=!1,xe=!0,ke=!1,Me=!0,Ie=!1,Ue=!1,Pe=!1,Fe=!1,He=!1,ze=!1,Be=!0,We=!1,Ge=!0,Ye=!1,je={},Xe=null;const qe=S({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let $e=null;const Ke=S({},["audio","video","img","source","image","track"]);let Ve=null;const Ze=S({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Je="http://www.w3.org/1998/Math/MathML",Qe="http://www.w3.org/2000/svg",et="http://www.w3.org/1999/xhtml";let tt=et,nt=!1,ot=null;const rt=S({},[Je,Qe,et],d);let it=null;const at=["application/xhtml+xml","text/html"];let lt=null,ct=null;const st=r.createElement("form"),ut=function(e){return e instanceof RegExp||e instanceof Function},mt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ct||ct!==e){if(e&&"object"==typeof e||(e={}
vendor: 10,230 bytes, lines 3-5
3),e=w(e),it=-1===at.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,lt="application/xhtml+xml"===it?d:f,Ne=E(e,"ALLOWED_TAGS")?S({},e.ALLOWED_TAGS,lt):be,Se=E(e,"ALLOWED_ATTR")?S({},e.ALLOWED_ATTR,lt):Re,ot=E(e,"ALLOWED_NAMESPACES")?S({},e.ALLOWED_NAMESPACES,d):rt,Ve=E(e,"ADD_URI_SAFE_ATTR")?S(w(Ze),e.ADD_URI_SAFE_ATTR,lt):Ze,$e=E(e,"ADD_DATA_URI_TAGS")?S(w(Ke),e.ADD_DATA_URI_TAGS,lt):Ke,Xe=E(e,"FORBID_CONTENTS")?S({},e.FORBID_CONTENTS,lt):qe,Ce=E(e,"FORBID_TAGS")?S({},e.FORBID_TAGS,lt):{},Le=E(e,"FORBID_ATTR")?S({},e.FORBID_ATTR,lt):{},je=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,De=!1!==e.ALLOW_ARIA_ATTR,ve=!1!==e.ALLOW_DATA_ATTR,Oe=e.ALLOW_UNKNOWN_PROTOCOLS||!1,xe=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Me=!1!==e.SAFE_FOR_XML,Ie=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,He=e.RETURN_DOM_FRAGMENT||!1,ze=e.RETURN_TRUSTED_TYPE||!1,Pe=e.FORCE_BODY||!1,Be=!1!==e.SANITIZE_DOM,We=e.SANITIZE_NAMED_PROPS||!1,Ge=!1!==e.KEEP_CONTENT,Ye=e.IN_PLACE||!1,Ae=e.ALLOWED_URI_REGEXP||Y,tt=e.NAMESPACE||et,we=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(we.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(we.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(we.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(ve=!1),He&&(Fe=!0),je&&(Ne=S({},M),Se=[],!0===je.html&&(S(Ne,L),S(Se,I)),!0===je.svg&&(S(Ne,D),S(Se,U),S(Se,F)),!0===je.svgFilters&&(S(Ne,v),S(Se,U),S(Se,F)),!0===je.mathMl&&(S(Ne,x),S(Se,P),S(Se,F))),e.ADD_TAGS&&(Ne===be&&(Ne=w(Ne)),S(Ne,e.ADD_TAGS,lt)),e.ADD_ATTR&&(Se===Re&&(Se=w(Se)),S(Se,e.ADD_ATTR,lt)),e.ADD_URI_SAFE_ATTR&&S(Ve,e.ADD_URI_SAFE_ATTR,lt),e.FORBID_CONTENTS&&(Xe===qe&&(Xe=w(Xe)),S(Xe,e.FORBID_CONTENTS,lt)),Ge&&(Ne["#text"]=!0),Ie&&S(Ne,["html","head","body"]),Ne.table&&(S(Ne,["tbody"]),delete Ce.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ie=e.TRUSTED_TYPES_POLICY,ae=ie.createHTML("")}else void 0===ie&&(ie=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(G,c)),null!==ie&&"string"==typeof ae&&(ae=ie.createHTML(""));i&&i(e),ct=e}},pt=S({},["mi","mo","mn","ms","mtext"]),ft=S({},["foreignobject","annotation-xml"]),dt=S({},["title","style","font","a","script"]),ht=S({},[...D,...v,...O]),gt=S({},[...x,...k]),Tt=function(e){p(o.removed,{element:e});try{re(e).removeChild(e)}catch(t){$(e)}},yt=function(e,t){try{p(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Se[e])if(Fe||He)try{Tt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Et=function(e){let t=null,n=null;if(Pe)e="<remove></remove>"+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===it&&tt===et&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=ie?ie.createHTML(e):e;if(tt===et)try{t=(new W).parseFromString(o,it)}catch(e){}if(!t||!t.documentElement){t=le.createDocument(tt,"template",null);try{t.documentElement.innerHTML=nt?ae:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),tt===et?ue.call(t,Ie?"html":"body")[0]:Ie?t.documentElement:i},_t=function(e){return ce.call(e.ownerDocument||e,e,H.SHOW_ELEMENT|H.SHOW_COMMENT|H.SHOW_TEXT|H.SHOW_PROCESSING_INSTRUCTION|H.SHOW_CDATA_SECTION,null)},At=function(e){return e instanceof B&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof z)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof b&&e instanceof b},bt=function(e,t,n){pe[e]&&u(pe[e],(e=>{e.call(o,t,n,ct)}))},St=function(e){let t=null;if(bt("beforeSanitizeElements",e,null),At(e))return Tt(e),!0;const n=lt(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ne}),e.hasChildNodes()&&!Nt(e.firstElementChild)&&_(/<[/\w]/g,e.innerHTML)&&_(/<[/\w]/g,e.textContent))return Tt(e),!0;if(e.nodeType===J)return Tt(e),!0;if(Me&&e.nodeType===Q&&_(/<[/\w]/g,e.data))return Tt(e),!0;if(!Ne[n]||Ce[n]){if(!Ce[n]&&wt(n)){if(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n))return!1;if(we.tagNameCheck instanceof Function&&we.tagNameCheck(n))return!1}if(Ge&&!Xe[n]){const t=re(e)||e.parentNode,n=oe(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=X(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,ne(e))}}}return Tt(e),!0}return e instanceof R&&!function(e){let t=re(e);t&&t.tagName||(t={namespaceURI:tt,tagName:"template"});const n=f(e.tagName),o=f(t.tagName);return!!ot[e.namespaceURI]&&(e.namespaceURI===Qe?t.namespaceURI===et?"svg"===n:t.namespaceURI===Je?"svg"===n&&("annotation-xml"===o||pt[o]):Boolean(ht[n]):e.namespaceURI===Je?t.namespaceURI===et?"math"===n:t.namespaceURI===Qe?"math"===n&&ft[o]:Boolean(gt[n]):e.namespaceURI===et?!(t.namespaceURI===Qe&&!ft[o])&&!(t.namespaceURI===Je&&!pt[o])&&!gt[n]&&(dt[n]||!ht[n]):!("application/xhtml+xml"!==it||!ot[e.namespaceURI]))}(e)?(Tt(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!_(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Z&&(t=e.textContent,u([fe,de,he],(e=>{t=g(t,e," ")})),e.textContent!==t&&(p(o.removed,{element:e.cloneNode()}),e.textContent=t)),bt("afterSanitizeElements",e,null),!1):(Tt(e),!0)},Rt=function(e,t,n){if(Be&&("id"===t||"name"===t)&&(n in r||n in st))return!1;if(ve&&!Le[t]&&_(ge,t));else if(De&&_(Te,t));else if(!Se[t]||Le[t]){if(!(wt(e)&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,e)||we.tagNameCheck instanceof Function&&we.tagNameCheck(e))&&(we.attributeNameCheck instanceof RegExp&&_(we.attributeNameCheck,t)||we.attributeNameCheck instanceof Function&&we.attributeNameCheck(t))||"is"===t&&we.allowCustomizedBuiltInElements&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n)||we.tagNameCheck instanceof Function&&we.tagNameCheck(n))))return!1}else if(Ve[t]);else if(_(Ae,g(n,Ee,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!$e[e]){if(Oe&&!_(ye,g(n,Ee,"")));else if(n)return!1}else;return!0},wt=function(e){return"annotation-xml"!==e&&h(e,_e)},Ct=function(e){bt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Se};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=lt(a);let p="value"===a?c:y(c);if(n.attrName=s,n.attrValue=p,n.keepAttr=!0,n.forceKeepAttr=void 0,bt("uponSanitizeAttribute",e,n),p=n.attrValue,Me&&_(/((--!?|])>)|<\/(style|title)/i,p)){yt(a,e);continue}if(n.forceKeepAttr)continue;if(yt(a,e),!n.keepAttr)continue;if(!xe&&_(/\/>/i,p)){yt(a,e);continue}ke&&u([fe,de,he],(e=>{p=g(p,e," ")}));const f=lt(e.nodeName);if(Rt(f,s,p)){if(!We||"id"!==s&&"name"!==s||(yt(a,e),p="user-content-"+p),ie&&"object"==typeof G&&"function"==typeof G.getAttributeType)if(l);else switch(G.getAttributeType(f,s)){case"TrustedHTML":p=ie.createHTML(p);break;case"TrustedScriptURL":p=ie.createScriptURL(p)}try{l?e.setAttributeNS(l,a,p):e.setAttribute(a,p),At(e)?Tt(e):m(o.removed)}catch(e){}}}bt("afterSanitizeAttributes",e,null)},Lt=function e(t){let n=null;const o=_t(t);for(bt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)bt("uponSanitizeShadowNode",n,null),St(n)||(n.content instanceof s&&e(n.content),Ct(n));bt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(nt=!e,nt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Ue||mt(t),o.removed=[],"string"==typeof e&&(Ye=!1),Ye){if(e.nodeName){const t=lt(e.nodeName);if(!Ne[t]||Ce[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof b)n=Et("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===V&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!Ie&&-1===e.indexOf("<"))return ie&&ze?ie.createHTML(e):e;if(n=Et(e),!n)return Fe?null:ze?ae:""}n&&Pe&&Tt(n.firstChild);const c=_t(Ye?e:n);for(;i=c.nextNode();)St(i)||(i.content instanceof s&&Lt(i.content),Ct(i));if(Ye)return e;if(Fe){if(He)for(l=se.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Se.shadowroot||Se.shadowrootmode)&&(l=me.call(a,l,!0)),l}let m=Ie?n.outerHTML:n.innerHTML;return Ie&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&_(q,n.ownerDocument.doctype.name)&&(m="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+m),ke&&u([fe,de,he],(e=>{m=g(m,e," ")})),ie&&ze?ie.createHTML(m):m},o.setConfig=function(){mt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ue=!0},o.clearConfig=function(){ct=null,Ue=!1},o.isValidAttribute=function(e,t,n){ct||mt({});const o=lt(e),r=lt(t);return Rt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(pe[e]=pe[e]||[],p(pe[e],t))},o.removeHook=function(e){if(pe[e])return m(pe[e])},o.removeHooks=function(e){pe[e]&&(pe[e]=[])},o.removeAllHooks=function(){pe={}},o}();return ne})); 4//# sourceMappingURL=purify.min.js.map; 5// source --> https://vicasol.es/wp-content/plugins/fancybox-for-wordpress/assets/js/jquery.fancybox.js?ver
vendor: 89,065 bytes, lines 5-3122
5=1.3.4 6// ================================================== 7// fancyBox v3.5.7 8// 9// Licensed GPLv3 for open source use 10// or fancyBox Commercial License for commercial use 11// 12// http://fancyapps.com/fancybox/ 13// Copyright 2019 fancyApps 14// 15// ================================================== 16(function (window, document, $, undefined) { 17 "use strict"; 18 19 window.console = window.console || { 20 info: function (stuff) {} 21 }; 22 23 // If there's no jQuery, fancyBox can't work 24 // ========================================= 25 26 if (!$) { 27 return; 28 } 29 30 // Check if fancyBox is already initialized 31 // ======================================== 32 33 if ($.fn.fancyboxforwp) { 34 console.info("fancyBox already initialized"); 35 36 return; 37 } 38 39 // Private default settings 40 // ======================== 41 42 var defaults = { 43 // Close existing modals 44 // Set this to false if you do not need to stack multiple instances 45 closeExisting: false, 46 47 // Enable infinite gallery navigation 48 loop: false, 49 50 // Horizontal space between slides 51 gutter: 50, 52 53 // Enable keyboard navigation 54 keyboard: true, 55 56 // Should allow caption to overlap the content 57 preventCaptionOverlap: true, 58 59 // Should display navigation arrows at the screen edges 60 arrows: true, 61 62 // Should display counter at the top left corner 63 infobar: true, 64 65 // Should display close button (using `btnTpl.smallBtn` template) over the content 66 // Can be true, false, "auto" 67 // If "auto" - will be automatically enabled for "html", "inline" or "ajax" items 68 smallBtn: "auto", 69 70 // Should display toolbar (buttons at the top) 71 // Can be true, false, "auto" 72 // If "auto" - will be automatically hidden if "smallBtn" is enabled 73 toolbar: "auto", 74 75 // What buttons should appear in the top right corner. 76 // Buttons will be created using templates from `btnTpl` option 77 // and they will be placed into toolbar (class="fancybox-toolbar"` element) 78 buttons: [ 79 "zoom", 80 //"share", 81 "slideShow", 82 //"fullScreen", 83 //"download", 84 "thumbs", 85 "close" 86 ], 87 88 // Detect "idle" time in seconds 89 idleTime: 3, 90 91 // Disable right-click and use simple image protection for images 92 protect: false, 93 94 // Shortcut to make content "modal" - disable keyboard navigtion, hide buttons, etc 95 modal: false, 96 97 image: { 98 // Wait for images to load before displaying 99 // true - wait for image to load and then display; 100 // false - display thumbnail and load the full-sized image over top, 101 // requires predefined image dimensions (`data-width` and `data-height` attributes) 102 preload: false 103 }, 104 105 ajax: { 106 // Object containing settings for ajax request 107 settings: { 108 // This helps to indicate that request comes from the modal 109 // Feel free to change naming 110 data: { 111 fancybox: true 112 } 113 } 114 }, 115 116 iframe: { 117 // Iframe template 118 tpl: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>', 119 120 // Preload iframe before displaying it 121 // This allows to calculate iframe content width and height 122 // (note: Due to "Same Origin Policy", you can't get cross domain data). 123 preload: true, 124 125 // Custom CSS styling for iframe wrapping element 126 // You can use this to set custom iframe dimensions 127 css: {}, 128 129 // Iframe tag attributes 130 attr: { 131 scrolling: "auto" 132 } 133 }, 134 135 // For HTML5 video only 136 video: { 137 tpl: '<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}">' + 138 '<source src="{{src}}" type="{{format}}" />' + 139 'Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!' + 140 "</video>", 141 format: "", // custom video format 142 autoStart: true 143 }, 144 145 // Default content type if cannot be detected automatically 146 defaultType: "image", 147 148 // Open/close animation type 149 // Possible values: 150 // false - disable 151 // "zoom" - zoom images from/to thumbnail 152 // "fade" 153 // "zoom-in-out" 154 // 155 animationEffect: "zoom", 156 157 // Duration in ms for open/close animation 158 animationDuration: 366, 159 160 // Should image change opacity while zooming 161 // If opacity is "auto", then opacity will be changed if image and thumbnail have different aspect ratios 162 zoomOpacity: "auto", 163 164 // Transition effect between slides 165 // 166 // Possible values: 167 // false - disable 168 // "fade' 169 // "slide' 170 // "circular' 171 // "tube' 172 // "zoom-in-out' 173 // "rotate' 174 // 175 transitionEffect: "fade", 176 177 // Duration in ms for transition animation 178 transitionDuration: 366, 179 180 // Custom CSS class for slide element 181 slideClass: "", 182 183 // Custom CSS class for layout 184 baseClass: "", 185 186 // Base template for layout 187 baseTpl: '<div class="fancybox-container" role="dialog" tabindex="-1">' + 188 '<div class="fancybox-bg"></div>' + 189 '<div class="fancybox-inner">' + 190 '<div class="fancybox-infobar"><span data-fancybox-index></span> / <span data-fancybox-count></span></div>' + 191 '<div class="fancybox-toolbar">{{buttons}}</div>' + 192 '<div class="fancybox-navigation">{{arrows}}</div>' + 193 '<div class="fancybox-stage"></div>' + 194 '<div class="fancybox-caption"><div class="fancybox-caption__body"></div></div>' + 195 "</div>" + 196 "</div>", 197 198 // Loading indicator template 199 spinnerTpl: '<div class="fancybox-loading"></div>', 200 201 // Error message template 202 errorTpl: '<div class="fancybox-error"><p>{{ERROR}}</p></div>', 203 204 btnTpl: { 205 download: '<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;">' + 206 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg>' + 207 "</a>", 208 209 zoom: '<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}">' + 210 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg>' + 211 "</button>", 212 213 close: '<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}">' + 214 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg>' + 215 "</button>", 216 217 // Arrows 218 arrowLeft: '<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}">' + 219 '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div>' + 220 "</button>", 221 222 arrowRight: '<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}">' + 223 '<div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div>' + 224 "</button>", 225 226 // This small close button will be appended to your html/inline/ajax content by default, 227 // if "smallBtn" option is not set to false 228 smallBtn: '<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}">' + 229 '<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg>' + 230 "</button>" 231 }, 232 233 // Container is injected into this element 234 parentEl: "body", 235 236 // Hide browser vertical scrollbars; use at your own risk 237 hideScrollbar: true, 238 239 // Focus handling 240 // ============== 241 242 // Try to focus on the first focusable element after opening 243 autoFocus: true, 244 245 // Put focus back to active element after closing 246 backFocus: true, 247 248 // Do not let user to focus on element outside modal content 249 trapFocus: true, 250 251 // Module specific options 252 // ======================= 253 254 fullScreen: { 255 autoStart: false 256 }, 257 258 // Set `touch: false` to disable panning/swiping 259 touch: { 260 vertical: true, // Allow to drag content vertically 261 momentum: true // Continue movement after releasing mouse/touch when panning 262 }, 263 264 // Hash value when initializing manually, 265 // set `false` to disable hash change 266 hash: null, 267 268 // Customize or add new media types 269 // Example: 270 /* 271 media : { 272 youtube : { 273 params : { 274 autoplay : 0 275 } 276 } 277 } 278 */ 279 media: {}, 280 281 slideShow: { 282 autoStart: false, 283 speed: 3000 284 }, 285 286 thumbs: { 287 autoStart: false, // Display thumbnails on opening 288 hideOnClose: true, // Hide thumbnail grid when closing animation starts 289 parentEl: ".fancybox-container", // Container is injected into this element 290 axis: "y" // Vertical (y) or horizontal (x) scrolling 291 }, 292 293 // Use mousewheel to navigate gallery 294 // If 'auto' - enabled for images only 295 wheel: "auto", 296 297 // Callbacks 298 //========== 299 300 // See Documentation/API/Events for more information 301 // Example: 302 /* 303 afterShow: function( instance, current ) { 304 console.info( 'Clicked element:' ); 305 console.info( current.opts.$orig ); 306 } 307 */ 308 309 onInit: $.noop, // When instance has been initialized 310 311 beforeLoad: $.noop, // Before the content of a slide is being loaded 312 afterLoad: $.noop, // When the content of a slide is done loading 313 314 beforeShow: $.noop, // Before open animation starts 315 afterShow: $.noop, // When content is done loading and animating 316 317 beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close. 318 afterClose: $.noop, // After instance has been closed 319 320 onActivate: $.noop, // When instance is brought to front 321 onDeactivate: $.noop, // When other instance has been activated 322 323 // Interaction 324 // =========== 325 326 // Use options below to customize taken action when user clicks or double clicks on the fancyBox area, 327 // each option can be string or method that returns value. 328 // 329 // Possible values: 330 // "close" - close instance 331 // "next" - move to next gallery item 332 // "nextOrClose" - move to next gallery item or close if gallery has only one item 333 // "toggleControls" - show/hide controls 334 // "zoom" - zoom image (if loaded) 335 // false - do nothing 336 337 // Clicked on the content 338 clickContent: function (current, event) { 339 return current.type === "image" ? "zoom" : false; 340 }, 341 342 // Clicked on the slide 343 clickSlide: "close", 344 345 // Clicked on the background (backdrop) element; 346 // if you have not changed the layout, then most likely you need to use `clickSlide` option 347 clickOutside: "close", 348 349 // Same as previous two, but for double click 350 dblclickContent: false, 351 dblclickSlide: false, 352 dblclickOutside: false, 353 354 // Custom options when mobile device is detected 355 // ============================================= 356 357 mobile: { 358 preventCaptionOverlap: false, 359 idleTime: false, 360 clickContent: function (current, event) { 361 return current.type === "image" ? "toggleControls" : false; 362 }, 363 clickSlide: function (current, event) { 364 return current.type === "image" ? "toggleControls" : "close"; 365 }, 366 dblclickContent: function (current, event) { 367 return current.type === "image" ? "zoom" : false; 368 }, 369 dblclickSlide: function (current, event) { 370 return current.type === "image" ? "zoom" : false; 371 } 372 }, 373 374 // Internationalization 375 // ==================== 376 377 lang: "en", 378 i18n: { 379 en: { 380 CLOSE: "Close", 381 NEXT: "Next", 382 PREV: "Previous", 383 ERROR: "The requested content cannot be loaded. <br/> Please try again later.", 384 PLAY_START: "Start slideshow", 385 PLAY_STOP: "Pause slideshow", 386 FULL_SCREEN: "Full screen", 387 THUMBS: "Thumbnails", 388 DOWNLOAD: "Download", 389 SHARE: "Share", 390 ZOOM: "Zoom" 391 }, 392 de: { 393 CLOSE: "Schließen", 394 NEXT: "Weiter", 395 PREV: "Zurück", 396 ERROR: "Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.", 397 PLAY_START: "Diaschau starten", 398 PLAY_STOP: "Diaschau beenden", 399 FULL_SCREEN: "Vollbild", 400 THUMBS: "Vorschaubilder", 401 DOWNLOAD: "Herunterladen", 402 SHARE: "Teilen", 403 ZOOM: "Vergrößern" 404 } 405 } 406 }; 407 408 // Few useful variables and methods 409 // ================================ 410 411 var $W = $(window); 412 var $D = $(document); 413 414 var called = 0; 415 416 // Check if an object is a jQuery object and not a native JavaScript object 417 // ======================================================================== 418 var isQuery = function (obj) { 419 return obj && obj.hasOwnProperty && obj instanceof $; 420 }; 421 422 // Handle multiple browsers for "requestAnimationFrame" and "cancelAnimationFrame" 423 // =============================================================================== 424 var requestAFrame = (function () { 425 return ( 426 window.requestAnimationFrame || 427 window.webkitRequestAnimationFrame || 428 window.mozRequestAnimationFrame || 429 window.oRequestAnimationFrame || 430 // if all else fails, use setTimeout 431 function (callback) { 432 return window.setTimeout(callback, 1000 / 60); 433 } 434 ); 435 })(); 436 437 var cancelAFrame = (function () { 438 return ( 439 window.cancelAnimationFrame || 440 window.webkitCancelAnimationFrame || 441 window.mozCancelAnimationFrame || 442 window.oCancelAnimationFrame || 443 function (id) { 444 window.clearTimeout(id); 445 } 446 ); 447 })(); 448 449 // Detect the supported transition-end event property name 450 // ======================================================= 451 var transitionEnd = (function () { 452 var el = document.createElement("fakeelement"), 453 t; 454 455 var transitions = { 456 transition: "transitionend", 457 OTransition: "oTransitionEnd", 458 MozTransition: "transitionend", 459 WebkitTransition: "webkitTransitionEnd" 460 }; 461 462 for (t in transitions) { 463 if (el.style[t] !== undefined) { 464 return transitions[t]; 465 } 466 } 467 468 return "transitionend"; 469 })(); 470 471 // Force redraw on an element. 472 // This helps in cases where the browser doesn't redraw an updated element properly 473 // ================================================================================ 474 var forceRedraw = function ($el) { 475 return $el && $el.length && $el[0].offsetHeight; 476 }; 477 478 // Exclude array (`buttons`) options from deep merging 479 // =================================================== 480 var mergeOpts = function (opts1, opts2) { 481 var rez = $.extend(true, {}, opts1, opts2); 482 483 $.each(opts2, function (key, value) { 484 if ($.isArray(value)) { 485 rez[key] = value; 486 } 487 }); 488 489 return rez; 490 }; 491 492 // How much of an element is visible in viewport 493 // ============================================= 494 495 var inViewport = function (elem) { 496 var elemCenter, rez; 497 498 if (!elem || elem.ownerDocument !== document) { 499 return false; 500 } 501 502 $(".fancybox-container").css("pointer-events", "none"); 503 504 elemCenter = { 505 x: elem.getBoundingClientRect().left + elem.offsetWidth / 2, 506 y: elem.getBoundingClientRect().top + elem.offsetHeight / 2 507 }; 508 509 rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem; 510 511 $(".fancybox-container").css("pointer-events", ""); 512 513 return rez; 514 }; 515 516 // Class definition 517 // ================ 518 519 var FancyBox = function (content, opts, index) { 520 var self = this; 521 522 self.opts = mergeOpts({ 523 index: index 524 }, $.fancyboxforwp.defaults); 525 526 if ($.isPlainObject(opts)) { 527 self.opts = mergeOpts(self.opts, opts); 528 } 529 530 if ($.fancyboxforwp.isMobile) { 531 self.opts = mergeOpts(self.opts, self.opts.mobile); 532 } 533 534 self.id = self.opts.id || ++called; 535 536 self.currIndex = parseInt(self.opts.index, 10) || 0; 537 self.prevIndex = null; 538 539 self.prevPos = null; 540 self.currPos = 0; 541 542 self.firstRun = true; 543 544 // All group items 545 self.group = []; 546 547 // Existing slides (for current, next and previous gallery items) 548 self.slides = {}; 549 550 // Create group elements 551 self.addContent(content); 552 553 if (!self.group.length) { 554 return; 555 } 556 557 self.init(); 558 }; 559 560 $.extend(FancyBox.prototype, { 561 // Create DOM structure 562 // ==================== 563 564 init: function () { 565 var self = this, 566 firstItem = self.group[self.currIndex], 567 firstItemOpts = firstItem.opts, 568 $container, 569 buttonStr; 570 571 if (firstItemOpts.closeExisting) { 572 $.fancyboxforwp.close(true); 573 } 574 575 // Hide scrollbars 576 // =============== 577 578 $("body").addClass("fancybox-active"); 579 580 if ( 581 !$.fancyboxforwp.getInstance() && 582 firstItemOpts.hideScrollbar !== false && 583 !$.fancyboxforwp.isMobile && 584 document.body.scrollHeight > window.innerHeight 585 ) { 586 $("head").append( 587 '<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:' + 588 (window.innerWidth - document.documentElement.clientWidth) + 589 "px;}</style>" 590 ); 591 592 $("body").addClass("compensate-for-scrollbar"); 593 } 594 595 // Build html markup and set references 596 // ==================================== 597 598 // Build html code for buttons and insert into main template 599 buttonStr = ""; 600 601 $.each(firstItemOpts.buttons, function (index, value) { 602 buttonStr += firstItemOpts.btnTpl[value] || ""; 603 }); 604 605 // Create markup from base template, it will be initially hidden to 606 // avoid unnecessary work like painting while initializing is not complete 607 $container = $( 608 self.translate( 609 self, 610 firstItemOpts.baseTpl 611 .replace("{{buttons}}", buttonStr) 612 .replace("{{arrows}}", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight) 613 ) 614 ) 615 .attr("id", "fancybox-container-" + self.id) 616 .addClass(firstItemOpts.baseClass) 617 .data("FancyBox", self) 618 .appendTo(firstItemOpts.parentEl); 619 620 // Create object holding references to jQuery wrapped nodes 621 self.$refs = { 622 container: $container 623 }; 624 625 ["bg", "inner", "infobar", "toolbar", "stage", "caption", "navigation"].forEach(function (item) { 626 self.$refs[item] = $container.find(".fancybox-" + item); 627 }); 628 629 self.trigger("onInit"); 630 631 // Enable events, deactive previous instances 632 self.activate(); 633 634 // Build slides, load and reveal content 635 self.jumpTo(self.currIndex); 636 }, 637 638 // Simple i18n support - replaces object keys found in template 639 // with corresponding values 640 // ============================================================ 641 642 translate: function (obj, str) { 643 var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en; 644 645 return str.replace(/\{\{(\w+)\}\}/g, function (match, n) { 646 return arr[n] === undefined ? match : arr[n]; 647 }); 648 }, 649 650 // Populate current group with fresh content 651 // Check if each object has valid type and content 652 // =============================================== 653 654 addContent: function (content) { 655 var self = this, 656 items = $.makeArray(content), 657 thumbs; 658 659 $.each(items, function (i, item) { 660 var obj = {}, 661 opts = {}, 662 $item, 663 type, 664 found, 665 src, 666 srcParts; 667 668 // Step 1 - Make sure we have an object 669 // ==================================== 670 671 if ($.isPlainObject(item)) { 672 // We probably have manual usage here, something like 673 // $.fancyboxforwp.open( [ { src : "image.jpg", type : "image" } ] ) 674 675 obj = item; 676 opts = item.opts || item; 677 } else if ($.type(item) === "object" && $(item).length) { 678 // Here we probably have jQuery collection returned by some selector 679 $item = $(item); 680 681 // Support attributes like `data-options='{"touch" : false}'` and `data-touch='false'` 682 opts = $item.data() || {}; 683 opts = $.extend(true, {}, opts, opts.options); 684 685 // Here we store clicked element 686 opts.$orig = $item; 687 688 obj.src = self.opts.src || opts.src || $item.attr("href"); 689 690 // Assume that simple syntax is used, for example: 691 // `$.fancyboxforwp.open( $("#test"), {} );` 692 if (!obj.type && !obj.src) { 693 obj.type = "inline"; 694 obj.src = item; 695 } 696 } else { 697 // Assume we have a simple html code, for example: 698 // $.fancyboxforwp.open( '<div><h1>Hi!</h1></div>' ); 699 obj = { 700 type: "html", 701 src: item + "" 702 }; 703 } 704 705 // Each gallery object has full collection of options 706 obj.opts = $.extend(true, {}, self.opts, opts); 707 708 // Do not merge buttons array 709 if ($.isArray(opts.buttons)) { 710 obj.opts.buttons = opts.buttons; 711 } 712 713 if ($.fancyboxforwp.isMobile && obj.opts.mobile) { 714 obj.opts = mergeOpts(obj.opts, obj.opts.mobile); 715 } 716 717 // Step 2 - Make sure we have content type, if not - try to guess 718 // ============================================================== 719 720 type = obj.type || obj.opts.type; 721 src = obj.src || ""; 722 723 if (!type && src) { 724 if ((found = src.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))) { 725 type = "video"; 726 727 if (!obj.opts.video.format) { 728 obj.opts.video.format = "video/" + (found[1] === "ogv" ? "ogg" : found[1]); 729 } 730 } else if (src.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)) { 731 type = "image"; 732 } else if (src.match(/\.(pdf)((\?|#).*)?$/i)) { 733 type = "iframe"; 734 obj = $.extend(true, obj, { 735 contentType: "pdf", 736 opts: { 737 iframe: { 738 preload: false 739 } 740 } 741 }); 742 } else if (src.charAt(0) === "#") { 743 type = "inline"; 744 } 745 } 746 747 if (type) { 748 obj.type = type; 749 } else { 750 self.trigger("objectNeedsType", obj); 751 } 752 753 if (!obj.contentType) { 754 obj.contentType = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1 ? "html" : obj.type; 755 } 756 757 // Step 3 - Some adjustments 758 // ========================= 759 760 obj.index = self.group.length; 761 762 if (obj.opts.smallBtn == "auto") { 763 obj.opts.smallBtn = $.inArray(obj.type, ["html", "inline", "ajax"]) > -1; 764 } 765 766 if (obj.opts.toolbar === "auto") { 767 obj.opts.toolbar = !obj.opts.smallBtn; 768 } 769 770 // Find thumbnail image, check if exists and if is in the viewport 771 obj.$thumb = obj.opts.$thumb || null; 772 773 if (obj.opts.$trigger && obj.index === self.opts.index) { 774 obj.$thumb = obj.opts.$trigger.find("img:first"); 775 776 if (obj.$thumb.length) { 777 obj.opts.$orig = obj.opts.$trigger; 778 } 779 } 780 781 if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) { 782 obj.$thumb = obj.opts.$orig.find("img:first"); 783 } 784 785 if (obj.$thumb && !obj.$thumb.length) { 786 obj.$thumb = null; 787 } 788 789 obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null); 790 791 // "caption" is a "special" option, it can be used to customize caption per gallery item 792 if ($.type(obj.opts.caption) === "function") { 793 obj.opts.caption = obj.opts.caption.apply(item, [self, obj]); 794 } 795 796 if ($.type(self.opts.caption) === "function") { 797 obj.opts.caption = self.opts.caption.apply(item, [self, obj]); 798 } 799 800 // Make sure we have caption as a string or jQuery object 801 if (!(obj.opts.caption instanceof $)) { 802 obj.opts.caption = obj.opts.caption === undefined ? "" : obj.opts.caption + ""; 803 } 804 805 // Check if url contains "filter" used to filter the content 806 // Example: "ajax.html #something" 807 if (obj.type === "ajax") { 808 srcParts = src.split(/\s+/, 2); 809 810 if (srcParts.length > 1) { 811 obj.src = srcParts.shift(); 812 813 obj.opts.filter = srcParts.shift(); 814 } 815 } 816 817 // Hide all buttons and disable interactivity for modal items 818 if (obj.opts.modal) { 819 obj.opts = $.extend(true, obj.opts, { 820 trapFocus: true, 821 // Remove buttons 822 infobar: 0, 823 toolbar: 0, 824 825 smallBtn: 0, 826 827 // Disable keyboard navigation 828 keyboard: 0, 829 830 // Disable some modules 831 slideShow: 0, 832 fullScreen: 0, 833 thumbs: 0, 834 touch: 0, 835 836 // Disable click event handlers 837 clickContent: false, 838 clickSlide: false, 839 clickOutside: false, 840 dblclickContent: false, 841 dblclickSlide: false, 842 dblclickOutside: false 843 }); 844 } 845 846 // Step 4 - Add processed object to group 847 // ====================================== 848 849 self.group.push(obj); 850 }); 851 852 // Update controls if gallery is already opened 853 if (Object.keys(self.slides).length) { 854 self.updateControls(); 855 856 // Update thumbnails, if needed 857 thumbs = self.Thumbs; 858 859 if (thumbs && thumbs.isActive) { 860 thumbs.create(); 861 862 thumbs.focus(); 863 } 864 } 865 }, 866 867 // Attach an event handler functions for: 868 // - navigation buttons 869 // - browser scrolling, resizing; 870 // - focusing 871 // - keyboard 872 // - detecting inactivity 873 // ====================================== 874 875 addEvents: function () { 876 var self = this; 877 878 self.removeEvents(); 879 880 // Make navigation elements clickable 881 // ================================== 882 883 self.$refs.container 884 .on("click.fb-close", "[data-fancybox-close]", function (e) { 885 e.stopPropagation(); 886 e.preventDefault(); 887 888 self.close(e); 889 }) 890 .on("touchstart.fb-prev click.fb-prev", "[data-fancybox-prev]", function (e) { 891 e.stopPropagation(); 892 e.preventDefault(); 893 894 self.previous(); 895 }) 896 .on("touchstart.fb-next click.fb-next", "[data-fancybox-next]", function (e) { 897 e.stopPropagation(); 898 e.preventDefault(); 899 900 self.next(); 901 }) 902 .on("click.fb", "[data-fancybox-zoom]", function (e) { 903 // Click handler for zoom button 904 self[self.isScaledDown() ? "scaleToActual" : "scaleToFit"](); 905 }); 906 907 // Handle page scrolling and browser resizing 908 // ========================================== 909 910 $W.on("orientationchange.fb resize.fb", function (e) { 911 if (e && e.originalEvent && e.originalEvent.type === "resize") { 912 if (self.requestId) { 913 cancelAFrame(self.requestId); 914 } 915 916 self.requestId = requestAFrame(function () { 917 self.update(e); 918 }); 919 } else { 920 if (self.current && self.current.type === "iframe") { 921 self.$refs.stage.hide(); 922 } 923 924 setTimeout( 925 function () { 926 self.$refs.stage.show(); 927 928 self.update(e); 929 }, 930 $.fancyboxforwp.isMobile ? 600 : 250 931 ); 932 } 933 }); 934 935 $D.on("keydown.fb", function (e) { 936 var instance = $.fancyboxforwp ? $.fancyboxforwp.getInstance() : null, 937 current = instance.current, 938 keycode = e.keyCode || e.which; 939 940 // Trap keyboard focus inside of the modal 941 // ======================================= 942 943 if (keycode == 9) { 944 if (current.opts.trapFocus) { 945 self.focus(e); 946 } 947 948 return; 949 } 950 951 // Enable keyboard navigation 952 // ========================== 953 954 if (!current.opts.keyboard || e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is("input,textarea,video,audio,select")) { 955 return; 956 } 957 958 // Backspace and Esc keys 959 if (keycode === 8 || keycode === 27) { 960 e.preventDefault(); 961 962 self.close(e); 963 964 return; 965 } 966 967 // Left arrow and Up arrow 968 if (keycode === 37 || keycode === 38) { 969 e.preventDefault(); 970 971 self.previous(); 972 973 return; 974 } 975 976 // Righ arrow and Down arrow 977 if (keycode === 39 || keycode === 40) { 978 e.preventDefault(); 979 980 self.next(); 981 982 return; 983 } 984 985 self.trigger("afterKeydown", e, keycode); 986 }); 987 988 // Hide controls after some inactivity period 989 if (self.group[self.currIndex].opts.idleTime) { 990 self.idleSecondsCounter = 0; 991 992 $D.on( 993 "mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle", 994 function (e) { 995 self.idleSecondsCounter = 0; 996 997 if (self.isIdle) { 998 self.showControls(); 999 } 1000 1001 self.isIdle = false; 1002 } 1003 ); 1004 1005 self.idleInterval = window.setInterval(function () { 1006 self.idleSecondsCounter++; 1007 1008 if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) { 1009 self.isIdle = true; 1010 self.idleSecondsCounter = 0; 1011 1012 self.hideControls(); 1013 } 1014 }, 1000); 1015 } 1016 }, 1017 1018 // Remove events added by the core 1019 // =============================== 1020 1021 removeEvents: function () { 1022 var self = this; 1023 1024 $W.off("orientationchange.fb resize.fb"); 1025 $D.off("keydown.fb .fb-idle"); 1026 1027 this.$refs.container.off(".fb-close .fb-prev .fb-next"); 1028 1029 if (self.idleInterval) { 1030 window.clearInterval(self.idleInterval); 1031 1032 self.idleInterval = null; 1033 } 1034 }, 1035 1036 // Change to previous gallery item 1037 // =============================== 1038 1039 previous: function (duration) { 1040 return this.jumpTo(this.currPos - 1, duration); 1041 }, 1042 1043 // Change to next gallery item 1044 // =========================== 1045 1046 next: function (duration) { 1047 return this.jumpTo(this.currPos + 1, duration); 1048 }, 1049 1050 // Switch to selected gallery item 1051 // =============================== 1052 1053 jumpTo: function (pos, duration) { 1054 var self = this, 1055 groupLen = self.group.length, 1056 firstRun, 1057 isMoved, 1058 loop, 1059 current, 1060 previous, 1061 slidePos, 1062 stagePos, 1063 prop, 1064 diff; 1065 1066 if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) { 1067 return; 1068 } 1069 1070 // Should loop? 1071 pos = parseInt(pos, 10); 1072 loop = self.current ? self.current.opts.loop : self.opts.loop; 1073 1074 if (!loop && (pos < 0 || pos >= groupLen)) { 1075 return false; 1076 } 1077 1078 // Check if opening for the first time; this helps to speed things up 1079 firstRun = self.firstRun = !Object.keys(self.slides).length; 1080 1081 // Create slides 1082 previous = self.current; 1083 1084 self.prevIndex = self.currIndex; 1085 self.prevPos = self.currPos; 1086 1087 current = self.createSlide(pos); 1088 1089 if (groupLen > 1) { 1090 if (loop || current.index < groupLen - 1) { 1091 self.createSlide(pos + 1); 1092 } 1093 1094 if (loop || current.index > 0) { 1095 self.createSlide(pos - 1); 1096 } 1097 } 1098 1099 self.current = current; 1100 self.currIndex = current.index; 1101 self.currPos = current.pos; 1102 1103 self.trigger("beforeShow", firstRun); 1104 1105 self.updateControls(); 1106 1107 // Validate duration length 1108 current.forcedDuration = undefined; 1109 1110 if ($.isNumeric(duration)) { 1111 current.forcedDuration = duration; 1112 } else { 1113 duration = current.opts[firstRun ? "animationDuration" : "transitionDuration"]; 1114 } 1115 1116 duration = parseInt(duration, 10); 1117 1118 // Check if user has swiped the slides or if still animating 1119 isMoved = self.isMoved(current); 1120 1121 // Make sure current slide is visible 1122 current.$slide.addClass("fancybox-slide--current"); 1123 1124 // Fresh start - reveal container, current slide and start loading content 1125 if (firstRun) { 1126 if (current.opts.animationEffect && duration) { 1127 self.$refs.container.css("transition-duration", duration + "ms"); 1128 } 1129 1130 self.$refs.container.addClass("fancybox-is-open").trigger("focus"); 1131 1132 // Attempt to load content into slide 1133 // This will later call `afterLoad` -> `revealContent` 1134 self.loadSlide(current); 1135 1136 self.preload("image"); 1137 1138 return; 1139 } 1140 1141 // Get actual slide/stage positions (before cleaning up) 1142 slidePos = $.fancyboxforwp.getTranslate(previous.$slide); 1143 stagePos = $.fancyboxforwp.getTranslate(self.$refs.stage); 1144 1145 // Clean up all slides 1146 $.each(self.slides, function (index, slide) { 1147 $.fancyboxforwp.stop(slide.$slide, true); 1148 }); 1149 1150 if (previous.pos !== current.pos) { 1151 previous.isComplete = false; 1152 } 1153 1154 previous.$slide.removeClass("fancybox-slide--complete fancybox-slide--current"); 1155 1156 // If slides are out of place, then animate them to correct position 1157 if (isMoved) { 1158 // Calculate horizontal swipe distance 1159 diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter); 1160 1161 $.each(self.slides, function (index, slide) { 1162 slide.$slide.removeClass("fancybox-animated").removeClass(function (index, className) { 1163 return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); 1164 }); 1165 1166 // Make sure that each slide is in equal distance 1167 // This is mostly needed for freshly added slides, because they are not yet positioned 1168 var leftPos = slide.pos * slidePos.width + slide.pos * slide.opts.gutter; 1169 1170 $.fancyboxforwp.setTranslate(slide.$slide, { 1171 top: 0, 1172 left: leftPos - stagePos.left + diff 1173 }); 1174 1175 if (slide.pos !== current.pos) { 1176 slide.$slide.addClass("fancybox-slide--" + (slide.pos > current.pos ? "next" : "previous")); 1177 } 1178 1179 // Redraw to make sure that transition will start 1180 forceRedraw(slide.$slide); 1181 1182 // Animate the slide 1183 $.fancyboxforwp.animate( 1184 slide.$slide, { 1185 top: 0, 1186 left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter 1187 }, 1188 duration, 1189 function () { 1190 slide.$slide 1191 .css({ 1192 transform: "", 1193 opacity: "" 1194 }) 1195 .removeClass("fancybox-slide--next fancybox-slide--previous"); 1196 1197 if (slide.pos === self.currPos) { 1198 self.complete(); 1199 } 1200 } 1201 ); 1202 }); 1203 } else if (duration && current.opts.transitionEffect) { 1204 // Set transition effect for previously active slide 1205 prop = "fancybox-animated fancybox-fx-" + current.opts.transitionEffect; 1206 1207 previous.$slide.addClass("fancybox-slide--" + (previous.pos > current.pos ? "next" : "previous")); 1208 1209 $.fancyboxforwp.animate( 1210 previous.$slide, 1211 prop, 1212 duration, 1213 function () { 1214 previous.$slide.removeClass(prop).removeClass("fancybox-slide--next fancybox-slide--previous"); 1215 }, 1216 false 1217 ); 1218 } 1219 1220 if (current.isLoaded) { 1221 self.revealContent(current); 1222 } else { 1223 self.loadSlide(current); 1224 } 1225 1226 self.preload("image"); 1227 }, 1228 1229 // Create new "slide" element 1230 // These are gallery items that are actually added to DOM 1231 // ======================================================= 1232 1233 createSlide: function (pos) { 1234 var self = this, 1235 $slide, 1236 index; 1237 1238 index = pos % self.group.length; 1239 index = index < 0 ? self.group.length + index : index; 1240 1241 if (!self.slides[pos] && self.group[index]) { 1242 $slide = $('<div class="fancybox-slide"></div>').appendTo(self.$refs.stage); 1243 1244 self.slides[pos] = $.extend(true, {}, self.group[index], { 1245 pos: pos, 1246 $slide: $slide, 1247 isLoaded: false 1248 }); 1249 1250 self.updateSlide(self.slides[pos]); 1251 } 1252 1253 return self.slides[pos]; 1254 }, 1255 1256 // Scale image to the actual size of the image; 1257 // x and y values should be relative to the slide 1258 // ============================================== 1259 1260 scaleToActual: function (x, y, duration) { 1261 var self = this, 1262 current = self.current, 1263 $content = current.$content, 1264 canvasWidth = $.fancyboxforwp.getTranslate(current.$slide).width, 1265 canvasHeight = $.fancyboxforwp.getTranslate(current.$slide).height, 1266 newImgWidth = current.width, 1267 newImgHeight = current.height, 1268 imgPos, 1269 posX, 1270 posY, 1271 scaleX, 1272 scaleY; 1273 1274 if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) { 1275 return; 1276 } 1277 1278 self.isAnimating = true; 1279 1280 $.fancyboxforwp.stop($content); 1281 1282 x = x === undefined ? canvasWidth * 0.5 : x; 1283 y = y === undefined ? canvasHeight * 0.5 : y; 1284 1285 imgPos = $.fancyboxforwp.getTranslate($content); 1286 1287 imgPos.top -= $.fancyboxforwp.getTranslate(current.$slide).top; 1288 imgPos.left -= $.fancyboxforwp.getTranslate(current.$slide).left; 1289 1290 scaleX = newImgWidth / imgPos.width; 1291 scaleY = newImgHeight / imgPos.height; 1292 1293 // Get center position for original image 1294 posX = canvasWidth * 0.5 - newImgWidth * 0.5; 1295 posY = canvasHeight * 0.5 - newImgHeight * 0.5; 1296 1297 // Make sure image does not move away from edges 1298 if (newImgWidth > canvasWidth) { 1299 posX = imgPos.left * scaleX - (x * scaleX - x); 1300 1301 if (posX > 0) { 1302 posX = 0; 1303 } 1304 1305 if (posX < canvasWidth - newImgWidth) { 1306 posX = canvasWidth - newImgWidth; 1307 } 1308 } 1309 1310 if (newImgHeight > canvasHeight) { 1311 posY = imgPos.top * scaleY - (y * scaleY - y); 1312 1313 if (posY > 0) { 1314 posY = 0; 1315 } 1316 1317 if (posY < canvasHeight - newImgHeight) { 1318 posY = canvasHeight - newImgHeight; 1319 } 1320 } 1321 1322 self.updateCursor(newImgWidth, newImgHeight); 1323 1324 $.fancyboxforwp.animate( 1325 $content, { 1326 top: posY, 1327 left: posX, 1328 scaleX: scaleX, 1329 scaleY: scaleY 1330 }, 1331 duration || 366, 1332 function () { 1333 self.isAnimating = false; 1334 } 1335 ); 1336 1337 // Stop slideshow 1338 if (self.SlideShow && self.SlideShow.isActive) { 1339 self.SlideShow.stop(); 1340 } 1341 }, 1342 1343 // Scale image to fit inside parent element 1344 // ======================================== 1345 1346 scaleToFit: function (duration) { 1347 var self = this, 1348 current = self.current, 1349 $content = current.$content, 1350 end; 1351 1352 if (self.isAnimating || self.isMoved() || !$content || !(current.type == "image" && current.isLoaded && !current.hasError)) { 1353 return; 1354 } 1355 1356 self.isAnimating = true; 1357 1358 $.fancyboxforwp.stop($content); 1359 1360 end = self.getFitPos(current); 1361 1362 self.updateCursor(end.width, end.height); 1363 1364 $.fancyboxforwp.animate( 1365 $content, { 1366 top: end.top, 1367 left: end.left, 1368 scaleX: end.width / $content.width(), 1369 scaleY: end.height / $content.height() 1370 }, 1371 duration || 366, 1372 function () { 1373 self.isAnimating = false; 1374 } 1375 ); 1376 }, 1377 1378 // Calculate image size to fit inside viewport 1379 // =========================================== 1380 1381 getFitPos: function (slide) { 1382 var self = this, 1383 $content = slide.$content, 1384 $slide = slide.$slide, 1385 width = slide.width || slide.opts.width, 1386 height = slide.height || slide.opts.height, 1387 maxWidth, 1388 maxHeight, 1389 minRatio, 1390 aspectRatio, 1391 rez = {}; 1392 1393 if (!slide.isLoaded || !$content || !$content.length) { 1394 return false; 1395 } 1396 1397 maxWidth = $.fancyboxforwp.getTranslate(self.$refs.stage).width; 1398 maxHeight = $.fancyboxforwp.getTranslate(self.$refs.stage).height; 1399 1400 maxWidth -= 1401 parseFloat($slide.css("paddingLeft")) + 1402 parseFloat($slide.css("paddingRight")) + 1403 parseFloat($content.css("marginLeft")) + 1404 parseFloat($content.css("marginRight")); 1405 1406 maxHeight -= 1407 parseFloat($slide.css("paddingTop")) + 1408 parseFloat($slide.css("paddingBottom")) + 1409 parseFloat($content.css("marginTop")) + 1410 parseFloat($content.css("marginBottom")); 1411 1412 if (!width || !height) { 1413 width = maxWidth; 1414 height = maxHeight; 1415 } 1416 1417 minRatio = Math.min(1, maxWidth / width, maxHeight / height); 1418 1419 width = minRatio * width; 1420 height = minRatio * height; 1421 1422 // Adjust width/height to precisely fit into container 1423 if (width > maxWidth - 0.5) { 1424 width = maxWidth; 1425 } 1426 1427 if (height > maxHeight - 0.5) { 1428 height = maxHeight; 1429 } 1430 1431 if (slide.type === "image") { 1432 rez.top = Math.floor((maxHeight - height) * 0.5) + parseFloat($slide.css("paddingTop")); 1433 rez.left = Math.floor((maxWidth - width) * 0.5) + parseFloat($slide.css("paddingLeft")); 1434 } else if (slide.contentType === "video") { 1435 // Force aspect ratio for the video 1436 // "I say the whole world must learn of our peaceful ways… by force!" 1437 aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9; 1438 1439 if (height > width / aspectRatio) { 1440 height = width / aspectRatio; 1441 } else if (width > height * aspectRatio) { 1442 width = height * aspectRatio; 1443 } 1444 } 1445 1446 rez.width = width; 1447 rez.height = height; 1448 1449 return rez; 1450 }, 1451 1452 // Update content size and position for all slides 1453 // ============================================== 1454 1455 update: function (e) { 1456 var self = this; 1457 1458 $.each(self.slides, function (key, slide) { 1459 self.updateSlide(slide, e); 1460 }); 1461 }, 1462 1463 // Update slide content position and size 1464 // ====================================== 1465 1466 updateSlide: function (slide, e) { 1467 var self = this, 1468 $content = slide && slide.$content, 1469 width = slide.width || slide.opts.width, 1470 height = slide.height || slide.opts.height, 1471 $slide = slide.$slide; 1472 1473 // First, prevent caption overlap, if needed 1474 self.adjustCaption(slide); 1475 1476 // Then resize content to fit inside the slide 1477 if ($content && (width || height || slide.contentType === "video") && !slide.hasError) { 1478 $.fancyboxforwp.stop($content); 1479 1480 $.fancyboxforwp.setTranslate($content, self.getFitPos(slide)); 1481 1482 if (slide.pos === self.currPos) { 1483 self.isAnimating = false; 1484 1485 self.updateCursor(); 1486 } 1487 } 1488 1489 // Then some adjustments 1490 self.adjustLayout(slide); 1491 1492 if ($slide.length) { 1493 $slide.trigger("refresh"); 1494 1495 if (slide.pos === self.currPos) { 1496 self.$refs.toolbar 1497 .add(self.$refs.navigation.find(".fancybox-button--arrow_right")) 1498 .toggleClass("compensate-for-scrollbar", $slide.get(0).scrollHeight > $slide.get(0).clientHeight); 1499 } 1500 } 1501 1502 self.trigger("onUpdate", slide, e); 1503 }, 1504 1505 // Horizontally center slide 1506 // ========================= 1507 1508 centerSlide: function (duration) { 1509 var self = this, 1510 current = self.current, 1511 $slide = current.$slide; 1512 1513 if (self.isClosing || !current) { 1514 return; 1515 } 1516 1517 $slide.siblings().css({ 1518 transform: "", 1519 opacity: "" 1520 }); 1521 1522 $slide 1523 .parent() 1524 .children() 1525 .removeClass("fancybox-slide--previous fancybox-slide--next"); 1526 1527 $.fancyboxforwp.animate( 1528 $slide, { 1529 top: 0, 1530 left: 0, 1531 opacity: 1 1532 }, 1533 duration === undefined ? 0 : duration, 1534 function () { 1535 // Clean up 1536 $slide.css({ 1537 transform: "", 1538 opacity: "" 1539 }); 1540 1541 if (!current.isComplete) { 1542 self.complete(); 1543 } 1544 }, 1545 false 1546 ); 1547 }, 1548 1549 // Check if current slide is moved (swiped) 1550 // ======================================== 1551 1552 isMoved: function (slide) { 1553 var current = slide || this.current, 1554 slidePos, 1555 stagePos; 1556 1557 if (!current) { 1558 return false; 1559 } 1560 1561 stagePos = $.fancyboxforwp.getTranslate(this.$refs.stage); 1562 slidePos = $.fancyboxforwp.getTranslate(current.$slide); 1563 1564 return ( 1565 !current.$slide.hasClass("fancybox-animated") && 1566 (Math.abs(slidePos.top - stagePos.top) > 0.5 || Math.abs(slidePos.left - stagePos.left) > 0.5) 1567 ); 1568 }, 1569 1570 // Update cursor style depending if content can be zoomed 1571 // ====================================================== 1572 1573 updateCursor: function (nextWidth, nextHeight) { 1574 var self = this, 1575 current = self.current, 1576 $container = self.$refs.container, 1577 canPan, 1578 isZoomable; 1579 1580 if (!current || self.isClosing || !self.Guestures) { 1581 return; 1582 } 1583 1584 $container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"); 1585 1586 canPan = self.canPan(nextWidth, nextHeight); 1587 1588 isZoomable = canPan ? true : self.isZoomable(); 1589 1590 $container.toggleClass("fancybox-is-zoomable", isZoomable); 1591 1592 $("[data-fancybox-zoom]").prop("disabled", !isZoomable); 1593 1594 if (canPan) { 1595 $container.addClass("fancybox-can-pan"); 1596 } else if ( 1597 isZoomable && 1598 (current.opts.clickContent === "zoom" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) == "zoom")) 1599 ) { 1600 $container.addClass("fancybox-can-zoomIn"); 1601 } else if (current.opts.touch && (current.opts.touch.vertical || self.group.length > 1) && current.contentType !== "video") { 1602 $container.addClass("fancybox-can-swipe"); 1603 } 1604 }, 1605 1606 // Check if current slide is zoomable 1607 // ================================== 1608 1609 isZoomable: function () { 1610 var self = this, 1611 current = self.current, 1612 fitPos; 1613 1614 // Assume that slide is zoomable if: 1615 // - image is still loading 1616 // - actual size of the image is smaller than available area 1617 if (current && !self.isClosing && current.type === "image" && !current.hasError) { 1618 if (!current.isLoaded) { 1619 return true; 1620 } 1621 1622 fitPos = self.getFitPos(current); 1623 1624 if (fitPos && (current.width > fitPos.width || current.height > fitPos.height)) { 1625 return true; 1626 } 1627 } 1628 1629 return false; 1630 }, 1631 1632 // Check if current image dimensions are smaller than actual 1633 // ========================================================= 1634 1635 isScaledDown: function (nextWidth, nextHeight) { 1636 var self = this, 1637 rez = false, 1638 current = self.current, 1639 $content = current.$content; 1640 1641 if (nextWidth !== undefined && nextHeight !== undefined) { 1642 rez = nextWidth < current.width && nextHeight < current.height; 1643 } else if ($content) { 1644 rez = $.fancyboxforwp.getTranslate($content); 1645 rez = rez.width < current.width && rez.height < current.height; 1646 } 1647 1648 return rez; 1649 }, 1650 1651 // Check if image dimensions exceed parent element 1652 // =============================================== 1653 1654 canPan: function (nextWidth, nextHeight) { 1655 var self = this, 1656 current = self.current, 1657 pos = null, 1658 rez = false; 1659 1660 if (current.type === "image" && (current.isComplete || (nextWidth && nextHeight)) && !current.hasError) { 1661 rez = self.getFitPos(current); 1662 1663 if (nextWidth !== undefined && nextHeight !== undefined) { 1664 pos = { 1665 width: nextWidth, 1666 height: nextHeight 1667 }; 1668 } else if (current.isComplete) { 1669 pos = $.fancyboxforwp.getTranslate(current.$content); 1670 } 1671 1672 if (pos && rez) { 1673 rez = Math.abs(pos.width - rez.width) > 1.5 || Math.abs(pos.height - rez.height) > 1.5; 1674 } 1675 } 1676 1677 return rez; 1678 }, 1679 1680 // Load content into the slide 1681 // =========================== 1682 1683 loadSlide: function (slide) { 1684 var self = this, 1685 type, 1686 $slide, 1687 ajaxLoad; 1688 1689 if (slide.isLoading || slide.isLoaded) { 1690 return; 1691 } 1692 1693 slide.isLoading = true; 1694 1695 if (self.trigger("beforeLoad", slide) === false) { 1696 slide.isLoading = false; 1697 1698 return false; 1699 } 1700 1701 type = slide.type; 1702 $slide = slide.$slide; 1703 1704 $slide 1705 .off("refresh") 1706 .trigger("onReset") 1707 .addClass(slide.opts.slideClass); 1708 1709 // Create content depending on the type 1710 switch (type) { 1711 case "image": 1712 self.setImage(slide); 1713 1714 break; 1715 1716 case "iframe": 1717 self.setIframe(slide); 1718 1719 break; 1720 1721 case "html": 1722 self.setContent(slide, slide.src || slide.content); 1723 1724 break; 1725 1726 case "video": 1727 self.setContent( 1728 slide, 1729 slide.opts.video.tpl 1730 .replace(/\{\{src\}\}/gi, slide.src) 1731 .replace("{{format}}", slide.opts.videoFormat || slide.opts.video.format || "") 1732 .replace("{{poster}}", slide.thumb || "") 1733 ); 1734 1735 break; 1736 1737 case "inline": 1738 if ($(slide.src).length) { 1739 self.setContent(slide, $(slide.src)); 1740 } else { 1741 self.setError(slide); 1742 } 1743 1744 break; 1745 1746 case "ajax": 1747 self.showLoading(slide); 1748 1749 ajaxLoad = $.ajax( 1750 $.extend({}, slide.opts.ajax.settings, { 1751 url: slide.src, 1752 success: function (data, textStatus) { 1753 if (textStatus === "success") { 1754 self.setContent(slide, data); 1755 } 1756 }, 1757 error: function (jqXHR, textStatus) { 1758 if (jqXHR && textStatus !== "abort") { 1759 self.setError(slide); 1760 } 1761 } 1762 }) 1763 ); 1764 1765 $slide.one("onReset", function () { 1766 ajaxLoad.abort(); 1767 }); 1768 1769 break; 1770 1771 default: 1772 self.setError(slide); 1773 1774 break; 1775 } 1776 1777 return true; 1778 }, 1779 1780 // Use thumbnail image, if possible 1781 // ================================ 1782 1783 setImage: function (slide) { 1784 var self = this, 1785 ghost; 1786 1787 // Check if need to show loading icon 1788 setTimeout(function () { 1789 var $img = slide.$image; 1790 1791 if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) { 1792 self.showLoading(slide); 1793 } 1794 }, 50); 1795 1796 //Check if image has srcset 1797 self.checkSrcset(slide); 1798 1799 // This will be wrapper containing both ghost and actual image 1800 slide.$content = $('<div class="fancybox-content"></div>') 1801 .addClass("fancybox-is-hidden") 1802 .appendTo(slide.$slide.addClass("fancybox-slide--image")); 1803 1804 // If we have a thumbnail, we can display it while actual image is loading 1805 // Users will not stare at black screen and actual image will appear gradually 1806 if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && slide.thumb) { 1807 slide.width = slide.opts.width; 1808 slide.height = slide.opts.height; 1809 1810 ghost = document.createElement("img"); 1811 1812 ghost.onerror = function () { 1813 $(this).remove(); 1814 1815 slide.$ghost = null; 1816 }; 1817 1818 ghost.onload = function () { 1819 self.afterLoad(slide); 1820 }; 1821 1822 slide.$ghost = $(ghost) 1823 .addClass("fancybox-image") 1824 .appendTo(slide.$content) 1825 .attr("src", slide.thumb); 1826 } 1827 1828 // Start loading actual image 1829 self.setBigImage(slide); 1830 }, 1831 1832 // Check if image has srcset and get the source 1833 // ============================================ 1834 checkSrcset: function (slide) { 1835 var srcset = slide.opts.srcset || slide.opts.image.srcset, 1836 found, 1837 temp, 1838 pxRatio, 1839 windowWidth; 1840 1841 // If we have "srcset", then we need to find first matching "src" value. 1842 // This is necessary, because when you set an src attribute, the browser will preload the image 1843 // before any javascript or even CSS is applied. 1844 if (srcset) { 1845 pxRatio = window.devicePixelRatio || 1; 1846 windowWidth = window.innerWidth * pxRatio; 1847 1848 temp = srcset.split(",").map(function (el) { 1849 var ret = {}; 1850 1851 el.trim() 1852 .split(/\s+/) 1853 .forEach(function (el, i) { 1854 var value = parseInt(el.substring(0, el.length - 1), 10); 1855 1856 if (i === 0) { 1857 return (ret.url = el); 1858 } 1859 1860 if (value) { 1861 ret.value = value; 1862 ret.postfix = el[el.length - 1]; 1863 } 1864 }); 1865 1866 return ret; 1867 }); 1868 1869 // Sort by value 1870 temp.sort(function (a, b) { 1871 return a.value - b.value; 1872 }); 1873 1874 // Ok, now we have an array of all srcset values 1875 for (var j = 0; j < temp.length; j++) { 1876 var el = temp[j]; 1877 1878 if ((el.postfix === "w" && el.value >= windowWidth) || (el.postfix === "x" && el.value >= pxRatio)) { 1879 found = el; 1880 break; 1881 } 1882 } 1883 1884 // If not found, take the last one 1885 if (!found && temp.length) { 1886 found = temp[temp.length - 1]; 1887 } 1888 1889 if (found) { 1890 slide.src = found.url; 1891 1892 // If we have default width/height values, we can calculate height for matching source 1893 if (slide.width && slide.height && found.postfix == "w") { 1894 slide.height = (slide.width / slide.height) * found.value; 1895 slide.width = found.value; 1896 } 1897 1898 slide.opts.srcset = srcset; 1899 } 1900 } 1901 }, 1902 1903 // Create full-size image 1904 // ====================== 1905 1906 setBigImage: function (slide) { 1907 var self = this, 1908 img = document.createElement("img"), 1909 $img = $(img); 1910 1911 slide.$image = $img 1912 .one("error", function () { 1913 self.setError(slide); 1914 }) 1915 .one("load", function () { 1916 var sizes; 1917 1918 if (!slide.$ghost) { 1919 self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight); 1920 1921 self.afterLoad(slide); 1922 } 1923 1924 if (self.isClosing) { 1925 return; 1926 } 1927 1928 if (slide.opts.srcset) { 1929 sizes = slide.opts.sizes; 1930 1931 if (!sizes || sizes === "auto") { 1932 sizes = 1933 (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? "100" : Math.round((slide.width / slide.height) * 100)) + 1934 "vw"; 1935 } 1936 1937 $img.attr("sizes", sizes).attr("srcset", slide.opts.srcset); 1938 } 1939 1940 // Hide temporary image after some delay 1941 if (slide.$ghost) { 1942 setTimeout(function () { 1943 if (slide.$ghost && !self.isClosing) { 1944 slide.$ghost.hide(); 1945 } 1946 }, Math.min(300, Math.max(1000, slide.height / 1600))); 1947 } 1948 1949 self.hideLoading(slide); 1950 }) 1951 .addClass("fancybox-image") 1952 .attr("src", slide.src) 1953 .appendTo(slide.$content); 1954 1955 if ((img.complete || img.readyState == "complete") && $img.naturalWidth && $img.naturalHeight) { 1956 $img.trigger("load"); 1957 } else if (img.error) { 1958 $img.trigger("error"); 1959 } 1960 }, 1961 1962 // Computes the slide size from image size and maxWidth/maxHeight 1963 // ============================================================== 1964 1965 resolveImageSlideSize: function (slide, imgWidth, imgHeight) { 1966 var maxWidth = parseInt(slide.opts.width, 10), 1967 maxHeight = parseInt(slide.opts.height, 10); 1968 1969 // Sets the default values from the image 1970 slide.width = imgWidth; 1971 slide.height = imgHeight; 1972 1973 if (maxWidth > 0) { 1974 slide.width = maxWidth; 1975 slide.height = Math.floor((maxWidth * imgHeight) / imgWidth); 1976 } 1977 1978 if (maxHeight > 0) { 1979 slide.width = Math.floor((maxHeight * imgWidth) / imgHeight); 1980 slide.height = maxHeight; 1981 } 1982 }, 1983 1984 // Create iframe wrapper, iframe and bindings 1985 // ========================================== 1986 1987 setIframe: function (slide) { 1988 var self = this, 1989 opts = slide.opts.iframe, 1990 $slide = slide.$slide, 1991 $iframe; 1992 1993 slide.$content = $('<div class="fancybox-content' + (opts.preload ? " fancybox-is-hidden" : "") + '"></div>') 1994 .css(opts.css) 1995 .appendTo($slide); 1996 1997 $slide.addClass("fancybox-slide--" + slide.contentType); 1998 1999 slide.$iframe = $iframe = $(opts.tpl.replace(/\{rnd\}/g, new Date().getTime())) 2000 .attr(opts.attr) 2001 .appendTo(slide.$content); 2002 2003 if (opts.preload) { 2004 self.showLoading(slide); 2005 2006 // Unfortunately, it is not always possible to determine if iframe is successfully loaded 2007 // (due to browser security policy) 2008 2009 $iframe.on("load.fb error.fb", function (e) { 2010 this.isReady = 1; 2011 2012 slide.$slide.trigger("refresh"); 2013 2014 self.afterLoad(slide); 2015 }); 2016 2017 // Recalculate iframe content size 2018 // =============================== 2019 2020 $slide.on("refresh.fb", function () { 2021 var $content = slide.$content, 2022 frameWidth = opts.css.width, 2023 frameHeight = opts.css.height, 2024 $contents, 2025 $body; 2026 2027 if ($iframe[0].isReady !== 1) { 2028 return; 2029 } 2030 2031 try { 2032 $contents = $iframe.contents(); 2033 $body = $contents.find("body"); 2034 } catch (ignore) {} 2035 2036 // Calculate content dimensions, if it is accessible 2037 if ($body && $body.length && $body.children().length) { 2038 // Avoid scrolling to top (if multiple instances) 2039 $slide.css("overflow", "visible"); 2040 2041 $content.css({ 2042 width: "100%", 2043 "max-width": "100%", 2044 height: "9999px" 2045 }); 2046 2047 if (frameWidth === undefined) { 2048 frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true))); 2049 } 2050 2051 $content.css("width", frameWidth ? frameWidth : "").css("max-width", ""); 2052 2053 if (frameHeight === undefined) { 2054 frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true))); 2055 } 2056 2057 $content.css("height", frameHeight ? frameHeight : ""); 2058 2059 $slide.css("overflow", "auto"); 2060 } 2061 2062 $content.removeClass("fancybox-is-hidden"); 2063 }); 2064 } else { 2065 self.afterLoad(slide); 2066 } 2067 2068 $iframe.attr("src", slide.src); 2069 2070 // Remove iframe if closing or changing gallery item 2071 $slide.one("onReset", function () { 2072 // This helps IE not to throw errors when closing 2073 try { 2074 $(this) 2075 .find("iframe") 2076 .hide() 2077 .unbind() 2078 .attr("src", "//about:blank"); 2079 } catch (ignore) {} 2080 2081 $(this) 2082 .off("refresh.fb") 2083 .empty(); 2084 2085 slide.isLoaded = false; 2086 slide.isRevealed = false; 2087 }); 2088 }, 2089 2090 // Wrap and append content to the slide 2091 // ====================================== 2092 2093 setContent: function (slide, content) { 2094 var self = this; 2095 2096 if (self.isClosing) { 2097 return; 2098 } 2099 2100 self.hideLoading(slide); 2101 2102 if (slide.$content) { 2103 $.fancyboxforwp.stop(slide.$content); 2104 } 2105 2106 slide.$slide.empty(); 2107 2108 // If content is a jQuery object, then it will be moved to the slide. 2109 // The placeholder is created so we will know where to put it back. 2110 if (isQuery(content) && content.parent().length) { 2111 // Make sure content is not already moved to fancyBox 2112 if (content.hasClass("fancybox-content") || content.parent().hasClass("fancybox-content")) { 2113 content.parents(".fancybox-slide").trigger("onReset"); 2114 } 2115 2116 // Create temporary element marking original place of the content 2117 slide.$placeholder = $("<div>") 2118 .hide() 2119 .insertAfter(content); 2120 2121 // Make sure content is visible 2122 content.css("display", "inline-block"); 2123 } else if (!slide.hasError) { 2124 // If content is just a plain text, try to convert it to html 2125 if ($.type(content) === "string") { 2126 content = $("<div>") 2127 .append($.trim(content)) 2128 .contents(); 2129 } 2130 2131 // If "filter" option is provided, then filter content 2132 if (slide.opts.filter) { 2133 content = $("<div>") 2134 .html(DOMPurify.sanitize(content)) 2135 .find(slide.opts.filter); 2136 } 2137 } 2138 2139 slide.$slide.one("onReset", function () { 2140 // Pause all html5 video/audio 2141 $(this) 2142 .find("video,audio") 2143 .trigger("pause"); 2144 2145 // Put content back 2146 if (slide.$placeholder) { 2147 slide.$placeholder.after(content.removeClass("fancybox-content").hide()).remove(); 2148 2149 slide.$placeholder = null; 2150 } 2151 2152 // Remove custom close button 2153 if (slide.$smallBtn) { 2154 slide.$smallBtn.remove(); 2155 2156 slide.$smallBtn = null; 2157 } 2158 2159 // Remove content and mark slide as not loaded 2160 if (!slide.hasError) { 2161 $(this).empty(); 2162 2163 slide.isLoaded = false; 2164 slide.isRevealed = false; 2165 } 2166 }); 2167 2168 $(content).appendTo(slide.$slide); 2169 2170 if ($(content).is("video,audio")) { 2171 $(content).addClass("fancybox-video"); 2172 2173 $(content).wrap("<div></div>"); 2174 2175 slide.contentType = "video"; 2176 2177 slide.opts.width = slide.opts.width || $(content).attr("width"); 2178 slide.opts.height = slide.opts.height || $(content).attr("height"); 2179 } 2180 2181 slide.$content = slide.$slide 2182 .children() 2183 .filter("div,form,main,video,audio,article,.fancybox-content") 2184 .first(); 2185 2186 slide.$content.siblings().hide(); 2187 2188 // Re-check if there is a valid content 2189 // (in some cases, ajax response can contain various elements or plain text) 2190 if (!slide.$content.length) { 2191 slide.$content = slide.$slide 2192 .wrapInner("<div></div>") 2193 .children() 2194 .first(); 2195 } 2196 2197 slide.$content.addClass("fancybox-content"); 2198 2199 slide.$slide.addClass("fancybox-slide--" + slide.contentType); 2200 2201 self.afterLoad(slide); 2202 }, 2203 2204 // Display error message 2205 // ===================== 2206 2207 setError: function (slide) { 2208 slide.hasError = true; 2209 2210 slide.$slide 2211 .trigger("onReset") 2212 .removeClass("fancybox-slide--" + slide.contentType) 2213 .addClass("fancybox-slide--error"); 2214 2215 slide.contentType = "html"; 2216 2217 this.setContent(slide, this.translate(slide, slide.opts.errorTpl)); 2218 2219 if (slide.pos === this.currPos) { 2220 this.isAnimating = false; 2221 } 2222 }, 2223 2224 // Show loading icon inside the slide 2225 // ================================== 2226 2227 showLoading: function (slide) { 2228 var self = this; 2229 2230 slide = slide || self.current; 2231 2232 if (slide && !slide.$spinner) { 2233 slide.$spinner = $(self.translate(self, self.opts.spinnerTpl)) 2234 .appendTo(slide.$slide) 2235 .hide() 2236 .fadeIn("fast"); 2237 } 2238 }, 2239 2240 // Remove loading icon from the slide 2241 // ================================== 2242 2243 hideLoading: function (slide) { 2244 var self = this; 2245 2246 slide = slide || self.current; 2247 2248 if (slide && slide.$spinner) { 2249 slide.$spinner.stop().remove(); 2250 2251 delete slide.$spinner; 2252 } 2253 }, 2254 2255 // Adjustments after slide content has been loaded 2256 // =============================================== 2257 2258 afterLoad: function (slide) { 2259 var self = this; 2260 2261 if (self.isClosing) { 2262 return; 2263 } 2264 2265 slide.isLoading = false; 2266 slide.isLoaded = true; 2267 2268 self.trigger("afterLoad", slide); 2269 2270 self.hideLoading(slide); 2271 2272 // Add small close button 2273 if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) { 2274 slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content); 2275 } 2276 2277 // Disable right click 2278 if (slide.opts.protect && slide.$content && !slide.hasError) { 2279 slide.$content.on("contextmenu.fb", function (e) { 2280 if (e.button == 2) { 2281 e.preventDefault(); 2282 } 2283 2284 return true; 2285 }); 2286 2287 // Add fake element on top of the image 2288 // This makes a bit harder for user to select image 2289 if (slide.type === "image") { 2290 $('<div class="fancybox-spaceball"></div>').appendTo(slide.$content); 2291 } 2292 } 2293 2294 self.adjustCaption(slide); 2295 2296 self.adjustLayout(slide); 2297 2298 if (slide.pos === self.currPos) { 2299 self.updateCursor(); 2300 } 2301 2302 self.revealContent(slide); 2303 }, 2304 2305 // Prevent caption overlap, 2306 // fix css inconsistency across browsers 2307 // ===================================== 2308 2309 adjustCaption: function (slide) { 2310 var self = this, 2311 current = slide || self.current, 2312 caption = current.opts.caption, 2313 preventOverlap = current.opts.preventCaptionOverlap, 2314 $caption = self.$refs.caption, 2315 $clone, 2316 captionH = false; 2317 2318 $caption.toggleClass("fancybox-caption--separate", preventOverlap); 2319 2320 if (preventOverlap && caption && caption.length) { 2321 if (current.pos !== self.currPos) { 2322 $clone = $caption.clone().appendTo($caption.parent()); 2323 2324 $clone 2325 .children() 2326 .eq(0) 2327 .empty() 2328 .html(DOMPurify.sanitize(caption)); 2329 2330 captionH = $clone.outerHeight(true); 2331 2332 $clone.empty().remove(); 2333 } else if (self.$caption) { 2334 captionH = self.$caption.outerHeight(true); 2335 } 2336 2337 current.$slide.css("padding-bottom", captionH || ""); 2338 } 2339 }, 2340 2341 // Simple hack to fix inconsistency across browsers, described here (affects Edge, too): 2342 // https://bugzilla.mozilla.org/show_bug.cgi?id=748518 2343 // ==================================================================================== 2344 2345 adjustLayout: function (slide) { 2346 var self = this, 2347 current = slide || self.current, 2348 scrollHeight, 2349 marginBottom, 2350 inlinePadding, 2351 actualPadding; 2352 2353 if (current.isLoaded && current.opts.disableLayoutFix !== true) { 2354 current.$content.css("margin-bottom", ""); 2355 2356 // If we would always set margin-bottom for the content, 2357 // then it would potentially break vertical align 2358 if (current.$content.outerHeight() > current.$slide.height() + 0.5) { 2359 inlinePadding = current.$slide[0].style["padding-bottom"]; 2360 actualPadding = current.$slide.css("padding-bottom"); 2361 2362 if (parseFloat(actualPadding) > 0) { 2363 scrollHeight = current.$slide[0].scrollHeight; 2364 2365 current.$slide.css("padding-bottom", 0); 2366 2367 if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) { 2368 marginBottom = actualPadding; 2369 } 2370 2371 current.$slide.css("padding-bottom", inlinePadding); 2372 } 2373 } 2374 2375 current.$content.css("margin-bottom", marginBottom); 2376 } 2377 }, 2378 2379 // Make content visible 2380 // This method is called right after content has been loaded or 2381 // user navigates gallery and transition should start 2382 // ============================================================ 2383 2384 revealContent: function (slide) { 2385 var self = this, 2386 $slide = slide.$slide, 2387 end = false, 2388 start = false, 2389 isMoved = self.isMoved(slide), 2390 isRevealed = slide.isRevealed, 2391 effect, 2392 effectClassName, 2393 duration, 2394 opacity; 2395 2396 slide.isRevealed = true; 2397 2398 effect = slide.opts[self.firstRun ? "animationEffect" : "transitionEffect"]; 2399 duration = slide.opts[self.firstRun ? "animationDuration" : "transitionDuration"]; 2400 2401 duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10); 2402 2403 if (isMoved || slide.pos !== self.currPos || !duration) { 2404 effect = false; 2405 } 2406 2407 // Check if can zoom 2408 if (effect === "zoom") { 2409 if (slide.pos === self.currPos && duration && slide.type === "image" && !slide.hasError && (start = self.getThumbPos(slide))) { 2410 end = self.getFitPos(slide); 2411 } else { 2412 effect = "fade"; 2413 } 2414 } 2415 2416 // Zoom animation 2417 // ============== 2418 if (effect === "zoom") { 2419 self.isAnimating = true; 2420 2421 end.scaleX = end.width / start.width; 2422 end.scaleY = end.height / start.height; 2423 2424 // Check if we need to animate opacity 2425 opacity = slide.opts.zoomOpacity; 2426 2427 if (opacity == "auto") { 2428 opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1; 2429 } 2430 2431 if (opacity) { 2432 start.opacity = 0.1; 2433 end.opacity = 1; 2434 } 2435 2436 // Draw image at start position 2437 $.fancyboxforwp.setTranslate(slide.$content.removeClass("fancybox-is-hidden"), start); 2438 2439 forceRedraw(slide.$content); 2440 2441 // Start animation 2442 $.fancyboxforwp.animate(slide.$content, end, duration, function () { 2443 self.isAnimating = false; 2444 2445 self.complete(); 2446 }); 2447 2448 return; 2449 } 2450 2451 self.updateSlide(slide); 2452 2453 // Simply show content if no effect 2454 // ================================ 2455 if (!effect) { 2456 slide.$content.removeClass("fancybox-is-hidden"); 2457 2458 if (!isRevealed && isMoved && slide.type === "image" && !slide.hasError) { 2459 slide.$content.hide().fadeIn("fast"); 2460 } 2461 2462 if (slide.pos === self.currPos) { 2463 self.complete(); 2464 } 2465 2466 return; 2467 } 2468 2469 // Prepare for CSS transiton 2470 // ========================= 2471 $.fancyboxforwp.stop($slide); 2472 2473 //effectClassName = "fancybox-animated fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-fx-" + effect; 2474 effectClassName = "fancybox-slide--" + (slide.pos >= self.prevPos ? "next" : "previous") + " fancybox-animated fancybox-fx-" + effect; 2475 2476 $slide.addClass(effectClassName).removeClass("fancybox-slide--current"); //.addClass(effectClassName); 2477 2478 slide.$content.removeClass("fancybox-is-hidden"); 2479 2480 // Force reflow 2481 forceRedraw($slide); 2482 2483 if (slide.type !== "image") { 2484 slide.$content.hide().show(0); 2485 } 2486 2487 $.fancyboxforwp.animate( 2488 $slide, 2489 "fancybox-slide--current", 2490 duration, 2491 function () { 2492 $slide.removeClass(effectClassName).css({ 2493 transform: "", 2494 opacity: "" 2495 }); 2496 2497 if (slide.pos === self.currPos) { 2498 self.complete(); 2499 } 2500 }, 2501 true 2502 ); 2503 }, 2504 2505 // Check if we can and have to zoom from thumbnail 2506 //================================================ 2507 2508 getThumbPos: function (slide) { 2509 var rez = false, 2510 $thumb = slide.$thumb, 2511 thumbPos, 2512 btw, 2513 brw, 2514 bbw, 2515 blw; 2516 2517 if (!$thumb || !inViewport($thumb[0])) { 2518 return false; 2519 } 2520 2521 thumbPos = $.fancyboxforwp.getTranslate($thumb); 2522 2523 btw = parseFloat($thumb.css("border-top-width") || 0); 2524 brw = parseFloat($thumb.css("border-right-width") || 0); 2525 bbw = parseFloat($thumb.css("border-bottom-width") || 0); 2526 blw = parseFloat($thumb.css("border-left-width") || 0); 2527 2528 rez = { 2529 top: thumbPos.top + btw, 2530 left: thumbPos.left + blw, 2531 width: thumbPos.width - brw - blw, 2532 height: thumbPos.height - btw - bbw, 2533 scaleX: 1, 2534 scaleY: 1 2535 }; 2536 2537 return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false; 2538 }, 2539 2540 // Final adjustments after current gallery item is moved to position 2541 // and it`s content is loaded 2542 // ================================================================== 2543 2544 complete: function () { 2545 var self = this, 2546 current = self.current, 2547 slides = {}, 2548 $el; 2549 2550 if (self.isMoved() || !current.isLoaded) { 2551 return; 2552 } 2553 2554 if (!current.isComplete) { 2555 current.isComplete = true; 2556 2557 current.$slide.siblings().trigger("onReset"); 2558 2559 self.preload("inline"); 2560 2561 // Trigger any CSS transiton inside the slide 2562 forceRedraw(current.$slide); 2563 2564 current.$slide.addClass("fancybox-slide--complete"); 2565 2566 // Remove unnecessary slides 2567 $.each(self.slides, function (key, slide) { 2568 if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) { 2569 slides[slide.pos] = slide; 2570 } else if (slide) { 2571 $.fancyboxforwp.stop(slide.$slide); 2572 2573 slide.$slide.off().remove(); 2574 } 2575 }); 2576 2577 self.slides = slides; 2578 } 2579 2580 self.isAnimating = false; 2581 2582 self.updateCursor(); 2583 2584 self.trigger("afterShow"); 2585 2586 // Autoplay first html5 video/audio 2587 if (!!current.opts.video.autoStart) { 2588 current.$slide 2589 .find("video,audio") 2590 .filter(":visible:first") 2591 .trigger("play") 2592 .one("ended", function () { 2593 if (Document.exitFullscreen) { 2594 Document.exitFullscreen(); 2595 } else if (this.webkitExitFullscreen) { 2596 this.webkitExitFullscreen(); 2597 } 2598 2599 self.next(); 2600 }); 2601 } 2602 2603 // Try to focus on the first focusable element 2604 if (current.opts.autoFocus && current.contentType === "html") { 2605 // Look for the first input with autofocus attribute 2606 $el = current.$content.find("input[autofocus]:enabled:visible:first"); 2607 2608 if ($el.length) { 2609 $el.trigger("focus"); 2610 } else { 2611 self.focus(null, true); 2612 } 2613 } 2614 2615 // Avoid jumping 2616 current.$slide.scrollTop(0).scrollLeft(0); 2617 }, 2618 2619 // Preload next and previous slides 2620 // ================================ 2621 2622 preload: function (type) { 2623 var self = this, 2624 prev, 2625 next; 2626 2627 if (self.group.length < 2) { 2628 return; 2629 } 2630 2631 next = self.slides[self.currPos + 1]; 2632 prev = self.slides[self.currPos - 1]; 2633 2634 if (prev && prev.type === type) { 2635 self.loadSlide(prev); 2636 } 2637 2638 if (next && next.type === type) { 2639 self.loadSlide(next); 2640 } 2641 }, 2642 2643 // Try to find and focus on the first focusable element 2644 // ==================================================== 2645 2646 focus: function (e, firstRun) { 2647 var self = this, 2648 focusableStr = [ 2649 "a[href]", 2650 "area[href]", 2651 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', 2652 "select:not([disabled]):not([aria-hidden])", 2653 "textarea:not([disabled]):not([aria-hidden])", 2654 "button:not([disabled]):not([aria-hidden])", 2655 "iframe", 2656 "object", 2657 "embed", 2658 "video", 2659 "audio", 2660 "[contenteditable]", 2661 '[tabindex]:not([tabindex^="-"])' 2662 ].join(","), 2663 focusableItems, 2664 focusedItemIndex; 2665 2666 if (self.isClosing) { 2667 return; 2668 } 2669 2670 if (e || !self.current || !self.current.isComplete) { 2671 // Focus on any element inside fancybox 2672 focusableItems = self.$refs.container.find("*:visible"); 2673 } else { 2674 // Focus inside current slide 2675 focusableItems = self.current.$slide.find("*:visible" + (firstRun ? ":not(.fancybox-close-small)" : "")); 2676 } 2677 2678 focusableItems = focusableItems.filter(focusableStr).filter(function () { 2679 return $(this).css("visibility") !== "hidden" && !$(this).hasClass("disabled"); 2680 }); 2681 2682 if (focusableItems.length) { 2683 focusedItemIndex = focusableItems.index(document.activeElement); 2684 2685 if (e && e.shiftKey) { 2686 // Back tab 2687 if (focusedItemIndex < 0 || focusedItemIndex == 0) { 2688 e.preventDefault(); 2689 2690 focusableItems.eq(focusableItems.length - 1).trigger("focus"); 2691 } 2692 } else { 2693 // Outside or Forward tab 2694 if (focusedItemIndex < 0 || focusedItemIndex == focusableItems.length - 1) { 2695 if (e) { 2696 e.preventDefault(); 2697 } 2698 2699 focusableItems.eq(0).trigger("focus"); 2700 } 2701 } 2702 } else { 2703 self.$refs.container.trigger("focus"); 2704 } 2705 }, 2706 2707 // Activates current instance - brings container to the front and enables keyboard, 2708 // notifies other instances about deactivating 2709 // ================================================================================= 2710 2711 activate: function () { 2712 var self = this; 2713 2714 // Deactivate all instances 2715 $(".fancybox-container").each(function () { 2716 var instance = $(this).data("FancyBox"); 2717 2718 // Skip self and closing instances 2719 if (instance && instance.id !== self.id && !instance.isClosing) { 2720 instance.trigger("onDeactivate"); 2721 2722 instance.removeEvents(); 2723 2724 instance.isVisible = false; 2725 } 2726 }); 2727 2728 self.isVisible = true; 2729 2730 if (self.current || self.isIdle) { 2731 self.update(); 2732 2733 self.updateControls(); 2734 } 2735 2736 self.trigger("onActivate"); 2737 2738 self.addEvents(); 2739 }, 2740 2741 // Start closing procedure 2742 // This will start "zoom-out" animation if needed and clean everything up afterwards 2743 // ================================================================================= 2744 2745 close: function (e, d) { 2746 var self = this, 2747 current = self.current, 2748 effect, 2749 duration, 2750 $content, 2751 domRect, 2752 opacity, 2753 start, 2754 end; 2755 2756 var done = function () { 2757 self.cleanUp(e); 2758 }; 2759 2760 if (self.isClosing) { 2761 return false; 2762 } 2763 2764 self.isClosing = true; 2765 2766 // If beforeClose callback prevents closing, make sure content is centered 2767 if (self.trigger("beforeClose", e) === false) { 2768 self.isClosing = false; 2769 2770 requestAFrame(function () { 2771 self.update(); 2772 }); 2773 2774 return false; 2775 } 2776 2777 // Remove all events 2778 // If there are multiple instances, they will be set again by "activate" method 2779 self.removeEvents(); 2780 2781 $content = current.$content; 2782 effect = current.opts.animationEffect; 2783 duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0; 2784 2785 current.$slide.removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"); 2786 2787 if (e !== true) { 2788 $.fancyboxforwp.stop(current.$slide); 2789 } else { 2790 effect = false; 2791 } 2792 2793 // Remove other slides 2794 current.$slide 2795 .siblings() 2796 .trigger("onReset") 2797 .remove(); 2798 2799 // Trigger animations 2800 if (duration) { 2801 self.$refs.container 2802 .removeClass("fancybox-is-open") 2803 .addClass("fancybox-is-closing") 2804 .css("transition-duration", duration + "ms"); 2805 } 2806 2807 // Clean up 2808 self.hideLoading(current); 2809 2810 self.hideControls(true); 2811 2812 self.updateCursor(); 2813 2814 // Check if possible to zoom-out 2815 if ( 2816 effect === "zoom" && 2817 !($content && duration && current.type === "image" && !self.isMoved() && !current.hasError && (end = self.getThumbPos(current))) 2818 ) { 2819 effect = "fade"; 2820 } 2821 2822 if (effect === "zoom") { 2823 $.fancyboxforwp.stop($content); 2824 2825 domRect = $.fancyboxforwp.getTranslate($content); 2826 2827 start = { 2828 top: domRect.top, 2829 left: domRect.left, 2830 scaleX: domRect.width / end.width, 2831 scaleY: domRect.height / end.height, 2832 width: end.width, 2833 height: end.height 2834 }; 2835 2836 // Check if we need to animate opacity 2837 opacity = current.opts.zoomOpacity; 2838 2839 if (opacity == "auto") { 2840 opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1; 2841 } 2842 2843 if (opacity) { 2844 end.opacity = 0; 2845 } 2846 2847 $.fancyboxforwp.setTranslate($content, start); 2848 2849 forceRedraw($content); 2850 2851 $.fancyboxforwp.animate($content, end, duration, done); 2852 2853 return true; 2854 } 2855 2856 if (effect && duration) { 2857 $.fancyboxforwp.animate( 2858 current.$slide.addClass("fancybox-slide--previous").removeClass("fancybox-slide--current"), 2859 "fancybox-animated fancybox-fx-" + effect, 2860 duration, 2861 done 2862 ); 2863 } else { 2864 // If skip animation 2865 if (e === true) { 2866 setTimeout(done, duration); 2867 } else { 2868 done(); 2869 } 2870 } 2871 2872 return true; 2873 }, 2874 2875 // Final adjustments after removing the instance 2876 // ============================================= 2877 2878 cleanUp: function (e) { 2879 var self = this, 2880 instance, 2881 $focus = self.current.opts.$orig, 2882 x, 2883 y; 2884 2885 self.current.$slide.trigger("onReset"); 2886 2887 self.$refs.container.empty().remove(); 2888 2889 self.trigger("afterClose", e); 2890 2891 // Place back focus 2892 if (!!self.current.opts.backFocus) { 2893 if (!$focus || !$focus.length || !$focus.is(":visible")) { 2894 $focus = self.$trigger; 2895 } 2896 2897 if ($focus && $focus.length) { 2898 x = window.scrollX; 2899 y = window.scrollY; 2900 2901 $focus.trigger("focus"); 2902 2903 $("html, body") 2904 .scrollTop(y) 2905 .scrollLeft(x); 2906 } 2907 } 2908 2909 self.current = null; 2910 2911 // Check if there are other instances 2912 instance = $.fancyboxforwp.getInstance(); 2913 2914 if (instance) { 2915 instance.activate(); 2916 } else { 2917 $("body").removeClass("fancybox-active compensate-for-scrollbar"); 2918 2919 $("#fancybox-style-noscroll").remove(); 2920 } 2921 }, 2922 2923 // Call callback and trigger an event 2924 // ================================== 2925 2926 trigger: function (name, slide) { 2927 var args = Array.prototype.slice.call(arguments, 1), 2928 self = this, 2929 obj = slide && slide.opts ? slide : self.current, 2930 rez; 2931 2932 if (obj) { 2933 args.unshift(obj); 2934 } else { 2935 obj = self; 2936 } 2937 2938 args.unshift(self); 2939 2940 if ($.isFunction(obj.opts[name])) { 2941 rez = obj.opts[name].apply(obj, args); 2942 } 2943 2944 if (rez === false) { 2945 return rez; 2946 } 2947 2948 if (name === "afterClose" || !self.$refs) { 2949 $D.trigger(name + ".fb", args); 2950 } else { 2951 self.$refs.container.trigger(name + ".fb", args); 2952 } 2953 }, 2954 2955 // Update infobar values, navigation button states and reveal caption 2956 // ================================================================== 2957 2958 updateControls: function () { 2959 var self = this, 2960 current = self.current, 2961 index = current.index, 2962 $container = self.$refs.container, 2963 $caption = self.$refs.caption, 2964 caption = current.opts.caption; 2965 2966 // Recalculate content dimensions 2967 current.$slide.trigger("refresh"); 2968 2969 // Set caption 2970 if (caption && caption.length) { 2971 self.$caption = $caption; 2972 2973 $caption 2974 .children() 2975 .eq(0) 2976 .html(DOMPurify.sanitize(caption)); 2977 } else { 2978 self.$caption = null; 2979 } 2980 2981 if (!self.hasHiddenControls && !self.isIdle) { 2982 self.showControls(); 2983 } 2984 2985 // Update info and navigation elements 2986 $container.find("[data-fancybox-count]").html(DOMPurify.sanitize(self.group.length)); 2987 $container.find("[data-fancybox-index]").html(DOMPurify.sanitize(index + 1)); 2988 2989 $container.find("[data-fancybox-prev]").prop("disabled", !current.opts.loop && index <= 0); 2990 $container.find("[data-fancybox-next]").prop("disabled", !current.opts.loop && index >= self.group.length - 1); 2991 2992 if (current.type === "image") { 2993 // Re-enable buttons; update download button source 2994 $container 2995 .find("[data-fancybox-zoom]") 2996 .show() 2997 .end() 2998 .find("[data-fancybox-download]") 2999 .attr("href", current.opts.image.src || current.src) 3000 .show(); 3001 } else if (current.opts.toolbar) { 3002 $container.find("[data-fancybox-download],[data-fancybox-zoom]").hide(); 3003 } 3004 3005 // Make sure focus is not on disabled button/element 3006 if ($(document.activeElement).is(":hidden,[disabled]")) { 3007 self.$refs.container.trigger("focus"); 3008 } 3009 }, 3010 3011 // Hide toolbar and caption 3012 // ======================== 3013 3014 hideControls: function (andCaption) { 3015 var self = this, 3016 arr = ["infobar", "toolbar", "nav"]; 3017 3018 if (andCaption || !self.current.opts.preventCaptionOverlap) { 3019 arr.push("caption"); 3020 } 3021 3022 this.$refs.container.removeClass( 3023 arr 3024 .map(function (i) { 3025 return "fancybox-show-" + i; 3026 }) 3027 .join(" ") 3028 ); 3029 3030 this.hasHiddenControls = true; 3031 }, 3032 3033 showControls: function () { 3034 var self = this, 3035 opts = self.current ? self.current.opts : self.opts, 3036 $container = self.$refs.container; 3037 3038 self.hasHiddenControls = false; 3039 self.idleSecondsCounter = 0; 3040 3041 $container 3042 .toggleClass("fancybox-show-toolbar", !!(opts.toolbar && opts.buttons)) 3043 .toggleClass("fancybox-show-infobar", !!(opts.infobar && self.group.length > 1)) 3044 .toggleClass("fancybox-show-caption", !!self.$caption) 3045 .toggleClass("fancybox-show-nav", !!(opts.arrows && self.group.length > 1)) 3046 .toggleClass("fancybox-is-modal", !!opts.modal); 3047 }, 3048 3049 // Toggle toolbar and caption 3050 // ========================== 3051 3052 toggleControls: function () { 3053 if (this.hasHiddenControls) { 3054 this.showControls(); 3055 } else { 3056 this.hideControls(); 3057 } 3058 } 3059 }); 3060 3061 $.fancyboxforwp = { 3062 version: "3.5.7", 3063 defaults: defaults, 3064 3065 // Get current instance and execute a command. 3066 // 3067 // Examples of usage: 3068 // 3069 // $instance = $.fancyboxforwp.getInstance(); 3070 // $.fancyboxforwp.getInstance().jumpTo( 1 ); 3071 // $.fancyboxforwp.getInstance( 'jumpTo', 1 ); 3072 // $.fancyboxforwp.getInstance( function() { 3073 // console.info( this.currIndex ); 3074 // }); 3075 // ====================================================== 3076 3077 getInstance: function (command) { 3078 var instance = $('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"), 3079 args = Array.prototype.slice.call(arguments, 1); 3080 3081 if (instance instanceof FancyBox) { 3082 if ($.type(command) === "string") { 3083 instance[command].apply(instance, args); 3084 } else if ($.type(command) === "function") { 3085 command.apply(instance, args); 3086 } 3087 3088 return instance; 3089 } 3090 3091 return false; 3092 }, 3093 3094 // Create new instance 3095 // =================== 3096 3097 open: function (items, opts, index) { 3098 return new FancyBox(items, opts, index); 3099 }, 3100 3101 // Close current or all instances 3102 // ============================== 3103 3104 close: function (all) { 3105 var instance = this.getInstance(); 3106 3107 if (instance) { 3108 instance.close(); 3109 3110 // Try to find and close next instance 3111 if (all === true) { 3112 this.close(all); 3113 } 3114 } 3115 }, 3116 3117 // Close all instances and unbind all events 3118 // ========================================= 3119 3120 destroy: function () { 3121 this.close(true); 3122
3123 $D.add("body").off("click.fb-start", "**"); 3124 }, 3125 3126 // Try to detect mobile devices 3127 // ============================ 3128 3129 isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), 3130 3131 // Detect if 'translate3d' support is available 3132 // ============================================ 3133 3134 use3d: (function () { 3135 var div = document.createElement("div"); 3136 3137 return ( 3138 window.getComputedStyle && 3139 window.getComputedStyle(div) && 3140 window.getComputedStyle(div).getPropertyValue("transform") && 3141 !(document.documentMode && document.documentMode < 11) 3142 ); 3143 })(), 3144 3145 // Helper function to get current visual state of an element 3146 // returns array[ top, left, horizontal-scale, vertical-scale, opacity ] 3147 // ===================================================================== 3148 3149 getTranslate: function ($el) { 3150 var domRect; 3151 3152 if (!$el || !$el.length) { 3153 return false; 3154 } 3155 3156 domRect = $el[0].getBoundingClientRect(); 3157 3158 return { 3159 top: domRect.top || 0, 3160 left: domRect.left || 0, 3161 width: domRect.width, 3162 height: domRect.height, 3163 opacity: parseFloat($el.css("opacity")) 3164 }; 3165 }, 3166 3167 // Shortcut for setting "translate3d" properties for element 3168 // Can set be used to set opacity, too 3169 // ======================================================== 3170 3171 setTranslate: function ($el, props) { 3172 var str = "", 3173 css = {}; 3174 3175 if (!$el || !props) { 3176 return; 3177 } 3178 3179 if (props.left !== undefined || props.top !== undefined) { 3180 str = 3181 (props.left === undefined ? $el.position().left : props.left) + 3182 "px, " + 3183 (props.top === undefined ? $el.position().top : props.top) + 3184 "px"; 3185 3186 if (this.use3d) { 3187 str = "translate3d(" + str + ", 0px)"; 3188 } else { 3189 str = "translate(" + str + ")"; 3190 } 3191 } 3192 3193 if (props.scaleX !== undefined && props.scaleY !== undefined) { 3194 str += " scale(" + props.scaleX + ", " + props.scaleY + ")"; 3195 } else if (props.scaleX !== undefined) { 3196 str += " scaleX(" + props.scaleX + ")"; 3197 } 3198 3199 if (str.length) { 3200 css.transform = str; 3201 } 3202 3203 if (props.opacity !== undefined) { 3204 css.opacity = props.opacity; 3205 } 3206 3207 if (props.width !== undefined) { 3208 css.width = props.width; 3209 } 3210 3211 var custom_caption_outerHeight = 0; 3212 3213 if($('.fancybox-custom-caption.inside-caption').length ){ 3214 custom_caption_outerHeight = $el.find('.fancybox-custom-caption').outerHeight(); 3215 if(custom_caption_outerHeight == 0){ 3216 custom_caption_outerHeight = 10; 3217 } 3218 } else { 3219 custom_caption_outerHeight = ($el.find('.fancybox-image').outerHeight() - $el.find('.fancybox-image').height())/2; 3220 // Seems like different border width for image requires a little trimming 3221 if(custom_caption_outerHeight > 20 && custom_caption_outerHeight < 25 ){ 3222 custom_caption_outerHeight -= 2; 3223 } 3224 3225 if(custom_caption_outerHeight >= 25 && custom_caption_outerHeight <= 30){ 3226 custom_caption_outerHeight -= 4; 3227 } 3228 3229 if(custom_caption_outerHeight > 30){ 3230 custom_caption_outerHeight -= 6; 3231 } 3232 } 3233 3234 if (props.height !== undefined && props.height != $el.outerHeight()) { 3235 css.height = props.height + custom_caption_outerHeight; 3236 } 3237 3238 return $el.css(css); 3239 }, 3240 3241 // Simple CSS transition handler 3242 // ============================= 3243 3244 animate: function ($el, to, duration, callback, leaveAnimationName) { 3245 var self = this, 3246 from; 3247 3248 if ($.isFunction(duration)) { 3249 callback = duration; 3250 duration = null; 3251 } 3252 3253 self.stop($el); 3254 3255 from = self.getTranslate($el); 3256 3257 $el.on(transitionEnd, function (e) { 3258 // Skip events from child elements and z-index change 3259 if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == "z-index")) { 3260 return; 3261 } 3262 3263 self.stop($el); 3264 3265 if ($.isNumeric(duration)) { 3266 $el.css("transition-duration", ""); 3267 } 3268 3269 if ($.isPlainObject(to)) { 3270 if (to.scaleX !== undefined && to.scaleY !== undefined) { 3271 self.setTranslate($el, { 3272 top: to.top, 3273 left: to.left, 3274 width: from.width * to.scaleX, 3275 height: from.height * to.scaleY, 3276 scaleX: 1, 3277 scaleY: 1 3278 }); 3279 } 3280 } else if (leaveAnimationName !== true) { 3281 $el.removeClass(to); 3282 } 3283 3284 if ($.isFunction(callback)) { 3285 callback(e); 3286 } 3287 }); 3288 3289 if ($.isNumeric(duration)) { 3290 $el.css("transition-duration", duration + "ms"); 3291 } 3292 3293 // Start animation by changing CSS properties or class name 3294 if ($.isPlainObject(to)) { 3295 if (to.scaleX !== undefined && to.scaleY !== undefined) { 3296 delete to.width; 3297 delete to.height; 3298 3299 if ($el.parent().hasClass("fancybox-slide--image")) { 3300 $el.parent().addClass("fancybox-is-scaling"); 3301 } 3302 } 3303 3304 $.fancyboxforwp.setTranslate($el, to); 3305 } else { 3306 $el.addClass(to); 3307 } 3308 3309 // Make sure that `transitionend` callback gets fired 3310 $el.data( 3311 "timer", 3312 setTimeout(function () { 3313 $el.trigger(transitionEnd); 3314 }, duration + 33) 3315 ); 3316 }, 3317
vendor: 67,591 bytes, lines 3318-5660
3318 stop: function ($el, callCallback) { 3319 if ($el && $el.length) { 3320 clearTimeout($el.data("timer")); 3321 3322 if (callCallback) { 3323 $el.trigger(transitionEnd); 3324 } 3325 3326 $el.off(transitionEnd).css("transition-duration", ""); 3327 3328 $el.parent().removeClass("fancybox-is-scaling"); 3329 } 3330 } 3331 }; 3332 3333 // Default click handler for "fancyboxed" links 3334 // ============================================ 3335 3336 function _run(e, opts) { 3337 var items = [], 3338 index = 0, 3339 $target, 3340 value, 3341 instance; 3342 3343 // Avoid opening multiple times 3344 if (e && e.isDefaultPrevented()) { 3345 return; 3346 } 3347 3348 e.preventDefault(); 3349 3350 opts = opts || {}; 3351 3352 if (e && e.data) { 3353 opts = mergeOpts(e.data.options, opts); 3354 } 3355 3356 $target = opts.$target || $(e.currentTarget).trigger("blur"); 3357 instance = $.fancyboxforwp.getInstance(); 3358 3359 if (instance && instance.$trigger && instance.$trigger.is($target)) { 3360 return; 3361 } 3362 3363 if (opts.selector) { 3364 items = $(opts.selector); 3365 } else { 3366 // Get all related items and find index for clicked one 3367 value = $target.attr("data-fancybox") || ""; 3368 3369 if (value) { 3370 items = e.data ? e.data.items : []; 3371 items = items.length ? items.filter('[data-fancybox="' + value + '"]') : $('[data-fancybox="' + value + '"]'); 3372 } else { 3373 items = [$target]; 3374 } 3375 } 3376 3377 index = $(items).index($target); 3378 3379 // Sometimes current item can not be found 3380 if (index < 0) { 3381 index = 0; 3382 } 3383 3384 instance = $.fancyboxforwp.open(items, opts, index); 3385 3386 // Save last active element 3387 instance.$trigger = $target; 3388 } 3389 3390 // Create a jQuery plugin 3391 // ====================== 3392 3393 $.fn.fancyboxforwp = function (options) { 3394 var selector; 3395 3396 options = options || {}; 3397 selector = options.selector || false; 3398 3399 if (selector) { 3400 // Use body element instead of document so it executes first 3401 $("body") 3402 .off("click.fb-start", selector) 3403 .on("click.fb-start", selector, { 3404 options: options 3405 }, _run); 3406 } else { 3407 this.off("click.fb-start").on( 3408 "click.fb-start", { 3409 items: this, 3410 options: options 3411 }, 3412 _run 3413 ); 3414 } 3415 3416 return this; 3417 }; 3418 3419 // Self initializing plugin for all elements having `data-fancybox` attribute 3420 // ========================================================================== 3421 3422 $D.on("click.fb-start", "[data-fancybox]", _run); 3423 3424 // Enable "trigger elements" 3425 // ========================= 3426 3427 $D.on("click.fb-start", "[data-fancybox-trigger]", function (e) { 3428 $('[data-fancybox="' + $(this).attr("data-fancybox-trigger") + '"]') 3429 .eq($(this).attr("data-fancybox-index") || 0) 3430 .trigger("click.fb-start", { 3431 $trigger: $(this) 3432 }); 3433 }); 3434 3435 // Track focus event for better accessibility styling 3436 // ================================================== 3437 (function () { 3438 var buttonStr = ".fancybox-button", 3439 focusStr = "fancybox-focus", 3440 $pressed = null; 3441 3442 $D.on("mousedown mouseup focus blur", buttonStr, function (e) { 3443 switch (e.type) { 3444 case "mousedown": 3445 $pressed = $(this); 3446 break; 3447 case "mouseup": 3448 $pressed = null; 3449 break; 3450 case "focusin": 3451 $(buttonStr).removeClass(focusStr); 3452 3453 if (!$(this).is($pressed) && !$(this).is("[disabled]")) { 3454 $(this).addClass(focusStr); 3455 } 3456 break; 3457 case "focusout": 3458 $(buttonStr).removeClass(focusStr); 3459 break; 3460 } 3461 }); 3462 })(); 3463})(window, document, jQuery); 3464// ========================================================================== 3465// 3466// Media 3467// Adds additional media type support 3468// 3469// ========================================================================== 3470(function ($) { 3471 "use strict"; 3472 3473 // Object containing properties for each media type 3474 var defaults = { 3475 youtube: { 3476 matcher: /(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i, 3477 params: { 3478 autoplay: 1, 3479 autohide: 1, 3480 fs: 1, 3481 rel: 0, 3482 hd: 1, 3483 wmode: "transparent", 3484 enablejsapi: 1, 3485 html5: 1 3486 }, 3487 paramPlace: 8, 3488 type: "iframe", 3489 url: "https://www.youtube-nocookie.com/embed/$4", 3490 thumb: "https://img.youtube.com/vi/$4/hqdefault.jpg" 3491 }, 3492 3493 vimeo: { 3494 matcher: /^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/, 3495 params: { 3496 autoplay: 1, 3497 hd: 1, 3498 show_title: 1, 3499 show_byline: 1, 3500 show_portrait: 0, 3501 fullscreen: 1 3502 }, 3503 paramPlace: 3, 3504 type: "iframe", 3505 url: "//player.vimeo.com/video/$2" 3506 }, 3507 3508 instagram: { 3509 matcher: /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i, 3510 type: "image", 3511 url: "//$1/p/$2/media/?size=l" 3512 }, 3513 3514 // Examples: 3515 // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16 3516 // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z 3517 // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en 3518 // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572 3519 gmap_place: { 3520 matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i, 3521 type: "iframe", 3522 url: function (rez) { 3523 return ( 3524 "//maps.google." + 3525 rez[2] + 3526 "/?ll=" + 3527 (rez[9] ? rez[9] + "&z=" + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\//, "&") : "") : rez[12] + "").replace(/\?/, "&") + 3528 "&output=" + 3529 (rez[12] && rez[12].indexOf("layer=c") > 0 ? "svembed" : "embed") 3530 ); 3531 } 3532 }, 3533 3534 // Examples: 3535 // https://www.google.com/maps/search/Empire+State+Building/ 3536 // https://www.google.com/maps/search/?api=1&query=centurylink+field 3537 // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393 3538 gmap_search: { 3539 matcher: /(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i, 3540 type: "iframe", 3541 url: function (rez) { 3542 return "//maps.google." + rez[2] + "/maps?q=" + rez[5].replace("query=", "q=").replace("api=1", "") + "&output=embed"; 3543 } 3544 } 3545 }; 3546 3547 // Formats matching url to final form 3548 var format = function (url, rez, params) { 3549 if (!url) { 3550 return; 3551 } 3552 3553 params = params || ""; 3554 3555 if ($.type(params) === "object") { 3556 params = $.param(params, true); 3557 } 3558 3559 $.each(rez, function (key, value) { 3560 url = url.replace("$" + key, value || ""); 3561 }); 3562 3563 if (params.length) { 3564 url += (url.indexOf("?") > 0 ? "&" : "?") + params; 3565 } 3566 3567 return url; 3568 }; 3569 3570 $(document).on("objectNeedsType.fb", function (e, instance, item) { 3571 var url = item.src || "", 3572 type = false, 3573 media, 3574 thumb, 3575 rez, 3576 params, 3577 urlParams, 3578 paramObj, 3579 provider; 3580 3581 media = $.extend(true, {}, defaults, item.opts.media); 3582 3583 // Look for any matching media type 3584 $.each(media, function (providerName, providerOpts) { 3585 rez = url.match(providerOpts.matcher); 3586 3587 if (!rez) { 3588 return; 3589 } 3590 3591 type = providerOpts.type; 3592 provider = providerName; 3593 paramObj = {}; 3594 3595 if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) { 3596 urlParams = rez[providerOpts.paramPlace]; 3597 3598 if (urlParams[0] == "?") { 3599 urlParams = urlParams.substring(1); 3600 } 3601 3602 urlParams = urlParams.split("&"); 3603 3604 for (var m = 0; m < urlParams.length; ++m) { 3605 var p = urlParams[m].split("=", 2); 3606 3607 if (p.length == 2) { 3608 paramObj[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); 3609 } 3610 } 3611 } 3612 3613 params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj); 3614 3615 url = 3616 $.type(providerOpts.url) === "function" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params); 3617 3618 thumb = 3619 $.type(providerOpts.thumb) === "function" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez); 3620 3621 if (providerName === "youtube") { 3622 url = url.replace(/&t=((\d+)m)?(\d+)s/, function (match, p1, m, s) { 3623 return "&start=" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10)); 3624 }); 3625 } else if (providerName === "vimeo") { 3626 url = url.replace("&%23", "#"); 3627 } 3628 3629 return false; 3630 }); 3631 3632 // If it is found, then change content type and update the url 3633 3634 if (type) { 3635 if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) { 3636 item.opts.thumb = thumb; 3637 } 3638 3639 if (type === "iframe") { 3640 item.opts = $.extend(true, item.opts, { 3641 iframe: { 3642 preload: false, 3643 attr: { 3644 scrolling: "no" 3645 } 3646 } 3647 }); 3648 } 3649 3650 $.extend(item, { 3651 type: type, 3652 src: url, 3653 origSrc: item.src, 3654 contentSource: provider, 3655 contentType: type === "image" ? "image" : provider == "gmap_place" || provider == "gmap_search" ? "map" : "video" 3656 }); 3657 } else if (url) { 3658 item.type = item.opts.defaultType; 3659 } 3660 }); 3661 3662 // Load YouTube/Video API on request to detect when video finished playing 3663 var VideoAPILoader = { 3664 youtube: { 3665 src: "https://www.youtube.com/iframe_api", 3666 class: "YT", 3667 loading: false, 3668 loaded: false 3669 }, 3670 3671 vimeo: { 3672 src: "https://player.vimeo.com/api/player.js", 3673 class: "Vimeo", 3674 loading: false, 3675 loaded: false 3676 }, 3677 3678 load: function (vendor) { 3679 var _this = this, 3680 script; 3681 3682 if (this[vendor].loaded) { 3683 setTimeout(function () { 3684 _this.done(vendor); 3685 }); 3686 return; 3687 } 3688 3689 if (this[vendor].loading) { 3690 return; 3691 } 3692 3693 this[vendor].loading = true; 3694 3695 script = document.createElement("script"); 3696 script.type = "text/javascript"; 3697 script.src = this[vendor].src; 3698 3699 if (vendor === "youtube") { 3700 window.onYouTubeIframeAPIReady = function () { 3701 _this[vendor].loaded = true; 3702 _this.done(vendor); 3703 }; 3704 } else { 3705 script.onload = function () { 3706 _this[vendor].loaded = true; 3707 _this.done(vendor); 3708 }; 3709 } 3710 3711 document.body.appendChild(script); 3712 }, 3713 done: function (vendor) { 3714 var instance, $el, player; 3715 3716 if (vendor === "youtube") { 3717 delete window.onYouTubeIframeAPIReady; 3718 } 3719 3720 instance = $.fancyboxforwp.getInstance(); 3721 3722 if (instance) { 3723 $el = instance.current.$content.find("iframe"); 3724 3725 if (vendor === "youtube" && YT !== undefined && YT) { 3726 player = new YT.Player($el.attr("id"), { 3727 events: { 3728 onStateChange: function (e) { 3729 if (e.data == 0) { 3730 instance.next(); 3731 } 3732 } 3733 } 3734 }); 3735 } else if (vendor === "vimeo" && Vimeo !== undefined && Vimeo) { 3736 player = new Vimeo.Player($el); 3737 3738 player.on("ended", function () { 3739 instance.next(); 3740 }); 3741 } 3742 } 3743 } 3744 }; 3745 3746 $(document).on({ 3747 "afterShow.fb": function (e, instance, current) { 3748 if (instance.group.length > 1 && (current.contentSource === "youtube" || current.contentSource === "vimeo")) { 3749 VideoAPILoader.load(current.contentSource); 3750 } 3751 } 3752 }); 3753})(jQuery); 3754// ========================================================================== 3755// 3756// Guestures 3757// Adds touch guestures, handles click and tap events 3758// 3759// ========================================================================== 3760(function (window, document, $) { 3761 "use strict"; 3762 3763 var requestAFrame = (function () { 3764 return ( 3765 window.requestAnimationFrame || 3766 window.webkitRequestAnimationFrame || 3767 window.mozRequestAnimationFrame || 3768 window.oRequestAnimationFrame || 3769 // if all else fails, use setTimeout 3770 function (callback) { 3771 return window.setTimeout(callback, 1000 / 60); 3772 } 3773 ); 3774 })(); 3775 3776 var cancelAFrame = (function () { 3777 return ( 3778 window.cancelAnimationFrame || 3779 window.webkitCancelAnimationFrame || 3780 window.mozCancelAnimationFrame || 3781 window.oCancelAnimationFrame || 3782 function (id) { 3783 window.clearTimeout(id); 3784 } 3785 ); 3786 })(); 3787 3788 var getPointerXY = function (e) { 3789 var result = []; 3790 3791 e = e.originalEvent || e || window.e; 3792 e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e]; 3793 3794 for (var key in e) { 3795 if (e[key].pageX) { 3796 result.push({ 3797 x: e[key].pageX, 3798 y: e[key].pageY 3799 }); 3800 } else if (e[key].clientX) { 3801 result.push({ 3802 x: e[key].clientX, 3803 y: e[key].clientY 3804 }); 3805 } 3806 } 3807 3808 return result; 3809 }; 3810 3811 var distance = function (point2, point1, what) { 3812 if (!point1 || !point2) { 3813 return 0; 3814 } 3815 3816 if (what === "x") { 3817 return point2.x - point1.x; 3818 } else if (what === "y") { 3819 return point2.y - point1.y; 3820 } 3821 3822 return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)); 3823 }; 3824 3825 var isClickable = function ($el) { 3826 if ( 3827 $el.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe') || 3828 $.isFunction($el.get(0).onclick) || 3829 $el.data("selectable") 3830 ) { 3831 return true; 3832 } 3833 3834 // Check for attributes like data-fancybox-next or data-fancybox-close 3835 for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) { 3836 if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") { 3837 return true; 3838 } 3839 } 3840 3841 return false; 3842 }; 3843 3844 var hasScrollbars = function (el) { 3845 var overflowY = window.getComputedStyle(el)["overflow-y"], 3846 overflowX = window.getComputedStyle(el)["overflow-x"], 3847 vertical = (overflowY === "scroll" || overflowY === "auto") && el.scrollHeight > el.clientHeight, 3848 horizontal = (overflowX === "scroll" || overflowX === "auto") && el.scrollWidth > el.clientWidth; 3849 3850 return vertical || horizontal; 3851 }; 3852 3853 var isScrollable = function ($el) { 3854 var rez = false; 3855 3856 while (true) { 3857 rez = hasScrollbars($el.get(0)); 3858 3859 if (rez) { 3860 break; 3861 } 3862 3863 $el = $el.parent(); 3864 3865 if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) { 3866 break; 3867 } 3868 } 3869 3870 return rez; 3871 }; 3872 3873 var Guestures = function (instance) { 3874 var self = this; 3875 3876 self.instance = instance; 3877 3878 self.$bg = instance.$refs.bg; 3879 self.$stage = instance.$refs.stage; 3880 self.$container = instance.$refs.container; 3881 3882 self.destroy(); 3883 3884 self.$container.on("touchstart.fb.touch mousedown.fb.touch", $.proxy(self, "ontouchstart")); 3885 }; 3886 3887 Guestures.prototype.destroy = function () { 3888 var self = this; 3889 3890 self.$container.off(".fb.touch"); 3891 3892 $(document).off(".fb.touch"); 3893 3894 if (self.requestId) { 3895 cancelAFrame(self.requestId); 3896 self.requestId = null; 3897 } 3898 3899 if (self.tapped) { 3900 clearTimeout(self.tapped); 3901 self.tapped = null; 3902 } 3903 }; 3904 3905 Guestures.prototype.ontouchstart = function (e) { 3906 var self = this, 3907 $target = $(e.target), 3908 instance = self.instance, 3909 current = instance.current, 3910 $slide = current.$slide, 3911 $content = current.$content, 3912 isTouchDevice = e.type == "touchstart"; 3913 3914 // Do not respond to both (touch and mouse) events 3915 if (isTouchDevice) { 3916 self.$container.off("mousedown.fb.touch"); 3917 } 3918 3919 // Ignore right click 3920 if (e.originalEvent && e.originalEvent.button == 2) { 3921 return; 3922 } 3923 3924 // Ignore taping on links, buttons, input elements 3925 if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) { 3926 return; 3927 } 3928 // Ignore clicks on the scrollbar 3929 if (!$target.is("img") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) { 3930 return; 3931 } 3932 3933 // Ignore clicks while zooming or closing 3934 if (!current || instance.isAnimating || current.$slide.hasClass("fancybox-animated")) { 3935 e.stopPropagation(); 3936 e.preventDefault(); 3937 3938 return; 3939 } 3940 3941 self.realPoints = self.startPoints = getPointerXY(e); 3942 3943 if (!self.startPoints.length) { 3944 return; 3945 } 3946 3947 // Allow other scripts to catch touch event if "touch" is set to false 3948 if (current.touch) { 3949 e.stopPropagation(); 3950 } 3951 3952 self.startEvent = e; 3953 3954 self.canTap = true; 3955 self.$target = $target; 3956 self.$content = $content; 3957 self.opts = current.opts.touch; 3958 3959 self.isPanning = false; 3960 self.isSwiping = false; 3961 self.isZooming = false; 3962 self.isScrolling = false; 3963 self.canPan = instance.canPan(); 3964 3965 self.startTime = new Date().getTime(); 3966 self.distanceX = self.distanceY = self.distance = 0; 3967 3968 self.canvasWidth = Math.round($slide[0].clientWidth); 3969 self.canvasHeight = Math.round($slide[0].clientHeight); 3970 3971 self.contentLastPos = null; 3972 self.contentStartPos = $.fancyboxforwp.getTranslate(self.$content) || { 3973 top: 0, 3974 left: 0 3975 }; 3976 self.sliderStartPos = $.fancyboxforwp.getTranslate($slide); 3977 3978 // Since position will be absolute, but we need to make it relative to the stage 3979 self.stagePos = $.fancyboxforwp.getTranslate(instance.$refs.stage); 3980 3981 self.sliderStartPos.top -= self.stagePos.top; 3982 self.sliderStartPos.left -= self.stagePos.left; 3983 3984 self.contentStartPos.top -= self.stagePos.top; 3985 self.contentStartPos.left -= self.stagePos.left; 3986 3987 $(document) 3988 .off(".fb.touch") 3989 .on(isTouchDevice ? "touchend.fb.touch touchcancel.fb.touch" : "mouseup.fb.touch mouseleave.fb.touch", $.proxy(self, "ontouchend")) 3990 .on(isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch", $.proxy(self, "ontouchmove")); 3991 3992 if ($.fancyboxforwp.isMobile) { 3993 document.addEventListener("scroll", self.onscroll, true); 3994 } 3995 3996 // Skip if clicked outside the sliding area 3997 if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) { 3998 if ($target.is(".fancybox-image")) { 3999 e.preventDefault(); 4000 } 4001 4002 if (!($.fancyboxforwp.isMobile && $target.parents(".fancybox-caption").length)) { 4003 return; 4004 } 4005 } 4006 4007 self.isScrollable = isScrollable($target) || isScrollable($target.parent()); 4008 4009 // Check if element is scrollable and try to prevent default behavior (scrolling) 4010 if (!($.fancyboxforwp.isMobile && self.isScrollable)) { 4011 e.preventDefault(); 4012 } 4013 4014 // One finger or mouse click - swipe or pan an image 4015 if (self.startPoints.length === 1 || current.hasError) { 4016 if (self.canPan) { 4017 $.fancyboxforwp.stop(self.$content); 4018 4019 self.isPanning = true; 4020 } else { 4021 self.isSwiping = true; 4022 } 4023 4024 self.$container.addClass("fancybox-is-grabbing"); 4025 } 4026 4027 // Two fingers - zoom image 4028 if (self.startPoints.length === 2 && current.type === "image" && (current.isLoaded || current.$ghost)) { 4029 self.canTap = false; 4030 self.isSwiping = false; 4031 self.isPanning = false; 4032 4033 self.isZooming = true; 4034 4035 $.fancyboxforwp.stop(self.$content); 4036 4037 self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft(); 4038 self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop(); 4039 4040 self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width; 4041 self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height; 4042 4043 self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]); 4044 } 4045 }; 4046 4047 Guestures.prototype.onscroll = function (e) { 4048 var self = this; 4049 4050 self.isScrolling = true; 4051 4052 document.removeEventListener("scroll", self.onscroll, true); 4053 }; 4054 4055 Guestures.prototype.ontouchmove = function (e) { 4056 var self = this; 4057 4058 // Make sure user has not released over iframe or disabled element 4059 if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) { 4060 self.ontouchend(e); 4061 return; 4062 } 4063 4064 if (self.isScrolling) { 4065 self.canTap = false; 4066 return; 4067 } 4068 4069 self.newPoints = getPointerXY(e); 4070 4071 if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) { 4072 return; 4073 } 4074 4075 if (!(self.isSwiping && self.isSwiping === true)) { 4076 e.preventDefault(); 4077 } 4078 4079 self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x"); 4080 self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y"); 4081 4082 self.distance = distance(self.newPoints[0], self.startPoints[0]); 4083 4084 // Skip false ontouchmove events (Chrome) 4085 if (self.distance > 0) { 4086 if (self.isSwiping) { 4087 self.onSwipe(e); 4088 } else if (self.isPanning) { 4089 self.onPan(); 4090 } else if (self.isZooming) { 4091 self.onZoom(); 4092 } 4093 } 4094 }; 4095 4096 Guestures.prototype.onSwipe = function (e) { 4097 var self = this, 4098 instance = self.instance, 4099 swiping = self.isSwiping, 4100 left = self.sliderStartPos.left || 0, 4101 angle; 4102 4103 // If direction is not yet determined 4104 if (swiping === true) { 4105 // We need at least 10px distance to correctly calculate an angle 4106 if (Math.abs(self.distance) > 10) { 4107 self.canTap = false; 4108 4109 if (instance.group.length < 2 && self.opts.vertical) { 4110 self.isSwiping = "y"; 4111 } else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) { 4112 self.isSwiping = "x"; 4113 } else { 4114 angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI); 4115 4116 self.isSwiping = angle > 45 && angle < 135 ? "y" : "x"; 4117 } 4118 4119 if (self.isSwiping === "y" && $.fancyboxforwp.isMobile && self.isScrollable) { 4120 self.isScrolling = true; 4121 4122 return; 4123 } 4124 4125 instance.isDragging = self.isSwiping; 4126 4127 // Reset points to avoid jumping, because we dropped first swipes to calculate the angle 4128 self.startPoints = self.newPoints; 4129 4130 $.each(instance.slides, function (index, slide) { 4131 var slidePos, stagePos; 4132 4133 $.fancyboxforwp.stop(slide.$slide); 4134 4135 slidePos = $.fancyboxforwp.getTranslate(slide.$slide); 4136 stagePos = $.fancyboxforwp.getTranslate(instance.$refs.stage); 4137 4138 slide.$slide 4139 .css({ 4140 transform: "", 4141 opacity: "", 4142 "transition-duration": "" 4143 }) 4144 .removeClass("fancybox-animated") 4145 .removeClass(function (index, className) { 4146 return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" "); 4147 }); 4148 4149 if (slide.pos === instance.current.pos) { 4150 self.sliderStartPos.top = slidePos.top - stagePos.top; 4151 self.sliderStartPos.left = slidePos.left - stagePos.left; 4152 } 4153 4154 $.fancyboxforwp.setTranslate(slide.$slide, { 4155 top: slidePos.top - stagePos.top, 4156 left: slidePos.left - stagePos.left 4157 }); 4158 }); 4159 4160 // Stop slideshow 4161 if (instance.SlideShow && instance.SlideShow.isActive) { 4162 instance.SlideShow.stop(); 4163 } 4164 } 4165 4166 return; 4167 } 4168 4169 // Sticky edges 4170 if (swiping == "x") { 4171 if ( 4172 self.distanceX > 0 && 4173 (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop)) 4174 ) { 4175 left = left + Math.pow(self.distanceX, 0.8); 4176 } else if ( 4177 self.distanceX < 0 && 4178 (self.instance.group.length < 2 || 4179 (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop)) 4180 ) { 4181 left = left - Math.pow(-self.distanceX, 0.8); 4182 } else { 4183 left = left + self.distanceX; 4184 } 4185 } 4186 4187 self.sliderLastPos = { 4188 top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY, 4189 left: left 4190 }; 4191 4192 if (self.requestId) { 4193 cancelAFrame(self.requestId); 4194 4195 self.requestId = null; 4196 } 4197 4198 self.requestId = requestAFrame(function () { 4199 if (self.sliderLastPos) { 4200 $.each(self.instance.slides, function (index, slide) { 4201 var pos = slide.pos - self.instance.currPos; 4202 4203 $.fancyboxforwp.setTranslate(slide.$slide, { 4204 top: self.sliderLastPos.top, 4205 left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter 4206 }); 4207 }); 4208 4209 self.$container.addClass("fancybox-is-sliding"); 4210 } 4211 }); 4212 }; 4213 4214 Guestures.prototype.onPan = function () { 4215 var self = this; 4216 4217 // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit) 4218 if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancyboxforwp.isMobile ? 10 : 5)) { 4219 self.startPoints = self.newPoints; 4220 return; 4221 } 4222 4223 self.canTap = false; 4224 4225 self.contentLastPos = self.limitMovement(); 4226 4227 if (self.requestId) { 4228 cancelAFrame(self.requestId); 4229 } 4230 4231 self.requestId = requestAFrame(function () { 4232 $.fancyboxforwp.setTranslate(self.$content, self.contentLastPos); 4233 }); 4234 }; 4235 4236 // Make panning sticky to the edges 4237 Guestures.prototype.limitMovement = function () { 4238 var self = this; 4239 4240 var canvasWidth = self.canvasWidth; 4241 var canvasHeight = self.canvasHeight; 4242 4243 var distanceX = self.distanceX; 4244 var distanceY = self.distanceY; 4245 4246 var contentStartPos = self.contentStartPos; 4247 4248 var currentOffsetX = contentStartPos.left; 4249 var currentOffsetY = contentStartPos.top; 4250 4251 var currentWidth = contentStartPos.width; 4252 var currentHeight = contentStartPos.height; 4253 4254 var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY; 4255 4256 if (currentWidth > canvasWidth) { 4257 newOffsetX = currentOffsetX + distanceX; 4258 } else { 4259 newOffsetX = currentOffsetX; 4260 } 4261 4262 newOffsetY = currentOffsetY + distanceY; 4263 4264 // Slow down proportionally to traveled distance 4265 minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5); 4266 minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5); 4267 4268 maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5); 4269 maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5); 4270 4271 // -> 4272 if (distanceX > 0 && newOffsetX > minTranslateX) { 4273 newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0; 4274 } 4275 4276 // <- 4277 if (distanceX < 0 && newOffsetX < maxTranslateX) { 4278 newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0; 4279 } 4280 4281 // \/ 4282 if (distanceY > 0 && newOffsetY > minTranslateY) { 4283 newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0; 4284 } 4285 4286 // /\ 4287 if (distanceY < 0 && newOffsetY < maxTranslateY) { 4288 newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0; 4289 } 4290 4291 return { 4292 top: newOffsetY, 4293 left: newOffsetX 4294 }; 4295 }; 4296 4297 Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) { 4298 var self = this; 4299 4300 var canvasWidth = self.canvasWidth; 4301 var canvasHeight = self.canvasHeight; 4302 4303 if (newWidth > canvasWidth) { 4304 newOffsetX = newOffsetX > 0 ? 0 : newOffsetX; 4305 newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX; 4306 } else { 4307 // Center horizontally 4308 newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2); 4309 } 4310 4311 if (newHeight > canvasHeight) { 4312 newOffsetY = newOffsetY > 0 ? 0 : newOffsetY; 4313 newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY; 4314 } else { 4315 // Center vertically 4316 newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2); 4317 } 4318 4319 return { 4320 top: newOffsetY, 4321 left: newOffsetX 4322 }; 4323 }; 4324 4325 Guestures.prototype.onZoom = function () { 4326 var self = this; 4327 4328 // Calculate current distance between points to get pinch ratio and new width and height 4329 var contentStartPos = self.contentStartPos; 4330 4331 var currentWidth = contentStartPos.width; 4332 var currentHeight = contentStartPos.height; 4333 4334 var currentOffsetX = contentStartPos.left; 4335 var currentOffsetY = contentStartPos.top; 4336 4337 var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]); 4338 4339 var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers; 4340 4341 var newWidth = Math.floor(currentWidth * pinchRatio); 4342 var newHeight = Math.floor(currentHeight * pinchRatio); 4343 4344 // This is the translation due to pinch-zooming 4345 var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX; 4346 var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY; 4347 4348 // Point between the two touches 4349 var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft(); 4350 var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop(); 4351 4352 // And this is the translation due to translation of the centerpoint 4353 // between the two fingers 4354 var translateFromTranslatingX = centerPointEndX - self.centerPointStartX; 4355 var translateFromTranslatingY = centerPointEndY - self.centerPointStartY; 4356 4357 // The new offset is the old/current one plus the total translation 4358 var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX); 4359 var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY); 4360 4361 var newPos = { 4362 top: newOffsetY, 4363 left: newOffsetX, 4364 scaleX: pinchRatio, 4365 scaleY: pinchRatio 4366 }; 4367 4368 self.canTap = false; 4369 4370 self.newWidth = newWidth; 4371 self.newHeight = newHeight; 4372 4373 self.contentLastPos = newPos; 4374 4375 if (self.requestId) { 4376 cancelAFrame(self.requestId); 4377 } 4378 4379 self.requestId = requestAFrame(function () { 4380 $.fancyboxforwp.setTranslate(self.$content, self.contentLastPos); 4381 }); 4382 }; 4383 4384 Guestures.prototype.ontouchend = function (e) { 4385 var self = this; 4386 4387 var swiping = self.isSwiping; 4388 var panning = self.isPanning; 4389 var zooming = self.isZooming; 4390 var scrolling = self.isScrolling; 4391 4392 self.endPoints = getPointerXY(e); 4393 self.dMs = Math.max(new Date().getTime() - self.startTime, 1); 4394 4395 self.$container.removeClass("fancybox-is-grabbing"); 4396 4397 $(document).off(".fb.touch"); 4398 4399 document.removeEventListener("scroll", self.onscroll, true); 4400 4401 if (self.requestId) { 4402 cancelAFrame(self.requestId); 4403 4404 self.requestId = null; 4405 } 4406 4407 self.isSwiping = false; 4408 self.isPanning = false; 4409 self.isZooming = false; 4410 self.isScrolling = false; 4411 4412 self.instance.isDragging = false; 4413 4414 if (self.canTap) { 4415 return self.onTap(e); 4416 } 4417 4418 self.speed = 100; 4419 4420 // Speed in px/ms 4421 self.velocityX = (self.distanceX / self.dMs) * 0.5; 4422 self.velocityY = (self.distanceY / self.dMs) * 0.5; 4423 4424 if (panning) { 4425 self.endPanning(); 4426 } else if (zooming) { 4427 self.endZooming(); 4428 } else { 4429 self.endSwiping(swiping, scrolling); 4430 } 4431 4432 return; 4433 }; 4434 4435 Guestures.prototype.endSwiping = function (swiping, scrolling) { 4436 var self = this, 4437 ret = false, 4438 len = self.instance.group.length, 4439 distanceX = Math.abs(self.distanceX), 4440 canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50), 4441 speedX = 300; 4442 4443 self.sliderLastPos = null; 4444 4445 // Close if swiped vertically / navigate if horizontally 4446 if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) { 4447 // Continue vertical movement 4448 $.fancyboxforwp.animate( 4449 self.instance.current.$slide, { 4450 top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150, 4451 opacity: 0 4452 }, 4453 200 4454 ); 4455 ret = self.instance.close(true, 250); 4456 } else if (canAdvance && self.distanceX > 0) { 4457 ret = self.instance.previous(speedX); 4458 } else if (canAdvance && self.distanceX < 0) { 4459 ret = self.instance.next(speedX); 4460 } 4461 4462 if (ret === false && (swiping == "x" || swiping == "y")) { 4463 self.instance.centerSlide(200); 4464 } 4465 4466 self.$container.removeClass("fancybox-is-sliding"); 4467 }; 4468 4469 // Limit panning from edges 4470 // ======================== 4471 Guestures.prototype.endPanning = function () { 4472 var self = this, 4473 newOffsetX, 4474 newOffsetY, 4475 newPos; 4476 4477 if (!self.contentLastPos) { 4478 return; 4479 } 4480 4481 if (self.opts.momentum === false || self.dMs > 350) { 4482 newOffsetX = self.contentLastPos.left; 4483 newOffsetY = self.contentLastPos.top; 4484 } else { 4485 // Continue movement 4486 newOffsetX = self.contentLastPos.left + self.velocityX * 500; 4487 newOffsetY = self.contentLastPos.top + self.velocityY * 500; 4488 } 4489 4490 newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height); 4491 4492 newPos.width = self.contentStartPos.width; 4493 newPos.height = self.contentStartPos.height; 4494 4495 $.fancyboxforwp.animate(self.$content, newPos, 366); 4496 }; 4497 4498 Guestures.prototype.endZooming = function () { 4499 var self = this; 4500 4501 var current = self.instance.current; 4502 4503 var newOffsetX, newOffsetY, newPos, reset; 4504 4505 var newWidth = self.newWidth; 4506 var newHeight = self.newHeight; 4507 4508 if (!self.contentLastPos) { 4509 return; 4510 } 4511 4512 newOffsetX = self.contentLastPos.left; 4513 newOffsetY = self.contentLastPos.top; 4514 4515 reset = { 4516 top: newOffsetY, 4517 left: newOffsetX, 4518 width: newWidth, 4519 height: newHeight, 4520 scaleX: 1, 4521 scaleY: 1 4522 }; 4523 4524 // Reset scalex/scaleY values; this helps for perfomance and does not break animation 4525 $.fancyboxforwp.setTranslate(self.$content, reset); 4526 4527 if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) { 4528 self.instance.scaleToFit(150); 4529 } else if (newWidth > current.width || newHeight > current.height) { 4530 self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150); 4531 } else { 4532 newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight); 4533 4534 $.fancyboxforwp.animate(self.$content, newPos, 150); 4535 } 4536 }; 4537 4538 Guestures.prototype.onTap = function (e) { 4539 var self = this; 4540 var $target = $(e.target); 4541 4542 var instance = self.instance; 4543 var current = instance.current; 4544 4545 var endPoints = (e && getPointerXY(e)) || self.startPoints; 4546 4547 var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0; 4548 var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0; 4549 4550 var where; 4551 4552 var process = function (prefix) { 4553 var action = current.opts[prefix]; 4554 4555 if ($.isFunction(action)) { 4556 action = action.apply(instance, [current, e]); 4557 } 4558 4559 if (!action) { 4560 return; 4561 } 4562 4563 switch (action) { 4564 case "close": 4565 instance.close(self.startEvent); 4566 4567 break; 4568 4569 case "toggleControls": 4570 instance.toggleControls(); 4571 4572 break; 4573 4574 case "next": 4575 instance.next(); 4576 4577 break; 4578 4579 case "nextOrClose": 4580 if (instance.group.length > 1) { 4581 instance.next(); 4582 } else { 4583 instance.close(self.startEvent); 4584 } 4585 4586 break; 4587 4588 case "zoom": 4589 if (current.type == "image" && (current.isLoaded || current.$ghost)) { 4590 if (instance.canPan()) { 4591 instance.scaleToFit(); 4592 } else if (instance.isScaledDown()) { 4593 instance.scaleToActual(tapX, tapY); 4594 } else if (instance.group.length < 2) { 4595 instance.close(self.startEvent); 4596 } 4597 } 4598 4599 break; 4600 } 4601 }; 4602 4603 // Ignore right click 4604 if (e.originalEvent && e.originalEvent.button == 2) { 4605 return; 4606 } 4607 4608 // Skip if clicked on the scrollbar 4609 if (!$target.is("img") && tapX > $target[0].clientWidth + $target.offset().left) { 4610 return; 4611 } 4612 4613 // Check where is clicked 4614 if ($target.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container")) { 4615 where = "Outside"; 4616 } else if ($target.is(".fancybox-slide")) { 4617 where = "Slide"; 4618 } else if ( 4619 instance.current.$content && 4620 instance.current.$content 4621 .find($target) 4622 .addBack() 4623 .filter($target).length 4624 ) { 4625 where = "Content"; 4626 } else { 4627 return; 4628 } 4629 4630 // Check if this is a double tap 4631 if (self.tapped) { 4632 // Stop previously created single tap 4633 clearTimeout(self.tapped); 4634 self.tapped = null; 4635 4636 // Skip if distance between taps is too big 4637 if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) { 4638 return this; 4639 } 4640 4641 // OK, now we assume that this is a double-tap 4642 process("dblclick" + where); 4643 } else { 4644 // Single tap will be processed if user has not clicked second time within 300ms 4645 // or there is no need to wait for double-tap 4646 self.tapX = tapX; 4647 self.tapY = tapY; 4648 4649 if (current.opts["dblclick" + where] && current.opts["dblclick" + where] !== current.opts["click" + where]) { 4650 self.tapped = setTimeout(function () { 4651 self.tapped = null; 4652 4653 if (!instance.isAnimating) { 4654 process("click" + where); 4655 } 4656 }, 500); 4657 } else { 4658 process("click" + where); 4659 } 4660 } 4661 4662 return this; 4663 }; 4664 4665 $(document) 4666 .on("onActivate.fb", function (e, instance) { 4667 if (instance && !instance.Guestures) { 4668 instance.Guestures = new Guestures(instance); 4669 } 4670 }) 4671 .on("beforeClose.fb", function (e, instance) { 4672 if (instance && instance.Guestures) { 4673 instance.Guestures.destroy(); 4674 } 4675 }); 4676})(window, document, jQuery); 4677// ========================================================================== 4678// 4679// SlideShow 4680// Enables slideshow functionality 4681// 4682// Example of usage: 4683// $.fancyboxforwp.getInstance().SlideShow.start() 4684// 4685// ========================================================================== 4686(function (document, $) { 4687 "use strict"; 4688 4689 $.extend(true, $.fancyboxforwp.defaults, { 4690 btnTpl: { 4691 slideShow: '<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}">' + 4692 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg>' + 4693 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.33 5.75h2.2v12.5h-2.2V5.75zm5.15 0h2.2v12.5h-2.2V5.75z"/></svg>' + 4694 "</button>" 4695 }, 4696 slideShow: { 4697 autoStart: false, 4698 speed: 3000, 4699 progress: true 4700 } 4701 }); 4702 4703 var SlideShow = function (instance) { 4704 this.instance = instance; 4705 this.init(); 4706 }; 4707 4708 $.extend(SlideShow.prototype, { 4709 timer: null, 4710 isActive: false, 4711 $button: null, 4712 4713 init: function () { 4714 var self = this, 4715 instance = self.instance, 4716 opts = instance.group[instance.currIndex].opts.slideShow; 4717 4718 self.$button = instance.$refs.toolbar.find("[data-fancybox-play]").on("click", function () { 4719 self.toggle(); 4720 }); 4721 4722 if (instance.group.length < 2 || !opts) { 4723 self.$button.hide(); 4724 } else if (opts.progress) { 4725 self.$progress = $('<div class="fancybox-progress"></div>').appendTo(instance.$refs.inner); 4726 } 4727 }, 4728 4729 set: function (force) { 4730 var self = this, 4731 instance = self.instance, 4732 current = instance.current; 4733 4734 // Check if reached last element 4735 if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) { 4736 if (self.isActive && current.contentType !== "video") { 4737 if (self.$progress) { 4738 $.fancyboxforwp.animate(self.$progress.show(), { 4739 scaleX: 1 4740 }, current.opts.slideShow.speed); 4741 } 4742 4743 self.timer = setTimeout(function () { 4744 if (!instance.current.opts.loop && instance.current.index == instance.group.length - 1) { 4745 instance.jumpTo(0); 4746 } else { 4747 instance.next(); 4748 } 4749 }, current.opts.slideShow.speed); 4750 } 4751 } else { 4752 self.stop(); 4753 instance.idleSecondsCounter = 0; 4754 instance.showControls(); 4755 } 4756 }, 4757 4758 clear: function () { 4759 var self = this; 4760 4761 clearTimeout(self.timer); 4762 4763 self.timer = null; 4764 4765 if (self.$progress) { 4766 self.$progress.removeAttr("style").hide(); 4767 } 4768 }, 4769 4770 start: function () { 4771 var self = this, 4772 current = self.instance.current; 4773 4774 if (current) { 4775 self.$button 4776 .attr("title", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_STOP) 4777 .removeClass("fancybox-button--play") 4778 .addClass("fancybox-button--pause"); 4779 4780 self.isActive = true; 4781 4782 if (current.isComplete) { 4783 self.set(true); 4784 } 4785 4786 self.instance.trigger("onSlideShowChange", true); 4787 } 4788 }, 4789 4790 stop: function () { 4791 var self = this, 4792 current = self.instance.current; 4793 4794 self.clear(); 4795 4796 self.$button 4797 .attr("title", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_START) 4798 .removeClass("fancybox-button--pause") 4799 .addClass("fancybox-button--play"); 4800 4801 self.isActive = false; 4802 4803 self.instance.trigger("onSlideShowChange", false); 4804 4805 if (self.$progress) { 4806 self.$progress.removeAttr("style").hide(); 4807 } 4808 }, 4809 4810 toggle: function () { 4811 var self = this; 4812 4813 if (self.isActive) { 4814 self.stop(); 4815 } else { 4816 self.start(); 4817 } 4818 } 4819 }); 4820 4821 $(document).on({ 4822 "onInit.fb": function (e, instance) { 4823 if (instance && !instance.SlideShow) { 4824 instance.SlideShow = new SlideShow(instance); 4825 } 4826 }, 4827 4828 "beforeShow.fb": function (e, instance, current, firstRun) { 4829 var SlideShow = instance && instance.SlideShow; 4830 4831 if (firstRun) { 4832 if (SlideShow && current.opts.slideShow.autoStart) { 4833 SlideShow.start(); 4834 } 4835 } else if (SlideShow && SlideShow.isActive) { 4836 SlideShow.clear(); 4837 } 4838 }, 4839 4840 "afterShow.fb": function (e, instance, current) { 4841 var SlideShow = instance && instance.SlideShow; 4842 4843 if (SlideShow && SlideShow.isActive) { 4844 SlideShow.set(); 4845 } 4846 }, 4847 4848 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 4849 var SlideShow = instance && instance.SlideShow; 4850 4851 // "P" or Spacebar 4852 if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is("button,a,input")) { 4853 keypress.preventDefault(); 4854 4855 SlideShow.toggle(); 4856 } 4857 }, 4858 4859 "beforeClose.fb onDeactivate.fb": function (e, instance) { 4860 var SlideShow = instance && instance.SlideShow; 4861 4862 if (SlideShow) { 4863 SlideShow.stop(); 4864 } 4865 } 4866 }); 4867 4868 // Page Visibility API to pause slideshow when window is not active 4869 $(document).on("visibilitychange", function () { 4870 var instance = $.fancyboxforwp.getInstance(), 4871 SlideShow = instance && instance.SlideShow; 4872 4873 if (SlideShow && SlideShow.isActive) { 4874 if (document.hidden) { 4875 SlideShow.clear(); 4876 } else { 4877 SlideShow.set(); 4878 } 4879 } 4880 }); 4881})(document, jQuery); 4882// ========================================================================== 4883// 4884// FullScreen 4885// Adds fullscreen functionality 4886// 4887// ========================================================================== 4888(function (document, $) { 4889 "use strict"; 4890 4891 // Collection of methods supported by user browser 4892 var fn = (function () { 4893 var fnMap = [ 4894 ["requestFullscreen", "exitFullscreen", "fullscreenElement", "fullscreenEnabled", "fullscreenchange", "fullscreenerror"], 4895 // new WebKit 4896 [ 4897 "webkitRequestFullscreen", 4898 "webkitExitFullscreen", 4899 "webkitFullscreenElement", 4900 "webkitFullscreenEnabled", 4901 "webkitfullscreenchange", 4902 "webkitfullscreenerror" 4903 ], 4904 // old WebKit (Safari 5.1) 4905 [ 4906 "webkitRequestFullScreen", 4907 "webkitCancelFullScreen", 4908 "webkitCurrentFullScreenElement", 4909 "webkitCancelFullScreen", 4910 "webkitfullscreenchange", 4911 "webkitfullscreenerror" 4912 ], 4913 [ 4914 "mozRequestFullScreen", 4915 "mozCancelFullScreen", 4916 "mozFullScreenElement", 4917 "mozFullScreenEnabled", 4918 "mozfullscreenchange", 4919 "mozfullscreenerror" 4920 ], 4921 ["msRequestFullscreen", "msExitFullscreen", "msFullscreenElement", "msFullscreenEnabled", "MSFullscreenChange", "MSFullscreenError"] 4922 ]; 4923 4924 var ret = {}; 4925 4926 for (var i = 0; i < fnMap.length; i++) { 4927 var val = fnMap[i]; 4928 4929 if (val && val[1] in document) { 4930 for (var j = 0; j < val.length; j++) { 4931 ret[fnMap[0][j]] = val[j]; 4932 } 4933 4934 return ret; 4935 } 4936 } 4937 4938 return false; 4939 })(); 4940 4941 if (fn) { 4942 var FullScreen = { 4943 request: function (elem) { 4944 elem = elem || document.documentElement; 4945 4946 elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT); 4947 }, 4948 exit: function () { 4949 document[fn.exitFullscreen](); 4950 }, 4951 toggle: function (elem) { 4952 elem = elem || document.documentElement; 4953 4954 if (this.isFullscreen()) { 4955 this.exit(); 4956 } else { 4957 this.request(elem); 4958 } 4959 }, 4960 isFullscreen: function () { 4961 return Boolean(document[fn.fullscreenElement]); 4962 }, 4963 enabled: function () { 4964 return Boolean(document[fn.fullscreenEnabled]); 4965 } 4966 }; 4967 4968 $.extend(true, $.fancyboxforwp.defaults, { 4969 btnTpl: { 4970 fullScreen: '<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}">' + 4971 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>' + 4972 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z"/></svg>' + 4973 "</button>" 4974 }, 4975 fullScreen: { 4976 autoStart: false 4977 } 4978 }); 4979 4980 $(document).on(fn.fullscreenchange, function () { 4981 var isFullscreen = FullScreen.isFullscreen(), 4982 instance = $.fancyboxforwp.getInstance(); 4983 4984 if (instance) { 4985 // If image is zooming, then force to stop and reposition properly 4986 if (instance.current && instance.current.type === "image" && instance.isAnimating) { 4987 instance.isAnimating = false; 4988 4989 instance.update(true, true, 0); 4990 4991 if (!instance.isComplete) { 4992 instance.complete(); 4993 } 4994 } 4995 4996 instance.trigger("onFullscreenChange", isFullscreen); 4997 4998 instance.$refs.container.toggleClass("fancybox-is-fullscreen", isFullscreen); 4999 5000 instance.$refs.toolbar 5001 .find("[data-fancybox-fullscreen]") 5002 .toggleClass("fancybox-button--fsenter", !isFullscreen) 5003 .toggleClass("fancybox-button--fsexit", isFullscreen); 5004 } 5005 }); 5006 } 5007 5008 $(document).on({ 5009 "onInit.fb": function (e, instance) { 5010 var $container; 5011 5012 if (!fn) { 5013 instance.$refs.toolbar.find("[data-fancybox-fullscreen]").remove(); 5014 5015 return; 5016 } 5017 5018 if (instance && instance.group[instance.currIndex].opts.fullScreen) { 5019 $container = instance.$refs.container; 5020 5021 $container.on("click.fb-fullscreen", "[data-fancybox-fullscreen]", function (e) { 5022 e.stopPropagation(); 5023 e.preventDefault(); 5024 5025 FullScreen.toggle(); 5026 }); 5027 5028 if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) { 5029 FullScreen.request(); 5030 } 5031 5032 // Expose API 5033 instance.FullScreen = FullScreen; 5034 } else if (instance) { 5035 instance.$refs.toolbar.find("[data-fancybox-fullscreen]").hide(); 5036 } 5037 }, 5038 5039 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 5040 // "F" 5041 if (instance && instance.FullScreen && keycode === 70) { 5042 keypress.preventDefault(); 5043 5044 instance.FullScreen.toggle(); 5045 } 5046 }, 5047 5048 "beforeClose.fb": function (e, instance) { 5049 if (instance && instance.FullScreen && instance.$refs.container.hasClass("fancybox-is-fullscreen")) { 5050 FullScreen.exit(); 5051 } 5052 } 5053 }); 5054})(document, jQuery); 5055// ========================================================================== 5056// 5057// Thumbs 5058// Displays thumbnails in a grid 5059// 5060// ========================================================================== 5061(function (document, $) { 5062 "use strict"; 5063 5064 var CLASS = "fancybox-thumbs", 5065 CLASS_ACTIVE = CLASS + "-active"; 5066 5067 // Make sure there are default values 5068 $.fancyboxforwp.defaults = $.extend( 5069 true, { 5070 btnTpl: { 5071 thumbs: '<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}">' + 5072 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.59 14.59h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76H5.65V5.65z"/></svg>' + 5073 "</button>" 5074 }, 5075 thumbs: { 5076 autoStart: false, // Display thumbnails on opening 5077 hideOnClose: true, // Hide thumbnail grid when closing animation starts 5078 parentEl: ".fancybox-container", // Container is injected into this element 5079 axis: "y" // Vertical (y) or horizontal (x) scrolling 5080 } 5081 }, 5082 $.fancyboxforwp.defaults 5083 ); 5084 5085 var FancyThumbs = function (instance) { 5086 this.init(instance); 5087 }; 5088 5089 $.extend(FancyThumbs.prototype, { 5090 $button: null, 5091 $grid: null, 5092 $list: null, 5093 isVisible: false, 5094 isActive: false, 5095 5096 init: function (instance) { 5097 var self = this, 5098 group = instance.group, 5099 enabled = 0; 5100 5101 self.instance = instance; 5102 self.opts = group[instance.currIndex].opts.thumbs; 5103 5104 instance.Thumbs = self; 5105 5106 self.$button = instance.$refs.toolbar.find("[data-fancybox-thumbs]"); 5107 5108 // Enable thumbs if at least two group items have thumbnails 5109 for (var i = 0, len = group.length; i < len; i++) { 5110 if (group[i].thumb) { 5111 enabled++; 5112 } 5113 5114 if (enabled > 1) { 5115 break; 5116 } 5117 } 5118 5119 if (enabled > 1 && !!self.opts) { 5120 self.$button.removeAttr("style").on("click", function () { 5121 self.toggle(); 5122 }); 5123 5124 self.isActive = true; 5125 } else { 5126 self.$button.hide(); 5127 } 5128 }, 5129 5130 create: function () { 5131 var self = this, 5132 instance = self.instance, 5133 parentEl = self.opts.parentEl, 5134 list = [], 5135 src; 5136 5137 if (!self.$grid) { 5138 // Create main element 5139 self.$grid = $('<div class="' + CLASS + " " + CLASS + "-" + self.opts.axis + '"></div>').appendTo( 5140 instance.$refs.container 5141 .find(parentEl) 5142 .addBack() 5143 .filter(parentEl) 5144 ); 5145 5146 // Add "click" event that performs gallery navigation 5147 self.$grid.on("click", "a", function () { 5148 instance.jumpTo($(this).attr("data-index")); 5149 }); 5150 } 5151 5152 // Build the list 5153 if (!self.$list) { 5154 self.$list = $('<div class="' + CLASS + '__list">').appendTo(self.$grid); 5155 } 5156 5157 $.each(instance.group, function (i, item) { 5158 src = item.thumb; 5159 5160 if (!src && item.type === "image") { 5161 src = item.src; 5162 } 5163 5164 list.push( 5165 '<a href="javascript:;" tabindex="0" data-index="' + 5166 i + 5167 '"' + 5168 (src && src.length ? ' style="background-image:url(' + src + ')"' : 'class="fancybox-thumbs-missing"') + 5169 "></a>" 5170 ); 5171 }); 5172 5173 self.$list[0].innerHTML = list.join(""); 5174 5175 if (self.opts.axis === "x") { 5176 // Set fixed width for list element to enable horizontal scrolling 5177 self.$list.width( 5178 parseInt(self.$grid.css("padding-right"), 10) + 5179 instance.group.length * 5180 self.$list 5181 .children() 5182 .eq(0) 5183 .outerWidth(true) 5184 ); 5185 } 5186 }, 5187 5188 focus: function (duration) { 5189 var self = this, 5190 $list = self.$list, 5191 $grid = self.$grid, 5192 thumb, 5193 thumbPos; 5194 5195 if (!self.instance.current) { 5196 return; 5197 } 5198 5199 thumb = $list 5200 .children() 5201 .removeClass(CLASS_ACTIVE) 5202 .filter('[data-index="' + self.instance.current.index + '"]') 5203 .addClass(CLASS_ACTIVE); 5204 5205 thumbPos = thumb.position(); 5206 5207 // Check if need to scroll to make current thumb visible 5208 if (self.opts.axis === "y" && (thumbPos.top < 0 || thumbPos.top > $list.height() - thumb.outerHeight())) { 5209 $list.stop().animate({ 5210 scrollTop: $list.scrollTop() + thumbPos.top 5211 }, 5212 duration 5213 ); 5214 } else if ( 5215 self.opts.axis === "x" && 5216 (thumbPos.left < $grid.scrollLeft() || thumbPos.left > $grid.scrollLeft() + ($grid.width() - thumb.outerWidth())) 5217 ) { 5218 $list 5219 .parent() 5220 .stop() 5221 .animate({ 5222 scrollLeft: thumbPos.left 5223 }, 5224 duration 5225 ); 5226 } 5227 }, 5228 5229 update: function () { 5230 var that = this; 5231 that.instance.$refs.container.toggleClass("fancybox-show-thumbs", this.isVisible); 5232 5233 if (that.isVisible) { 5234 if (!that.$grid) { 5235 that.create(); 5236 } 5237 5238 that.instance.trigger("onThumbsShow"); 5239 5240 that.focus(0); 5241 } else if (that.$grid) { 5242 that.instance.trigger("onThumbsHide"); 5243 } 5244 5245 // Update content position 5246 that.instance.update(); 5247 }, 5248 5249 hide: function () { 5250 this.isVisible = false; 5251 this.update(); 5252 }, 5253 5254 show: function () { 5255 this.isVisible = true; 5256 this.update(); 5257 }, 5258 5259 toggle: function () { 5260 this.isVisible = !this.isVisible; 5261 this.update(); 5262 } 5263 }); 5264 5265 $(document).on({ 5266 "onInit.fb": function (e, instance) { 5267 var Thumbs; 5268 5269 if (instance && !instance.Thumbs) { 5270 Thumbs = new FancyThumbs(instance); 5271 5272 if (Thumbs.isActive && Thumbs.opts.autoStart === true) { 5273 Thumbs.show(); 5274 } 5275 } 5276 }, 5277 5278 "beforeShow.fb": function (e, instance, item, firstRun) { 5279 var Thumbs = instance && instance.Thumbs; 5280 5281 if (Thumbs && Thumbs.isVisible) { 5282 Thumbs.focus(firstRun ? 0 : 250); 5283 } 5284 }, 5285 5286 "afterKeydown.fb": function (e, instance, current, keypress, keycode) { 5287 var Thumbs = instance && instance.Thumbs; 5288 5289 // "G" 5290 if (Thumbs && Thumbs.isActive && keycode === 71) { 5291 keypress.preventDefault(); 5292 5293 Thumbs.toggle(); 5294 } 5295 }, 5296 5297 "beforeClose.fb": function (e, instance) { 5298 var Thumbs = instance && instance.Thumbs; 5299 5300 if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) { 5301 Thumbs.$grid.hide(); 5302 } 5303 } 5304 }); 5305})(document, jQuery); 5306//// ========================================================================== 5307// 5308// Share 5309// Displays simple form for sharing current url 5310// 5311// ========================================================================== 5312(function (document, $) { 5313 "use strict"; 5314 5315 $.extend(true, $.fancyboxforwp.defaults, { 5316 btnTpl: { 5317 share: '<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}">' + 5318 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2.55 19c1.4-8.4 9.1-9.8 11.9-9.8V5l7 7-7 6.3v-3.5c-2.8 0-10.5 2.1-11.9 4.2z"/></svg>' + 5319 "</button>" 5320 }, 5321 share: { 5322 url: function (instance, item) { 5323 return ( 5324 (!instance.currentHash && !(item.type === "inline" || item.type === "html") ? item.origSrc || item.src : false) || window.location 5325 ); 5326 }, 5327 tpl: '<div class="fancybox-share">' + 5328 "<h1>{{SHARE}}</h1>" + 5329 "<p>" + 5330 '<a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}">' + 5331 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196" /></svg>' + 5332 "<span>Facebook</span>" + 5333 "</a>" + 5334 '<a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}">' + 5335 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z" /></svg>' + 5336 "<span>Twitter</span>" + 5337 "</a>" + 5338 '<a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}">' + 5339 '<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z" fill="#fff"/></svg>' + 5340 "<span>Pinterest</span>" + 5341 "</a>" + 5342 "</p>" + 5343 '<p><input class="fancybox-share__input" type="text" value="{{url_raw}}" onclick="select()" /></p>' + 5344 "</div>" 5345 } 5346 }); 5347 5348 function escapeHtml(string) { 5349 var entityMap = { 5350 "&": "&", 5351 "<": "<", 5352 ">": ">", 5353 '"': """, 5354 "'": "'", 5355 "/": "/", 5356 "`": "`", 5357 "=": "=" 5358 }; 5359 5360 return String(string).replace(/[&<>"'`=\/]/g, function (s) { 5361 return entityMap[s]; 5362 }); 5363 } 5364 5365 $(document).on("click", "[data-fancybox-share]", function () { 5366 var instance = $.fancyboxforwp.getInstance(), 5367 current = instance.current || null, 5368 url, 5369 tpl; 5370 5371 if (!current) { 5372 return; 5373 } 5374 5375 if ($.type(current.opts.share.url) === "function") { 5376 url = current.opts.share.url.apply(current, [instance, current]); 5377 } 5378 5379 tpl = current.opts.share.tpl 5380 .replace(/\{\{media\}\}/g, current.type === "image" ? encodeURIComponent(current.src) : "") 5381 .replace(/\{\{url\}\}/g, encodeURIComponent(url)) 5382 .replace(/\{\{url_raw\}\}/g, escapeHtml(url)) 5383 .replace(/\{\{descr\}\}/g, instance.$caption ? encodeURIComponent(instance.$caption.text()) : ""); 5384 5385 $.fancyboxforwp.open({ 5386 src: instance.translate(instance, tpl), 5387 type: "html", 5388 opts: { 5389 touch: false, 5390 animationEffect: false, 5391 afterLoad: function (shareInstance, shareCurrent) { 5392 // Close self if parent instance is closing 5393 instance.$refs.container.one("beforeClose.fb", function () { 5394 shareInstance.close(null, 0); 5395 }); 5396 5397 // Opening links in a popup window 5398 shareCurrent.$content.find(".fancybox-share__button").click(function () { 5399 window.open(this.href, "Share", "width=550, height=450"); 5400 return false; 5401 }); 5402 }, 5403 mobile: { 5404 autoFocus: false 5405 } 5406 } 5407 }); 5408 }); 5409})(document, jQuery); 5410// ========================================================================== 5411// 5412// Hash 5413// Enables linking to each modal 5414// 5415// ========================================================================== 5416(function (window, document, $) { 5417 "use strict"; 5418 5419 // Simple $.escapeSelector polyfill (for jQuery prior v3) 5420 if (!$.escapeSelector) { 5421 $.escapeSelector = function (sel) { 5422 var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; 5423 var fcssescape = function (ch, asCodePoint) { 5424 if (asCodePoint) { 5425 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER 5426 if (ch === "\0") { 5427 return "\uFFFD"; 5428 } 5429 5430 // Control characters and (dependent upon position) numbers get escaped as code points 5431 return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " "; 5432 } 5433 5434 // Other potentially-special ASCII characters get backslash-escaped 5435 return "\\" + ch; 5436 }; 5437 5438 return (sel + "").replace(rcssescape, fcssescape); 5439 }; 5440 } 5441 5442 // Get info about gallery name and current index from url 5443 function parseUrl() { 5444 var hash = window.location.hash.substr(1), 5445 rez = hash.split("-"), 5446 index = rez.length > 1 && /^\+?\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1, 5447 gallery = rez.join("-"); 5448 5449 return { 5450 hash: hash, 5451 /* Index is starting from 1 */ 5452 index: index < 1 ? 1 : index, 5453 gallery: gallery 5454 }; 5455 } 5456 5457 // Trigger click evnt on links to open new fancyBox instance 5458 function triggerFromUrl(url) { 5459 if (url.gallery !== "") { 5460 // If we can find element matching 'data-fancybox' atribute, 5461 // then triggering click event should start fancyBox 5462 $("[data-fancybox='" + $.escapeSelector(url.gallery) + "']") 5463 .eq(url.index - 1) 5464 .focus() 5465 .trigger("click.fb-start"); 5466 } 5467 } 5468 5469 // Get gallery name from current instance 5470 function getGalleryID(instance) { 5471 var opts, ret; 5472 5473 if (!instance) { 5474 return false; 5475 } 5476 5477 opts = instance.current ? instance.current.opts : instance.opts; 5478 ret = opts.hash || (opts.$orig ? opts.$orig.data("fancybox") || opts.$orig.data("fancybox-trigger") : ""); 5479 5480 return ret === "" ? false : ret; 5481 } 5482 5483 // Start when DOM becomes ready 5484 $(function () { 5485 // Check if user has disabled this module 5486 if ($.fancyboxforwp.defaults.hash === false) { 5487 return; 5488 } 5489 5490 // Update hash when opening/closing fancyBox 5491 $(document).on({ 5492 "onInit.fb": function (e, instance) { 5493 var url, gallery; 5494 5495 if (instance.group[instance.currIndex].opts.hash === false) { 5496 return; 5497 } 5498 5499 url = parseUrl(); 5500 gallery = getGalleryID(instance); 5501 5502 // Make sure gallery start index matches index from hash 5503 if (gallery && url.gallery && gallery == url.gallery) { 5504 instance.currIndex = url.index - 1; 5505 } 5506 }, 5507 5508 "beforeShow.fb": function (e, instance, current, firstRun) { 5509 var gallery; 5510 5511 if (!current || current.opts.hash === false) { 5512 return; 5513 } 5514 5515 // Check if need to update window hash 5516 gallery = getGalleryID(instance); 5517 5518 if (!gallery) { 5519 return; 5520 } 5521 5522 // Variable containing last hash value set by fancyBox 5523 // It will be used to determine if fancyBox needs to close after hash change is detected 5524 instance.currentHash = gallery + (instance.group.length > 1 ? "-" + (current.index + 1) : ""); 5525 5526 // If current hash is the same (this instance most likely is opened by hashchange), then do nothing 5527 if (window.location.hash === "#" + instance.currentHash) { 5528 return; 5529 } 5530 5531 if (firstRun && !instance.origHash) { 5532 instance.origHash = window.location.hash; 5533 } 5534 5535 if (instance.hashTimer) { 5536 clearTimeout(instance.hashTimer); 5537 } 5538 5539 // Update hash 5540 instance.hashTimer = setTimeout(function () { 5541 if ("replaceState" in window.history) { 5542 window.history[firstRun ? "pushState" : "replaceState"]({}, 5543 document.title, 5544 window.location.pathname + window.location.search + "#" + instance.currentHash 5545 ); 5546 5547 if (firstRun) { 5548 instance.hasCreatedHistory = true; 5549 } 5550 } else { 5551 window.location.hash = instance.currentHash; 5552 } 5553 5554 instance.hashTimer = null; 5555 }, 300); 5556 }, 5557 5558 "beforeClose.fb": function (e, instance, current) { 5559 if (!current || current.opts.hash === false) { 5560 return; 5561 } 5562 5563 clearTimeout(instance.hashTimer); 5564 5565 // Goto previous history entry 5566 if (instance.currentHash && instance.hasCreatedHistory) { 5567 window.history.back(); 5568 } else if (instance.currentHash) { 5569 if ("replaceState" in window.history) { 5570 window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (instance.origHash || "")); 5571 } else { 5572 window.location.hash = instance.origHash; 5573 } 5574 } 5575 5576 instance.currentHash = null; 5577 } 5578 }); 5579 5580 // Check if need to start/close after url has changed 5581 $(window).on("hashchange.fb", function () { 5582 var url = parseUrl(), 5583 fb = null; 5584 5585 // Find last fancyBox instance that has "hash" 5586 $.each( 5587 $(".fancybox-container") 5588 .get() 5589 .reverse(), 5590 function (index, value) { 5591 var tmp = $(value).data("FancyBox"); 5592 5593 if (tmp && tmp.currentHash) { 5594 fb = tmp; 5595 return false; 5596 } 5597 } 5598 ); 5599 5600 if (fb) { 5601 // Now, compare hash values 5602 if (fb.currentHash !== url.gallery + "-" + url.index && !(url.index === 1 && fb.currentHash == url.gallery)) { 5603 fb.currentHash = null; 5604 5605 fb.close(); 5606 } 5607 } else if (url.gallery !== "") { 5608 triggerFromUrl(url); 5609 } 5610 }); 5611 5612 // Check current hash and trigger click event on matching element to start fancyBox, if needed 5613 setTimeout(function () { 5614 if (!$.fancyboxforwp.getInstance()) { 5615 triggerFromUrl(parseUrl()); 5616 } 5617 }, 50); 5618 }); 5619})(window, document, jQuery); 5620// ========================================================================== 5621// 5622// Wheel 5623// Basic mouse weheel support for gallery navigation 5624// 5625// ========================================================================== 5626(function (document, $) { 5627 "use strict"; 5628 5629 var prevTime = new Date().getTime(); 5630 5631 $(document).on({ 5632 "onInit.fb": function (e, instance, current) { 5633 instance.$refs.stage.on("mousewheel DOMMouseScroll wheel MozMousePixelScroll", function (e) { 5634 var current = instance.current, 5635 currTime = new Date().getTime(); 5636 5637 if (instance.group.length < 2 || current.opts.wheel === false || (current.opts.wheel === "auto" && current.type !== "image")) { 5638 return; 5639 } 5640 5641 e.preventDefault(); 5642 e.stopPropagation(); 5643 5644 if (current.$slide.hasClass("fancybox-animated")) { 5645 return; 5646 } 5647 5648 e = e.originalEvent || e; 5649 5650 if (currTime - prevTime < 250) { 5651 return; 5652 } 5653 5654 prevTime = currTime; 5655 5656 instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? "next" : "previous"](); 5657 }); 5658 } 5659 }); 5660})(document, jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.