From 576556d34f6bf1814548ebd76a1d5a5f73027de9 Mon Sep 17 00:00:00 2001 From: Conner Chu Date: Sun, 6 Jul 2025 11:53:41 +0200 Subject: [PATCH] add vendor --- .../assets/shortcode-gallery/filterbar.sass | 52 + .../font-awesome/compress-alt-solid.svg | 1 + .../font-awesome/expand-alt-solid.svg | 1 + .../font-awesome/license.txt | 1 + .../mfg92/hugo-shortcode-gallery/config.toml | 4 + .../layouts/shortcodes/gallery.html | 436 ++++++ .../shortcode-gallery/jquery-3.7.1.min.js | 2 + .../justified_gallery/LICENSE | 22 + .../jquery.justifiedGallery.js | 1202 +++++++++++++++++ .../jquery.justifiedGallery.min.js | 1 + .../justified_gallery/justifiedGallery.css | 96 ++ .../justifiedGallery.min.css | 6 + .../shortcode-gallery/lazy/jquery.lazy.js | 872 ++++++++++++ .../shortcode-gallery/lazy/jquery.lazy.min.js | 1 + .../swipebox/css/swipebox.css | 332 +++++ .../swipebox/css/swipebox.min.css | 1 + .../shortcode-gallery/swipebox/img/icons.png | Bin 0 -> 729 bytes .../shortcode-gallery/swipebox/img/icons.svg | 1 + .../shortcode-gallery/swipebox/img/loader.gif | Bin 0 -> 2608 bytes .../swipebox/js/jquery.swipebox.js | 1023 ++++++++++++++ .../swipebox/js/jquery.swipebox.min.js | 2 + .../mfg92/hugo-shortcode-gallery/theme.toml | 12 + _vendor/modules.txt | 1 + 23 files changed, 4069 insertions(+) create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/filterbar.sass create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/compress-alt-solid.svg create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/expand-alt-solid.svg create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/license.txt create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/config.toml create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/layouts/shortcodes/gallery.html create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/jquery-3.7.1.min.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/LICENSE create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/jquery.justifiedGallery.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.css create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.min.css create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.min.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/css/swipebox.css create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/css/swipebox.min.css create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/img/icons.png create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/img/icons.svg create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/img/loader.gif create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/js/jquery.swipebox.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/swipebox/js/jquery.swipebox.min.js create mode 100644 _vendor/github.com/mfg92/hugo-shortcode-gallery/theme.toml create mode 100644 _vendor/modules.txt diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/filterbar.sass b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/filterbar.sass new file mode 100644 index 0000000..23004e5 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/filterbar.sass @@ -0,0 +1,52 @@ +/* Changes made here sadly only apply after restarting hugo server */ + +/* make 5px space between the button(filter options) in the filter bar +.justified-gallery-filterbar + display: flex + justify-content: flex-start + flex-wrap: wrap + gap: 5px + + button + padding: 6px + border: 1px solid #fff + border-radius: 5px + background-color: transparent + font-weight: bold + color: #fff + line-height: 1em + + &:hover + text-decoration: underline + + &.selected + text-decoration: underline + background-color: #fff3 + + svg + width: 1em + height: 1em + transform: rotate(90deg) + transition: transform .2s linear + + &:hover svg + transform: rotate(90deg) scale(1.3) + + +.fulltab + position: absolute + top: 0 + left: 0 + z-index: 100 + min-height: 100% + min-width: 100% + background-color: #222 + + .justified-gallery-filterbar + position: sticky + top: 0 + left: 0 + z-index: 101 + background-color: #222 + padding: 5px + margin: 0px diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/compress-alt-solid.svg b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/compress-alt-solid.svg new file mode 100644 index 0000000..4625a19 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/compress-alt-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/expand-alt-solid.svg b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/expand-alt-solid.svg new file mode 100644 index 0000000..14f859b --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/expand-alt-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/license.txt b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/license.txt new file mode 100644 index 0000000..c27f229 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/assets/shortcode-gallery/font-awesome/license.txt @@ -0,0 +1 @@ +https://fontawesome.com/license/free \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/config.toml b/_vendor/github.com/mfg92/hugo-shortcode-gallery/config.toml new file mode 100644 index 0000000..4e8bd48 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/config.toml @@ -0,0 +1,4 @@ +[module] +[module.hugoVersion] + extended = true + min = '0.121.2' diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/layouts/shortcodes/gallery.html b/_vendor/github.com/mfg92/hugo-shortcode-gallery/layouts/shortcodes/gallery.html new file mode 100644 index 0000000..f05c98f --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/layouts/shortcodes/gallery.html @@ -0,0 +1,436 @@ +{{ $currentPage := . }} + +{{ $images := slice }} +{{ if .Get "match"}} + {{ $images = (.Page.Resources.Match (.Get "match")) }} +{{ else }} + {{ $images = (.Page.Resources.ByType "image") }} +{{ end }} + +{{ $filterOptions := .Get "filterOptions" | default (.Site.Params.galleryFilterOptions | default "[]") }} +{{ if not $filterOptions }} + {{ $filterOptions = "[]" }} +{{ end }} + +{{ $storeSelectedFilterInUrl := .Get "storeSelectedFilterInUrl" | default (.Site.Params.storeSelectedFilterInUrl | default false) }} + +{{ $sortOrder := .Get "sortOrder" | default (.Site.Params.gallerySortOrder | default "asc") }} + +{{ $rowHeight := .Get "rowHeight" | default (.Site.Params.galleryRowHeight | default 150) }} + +{{ $margins := .Get "margins" | default (.Site.Params.galleryRowMargins | default 5) }} + +{{ $randomize := .Get "randomize" | default (.Site.Params.galleryRandomize | default false) }} + +{{ $thumbnailResizeOptions := .Get "thumbnailResizeOptions" | default (.Site.Params.galleryThumbnailResizeOptions | default "300x150 q85 Lanczos") }} + +{{ $imageResizeOptions := .Get "imageResizeOptions" | default .Site.Params.galleryImageResizeOptions }} + +{{ $loadJQuery := .Get "loadJQuery" | default (.Site.Params.galleryLoadJQuery | default false) }} + +{{ $showExif := .Get "showExif" | default (.Site.Params.galleryShowExif | default false) }} + +{{ $swipeboxParameters := .Get "swipeboxParameters" | default (.Site.Params.gallerySwipeboxParameters | default "") }} + +{{ $justifiedGalleryParameters := .Get "justifiedGalleryParameters" | default (.Site.Params.galleryJustifiedGalleryParameters | default "") }} + +{{ $previewType := .Get "previewType" | default (.Site.Params.galleryPreviewType | default "blur") }} + +{{ $embedPreview := .Get "embedPreview" | default (.Site.Params.galleryEmbedPreview | default true) }} + +{{ $thumbnailHoverEffect := .Get "thumbnailHoverEffect" | default (.Site.Params.galleryThumbnailHoverEffect | default "none") }} + + +{{ $thumbnailResourceDir := printf "%s%s" (.Site.Params.resourceDir | default "resources") "/_gen/images/" }} + + +{{ if not (.Page.Scratch.Get "galleryLoaded") }} + {{ .Page.Scratch.Set "galleryLoaded" true }} + + + {{ if $loadJQuery }} + + {{ end }} + + {{ if not (eq $previewType "none") }} + + {{ end }} + + + + + + +{{ end }} + + + + +{{ $galleryId := (printf "gallery-%v-%v" .Page.File.UniqueID .Ordinal)}} +{{ $galleryWrapperId := (printf "gallery-%v-%v-wrapper" .Page.File.UniqueID .Ordinal)}} + + + + diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/jquery-3.7.1.min.js b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0= 0 ? settings.border : settings.margins; + this.maxRowHeight = this.retrieveMaxRowHeight(); + this.suffixRanges = this.retrieveSuffixRanges(); + this.offY = this.border; + this.rows = 0; + this.spinner = { + phase : 0, + timeSlot : 150, + $el : $('
'), + intervalId : null + }; + this.scrollBarOn = false; + this.checkWidthIntervalId = null; + this.galleryWidth = $gallery.width(); + this.$gallery = $gallery; + + }; + + /** @returns {String} the best suffix given the width and the height */ + JustifiedGallery.prototype.getSuffix = function (width, height) { + var longestSide, i; + longestSide = (width > height) ? width : height; + for (i = 0; i < this.suffixRanges.length; i++) { + if (longestSide <= this.suffixRanges[i]) { + return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; + } + } + return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; + }; + + /** + * Remove the suffix from the string + * + * @returns {string} a new string without the suffix + */ + JustifiedGallery.prototype.removeSuffix = function (str, suffix) { + return str.substring(0, str.length - suffix.length); + }; + + /** + * @returns {boolean} a boolean to say if the suffix is contained in the str or not + */ + JustifiedGallery.prototype.endsWith = function (str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + }; + + /** + * Get the used suffix of a particular url + * + * @param str + * @returns {String} return the used suffix + */ + JustifiedGallery.prototype.getUsedSuffix = function (str) { + for (var si in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { + if (this.settings.sizeRangeSuffixes[si].length === 0) continue; + if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; + } + } + return ''; + }; + + /** + * Given an image src, with the width and the height, returns the new image src with the + * best suffix to show the best quality thumbnail. + * + * @returns {String} the suffix to use + */ + JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) { + var newImageSrc; + + if (this.settings.thumbnailPath) { + newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image); + } else { + var matchRes = imageSrc.match(this.settings.extension); + var ext = (matchRes !== null) ? matchRes[0] : ''; + newImageSrc = imageSrc.replace(this.settings.extension, ''); + newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc)); + newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; + } + + return newImageSrc; + }; + + /** + * Shows the images that is in the given entry + * + * @param $entry the entry + * @param callback the callback that is called when the show animation is finished + */ + JustifiedGallery.prototype.showImg = function ($entry, callback) { + if (this.settings.cssAnimation) { + $entry.addClass('entry-visible'); + if (callback) callback(); + } else { + $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); + $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); + } + }; + + /** + * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the + * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. + * + * @param $image the image to analyze + * @returns {String} the extracted src + */ + JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { + var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); + $image.data('jg.originalSrc', imageSrc); + return imageSrc; + }; + + /** @returns {jQuery} the image in the given entry */ + JustifiedGallery.prototype.imgFromEntry = function ($entry) { + var $img = $entry.find(this.settings.imgSelector); + return $img.length === 0 ? null : $img; + }; + + /** @returns {jQuery} the caption in the given entry */ + JustifiedGallery.prototype.captionFromEntry = function ($entry) { + var $caption = $entry.find('> .caption'); + return $caption.length === 0 ? null : $caption; + }; + + /** + * Display the entry + * + * @param {jQuery} $entry the entry to display + * @param {int} x the x position where the entry must be positioned + * @param y the y position where the entry must be positioned + * @param imgWidth the image width + * @param imgHeight the image height + * @param rowHeight the row height of the row that owns the entry + */ + JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { + $entry.width(imgWidth); + $entry.height(rowHeight); + $entry.css('top', y); + $entry.css('left', x); + + var $image = this.imgFromEntry($entry); + if ($image !== null) { + $image.css('width', imgWidth); + $image.css('height', imgHeight); + $image.css('margin-left', - imgWidth / 2); + $image.css('margin-top', - imgHeight / 2); + + // Image reloading for an high quality of thumbnails + var imageSrc = $image.attr('src'); + var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]); + + $image.one('error', function () { + $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. + }); + + var loadNewImage = function () { + if (imageSrc !== newImageSrc) { //load the new image after the fadeIn + $image.attr('src', newImageSrc); + } + }; + + if ($entry.data('jg.loaded') === 'skipped') { + this.onImageEvent(imageSrc, $.proxy(function() { + this.showImg($entry, loadNewImage); + $entry.data('jg.loaded', true); + }, this)); + } else { + this.showImg($entry, loadNewImage); + } + + } else { + this.showImg($entry); + } + + this.displayEntryCaption($entry); + }; + + /** + * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' + * or the 'title' attributes. + * + * @param {jQuery} $entry the entry to process + */ + JustifiedGallery.prototype.displayEntryCaption = function ($entry) { + var $image = this.imgFromEntry($entry); + if ($image !== null && this.settings.captions) { + var $imgCaption = this.captionFromEntry($entry); + + // Create it if it doesn't exists + if ($imgCaption === null) { + var caption = $image.attr('alt'); + if (!this.isValidCaption(caption)) caption = $entry.attr('title'); + if (this.isValidCaption(caption)) { // Create only we found something + $imgCaption = $('
' + caption + '
'); + $entry.append($imgCaption); + $entry.data('jg.createdCaption', true); + } + } + + // Create events (we check again the $imgCaption because it can be still inexistent) + if ($imgCaption !== null) { + if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); + this.addCaptionEventsHandlers($entry); + } + } else { + this.removeCaptionEventsHandlers($entry); + } + }; + + /** + * Validates the caption + * + * @param caption The caption that should be validated + * @return {boolean} Validation result + */ + JustifiedGallery.prototype.isValidCaption = function (caption) { + return (typeof caption !== 'undefined' && caption.length > 0); + }; + + /** + * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. + * It shows the caption using jQuery (or using CSS if it is configured so) + * + * @param {Event} eventObject the event object + */ + JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { + var $caption = this.captionFromEntry($(eventObject.currentTarget)); + if (this.settings.cssAnimation) { + $caption.addClass('caption-visible').removeClass('caption-hidden'); + } else { + $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, + this.settings.captionSettings.visibleOpacity); + } + }; + + /** + * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. + * It hides the caption using jQuery (or using CSS if it is configured so) + * + * @param {Event} eventObject the event object + */ + JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { + var $caption = this.captionFromEntry($(eventObject.currentTarget)); + if (this.settings.cssAnimation) { + $caption.removeClass('caption-visible').removeClass('caption-hidden'); + } else { + $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, + this.settings.captionSettings.nonVisibleOpacity); + } + }; + + /** + * Add the handlers of the entry for the caption + * + * @param $entry the entry to modify + */ + JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { + var captionMouseEvents = $entry.data('jg.captionMouseEvents'); + if (typeof captionMouseEvents === 'undefined') { + captionMouseEvents = { + mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), + mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) + }; + $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); + $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); + $entry.data('jg.captionMouseEvents', captionMouseEvents); + } + }; + + /** + * Remove the handlers of the entry for the caption + * + * @param $entry the entry to modify + */ + JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { + var captionMouseEvents = $entry.data('jg.captionMouseEvents'); + if (typeof captionMouseEvents !== 'undefined') { + $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); + $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); + $entry.removeData('jg.captionMouseEvents'); + } + }; + + /** + * Clear the building row data to be used for a new row + */ + JustifiedGallery.prototype.clearBuildingRow = function () { + this.buildingRow.entriesBuff = []; + this.buildingRow.aspectRatio = 0; + this.buildingRow.width = 0; + }; + + /** + * Justify the building row, preparing it to + * + * @param isLastRow + * @returns a boolean to know if the row has been justified or not + */ + JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { + var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; + var minHeight = 0; + var availableWidth = this.galleryWidth - 2 * this.border - ( + (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); + var rowHeight = availableWidth / this.buildingRow.aspectRatio; + var defaultRowHeight = this.settings.rowHeight; + var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; + + //Skip the last row if we can't justify it and the lastRow == 'hide' + if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { + for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + if (this.settings.cssAnimation) + $entry.removeClass('entry-visible'); + else { + $entry.stop().fadeTo(0, 0.1); + $entry.find('> img, > a > img').fadeTo(0, 0); + } + } + return -1; + } + + // With lastRow = nojustify, justify if is justificable (the images will not become too big) + if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') { + justify = false; + + if (this.rows > 0) { + defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows; + justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold; + } + } + + for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); + + if (justify) { + newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; + newImgH = rowHeight; + } else { + newImgW = defaultRowHeight * imgAspectRatio; + newImgH = defaultRowHeight; + } + + availableWidth -= Math.round(newImgW); + $entry.data('jg.jwidth', Math.round(newImgW)); + $entry.data('jg.jheight', Math.ceil(newImgH)); + if (i === 0 || minHeight > newImgH) minHeight = newImgH; + } + + this.buildingRow.height = minHeight; + return justify; + }; + + /** + * Flush a row: justify it, modify the gallery height accordingly to the row height + * + * @param isLastRow + */ + JustifiedGallery.prototype.flushRow = function (isLastRow) { + var settings = this.settings; + var $entry, buildingRowRes, offX = this.border, i; + + buildingRowRes = this.prepareBuildingRow(isLastRow); + if (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1) { + this.clearBuildingRow(); + return; + } + + if(this.maxRowHeight) { + if(this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight; + } + + //Align last (unjustified) row + if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) { + var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins; + + for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + availableWidth -= $entry.data('jg.jwidth'); + } + + if (settings.lastRow === 'center') + offX += availableWidth / 2; + else if (settings.lastRow === 'right') + offX += availableWidth; + } + + var lastEntryIdx = this.buildingRow.entriesBuff.length - 1; + for (i = 0; i <= lastEntryIdx; i++) { + $entry = this.buildingRow.entriesBuff[ this.settings.rtl ? lastEntryIdx - i : i ]; + this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height); + offX += $entry.data('jg.jwidth') + settings.margins; + } + + //Gallery Height + this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border; + this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight()); + + if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) { + //Ready for a new row + this.offY += this.buildingRow.height + settings.margins; + this.rows += 1; + this.clearBuildingRow(); + this.settings.triggerEvent.call(this, 'jg.rowflush'); + } + }; + + + // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221 + var galleryPrevStaticHeight = 0; + + JustifiedGallery.prototype.rememberGalleryHeight = function () { + galleryPrevStaticHeight = this.$gallery.height(); + this.$gallery.height(galleryPrevStaticHeight); + }; + + // grow only + JustifiedGallery.prototype.setGalleryTempHeight = function (height) { + galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight); + this.$gallery.height(galleryPrevStaticHeight); + }; + + JustifiedGallery.prototype.setGalleryFinalHeight = function (height) { + galleryPrevStaticHeight = height; + this.$gallery.height(height); + }; + + /** + * @returns {boolean} a boolean saying if the scrollbar is active or not + */ + function hasScrollBar() { + return $("body").height() > $(window).height(); + } + + /** + * Checks the width of the gallery container, to know if a new justification is needed + */ + JustifiedGallery.prototype.checkWidth = function () { + this.checkWidthIntervalId = setInterval($.proxy(function () { + + // if the gallery is not currently visible, abort. + if (!this.$gallery.is(":visible")) return; + + var galleryWidth = parseFloat(this.$gallery.width()); + if (hasScrollBar() === this.scrollBarOn) { + if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) { + this.galleryWidth = galleryWidth; + this.rewind(); + + this.rememberGalleryHeight(); + + // Restart to analyze + this.startImgAnalyzer(true); + } + } else { + this.scrollBarOn = hasScrollBar(); + this.galleryWidth = galleryWidth; + } + }, this), this.settings.refreshTime); + }; + + /** + * @returns {boolean} a boolean saying if the spinner is active or not + */ + JustifiedGallery.prototype.isSpinnerActive = function () { + return this.spinner.intervalId !== null; + }; + + /** + * @returns {int} the spinner height + */ + JustifiedGallery.prototype.getSpinnerHeight = function () { + return this.spinner.$el.innerHeight(); + }; + + /** + * Stops the spinner animation and modify the gallery height to exclude the spinner + */ + JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { + clearInterval(this.spinner.intervalId); + this.spinner.intervalId = null; + this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight()); + this.spinner.$el.detach(); + }; + + /** + * Starts the spinner animation + */ + JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { + var spinnerContext = this.spinner; + var $spinnerPoints = spinnerContext.$el.find('span'); + clearInterval(spinnerContext.intervalId); + this.$gallery.append(spinnerContext.$el); + this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight()); + spinnerContext.intervalId = setInterval(function () { + if (spinnerContext.phase < $spinnerPoints.length) { + $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); + } else { + $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); + } + spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); + }, spinnerContext.timeSlot); + }; + + /** + * Rewind the image analysis to start from the first entry. + */ + JustifiedGallery.prototype.rewind = function () { + this.lastFetchedEntry = null; + this.lastAnalyzedIndex = -1; + this.offY = this.border; + this.rows = 0; + this.clearBuildingRow(); + }; + + /** + * Update the entries searching it from the justified gallery HTML element + * + * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) + * @returns {boolean} true if some entries has been founded + */ + JustifiedGallery.prototype.updateEntries = function (norewind) { + var newEntries; + + if (norewind && this.lastFetchedEntry != null) { + newEntries = $(this.lastFetchedEntry).nextAll(this.settings.selector).toArray(); + } else { + this.entries = []; + newEntries = this.$gallery.children(this.settings.selector).toArray(); + } + + if (newEntries.length > 0) { + + // Sort or randomize + if ($.isFunction(this.settings.sort)) { + newEntries = this.sortArray(newEntries); + } else if (this.settings.randomize) { + newEntries = this.shuffleArray(newEntries); + } + this.lastFetchedEntry = newEntries[newEntries.length - 1]; + + // Filter + if (this.settings.filter) { + newEntries = this.filterArray(newEntries); + } else { + this.resetFilters(newEntries); + } + + } + + this.entries = this.entries.concat(newEntries); + return true; + }; + + /** + * Apply the entries order to the DOM, iterating the entries and appending the images + * + * @param entries the entries that has been modified and that must be re-ordered in the DOM + */ + JustifiedGallery.prototype.insertToGallery = function (entries) { + var that = this; + $.each(entries, function () { + $(this).appendTo(that.$gallery); + }); + }; + + /** + * Shuffle the array using the Fisher-Yates shuffle algorithm + * + * @param a the array to shuffle + * @return the shuffled array + */ + JustifiedGallery.prototype.shuffleArray = function (a) { + var i, j, temp; + for (i = a.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + this.insertToGallery(a); + return a; + }; + + /** + * Sort the array using settings.comparator as comparator + * + * @param a the array to sort (it is sorted) + * @return the sorted array + */ + JustifiedGallery.prototype.sortArray = function (a) { + a.sort(this.settings.sort); + this.insertToGallery(a); + return a; + }; + + /** + * Reset the filters removing the 'jg-filtered' class from all the entries + * + * @param a the array to reset + */ + JustifiedGallery.prototype.resetFilters = function (a) { + for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); + }; + + /** + * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. + * + * @param a the array to filter + * @return the filtered array + */ + JustifiedGallery.prototype.filterArray = function (a) { + var settings = this.settings; + if ($.type(settings.filter) === 'string') { + // Filter only keeping the entries passed in the string + return a.filter(function (el) { + var $el = $(el); + if ($el.is(settings.filter)) { + $el.removeClass('jg-filtered'); + return true; + } else { + $el.addClass('jg-filtered').removeClass('jg-visible'); + return false; + } + }); + } else if ($.isFunction(settings.filter)) { + // Filter using the passed function + var filteredArr = a.filter(settings.filter); + for (var i = 0; i < a.length; i++) { + if (filteredArr.indexOf(a[i]) === -1) { + $(a[i]).addClass('jg-filtered').removeClass('jg-visible'); + } else { + $(a[i]).removeClass('jg-filtered'); + } + } + return filteredArr; + } + }; + + /** + * Destroy the Justified Gallery instance. + * + * It clears all the css properties added in the style attributes. We doesn't backup the original + * values for those css attributes, because it costs (performance) and because in general one + * shouldn't use the style attribute for an uniform set of images (where we suppose the use of + * classes). Creating a backup is also difficult because JG could be called multiple times and + * with different style attributes. + */ + JustifiedGallery.prototype.destroy = function () { + clearInterval(this.checkWidthIntervalId); + + $.each(this.entries, $.proxy(function(_, entry) { + var $entry = $(entry); + + // Reset entry style + $entry.css('width', ''); + $entry.css('height', ''); + $entry.css('top', ''); + $entry.css('left', ''); + $entry.data('jg.loaded', undefined); + $entry.removeClass('jg-entry'); + + // Reset image style + var $img = this.imgFromEntry($entry); + $img.css('width', ''); + $img.css('height', ''); + $img.css('margin-left', ''); + $img.css('margin-top', ''); + $img.attr('src', $img.data('jg.originalSrc')); + $img.data('jg.originalSrc', undefined); + + // Remove caption + this.removeCaptionEventsHandlers($entry); + var $caption = this.captionFromEntry($entry); + if ($entry.data('jg.createdCaption')) { + // remove also the caption element (if created by jg) + $entry.data('jg.createdCaption', undefined); + if ($caption !== null) $caption.remove(); + } else { + if ($caption !== null) $caption.fadeTo(0, 1); + } + + }, this)); + + this.$gallery.css('height', ''); + this.$gallery.removeClass('justified-gallery'); + this.$gallery.data('jg.controller', undefined); + }; + + /** + * Analyze the images and builds the rows. It returns if it found an image that is not loaded. + * + * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end + */ + JustifiedGallery.prototype.analyzeImages = function (isForResize) { + for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { + var $entry = $(this.entries[i]); + if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { + var availableWidth = this.galleryWidth - 2 * this.border - ( + (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); + var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); + if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { + this.flushRow(false); + + if(++this.yield.flushed >= this.yield.every) { + this.startImgAnalyzer(isForResize); + return; + } + } + + this.buildingRow.entriesBuff.push($entry); + this.buildingRow.aspectRatio += imgAspectRatio; + this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; + this.lastAnalyzedIndex = i; + + } else if ($entry.data('jg.loaded') !== 'error') { + return; + } + } + + // Last row flush (the row is not full) + if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); + + if (this.isSpinnerActive()) { + this.stopLoadingSpinnerAnimation(); + } + + /* Stop, if there is, the timeout to start the analyzeImages. + This is because an image can be set loaded, and the timeout can be set, + but this image can be analyzed yet. + */ + this.stopImgAnalyzerStarter(); + + //On complete callback + this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete'); + this.setGalleryFinalHeight(this.galleryHeightToSet); + }; + + /** + * Stops any ImgAnalyzer starter (that has an assigned timeout) + */ + JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { + this.yield.flushed = 0; + if (this.imgAnalyzerTimeout !== null) { + clearTimeout(this.imgAnalyzerTimeout); + this.imgAnalyzerTimeout = null; + } + }; + + /** + * Starts the image analyzer. It is not immediately called to let the browser to update the view + * + * @param isForResize specifies if the image analyzer must be called for resizing or not + */ + JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { + var that = this; + this.stopImgAnalyzerStarter(); + this.imgAnalyzerTimeout = setTimeout(function () { + that.analyzeImages(isForResize); + }, 0.001); // we can't start it immediately due to a IE different behaviour + }; + + /** + * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, + * because some browsers, with a 404 set complete = true. + * + * @param imageSrc the image src to load + * @param onLoad callback that is called when the image has been loaded + * @param onError callback that is called in case of an error + */ + JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { + if (!onLoad && !onError) return; + + var memImage = new Image(); + var $memImage = $(memImage); + if (onLoad) { + $memImage.one('load', function () { + $memImage.off('load error'); + onLoad(memImage); + }); + } + if (onError) { + $memImage.one('error', function() { + $memImage.off('load error'); + onError(memImage); + }); + } + memImage.src = imageSrc; + }; + + /** + * Init of Justified Gallery controlled + * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) + */ + JustifiedGallery.prototype.init = function () { + var imagesToLoad = false, skippedImages = false, that = this; + $.each(this.entries, function (index, entry) { + var $entry = $(entry); + var $image = that.imgFromEntry($entry); + + $entry.addClass('jg-entry'); + + if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { + + // Link Rel global overwrite + if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); + + // Link Target global overwrite + if (that.settings.target !== null) $entry.attr('target', that.settings.target); + + if ($image !== null) { + + // Image src + var imageSrc = that.extractImgSrcFromImage($image); + $image.attr('src', imageSrc); + + /* If we have the height and the width, we don't wait that the image is loaded, but we start directly + * with the justification */ + if (that.settings.waitThumbnailsLoad === false) { + var width = parseFloat($image.attr('width')); + var height = parseFloat($image.attr('height')); + if (!isNaN(width) && !isNaN(height)) { + $entry.data('jg.width', width); + $entry.data('jg.height', height); + $entry.data('jg.loaded', 'skipped'); + skippedImages = true; + that.startImgAnalyzer(false); + return true; // continue + } + } + + $entry.data('jg.loaded', false); + imagesToLoad = true; + + // Spinner start + if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation(); + + that.onImageEvent(imageSrc, function (loadImg) { // image loaded + $entry.data('jg.width', loadImg.width); + $entry.data('jg.height', loadImg.height); + $entry.data('jg.loaded', true); + that.startImgAnalyzer(false); + }, function () { // image load error + $entry.data('jg.loaded', 'error'); + that.startImgAnalyzer(false); + }); + + } else { + $entry.data('jg.loaded', true); + $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1); + $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1); + } + + } + + }); + + if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); + this.checkWidth(); + }; + + /** + * Checks that it is a valid number. If a string is passed it is converted to a number + * + * @param settingContainer the object that contains the setting (to allow the conversion) + * @param settingName the setting name + */ + JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { + if ($.type(settingContainer[settingName]) === 'string') { + settingContainer[settingName] = parseFloat(settingContainer[settingName]); + } + + if ($.type(settingContainer[settingName]) === 'number') { + if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; + } else { + throw settingName + ' must be a number'; + } + }; + + /** + * Checks the sizeRangeSuffixes and, if necessary, converts + * its keys from string (e.g. old settings with 'lt100') to int. + */ + JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { + if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { + throw 'sizeRangeSuffixes must be defined and must be an object'; + } + + var suffixRanges = []; + for (var rangeIdx in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); + } + + var newSizeRngSuffixes = {0: ''}; + for (var i = 0; i < suffixRanges.length; i++) { + if ($.type(suffixRanges[i]) === 'string') { + try { + var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); + newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; + } catch (e) { + throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; + } + } else { + newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; + } + } + + this.settings.sizeRangeSuffixes = newSizeRngSuffixes; + }; + + /** + * check and convert the maxRowHeight setting + * requires rowHeight to be already set + * TODO: should be always called when only rowHeight is changed + * @return number or null + */ + JustifiedGallery.prototype.retrieveMaxRowHeight = function () { + var newMaxRowHeight = null; + var rowHeight = this.settings.rowHeight; + + if ($.type(this.settings.maxRowHeight) === 'string') { + if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { + newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100; + } else { + newMaxRowHeight = parseFloat(this.settings.maxRowHeight); + } + } else if ($.type(this.settings.maxRowHeight) === 'number') { + newMaxRowHeight = this.settings.maxRowHeight; + } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) { + return null; + } else { + throw 'maxRowHeight must be a number or a percentage'; + } + + // check if the converted value is not a number + if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight'; + + // check values, maxRowHeight must be >= rowHeight + if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight; + + return newMaxRowHeight; + }; + + /** + * Checks the settings + */ + JustifiedGallery.prototype.checkSettings = function () { + this.checkSizeRangesSuffixes(); + + this.checkOrConvertNumber(this.settings, 'rowHeight'); + this.checkOrConvertNumber(this.settings, 'margins'); + this.checkOrConvertNumber(this.settings, 'border'); + + var lastRowModes = [ + 'justify', + 'nojustify', + 'left', + 'center', + 'right', + 'hide' + ]; + if (lastRowModes.indexOf(this.settings.lastRow) === -1) { + throw 'lastRow must be one of: ' + lastRowModes.join(', '); + } + + this.checkOrConvertNumber(this.settings, 'justifyThreshold'); + if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { + throw 'justifyThreshold must be in the interval [0,1]'; + } + if ($.type(this.settings.cssAnimation) !== 'boolean') { + throw 'cssAnimation must be a boolean'; + } + + if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; + this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); + + this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); + if (this.settings.captionSettings.visibleOpacity < 0 || + this.settings.captionSettings.visibleOpacity > 1) { + throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; + } + + this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); + if (this.settings.captionSettings.nonVisibleOpacity < 0 || + this.settings.captionSettings.nonVisibleOpacity > 1) { + throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; + } + + this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); + this.checkOrConvertNumber(this.settings, 'refreshTime'); + this.checkOrConvertNumber(this.settings, 'refreshSensitivity'); + if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; + if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; + + if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { + throw 'sort must be false or a comparison function'; + } + + if (this.settings.filter !== false && !$.isFunction(this.settings.filter) && + $.type(this.settings.filter) !== 'string') { + throw 'filter must be false, a string or a filter function'; + } + }; + + /** + * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. + * @returns {Array} sorted suffix ranges + */ + JustifiedGallery.prototype.retrieveSuffixRanges = function () { + var suffixRanges = []; + for (var rangeIdx in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); + } + suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); + return suffixRanges; + }; + + /** + * Update the existing settings only changing some of them + * + * @param newSettings the new settings (or a subgroup of them) + */ + JustifiedGallery.prototype.updateSettings = function (newSettings) { + // In this case Justified Gallery has been called again changing only some options + this.settings = $.extend({}, this.settings, newSettings); + this.checkSettings(); + + // As reported in the settings: negative value = same as margins, 0 = disabled + this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; + + this.maxRowHeight = this.retrieveMaxRowHeight(); + this.suffixRanges = this.retrieveSuffixRanges(); + }; + + JustifiedGallery.prototype.defaults = { + sizeRangeSuffixes: { }, /* e.g. Flickr configuration + { + 100: '_t', // used when longest is less than 100px + 240: '_m', // used when longest is between 101px and 240px + 320: '_n', // ... + 500: '', + 640: '_z', + 1024: '_b' // used as else case because it is the last + } + */ + thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the + path relative to a specific thumbnail size. The function should accept respectively three arguments: + current path, width and height */ + rowHeight: 120, // required? required to be > 0? + maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels, + // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height + // can't exceed 3 * rowHeight) + margins: 1, + border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border + + lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide' + + justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified + * (i.e. lastRow setting is not considered) */ + waitThumbnailsLoad: true, + captions: true, + cssAnimation: true, + imagesAnimationDuration: 500, // ignored with css animations + captionSettings: { // ignored with css animations + animationDuration: 500, + visibleOpacity: 0.7, + nonVisibleOpacity: 0.0 + }, + rel: null, // rewrite the rel of each analyzed links + target: null, // rewrite the target of all links + extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image + refreshTime: 200, // time interval (in ms) to check if the page changes its width + refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery + randomize: false, + rtl: false, // right-to-left mode + sort: false, /* + - false: to do not sort + - function: to sort them using the function as comparator (see Array.prototype.sort()) + */ + filter: false, /* + - false, null or undefined: for a disabled filter + - a string: an entry is kept if entry.is(filter string) returns true + see jQuery's .is() function for further information + - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. + It follows the specifications of the Array.prototype.filter() function of JavaScript. + */ + selector: 'a, div:not(.spinner)', // The selector that is used to know what are the entries of the gallery + imgSelector: '> img, > a > img', // The selector that is used to know what are the images of each entry + triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger + this.$gallery.trigger(event); // Consider that 'this' is this set to the JustifiedGallery object, so it can + } // access to fields such as $gallery, useful to trigger events with jQuery. + }; + + /** + * Justified Gallery plugin for jQuery + * + * Events + * - jg.complete : called when all the gallery has been created + * - jg.resize : called when the gallery has been resized + * - jg.rowflush : when a new row appears + * + * @param arg the action (or the settings) passed when the plugin is called + * @returns {*} the object itself + */ + $.fn.justifiedGallery = function (arg) { + return this.each(function (index, gallery) { + + var $gallery = $(gallery); + $gallery.addClass('justified-gallery'); + + var controller = $gallery.data('jg.controller'); + if (typeof controller === 'undefined') { + // Create controller and assign it to the object data + if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { + if (arg === 'destroy') return; // Just a call to an unexisting object + throw 'The argument must be an object'; + } + controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg)); + $gallery.data('jg.controller', controller); + } else if (arg === 'norewind') { + // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row + // ... left to be more readable + } else if (arg === 'destroy') { + controller.destroy(); + return; + } else { + // In this case Justified Gallery has been called again changing only some options + controller.updateSettings(arg); + controller.rewind(); + } + + // Update the entries list + if (!controller.updateEntries(arg === 'norewind')) return; + + // Init justified gallery + controller.init(); + + }); + }; + +})); \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js new file mode 100644 index 0000000..62d8347 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js @@ -0,0 +1 @@ +(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&module.exports?module.exports=function(i,e){return void 0===e&&(e="undefined"!=typeof window?require("jquery"):require("jquery")(i)),t(e),e}:t(jQuery)})(function(t){function i(){return t("body").height()>t(window).height()}var e=function(i,e){this.settings=e,this.checkSettings(),this.imgAnalyzerTimeout=null,this.entries=null,this.buildingRow={entriesBuff:[],width:0,height:0,aspectRatio:0},this.lastFetchedEntry=null,this.lastAnalyzedIndex=-1,this.yield={every:2,flushed:0},this.border=e.border>=0?e.border:e.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges(),this.offY=this.border,this.rows=0,this.spinner={phase:0,timeSlot:150,$el:t('
'),intervalId:null},this.scrollBarOn=!1,this.checkWidthIntervalId=null,this.galleryWidth=i.width(),this.$gallery=i};e.prototype.getSuffix=function(t,i){var e,s;for(e=t>i?t:i,s=0;s .caption");return 0===i.length?null:i},e.prototype.displayEntry=function(i,e,s,n,r,o){i.width(n),i.height(o),i.css("top",s),i.css("left",e);var a=this.imgFromEntry(i);if(null!==a){a.css("width",n),a.css("height",r),a.css("margin-left",-n/2),a.css("margin-top",-r/2);var h=a.attr("src"),l=this.newSrc(h,n,r,a[0]);a.one("error",function(){a.attr("src",a.data("jg.originalSrc"))});var g=function(){h!==l&&a.attr("src",l)};"skipped"===i.data("jg.loaded")?this.onImageEvent(h,t.proxy(function(){this.showImg(i,g),i.data("jg.loaded",!0)},this)):this.showImg(i,g)}else this.showImg(i);this.displayEntryCaption(i)},e.prototype.displayEntryCaption=function(i){var e=this.imgFromEntry(i);if(null!==e&&this.settings.captions){var s=this.captionFromEntry(i);if(null===s){var n=e.attr("alt");this.isValidCaption(n)||(n=i.attr("title")),this.isValidCaption(n)&&(s=t('
'+n+"
"),i.append(s),i.data("jg.createdCaption",!0))}null!==s&&(this.settings.cssAnimation||s.stop().fadeTo(0,this.settings.captionSettings.nonVisibleOpacity),this.addCaptionEventsHandlers(i))}else this.removeCaptionEventsHandlers(i)},e.prototype.isValidCaption=function(t){return"undefined"!=typeof t&&t.length>0},e.prototype.onEntryMouseEnterForCaption=function(i){var e=this.captionFromEntry(t(i.currentTarget));this.settings.cssAnimation?e.addClass("caption-visible").removeClass("caption-hidden"):e.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.visibleOpacity)},e.prototype.onEntryMouseLeaveForCaption=function(i){var e=this.captionFromEntry(t(i.currentTarget));this.settings.cssAnimation?e.removeClass("caption-visible").removeClass("caption-hidden"):e.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.nonVisibleOpacity)},e.prototype.addCaptionEventsHandlers=function(i){var e=i.data("jg.captionMouseEvents");"undefined"==typeof e&&(e={mouseenter:t.proxy(this.onEntryMouseEnterForCaption,this),mouseleave:t.proxy(this.onEntryMouseLeaveForCaption,this)},i.on("mouseenter",void 0,void 0,e.mouseenter),i.on("mouseleave",void 0,void 0,e.mouseleave),i.data("jg.captionMouseEvents",e))},e.prototype.removeCaptionEventsHandlers=function(t){var i=t.data("jg.captionMouseEvents");"undefined"!=typeof i&&(t.off("mouseenter",void 0,i.mouseenter),t.off("mouseleave",void 0,i.mouseleave),t.removeData("jg.captionMouseEvents"))},e.prototype.clearBuildingRow=function(){this.buildingRow.entriesBuff=[],this.buildingRow.aspectRatio=0,this.buildingRow.width=0},e.prototype.prepareBuildingRow=function(t){var i,e,s,n,r,o=!0,a=0,h=this.galleryWidth-2*this.border-(this.buildingRow.entriesBuff.length-1)*this.settings.margins,l=h/this.buildingRow.aspectRatio,g=this.settings.rowHeight,f=this.buildingRow.width/h>this.settings.justifyThreshold;if(t&&"hide"===this.settings.lastRow&&!f){for(i=0;i img, > a > img").fadeTo(0,0));return-1}for(t&&!f&&"justify"!==this.settings.lastRow&&"hide"!==this.settings.lastRow&&(o=!1,this.rows>0&&(g=(this.offY-this.border-this.settings.margins*this.rows)/this.rows,o=g*this.buildingRow.aspectRatio/h>this.settings.justifyThreshold)),i=0;ir)&&(a=r);return this.buildingRow.height=a,o},e.prototype.flushRow=function(t){var i,e,s,n=this.settings,r=this.border;if(e=this.prepareBuildingRow(t),t&&"hide"===n.lastRow&&e===-1)return void this.clearBuildingRow();if(this.maxRowHeight&&this.maxRowHeightthis.settings.refreshSensitivity&&(this.galleryWidth=t,this.rewind(),this.rememberGalleryHeight(),this.startImgAnalyzer(!0)):(this.scrollBarOn=i(),this.galleryWidth=t)}},this),this.settings.refreshTime)},e.prototype.isSpinnerActive=function(){return null!==this.spinner.intervalId},e.prototype.getSpinnerHeight=function(){return this.spinner.$el.innerHeight()},e.prototype.stopLoadingSpinnerAnimation=function(){clearInterval(this.spinner.intervalId),this.spinner.intervalId=null,this.setGalleryTempHeight(this.$gallery.height()-this.getSpinnerHeight()),this.spinner.$el.detach()},e.prototype.startLoadingSpinnerAnimation=function(){var t=this.spinner,i=t.$el.find("span");clearInterval(t.intervalId),this.$gallery.append(t.$el),this.setGalleryTempHeight(this.offY+this.buildingRow.height+this.getSpinnerHeight()),t.intervalId=setInterval(function(){t.phase0&&(t.isFunction(this.settings.sort)?e=this.sortArray(e):this.settings.randomize&&(e=this.shuffleArray(e)),this.lastFetchedEntry=e[e.length-1],this.settings.filter?e=this.filterArray(e):this.resetFilters(e)),this.entries=this.entries.concat(e),!0},e.prototype.insertToGallery=function(i){var e=this;t.each(i,function(){t(this).appendTo(e.$gallery)})},e.prototype.shuffleArray=function(t){var i,e,s;for(i=t.length-1;i>0;i--)e=Math.floor(Math.random()*(i+1)),s=t[i],t[i]=t[e],t[e]=s;return this.insertToGallery(t),t},e.prototype.sortArray=function(t){return t.sort(this.settings.sort),this.insertToGallery(t),t},e.prototype.resetFilters=function(i){for(var e=0;e=this.yield.every))return void this.startImgAnalyzer(i);this.buildingRow.entriesBuff.push(s),this.buildingRow.aspectRatio+=r,this.buildingRow.width+=r*this.settings.rowHeight,this.lastAnalyzedIndex=e}else if("error"!==s.data("jg.loaded"))return}this.buildingRow.entriesBuff.length>0&&this.flushRow(!0),this.isSpinnerActive()&&this.stopLoadingSpinnerAnimation(),this.stopImgAnalyzerStarter(),this.settings.triggerEvent.call(this,i?"jg.resize":"jg.complete"),this.setGalleryFinalHeight(this.galleryHeightToSet)},e.prototype.stopImgAnalyzerStarter=function(){this.yield.flushed=0,null!==this.imgAnalyzerTimeout&&(clearTimeout(this.imgAnalyzerTimeout),this.imgAnalyzerTimeout=null)},e.prototype.startImgAnalyzer=function(t){var i=this;this.stopImgAnalyzerStarter(),this.imgAnalyzerTimeout=setTimeout(function(){i.analyzeImages(t)},.001)},e.prototype.onImageEvent=function(i,e,s){if(e||s){var n=new Image,r=t(n);e&&r.one("load",function(){r.off("load error"),e(n)}),s&&r.one("error",function(){r.off("load error"),s(n)}),n.src=i}},e.prototype.init=function(){var i=!1,e=!1,s=this;t.each(this.entries,function(n,r){var o=t(r),a=s.imgFromEntry(o);if(o.addClass("jg-entry"),o.data("jg.loaded")!==!0&&"skipped"!==o.data("jg.loaded"))if(null!==s.settings.rel&&o.attr("rel",s.settings.rel),null!==s.settings.target&&o.attr("target",s.settings.target),null!==a){var h=s.extractImgSrcFromImage(a);if(a.attr("src",h),s.settings.waitThumbnailsLoad===!1){var l=parseFloat(a.attr("width")),g=parseFloat(a.attr("height"));if(!isNaN(l)&&!isNaN(g))return o.data("jg.width",l),o.data("jg.height",g),o.data("jg.loaded","skipped"),e=!0,s.startImgAnalyzer(!1),!0}o.data("jg.loaded",!1),i=!0,s.isSpinnerActive()||s.startLoadingSpinnerAnimation(),s.onImageEvent(h,function(t){o.data("jg.width",t.width),o.data("jg.height",t.height),o.data("jg.loaded",!0),s.startImgAnalyzer(!1)},function(){o.data("jg.loaded","error"),s.startImgAnalyzer(!1)})}else o.data("jg.loaded",!0),o.data("jg.width",o.width()|parseFloat(o.css("width"))|1),o.data("jg.height",o.height()|parseFloat(o.css("height"))|1)}),i||e||this.startImgAnalyzer(!1),this.checkWidth()},e.prototype.checkOrConvertNumber=function(i,e){if("string"===t.type(i[e])&&(i[e]=parseFloat(i[e])),"number"!==t.type(i[e]))throw e+" must be a number";if(isNaN(i[e]))throw"invalid number for "+e},e.prototype.checkSizeRangesSuffixes=function(){if("object"!==t.type(this.settings.sizeRangeSuffixes))throw"sizeRangeSuffixes must be defined and must be an object";var i=[];for(var e in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(e)&&i.push(e);for(var s={0:""},n=0;n1)throw"justifyThreshold must be in the interval [0,1]";if("boolean"!==t.type(this.settings.cssAnimation))throw"cssAnimation must be a boolean";if("boolean"!==t.type(this.settings.captions))throw"captions must be a boolean";if(this.checkOrConvertNumber(this.settings.captionSettings,"animationDuration"),this.checkOrConvertNumber(this.settings.captionSettings,"visibleOpacity"),this.settings.captionSettings.visibleOpacity<0||this.settings.captionSettings.visibleOpacity>1)throw"captionSettings.visibleOpacity must be in the interval [0, 1]";if(this.checkOrConvertNumber(this.settings.captionSettings,"nonVisibleOpacity"),this.settings.captionSettings.nonVisibleOpacity<0||this.settings.captionSettings.nonVisibleOpacity>1)throw"captionSettings.nonVisibleOpacity must be in the interval [0, 1]";if(this.checkOrConvertNumber(this.settings,"imagesAnimationDuration"),this.checkOrConvertNumber(this.settings,"refreshTime"),this.checkOrConvertNumber(this.settings,"refreshSensitivity"),"boolean"!==t.type(this.settings.randomize))throw"randomize must be a boolean";if("string"!==t.type(this.settings.selector))throw"selector must be a string";if(this.settings.sort!==!1&&!t.isFunction(this.settings.sort))throw"sort must be false or a comparison function";if(this.settings.filter!==!1&&!t.isFunction(this.settings.filter)&&"string"!==t.type(this.settings.filter))throw"filter must be false, a string or a filter function"},e.prototype.retrieveSuffixRanges=function(){var t=[];for(var i in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(i)&&t.push(parseInt(i,10));return t.sort(function(t,i){return t>i?1:t=0?this.settings.border:this.settings.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges()},e.prototype.defaults={sizeRangeSuffixes:{},thumbnailPath:void 0,rowHeight:120,maxRowHeight:!1,margins:1,border:-1,lastRow:"nojustify",justifyThreshold:.9,waitThumbnailsLoad:!0,captions:!0,cssAnimation:!0,imagesAnimationDuration:500,captionSettings:{animationDuration:500,visibleOpacity:.7,nonVisibleOpacity:0},rel:null,target:null,extension:/\.[^.\\\/]+$/,refreshTime:200,refreshSensitivity:0,randomize:!1,rtl:!1,sort:!1,filter:!1,selector:"a, div:not(.spinner)",imgSelector:"> img, > a > img",triggerEvent:function(t){this.$gallery.trigger(t)}},t.fn.justifiedGallery=function(i){return this.each(function(s,n){var r=t(n);r.addClass("justified-gallery");var o=r.data("jg.controller");if("undefined"==typeof o){if("undefined"!=typeof i&&null!==i&&"object"!==t.type(i)){if("destroy"===i)return;throw"The argument must be an object"}o=new e(r,t.extend({},e.prototype.defaults,i)),r.data("jg.controller",o)}else if("norewind"===i);else{if("destroy"===i)return void o.destroy();o.updateSettings(i),o.rewind()}o.updateEntries("norewind"===i)&&o.init()})}}); \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.css b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.css new file mode 100644 index 0000000..6743cb7 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.css @@ -0,0 +1,96 @@ +/*! + * justifiedGallery - v3.7.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2018 Miro Mannino + * Licensed under the MIT license. + */ +.justified-gallery { + width: 100%; + position: relative; + overflow: hidden; +} +.justified-gallery > a, +.justified-gallery > div, +.justified-gallery > figure { + position: absolute; + display: inline-block; + overflow: hidden; + /* background: #888888; To have gray placeholders while the gallery is loading with waitThumbnailsLoad = false */ + filter: "alpha(opacity=10)"; + opacity: 0.1; + margin: 0; + padding: 0; +} +.justified-gallery > a > img, +.justified-gallery > div > img, +.justified-gallery > figure > img, +.justified-gallery > a > a > img, +.justified-gallery > div > a > img, +.justified-gallery > figure > a > img { + position: absolute; + top: 50%; + left: 50%; + margin: 0; + padding: 0; + border: none; + filter: "alpha(opacity=0)"; + opacity: 0; +} +.justified-gallery > a > .caption, +.justified-gallery > div > .caption, +.justified-gallery > figure > .caption { + display: none; + position: absolute; + bottom: 0; + padding: 5px; + background-color: #000000; + left: 0; + right: 0; + margin: 0; + color: white; + font-size: 12px; + font-weight: 300; + font-family: sans-serif; +} +.justified-gallery > a > .caption.caption-visible, +.justified-gallery > div > .caption.caption-visible, +.justified-gallery > figure > .caption.caption-visible { + display: initial; + filter: "alpha(opacity=70)"; + opacity: 0.7; + transition: opacity 500ms ease-in; +} +.justified-gallery > .entry-visible { + filter: "alpha(opacity=100)"; + opacity: 1; + background: none; +} +.justified-gallery > .entry-visible > img, +.justified-gallery > .entry-visible > a > img { + filter: "alpha(opacity=100)"; + opacity: 1; + transition: opacity 500ms ease-in; +} +.justified-gallery > .jg-filtered { + display: none; +} +.justified-gallery > .spinner { + position: absolute; + bottom: 0; + margin-left: -24px; + padding: 10px 0 10px 0; + left: 50%; + filter: "alpha(opacity=100)"; + opacity: 1; + overflow: initial; +} +.justified-gallery > .spinner > span { + display: inline-block; + filter: "alpha(opacity=0)"; + opacity: 0; + width: 8px; + height: 8px; + margin: 0 4px 0 4px; + background-color: #000; + border-radius: 6px; +} diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.min.css b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.min.css new file mode 100644 index 0000000..d8b714c --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/justified_gallery/justifiedGallery.min.css @@ -0,0 +1,6 @@ +/*! + * justifiedGallery - v3.7.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2018 Miro Mannino + * Licensed under the MIT license. + */.justified-gallery{width:100%;position:relative;overflow:hidden}.justified-gallery>a,.justified-gallery>div,.justified-gallery>figure{position:absolute;display:inline-block;overflow:hidden;filter:"alpha(opacity=10)";opacity:.1;margin:0;padding:0}.justified-gallery>a>a>img,.justified-gallery>a>img,.justified-gallery>div>a>img,.justified-gallery>div>img,.justified-gallery>figure>a>img,.justified-gallery>figure>img{position:absolute;top:50%;left:50%;margin:0;padding:0;border:none;filter:"alpha(opacity=0)";opacity:0}.justified-gallery>a>.caption,.justified-gallery>div>.caption,.justified-gallery>figure>.caption{display:none;position:absolute;bottom:0;padding:5px;background-color:#000;left:0;right:0;margin:0;color:#fff;font-size:12px;font-weight:300;font-family:sans-serif}.justified-gallery>a>.caption.caption-visible,.justified-gallery>div>.caption.caption-visible,.justified-gallery>figure>.caption.caption-visible{display:initial;filter:"alpha(opacity=70)";opacity:.7;transition:opacity .5s ease-in}.justified-gallery>.entry-visible{filter:"alpha(opacity=100)";opacity:1;background:0 0}.justified-gallery>.entry-visible>a>img,.justified-gallery>.entry-visible>img{filter:"alpha(opacity=100)";opacity:1;transition:opacity .5s ease-in}.justified-gallery>.jg-filtered{display:none}.justified-gallery>.spinner{position:absolute;bottom:0;margin-left:-24px;padding:10px 0;left:50%;filter:"alpha(opacity=100)";opacity:1;overflow:initial}.justified-gallery>.spinner>span{display:inline-block;filter:"alpha(opacity=0)";opacity:0;width:8px;height:8px;margin:0 4px;background-color:#000;border-radius:6px} \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.js b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.js new file mode 100644 index 0000000..e97bf95 --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.js @@ -0,0 +1,872 @@ +/*! + * jQuery & Zepto Lazy - v1.7.10 + * http://jquery.eisbehr.de/lazy/ + * + * Copyright 2012 - 2018, Daniel 'Eisbehr' Kern + * + * Dual licensed under the MIT and GPL-2.0 licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl-2.0.html + * + * $("img.lazy").lazy(); + */ + +;(function(window, undefined) { + "use strict"; + + // noinspection JSUnresolvedVariable + /** + * library instance - here and not in construct to be shorter in minimization + * @return void + */ + var $ = window.jQuery || window.Zepto, + + /** + * unique plugin instance id counter + * @type {number} + */ + lazyInstanceId = 0, + + /** + * helper to register window load for jQuery 3 + * @type {boolean} + */ + windowLoaded = false; + + /** + * make lazy available to jquery - and make it a bit more case-insensitive :) + * @access public + * @type {function} + * @param {object} settings + * @return {LazyPlugin} + */ + $.fn.Lazy = $.fn.lazy = function(settings) { + return new LazyPlugin(this, settings); + }; + + /** + * helper to add plugins to lazy prototype configuration + * @access public + * @type {function} + * @param {string|Array} names + * @param {string|Array|function} [elements] + * @param {function} loader + * @return void + */ + $.Lazy = $.lazy = function(names, elements, loader) { + // make second parameter optional + if ($.isFunction(elements)) { + loader = elements; + elements = []; + } + + // exit here if parameter is not a callable function + if (!$.isFunction(loader)) { + return; + } + + // make parameters an array of names to be sure + names = $.isArray(names) ? names : [names]; + elements = $.isArray(elements) ? elements : [elements]; + + var config = LazyPlugin.prototype.config, + forced = config._f || (config._f = {}); + + // add the loader plugin for every name + for (var i = 0, l = names.length; i < l; i++) { + if (config[names[i]] === undefined || $.isFunction(config[names[i]])) { + config[names[i]] = loader; + } + } + + // add forced elements loader + for (var c = 0, a = elements.length; c < a; c++) { + forced[elements[c]] = names[0]; + } + }; + + /** + * contains all logic and the whole element handling + * is packed in a private function outside class to reduce memory usage, because it will not be created on every plugin instance + * @access private + * @type {function} + * @param {LazyPlugin} instance + * @param {object} config + * @param {object|Array} items + * @param {object} events + * @param {string} namespace + * @return void + */ + function _executeLazy(instance, config, items, events, namespace) { + /** + * a helper to trigger the 'onFinishedAll' callback after all other events + * @access private + * @type {number} + */ + var _awaitingAfterLoad = 0, + + /** + * visible content width + * @access private + * @type {number} + */ + _actualWidth = -1, + + /** + * visible content height + * @access private + * @type {number} + */ + _actualHeight = -1, + + /** + * determine possibly detected high pixel density + * @access private + * @type {boolean} + */ + _isRetinaDisplay = false, + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _afterLoad = 'afterLoad', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _load = 'load', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _error = 'error', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _img = 'img', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _src = 'src', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _srcset = 'srcset', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _sizes = 'sizes', + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _backgroundImage = 'background-image'; + + /** + * initialize plugin + * bind loading to events or set delay time to load all items at once + * @access private + * @return void + */ + function _initialize() { + // detect actual device pixel ratio + // noinspection JSUnresolvedVariable + _isRetinaDisplay = window.devicePixelRatio > 1; + + // prepare all initial items + items = _prepareItems(items); + + // if delay time is set load all items at once after delay time + if (config.delay >= 0) { + setTimeout(function() { + _lazyLoadItems(true); + }, config.delay); + } + + // if no delay is set or combine usage is active bind events + if (config.delay < 0 || config.combined) { + // create unique event function + events.e = _throttle(config.throttle, function(event) { + // reset detected window size on resize event + if (event.type === 'resize') { + _actualWidth = _actualHeight = -1; + } + + // execute 'lazy magic' + _lazyLoadItems(event.all); + }); + + // create function to add new items to instance + events.a = function(additionalItems) { + additionalItems = _prepareItems(additionalItems); + items.push.apply(items, additionalItems); + }; + + // create function to get all instance items left + events.g = function() { + // filter loaded items before return in case internal filter was not running until now + return (items = $(items).filter(function() { + return !$(this).data(config.loadedName); + })); + }; + + // create function to force loading elements + events.f = function(forcedItems) { + for (var i = 0; i < forcedItems.length; i++) { + // only handle item if available in current instance + // use a compare function, because Zepto can't handle object parameter for filter + // var item = items.filter(forcedItems[i]); + /* jshint loopfunc: true */ + var item = items.filter(function() { + return this === forcedItems[i]; + }); + + if (item.length) { + _lazyLoadItems(false, item); + } + } + }; + + // load initial items + _lazyLoadItems(); + + // bind lazy load functions to scroll and resize event + // noinspection JSUnresolvedVariable + $(config.appendScroll).on('scroll.' + namespace + ' resize.' + namespace, events.e); + } + } + + /** + * prepare items before handle them + * @access private + * @param {Array|object|jQuery} items + * @return {Array|object|jQuery} + */ + function _prepareItems(items) { + // fetch used configurations before loops + var defaultImage = config.defaultImage, + placeholder = config.placeholder, + imageBase = config.imageBase, + srcsetAttribute = config.srcsetAttribute, + loaderAttribute = config.loaderAttribute, + forcedTags = config._f || {}; + + // filter items and only add those who not handled yet and got needed attributes available + items = $(items).filter(function() { + var element = $(this), + tag = _getElementTagName(this); + + return !element.data(config.handledName) && + (element.attr(config.attribute) || element.attr(srcsetAttribute) || element.attr(loaderAttribute) || forcedTags[tag] !== undefined); + }) + + // append plugin instance to all elements + .data('plugin_' + config.name, instance); + + for (var i = 0, l = items.length; i < l; i++) { + var element = $(items[i]), + tag = _getElementTagName(items[i]), + elementImageBase = element.attr(config.imageBaseAttribute) || imageBase; + + // generate and update source set if an image base is set + if (tag === _img && elementImageBase && element.attr(srcsetAttribute)) { + element.attr(srcsetAttribute, _getCorrectedSrcSet(element.attr(srcsetAttribute), elementImageBase)); + } + + // add loader to forced element types + if (forcedTags[tag] !== undefined && !element.attr(loaderAttribute)) { + element.attr(loaderAttribute, forcedTags[tag]); + } + + // set default image on every element without source + if (tag === _img && defaultImage && !element.attr(_src)) { + element.attr(_src, defaultImage); + } + + // set placeholder on every element without background image + else if (tag !== _img && placeholder && (!element.css(_backgroundImage) || element.css(_backgroundImage) === 'none')) { + element.css(_backgroundImage, "url('" + placeholder + "')"); + } + } + + return items; + } + + /** + * the 'lazy magic' - check all items + * @access private + * @param {boolean} [allItems] + * @param {object} [forced] + * @return void + */ + function _lazyLoadItems(allItems, forced) { + // skip if no items where left + if (!items.length) { + // destroy instance if option is enabled + if (config.autoDestroy) { + // noinspection JSUnresolvedFunction + instance.destroy(); + } + + return; + } + + var elements = forced || items, + loadTriggered = false, + imageBase = config.imageBase || '', + srcsetAttribute = config.srcsetAttribute, + handledName = config.handledName; + + // loop all available items + for (var i = 0; i < elements.length; i++) { + // item is at least in loadable area + if (allItems || forced || _isInLoadableArea(elements[i])) { + var element = $(elements[i]), + tag = _getElementTagName(elements[i]), + attribute = element.attr(config.attribute), + elementImageBase = element.attr(config.imageBaseAttribute) || imageBase, + customLoader = element.attr(config.loaderAttribute); + + // is not already handled + if (!element.data(handledName) && + // and is visible or visibility doesn't matter + (!config.visibleOnly || element.is(':visible')) && ( + // and image source or source set attribute is available + (attribute || element.attr(srcsetAttribute)) && ( + // and is image tag where attribute is not equal source or source set + (tag === _img && (elementImageBase + attribute !== element.attr(_src) || element.attr(srcsetAttribute) !== element.attr(_srcset))) || + // or is non image tag where attribute is not equal background + (tag !== _img && elementImageBase + attribute !== element.css(_backgroundImage)) + ) || + // or custom loader is available + customLoader)) + { + // mark element always as handled as this point to prevent double handling + loadTriggered = true; + element.data(handledName, true); + + // load item + _handleItem(element, tag, elementImageBase, customLoader); + } + } + } + + // when something was loaded remove them from remaining items + if (loadTriggered) { + items = $(items).filter(function() { + return !$(this).data(handledName); + }); + } + } + + /** + * load the given element the lazy way + * @access private + * @param {object} element + * @param {string} tag + * @param {string} imageBase + * @param {function} [customLoader] + * @return void + */ + function _handleItem(element, tag, imageBase, customLoader) { + // increment count of items waiting for after load + ++_awaitingAfterLoad; + + // extended error callback for correct 'onFinishedAll' handling + var errorCallback = function() { + _triggerCallback('onError', element); + _reduceAwaiting(); + + // prevent further callback calls + errorCallback = $.noop; + }; + + // trigger function before loading image + _triggerCallback('beforeLoad', element); + + // fetch all double used data here for better code minimization + var srcAttribute = config.attribute, + srcsetAttribute = config.srcsetAttribute, + sizesAttribute = config.sizesAttribute, + retinaAttribute = config.retinaAttribute, + removeAttribute = config.removeAttribute, + loadedName = config.loadedName, + elementRetina = element.attr(retinaAttribute); + + // handle custom loader + if (customLoader) { + // on load callback + var loadCallback = function() { + // remove attribute from element + if (removeAttribute) { + element.removeAttr(config.loaderAttribute); + } + + // mark element as loaded + element.data(loadedName, true); + + // call after load event + _triggerCallback(_afterLoad, element); + + // remove item from waiting queue and possibly trigger finished event + // it's needed to be asynchronous to run after filter was in _lazyLoadItems + setTimeout(_reduceAwaiting, 1); + + // prevent further callback calls + loadCallback = $.noop; + }; + + // bind error event to trigger callback and reduce waiting amount + element.off(_error).one(_error, errorCallback) + + // bind after load callback to element + .one(_load, loadCallback); + + // trigger custom loader and handle response + if (!_triggerCallback(customLoader, element, function(response) { + if(response) { + element.off(_load); + loadCallback(); + } + else { + element.off(_error); + errorCallback(); + } + })) { + element.trigger(_error); + } + } + + // handle images + else { + // create image object + var imageObj = $(new Image()); + + // bind error event to trigger callback and reduce waiting amount + imageObj.one(_error, errorCallback) + + // bind after load callback to image + .one(_load, function() { + // remove element from view + element.hide(); + + // set image back to element + // do it as single 'attr' calls, to be sure 'src' is set after 'srcset' + if (tag === _img) { + element.attr(_sizes, imageObj.attr(_sizes)) + .attr(_srcset, imageObj.attr(_srcset)) + .attr(_src, imageObj.attr(_src)); + } + else { + element.css(_backgroundImage, "url('" + imageObj.attr(_src) + "')"); + } + + // bring it back with some effect! + element[config.effect](config.effectTime); + + // remove attribute from element + if (removeAttribute) { + element.removeAttr(srcAttribute + ' ' + srcsetAttribute + ' ' + retinaAttribute + ' ' + config.imageBaseAttribute); + + // only remove 'sizes' attribute, if it was a custom one + if (sizesAttribute !== _sizes) { + element.removeAttr(sizesAttribute); + } + } + + // mark element as loaded + element.data(loadedName, true); + + // call after load event + _triggerCallback(_afterLoad, element); + + // cleanup image object + imageObj.remove(); + + // remove item from waiting queue and possibly trigger finished event + _reduceAwaiting(); + }); + + // set sources + // do it as single 'attr' calls, to be sure 'src' is set after 'srcset' + var imageSrc = (_isRetinaDisplay && elementRetina ? elementRetina : element.attr(srcAttribute)) || ''; + imageObj.attr(_sizes, element.attr(sizesAttribute)) + .attr(_srcset, element.attr(srcsetAttribute)) + .attr(_src, imageSrc ? imageBase + imageSrc : null); + + // call after load even on cached image + imageObj.complete && imageObj.trigger(_load); // jshint ignore : line + } + } + + /** + * check if the given element is inside the current viewport or threshold + * @access private + * @param {object} element + * @return {boolean} + */ + function _isInLoadableArea(element) { + var elementBound = element.getBoundingClientRect(), + direction = config.scrollDirection, + threshold = config.threshold, + vertical = // check if element is in loadable area from top + ((_getActualHeight() + threshold) > elementBound.top) && + // check if element is even in loadable are from bottom + (-threshold < elementBound.bottom), + horizontal = // check if element is in loadable area from left + ((_getActualWidth() + threshold) > elementBound.left) && + // check if element is even in loadable area from right + (-threshold < elementBound.right); + + if (direction === 'vertical') { + return vertical; + } + else if (direction === 'horizontal') { + return horizontal; + } + + return vertical && horizontal; + } + + /** + * receive the current viewed width of the browser + * @access private + * @return {number} + */ + function _getActualWidth() { + return _actualWidth >= 0 ? _actualWidth : (_actualWidth = $(window).width()); + } + + /** + * receive the current viewed height of the browser + * @access private + * @return {number} + */ + function _getActualHeight() { + return _actualHeight >= 0 ? _actualHeight : (_actualHeight = $(window).height()); + } + + /** + * get lowercase tag name of an element + * @access private + * @param {object} element + * @returns {string} + */ + function _getElementTagName(element) { + return element.tagName.toLowerCase(); + } + + /** + * prepend image base to all srcset entries + * @access private + * @param {string} srcset + * @param {string} imageBase + * @returns {string} + */ + function _getCorrectedSrcSet(srcset, imageBase) { + if (imageBase) { + // trim, remove unnecessary spaces and split entries + var entries = srcset.split(','); + srcset = ''; + + for (var i = 0, l = entries.length; i < l; i++) { + srcset += imageBase + entries[i].trim() + (i !== l - 1 ? ',' : ''); + } + } + + return srcset; + } + + /** + * helper function to throttle down event triggering + * @access private + * @param {number} delay + * @param {function} callback + * @return {function} + */ + function _throttle(delay, callback) { + var timeout, + lastExecute = 0; + + return function(event, ignoreThrottle) { + var elapsed = +new Date() - lastExecute; + + function run() { + lastExecute = +new Date(); + // noinspection JSUnresolvedFunction + callback.call(instance, event); + } + + timeout && clearTimeout(timeout); // jshint ignore : line + + if (elapsed > delay || !config.enableThrottle || ignoreThrottle) { + run(); + } + else { + timeout = setTimeout(run, delay - elapsed); + } + }; + } + + /** + * reduce count of awaiting elements to 'afterLoad' event and fire 'onFinishedAll' if reached zero + * @access private + * @return void + */ + function _reduceAwaiting() { + --_awaitingAfterLoad; + + // if no items were left trigger finished event + if (!items.length && !_awaitingAfterLoad) { + _triggerCallback('onFinishedAll'); + } + } + + /** + * single implementation to handle callbacks, pass element and set 'this' to current instance + * @access private + * @param {string|function} callback + * @param {object} [element] + * @param {*} [args] + * @return {boolean} + */ + function _triggerCallback(callback, element, args) { + if ((callback = config[callback])) { + // jQuery's internal '$(arguments).slice(1)' are causing problems at least on old iPads + // below is shorthand of 'Array.prototype.slice.call(arguments, 1)' + callback.apply(instance, [].slice.call(arguments, 1)); + return true; + } + + return false; + } + + // if event driven or window is already loaded don't wait for page loading + if (config.bind === 'event' || windowLoaded) { + _initialize(); + } + + // otherwise load initial items and start lazy after page load + else { + // noinspection JSUnresolvedVariable + $(window).on(_load + '.' + namespace, _initialize); + } + } + + /** + * lazy plugin class constructor + * @constructor + * @access private + * @param {object} elements + * @param {object} settings + * @return {object|LazyPlugin} + */ + function LazyPlugin(elements, settings) { + /** + * this lazy plugin instance + * @access private + * @type {object|LazyPlugin|LazyPlugin.prototype} + */ + var _instance = this, + + /** + * this lazy plugin instance configuration + * @access private + * @type {object} + */ + _config = $.extend({}, _instance.config, settings), + + /** + * instance generated event executed on container scroll or resize + * packed in an object to be referenceable and short named because properties will not be minified + * @access private + * @type {object} + */ + _events = {}, + + /** + * unique namespace for instance related events + * @access private + * @type {string} + */ + _namespace = _config.name + '-' + (++lazyInstanceId); + + // noinspection JSUndefinedPropertyAssignment + /** + * wrapper to get or set an entry from plugin instance configuration + * much smaller on minify as direct access + * @access public + * @type {function} + * @param {string} entryName + * @param {*} [value] + * @return {LazyPlugin|*} + */ + _instance.config = function(entryName, value) { + if (value === undefined) { + return _config[entryName]; + } + + _config[entryName] = value; + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * add additional items to current instance + * @access public + * @param {Array|object|string} items + * @return {LazyPlugin} + */ + _instance.addItems = function(items) { + _events.a && _events.a($.type(items) === 'string' ? $(items) : items); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * get all left items of this instance + * @access public + * @returns {object} + */ + _instance.getItems = function() { + return _events.g ? _events.g() : {}; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force lazy to load all items in loadable area right now + * by default without throttle + * @access public + * @type {function} + * @param {boolean} [useThrottle] + * @return {LazyPlugin} + */ + _instance.update = function(useThrottle) { + _events.e && _events.e({}, !useThrottle); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force element(s) to load directly, ignoring the viewport + * @access public + * @param {Array|object|string} items + * @return {LazyPlugin} + */ + _instance.force = function(items) { + _events.f && _events.f($.type(items) === 'string' ? $(items) : items); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force lazy to load all available items right now + * this call ignores throttling + * @access public + * @type {function} + * @return {LazyPlugin} + */ + _instance.loadAll = function() { + _events.e && _events.e({all: true}, true); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * destroy this plugin instance + * @access public + * @type {function} + * @return undefined + */ + _instance.destroy = function() { + // unbind instance generated events + // noinspection JSUnresolvedFunction, JSUnresolvedVariable + $(_config.appendScroll).off('.' + _namespace, _events.e); + // noinspection JSUnresolvedVariable + $(window).off('.' + _namespace); + + // clear events + _events = {}; + + return undefined; + }; + + // start using lazy and return all elements to be chainable or instance for further use + // noinspection JSUnresolvedVariable + _executeLazy(_instance, _config, elements, _events, _namespace); + return _config.chainable ? elements : _instance; + } + + /** + * settings and configuration data + * @access public + * @type {object|*} + */ + LazyPlugin.prototype.config = { + // general + name : 'lazy', + chainable : true, + autoDestroy : true, + bind : 'load', + threshold : 500, + visibleOnly : false, + appendScroll : window, + scrollDirection : 'both', + imageBase : null, + defaultImage : 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', + placeholder : null, + delay : -1, + combined : false, + + // attributes + attribute : 'data-src', + srcsetAttribute : 'data-srcset', + sizesAttribute : 'data-sizes', + retinaAttribute : 'data-retina', + loaderAttribute : 'data-loader', + imageBaseAttribute : 'data-imagebase', + removeAttribute : true, + handledName : 'handled', + loadedName : 'loaded', + + // effect + effect : 'show', + effectTime : 0, + + // throttle + enableThrottle : true, + throttle : 250, + + // callbacks + beforeLoad : undefined, + afterLoad : undefined, + onError : undefined, + onFinishedAll : undefined + }; + + // register window load event globally to prevent not loading elements + // since jQuery 3.X ready state is fully async and may be executed after 'load' + $(window).on('load', function() { + windowLoaded = true; + }); +})(window); \ No newline at end of file diff --git a/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.min.js b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.min.js new file mode 100644 index 0000000..0a54f7c --- /dev/null +++ b/_vendor/github.com/mfg92/hugo-shortcode-gallery/static/shortcode-gallery/lazy/jquery.lazy.min.js @@ -0,0 +1 @@ +(function(t,e){"use strict";function r(r,a,i,u,l){function f(){L=t.devicePixelRatio>1,i=c(i),a.delay>=0&&setTimeout(function(){s(!0)},a.delay),(a.delay<0||a.combined)&&(u.e=v(a.throttle,function(t){"resize"===t.type&&(w=B=-1),s(t.all)}),u.a=function(t){t=c(t),i.push.apply(i,t)},u.g=function(){return i=n(i).filter(function(){return!n(this).data(a.loadedName)})},u.f=function(t){for(var e=0;ee.top&&-ne.left&&-n=0?w:w=n(t).width()}function h(){return B>=0?B:B=n(t).height()}function m(t){return t.tagName.toLowerCase()}function b(t,e){if(e){var r=t.split(",");t="";for(var a=0,n=r.length;at||!a.enableThrottle||u?l():n=setTimeout(l,t-f)}}function p(){--z,i.length||z||y("onFinishedAll")}function y(t,e,n){return!!(t=a[t])&&(t.apply(r,[].slice.call(arguments,1)),!0)}var z=0,w=-1,B=-1,L=!1,T="afterLoad",D="load",I="error",N="img",E="src",F="srcset",C="sizes",O="background-image";"event"===a.bind||o?f():n(t).on(D+"."+l,f)}function a(a,o){var u=this,l=n.extend({},u.config,o),f={},c=l.name+"-"+ ++i;return u.config=function(t,r){return r===e?l[t]:(l[t]=r,u)},u.addItems=function(t){return f.a&&f.a("string"===n.type(t)?n(t):t),u},u.getItems=function(){return f.g?f.g():{}},u.update=function(t){return f.e&&f.e({},!t),u},u.force=function(t){return f.f&&f.f("string"===n.type(t)?n(t):t),u},u.loadAll=function(){return f.e&&f.e({all:!0},!0),u},u.destroy=function(){return n(l.appendScroll).off("."+c,f.e),n(t).off("."+c),f={},e},r(u,l,a,f,c),l.chainable?a:u}var n=t.jQuery||t.Zepto,i=0,o=!1;n.fn.Lazy=n.fn.lazy=function(t){return new a(this,t)},n.Lazy=n.lazy=function(t,r,i){if(n.isFunction(r)&&(i=r,r=[]),n.isFunction(i)){t=n.isArray(t)?t:[t],r=n.isArray(r)?r:[r];for(var o=a.prototype.config,u=o._f||(o._f={}),l=0,f=t.length;l