diff --git a/WebRoot/html/ypzs/component/other/css/photoviewer.min.css b/WebRoot/html/ypzs/component/other/css/photoviewer.min.css new file mode 100644 index 0000000..0323804 --- /dev/null +++ b/WebRoot/html/ypzs/component/other/css/photoviewer.min.css @@ -0,0 +1,16 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */.photoviewer-modal{position:absolute;z-index:1090;width:320px;height:320px;overflow:visible !important;color:#333;cursor:default;background-color:rgba(255,255,255,.92);border:1px solid rgba(0,0,0,.64);border-radius:6px;outline:none;box-shadow:0 2px 10px 2px rgba(0,0,0,.32)}.photoviewer-inner{position:absolute;top:0;left:0;right:0;bottom:0}.photoviewer-maximized{position:fixed;top:0;right:0;bottom:0;left:0;width:auto;height:auto}.photoviewer-maximized.photoviewer-modal{border-width:0;border-radius:0}.photoviewer-maximized .photoviewer-header{border-radius:0}.photoviewer-maximized .photoviewer-resizable-handle{display:none}.photoviewer-toolbar{font-size:0}.photoviewer-button{display:inline-block;min-width:40px;height:40px;box-sizing:border-box;margin:0;font-size:16px;line-height:1;text-align:center;background:none;border-width:0;border-radius:0;color:inherit;cursor:pointer;outline:none}.photoviewer-button:hover{color:#111}.photoviewer-button:focus{background-color:rgba(0,0,0,.08)}.photoviewer-button svg{display:inline-block;font-size:inherit;width:1em;height:1em;overflow:visible;vertical-align:-0.125em}.photoviewer-header{position:relative;z-index:2;height:30px;border-radius:5px 5px 0 0;overflow:hidden}.photoviewer-header .photoviewer-toolbar{float:right}[dir=rtl] .photoviewer-header .photoviewer-toolbar{float:left}.photoviewer-header .photoviewer-button{height:30px}.photoviewer-header .photoviewer-button:hover{background-color:rgba(0,0,0,.08)}.photoviewer-header .photoviewer-button-close:hover{color:#fff;background-color:#ff4545}.photoviewer-title{padding:8px 10px;font-size:14px;line-height:1;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden}.photoviewer-stage{position:absolute;top:30px;right:0;bottom:40px;left:0;z-index:1;border-top:1px solid rgba(0,0,0,.64);border-bottom:1px solid rgba(0,0,0,.64);background-color:#fff;overflow:hidden}.photoviewer-stage.stage-ready{text-align:center;font-size:0}.photoviewer-stage.stage-ready::before{content:"";display:inline-block;height:100%;vertical-align:middle;overflow:hidden}.photoviewer-image{position:absolute;display:inline-block;min-width:auto;max-width:none}.photoviewer-image.image-ready{position:static;max-width:100%;max-height:100%;vertical-align:middle}.photoviewer-footer{position:absolute;bottom:0;z-index:2;width:100%;height:40px;text-align:center}.photoviewer-footer .photoviewer-toolbar{display:inline-block}[dir=rtl] .photoviewer-button-prev,[dir=rtl] .photoviewer-button-next{-ms-transform:rotate(180deg);transform:rotate(180deg)}.photoviewer-resizable-handle{position:absolute;z-index:10}.photoviewer-resizable-handle-e{top:0;right:-5px;bottom:0;left:auto;width:10px;cursor:e-resize}.photoviewer-resizable-handle-s{top:auto;right:0;bottom:-5px;left:0;height:10px;cursor:s-resize}.photoviewer-resizable-handle-w{top:0;right:auto;bottom:0;left:-5px;width:10px;cursor:w-resize}.photoviewer-resizable-handle-n{top:-5px;right:0;bottom:auto;left:0;height:10px;cursor:n-resize}.photoviewer-resizable-handle-se{top:auto;right:-5px;bottom:-5px;left:auto;width:10px;height:10px;cursor:se-resize}.photoviewer-resizable-handle-sw{top:auto;right:auto;bottom:-5px;left:-5px;width:10px;height:10px;cursor:sw-resize}.photoviewer-resizable-handle-nw{top:-5px;right:auto;bottom:auto;left:-5px;width:10px;height:10px;cursor:nw-resize}.photoviewer-resizable-handle-ne{top:-5px;right:-5px;bottom:auto;left:auto;width:10px;height:10px;cursor:ne-resize}:-webkit-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-webkit-full-screen .photoviewer-header,:-webkit-full-screen .photoviewer-footer,:-webkit-full-screen .photoviewer-resizable-handle{display:none}:-webkit-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-moz-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-moz-full-screen .photoviewer-header,:-moz-full-screen .photoviewer-footer,:-moz-full-screen .photoviewer-resizable-handle{display:none}:-moz-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-ms-fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-ms-fullscreen .photoviewer-header,:-ms-fullscreen .photoviewer-footer,:-ms-fullscreen .photoviewer-resizable-handle{display:none}:-ms-fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:full-screen .photoviewer-header,:full-screen .photoviewer-footer,:full-screen .photoviewer-resizable-handle{display:none}:full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-webkit-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-ms-fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-webkit-full-screen .photoviewer-header, :-webkit-full-screen .photoviewer-footer, :-webkit-full-screen .photoviewer-resizable-handle{display:none}:-ms-fullscreen .photoviewer-header, :-ms-fullscreen .photoviewer-footer, :-ms-fullscreen .photoviewer-resizable-handle{display:none}:fullscreen .photoviewer-header,:fullscreen .photoviewer-footer,:fullscreen .photoviewer-resizable-handle{display:none}:-webkit-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-ms-fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}::backdrop{background-color:#000}::-ms-backdrop{background-color:#000}.is-grab{cursor:move;cursor:grab}.is-grabbing{cursor:move;cursor:grabbing}.photoviewer-loader{position:absolute;top:30px;left:0;right:0;bottom:40px;z-index:2;text-align:center;color:#333}.photoviewer-loader::before{content:"";position:relative;display:inline-block;width:36px;height:36px;box-sizing:border-box;border-width:5px;border-style:solid;border-color:rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(255,255,255,.5);border-radius:100%;vertical-align:middle;animation:photoviewerLoading 1s infinite linear}.photoviewer-loader::after{content:"";display:inline-block;width:0;height:100%;vertical-align:middle;overflow:hidden}@keyframes photoviewerLoading{0%{transform:rotateZ(0deg) translate3d(0, 0, 0)}100%{transform:rotateZ(360deg) translate3d(0, 0, 0)}} + +/*# sourceMappingURL=photoviewer.min.css.map */ \ No newline at end of file diff --git a/WebRoot/html/ypzs/component/other/js/photoviewer.min.js b/WebRoot/html/ypzs/component/other/js/photoviewer.min.js new file mode 100644 index 0000000..c1ba8dd --- /dev/null +++ b/WebRoot/html/ypzs/component/other/js/photoviewer.min.js @@ -0,0 +1,15 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).photoviewer=e()}(this,function(){"use strict";function D(t,e){for(var i=0;i]*>/,N=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,X=/^(?:body|html)$/i,W=["val","css","html","text","data","width","height","offset"],t=y.createElement("table"),e=y.createElement("tr"),q={tr:y.createElement("tbody"),tbody:t,thead:t,tfoot:t,td:e,th:e,"*":y.createElement("div")},Z=/^[\w-]*$/,U={},K=U.toString,Q=y.createElement("div"),l=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)},x=y.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e=e&&e.parentNode;)if(e===t)return!0;return!1};function h(t){return null==t?String(t):U[K.call(t)]||"object"}function c(t){return"function"==h(t)}function n(t){return null!=t&&t==t.window}function G(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function s(t){return"object"==h(t)}function u(t){return s(t)&&!n(t)&&Object.getPrototypeOf(t)==Object.prototype}function J(t){var e=!!t&&"length"in t&&t.length,i=h(t);return"function"!=i&&!n(t)&&("array"==i||0===e||"number"==typeof e&&0$2>")),void 0===e&&(e=B.test(t)&&RegExp.$1),(s=q[e=e in q?e:"*"]).innerHTML=""+t,o=w.each(b.call(s.childNodes),function(){s.removeChild(this)})),u(i)&&(n=w(o),w.each(i,function(t,e){-1\n \n ',maximize:'\n \n ',close:'\n \n ',zoomIn:'\n \n ',zoomOut:'\n \n ',prev:'\n \n ',next:'\n \n ',fullscreen:'\n \n ',actualSize:'\n \n ',rotateLeft:'\n \n ',rotateRight:'\n \n '},i18n:{minimize:"Minimize",maximize:"Maximize (Alt+X)",close:"Close (Q)",zoomIn:"Zoom-in (+)",zoomOut:"Zoom-out (-)",prev:"Prev (←)",next:"Next (→)",fullscreen:"Fullscreen (F)",actualSize:"Actual-size (Ctrl+Alt+0)",rotateLeft:"Rotate-left (Ctrl+,)",rotateRight:"Rotate-right (Ctrl+.)"},multiInstances:!0,initAnimation:!0,animationDuration:400,fixedModalPos:!1,zIndex:1090,dragHandle:null,callbacks:{beforeOpen:H.noop,opened:H.noop,beforeClose:H.noop,closed:H.noop,beforeChange:H.noop,changed:H.noop},index:0,progressiveLoading:!0,appendTo:"body",customButtons:{},positionFixed:!0,initModalPos:null}),Rt=window.document;function St(t,e,i,o){var n=o?t.h:t.w,o=o?t.w:t.h;(o>e.h||n>e.w)&&i.addClass("is-grab"),o<=e.h&&n<=e.w&&i.removeClass("is-grab")}function At(){return"ontouchstart"in window||window.DocumentTouch&&Rt instanceof window.DocumentTouch}function v(t){return/^(?:body|html)$/i.test(t.nodeName)}function T(i,t){return t.reduce(function(t,e){return t+parseFloat(i.css(e))},0)}function k(t){return"border-box"===t.css("box-sizing")}var Ot=H(window),V=H(Rt),C="click",Ft="keydown",jt="wheel mousewheel DOMMouseScroll",Bt=At()?"touchstart":"mousedown",E=At()?"touchmove":"mousemove",P=At()?"touchend":"mouseup",I="photoviewer",L="."+I,_="."+I,R={isMoving:!1,isResizing:!1,zIndex:0},t={draggable:function(i,t,e){var o=this,n=!1,s=0,a=0,r=0,h=0,l=function(t){var e;(t=t||window.event).preventDefault(),!n||R.isMoving||R.isResizing||o.isMaximized||(e="touchmove"===t.type?t.targetTouches[0].pageX:t.clientX,t="touchmove"===t.type?t.targetTouches[0].pageY:t.clientY,e=e-s,t=t-a,i.css({left:e+r,top:t+h}))},c=function t(){V.off(E+_,l).off(P+_,t),n=!1,i[0].focus()};H(t).on(Bt+_,function(t){if(t=t||window.event,i[0].blur(),H(t.target).closest(e).length)return!0;o.options.multiInstances&&i.css("z-index",++R.zIndex),n=!0,s="touchstart"===t.type?t.targetTouches[0].pageX:t.clientX,a="touchstart"===t.type?t.targetTouches[0].pageY:t.clientY,r=parseFloat(i.css("left")),h=parseFloat(i.css("top")),i.css({left:r,top:h,right:"",bottom:""}),V.on(E+_,l).on(P+_,c)})}},Nt="html, body, .".concat(I,"-modal, .").concat(I,"-stage, .").concat(I,"-button, .").concat(I,"-resizable-handle"),e={movable:function(s,a){function r(){V.off(E+_,v).off(P+_,r),l=!1,R.isMoving=!1,H(Nt).removeClass("is-grabbing")}var h=this,l=!1,c=0,u=0,d=0,f=0,p=0,g=0,m=0,v=function(t){var e,i,o;(t=t||window.event).preventDefault(),l&&(e="touchmove"===t.type?t.targetTouches[0].pageX:t.clientX,t="touchmove"===t.type?t.targetTouches[0].pageY:t.clientY,i=(e=e-c)+d,o=(t=t-u)+f,0')),e=H('')),i=H('')),a=H('')),r=H('')),h=H('')),d=H('')),f=H('')),p={e:t,s:i,se:r,n:a,w:e,nw:f,ne:d,sw:h},g=(o.append(t,e,i,a,r,h,d,f),!1),m=0,v=0,w={w:0,h:0,x:0,y:0},y={w:0,h:0,x:0,y:0},b={w:0,h:0,x:0,y:0},x=0,z=0,$=0,M="",T=function(t,e,i){var o=-e+w.w>c?e+w.x:w.x+w.w-c,n=-i+w.h>u?i+w.y:w.y+w.h-u;return{e:{width:Math.max(e+w.w,c)},s:{height:Math.max(i+w.h,u)},se:{width:Math.max(e+w.w,c),height:Math.max(i+w.h,u)},w:{width:Math.max(-e+w.w,c),left:o},n:{height:Math.max(-i+w.h,u),top:n},nw:{width:Math.max(-e+w.w,c),height:Math.max(-i+w.h,u),top:n,left:o},ne:{width:Math.max(e+w.w,c),height:Math.max(-i+w.h,u),top:n},sw:{width:Math.max(-e+w.w,c),height:Math.max(i+w.h,u),left:o}}[t]},C=function(t,e,i){var o=e+w.w>c?y.w-z+e-x:c-(w.w-y.w)-z-x,n=i+w.h>u?y.h-$+i+x:u-(w.h-y.h)-$+x,e=-e+w.w>c?y.w-z-e-x:c-(w.w-y.w)-z-x,i=-i+w.h>u?y.h-$-i+x:u-(w.h-y.h)-$+x,s=(0\n ').concat(o.options.icons[e],"\n "):o.options.customButtons[e]&&(s+='\n ').concat(o.options.customButtons[e].text,"\n "))}),s}},{key:"_createTitle",value:function(){return this.options.title?''):""}},{key:"_createTemplate",value:function(){return'\n \n \n \n ').concat(this._createBtns(this.options.headerToolbar),"\n \n ").concat(this._createTitle(),'\n \n \n \n \n \n \n ")}},{key:"build",value:function(){var t=this._createTemplate(),t=H(t);this.$photoviewer=t,this.$stage=t.find(L+"-stage"),this.$title=t.find(L+"-title"),this.$image=t.find(L+"-image"),this.$close=t.find(L+"-button-close"),this.$maximize=t.find(L+"-button-maximize"),this.$minimize=t.find(L+"-button-minimize"),this.$zoomIn=t.find(L+"-button-zoomIn"),this.$zoomOut=t.find(L+"-button-zoomOut"),this.$actualSize=t.find(L+"-button-actualSize"),this.$fullscreen=t.find(L+"-button-fullscreen"),this.$rotateLeft=t.find(L+"-button-rotateLeft"),this.$rotateRight=t.find(L+"-button-rotateRight"),this.$prev=t.find(L+"-button-prev"),this.$next=t.find(L+"-button-next"),this.$stage.addClass("stage-ready"),this.$image.addClass("image-ready"),this.$photoviewer.css("z-index",R.zIndex),this.options.positionFixed&&this.$photoviewer.css({position:"fixed"}),this.options.dragHandle&&this.options.dragHandle!==L+"-modal"?this.dragHandle=this.$photoviewer.find(this.options.dragHandle):this.dragHandle=this.$photoviewer,H(this.options.appendTo).eq(0).append(this.$photoviewer),this._stageEdgeValue={horizontal:T(this.$stage,["left","right","border-left-width","border-right-width"]),vertical:T(this.$stage,["top","bottom","border-top-width","border-bottom-width"])},this._modalEdgeValue={horizontal:T(this.$photoviewer,["padding-left","padding-right","border-left-width","border-right-width"]),vertical:T(this.$photoviewer,["padding-top","padding-bottom","border-top-width","border-bottom-width"])},this._addEvents(),this._addCustomButtonEvents()}},{key:"open",value:function(){this._triggerHook("beforeOpen",this),this.options.multiInstances||H(L+"-modal").eq(0).remove(),this.build(),this.setInitModalPos(),this._triggerHook("opened",this)}},{key:"close",value:function(){this._triggerHook("beforeClose",this),this.$photoviewer.remove(),this.isOpened=!1,this.isMaximized=!1,this.isRotated=!1,this.rotationDegree=0,H(L+"-modal").length||(this.options.multiInstances&&(R.zIndex=this.options.zIndex),Ot.off("resize"+_)),this._triggerHook("closed",this)}},{key:"_getOffsetParentData",value:function(){var t=H(this.options.appendTo)[0];return{width:this.options.positionFixed||v(t)?Ot.width():t.clientWidth,height:this.options.positionFixed||v(t)?Ot.height():t.clientHeight,scrollLeft:this.options.positionFixed?0:v(t)?V.scrollLeft():t.scrollLeft,scrollTop:this.options.positionFixed?0:v(t)?V.scrollTop():t.scrollTop}}},{key:"setModalToCenter",value:function(){var t,e,i,o,n,s=0,a=0,s=(k(this.$photoviewer)||(s+=this._modalEdgeValue.horizontal,a+=this._modalEdgeValue.vertical),H.isPlainObject(this.options.initModalPos)?(o=this.options.initModalPos.left,n=this.options.initModalPos.top,t=this.options.initModalPos.right,e=this.options.initModalPos.bottom):(o=((i=this._getOffsetParentData()).width-this.options.modalWidth-s)/2+i.scrollLeft,n=(i.height-this.options.modalHeight-a)/2+i.scrollTop),{width:this.modalData.width||this.options.modalWidth,height:this.modalData.height||this.options.modalHeight,left:this.modalData.left||o,top:this.modalData.top||n,right:this.modalData.right||t,bottom:this.modalData.bottom||e});this.$photoviewer.css(s)}},{key:"setInitModalPos",value:function(){this.options.initMaximized?(this.maximize(),this.isOpened=!0):this.setModalToCenter(),this.$photoviewer[0].focus()}},{key:"setModalSize",value:function(t){var e,i,o,n,s=this,a=this._getOffsetParentData(),r=t.width+this._stageEdgeValue.horizontal,h=t.height+this._stageEdgeValue.vertical,l=0,c=0,u=(k(this.$photoviewer)?(r+=this._modalEdgeValue.horizontal,h+=this._modalEdgeValue.vertical):(l+=this._modalEdgeValue.horizontal,c+=this._modalEdgeValue.vertical),(0')),this.$stage.addClass("stage-ready"),this.$image.addClass("image-ready"),this.options.initAnimation&&!this.options.progressiveLoading&&this.$image.hide(),this.$image.attr("src",t),o=t,n=function(t){r.img=t,r.imageData={originalWidth:t.width,originalHeight:t.height},r.isMaximized||r.isOpened&&r.options.fixedModalPos?r.setImageSize(t):r.setModalSize(t),e&&e.call()},s=function(){r.$photoviewer.find(L+"-loader").remove(),i&&i.call()},(a=new Image).onload=function(){n(a)},a.onerror=function(){s(a)},a.src=o,this.options.title&&this.setImageTitle(t)}},{key:"setImageTitle",value:function(t){t=this.groupData[this.groupIndex].title||t.replace(/^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/gi,"$1");this.$title.html(t)}},{key:"jump",value:function(t){this._triggerHook("beforeChange",[this,this.groupIndex]);var e=Date.now();e-this._lastTimestamp>=this.options.animationDuration&&(this.groupIndex=this.groupIndex+t,this.jumpTo(this.groupIndex),this._lastTimestamp=e)}},{key:"jumpTo",value:function(t){var e=this;0<=(t%=this.groupData.length)?t%=this.groupData.length:t<0&&(t=(this.groupData.length+t)%this.groupData.length),this.groupIndex=t,this.loadImage(this.groupData[t].src,function(){e._triggerHook("changed",[e,t])},function(){e._triggerHook("changed",[e,t])})}},{key:"wheel",value:function(t){t.preventDefault();var e=1,e=(t.deltaY?e=0this.options.maxRatio||t]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + table = document$1.createElement('table'), + tableRow = document$1.createElement('tr'), + containers = { + 'tr': document$1.createElement('tbody'), + 'tbody': table, + 'thead': table, + 'tfoot': table, + 'td': tableRow, + 'th': tableRow, + '*': document$1.createElement('div') + }, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + tempParent = document$1.createElement('div'), + isArray = Array.isArray || function (arg) { + return Object.prototype.toString.call(arg) === '[object Array]'; + }, + contains = document$1.documentElement.contains + ? function (parent, node) { + return parent !== node && parent.contains(node); + } + : function (parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true; + return false; + }; + +function type(obj) { + return obj == null + ? String(obj) + : class2type[toString.call(obj)] || 'object'; +} + +function isFunction(value) { + return type(value) == 'function'; +} + +function isWindow(obj) { + return obj != null && obj == obj.window; +} + +function isDocument(obj) { + return obj != null && obj.nodeType == obj.DOCUMENT_NODE; +} + +function isObject(obj) { + return type(obj) == 'object'; +} + +function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} + +function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + typeRes = type(obj); + + return 'function' != typeRes && !isWindow(obj) && ( + 'array' == typeRes || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ); +} + +function compact(array) { + return filter.call(array, function (item) { + return item != null; + }); +} + +function dasherize$1(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase(); +} + +function maybeAddPx(name, value) { + return (typeof value == 'number' && !cssNumber[dasherize$1(name)]) ? value + 'px' : value; +} + +function camelize(str) { + return str.replace(/-+(.)?/g, function (match, chr) { + return chr ? chr.toUpperCase() : ''; + }); +} + +function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')); +} + +function defaultDisplay(nodeName) { + var element, display; + if (!elementDisplay[nodeName]) { + element = document$1.createElement(nodeName); + document$1.body.appendChild(element); + display = getComputedStyle(element, '').getPropertyValue('display'); + element.parentNode.removeChild(element); + display == 'none' && (display = 'block'); + elementDisplay[nodeName] = display; + } + return elementDisplay[nodeName]; +} + +function flatten(array) { + return array.length > 0 ? D.fn.concat.apply([], array) : array; +} + +function isD(object) { + return object instanceof D; +} + +function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg; +} + +function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value); +} + +// access className property while respecting SVGAnimatedString +function className(node, value) { + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined; + + if (value === undefined) return svg ? klass.baseVal : klass; + svg ? (klass.baseVal = value) : (node.className = value); +} + +D.fn = D.prototype = { + constuctor: D, + length: 0, + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + // D's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + init: function (selector, context) { + var dom; + // If nothing given, return an empty D collection + if (!selector) { + return this; + } + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim(); + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) { + dom = D.fragment(selector, RegExp.$1, context); + selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // If it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) { + return D(document$1).ready(selector); + } + // If a D collection is given, just return it + else if (isD(selector)) { + return selector; + } + // normalize array if an array of nodes is given + else if (isArray(selector)) { + dom = compact(selector); + } + // Wrap DOM nodes. + else if (isObject(selector)) { + dom = [selector], selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // And last but no least, if it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + // create a new D collection from the nodes found + return D.makeArray(dom, selector, this); + }, + // Modify the collection by adding elements to it + concat: function () { + var i, value, args = []; + for (i = 0; i < arguments.length; i++) { + value = arguments[i]; + args[i] = isD(value) ? value.toArray() : value; + } + return concat.apply(isD(this) ? this.toArray() : this, args); + }, + // `pluck` is borrowed from Prototype.js + pluck: function (property) { + return D.map(this, function (el) { return el[property]; }); + }, + toArray: function () { + return this.get(); + }, + get: function (idx) { + return idx === undefined + ? slice.call(this) + : this[idx >= 0 ? idx : idx + this.length]; + }, + size: function () { + return this.length; + }, + each: function (callback) { + emptyArray.every.call(this, function (el, idx) { + return callback.call(el, idx, el) !== false; + }); + return this; + }, + map: function (fn) { + return D(D.map(this, function (el, i) { return fn.call(el, i, el); })); + }, + slice: function () { + return D(slice.apply(this, arguments)); + }, + first: function () { + var el = this[0]; + return el && !isObject(el) ? el : D(el); + }, + last: function () { + var el = this[this.length - 1]; + return el && !isObject(el) ? el : D(el); + }, + eq: function (idx) { + return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1); + } +}; + +D.extend = D.fn.extend = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === 'boolean') { + deep = target; + + // Skip the boolean and the target + target = arguments[i] || {}; + i++; + } + // Handle case when target is a string or something (possible in deep copy) + if (typeof target !== 'object' && !isFunction(target)) { + target = {}; + } + // Extend D itself if only one argument is passed + if (i === length) { + target = this; + i--; + } + for (; i < length; i++) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + src = target[name]; + copy = options[name]; + // Prevent never-ending loop + if (target === copy) { + continue; + } + // Recurse if we're merging plain objects or arrays + if (deep && copy && (isPlainObject(copy) || + (copyIsArray = isArray(copy)))) { + if (copyIsArray) { + copyIsArray = false; + clone = src && isArray(src) ? src : []; + } else { + clone = src && isPlainObject(src) ? src : {}; + } + // Never move original objects, clone them + target[name] = D.extend(deep, clone, copy); + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; + } + } + } + } + // Return the modified object + return target; +}; + +D.extend({ + // Make DOM Array + makeArray: function (dom, selector, me) { + var i, len = dom ? dom.length : 0; + for (i = 0; i < len; i++) me[i] = dom[i]; + me.length = len; + me.selector = selector || ''; + return me; + }, + // D's CSS selector + qsa: function (element, selector) { + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + // Ensure that a 1 char tag name still gets checked + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, + isSimple = simpleSelectorRE.test(nameOnly); + return ( + // Safari DocumentFragment doesn't have getElementById + element.getElementById && isSimple && maybeID) + // eslint-disable-next-line no-cond-assign + ? (found = element.getElementById(nameOnly)) + ? [found] + : [] + : element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11 + ? [] + : slice.call( + // DocumentFragment doesn't have getElementsByClassName/TagName + isSimple && !maybeID && element.getElementsByClassName + ? maybeClass + // If it's simple, it could be a class + ? element.getElementsByClassName(nameOnly) + // Or a tag + : element.getElementsByTagName(selector) + // Or it's not simple, and we need to query all + : element.querySelectorAll(selector) + ); + }, + // Html -> Node + fragment: function (html, name, properties) { + var dom, nodes, container; + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = D(document$1.createElement(RegExp.$1)); + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, '<$1>$2>'); + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1; + if (!(name in containers)) name = '*'; + + container = containers[name]; + container.innerHTML = '' + html; + dom = D.each(slice.call(container.childNodes), function () { + container.removeChild(this); + }); + } + + if (isPlainObject(properties)) { + nodes = D(dom); + D.each(properties, function (key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value); + else nodes.attr(key, value); + }); + } + + return dom; + }, + matches: function (element, selector) { + if (!selector || !element || element.nodeType !== 1) return false; + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector; + if (matchesSelector) return matchesSelector.call(element, selector); + // fall back to performing a selector: + var match, parent = element.parentNode, + temp = !parent; + if (temp) (parent = tempParent).appendChild(element); + match = ~D.qsa(parent, selector).indexOf(element); + temp && tempParent.removeChild(element); + return match; + }, + each: function (elements, callback) { + var i, key; + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements; + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements; + } + + return elements; + }, + map: function (elements, callback) { + var value, values = [], + i, key; + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i); + if (value != null) values.push(value); + } + else + for (key in elements) { + value = callback(elements[key], key); + if (value != null) values.push(value); + } + return flatten(values); + } +}); + +// Populate the class2type map +D.each('Boolean Number String Function Array Date RegExp Object Error'.split(' '), function (i, name) { + class2type['[object ' + name + ']'] = name.toLowerCase(); +}); + +D.fn.init.prototype = D.fn; + +function noop() { +} + +function css(property, value) { + if (arguments.length < 2) { + var element = this[0]; + if (typeof property == 'string') { + if (!element) return; + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property); + } else if (isArray(property)) { + if (!element) return; + var props = {}; + var computedStyle = getComputedStyle(element, ''); + D.each(property, function (_, prop) { + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)); + }); + return props; + } + } + + var css = ''; + if (type(property) == 'string') { + if (!value && value !== 0) { + this.each(function () { + this.style.removeProperty(dasherize$1(property)); + }); + } else { + css = dasherize$1(property) + ':' + maybeAddPx(property, value); + } + } else { + for (var key in property) { + if (!property[key] && property[key] !== 0) { + this.each(function () { this.style.removeProperty(dasherize$1(key)); }); + } else { + css += dasherize$1(key) + ':' + maybeAddPx(key, property[key]) + ';'; + } + } + } + + return this.each(function () { this.style.cssText += ';' + css; }); +} + +function hasClass(name) { + if (!name) return false; + return emptyArray.some.call(this, function (el) { + return this.test(className(el)); + }, classRE(name)); +} + +function addClass(name) { + var classList = []; + if (!name) return this; + return this.each(function (idx) { + if (!('className' in this)) return; + classList = []; + var cls = className(this), + newName = funcArg(this, name, idx, cls); + newName.split(/\s+/g).forEach(function (klass) { + if (!D(this).hasClass(klass)) classList.push(klass); + }, this); + classList.length && className(this, cls + (cls ? ' ' : '') + classList.join(' ')); + }); +} + +function removeClass(name) { + var classList = []; + return this.each(function (idx) { + if (!('className' in this)) return; + if (name === undefined) return className(this, ''); + classList = className(this); + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function (klass) { + classList = classList.replace(classRE(klass), ' '); + }); + className(this, classList.trim()); + }); +} + +function offset(coordinates) { + if (coordinates) return this.each(function (index) { + var $this = D(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + }; + + if ($this.css('position') == 'static') props['position'] = 'relative'; + $this.css(props); + }); + if (!this.length) return null; + if (document$1.documentElement !== this[0] && !contains(document$1.documentElement, this[0])) + return { top: 0, left: 0 }; + var obj = this[0].getBoundingClientRect(); + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + }; +} + +function position() { + if (!this.length) return; + + var elem = this[0], offset, + // Get *real* offset parent + offsetParent = this.offsetParent(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // `position: fixed` elements are offset from the viewport, which itself always has zero offset + if (D(elem).css('position') === 'fixed') { + // Assume `position: fixed` implies availability of getBoundingClientRect + offset = elem.getBoundingClientRect(); + } else { + offset = this.offset(); + + // Incorporate borders into its offset, since they are outside its content origin + parentOffset.top += parseFloat(D(offsetParent[0]).css('border-top-width')) || 0; + parentOffset.left += parseFloat(D(offsetParent[0]).css('border-left-width')) || 0; + } + + // Subtract parent offsets and element margins + // note: when an element has `margin: auto` the offsetLeft and marginLeft + // are the same in Safari causing `offset.left` to incorrectly be 0 + return { + top: offset.top - parentOffset.top - parseFloat(D(elem).css('margin-top')) || 0, + left: offset.left - parentOffset.left - parseFloat(D(elem).css('margin-left')) || 0 + }; +} + +function scrollTop(value) { + if (!this.length) return; + var hasScrollTop = 'scrollTop' in this[0]; + if (value === undefined) return hasScrollTop + ? this[0].scrollTop + : isWindow(this[0]) + ? this[0].pageYOffset + : this[0].defaultView.pageYOffset; + return this.each(hasScrollTop ? + function () { this.scrollTop = value; } : + function () { this.scrollTo(this.scrollX, value); }); +} + +function scrollLeft(value) { + if (!this.length) return; + var hasScrollLeft = 'scrollLeft' in this[0]; + if (value === undefined) return hasScrollLeft + ? this[0].scrollLeft + : isWindow(this[0]) + ? this[0].pageXOffset + : this[0].defaultView.pageXOffset; + return this.each(hasScrollLeft ? + function () { this.scrollLeft = value; } : + function () { this.scrollTo(value, this.scrollY); }); +} + +function offsetParent() { + return this.map(function () { + var parent = this.offsetParent || document$1.body; + while (parent && !rootNodeRE.test(parent.nodeName) && D(parent).css('position') == 'static') + parent = parent.offsetParent; + return parent; + }); +} + +function attr(name, value) { + var result; + return (typeof name == 'string' && !(1 in arguments)) + ? (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null + ? result + : undefined) + : this.each(function (idx) { + if (this.nodeType !== 1) return; + if (isObject(name)) + for (var key in name) setAttribute(this, key, name[key]); + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))); + }); +} + +function removeAttr(name) { + return this.each(function () { + this.nodeType === 1 && name.split(' ').forEach(function (attribute) { + setAttribute(this, attribute); + }, this); + }); +} + +function find(selector) { + var result, $this = this; + if (!selector) result = D(); + else if (typeof selector == 'object') + result = D(selector).filter(function () { + var node = this; + return emptyArray.some.call($this, function (parent) { + return contains(parent, node); + }); + }); + else if (this.length == 1) result = D(D.qsa(this[0], selector)); + else result = this.map(function () { return D.qsa(this, selector); }); + return result; +} + +function closest(selector, context) { + var nodes = [], + collection = typeof selector == 'object' && D(selector); + this.each(function (_, node) { + while (node && !(collection ? collection.indexOf(node) >= 0 : D.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode; + if (node && nodes.indexOf(node) < 0) nodes.push(node); + }); + return D(nodes); +} + +function isIE() { + var ua = window.navigator.userAgent; + var msie = ua.indexOf('MSIE '); + return msie > 0 || !!navigator.userAgent.match(/Trident.*rv:11\./); +} + +function subtract(el, dimen) { + var offsetMap = { + width: ['padding-left', 'padding-right', 'border-left-width', 'border-right-width'], + height: ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width'] + }; + return el.css('box-sizing') === 'border-box' && !isIE() + ? parseFloat(el.css(dimen)) + - parseFloat(el.css(offsetMap[dimen][0])) + - parseFloat(el.css(offsetMap[dimen][1])) + - parseFloat(el.css(offsetMap[dimen][2])) + - parseFloat(el.css(offsetMap[dimen][3])) + : parseFloat(el.css(dimen)); +} + +function calc(dimension, value) { + var dimensionProperty = dimension.replace(/./, function (m) { return m[0].toUpperCase(); }); + var el = this[0]; + if (value === undefined) return isWindow(el) + ? el.document.documentElement['client' + dimensionProperty] + : isDocument(el) + ? el.documentElement['scroll' + dimensionProperty] + : subtract(this, dimension); + else return this.each(function (idx) { + el = D(this); + el.css(dimension, funcArg(this, value, idx, el[dimension]())); + }); +} + +// Export + +function width(value) { + return calc.call(this, 'width', value); +} + +function height(value) { + return calc.call(this, 'height', value); +} + +var traverseNode = function (node, fn) { + fn(node); + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fn); +}; + +// inside => append, prepend +var domMani = function (elem, args, fn, inside) { + // arguments can be nodes, arrays of nodes, D objects and HTML strings + var argType, + nodes = D.map(args, function (arg) { + var arr = []; + argType = type(arg); + if (argType == 'array') { + arg.forEach(function (el) { + if (el.nodeType !== undefined) return arr.push(el); + else if (isD(el)) return arr = arr.concat(el.get()); + arr = arr.concat(D.fragment(el)); + }); + return arr; + } + return argType == 'object' || arg == null ? arg : D.fragment(arg); + }), + parent, + copyByClone = elem.length > 1; + + if (nodes.length < 1) return elem; + + return elem.each(function (_, target) { + parent = inside ? target : target.parentNode; + var parentInDocument = contains(document$1.documentElement, parent); + + nodes.forEach(function (node) { + if (copyByClone) node = node.cloneNode(true); + else if (!parent) return D(node).remove(); + + fn.call(target, node); + + if (parentInDocument) { + traverseNode(node, function (el) { + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) { + var target = el.ownerDocument ? el.ownerDocument.defaultView : window; + target['eval'].call(target, el.innerHTML); + } + }); + } + }); + }); +}; + +// Export + +function remove$1() { + return this.each(function () { + if (this.parentNode != null) + this.parentNode.removeChild(this); + }); +} + +function empty() { + return this.each(function () { this.innerHTML = ''; }); +} + +function html(html) { + return 0 in arguments + ? this.each(function (idx) { + var originHtml = this.innerHTML; + D(this).empty().append(funcArg(this, html, idx, originHtml)); + }) + : (0 in this ? this[0].innerHTML : null); +} + +function append() { + return domMani(this, arguments, function (elem) { + this.insertBefore(elem, null); + }, true); +} + +var _zid = 1; +function zid(element) { + return element._zid || (element._zid = _zid++); +} + +function isString(obj) { + return typeof obj == 'string'; +} + +var returnTrue = function () { return true; }, + returnFalse = function () { return false; }, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + }; + +function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event); + + D.each(eventMethods, function (name, predicate) { + var sourceMethod = source[name]; + event[name] = function () { + this[predicate] = returnTrue; + return sourceMethod && sourceMethod.apply(source, arguments); + }; + event[predicate] = returnFalse; + }); + + try { + event.timeStamp || (event.timeStamp = Date.now()); + } catch (ignored) { + console.warn(ignored); + } + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue; + } + return event; +} + +var handlers = {}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/; + +function parse(event) { + var parts = ('' + event).split('.'); + return { e: parts[0], ns: parts.slice(1).sort().join(' ') }; +} +function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)'); +} + +function findHandlers(element, event, fn, selector) { + event = parse(event); + if (event.ns) var matcher = matcherFor(event.ns); + return (handlers[zid(element)] || []).filter(function (handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector); + }); +} + +function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting; +} + +function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type; +} + +function add(element, events, fn, data, selector, delegator, capture) { + var id = zid(element), set = (handlers[id] || (handlers[id] = [])); + events.split(/\s/).forEach(function (event) { + if (event == 'ready') return D(document$1).ready(fn); + var handler = parse(event); + handler.fn = fn; + handler.sel = selector; + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function (e) { + var related = e.relatedTarget; + if (!related || (related !== this && !contains(this, related))) + return handler.fn.apply(this, arguments); + }; + handler.del = delegator; + var callback = delegator || fn; + handler.proxy = function (e) { + e = compatible(e); + if (e.isImmediatePropagationStopped()) return; + e.data = data; + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)); + if (result === false) e.preventDefault(), e.stopPropagation(); + return result; + }; + handler.i = set.length; + set.push(handler); + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); +} + +function remove(element, events, fn, selector, capture) { + var id = zid(element); + (events || '').split(/\s/).forEach(function (event) { + findHandlers(element, event, fn, selector).forEach(function (handler) { + delete handlers[id][handler.i]; + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); + }); +} + +function createProxy(event) { + var key, proxy = { originalEvent: event }; + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]; + + return compatible(proxy, event); +} + +var on = function (event, selector, data, callback, one) { + var autoRemove, delegator, $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.on(type, selector, data, fn, one); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined; + if (callback === undefined || data === false) + callback = data, data = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function (_, element) { + if (one) autoRemove = function (e) { + remove(element, e.type, callback); + return callback.apply(this, arguments); + }; + + if (selector) delegator = function (e) { + var evt, match = D(e.target).closest(selector, element).get(0); + if (match && match !== element) { + evt = D.extend(createProxy(e), { currentTarget: match, liveFired: element }); + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))); + } + }; + + add(element, event, callback, data, selector, delegator || autoRemove); + }); +}; + +var off = function (event, selector, callback) { + var $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.off(type, selector, fn); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function () { + remove(this, event, callback, selector); + }); +}; + +var prefix = '', + eventPrefix, + vendors = { Webkit: 'webkit', Moz: '', O: 'o' }, + testEl = document$1.createElement('div'), + testTransitionProperty = testEl.style.transitionProperty; + +if (testEl.style.transform === undefined) D.each(vendors, function (vendor, event) { + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + vendor.toLowerCase() + '-'; + eventPrefix = event; + return false; + } +}); + +testEl = null; + +// fx cannot seperate +function normalizeEvent(name) { + return eventPrefix ? eventPrefix + name : name.toLowerCase(); +} + +D.fx = { + off: (eventPrefix === undefined && testTransitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') +}; + +var supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, transitionDelay, + animationName, animationDuration, animationTiming, animationDelay, + cssReset = {}; + +function dasherize(str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); } + +transform = prefix + 'transform'; +cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionDelay = prefix + 'transition-delay'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationDelay = prefix + 'animation-delay'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = ''; + +var anim$1 = function (properties, duration, ease, callback, delay) { + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = D.fx.transitionEnd, + fired = false; + + if (duration === undefined) duration = D.fx.speeds._default / 1000; + if (delay === undefined) delay = 0; + if (D.fx.off) duration = 0; + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties; + cssValues[animationDuration] = duration + 's'; + cssValues[animationDelay] = delay + 's'; + cssValues[animationTiming] = (ease || 'linear'); + endEvent = D.fx.animationEnd; + } else { + cssProperties = []; + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '; + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)); + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform); + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', '); + cssValues[transitionDuration] = duration + 's'; + cssValues[transitionDelay] = delay + 's'; + cssValues[transitionTiming] = (ease || 'linear'); + } + } + + wrappedCallback = function (event) { + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return; // makes sure the event didn't bubble from "below" + D(event.target).off(endEvent, wrappedCallback); + } else + D(this).off(endEvent, wrappedCallback); // triggered by setTimeout + + fired = true; + D(this).css(cssReset); + callback && callback.call(this); + }; + if (duration > 0) { + this.on(endEvent, wrappedCallback); + // transitionEnd is not always firing on older Android phones + // so make sure it gets fired + setTimeout(function () { + if (fired) return; + wrappedCallback.call(that); + }, ((duration + delay) * 1000) + 25); + } + + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft; + + this.css(cssValues); + + if (duration <= 0) setTimeout(function () { + that.each(function () { wrappedCallback.call(this); }); + }, 0); + + return this; +}; + +var animate = function (properties, duration, ease, callback, delay) { + if (isFunction(duration)) + callback = duration, ease = undefined, duration = undefined; + if (isFunction(ease)) + callback = ease, ease = undefined; + if (isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration; + if (duration) duration = (typeof duration == 'number' ? duration : + (D.fx.speeds[duration] || D.fx.speeds._default)) / 1000; + if (delay) delay = parseFloat(delay) / 1000; + return this.anim(properties, duration, ease, callback, delay); +}; + +var origShow = function () { + return this.each(function () { + this.style.display == 'none' && (this.style.display = ''); + if (getComputedStyle(this, '').getPropertyValue('display') == 'none') + this.style.display = defaultDisplay(this.nodeName); + }); +}; + +var origHide = function () { + return this.css('display', 'none'); +}; + +function anim(el, speed, opacity, scale, callback) { + if (typeof speed == 'function' && !callback) callback = speed, speed = undefined; + var props = { opacity: opacity }; + if (scale) { + props.scale = scale; + el.css(D.fx.cssPrefix + 'transform-origin', '0 0'); + } + return el.animate(props, speed, null, callback); +} + +function hideHelper(el, speed, scale, callback) { + return anim(el, speed, 0, scale, function () { + origHide.call(D(this)); + callback && callback.call(this); + }); +} + +// Export + +var show = function (speed, callback) { + origShow.call(this); + if (speed === undefined) speed = 0; + else this.css('opacity', 0); + return anim(this, speed, 1, '1,1', callback); +}; + +var hide = function (speed, callback) { + if (speed === undefined) return origHide.call(this); + else return hideHelper(this, speed, '0,0', callback); +}; + +var fadeTo = function (speed, opacity, callback) { + return anim(this, speed, opacity, null, callback); +}; + +var fadeIn = function (speed, callback) { + var target = this.css('opacity'); + if (target > 0) this.css('opacity', 0); + else target = 1; + return origShow.call(this).fadeTo(speed, target, callback); +}; + +var $ = D; +var methods = { + isPlainObject: isPlainObject, + isArray: isArray, + noop: noop +}; +var fnMethods = { + find: find, + closest: closest, + css: css, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass, + attr: attr, + removeAttr: removeAttr, + append: append, + remove: remove$1, + empty: empty, + html: html, + width: width, + height: height, + scrollTop: scrollTop, + scrollLeft: scrollLeft, + offset: offset, + offsetParent: offsetParent, + position: position, + on: on, + off: off, + show: show, + hide: hide, + anim: anim$1, + animate: animate, + fadeTo: fadeTo, + fadeIn: fadeIn +}; +$.extend(methods); +$.fn.extend(fnMethods); + +var DEFAULTS = { + // Whether to enable modal dragging + draggable: true, + // Whether to enable modal resizing + resizable: true, + // Whether to enable image moving + movable: true, + // Whether to enable keyboard navigation + keyboard: true, + // Whether to show the title + title: true, + // Min width of modal + modalWidth: 320, + // Min height of modal + modalHeight: 320, + // Whether to change the modal size after image loaded + fixedModalSize: false, + // Whether to set maximized on init + initMaximized: false, + // Threshold of modal relative to browser window + gapThreshold: 0.02, + // Threshold of image ratio + ratioThreshold: 0.1, + // Min ratio of image when zoom out + minRatio: 0.05, + // Max ratio of image when zoom in + maxRatio: 16, + // Toolbar options in header + headerToolbar: ['maximize', 'close'], + // Toolbar options in footer + footerToolbar: ['zoomIn', 'zoomOut', 'prev', 'fullscreen', 'next', 'actualSize', 'rotateRight'], + // Custom icon for button + icons: { + minimize: "\n \n ", + maximize: "\n \n ", + close: "\n \n ", + zoomIn: "\n \n ", + zoomOut: "\n \n ", + prev: "\n \n ", + next: "\n \n ", + fullscreen: "\n \n ", + actualSize: "\n \n ", + rotateLeft: "\n \n ", + rotateRight: "\n \n " + }, + // Custom title for button + i18n: { + minimize: 'Minimize', + maximize: 'Maximize (Alt+X)', + close: 'Close (Q)', + zoomIn: 'Zoom-in (+)', + zoomOut: 'Zoom-out (-)', + prev: 'Prev (←)', + next: 'Next (→)', + fullscreen: 'Fullscreen (F)', + actualSize: 'Actual-size (Ctrl+Alt+0)', + rotateLeft: 'Rotate-left (Ctrl+,)', + rotateRight: 'Rotate-right (Ctrl+.)' + }, + // Whether to enable multiple instances + multiInstances: true, + // Whether to enable modal transform animation + initAnimation: true, + // Modal transform animation duration + animationDuration: 400, + // Whether to disable modal translate to center after image changed + fixedModalPos: false, + // Modal css `z-index` + zIndex: 1090, + // Selector of drag handler + dragHandle: null, + // Callback events + callbacks: { + beforeOpen: $.noop, + opened: $.noop, + beforeClose: $.noop, + closed: $.noop, + beforeChange: $.noop, + changed: $.noop + }, + // Start index of images + index: 0, + // Whether to load the image progressively + progressiveLoading: true, + // The DOM element which photoviewer will be attached to + appendTo: 'body', + // Custom Buttons + customButtons: {}, + // Whether to set modal css `position: fixed` + positionFixed: true, + // Init modal position `{top: 0, right: 0, bottom: 0, left: 0}` + initModalPos: null +}; + +var document = window.document; + +/** + * Debounce function + * + * @param {function} fn - The function will be triggered + * @param {number} delay - The debounce delay time + * @return {function} + */ +function debounce(fn, delay) { + var timer = null; + return function () { + var context = this; + var args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; +} + +/** + * Preload a image + * + * @param {string} src - The image src + * @param {function} success - The callback of success + * @param {function} error - The callback of error + */ +function preloadImage(src, success, error) { + var img = new Image(); + img.onload = function () { + success(img); + }; + img.onerror = function () { + error(img); + }; + img.src = src; +} + +/** + * Request fullscreen + * + * @param {type} element + */ +function requestFullscreen(element) { + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } +} + +/** + * Get the image name from its url + * + * @param {string} url - The image src + * @return {string} + */ +function getImageNameFromUrl(url) { + var reg = /^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/gi; + var txt = url.replace(reg, '$1'); + return txt; +} + +/** + * Set grab cursor when move image + * + * @param {object} imageData - The image data + * @param {object} stageData - The stage data + * @param {object} $stage - The stage element of domq + * @param {boolean} isRotate - The image rotated flag + */ +function setGrabCursor(imageData, stageData, $stage, isRotated) { + var imageWidth = !isRotated ? imageData.w : imageData.h; + var imageHeight = !isRotated ? imageData.h : imageData.w; + if (imageHeight > stageData.h || imageWidth > stageData.w) { + $stage.addClass('is-grab'); + } + if (imageHeight <= stageData.h && imageWidth <= stageData.w) { + $stage.removeClass('is-grab'); + } +} + +/** + * Check whether browser support touch event + * + * @return {boolean} + */ +function supportTouch() { + return !!('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch); +} + +/** + * Check whether element is root node (`body` or `html`) + * + * @param {object} elem - The DOM element + * @return {boolean} + */ +function isRootNode(elem) { + return /^(?:body|html)$/i.test(elem.nodeName); +} + +/** + * Get sum value of CSS props + * + * @param {object} $elem - The domq element + * @param {array} props - The array of CSS props + * @return {number} + */ +function getCSSValueSum($elem, props) { + return props.reduce(function (acc, cur) { + return acc + parseFloat($elem.css(cur)); + }, 0); +} + +/** + * Check whether element's CSS `box-sizing` is `border-box` + * + * @param {object} $elem - The domq element + * @return {boolean} + */ +function isBorderBox($elem) { + return $elem.css('box-sizing') === 'border-box'; +} + +var $W = $(window); +var $D = $(document); +var CLICK_EVENT = 'click'; +var RESIZE_EVENT = 'resize'; +var KEYDOWN_EVENT = 'keydown'; +var WHEEL_EVENT = 'wheel mousewheel DOMMouseScroll'; +var TOUCH_START_EVENT = supportTouch() ? 'touchstart' : 'mousedown'; +var TOUCH_MOVE_EVENT = supportTouch() ? 'touchmove' : 'mousemove'; +var TOUCH_END_EVENT = supportTouch() ? 'touchend' : 'mouseup'; +var NS = 'photoviewer'; +var CLASS_NS = '.' + NS; +var EVENT_NS = '.' + NS; +var PUBLIC_VARS = { + // Whether image is moving + isMoving: false, + // Whether modal is resizing + isResizing: false, + // Modal's `z-index` + zIndex: 0 +}; + +var draggable = { + /** + * Modal draggable + * + * @param {object} $modal - The modal element of domq + * @param {object} dragHandle - The handle element when dragging + * @param {object} dragCancel - The cancel element when dragging + */ + draggable: function draggable($modal, dragHandle, dragCancel) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + + // Must be removed + // e.preventDefault(); + + // Fix focus scroll issue on Chrome + $modal[0].blur(); + + // Get clicked button + var elemCancel = $(e.target).closest(dragCancel); + // Stop modal moving when click buttons + if (elemCancel.length) { + return true; + } + if (_this.options.multiInstances) { + $modal.css('z-index', ++PUBLIC_VARS['zIndex']); + } + isDragging = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Get current position of the modal + left = parseFloat($modal.css('left')); + top = parseFloat($modal.css('top')); + + // Reset modal position with left and top + $modal.css({ + left: left, + top: top, + right: '', + bottom: '' + }); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !PUBLIC_VARS['isMoving'] && !PUBLIC_VARS['isResizing'] && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + $modal.css({ + left: relativeX + left, + top: relativeY + top + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + + // Focus must be executed after drag end + $modal[0].focus(); + }; + $(dragHandle).on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } +}; + +var ELEMS_WITH_GRABBING_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button, .").concat(NS, "-resizable-handle"); +var movable = { + /** + * Image movable + * + * 1. No movable + * 2. Vertical movable + * 3. Horizontal movable + * 4. Vertical & Horizontal movable + * + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + */ + movable: function movable($stage, $image) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var widthDiff = 0; + var heightDiff = 0; + var δ = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + e.preventDefault(); + var imageWidth = $image.width(); + var imageHeight = $image.height(); + var stageWidth = $stage.width(); + var stageHeight = $stage.height(); + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageWidth - imageHeight) / 2; + + // Width or height difference can be use to limit image right or top position + widthDiff = !_this.isRotated ? imageWidth - stageWidth : imageHeight - stageWidth; + heightDiff = !_this.isRotated ? imageHeight - stageHeight : imageWidth - stageHeight; + + // Modal can be dragging if image is smaller to stage + isDragging = widthDiff > 0 || heightDiff > 0 ? true : false; + PUBLIC_VARS['isMoving'] = widthDiff > 0 || heightDiff > 0 ? true : false; + + // Reclac the element position when mousedown + // Fix the issue of stage with a border + left = $image.position().left - δ; + top = $image.position().top + δ; + + // Add grabbing cursor + if ($stage.hasClass('is-grab')) { + $(ELEMS_WITH_GRABBING_CURSOR).addClass('is-grabbing'); + } + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var newLeft = relativeX + left; + var newTop = relativeY + top; + + // Vertical limit + if (heightDiff > 0) { + if (relativeY + top > δ) { + newTop = δ; + } else if (relativeY + top < -heightDiff + δ) { + newTop = -heightDiff + δ; + } + } else { + newTop = top; + } + // Horizontal limit + if (widthDiff > 0) { + if (relativeX + left > -δ) { + newLeft = -δ; + } else if (relativeX + left < -widthDiff - δ) { + newLeft = -widthDiff - δ; + } + } else { + newLeft = left; + } + $image.css({ + left: newLeft, + top: newTop + }); + + // Update image initial data + $.extend(_this.imageData, { + left: newLeft, + top: newTop + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + PUBLIC_VARS['isMoving'] = false; + + // Remove grabbing cursor + $(ELEMS_WITH_GRABBING_CURSOR).removeClass('is-grabbing'); + }; + $stage.on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } +}; + +var ELEMS_WITH_RESIZE_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button"); +var resizable = { + /** + * Modal resizable + * + * 1. Can be resized in 8 directions + * 2. Keep image in stage center + * 3. Other restrictions for image + * + * @param {object} $modal - The modal element of domq + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + * @param {number} minWidth - The modalWidth option + * @param {number} minHeight - The modalHeight option + */ + resizable: function resizable($modal, $stage, $image, minWidth, minHeight) { + var _this = this; + var resizableHandleE = $("")); + var resizableHandleW = $("")); + var resizableHandleS = $("")); + var resizableHandleN = $("")); + var resizableHandleSE = $("")); + var resizableHandleSW = $("")); + var resizableHandleNE = $("")); + var resizableHandleNW = $("")); + var resizableHandles = { + e: resizableHandleE, + s: resizableHandleS, + se: resizableHandleSE, + n: resizableHandleN, + w: resizableHandleW, + nw: resizableHandleNW, + ne: resizableHandleNE, + sw: resizableHandleSW + }; + $modal.append(resizableHandleE, resizableHandleW, resizableHandleS, resizableHandleN, resizableHandleSE, resizableHandleSW, resizableHandleNE, resizableHandleNW); + var isDragging = false; + var startX = 0; + var startY = 0; + var modalData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var stageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var imageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + // δ is the difference between image width and height + var δ = 0; + var imgWidth = 0; + var imgHeight = 0; + var direction = ''; + + // Modal CSS options + var getModalOpts = function getModalOpts(dir, offsetX, offsetY) { + // Modal should not move when its width to the minwidth + var modalLeft = -offsetX + modalData.w > minWidth ? offsetX + modalData.x : modalData.x + modalData.w - minWidth; + var modalTop = -offsetY + modalData.h > minHeight ? offsetY + modalData.y : modalData.y + modalData.h - minHeight; + var opts = { + e: { + width: Math.max(offsetX + modalData.w, minWidth) + }, + s: { + height: Math.max(offsetY + modalData.h, minHeight) + }, + se: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight) + }, + w: { + width: Math.max(-offsetX + modalData.w, minWidth), + left: modalLeft + }, + n: { + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + nw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop, + left: modalLeft + }, + ne: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + sw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight), + left: modalLeft + } + }; + return opts[dir]; + }; + + // Image CSS options + var getImageOpts = function getImageOpts(dir, offsetX, offsetY) { + // Image should not move when modal width to the min width + // The minwidth is modal width, so we should clac the stage minwidth + var widthDiff = offsetX + modalData.w > minWidth ? stageData.w - imgWidth + offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff = offsetY + modalData.h > minHeight ? stageData.h - imgHeight + offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + var widthDiff2 = -offsetX + modalData.w > minWidth ? stageData.w - imgWidth - offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff2 = -offsetY + modalData.h > minHeight ? stageData.h - imgHeight - offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + + // Get image position in dragging + var imgLeft = (widthDiff > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop = (heightDiff > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var imgLeft2 = (widthDiff2 > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop2 = (heightDiff2 > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var opts = { + e: { + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + s: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff + }, + se: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + w: { + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + n: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2 + }, + nw: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + ne: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + sw: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + } + }; + return opts[dir]; + }; + var dragStart = function dragStart(dir, e) { + e = e || window.event; + e.preventDefault(); + isDragging = true; + PUBLIC_VARS['isResizing'] = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Reclac the modal data when mousedown + modalData = { + w: $modal.width() + (isBorderBox($modal) ? _this._modalEdgeValue.horizontal : 0), + h: $modal.height() + (isBorderBox($modal) ? _this._modalEdgeValue.vertical : 0), + x: $modal.position().left, + y: $modal.position().top + }; + stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.position().left, + y: $stage.position().top + }; + imageData = { + w: $image.width(), + h: $image.height(), + x: $image.position().left, + y: $image.position().top + }; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageData.w - imageData.h) / 2; + imgWidth = !_this.isRotated ? imageData.w : imageData.h; + imgHeight = !_this.isRotated ? imageData.h : imageData.w; + direction = dir; + + // Add resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', dir + '-resize'); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var modalOpts = getModalOpts(direction, relativeX, relativeY); + $modal.css(modalOpts); + var imageOpts = getImageOpts(direction, relativeX, relativeY); + $image.css(imageOpts); + _this.isDoResize = true; + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + + // Set grab cursor + if (PUBLIC_VARS['isResizing']) { + setGrabCursor({ + w: imgWidth, + h: imgHeight + }, { + w: $stage.width(), + h: $stage.height() + }, $stage); + } + isDragging = false; + PUBLIC_VARS['isResizing'] = false; + + // Remove resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', ''); + + // Update image initial data + var scale = _this.getImageScale($stage.width(), $stage.height()); + $.extend(_this.imageData, { + initWidth: _this.img.width * scale, + initHeight: _this.img.height * scale, + initLeft: ($stage.width() - _this.img.width * scale) / 2, + initTop: ($stage.height() - _this.img.height * scale) / 2 + }); + }; + $.each(resizableHandles, function (dir, handle) { + handle.on(TOUCH_START_EVENT + EVENT_NS, function (e) { + dragStart(dir, e); + }); + }); + } +}; + +/** + * PhotoViewer class + */ +var PhotoViewer = /*#__PURE__*/function () { + function PhotoViewer(items, options, el) { + _classCallCheck(this, PhotoViewer); + this.options = $.extend(true, {}, DEFAULTS, options); + if (options && $.isArray(options.footerToolbar)) { + this.options.footerToolbar = options.footerToolbar; + } + if (options && $.isArray(options.headerToolbar)) { + this.options.headerToolbar = options.headerToolbar; + } + + // Store element of clicked + this.$el = $(el); + + // As we have multiple instances, so every instance has the following variables. + + // Whether modal opened + this.isOpened = false; + + // Whether modal maximized + this.isMaximized = false; + + // Whether image rotated (`90*(2n+1)`) + this.isRotated = false; + + // Image rotation degree + this.rotationDegree = 0; + + // Whether modal do resize + this.isDoResize = false; + + // Store image data in every instance + this.imageData = {}; + + // Store modal data in every instance + this.modalData = { + width: null, + height: null, + left: null, + top: null + }; + + // Used for time comparison + this._lastTimestamp = 0; + this.init(items, this.options); + } + _createClass(PhotoViewer, [{ + key: "init", + value: function init(items, opts) { + this.groupData = items; + this.groupIndex = opts['index']; + + // Reset public z-index with option + PUBLIC_VARS['zIndex'] = PUBLIC_VARS['zIndex'] === 0 ? opts['zIndex'] : PUBLIC_VARS['zIndex']; + + // Get image src + var imgSrc = items[this.groupIndex]['src']; + this.open(); + this.loadImage(imgSrc); + if (opts.draggable) { + this.draggable(this.$photoviewer, this.dragHandle, CLASS_NS + '-button'); + } + if (opts.movable) { + this.movable(this.$stage, this.$image); + } + if (opts.resizable) { + this.resizable(this.$photoviewer, this.$stage, this.$image, opts.modalWidth, opts.modalHeight); + } + } + }, { + key: "_createBtns", + value: function _createBtns(toolbar) { + var _this = this; + var btns = ['minimize', 'maximize', 'close', 'zoomIn', 'zoomOut', 'prev', 'next', 'fullscreen', 'actualSize', 'rotateLeft', 'rotateRight']; + var btnsHTML = ''; + $.each(toolbar, function (index, item) { + var btnClass = "".concat(NS, "-button ").concat(NS, "-button-").concat(item); + if (btns.indexOf(item) >= 0) { + btnsHTML += "\n ").concat(_this.options.icons[item], "\n "); + } else if (_this.options.customButtons[item]) { + btnsHTML += "\n ").concat(_this.options.customButtons[item].text, "\n "); + } + }); + return btnsHTML; + } + }, { + key: "_createTitle", + value: function _createTitle() { + return this.options.title ? "") : ''; + } + }, { + key: "_createTemplate", + value: function _createTemplate() { + // PhotoViewer base HTML + var photoviewerHTML = "\n \n \n \n ").concat(this._createBtns(this.options.headerToolbar), "\n \n ").concat(this._createTitle(), "\n \n \n \n \n \n \n ").concat(this._createBtns(this.options.footerToolbar), "\n \n \n \n "); + return photoviewerHTML; + } + }, { + key: "build", + value: function build() { + // Create PhotoViewer HTML string + var photoviewerHTML = this._createTemplate(); + + // Make PhotoViewer HTML string to jQuery element + var $photoviewer = $(photoviewerHTML); + + // Get all PhotoViewer elements + this.$photoviewer = $photoviewer; + this.$stage = $photoviewer.find(CLASS_NS + '-stage'); + this.$title = $photoviewer.find(CLASS_NS + '-title'); + this.$image = $photoviewer.find(CLASS_NS + '-image'); + this.$close = $photoviewer.find(CLASS_NS + '-button-close'); + this.$maximize = $photoviewer.find(CLASS_NS + '-button-maximize'); + this.$minimize = $photoviewer.find(CLASS_NS + '-button-minimize'); + this.$zoomIn = $photoviewer.find(CLASS_NS + '-button-zoomIn'); + this.$zoomOut = $photoviewer.find(CLASS_NS + '-button-zoomOut'); + this.$actualSize = $photoviewer.find(CLASS_NS + '-button-actualSize'); + this.$fullscreen = $photoviewer.find(CLASS_NS + '-button-fullscreen'); + this.$rotateLeft = $photoviewer.find(CLASS_NS + '-button-rotateLeft'); + this.$rotateRight = $photoviewer.find(CLASS_NS + '-button-rotateRight'); + this.$prev = $photoviewer.find(CLASS_NS + '-button-prev'); + this.$next = $photoviewer.find(CLASS_NS + '-button-next'); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + + // Reset modal `z-index` of multiple instances + this.$photoviewer.css('z-index', PUBLIC_VARS['zIndex']); + if (this.options.positionFixed) { + this.$photoviewer.css({ + position: 'fixed' + }); + } + + // Set handle element of draggable + if (!this.options.dragHandle || this.options.dragHandle === CLASS_NS + '-modal') { + this.dragHandle = this.$photoviewer; + } else { + this.dragHandle = this.$photoviewer.find(this.options.dragHandle); + } + + // Add PhotoViewer to DOM + $(this.options.appendTo).eq(0).append(this.$photoviewer); + + // Store the edge value of stage + this._stageEdgeValue = { + horizontal: getCSSValueSum(this.$stage, ['left', 'right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$stage, ['top', 'bottom', 'border-top-width', 'border-bottom-width']) + }; + + // Store the edge value of modal + this._modalEdgeValue = { + horizontal: getCSSValueSum(this.$photoviewer, ['padding-left', 'padding-right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$photoviewer, ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width']) + }; + this._addEvents(); + this._addCustomButtonEvents(); + } + }, { + key: "open", + value: function open() { + this._triggerHook('beforeOpen', this); + if (!this.options.multiInstances) { + $(CLASS_NS + '-modal').eq(0).remove(); + } + this.build(); + this.setInitModalPos(); + this._triggerHook('opened', this); + } + }, { + key: "close", + value: function close() { + this._triggerHook('beforeClose', this); + + // Remove PhotoViewer instance + this.$photoviewer.remove(); + this.isOpened = false; + this.isMaximized = false; + this.isRotated = false; + this.rotationDegree = 0; + if (!$(CLASS_NS + '-modal').length) { + // Reset `z-index` after close + if (this.options.multiInstances) { + PUBLIC_VARS['zIndex'] = this.options.zIndex; + } + + // Off resize event + $W.off(RESIZE_EVENT + EVENT_NS); + } + this._triggerHook('closed', this); + } + }, { + key: "_getOffsetParentData", + value: function _getOffsetParentData() { + var offsetParent = $(this.options.appendTo)[0]; + return { + width: this.options.positionFixed || isRootNode(offsetParent) ? $W.width() : offsetParent.clientWidth, + height: this.options.positionFixed || isRootNode(offsetParent) ? $W.height() : offsetParent.clientHeight, + scrollLeft: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollLeft() : offsetParent.scrollLeft, + scrollTop: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollTop() : offsetParent.scrollTop + }; + } + }, { + key: "setModalToCenter", + value: function setModalToCenter() { + var initLeft, initTop, initRight, initBottom; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (!isBorderBox(this.$photoviewer)) { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + if ($.isPlainObject(this.options.initModalPos)) { + initLeft = this.options.initModalPos.left; + initTop = this.options.initModalPos.top; + initRight = this.options.initModalPos.right; + initBottom = this.options.initModalPos.bottom; + } else { + var offsetParentData = this._getOffsetParentData(); + initLeft = (offsetParentData.width - this.options.modalWidth - extraWidth) / 2 + offsetParentData.scrollLeft; + initTop = (offsetParentData.height - this.options.modalHeight - extraHeight) / 2 + offsetParentData.scrollTop; + } + var modalInitCSS = { + width: this.modalData.width || this.options.modalWidth, + height: this.modalData.height || this.options.modalHeight, + left: this.modalData.left || initLeft, + top: this.modalData.top || initTop, + right: this.modalData.right || initRight, + bottom: this.modalData.bottom || initBottom + }; + this.$photoviewer.css(modalInitCSS); + } + }, { + key: "setInitModalPos", + value: function setInitModalPos() { + if (this.options.initMaximized) { + this.maximize(); + this.isOpened = true; + } else { + this.setModalToCenter(); + } + + // The focus must be set after opening + this.$photoviewer[0].focus(); + } + }, { + key: "setModalSize", + value: function setModalSize(img) { + var _this2 = this; + var offsetParentData = this._getOffsetParentData(); + + // Modal size should calculate with stage css value + var modalWidth = img.width + this._stageEdgeValue.horizontal; + var modalHeight = img.height + this._stageEdgeValue.vertical; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (isBorderBox(this.$photoviewer)) { + modalWidth += this._modalEdgeValue.horizontal; + modalHeight += this._modalEdgeValue.vertical; + } else { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + var gapThreshold = (this.options.gapThreshold > 0 ? this.options.gapThreshold : 0) + 1; + + // Modal scale relative to parent element + var scale = Math.min(offsetParentData.width / ((modalWidth + extraWidth) * gapThreshold), offsetParentData.height / ((modalHeight + extraHeight) * gapThreshold), 1); + var minWidth = Math.max(modalWidth * scale, this.options.modalWidth); + var minHeight = Math.max(modalHeight * scale, this.options.modalHeight); + minWidth = this.options.fixedModalSize ? this.options.modalWidth : Math.round(minWidth); + minHeight = this.options.fixedModalSize ? this.options.modalHeight : Math.round(minHeight); + var transLeft, transTop, transRight, transBottom; + if ($.isPlainObject(this.options.initModalPos)) { + transLeft = this.options.initModalPos.left; + transTop = this.options.initModalPos.top; + transRight = this.options.initModalPos.right; + transBottom = this.options.initModalPos.bottom; + } else { + var _offsetParentData = this._getOffsetParentData(); + transLeft = (_offsetParentData.width - minWidth - extraWidth) / 2 + _offsetParentData.scrollLeft; + transTop = (_offsetParentData.height - minHeight - extraHeight) / 2 + _offsetParentData.scrollTop; + } + var modalTransCSS = { + width: minWidth, + height: minHeight, + left: transLeft, + top: transTop, + right: transRight, + bottom: transBottom + }; + + // Add init animation for modal + if (this.options.initAnimation) { + this.$photoviewer.animate(modalTransCSS, this.options.animationDuration, 'ease-in-out', function () { + _this2.setImageSize(img); + }); + } else { + this.$photoviewer.css(modalTransCSS); + this.setImageSize(img); + } + this.isOpened = true; + } + }, { + key: "getImageScale", + value: function getImageScale(stageWidth, stageHeight) { + var scale = 1; + if (!this.isRotated) { + scale = Math.min(stageWidth / this.img.width, stageHeight / this.img.height, 1); + } else { + scale = Math.min(stageWidth / this.img.height, stageHeight / this.img.width, 1); + } + return scale; + } + }, { + key: "setImageSize", + value: function setImageSize(img) { + var stageData = { + w: this.$stage.width(), + h: this.$stage.height() + }; + var scale = this.getImageScale(stageData.w, stageData.h); + this.$image.css({ + width: Math.round(img.width * scale), + height: Math.round(img.height * scale), + left: (stageData.w - Math.round(img.width * scale)) / 2, + top: (stageData.h - Math.round(img.height * scale)) / 2 + }); + + // Store image initial data + $.extend(this.imageData, { + initWidth: img.width * scale, + initHeight: img.height * scale, + initLeft: (stageData.w - img.width * scale) / 2, + initTop: (stageData.h - img.height * scale) / 2, + width: img.width * scale, + height: img.height * scale, + left: (stageData.w - img.width * scale) / 2, + top: (stageData.h - img.height * scale) / 2 + }); + + // Set grab cursor + setGrabCursor({ + w: this.$image.width(), + h: this.$image.height() + }, { + w: this.$stage.width(), + h: this.$stage.height() + }, this.$stage, this.isRotated); + + // Just execute before image loaded + if (!this.imageLoaded) { + // Loader end + this.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Remove class after image loaded + this.$stage.removeClass('stage-ready'); + this.$image.removeClass('image-ready'); + + // Add init animation for image + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.fadeIn(); + } + this.imageLoaded = true; + } + } + }, { + key: "loadImage", + value: function loadImage(imgSrc, fn, err) { + var _this3 = this; + // Reset image + this.$image.removeAttr('style').attr('src', ''); + this.isRotated = false; + this.rotationDegree = 0; + this.imageLoaded = false; + + // Loader start + this.$photoviewer.append("")); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.hide(); + } + this.$image.attr('src', imgSrc); + preloadImage(imgSrc, function (img) { + // Store HTMLImageElement + _this3.img = img; + + // Store original data + _this3.imageData = { + originalWidth: img.width, + originalHeight: img.height + }; + if (_this3.isMaximized || _this3.isOpened && _this3.options.fixedModalPos) { + _this3.setImageSize(img); + } else { + _this3.setModalSize(img); + } + + // Callback of image loaded successfully + if (fn) { + fn.call(); + } + }, function () { + // Loader end + _this3.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Callback of image loading failed + if (err) { + err.call(); + } + }); + if (this.options.title) { + this.setImageTitle(imgSrc); + } + } + }, { + key: "setImageTitle", + value: function setImageTitle(url) { + var title = this.groupData[this.groupIndex].title || getImageNameFromUrl(url); + this.$title.html(title); + } + }, { + key: "jump", + value: function jump(step) { + this._triggerHook('beforeChange', [this, this.groupIndex]); + + // Make sure change image after the modal animation has finished + var now = Date.now(); + if (now - this._lastTimestamp >= this.options.animationDuration) { + this.groupIndex = this.groupIndex + step; + this.jumpTo(this.groupIndex); + this._lastTimestamp = now; + } + } + }, { + key: "jumpTo", + value: function jumpTo(index) { + var _this4 = this; + index = index % this.groupData.length; + if (index >= 0) { + index = index % this.groupData.length; + } else if (index < 0) { + index = (this.groupData.length + index) % this.groupData.length; + } + this.groupIndex = index; + this.loadImage(this.groupData[index].src, function () { + _this4._triggerHook('changed', [_this4, index]); + }, function () { + _this4._triggerHook('changed', [_this4, index]); + }); + } + }, { + key: "wheel", + value: function wheel(e) { + e.preventDefault(); + var delta = 1; + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + // Ratio threshold + var ratio = -delta * this.options.ratioThreshold; + + // Mouse point position relative to stage + var pointer = { + x: e.clientX - this.$stage.offset().left + $D.scrollLeft(), + y: e.clientY - this.$stage.offset().top + $D.scrollTop() + }; + this.zoom(ratio, pointer); + } + }, { + key: "zoom", + value: function zoom(ratio, origin) { + // Zoom out ratio & Zoom in ratio + ratio = ratio < 0 ? 1 / (1 - ratio) : 1 + ratio; + + // Image ratio + ratio = this.$image.width() / this.imageData.originalWidth * ratio; + if (ratio > this.options.maxRatio || ratio < this.options.minRatio) { + return; + } + this.zoomTo(ratio, origin); + } + }, { + key: "zoomTo", + value: function zoomTo(ratio, origin) { + var $image = this.$image; + var $stage = this.$stage; + var imgData = { + w: this.imageData.width, + h: this.imageData.height, + x: this.imageData.left, + y: this.imageData.top + }; + + // Image stage position + // We will use it to calc the relative position of image + var stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.offset().left, + y: $stage.offset().top + }; + + // Set default origin coordinates (center of stage) + if (origin === void 0) { + origin = { + x: $stage.width() / 2, + y: $stage.height() / 2 + }; + } + var newWidth = this.imageData.originalWidth * ratio; + var newHeight = this.imageData.originalHeight * ratio; + // Think about it for a while + var newLeft = origin.x - (origin.x - imgData.x) / imgData.w * newWidth; + var newTop = origin.y - (origin.y - imgData.y) / imgData.h * newHeight; + + // δ is the difference between image new width and new height + var δ = !this.isRotated ? 0 : (newWidth - newHeight) / 2; + var imgNewWidth = !this.isRotated ? newWidth : newHeight; + var imgNewHeight = !this.isRotated ? newHeight : newWidth; + var offsetX = stageData.w - newWidth; + var offsetY = stageData.h - newHeight; + + // Zoom out & Zoom in condition + // It's important and it takes me a lot of time to get it + // The conditions with image rotate 90 degree drive me crazy alomst! + if (imgNewHeight <= stageData.h) { + newTop = (stageData.h - newHeight) / 2; + } else { + newTop = newTop > δ ? δ : newTop > offsetY - δ ? newTop : offsetY - δ; + } + if (imgNewWidth <= stageData.w) { + newLeft = (stageData.w - newWidth) / 2; + } else { + newLeft = newLeft > -δ ? -δ : newLeft > offsetX + δ ? newLeft : offsetX + δ; + } + + // Whether the image scale get to the critical point + if (Math.abs(this.imageData.initWidth - newWidth) < this.imageData.initWidth * 0.05) { + this.setImageSize(this.img); + } else { + $image.css({ + width: Math.round(newWidth), + height: Math.round(newHeight), + left: Math.round(newLeft), + top: Math.round(newTop) + }); + + // Set grab cursor + setGrabCursor({ + w: Math.round(imgNewWidth), + h: Math.round(imgNewHeight) + }, { + w: stageData.w, + h: stageData.h + }, this.$stage); + } + + // Update image initial data + $.extend(this.imageData, { + width: newWidth, + height: newHeight, + left: newLeft, + top: newTop + }); + } + }, { + key: "rotate", + value: function rotate(degree) { + this.rotationDegree = this.rotationDegree + degree; + if (this.rotationDegree / 90 % 2 === 0) { + this.isRotated = false; + } else { + this.isRotated = true; + } + this.rotateTo(this.rotationDegree); + } + }, { + key: "rotateTo", + value: function rotateTo(degree) { + this.$image.css({ + transform: 'rotate(' + degree + 'deg)' + }); + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + + // Remove grab cursor when rotate + this.$stage.removeClass('is-grab'); + } + }, { + key: "resize", + value: function resize() { + if (this.isOpened) { + if (this.isMaximized) { + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } else { + this.setModalSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } + } + } + }, { + key: "maximize", + value: function maximize() { + this.$photoviewer.addClass(NS + '-maximized'); + this.$photoviewer.css({ + width: 'auto', + height: 'auto', + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + this.isMaximized = true; + } + }, { + key: "exitMaximize", + value: function exitMaximize() { + this.$photoviewer.removeClass(NS + '-maximized'); + this.setModalToCenter(); + this.isMaximized = false; + } + }, { + key: "toggleMaximize", + value: function toggleMaximize() { + if (!this.isMaximized) { + var originalWidth = this.$photoviewer.width(); + var originalHeight = this.$photoviewer.height(); + if (isBorderBox(this.$photoviewer)) { + originalWidth += this._modalEdgeValue.horizontal; + originalHeight += this._modalEdgeValue.vertical; + } + + // Store modal's size and position before maximized + this.modalData = { + width: originalWidth, + height: originalHeight, + left: parseFloat(this.$photoviewer.css('left')), + top: parseFloat(this.$photoviewer.css('top')) + }; + this.maximize(); + } else { + this.exitMaximize(); + } + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + this.$photoviewer[0].focus(); + } + }, { + key: "fullscreen", + value: function fullscreen() { + requestFullscreen(this.$photoviewer[0]); + this.$photoviewer[0].focus(); + } + }, { + key: "_keydown", + value: function _keydown(e) { + if (!this.options.keyboard) { + return false; + } + e.preventDefault(); + var keyCode = e.keyCode || e.which || e.charCode; + var ctrlKey = e.ctrlKey || e.metaKey; + var altKey = e.altKey; + switch (keyCode) { + // ← + case 37: + this.jump(-1); + break; + // → + case 39: + this.jump(1); + break; + // + + case 187: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - + case 189: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // + Firefox + case 61: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - Firefox + case 173: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // Ctrl + Alt + 0 + case 48: + if (ctrlKey && altKey) { + this.zoomTo(1, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + } + break; + // Ctrl + , + case 188: + if (ctrlKey) { + this.rotate(-90); + } + break; + // Ctrl + . + case 190: + if (ctrlKey) { + this.rotate(90); + } + break; + // Q + case 81: + this.close(); + break; + // Alt + X + case 88: + if (altKey) { + this.toggleMaximize(); + } + break; + // F + case 70: + this.fullscreen(); + break; + } + } + }, { + key: "_addEvents", + value: function _addEvents() { + var _this5 = this; + this.$close.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.close(); + }); + this.$stage.off(WHEEL_EVENT + EVENT_NS).on(WHEEL_EVENT + EVENT_NS, function (e) { + _this5.wheel(e); + }); + this.$zoomIn.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(_this5.options.ratioThreshold * 3); + }); + this.$zoomOut.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(-_this5.options.ratioThreshold * 3); + }); + this.$actualSize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoomTo(1); + }); + this.$prev.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(-1); + }); + this.$fullscreen.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.fullscreen(); + }); + this.$next.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(1); + }); + this.$rotateLeft.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(-90); + }); + this.$rotateRight.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(90); + }); + this.$maximize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.toggleMaximize(); + }); + this.$photoviewer.off(KEYDOWN_EVENT + EVENT_NS).on(KEYDOWN_EVENT + EVENT_NS, function (e) { + _this5._keydown(e); + }); + $W.on(RESIZE_EVENT + EVENT_NS, debounce(function () { + return _this5.resize(); + }, 500)); + } + }, { + key: "_addCustomButtonEvents", + value: function _addCustomButtonEvents() { + var _this6 = this; + var _loop = function _loop(btnKey) { + _this6.$photoviewer.find(CLASS_NS + '-button-' + btnKey).off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function (e) { + _this6.options.customButtons[btnKey].click.apply(_this6, [_this6, e]); + }); + }; + for (var btnKey in this.options.customButtons) { + _loop(btnKey); + } + } + }, { + key: "_triggerHook", + value: function _triggerHook(e, data) { + if (this.options.callbacks[e]) { + this.options.callbacks[e].apply(this, $.isArray(data) ? data : [data]); + } + } + }]); + return PhotoViewer; +}(); +/** + * Add methods to PhotoViewer + */ +$.extend(PhotoViewer.prototype, draggable, movable, resizable); + +/** + * Add PhotoViewer to globle + */ +window.PhotoViewer = PhotoViewer; + +module.exports = PhotoViewer; diff --git a/WebRoot/html/ypzs/view/js/photoviewer.css b/WebRoot/html/ypzs/view/js/photoviewer.css new file mode 100644 index 0000000..cfafab6 --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.css @@ -0,0 +1,498 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ + +.photoviewer-modal { + position: absolute; + z-index: 1090; + width: 320px; + height: 320px; + overflow: visible !important; + color: #333; + cursor: default; + background-color: rgba(255, 255, 255, 0.92); + border: 1px solid rgba(0, 0, 0, 0.64); + border-radius: 6px; + outline: none; + box-shadow: 0 2px 10px 2px rgba(0, 0, 0, 0.32); +} + +.photoviewer-inner { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.photoviewer-maximized { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: auto; + height: auto; +} +.photoviewer-maximized.photoviewer-modal { + border-width: 0; + border-radius: 0; +} +.photoviewer-maximized .photoviewer-header { + border-radius: 0; +} +.photoviewer-maximized .photoviewer-resizable-handle { + display: none; +} + +.photoviewer-toolbar { + font-size: 0; +} + +.photoviewer-button { + display: inline-block; + min-width: 40px; + height: 40px; + box-sizing: border-box; + margin: 0; + font-size: 16px; + line-height: 1; + text-align: center; + background: none; + border-width: 0; + border-radius: 0; + color: inherit; + cursor: pointer; + outline: none; +} +.photoviewer-button:hover { + color: #111; +} +.photoviewer-button:focus { + background-color: rgba(0, 0, 0, 0.08); +} +.photoviewer-button svg { + display: inline-block; + font-size: inherit; + width: 1em; + height: 1em; + overflow: visible; + vertical-align: -0.125em; +} + +.photoviewer-header { + position: relative; + z-index: 2; + height: 30px; + border-radius: 5px 5px 0 0; + overflow: hidden; +} +.photoviewer-header .photoviewer-toolbar { + float: right; +} +[dir=rtl] .photoviewer-header .photoviewer-toolbar { + float: left; +} +.photoviewer-header .photoviewer-button { + height: 30px; +} +.photoviewer-header .photoviewer-button:hover { + background-color: rgba(0, 0, 0, 0.08); +} +.photoviewer-header .photoviewer-button-close:hover { + color: #fff; + background-color: #ff4545; +} + +.photoviewer-title { + padding: 8px 10px; + font-size: 14px; + line-height: 1; + white-space: nowrap; + text-overflow: ellipsis; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + overflow: hidden; +} + +.photoviewer-stage { + position: absolute; + top: 30px; + right: 0; + bottom: 40px; + left: 0; + z-index: 1; + border-top: 1px solid rgba(0, 0, 0, 0.64); + border-bottom: 1px solid rgba(0, 0, 0, 0.64); + background-color: #fff; + overflow: hidden; +} +.photoviewer-stage.stage-ready { + text-align: center; + font-size: 0; +} +.photoviewer-stage.stage-ready::before { + content: ""; + display: inline-block; + height: 100%; + vertical-align: middle; + overflow: hidden; +} + +.photoviewer-image { + position: absolute; + display: inline-block; + min-width: auto; + max-width: none; +} +.photoviewer-image.image-ready { + position: static; + max-width: 100%; + max-height: 100%; + vertical-align: middle; +} + +.photoviewer-footer { + position: absolute; + bottom: 0; + z-index: 2; + width: 100%; + height: 40px; + text-align: center; +} +.photoviewer-footer .photoviewer-toolbar { + display: inline-block; +} + +[dir=rtl] .photoviewer-button-prev, +[dir=rtl] .photoviewer-button-next { + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} + +.photoviewer-resizable-handle { + position: absolute; + z-index: 10; +} + +.photoviewer-resizable-handle-e { + top: 0; + right: -5px; + bottom: 0; + left: auto; + width: 10px; + cursor: e-resize; +} + +.photoviewer-resizable-handle-s { + top: auto; + right: 0; + bottom: -5px; + left: 0; + height: 10px; + cursor: s-resize; +} + +.photoviewer-resizable-handle-w { + top: 0; + right: auto; + bottom: 0; + left: -5px; + width: 10px; + cursor: w-resize; +} + +.photoviewer-resizable-handle-n { + top: -5px; + right: 0; + bottom: auto; + left: 0; + height: 10px; + cursor: n-resize; +} + +.photoviewer-resizable-handle-se { + top: auto; + right: -5px; + bottom: -5px; + left: auto; + width: 10px; + height: 10px; + cursor: se-resize; +} + +.photoviewer-resizable-handle-sw { + top: auto; + right: auto; + bottom: -5px; + left: -5px; + width: 10px; + height: 10px; + cursor: sw-resize; +} + +.photoviewer-resizable-handle-nw { + top: -5px; + right: auto; + bottom: auto; + left: -5px; + width: 10px; + height: 10px; + cursor: nw-resize; +} + +.photoviewer-resizable-handle-ne { + top: -5px; + right: -5px; + bottom: auto; + left: auto; + width: 10px; + height: 10px; + cursor: ne-resize; +} + +:-webkit-full-screen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} +:-webkit-full-screen .photoviewer-header, +:-webkit-full-screen .photoviewer-footer, +:-webkit-full-screen .photoviewer-resizable-handle { + display: none; +} +:-webkit-full-screen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} + +:-moz-full-screen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} +:-moz-full-screen .photoviewer-header, +:-moz-full-screen .photoviewer-footer, +:-moz-full-screen .photoviewer-resizable-handle { + display: none; +} +:-moz-full-screen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} + +:-ms-fullscreen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} +:-ms-fullscreen .photoviewer-header, +:-ms-fullscreen .photoviewer-footer, +:-ms-fullscreen .photoviewer-resizable-handle { + display: none; +} +:-ms-fullscreen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} + +:full-screen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} +:full-screen .photoviewer-header, +:full-screen .photoviewer-footer, +:full-screen .photoviewer-resizable-handle { + display: none; +} +:full-screen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} + +:-webkit-full-screen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} + +:-ms-fullscreen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} + +:fullscreen { + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + background-color: transparent; + border-width: 0; + border-radius: 0; +} +:-webkit-full-screen .photoviewer-header, :-webkit-full-screen .photoviewer-footer, :-webkit-full-screen .photoviewer-resizable-handle { + display: none; +} +:-ms-fullscreen .photoviewer-header, :-ms-fullscreen .photoviewer-footer, :-ms-fullscreen .photoviewer-resizable-handle { + display: none; +} +:fullscreen .photoviewer-header, +:fullscreen .photoviewer-footer, +:fullscreen .photoviewer-resizable-handle { + display: none; +} +:-webkit-full-screen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} +:-ms-fullscreen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} +:fullscreen .photoviewer-stage { + top: 0; + right: 0; + bottom: 0; + left: 0; + border-width: 0; + background-color: black; +} + +::backdrop { + background-color: black; +} + +::-ms-backdrop { + background-color: black; +} + +.is-grab { + cursor: move; + cursor: grab; +} + +.is-grabbing { + cursor: move; + cursor: grabbing; +} + +.photoviewer-loader { + position: absolute; + top: 30px; + left: 0; + right: 0; + bottom: 40px; + z-index: 2; + text-align: center; + color: #333; +} +.photoviewer-loader::before { + content: ""; + position: relative; + display: inline-block; + width: 36px; + height: 36px; + box-sizing: border-box; + border-width: 5px; + border-style: solid; + border-color: rgba(0, 0, 0, 0.5) rgba(0, 0, 0, 0.5) rgba(0, 0, 0, 0.5) rgba(255, 255, 255, 0.5); + border-radius: 100%; + vertical-align: middle; + animation: photoviewerLoading 1s infinite linear; +} +.photoviewer-loader::after { + content: ""; + display: inline-block; + width: 0; + height: 100%; + vertical-align: middle; + overflow: hidden; +} + +@keyframes photoviewerLoading { + 0% { + transform: rotateZ(0deg) translate3d(0, 0, 0); + } + 100% { + transform: rotateZ(360deg) translate3d(0, 0, 0); + } +} + +/*# sourceMappingURL=photoviewer.css.map */ \ No newline at end of file diff --git a/WebRoot/html/ypzs/view/js/photoviewer.css.map b/WebRoot/html/ypzs/view/js/photoviewer.css.map new file mode 100644 index 0000000..3b1f244 --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["","../src/sass/_general.scss","photoviewer.css","../src/sass/_resizable.scss","../src/sass/_fullscreen.scss","../src/sass/_helpers.scss","../src/sass/_loader.scss"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAAA;;ACAA;EACE,kBAAA;EACA,aAAA;EACA,YAAA;EACA,aAAA;EACA,4BAAA;EACA,WAAA;EACA,eAAA;EACA,2CAAA;EACA,qCAAA;EACA,kBAAA;EACA,aAAA;EACA,8CAAA;ACCF;;ADEA;EACE,kBAAA;EACA,MAAA;EACA,OAAA;EACA,QAAA;EACA,SAAA;ACCF;;ADEA;EACE,eAAA;EACA,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,WAAA;EACA,YAAA;ACCF;ADCE;EACE,eAAA;EACA,gBAAA;ACCJ;ADEE;EACE,gBAAA;ACAJ;ADGE;EACE,aAAA;ACDJ;;ADKA;EACE,YAAA;ACFF;;ADKA;EACE,qBAAA;EACA,eAAA;EACA,YAAA;EACA,sBAAA;EACA,SAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,gBAAA;EACA,eAAA;EACA,gBAAA;EACA,cAAA;EACA,eAAA;EACA,aAAA;ACFF;ADIE;EACE,WAAA;ACFJ;ADKE;EACE,qCAAA;ACHJ;ADME;EACE,qBAAA;EACA,kBAAA;EACA,UAAA;EACA,WAAA;EACA,iBAAA;EACA,wBAAA;ACJJ;;ADQA;EACE,kBAAA;EACA,UAAA;EACA,YAAA;EACA,0BAAA;EACA,gBAAA;ACLF;ADOE;EACE,YAAA;ACLJ;ADOI;EACE,WAAA;ACLN;ADSE;EACE,YAAA;ACPJ;ADSI;EACE,qCAAA;ACPN;ADYI;EACE,WAAA;EACA,yBAAA;ACVN;;ADeA;EACE,iBAAA;EACA,eAAA;EACA,cAAA;EACA,mBAAA;EACA,uBAAA;EACA,yBAAA;EAAA,sBAAA;EAAA,qBAAA;EAAA,iBAAA;EACA,gBAAA;ACZF;;ADeA;EACE,kBAAA;EACA,SAAA;EACA,QAAA;EACA,YAAA;EACA,OAAA;EACA,UAAA;EACA,yCAAA;EACA,4CAAA;EACA,sBAAA;EACA,gBAAA;ACZF;ADcE;EACE,kBAAA;EACA,YAAA;ACZJ;ADcI;EACE,WAAA;EACA,qBAAA;EACA,YAAA;EACA,sBAAA;EACA,gBAAA;ACZN;;ADiBA;EACE,kBAAA;EACA,qBAAA;EACA,eAAA;EACA,eAAA;ACdF;ADgBE;EACE,gBAAA;EACA,eAAA;EACA,gBAAA;EACA,sBAAA;ACdJ;;ADkBA;EACE,kBAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,kBAAA;ACfF;ADiBE;EACE,qBAAA;ACfJ;;ADoBE;;EAEE,yBAAA;ACjBJ;;ACpKA;EACE,kBAAA;EACA,WAAA;ADuKF;;ACpKA;EACE,MAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,gBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,QAAA;EACA,YAAA;EACA,OAAA;EACA,YAAA;EACA,gBAAA;ADuKF;;ACpKA;EACE,MAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,gBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,QAAA;EACA,YAAA;EACA,OAAA;EACA,YAAA;EACA,gBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;ADuKF;;ACpKA;EACE,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,iBAAA;ADuKF;;AEjPE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AFoPJ;AElPI;;;EAGE,aAAA;AFoPN;AEjPI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AFmPN;;AE1QE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AF6QJ;AE3QI;;;EAGE,aAAA;AF6QN;AE1QI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AF4QN;;AEnSE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AFsSJ;AEpSI;;;EAGE,aAAA;AFsSN;AEnSI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AFqSN;;AE5TE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AF+TJ;AE7TI;;;EAGE,aAAA;AF+TN;AE5TI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AF8TN;;AErVE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AFwVJ;;AEjWE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AFwVJ;;AEjWE;EACE,iBAAA;EACA,mBAAA;EACA,oBAAA;EACA,kBAAA;EACA,sBAAA;EACA,uBAAA;EACA,6BAAA;EACA,eAAA;EACA,gBAAA;AFwVJ;AEtVI;EAGE,aAAA;AFwVN;AE3VI;EAGE,aAAA;AFwVN;AE3VI;;;EAGE,aAAA;AFwVN;AErVI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AFuVN;AE7VI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AFuVN;AE7VI;EACE,MAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,eAAA;EACA,uBAAA;AFuVN;;AEjVE;EACE,uBAAA;AFoVJ;;AErVE;EACE,uBAAA;AFwVJ;;AG1XA;EACE,YAAA;EAEA,YAAA;AH6XF;;AG1XA;EACE,YAAA;EAEA,gBAAA;AH6XF;;AItYA;EACE,kBAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,YAAA;EACA,UAAA;EACA,kBAAA;EACA,WAAA;AJyYF;AIvYE;EACE,WAAA;EACA,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,YAAA;EACA,sBAAA;EACA,iBAAA;EACA,mBAAA;EACA,+FAAA;EACA,mBAAA;EACA,sBAAA;EACA,gDAAA;AJyYJ;AItYE;EACE,WAAA;EACA,qBAAA;EACA,QAAA;EACA,YAAA;EACA,sBAAA;EACA,gBAAA;AJwYJ;;AIpYA;EACE;IACE,6CAAA;EJuYF;EIpYA;IACE,+CAAA;EJsYF;AACF","file":"photoviewer.css"} \ No newline at end of file diff --git a/WebRoot/html/ypzs/view/js/photoviewer.esm.js b/WebRoot/html/ypzs/view/js/photoviewer.esm.js new file mode 100644 index 0000000..f8960f3 --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.esm.js @@ -0,0 +1,2749 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } +} +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; +} +function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); +} +function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); +} + +// Class D +var D = function (selector, context) { + return new D.fn.init(selector, context); +}; + +var document$1 = window.document, + emptyArray = [], + concat = emptyArray.concat, + filter = emptyArray.filter, + slice = emptyArray.slice, + elementDisplay = {}, + classCache = {}, + cssNumber = { + 'column-count': 1, + 'columns': 1, + 'font-weight': 1, + 'line-height': 1, + 'opacity': 1, + 'z-index': 1, + 'zoom': 1 + }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + table = document$1.createElement('table'), + tableRow = document$1.createElement('tr'), + containers = { + 'tr': document$1.createElement('tbody'), + 'tbody': table, + 'thead': table, + 'tfoot': table, + 'td': tableRow, + 'th': tableRow, + '*': document$1.createElement('div') + }, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + tempParent = document$1.createElement('div'), + isArray = Array.isArray || function (arg) { + return Object.prototype.toString.call(arg) === '[object Array]'; + }, + contains = document$1.documentElement.contains + ? function (parent, node) { + return parent !== node && parent.contains(node); + } + : function (parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true; + return false; + }; + +function type(obj) { + return obj == null + ? String(obj) + : class2type[toString.call(obj)] || 'object'; +} + +function isFunction(value) { + return type(value) == 'function'; +} + +function isWindow(obj) { + return obj != null && obj == obj.window; +} + +function isDocument(obj) { + return obj != null && obj.nodeType == obj.DOCUMENT_NODE; +} + +function isObject(obj) { + return type(obj) == 'object'; +} + +function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype; +} + +function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + typeRes = type(obj); + + return 'function' != typeRes && !isWindow(obj) && ( + 'array' == typeRes || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ); +} + +function compact(array) { + return filter.call(array, function (item) { + return item != null; + }); +} + +function dasherize$1(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase(); +} + +function maybeAddPx(name, value) { + return (typeof value == 'number' && !cssNumber[dasherize$1(name)]) ? value + 'px' : value; +} + +function camelize(str) { + return str.replace(/-+(.)?/g, function (match, chr) { + return chr ? chr.toUpperCase() : ''; + }); +} + +function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')); +} + +function defaultDisplay(nodeName) { + var element, display; + if (!elementDisplay[nodeName]) { + element = document$1.createElement(nodeName); + document$1.body.appendChild(element); + display = getComputedStyle(element, '').getPropertyValue('display'); + element.parentNode.removeChild(element); + display == 'none' && (display = 'block'); + elementDisplay[nodeName] = display; + } + return elementDisplay[nodeName]; +} + +function flatten(array) { + return array.length > 0 ? D.fn.concat.apply([], array) : array; +} + +function isD(object) { + return object instanceof D; +} + +function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg; +} + +function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value); +} + +// access className property while respecting SVGAnimatedString +function className(node, value) { + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined; + + if (value === undefined) return svg ? klass.baseVal : klass; + svg ? (klass.baseVal = value) : (node.className = value); +} + +D.fn = D.prototype = { + constuctor: D, + length: 0, + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + // D's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + init: function (selector, context) { + var dom; + // If nothing given, return an empty D collection + if (!selector) { + return this; + } + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim(); + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) { + dom = D.fragment(selector, RegExp.$1, context); + selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // If it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) { + return D(document$1).ready(selector); + } + // If a D collection is given, just return it + else if (isD(selector)) { + return selector; + } + // normalize array if an array of nodes is given + else if (isArray(selector)) { + dom = compact(selector); + } + // Wrap DOM nodes. + else if (isObject(selector)) { + dom = [selector], selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // And last but no least, if it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + // create a new D collection from the nodes found + return D.makeArray(dom, selector, this); + }, + // Modify the collection by adding elements to it + concat: function () { + var i, value, args = []; + for (i = 0; i < arguments.length; i++) { + value = arguments[i]; + args[i] = isD(value) ? value.toArray() : value; + } + return concat.apply(isD(this) ? this.toArray() : this, args); + }, + // `pluck` is borrowed from Prototype.js + pluck: function (property) { + return D.map(this, function (el) { return el[property]; }); + }, + toArray: function () { + return this.get(); + }, + get: function (idx) { + return idx === undefined + ? slice.call(this) + : this[idx >= 0 ? idx : idx + this.length]; + }, + size: function () { + return this.length; + }, + each: function (callback) { + emptyArray.every.call(this, function (el, idx) { + return callback.call(el, idx, el) !== false; + }); + return this; + }, + map: function (fn) { + return D(D.map(this, function (el, i) { return fn.call(el, i, el); })); + }, + slice: function () { + return D(slice.apply(this, arguments)); + }, + first: function () { + var el = this[0]; + return el && !isObject(el) ? el : D(el); + }, + last: function () { + var el = this[this.length - 1]; + return el && !isObject(el) ? el : D(el); + }, + eq: function (idx) { + return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1); + } +}; + +D.extend = D.fn.extend = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === 'boolean') { + deep = target; + + // Skip the boolean and the target + target = arguments[i] || {}; + i++; + } + // Handle case when target is a string or something (possible in deep copy) + if (typeof target !== 'object' && !isFunction(target)) { + target = {}; + } + // Extend D itself if only one argument is passed + if (i === length) { + target = this; + i--; + } + for (; i < length; i++) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + src = target[name]; + copy = options[name]; + // Prevent never-ending loop + if (target === copy) { + continue; + } + // Recurse if we're merging plain objects or arrays + if (deep && copy && (isPlainObject(copy) || + (copyIsArray = isArray(copy)))) { + if (copyIsArray) { + copyIsArray = false; + clone = src && isArray(src) ? src : []; + } else { + clone = src && isPlainObject(src) ? src : {}; + } + // Never move original objects, clone them + target[name] = D.extend(deep, clone, copy); + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; + } + } + } + } + // Return the modified object + return target; +}; + +D.extend({ + // Make DOM Array + makeArray: function (dom, selector, me) { + var i, len = dom ? dom.length : 0; + for (i = 0; i < len; i++) me[i] = dom[i]; + me.length = len; + me.selector = selector || ''; + return me; + }, + // D's CSS selector + qsa: function (element, selector) { + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + // Ensure that a 1 char tag name still gets checked + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, + isSimple = simpleSelectorRE.test(nameOnly); + return ( + // Safari DocumentFragment doesn't have getElementById + element.getElementById && isSimple && maybeID) + // eslint-disable-next-line no-cond-assign + ? (found = element.getElementById(nameOnly)) + ? [found] + : [] + : element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11 + ? [] + : slice.call( + // DocumentFragment doesn't have getElementsByClassName/TagName + isSimple && !maybeID && element.getElementsByClassName + ? maybeClass + // If it's simple, it could be a class + ? element.getElementsByClassName(nameOnly) + // Or a tag + : element.getElementsByTagName(selector) + // Or it's not simple, and we need to query all + : element.querySelectorAll(selector) + ); + }, + // Html -> Node + fragment: function (html, name, properties) { + var dom, nodes, container; + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = D(document$1.createElement(RegExp.$1)); + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, '<$1>$2>'); + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1; + if (!(name in containers)) name = '*'; + + container = containers[name]; + container.innerHTML = '' + html; + dom = D.each(slice.call(container.childNodes), function () { + container.removeChild(this); + }); + } + + if (isPlainObject(properties)) { + nodes = D(dom); + D.each(properties, function (key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value); + else nodes.attr(key, value); + }); + } + + return dom; + }, + matches: function (element, selector) { + if (!selector || !element || element.nodeType !== 1) return false; + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector; + if (matchesSelector) return matchesSelector.call(element, selector); + // fall back to performing a selector: + var match, parent = element.parentNode, + temp = !parent; + if (temp) (parent = tempParent).appendChild(element); + match = ~D.qsa(parent, selector).indexOf(element); + temp && tempParent.removeChild(element); + return match; + }, + each: function (elements, callback) { + var i, key; + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements; + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements; + } + + return elements; + }, + map: function (elements, callback) { + var value, values = [], + i, key; + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i); + if (value != null) values.push(value); + } + else + for (key in elements) { + value = callback(elements[key], key); + if (value != null) values.push(value); + } + return flatten(values); + } +}); + +// Populate the class2type map +D.each('Boolean Number String Function Array Date RegExp Object Error'.split(' '), function (i, name) { + class2type['[object ' + name + ']'] = name.toLowerCase(); +}); + +D.fn.init.prototype = D.fn; + +function noop() { +} + +function css(property, value) { + if (arguments.length < 2) { + var element = this[0]; + if (typeof property == 'string') { + if (!element) return; + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property); + } else if (isArray(property)) { + if (!element) return; + var props = {}; + var computedStyle = getComputedStyle(element, ''); + D.each(property, function (_, prop) { + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)); + }); + return props; + } + } + + var css = ''; + if (type(property) == 'string') { + if (!value && value !== 0) { + this.each(function () { + this.style.removeProperty(dasherize$1(property)); + }); + } else { + css = dasherize$1(property) + ':' + maybeAddPx(property, value); + } + } else { + for (var key in property) { + if (!property[key] && property[key] !== 0) { + this.each(function () { this.style.removeProperty(dasherize$1(key)); }); + } else { + css += dasherize$1(key) + ':' + maybeAddPx(key, property[key]) + ';'; + } + } + } + + return this.each(function () { this.style.cssText += ';' + css; }); +} + +function hasClass(name) { + if (!name) return false; + return emptyArray.some.call(this, function (el) { + return this.test(className(el)); + }, classRE(name)); +} + +function addClass(name) { + var classList = []; + if (!name) return this; + return this.each(function (idx) { + if (!('className' in this)) return; + classList = []; + var cls = className(this), + newName = funcArg(this, name, idx, cls); + newName.split(/\s+/g).forEach(function (klass) { + if (!D(this).hasClass(klass)) classList.push(klass); + }, this); + classList.length && className(this, cls + (cls ? ' ' : '') + classList.join(' ')); + }); +} + +function removeClass(name) { + var classList = []; + return this.each(function (idx) { + if (!('className' in this)) return; + if (name === undefined) return className(this, ''); + classList = className(this); + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function (klass) { + classList = classList.replace(classRE(klass), ' '); + }); + className(this, classList.trim()); + }); +} + +function offset(coordinates) { + if (coordinates) return this.each(function (index) { + var $this = D(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + }; + + if ($this.css('position') == 'static') props['position'] = 'relative'; + $this.css(props); + }); + if (!this.length) return null; + if (document$1.documentElement !== this[0] && !contains(document$1.documentElement, this[0])) + return { top: 0, left: 0 }; + var obj = this[0].getBoundingClientRect(); + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + }; +} + +function position() { + if (!this.length) return; + + var elem = this[0], offset, + // Get *real* offset parent + offsetParent = this.offsetParent(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // `position: fixed` elements are offset from the viewport, which itself always has zero offset + if (D(elem).css('position') === 'fixed') { + // Assume `position: fixed` implies availability of getBoundingClientRect + offset = elem.getBoundingClientRect(); + } else { + offset = this.offset(); + + // Incorporate borders into its offset, since they are outside its content origin + parentOffset.top += parseFloat(D(offsetParent[0]).css('border-top-width')) || 0; + parentOffset.left += parseFloat(D(offsetParent[0]).css('border-left-width')) || 0; + } + + // Subtract parent offsets and element margins + // note: when an element has `margin: auto` the offsetLeft and marginLeft + // are the same in Safari causing `offset.left` to incorrectly be 0 + return { + top: offset.top - parentOffset.top - parseFloat(D(elem).css('margin-top')) || 0, + left: offset.left - parentOffset.left - parseFloat(D(elem).css('margin-left')) || 0 + }; +} + +function scrollTop(value) { + if (!this.length) return; + var hasScrollTop = 'scrollTop' in this[0]; + if (value === undefined) return hasScrollTop + ? this[0].scrollTop + : isWindow(this[0]) + ? this[0].pageYOffset + : this[0].defaultView.pageYOffset; + return this.each(hasScrollTop ? + function () { this.scrollTop = value; } : + function () { this.scrollTo(this.scrollX, value); }); +} + +function scrollLeft(value) { + if (!this.length) return; + var hasScrollLeft = 'scrollLeft' in this[0]; + if (value === undefined) return hasScrollLeft + ? this[0].scrollLeft + : isWindow(this[0]) + ? this[0].pageXOffset + : this[0].defaultView.pageXOffset; + return this.each(hasScrollLeft ? + function () { this.scrollLeft = value; } : + function () { this.scrollTo(value, this.scrollY); }); +} + +function offsetParent() { + return this.map(function () { + var parent = this.offsetParent || document$1.body; + while (parent && !rootNodeRE.test(parent.nodeName) && D(parent).css('position') == 'static') + parent = parent.offsetParent; + return parent; + }); +} + +function attr(name, value) { + var result; + return (typeof name == 'string' && !(1 in arguments)) + ? (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null + ? result + : undefined) + : this.each(function (idx) { + if (this.nodeType !== 1) return; + if (isObject(name)) + for (var key in name) setAttribute(this, key, name[key]); + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))); + }); +} + +function removeAttr(name) { + return this.each(function () { + this.nodeType === 1 && name.split(' ').forEach(function (attribute) { + setAttribute(this, attribute); + }, this); + }); +} + +function find(selector) { + var result, $this = this; + if (!selector) result = D(); + else if (typeof selector == 'object') + result = D(selector).filter(function () { + var node = this; + return emptyArray.some.call($this, function (parent) { + return contains(parent, node); + }); + }); + else if (this.length == 1) result = D(D.qsa(this[0], selector)); + else result = this.map(function () { return D.qsa(this, selector); }); + return result; +} + +function closest(selector, context) { + var nodes = [], + collection = typeof selector == 'object' && D(selector); + this.each(function (_, node) { + while (node && !(collection ? collection.indexOf(node) >= 0 : D.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode; + if (node && nodes.indexOf(node) < 0) nodes.push(node); + }); + return D(nodes); +} + +function isIE() { + var ua = window.navigator.userAgent; + var msie = ua.indexOf('MSIE '); + return msie > 0 || !!navigator.userAgent.match(/Trident.*rv:11\./); +} + +function subtract(el, dimen) { + var offsetMap = { + width: ['padding-left', 'padding-right', 'border-left-width', 'border-right-width'], + height: ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width'] + }; + return el.css('box-sizing') === 'border-box' && !isIE() + ? parseFloat(el.css(dimen)) + - parseFloat(el.css(offsetMap[dimen][0])) + - parseFloat(el.css(offsetMap[dimen][1])) + - parseFloat(el.css(offsetMap[dimen][2])) + - parseFloat(el.css(offsetMap[dimen][3])) + : parseFloat(el.css(dimen)); +} + +function calc(dimension, value) { + var dimensionProperty = dimension.replace(/./, function (m) { return m[0].toUpperCase(); }); + var el = this[0]; + if (value === undefined) return isWindow(el) + ? el.document.documentElement['client' + dimensionProperty] + : isDocument(el) + ? el.documentElement['scroll' + dimensionProperty] + : subtract(this, dimension); + else return this.each(function (idx) { + el = D(this); + el.css(dimension, funcArg(this, value, idx, el[dimension]())); + }); +} + +// Export + +function width(value) { + return calc.call(this, 'width', value); +} + +function height(value) { + return calc.call(this, 'height', value); +} + +var traverseNode = function (node, fn) { + fn(node); + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fn); +}; + +// inside => append, prepend +var domMani = function (elem, args, fn, inside) { + // arguments can be nodes, arrays of nodes, D objects and HTML strings + var argType, + nodes = D.map(args, function (arg) { + var arr = []; + argType = type(arg); + if (argType == 'array') { + arg.forEach(function (el) { + if (el.nodeType !== undefined) return arr.push(el); + else if (isD(el)) return arr = arr.concat(el.get()); + arr = arr.concat(D.fragment(el)); + }); + return arr; + } + return argType == 'object' || arg == null ? arg : D.fragment(arg); + }), + parent, + copyByClone = elem.length > 1; + + if (nodes.length < 1) return elem; + + return elem.each(function (_, target) { + parent = inside ? target : target.parentNode; + var parentInDocument = contains(document$1.documentElement, parent); + + nodes.forEach(function (node) { + if (copyByClone) node = node.cloneNode(true); + else if (!parent) return D(node).remove(); + + fn.call(target, node); + + if (parentInDocument) { + traverseNode(node, function (el) { + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) { + var target = el.ownerDocument ? el.ownerDocument.defaultView : window; + target['eval'].call(target, el.innerHTML); + } + }); + } + }); + }); +}; + +// Export + +function remove$1() { + return this.each(function () { + if (this.parentNode != null) + this.parentNode.removeChild(this); + }); +} + +function empty() { + return this.each(function () { this.innerHTML = ''; }); +} + +function html(html) { + return 0 in arguments + ? this.each(function (idx) { + var originHtml = this.innerHTML; + D(this).empty().append(funcArg(this, html, idx, originHtml)); + }) + : (0 in this ? this[0].innerHTML : null); +} + +function append() { + return domMani(this, arguments, function (elem) { + this.insertBefore(elem, null); + }, true); +} + +var _zid = 1; +function zid(element) { + return element._zid || (element._zid = _zid++); +} + +function isString(obj) { + return typeof obj == 'string'; +} + +var returnTrue = function () { return true; }, + returnFalse = function () { return false; }, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + }; + +function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event); + + D.each(eventMethods, function (name, predicate) { + var sourceMethod = source[name]; + event[name] = function () { + this[predicate] = returnTrue; + return sourceMethod && sourceMethod.apply(source, arguments); + }; + event[predicate] = returnFalse; + }); + + try { + event.timeStamp || (event.timeStamp = Date.now()); + } catch (ignored) { + console.warn(ignored); + } + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue; + } + return event; +} + +var handlers = {}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/; + +function parse(event) { + var parts = ('' + event).split('.'); + return { e: parts[0], ns: parts.slice(1).sort().join(' ') }; +} +function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)'); +} + +function findHandlers(element, event, fn, selector) { + event = parse(event); + if (event.ns) var matcher = matcherFor(event.ns); + return (handlers[zid(element)] || []).filter(function (handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector); + }); +} + +function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting; +} + +function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type; +} + +function add(element, events, fn, data, selector, delegator, capture) { + var id = zid(element), set = (handlers[id] || (handlers[id] = [])); + events.split(/\s/).forEach(function (event) { + if (event == 'ready') return D(document$1).ready(fn); + var handler = parse(event); + handler.fn = fn; + handler.sel = selector; + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function (e) { + var related = e.relatedTarget; + if (!related || (related !== this && !contains(this, related))) + return handler.fn.apply(this, arguments); + }; + handler.del = delegator; + var callback = delegator || fn; + handler.proxy = function (e) { + e = compatible(e); + if (e.isImmediatePropagationStopped()) return; + e.data = data; + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)); + if (result === false) e.preventDefault(), e.stopPropagation(); + return result; + }; + handler.i = set.length; + set.push(handler); + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); +} + +function remove(element, events, fn, selector, capture) { + var id = zid(element); + (events || '').split(/\s/).forEach(function (event) { + findHandlers(element, event, fn, selector).forEach(function (handler) { + delete handlers[id][handler.i]; + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); + }); +} + +function createProxy(event) { + var key, proxy = { originalEvent: event }; + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]; + + return compatible(proxy, event); +} + +var on = function (event, selector, data, callback, one) { + var autoRemove, delegator, $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.on(type, selector, data, fn, one); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined; + if (callback === undefined || data === false) + callback = data, data = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function (_, element) { + if (one) autoRemove = function (e) { + remove(element, e.type, callback); + return callback.apply(this, arguments); + }; + + if (selector) delegator = function (e) { + var evt, match = D(e.target).closest(selector, element).get(0); + if (match && match !== element) { + evt = D.extend(createProxy(e), { currentTarget: match, liveFired: element }); + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))); + } + }; + + add(element, event, callback, data, selector, delegator || autoRemove); + }); +}; + +var off = function (event, selector, callback) { + var $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.off(type, selector, fn); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function () { + remove(this, event, callback, selector); + }); +}; + +var prefix = '', + eventPrefix, + vendors = { Webkit: 'webkit', Moz: '', O: 'o' }, + testEl = document$1.createElement('div'), + testTransitionProperty = testEl.style.transitionProperty; + +if (testEl.style.transform === undefined) D.each(vendors, function (vendor, event) { + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + vendor.toLowerCase() + '-'; + eventPrefix = event; + return false; + } +}); + +testEl = null; + +// fx cannot seperate +function normalizeEvent(name) { + return eventPrefix ? eventPrefix + name : name.toLowerCase(); +} + +D.fx = { + off: (eventPrefix === undefined && testTransitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') +}; + +var supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, transitionDelay, + animationName, animationDuration, animationTiming, animationDelay, + cssReset = {}; + +function dasherize(str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); } + +transform = prefix + 'transform'; +cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionDelay = prefix + 'transition-delay'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationDelay = prefix + 'animation-delay'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = ''; + +var anim$1 = function (properties, duration, ease, callback, delay) { + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = D.fx.transitionEnd, + fired = false; + + if (duration === undefined) duration = D.fx.speeds._default / 1000; + if (delay === undefined) delay = 0; + if (D.fx.off) duration = 0; + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties; + cssValues[animationDuration] = duration + 's'; + cssValues[animationDelay] = delay + 's'; + cssValues[animationTiming] = (ease || 'linear'); + endEvent = D.fx.animationEnd; + } else { + cssProperties = []; + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '; + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)); + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform); + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', '); + cssValues[transitionDuration] = duration + 's'; + cssValues[transitionDelay] = delay + 's'; + cssValues[transitionTiming] = (ease || 'linear'); + } + } + + wrappedCallback = function (event) { + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return; // makes sure the event didn't bubble from "below" + D(event.target).off(endEvent, wrappedCallback); + } else + D(this).off(endEvent, wrappedCallback); // triggered by setTimeout + + fired = true; + D(this).css(cssReset); + callback && callback.call(this); + }; + if (duration > 0) { + this.on(endEvent, wrappedCallback); + // transitionEnd is not always firing on older Android phones + // so make sure it gets fired + setTimeout(function () { + if (fired) return; + wrappedCallback.call(that); + }, ((duration + delay) * 1000) + 25); + } + + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft; + + this.css(cssValues); + + if (duration <= 0) setTimeout(function () { + that.each(function () { wrappedCallback.call(this); }); + }, 0); + + return this; +}; + +var animate = function (properties, duration, ease, callback, delay) { + if (isFunction(duration)) + callback = duration, ease = undefined, duration = undefined; + if (isFunction(ease)) + callback = ease, ease = undefined; + if (isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration; + if (duration) duration = (typeof duration == 'number' ? duration : + (D.fx.speeds[duration] || D.fx.speeds._default)) / 1000; + if (delay) delay = parseFloat(delay) / 1000; + return this.anim(properties, duration, ease, callback, delay); +}; + +var origShow = function () { + return this.each(function () { + this.style.display == 'none' && (this.style.display = ''); + if (getComputedStyle(this, '').getPropertyValue('display') == 'none') + this.style.display = defaultDisplay(this.nodeName); + }); +}; + +var origHide = function () { + return this.css('display', 'none'); +}; + +function anim(el, speed, opacity, scale, callback) { + if (typeof speed == 'function' && !callback) callback = speed, speed = undefined; + var props = { opacity: opacity }; + if (scale) { + props.scale = scale; + el.css(D.fx.cssPrefix + 'transform-origin', '0 0'); + } + return el.animate(props, speed, null, callback); +} + +function hideHelper(el, speed, scale, callback) { + return anim(el, speed, 0, scale, function () { + origHide.call(D(this)); + callback && callback.call(this); + }); +} + +// Export + +var show = function (speed, callback) { + origShow.call(this); + if (speed === undefined) speed = 0; + else this.css('opacity', 0); + return anim(this, speed, 1, '1,1', callback); +}; + +var hide = function (speed, callback) { + if (speed === undefined) return origHide.call(this); + else return hideHelper(this, speed, '0,0', callback); +}; + +var fadeTo = function (speed, opacity, callback) { + return anim(this, speed, opacity, null, callback); +}; + +var fadeIn = function (speed, callback) { + var target = this.css('opacity'); + if (target > 0) this.css('opacity', 0); + else target = 1; + return origShow.call(this).fadeTo(speed, target, callback); +}; + +var $ = D; +var methods = { + isPlainObject: isPlainObject, + isArray: isArray, + noop: noop +}; +var fnMethods = { + find: find, + closest: closest, + css: css, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass, + attr: attr, + removeAttr: removeAttr, + append: append, + remove: remove$1, + empty: empty, + html: html, + width: width, + height: height, + scrollTop: scrollTop, + scrollLeft: scrollLeft, + offset: offset, + offsetParent: offsetParent, + position: position, + on: on, + off: off, + show: show, + hide: hide, + anim: anim$1, + animate: animate, + fadeTo: fadeTo, + fadeIn: fadeIn +}; +$.extend(methods); +$.fn.extend(fnMethods); + +var DEFAULTS = { + // Whether to enable modal dragging + draggable: true, + // Whether to enable modal resizing + resizable: true, + // Whether to enable image moving + movable: true, + // Whether to enable keyboard navigation + keyboard: true, + // Whether to show the title + title: true, + // Min width of modal + modalWidth: 320, + // Min height of modal + modalHeight: 320, + // Whether to change the modal size after image loaded + fixedModalSize: false, + // Whether to set maximized on init + initMaximized: false, + // Threshold of modal relative to browser window + gapThreshold: 0.02, + // Threshold of image ratio + ratioThreshold: 0.1, + // Min ratio of image when zoom out + minRatio: 0.05, + // Max ratio of image when zoom in + maxRatio: 16, + // Toolbar options in header + headerToolbar: ['maximize', 'close'], + // Toolbar options in footer + footerToolbar: ['zoomIn', 'zoomOut', 'prev', 'fullscreen', 'next', 'actualSize', 'rotateRight'], + // Custom icon for button + icons: { + minimize: "\n \n ", + maximize: "\n \n ", + close: "\n \n ", + zoomIn: "\n \n ", + zoomOut: "\n \n ", + prev: "\n \n ", + next: "\n \n ", + fullscreen: "\n \n ", + actualSize: "\n \n ", + rotateLeft: "\n \n ", + rotateRight: "\n \n " + }, + // Custom title for button + i18n: { + minimize: 'Minimize', + maximize: 'Maximize (Alt+X)', + close: 'Close (Q)', + zoomIn: 'Zoom-in (+)', + zoomOut: 'Zoom-out (-)', + prev: 'Prev (←)', + next: 'Next (→)', + fullscreen: 'Fullscreen (F)', + actualSize: 'Actual-size (Ctrl+Alt+0)', + rotateLeft: 'Rotate-left (Ctrl+,)', + rotateRight: 'Rotate-right (Ctrl+.)' + }, + // Whether to enable multiple instances + multiInstances: true, + // Whether to enable modal transform animation + initAnimation: true, + // Modal transform animation duration + animationDuration: 400, + // Whether to disable modal translate to center after image changed + fixedModalPos: false, + // Modal css `z-index` + zIndex: 1090, + // Selector of drag handler + dragHandle: null, + // Callback events + callbacks: { + beforeOpen: $.noop, + opened: $.noop, + beforeClose: $.noop, + closed: $.noop, + beforeChange: $.noop, + changed: $.noop + }, + // Start index of images + index: 0, + // Whether to load the image progressively + progressiveLoading: true, + // The DOM element which photoviewer will be attached to + appendTo: 'body', + // Custom Buttons + customButtons: {}, + // Whether to set modal css `position: fixed` + positionFixed: true, + // Init modal position `{top: 0, right: 0, bottom: 0, left: 0}` + initModalPos: null +}; + +var document = window.document; + +/** + * Debounce function + * + * @param {function} fn - The function will be triggered + * @param {number} delay - The debounce delay time + * @return {function} + */ +function debounce(fn, delay) { + var timer = null; + return function () { + var context = this; + var args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; +} + +/** + * Preload a image + * + * @param {string} src - The image src + * @param {function} success - The callback of success + * @param {function} error - The callback of error + */ +function preloadImage(src, success, error) { + var img = new Image(); + img.onload = function () { + success(img); + }; + img.onerror = function () { + error(img); + }; + img.src = src; +} + +/** + * Request fullscreen + * + * @param {type} element + */ +function requestFullscreen(element) { + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } +} + +/** + * Get the image name from its url + * + * @param {string} url - The image src + * @return {string} + */ +function getImageNameFromUrl(url) { + var reg = /^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/gi; + var txt = url.replace(reg, '$1'); + return txt; +} + +/** + * Set grab cursor when move image + * + * @param {object} imageData - The image data + * @param {object} stageData - The stage data + * @param {object} $stage - The stage element of domq + * @param {boolean} isRotate - The image rotated flag + */ +function setGrabCursor(imageData, stageData, $stage, isRotated) { + var imageWidth = !isRotated ? imageData.w : imageData.h; + var imageHeight = !isRotated ? imageData.h : imageData.w; + if (imageHeight > stageData.h || imageWidth > stageData.w) { + $stage.addClass('is-grab'); + } + if (imageHeight <= stageData.h && imageWidth <= stageData.w) { + $stage.removeClass('is-grab'); + } +} + +/** + * Check whether browser support touch event + * + * @return {boolean} + */ +function supportTouch() { + return !!('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch); +} + +/** + * Check whether element is root node (`body` or `html`) + * + * @param {object} elem - The DOM element + * @return {boolean} + */ +function isRootNode(elem) { + return /^(?:body|html)$/i.test(elem.nodeName); +} + +/** + * Get sum value of CSS props + * + * @param {object} $elem - The domq element + * @param {array} props - The array of CSS props + * @return {number} + */ +function getCSSValueSum($elem, props) { + return props.reduce(function (acc, cur) { + return acc + parseFloat($elem.css(cur)); + }, 0); +} + +/** + * Check whether element's CSS `box-sizing` is `border-box` + * + * @param {object} $elem - The domq element + * @return {boolean} + */ +function isBorderBox($elem) { + return $elem.css('box-sizing') === 'border-box'; +} + +var $W = $(window); +var $D = $(document); +var CLICK_EVENT = 'click'; +var RESIZE_EVENT = 'resize'; +var KEYDOWN_EVENT = 'keydown'; +var WHEEL_EVENT = 'wheel mousewheel DOMMouseScroll'; +var TOUCH_START_EVENT = supportTouch() ? 'touchstart' : 'mousedown'; +var TOUCH_MOVE_EVENT = supportTouch() ? 'touchmove' : 'mousemove'; +var TOUCH_END_EVENT = supportTouch() ? 'touchend' : 'mouseup'; +var NS = 'photoviewer'; +var CLASS_NS = '.' + NS; +var EVENT_NS = '.' + NS; +var PUBLIC_VARS = { + // Whether image is moving + isMoving: false, + // Whether modal is resizing + isResizing: false, + // Modal's `z-index` + zIndex: 0 +}; + +var draggable = { + /** + * Modal draggable + * + * @param {object} $modal - The modal element of domq + * @param {object} dragHandle - The handle element when dragging + * @param {object} dragCancel - The cancel element when dragging + */ + draggable: function draggable($modal, dragHandle, dragCancel) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + + // Must be removed + // e.preventDefault(); + + // Fix focus scroll issue on Chrome + $modal[0].blur(); + + // Get clicked button + var elemCancel = $(e.target).closest(dragCancel); + // Stop modal moving when click buttons + if (elemCancel.length) { + return true; + } + if (_this.options.multiInstances) { + $modal.css('z-index', ++PUBLIC_VARS['zIndex']); + } + isDragging = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Get current position of the modal + left = parseFloat($modal.css('left')); + top = parseFloat($modal.css('top')); + + // Reset modal position with left and top + $modal.css({ + left: left, + top: top, + right: '', + bottom: '' + }); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !PUBLIC_VARS['isMoving'] && !PUBLIC_VARS['isResizing'] && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + $modal.css({ + left: relativeX + left, + top: relativeY + top + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + + // Focus must be executed after drag end + $modal[0].focus(); + }; + $(dragHandle).on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } +}; + +var ELEMS_WITH_GRABBING_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button, .").concat(NS, "-resizable-handle"); +var movable = { + /** + * Image movable + * + * 1. No movable + * 2. Vertical movable + * 3. Horizontal movable + * 4. Vertical & Horizontal movable + * + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + */ + movable: function movable($stage, $image) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var widthDiff = 0; + var heightDiff = 0; + var δ = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + e.preventDefault(); + var imageWidth = $image.width(); + var imageHeight = $image.height(); + var stageWidth = $stage.width(); + var stageHeight = $stage.height(); + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageWidth - imageHeight) / 2; + + // Width or height difference can be use to limit image right or top position + widthDiff = !_this.isRotated ? imageWidth - stageWidth : imageHeight - stageWidth; + heightDiff = !_this.isRotated ? imageHeight - stageHeight : imageWidth - stageHeight; + + // Modal can be dragging if image is smaller to stage + isDragging = widthDiff > 0 || heightDiff > 0 ? true : false; + PUBLIC_VARS['isMoving'] = widthDiff > 0 || heightDiff > 0 ? true : false; + + // Reclac the element position when mousedown + // Fix the issue of stage with a border + left = $image.position().left - δ; + top = $image.position().top + δ; + + // Add grabbing cursor + if ($stage.hasClass('is-grab')) { + $(ELEMS_WITH_GRABBING_CURSOR).addClass('is-grabbing'); + } + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var newLeft = relativeX + left; + var newTop = relativeY + top; + + // Vertical limit + if (heightDiff > 0) { + if (relativeY + top > δ) { + newTop = δ; + } else if (relativeY + top < -heightDiff + δ) { + newTop = -heightDiff + δ; + } + } else { + newTop = top; + } + // Horizontal limit + if (widthDiff > 0) { + if (relativeX + left > -δ) { + newLeft = -δ; + } else if (relativeX + left < -widthDiff - δ) { + newLeft = -widthDiff - δ; + } + } else { + newLeft = left; + } + $image.css({ + left: newLeft, + top: newTop + }); + + // Update image initial data + $.extend(_this.imageData, { + left: newLeft, + top: newTop + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + PUBLIC_VARS['isMoving'] = false; + + // Remove grabbing cursor + $(ELEMS_WITH_GRABBING_CURSOR).removeClass('is-grabbing'); + }; + $stage.on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } +}; + +var ELEMS_WITH_RESIZE_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button"); +var resizable = { + /** + * Modal resizable + * + * 1. Can be resized in 8 directions + * 2. Keep image in stage center + * 3. Other restrictions for image + * + * @param {object} $modal - The modal element of domq + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + * @param {number} minWidth - The modalWidth option + * @param {number} minHeight - The modalHeight option + */ + resizable: function resizable($modal, $stage, $image, minWidth, minHeight) { + var _this = this; + var resizableHandleE = $("")); + var resizableHandleW = $("")); + var resizableHandleS = $("")); + var resizableHandleN = $("")); + var resizableHandleSE = $("")); + var resizableHandleSW = $("")); + var resizableHandleNE = $("")); + var resizableHandleNW = $("")); + var resizableHandles = { + e: resizableHandleE, + s: resizableHandleS, + se: resizableHandleSE, + n: resizableHandleN, + w: resizableHandleW, + nw: resizableHandleNW, + ne: resizableHandleNE, + sw: resizableHandleSW + }; + $modal.append(resizableHandleE, resizableHandleW, resizableHandleS, resizableHandleN, resizableHandleSE, resizableHandleSW, resizableHandleNE, resizableHandleNW); + var isDragging = false; + var startX = 0; + var startY = 0; + var modalData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var stageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var imageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + // δ is the difference between image width and height + var δ = 0; + var imgWidth = 0; + var imgHeight = 0; + var direction = ''; + + // Modal CSS options + var getModalOpts = function getModalOpts(dir, offsetX, offsetY) { + // Modal should not move when its width to the minwidth + var modalLeft = -offsetX + modalData.w > minWidth ? offsetX + modalData.x : modalData.x + modalData.w - minWidth; + var modalTop = -offsetY + modalData.h > minHeight ? offsetY + modalData.y : modalData.y + modalData.h - minHeight; + var opts = { + e: { + width: Math.max(offsetX + modalData.w, minWidth) + }, + s: { + height: Math.max(offsetY + modalData.h, minHeight) + }, + se: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight) + }, + w: { + width: Math.max(-offsetX + modalData.w, minWidth), + left: modalLeft + }, + n: { + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + nw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop, + left: modalLeft + }, + ne: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + sw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight), + left: modalLeft + } + }; + return opts[dir]; + }; + + // Image CSS options + var getImageOpts = function getImageOpts(dir, offsetX, offsetY) { + // Image should not move when modal width to the min width + // The minwidth is modal width, so we should clac the stage minwidth + var widthDiff = offsetX + modalData.w > minWidth ? stageData.w - imgWidth + offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff = offsetY + modalData.h > minHeight ? stageData.h - imgHeight + offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + var widthDiff2 = -offsetX + modalData.w > minWidth ? stageData.w - imgWidth - offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff2 = -offsetY + modalData.h > minHeight ? stageData.h - imgHeight - offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + + // Get image position in dragging + var imgLeft = (widthDiff > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop = (heightDiff > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var imgLeft2 = (widthDiff2 > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop2 = (heightDiff2 > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var opts = { + e: { + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + s: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff + }, + se: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + w: { + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + n: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2 + }, + nw: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + ne: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + sw: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + } + }; + return opts[dir]; + }; + var dragStart = function dragStart(dir, e) { + e = e || window.event; + e.preventDefault(); + isDragging = true; + PUBLIC_VARS['isResizing'] = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Reclac the modal data when mousedown + modalData = { + w: $modal.width() + (isBorderBox($modal) ? _this._modalEdgeValue.horizontal : 0), + h: $modal.height() + (isBorderBox($modal) ? _this._modalEdgeValue.vertical : 0), + x: $modal.position().left, + y: $modal.position().top + }; + stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.position().left, + y: $stage.position().top + }; + imageData = { + w: $image.width(), + h: $image.height(), + x: $image.position().left, + y: $image.position().top + }; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageData.w - imageData.h) / 2; + imgWidth = !_this.isRotated ? imageData.w : imageData.h; + imgHeight = !_this.isRotated ? imageData.h : imageData.w; + direction = dir; + + // Add resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', dir + '-resize'); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var modalOpts = getModalOpts(direction, relativeX, relativeY); + $modal.css(modalOpts); + var imageOpts = getImageOpts(direction, relativeX, relativeY); + $image.css(imageOpts); + _this.isDoResize = true; + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + + // Set grab cursor + if (PUBLIC_VARS['isResizing']) { + setGrabCursor({ + w: imgWidth, + h: imgHeight + }, { + w: $stage.width(), + h: $stage.height() + }, $stage); + } + isDragging = false; + PUBLIC_VARS['isResizing'] = false; + + // Remove resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', ''); + + // Update image initial data + var scale = _this.getImageScale($stage.width(), $stage.height()); + $.extend(_this.imageData, { + initWidth: _this.img.width * scale, + initHeight: _this.img.height * scale, + initLeft: ($stage.width() - _this.img.width * scale) / 2, + initTop: ($stage.height() - _this.img.height * scale) / 2 + }); + }; + $.each(resizableHandles, function (dir, handle) { + handle.on(TOUCH_START_EVENT + EVENT_NS, function (e) { + dragStart(dir, e); + }); + }); + } +}; + +/** + * PhotoViewer class + */ +var PhotoViewer = /*#__PURE__*/function () { + function PhotoViewer(items, options, el) { + _classCallCheck(this, PhotoViewer); + this.options = $.extend(true, {}, DEFAULTS, options); + if (options && $.isArray(options.footerToolbar)) { + this.options.footerToolbar = options.footerToolbar; + } + if (options && $.isArray(options.headerToolbar)) { + this.options.headerToolbar = options.headerToolbar; + } + + // Store element of clicked + this.$el = $(el); + + // As we have multiple instances, so every instance has the following variables. + + // Whether modal opened + this.isOpened = false; + + // Whether modal maximized + this.isMaximized = false; + + // Whether image rotated (`90*(2n+1)`) + this.isRotated = false; + + // Image rotation degree + this.rotationDegree = 0; + + // Whether modal do resize + this.isDoResize = false; + + // Store image data in every instance + this.imageData = {}; + + // Store modal data in every instance + this.modalData = { + width: null, + height: null, + left: null, + top: null + }; + + // Used for time comparison + this._lastTimestamp = 0; + this.init(items, this.options); + } + _createClass(PhotoViewer, [{ + key: "init", + value: function init(items, opts) { + this.groupData = items; + this.groupIndex = opts['index']; + + // Reset public z-index with option + PUBLIC_VARS['zIndex'] = PUBLIC_VARS['zIndex'] === 0 ? opts['zIndex'] : PUBLIC_VARS['zIndex']; + + // Get image src + var imgSrc = items[this.groupIndex]['src']; + this.open(); + this.loadImage(imgSrc); + if (opts.draggable) { + this.draggable(this.$photoviewer, this.dragHandle, CLASS_NS + '-button'); + } + if (opts.movable) { + this.movable(this.$stage, this.$image); + } + if (opts.resizable) { + this.resizable(this.$photoviewer, this.$stage, this.$image, opts.modalWidth, opts.modalHeight); + } + } + }, { + key: "_createBtns", + value: function _createBtns(toolbar) { + var _this = this; + var btns = ['minimize', 'maximize', 'close', 'zoomIn', 'zoomOut', 'prev', 'next', 'fullscreen', 'actualSize', 'rotateLeft', 'rotateRight']; + var btnsHTML = ''; + $.each(toolbar, function (index, item) { + var btnClass = "".concat(NS, "-button ").concat(NS, "-button-").concat(item); + if (btns.indexOf(item) >= 0) { + btnsHTML += "\n ").concat(_this.options.icons[item], "\n "); + } else if (_this.options.customButtons[item]) { + btnsHTML += "\n ").concat(_this.options.customButtons[item].text, "\n "); + } + }); + return btnsHTML; + } + }, { + key: "_createTitle", + value: function _createTitle() { + return this.options.title ? "") : ''; + } + }, { + key: "_createTemplate", + value: function _createTemplate() { + // PhotoViewer base HTML + var photoviewerHTML = "\n \n \n \n ").concat(this._createBtns(this.options.headerToolbar), "\n \n ").concat(this._createTitle(), "\n \n \n \n \n \n \n ").concat(this._createBtns(this.options.footerToolbar), "\n \n \n \n "); + return photoviewerHTML; + } + }, { + key: "build", + value: function build() { + // Create PhotoViewer HTML string + var photoviewerHTML = this._createTemplate(); + + // Make PhotoViewer HTML string to jQuery element + var $photoviewer = $(photoviewerHTML); + + // Get all PhotoViewer elements + this.$photoviewer = $photoviewer; + this.$stage = $photoviewer.find(CLASS_NS + '-stage'); + this.$title = $photoviewer.find(CLASS_NS + '-title'); + this.$image = $photoviewer.find(CLASS_NS + '-image'); + this.$close = $photoviewer.find(CLASS_NS + '-button-close'); + this.$maximize = $photoviewer.find(CLASS_NS + '-button-maximize'); + this.$minimize = $photoviewer.find(CLASS_NS + '-button-minimize'); + this.$zoomIn = $photoviewer.find(CLASS_NS + '-button-zoomIn'); + this.$zoomOut = $photoviewer.find(CLASS_NS + '-button-zoomOut'); + this.$actualSize = $photoviewer.find(CLASS_NS + '-button-actualSize'); + this.$fullscreen = $photoviewer.find(CLASS_NS + '-button-fullscreen'); + this.$rotateLeft = $photoviewer.find(CLASS_NS + '-button-rotateLeft'); + this.$rotateRight = $photoviewer.find(CLASS_NS + '-button-rotateRight'); + this.$prev = $photoviewer.find(CLASS_NS + '-button-prev'); + this.$next = $photoviewer.find(CLASS_NS + '-button-next'); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + + // Reset modal `z-index` of multiple instances + this.$photoviewer.css('z-index', PUBLIC_VARS['zIndex']); + if (this.options.positionFixed) { + this.$photoviewer.css({ + position: 'fixed' + }); + } + + // Set handle element of draggable + if (!this.options.dragHandle || this.options.dragHandle === CLASS_NS + '-modal') { + this.dragHandle = this.$photoviewer; + } else { + this.dragHandle = this.$photoviewer.find(this.options.dragHandle); + } + + // Add PhotoViewer to DOM + $(this.options.appendTo).eq(0).append(this.$photoviewer); + + // Store the edge value of stage + this._stageEdgeValue = { + horizontal: getCSSValueSum(this.$stage, ['left', 'right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$stage, ['top', 'bottom', 'border-top-width', 'border-bottom-width']) + }; + + // Store the edge value of modal + this._modalEdgeValue = { + horizontal: getCSSValueSum(this.$photoviewer, ['padding-left', 'padding-right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$photoviewer, ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width']) + }; + this._addEvents(); + this._addCustomButtonEvents(); + } + }, { + key: "open", + value: function open() { + this._triggerHook('beforeOpen', this); + if (!this.options.multiInstances) { + $(CLASS_NS + '-modal').eq(0).remove(); + } + this.build(); + this.setInitModalPos(); + this._triggerHook('opened', this); + } + }, { + key: "close", + value: function close() { + this._triggerHook('beforeClose', this); + + // Remove PhotoViewer instance + this.$photoviewer.remove(); + this.isOpened = false; + this.isMaximized = false; + this.isRotated = false; + this.rotationDegree = 0; + if (!$(CLASS_NS + '-modal').length) { + // Reset `z-index` after close + if (this.options.multiInstances) { + PUBLIC_VARS['zIndex'] = this.options.zIndex; + } + + // Off resize event + $W.off(RESIZE_EVENT + EVENT_NS); + } + this._triggerHook('closed', this); + } + }, { + key: "_getOffsetParentData", + value: function _getOffsetParentData() { + var offsetParent = $(this.options.appendTo)[0]; + return { + width: this.options.positionFixed || isRootNode(offsetParent) ? $W.width() : offsetParent.clientWidth, + height: this.options.positionFixed || isRootNode(offsetParent) ? $W.height() : offsetParent.clientHeight, + scrollLeft: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollLeft() : offsetParent.scrollLeft, + scrollTop: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollTop() : offsetParent.scrollTop + }; + } + }, { + key: "setModalToCenter", + value: function setModalToCenter() { + var initLeft, initTop, initRight, initBottom; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (!isBorderBox(this.$photoviewer)) { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + if ($.isPlainObject(this.options.initModalPos)) { + initLeft = this.options.initModalPos.left; + initTop = this.options.initModalPos.top; + initRight = this.options.initModalPos.right; + initBottom = this.options.initModalPos.bottom; + } else { + var offsetParentData = this._getOffsetParentData(); + initLeft = (offsetParentData.width - this.options.modalWidth - extraWidth) / 2 + offsetParentData.scrollLeft; + initTop = (offsetParentData.height - this.options.modalHeight - extraHeight) / 2 + offsetParentData.scrollTop; + } + var modalInitCSS = { + width: this.modalData.width || this.options.modalWidth, + height: this.modalData.height || this.options.modalHeight, + left: this.modalData.left || initLeft, + top: this.modalData.top || initTop, + right: this.modalData.right || initRight, + bottom: this.modalData.bottom || initBottom + }; + this.$photoviewer.css(modalInitCSS); + } + }, { + key: "setInitModalPos", + value: function setInitModalPos() { + if (this.options.initMaximized) { + this.maximize(); + this.isOpened = true; + } else { + this.setModalToCenter(); + } + + // The focus must be set after opening + this.$photoviewer[0].focus(); + } + }, { + key: "setModalSize", + value: function setModalSize(img) { + var _this2 = this; + var offsetParentData = this._getOffsetParentData(); + + // Modal size should calculate with stage css value + var modalWidth = img.width + this._stageEdgeValue.horizontal; + var modalHeight = img.height + this._stageEdgeValue.vertical; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (isBorderBox(this.$photoviewer)) { + modalWidth += this._modalEdgeValue.horizontal; + modalHeight += this._modalEdgeValue.vertical; + } else { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + var gapThreshold = (this.options.gapThreshold > 0 ? this.options.gapThreshold : 0) + 1; + + // Modal scale relative to parent element + var scale = Math.min(offsetParentData.width / ((modalWidth + extraWidth) * gapThreshold), offsetParentData.height / ((modalHeight + extraHeight) * gapThreshold), 1); + var minWidth = Math.max(modalWidth * scale, this.options.modalWidth); + var minHeight = Math.max(modalHeight * scale, this.options.modalHeight); + minWidth = this.options.fixedModalSize ? this.options.modalWidth : Math.round(minWidth); + minHeight = this.options.fixedModalSize ? this.options.modalHeight : Math.round(minHeight); + var transLeft, transTop, transRight, transBottom; + if ($.isPlainObject(this.options.initModalPos)) { + transLeft = this.options.initModalPos.left; + transTop = this.options.initModalPos.top; + transRight = this.options.initModalPos.right; + transBottom = this.options.initModalPos.bottom; + } else { + var _offsetParentData = this._getOffsetParentData(); + transLeft = (_offsetParentData.width - minWidth - extraWidth) / 2 + _offsetParentData.scrollLeft; + transTop = (_offsetParentData.height - minHeight - extraHeight) / 2 + _offsetParentData.scrollTop; + } + var modalTransCSS = { + width: minWidth, + height: minHeight, + left: transLeft, + top: transTop, + right: transRight, + bottom: transBottom + }; + + // Add init animation for modal + if (this.options.initAnimation) { + this.$photoviewer.animate(modalTransCSS, this.options.animationDuration, 'ease-in-out', function () { + _this2.setImageSize(img); + }); + } else { + this.$photoviewer.css(modalTransCSS); + this.setImageSize(img); + } + this.isOpened = true; + } + }, { + key: "getImageScale", + value: function getImageScale(stageWidth, stageHeight) { + var scale = 1; + if (!this.isRotated) { + scale = Math.min(stageWidth / this.img.width, stageHeight / this.img.height, 1); + } else { + scale = Math.min(stageWidth / this.img.height, stageHeight / this.img.width, 1); + } + return scale; + } + }, { + key: "setImageSize", + value: function setImageSize(img) { + var stageData = { + w: this.$stage.width(), + h: this.$stage.height() + }; + var scale = this.getImageScale(stageData.w, stageData.h); + this.$image.css({ + width: Math.round(img.width * scale), + height: Math.round(img.height * scale), + left: (stageData.w - Math.round(img.width * scale)) / 2, + top: (stageData.h - Math.round(img.height * scale)) / 2 + }); + + // Store image initial data + $.extend(this.imageData, { + initWidth: img.width * scale, + initHeight: img.height * scale, + initLeft: (stageData.w - img.width * scale) / 2, + initTop: (stageData.h - img.height * scale) / 2, + width: img.width * scale, + height: img.height * scale, + left: (stageData.w - img.width * scale) / 2, + top: (stageData.h - img.height * scale) / 2 + }); + + // Set grab cursor + setGrabCursor({ + w: this.$image.width(), + h: this.$image.height() + }, { + w: this.$stage.width(), + h: this.$stage.height() + }, this.$stage, this.isRotated); + + // Just execute before image loaded + if (!this.imageLoaded) { + // Loader end + this.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Remove class after image loaded + this.$stage.removeClass('stage-ready'); + this.$image.removeClass('image-ready'); + + // Add init animation for image + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.fadeIn(); + } + this.imageLoaded = true; + } + } + }, { + key: "loadImage", + value: function loadImage(imgSrc, fn, err) { + var _this3 = this; + // Reset image + this.$image.removeAttr('style').attr('src', ''); + this.isRotated = false; + this.rotationDegree = 0; + this.imageLoaded = false; + + // Loader start + this.$photoviewer.append("")); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.hide(); + } + this.$image.attr('src', imgSrc); + preloadImage(imgSrc, function (img) { + // Store HTMLImageElement + _this3.img = img; + + // Store original data + _this3.imageData = { + originalWidth: img.width, + originalHeight: img.height + }; + if (_this3.isMaximized || _this3.isOpened && _this3.options.fixedModalPos) { + _this3.setImageSize(img); + } else { + _this3.setModalSize(img); + } + + // Callback of image loaded successfully + if (fn) { + fn.call(); + } + }, function () { + // Loader end + _this3.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Callback of image loading failed + if (err) { + err.call(); + } + }); + if (this.options.title) { + this.setImageTitle(imgSrc); + } + } + }, { + key: "setImageTitle", + value: function setImageTitle(url) { + var title = this.groupData[this.groupIndex].title || getImageNameFromUrl(url); + this.$title.html(title); + } + }, { + key: "jump", + value: function jump(step) { + this._triggerHook('beforeChange', [this, this.groupIndex]); + + // Make sure change image after the modal animation has finished + var now = Date.now(); + if (now - this._lastTimestamp >= this.options.animationDuration) { + this.groupIndex = this.groupIndex + step; + this.jumpTo(this.groupIndex); + this._lastTimestamp = now; + } + } + }, { + key: "jumpTo", + value: function jumpTo(index) { + var _this4 = this; + index = index % this.groupData.length; + if (index >= 0) { + index = index % this.groupData.length; + } else if (index < 0) { + index = (this.groupData.length + index) % this.groupData.length; + } + this.groupIndex = index; + this.loadImage(this.groupData[index].src, function () { + _this4._triggerHook('changed', [_this4, index]); + }, function () { + _this4._triggerHook('changed', [_this4, index]); + }); + } + }, { + key: "wheel", + value: function wheel(e) { + e.preventDefault(); + var delta = 1; + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + // Ratio threshold + var ratio = -delta * this.options.ratioThreshold; + + // Mouse point position relative to stage + var pointer = { + x: e.clientX - this.$stage.offset().left + $D.scrollLeft(), + y: e.clientY - this.$stage.offset().top + $D.scrollTop() + }; + this.zoom(ratio, pointer); + } + }, { + key: "zoom", + value: function zoom(ratio, origin) { + // Zoom out ratio & Zoom in ratio + ratio = ratio < 0 ? 1 / (1 - ratio) : 1 + ratio; + + // Image ratio + ratio = this.$image.width() / this.imageData.originalWidth * ratio; + if (ratio > this.options.maxRatio || ratio < this.options.minRatio) { + return; + } + this.zoomTo(ratio, origin); + } + }, { + key: "zoomTo", + value: function zoomTo(ratio, origin) { + var $image = this.$image; + var $stage = this.$stage; + var imgData = { + w: this.imageData.width, + h: this.imageData.height, + x: this.imageData.left, + y: this.imageData.top + }; + + // Image stage position + // We will use it to calc the relative position of image + var stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.offset().left, + y: $stage.offset().top + }; + + // Set default origin coordinates (center of stage) + if (origin === void 0) { + origin = { + x: $stage.width() / 2, + y: $stage.height() / 2 + }; + } + var newWidth = this.imageData.originalWidth * ratio; + var newHeight = this.imageData.originalHeight * ratio; + // Think about it for a while + var newLeft = origin.x - (origin.x - imgData.x) / imgData.w * newWidth; + var newTop = origin.y - (origin.y - imgData.y) / imgData.h * newHeight; + + // δ is the difference between image new width and new height + var δ = !this.isRotated ? 0 : (newWidth - newHeight) / 2; + var imgNewWidth = !this.isRotated ? newWidth : newHeight; + var imgNewHeight = !this.isRotated ? newHeight : newWidth; + var offsetX = stageData.w - newWidth; + var offsetY = stageData.h - newHeight; + + // Zoom out & Zoom in condition + // It's important and it takes me a lot of time to get it + // The conditions with image rotate 90 degree drive me crazy alomst! + if (imgNewHeight <= stageData.h) { + newTop = (stageData.h - newHeight) / 2; + } else { + newTop = newTop > δ ? δ : newTop > offsetY - δ ? newTop : offsetY - δ; + } + if (imgNewWidth <= stageData.w) { + newLeft = (stageData.w - newWidth) / 2; + } else { + newLeft = newLeft > -δ ? -δ : newLeft > offsetX + δ ? newLeft : offsetX + δ; + } + + // Whether the image scale get to the critical point + if (Math.abs(this.imageData.initWidth - newWidth) < this.imageData.initWidth * 0.05) { + this.setImageSize(this.img); + } else { + $image.css({ + width: Math.round(newWidth), + height: Math.round(newHeight), + left: Math.round(newLeft), + top: Math.round(newTop) + }); + + // Set grab cursor + setGrabCursor({ + w: Math.round(imgNewWidth), + h: Math.round(imgNewHeight) + }, { + w: stageData.w, + h: stageData.h + }, this.$stage); + } + + // Update image initial data + $.extend(this.imageData, { + width: newWidth, + height: newHeight, + left: newLeft, + top: newTop + }); + } + }, { + key: "rotate", + value: function rotate(degree) { + this.rotationDegree = this.rotationDegree + degree; + if (this.rotationDegree / 90 % 2 === 0) { + this.isRotated = false; + } else { + this.isRotated = true; + } + this.rotateTo(this.rotationDegree); + } + }, { + key: "rotateTo", + value: function rotateTo(degree) { + this.$image.css({ + transform: 'rotate(' + degree + 'deg)' + }); + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + + // Remove grab cursor when rotate + this.$stage.removeClass('is-grab'); + } + }, { + key: "resize", + value: function resize() { + if (this.isOpened) { + if (this.isMaximized) { + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } else { + this.setModalSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } + } + } + }, { + key: "maximize", + value: function maximize() { + this.$photoviewer.addClass(NS + '-maximized'); + this.$photoviewer.css({ + width: 'auto', + height: 'auto', + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + this.isMaximized = true; + } + }, { + key: "exitMaximize", + value: function exitMaximize() { + this.$photoviewer.removeClass(NS + '-maximized'); + this.setModalToCenter(); + this.isMaximized = false; + } + }, { + key: "toggleMaximize", + value: function toggleMaximize() { + if (!this.isMaximized) { + var originalWidth = this.$photoviewer.width(); + var originalHeight = this.$photoviewer.height(); + if (isBorderBox(this.$photoviewer)) { + originalWidth += this._modalEdgeValue.horizontal; + originalHeight += this._modalEdgeValue.vertical; + } + + // Store modal's size and position before maximized + this.modalData = { + width: originalWidth, + height: originalHeight, + left: parseFloat(this.$photoviewer.css('left')), + top: parseFloat(this.$photoviewer.css('top')) + }; + this.maximize(); + } else { + this.exitMaximize(); + } + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + this.$photoviewer[0].focus(); + } + }, { + key: "fullscreen", + value: function fullscreen() { + requestFullscreen(this.$photoviewer[0]); + this.$photoviewer[0].focus(); + } + }, { + key: "_keydown", + value: function _keydown(e) { + if (!this.options.keyboard) { + return false; + } + e.preventDefault(); + var keyCode = e.keyCode || e.which || e.charCode; + var ctrlKey = e.ctrlKey || e.metaKey; + var altKey = e.altKey; + switch (keyCode) { + // ← + case 37: + this.jump(-1); + break; + // → + case 39: + this.jump(1); + break; + // + + case 187: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - + case 189: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // + Firefox + case 61: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - Firefox + case 173: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // Ctrl + Alt + 0 + case 48: + if (ctrlKey && altKey) { + this.zoomTo(1, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + } + break; + // Ctrl + , + case 188: + if (ctrlKey) { + this.rotate(-90); + } + break; + // Ctrl + . + case 190: + if (ctrlKey) { + this.rotate(90); + } + break; + // Q + case 81: + this.close(); + break; + // Alt + X + case 88: + if (altKey) { + this.toggleMaximize(); + } + break; + // F + case 70: + this.fullscreen(); + break; + } + } + }, { + key: "_addEvents", + value: function _addEvents() { + var _this5 = this; + this.$close.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.close(); + }); + this.$stage.off(WHEEL_EVENT + EVENT_NS).on(WHEEL_EVENT + EVENT_NS, function (e) { + _this5.wheel(e); + }); + this.$zoomIn.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(_this5.options.ratioThreshold * 3); + }); + this.$zoomOut.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(-_this5.options.ratioThreshold * 3); + }); + this.$actualSize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoomTo(1); + }); + this.$prev.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(-1); + }); + this.$fullscreen.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.fullscreen(); + }); + this.$next.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(1); + }); + this.$rotateLeft.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(-90); + }); + this.$rotateRight.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(90); + }); + this.$maximize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.toggleMaximize(); + }); + this.$photoviewer.off(KEYDOWN_EVENT + EVENT_NS).on(KEYDOWN_EVENT + EVENT_NS, function (e) { + _this5._keydown(e); + }); + $W.on(RESIZE_EVENT + EVENT_NS, debounce(function () { + return _this5.resize(); + }, 500)); + } + }, { + key: "_addCustomButtonEvents", + value: function _addCustomButtonEvents() { + var _this6 = this; + var _loop = function _loop(btnKey) { + _this6.$photoviewer.find(CLASS_NS + '-button-' + btnKey).off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function (e) { + _this6.options.customButtons[btnKey].click.apply(_this6, [_this6, e]); + }); + }; + for (var btnKey in this.options.customButtons) { + _loop(btnKey); + } + } + }, { + key: "_triggerHook", + value: function _triggerHook(e, data) { + if (this.options.callbacks[e]) { + this.options.callbacks[e].apply(this, $.isArray(data) ? data : [data]); + } + } + }]); + return PhotoViewer; +}(); +/** + * Add methods to PhotoViewer + */ +$.extend(PhotoViewer.prototype, draggable, movable, resizable); + +/** + * Add PhotoViewer to globle + */ +window.PhotoViewer = PhotoViewer; + +export { PhotoViewer as default }; diff --git a/WebRoot/html/ypzs/view/js/photoviewer.js b/WebRoot/html/ypzs/view/js/photoviewer.js new file mode 100644 index 0000000..167010c --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.js @@ -0,0 +1,2757 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.photoviewer = factory()); +})(this, (function () { 'use strict'; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + // Class D + var D = function (selector, context) { + return new D.fn.init(selector, context); + }; + + var document$1 = window.document, + emptyArray = [], + concat = emptyArray.concat, + filter = emptyArray.filter, + slice = emptyArray.slice, + elementDisplay = {}, + classCache = {}, + cssNumber = { + 'column-count': 1, + 'columns': 1, + 'font-weight': 1, + 'line-height': 1, + 'opacity': 1, + 'z-index': 1, + 'zoom': 1 + }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + table = document$1.createElement('table'), + tableRow = document$1.createElement('tr'), + containers = { + 'tr': document$1.createElement('tbody'), + 'tbody': table, + 'thead': table, + 'tfoot': table, + 'td': tableRow, + 'th': tableRow, + '*': document$1.createElement('div') + }, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + tempParent = document$1.createElement('div'), + isArray = Array.isArray || function (arg) { + return Object.prototype.toString.call(arg) === '[object Array]'; + }, + contains = document$1.documentElement.contains + ? function (parent, node) { + return parent !== node && parent.contains(node); + } + : function (parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true; + return false; + }; + + function type(obj) { + return obj == null + ? String(obj) + : class2type[toString.call(obj)] || 'object'; + } + + function isFunction(value) { + return type(value) == 'function'; + } + + function isWindow(obj) { + return obj != null && obj == obj.window; + } + + function isDocument(obj) { + return obj != null && obj.nodeType == obj.DOCUMENT_NODE; + } + + function isObject(obj) { + return type(obj) == 'object'; + } + + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype; + } + + function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + typeRes = type(obj); + + return 'function' != typeRes && !isWindow(obj) && ( + 'array' == typeRes || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ); + } + + function compact(array) { + return filter.call(array, function (item) { + return item != null; + }); + } + + function dasherize$1(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase(); + } + + function maybeAddPx(name, value) { + return (typeof value == 'number' && !cssNumber[dasherize$1(name)]) ? value + 'px' : value; + } + + function camelize(str) { + return str.replace(/-+(.)?/g, function (match, chr) { + return chr ? chr.toUpperCase() : ''; + }); + } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')); + } + + function defaultDisplay(nodeName) { + var element, display; + if (!elementDisplay[nodeName]) { + element = document$1.createElement(nodeName); + document$1.body.appendChild(element); + display = getComputedStyle(element, '').getPropertyValue('display'); + element.parentNode.removeChild(element); + display == 'none' && (display = 'block'); + elementDisplay[nodeName] = display; + } + return elementDisplay[nodeName]; + } + + function flatten(array) { + return array.length > 0 ? D.fn.concat.apply([], array) : array; + } + + function isD(object) { + return object instanceof D; + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg; + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value); + } + + // access className property while respecting SVGAnimatedString + function className(node, value) { + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined; + + if (value === undefined) return svg ? klass.baseVal : klass; + svg ? (klass.baseVal = value) : (node.className = value); + } + + D.fn = D.prototype = { + constuctor: D, + length: 0, + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + // D's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + init: function (selector, context) { + var dom; + // If nothing given, return an empty D collection + if (!selector) { + return this; + } + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim(); + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) { + dom = D.fragment(selector, RegExp.$1, context); + selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // If it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) { + return D(document$1).ready(selector); + } + // If a D collection is given, just return it + else if (isD(selector)) { + return selector; + } + // normalize array if an array of nodes is given + else if (isArray(selector)) { + dom = compact(selector); + } + // Wrap DOM nodes. + else if (isObject(selector)) { + dom = [selector], selector = null; + } + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) { + return D(context).find(selector); + } + // And last but no least, if it's a CSS selector, use it to select nodes. + else { + dom = D.qsa(document$1, selector); + } + // create a new D collection from the nodes found + return D.makeArray(dom, selector, this); + }, + // Modify the collection by adding elements to it + concat: function () { + var i, value, args = []; + for (i = 0; i < arguments.length; i++) { + value = arguments[i]; + args[i] = isD(value) ? value.toArray() : value; + } + return concat.apply(isD(this) ? this.toArray() : this, args); + }, + // `pluck` is borrowed from Prototype.js + pluck: function (property) { + return D.map(this, function (el) { return el[property]; }); + }, + toArray: function () { + return this.get(); + }, + get: function (idx) { + return idx === undefined + ? slice.call(this) + : this[idx >= 0 ? idx : idx + this.length]; + }, + size: function () { + return this.length; + }, + each: function (callback) { + emptyArray.every.call(this, function (el, idx) { + return callback.call(el, idx, el) !== false; + }); + return this; + }, + map: function (fn) { + return D(D.map(this, function (el, i) { return fn.call(el, i, el); })); + }, + slice: function () { + return D(slice.apply(this, arguments)); + }, + first: function () { + var el = this[0]; + return el && !isObject(el) ? el : D(el); + }, + last: function () { + var el = this[this.length - 1]; + return el && !isObject(el) ? el : D(el); + }, + eq: function (idx) { + return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1); + } + }; + + D.extend = D.fn.extend = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === 'boolean') { + deep = target; + + // Skip the boolean and the target + target = arguments[i] || {}; + i++; + } + // Handle case when target is a string or something (possible in deep copy) + if (typeof target !== 'object' && !isFunction(target)) { + target = {}; + } + // Extend D itself if only one argument is passed + if (i === length) { + target = this; + i--; + } + for (; i < length; i++) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + src = target[name]; + copy = options[name]; + // Prevent never-ending loop + if (target === copy) { + continue; + } + // Recurse if we're merging plain objects or arrays + if (deep && copy && (isPlainObject(copy) || + (copyIsArray = isArray(copy)))) { + if (copyIsArray) { + copyIsArray = false; + clone = src && isArray(src) ? src : []; + } else { + clone = src && isPlainObject(src) ? src : {}; + } + // Never move original objects, clone them + target[name] = D.extend(deep, clone, copy); + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; + } + } + } + } + // Return the modified object + return target; + }; + + D.extend({ + // Make DOM Array + makeArray: function (dom, selector, me) { + var i, len = dom ? dom.length : 0; + for (i = 0; i < len; i++) me[i] = dom[i]; + me.length = len; + me.selector = selector || ''; + return me; + }, + // D's CSS selector + qsa: function (element, selector) { + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + // Ensure that a 1 char tag name still gets checked + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, + isSimple = simpleSelectorRE.test(nameOnly); + return ( + // Safari DocumentFragment doesn't have getElementById + element.getElementById && isSimple && maybeID) + // eslint-disable-next-line no-cond-assign + ? (found = element.getElementById(nameOnly)) + ? [found] + : [] + : element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11 + ? [] + : slice.call( + // DocumentFragment doesn't have getElementsByClassName/TagName + isSimple && !maybeID && element.getElementsByClassName + ? maybeClass + // If it's simple, it could be a class + ? element.getElementsByClassName(nameOnly) + // Or a tag + : element.getElementsByTagName(selector) + // Or it's not simple, and we need to query all + : element.querySelectorAll(selector) + ); + }, + // Html -> Node + fragment: function (html, name, properties) { + var dom, nodes, container; + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = D(document$1.createElement(RegExp.$1)); + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, '<$1>$2>'); + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1; + if (!(name in containers)) name = '*'; + + container = containers[name]; + container.innerHTML = '' + html; + dom = D.each(slice.call(container.childNodes), function () { + container.removeChild(this); + }); + } + + if (isPlainObject(properties)) { + nodes = D(dom); + D.each(properties, function (key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value); + else nodes.attr(key, value); + }); + } + + return dom; + }, + matches: function (element, selector) { + if (!selector || !element || element.nodeType !== 1) return false; + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector; + if (matchesSelector) return matchesSelector.call(element, selector); + // fall back to performing a selector: + var match, parent = element.parentNode, + temp = !parent; + if (temp) (parent = tempParent).appendChild(element); + match = ~D.qsa(parent, selector).indexOf(element); + temp && tempParent.removeChild(element); + return match; + }, + each: function (elements, callback) { + var i, key; + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements; + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements; + } + + return elements; + }, + map: function (elements, callback) { + var value, values = [], + i, key; + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i); + if (value != null) values.push(value); + } + else + for (key in elements) { + value = callback(elements[key], key); + if (value != null) values.push(value); + } + return flatten(values); + } + }); + + // Populate the class2type map + D.each('Boolean Number String Function Array Date RegExp Object Error'.split(' '), function (i, name) { + class2type['[object ' + name + ']'] = name.toLowerCase(); + }); + + D.fn.init.prototype = D.fn; + + function noop() { + } + + function css(property, value) { + if (arguments.length < 2) { + var element = this[0]; + if (typeof property == 'string') { + if (!element) return; + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property); + } else if (isArray(property)) { + if (!element) return; + var props = {}; + var computedStyle = getComputedStyle(element, ''); + D.each(property, function (_, prop) { + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)); + }); + return props; + } + } + + var css = ''; + if (type(property) == 'string') { + if (!value && value !== 0) { + this.each(function () { + this.style.removeProperty(dasherize$1(property)); + }); + } else { + css = dasherize$1(property) + ':' + maybeAddPx(property, value); + } + } else { + for (var key in property) { + if (!property[key] && property[key] !== 0) { + this.each(function () { this.style.removeProperty(dasherize$1(key)); }); + } else { + css += dasherize$1(key) + ':' + maybeAddPx(key, property[key]) + ';'; + } + } + } + + return this.each(function () { this.style.cssText += ';' + css; }); + } + + function hasClass(name) { + if (!name) return false; + return emptyArray.some.call(this, function (el) { + return this.test(className(el)); + }, classRE(name)); + } + + function addClass(name) { + var classList = []; + if (!name) return this; + return this.each(function (idx) { + if (!('className' in this)) return; + classList = []; + var cls = className(this), + newName = funcArg(this, name, idx, cls); + newName.split(/\s+/g).forEach(function (klass) { + if (!D(this).hasClass(klass)) classList.push(klass); + }, this); + classList.length && className(this, cls + (cls ? ' ' : '') + classList.join(' ')); + }); + } + + function removeClass(name) { + var classList = []; + return this.each(function (idx) { + if (!('className' in this)) return; + if (name === undefined) return className(this, ''); + classList = className(this); + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function (klass) { + classList = classList.replace(classRE(klass), ' '); + }); + className(this, classList.trim()); + }); + } + + function offset(coordinates) { + if (coordinates) return this.each(function (index) { + var $this = D(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + }; + + if ($this.css('position') == 'static') props['position'] = 'relative'; + $this.css(props); + }); + if (!this.length) return null; + if (document$1.documentElement !== this[0] && !contains(document$1.documentElement, this[0])) + return { top: 0, left: 0 }; + var obj = this[0].getBoundingClientRect(); + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + }; + } + + function position() { + if (!this.length) return; + + var elem = this[0], offset, + // Get *real* offset parent + offsetParent = this.offsetParent(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); + + // `position: fixed` elements are offset from the viewport, which itself always has zero offset + if (D(elem).css('position') === 'fixed') { + // Assume `position: fixed` implies availability of getBoundingClientRect + offset = elem.getBoundingClientRect(); + } else { + offset = this.offset(); + + // Incorporate borders into its offset, since they are outside its content origin + parentOffset.top += parseFloat(D(offsetParent[0]).css('border-top-width')) || 0; + parentOffset.left += parseFloat(D(offsetParent[0]).css('border-left-width')) || 0; + } + + // Subtract parent offsets and element margins + // note: when an element has `margin: auto` the offsetLeft and marginLeft + // are the same in Safari causing `offset.left` to incorrectly be 0 + return { + top: offset.top - parentOffset.top - parseFloat(D(elem).css('margin-top')) || 0, + left: offset.left - parentOffset.left - parseFloat(D(elem).css('margin-left')) || 0 + }; + } + + function scrollTop(value) { + if (!this.length) return; + var hasScrollTop = 'scrollTop' in this[0]; + if (value === undefined) return hasScrollTop + ? this[0].scrollTop + : isWindow(this[0]) + ? this[0].pageYOffset + : this[0].defaultView.pageYOffset; + return this.each(hasScrollTop ? + function () { this.scrollTop = value; } : + function () { this.scrollTo(this.scrollX, value); }); + } + + function scrollLeft(value) { + if (!this.length) return; + var hasScrollLeft = 'scrollLeft' in this[0]; + if (value === undefined) return hasScrollLeft + ? this[0].scrollLeft + : isWindow(this[0]) + ? this[0].pageXOffset + : this[0].defaultView.pageXOffset; + return this.each(hasScrollLeft ? + function () { this.scrollLeft = value; } : + function () { this.scrollTo(value, this.scrollY); }); + } + + function offsetParent() { + return this.map(function () { + var parent = this.offsetParent || document$1.body; + while (parent && !rootNodeRE.test(parent.nodeName) && D(parent).css('position') == 'static') + parent = parent.offsetParent; + return parent; + }); + } + + function attr(name, value) { + var result; + return (typeof name == 'string' && !(1 in arguments)) + ? (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null + ? result + : undefined) + : this.each(function (idx) { + if (this.nodeType !== 1) return; + if (isObject(name)) + for (var key in name) setAttribute(this, key, name[key]); + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))); + }); + } + + function removeAttr(name) { + return this.each(function () { + this.nodeType === 1 && name.split(' ').forEach(function (attribute) { + setAttribute(this, attribute); + }, this); + }); + } + + function find(selector) { + var result, $this = this; + if (!selector) result = D(); + else if (typeof selector == 'object') + result = D(selector).filter(function () { + var node = this; + return emptyArray.some.call($this, function (parent) { + return contains(parent, node); + }); + }); + else if (this.length == 1) result = D(D.qsa(this[0], selector)); + else result = this.map(function () { return D.qsa(this, selector); }); + return result; + } + + function closest(selector, context) { + var nodes = [], + collection = typeof selector == 'object' && D(selector); + this.each(function (_, node) { + while (node && !(collection ? collection.indexOf(node) >= 0 : D.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode; + if (node && nodes.indexOf(node) < 0) nodes.push(node); + }); + return D(nodes); + } + + function isIE() { + var ua = window.navigator.userAgent; + var msie = ua.indexOf('MSIE '); + return msie > 0 || !!navigator.userAgent.match(/Trident.*rv:11\./); + } + + function subtract(el, dimen) { + var offsetMap = { + width: ['padding-left', 'padding-right', 'border-left-width', 'border-right-width'], + height: ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width'] + }; + return el.css('box-sizing') === 'border-box' && !isIE() + ? parseFloat(el.css(dimen)) + - parseFloat(el.css(offsetMap[dimen][0])) + - parseFloat(el.css(offsetMap[dimen][1])) + - parseFloat(el.css(offsetMap[dimen][2])) + - parseFloat(el.css(offsetMap[dimen][3])) + : parseFloat(el.css(dimen)); + } + + function calc(dimension, value) { + var dimensionProperty = dimension.replace(/./, function (m) { return m[0].toUpperCase(); }); + var el = this[0]; + if (value === undefined) return isWindow(el) + ? el.document.documentElement['client' + dimensionProperty] + : isDocument(el) + ? el.documentElement['scroll' + dimensionProperty] + : subtract(this, dimension); + else return this.each(function (idx) { + el = D(this); + el.css(dimension, funcArg(this, value, idx, el[dimension]())); + }); + } + + // Export + + function width(value) { + return calc.call(this, 'width', value); + } + + function height(value) { + return calc.call(this, 'height', value); + } + + var traverseNode = function (node, fn) { + fn(node); + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fn); + }; + + // inside => append, prepend + var domMani = function (elem, args, fn, inside) { + // arguments can be nodes, arrays of nodes, D objects and HTML strings + var argType, + nodes = D.map(args, function (arg) { + var arr = []; + argType = type(arg); + if (argType == 'array') { + arg.forEach(function (el) { + if (el.nodeType !== undefined) return arr.push(el); + else if (isD(el)) return arr = arr.concat(el.get()); + arr = arr.concat(D.fragment(el)); + }); + return arr; + } + return argType == 'object' || arg == null ? arg : D.fragment(arg); + }), + parent, + copyByClone = elem.length > 1; + + if (nodes.length < 1) return elem; + + return elem.each(function (_, target) { + parent = inside ? target : target.parentNode; + var parentInDocument = contains(document$1.documentElement, parent); + + nodes.forEach(function (node) { + if (copyByClone) node = node.cloneNode(true); + else if (!parent) return D(node).remove(); + + fn.call(target, node); + + if (parentInDocument) { + traverseNode(node, function (el) { + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) { + var target = el.ownerDocument ? el.ownerDocument.defaultView : window; + target['eval'].call(target, el.innerHTML); + } + }); + } + }); + }); + }; + + // Export + + function remove$1() { + return this.each(function () { + if (this.parentNode != null) + this.parentNode.removeChild(this); + }); + } + + function empty() { + return this.each(function () { this.innerHTML = ''; }); + } + + function html(html) { + return 0 in arguments + ? this.each(function (idx) { + var originHtml = this.innerHTML; + D(this).empty().append(funcArg(this, html, idx, originHtml)); + }) + : (0 in this ? this[0].innerHTML : null); + } + + function append() { + return domMani(this, arguments, function (elem) { + this.insertBefore(elem, null); + }, true); + } + + var _zid = 1; + function zid(element) { + return element._zid || (element._zid = _zid++); + } + + function isString(obj) { + return typeof obj == 'string'; + } + + var returnTrue = function () { return true; }, + returnFalse = function () { return false; }, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + }; + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event); + + D.each(eventMethods, function (name, predicate) { + var sourceMethod = source[name]; + event[name] = function () { + this[predicate] = returnTrue; + return sourceMethod && sourceMethod.apply(source, arguments); + }; + event[predicate] = returnFalse; + }); + + try { + event.timeStamp || (event.timeStamp = Date.now()); + } catch (ignored) { + console.warn(ignored); + } + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue; + } + return event; + } + + var handlers = {}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/; + + function parse(event) { + var parts = ('' + event).split('.'); + return { e: parts[0], ns: parts.slice(1).sort().join(' ') }; + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)'); + } + + function findHandlers(element, event, fn, selector) { + event = parse(event); + if (event.ns) var matcher = matcherFor(event.ns); + return (handlers[zid(element)] || []).filter(function (handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector); + }); + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting; + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type; + } + + function add(element, events, fn, data, selector, delegator, capture) { + var id = zid(element), set = (handlers[id] || (handlers[id] = [])); + events.split(/\s/).forEach(function (event) { + if (event == 'ready') return D(document$1).ready(fn); + var handler = parse(event); + handler.fn = fn; + handler.sel = selector; + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function (e) { + var related = e.relatedTarget; + if (!related || (related !== this && !contains(this, related))) + return handler.fn.apply(this, arguments); + }; + handler.del = delegator; + var callback = delegator || fn; + handler.proxy = function (e) { + e = compatible(e); + if (e.isImmediatePropagationStopped()) return; + e.data = data; + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)); + if (result === false) e.preventDefault(), e.stopPropagation(); + return result; + }; + handler.i = set.length; + set.push(handler); + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); + } + + function remove(element, events, fn, selector, capture) { + var id = zid(element); + (events || '').split(/\s/).forEach(function (event) { + findHandlers(element, event, fn, selector).forEach(function (handler) { + delete handlers[id][handler.i]; + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)); + }); + }); + } + + function createProxy(event) { + var key, proxy = { originalEvent: event }; + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]; + + return compatible(proxy, event); + } + + var on = function (event, selector, data, callback, one) { + var autoRemove, delegator, $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.on(type, selector, data, fn, one); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined; + if (callback === undefined || data === false) + callback = data, data = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function (_, element) { + if (one) autoRemove = function (e) { + remove(element, e.type, callback); + return callback.apply(this, arguments); + }; + + if (selector) delegator = function (e) { + var evt, match = D(e.target).closest(selector, element).get(0); + if (match && match !== element) { + evt = D.extend(createProxy(e), { currentTarget: match, liveFired: element }); + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))); + } + }; + + add(element, event, callback, data, selector, delegator || autoRemove); + }); + }; + + var off = function (event, selector, callback) { + var $this = this; + if (event && !isString(event)) { + D.each(event, function (type, fn) { + $this.off(type, selector, fn); + }); + return $this; + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined; + + if (callback === false) callback = returnFalse; + + return $this.each(function () { + remove(this, event, callback, selector); + }); + }; + + var prefix = '', + eventPrefix, + vendors = { Webkit: 'webkit', Moz: '', O: 'o' }, + testEl = document$1.createElement('div'), + testTransitionProperty = testEl.style.transitionProperty; + + if (testEl.style.transform === undefined) D.each(vendors, function (vendor, event) { + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + vendor.toLowerCase() + '-'; + eventPrefix = event; + return false; + } + }); + + testEl = null; + + // fx cannot seperate + function normalizeEvent(name) { + return eventPrefix ? eventPrefix + name : name.toLowerCase(); + } + + D.fx = { + off: (eventPrefix === undefined && testTransitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') + }; + + var supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, transitionDelay, + animationName, animationDuration, animationTiming, animationDelay, + cssReset = {}; + + function dasherize(str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); } + + transform = prefix + 'transform'; + cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionDelay = prefix + 'transition-delay'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationDelay = prefix + 'animation-delay'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = ''; + + var anim$1 = function (properties, duration, ease, callback, delay) { + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = D.fx.transitionEnd, + fired = false; + + if (duration === undefined) duration = D.fx.speeds._default / 1000; + if (delay === undefined) delay = 0; + if (D.fx.off) duration = 0; + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties; + cssValues[animationDuration] = duration + 's'; + cssValues[animationDelay] = delay + 's'; + cssValues[animationTiming] = (ease || 'linear'); + endEvent = D.fx.animationEnd; + } else { + cssProperties = []; + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '; + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)); + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform); + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', '); + cssValues[transitionDuration] = duration + 's'; + cssValues[transitionDelay] = delay + 's'; + cssValues[transitionTiming] = (ease || 'linear'); + } + } + + wrappedCallback = function (event) { + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return; // makes sure the event didn't bubble from "below" + D(event.target).off(endEvent, wrappedCallback); + } else + D(this).off(endEvent, wrappedCallback); // triggered by setTimeout + + fired = true; + D(this).css(cssReset); + callback && callback.call(this); + }; + if (duration > 0) { + this.on(endEvent, wrappedCallback); + // transitionEnd is not always firing on older Android phones + // so make sure it gets fired + setTimeout(function () { + if (fired) return; + wrappedCallback.call(that); + }, ((duration + delay) * 1000) + 25); + } + + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft; + + this.css(cssValues); + + if (duration <= 0) setTimeout(function () { + that.each(function () { wrappedCallback.call(this); }); + }, 0); + + return this; + }; + + var animate = function (properties, duration, ease, callback, delay) { + if (isFunction(duration)) + callback = duration, ease = undefined, duration = undefined; + if (isFunction(ease)) + callback = ease, ease = undefined; + if (isPlainObject(duration)) + ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration; + if (duration) duration = (typeof duration == 'number' ? duration : + (D.fx.speeds[duration] || D.fx.speeds._default)) / 1000; + if (delay) delay = parseFloat(delay) / 1000; + return this.anim(properties, duration, ease, callback, delay); + }; + + var origShow = function () { + return this.each(function () { + this.style.display == 'none' && (this.style.display = ''); + if (getComputedStyle(this, '').getPropertyValue('display') == 'none') + this.style.display = defaultDisplay(this.nodeName); + }); + }; + + var origHide = function () { + return this.css('display', 'none'); + }; + + function anim(el, speed, opacity, scale, callback) { + if (typeof speed == 'function' && !callback) callback = speed, speed = undefined; + var props = { opacity: opacity }; + if (scale) { + props.scale = scale; + el.css(D.fx.cssPrefix + 'transform-origin', '0 0'); + } + return el.animate(props, speed, null, callback); + } + + function hideHelper(el, speed, scale, callback) { + return anim(el, speed, 0, scale, function () { + origHide.call(D(this)); + callback && callback.call(this); + }); + } + + // Export + + var show = function (speed, callback) { + origShow.call(this); + if (speed === undefined) speed = 0; + else this.css('opacity', 0); + return anim(this, speed, 1, '1,1', callback); + }; + + var hide = function (speed, callback) { + if (speed === undefined) return origHide.call(this); + else return hideHelper(this, speed, '0,0', callback); + }; + + var fadeTo = function (speed, opacity, callback) { + return anim(this, speed, opacity, null, callback); + }; + + var fadeIn = function (speed, callback) { + var target = this.css('opacity'); + if (target > 0) this.css('opacity', 0); + else target = 1; + return origShow.call(this).fadeTo(speed, target, callback); + }; + + var $ = D; + var methods = { + isPlainObject: isPlainObject, + isArray: isArray, + noop: noop + }; + var fnMethods = { + find: find, + closest: closest, + css: css, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass, + attr: attr, + removeAttr: removeAttr, + append: append, + remove: remove$1, + empty: empty, + html: html, + width: width, + height: height, + scrollTop: scrollTop, + scrollLeft: scrollLeft, + offset: offset, + offsetParent: offsetParent, + position: position, + on: on, + off: off, + show: show, + hide: hide, + anim: anim$1, + animate: animate, + fadeTo: fadeTo, + fadeIn: fadeIn + }; + $.extend(methods); + $.fn.extend(fnMethods); + + var DEFAULTS = { + // Whether to enable modal dragging + draggable: true, + // Whether to enable modal resizing + resizable: true, + // Whether to enable image moving + movable: true, + // Whether to enable keyboard navigation + keyboard: true, + // Whether to show the title + title: true, + // Min width of modal + modalWidth: 320, + // Min height of modal + modalHeight: 320, + // Whether to change the modal size after image loaded + fixedModalSize: false, + // Whether to set maximized on init + initMaximized: false, + // Threshold of modal relative to browser window + gapThreshold: 0.02, + // Threshold of image ratio + ratioThreshold: 0.1, + // Min ratio of image when zoom out + minRatio: 0.05, + // Max ratio of image when zoom in + maxRatio: 16, + // Toolbar options in header + headerToolbar: ['maximize', 'close'], + // Toolbar options in footer + footerToolbar: ['zoomIn', 'zoomOut', 'prev', 'fullscreen', 'next', 'actualSize', 'rotateRight'], + // Custom icon for button + icons: { + minimize: "\n \n ", + maximize: "\n \n ", + close: "\n \n ", + zoomIn: "\n \n ", + zoomOut: "\n \n ", + prev: "\n \n ", + next: "\n \n ", + fullscreen: "\n \n ", + actualSize: "\n \n ", + rotateLeft: "\n \n ", + rotateRight: "\n \n " + }, + // Custom title for button + i18n: { + minimize: 'Minimize', + maximize: 'Maximize (Alt+X)', + close: 'Close (Q)', + zoomIn: 'Zoom-in (+)', + zoomOut: 'Zoom-out (-)', + prev: 'Prev (←)', + next: 'Next (→)', + fullscreen: 'Fullscreen (F)', + actualSize: 'Actual-size (Ctrl+Alt+0)', + rotateLeft: 'Rotate-left (Ctrl+,)', + rotateRight: 'Rotate-right (Ctrl+.)' + }, + // Whether to enable multiple instances + multiInstances: true, + // Whether to enable modal transform animation + initAnimation: true, + // Modal transform animation duration + animationDuration: 400, + // Whether to disable modal translate to center after image changed + fixedModalPos: false, + // Modal css `z-index` + zIndex: 1090, + // Selector of drag handler + dragHandle: null, + // Callback events + callbacks: { + beforeOpen: $.noop, + opened: $.noop, + beforeClose: $.noop, + closed: $.noop, + beforeChange: $.noop, + changed: $.noop + }, + // Start index of images + index: 0, + // Whether to load the image progressively + progressiveLoading: true, + // The DOM element which photoviewer will be attached to + appendTo: 'body', + // Custom Buttons + customButtons: {}, + // Whether to set modal css `position: fixed` + positionFixed: true, + // Init modal position `{top: 0, right: 0, bottom: 0, left: 0}` + initModalPos: null + }; + + var document = window.document; + + /** + * Debounce function + * + * @param {function} fn - The function will be triggered + * @param {number} delay - The debounce delay time + * @return {function} + */ + function debounce(fn, delay) { + var timer = null; + return function () { + var context = this; + var args = arguments; + clearTimeout(timer); + timer = setTimeout(function () { + fn.apply(context, args); + }, delay); + }; + } + + /** + * Preload a image + * + * @param {string} src - The image src + * @param {function} success - The callback of success + * @param {function} error - The callback of error + */ + function preloadImage(src, success, error) { + var img = new Image(); + img.onload = function () { + success(img); + }; + img.onerror = function () { + error(img); + }; + img.src = src; + } + + /** + * Request fullscreen + * + * @param {type} element + */ + function requestFullscreen(element) { + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } + } + + /** + * Get the image name from its url + * + * @param {string} url - The image src + * @return {string} + */ + function getImageNameFromUrl(url) { + var reg = /^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/gi; + var txt = url.replace(reg, '$1'); + return txt; + } + + /** + * Set grab cursor when move image + * + * @param {object} imageData - The image data + * @param {object} stageData - The stage data + * @param {object} $stage - The stage element of domq + * @param {boolean} isRotate - The image rotated flag + */ + function setGrabCursor(imageData, stageData, $stage, isRotated) { + var imageWidth = !isRotated ? imageData.w : imageData.h; + var imageHeight = !isRotated ? imageData.h : imageData.w; + if (imageHeight > stageData.h || imageWidth > stageData.w) { + $stage.addClass('is-grab'); + } + if (imageHeight <= stageData.h && imageWidth <= stageData.w) { + $stage.removeClass('is-grab'); + } + } + + /** + * Check whether browser support touch event + * + * @return {boolean} + */ + function supportTouch() { + return !!('ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch); + } + + /** + * Check whether element is root node (`body` or `html`) + * + * @param {object} elem - The DOM element + * @return {boolean} + */ + function isRootNode(elem) { + return /^(?:body|html)$/i.test(elem.nodeName); + } + + /** + * Get sum value of CSS props + * + * @param {object} $elem - The domq element + * @param {array} props - The array of CSS props + * @return {number} + */ + function getCSSValueSum($elem, props) { + return props.reduce(function (acc, cur) { + return acc + parseFloat($elem.css(cur)); + }, 0); + } + + /** + * Check whether element's CSS `box-sizing` is `border-box` + * + * @param {object} $elem - The domq element + * @return {boolean} + */ + function isBorderBox($elem) { + return $elem.css('box-sizing') === 'border-box'; + } + + var $W = $(window); + var $D = $(document); + var CLICK_EVENT = 'click'; + var RESIZE_EVENT = 'resize'; + var KEYDOWN_EVENT = 'keydown'; + var WHEEL_EVENT = 'wheel mousewheel DOMMouseScroll'; + var TOUCH_START_EVENT = supportTouch() ? 'touchstart' : 'mousedown'; + var TOUCH_MOVE_EVENT = supportTouch() ? 'touchmove' : 'mousemove'; + var TOUCH_END_EVENT = supportTouch() ? 'touchend' : 'mouseup'; + var NS = 'photoviewer'; + var CLASS_NS = '.' + NS; + var EVENT_NS = '.' + NS; + var PUBLIC_VARS = { + // Whether image is moving + isMoving: false, + // Whether modal is resizing + isResizing: false, + // Modal's `z-index` + zIndex: 0 + }; + + var draggable = { + /** + * Modal draggable + * + * @param {object} $modal - The modal element of domq + * @param {object} dragHandle - The handle element when dragging + * @param {object} dragCancel - The cancel element when dragging + */ + draggable: function draggable($modal, dragHandle, dragCancel) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + + // Must be removed + // e.preventDefault(); + + // Fix focus scroll issue on Chrome + $modal[0].blur(); + + // Get clicked button + var elemCancel = $(e.target).closest(dragCancel); + // Stop modal moving when click buttons + if (elemCancel.length) { + return true; + } + if (_this.options.multiInstances) { + $modal.css('z-index', ++PUBLIC_VARS['zIndex']); + } + isDragging = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Get current position of the modal + left = parseFloat($modal.css('left')); + top = parseFloat($modal.css('top')); + + // Reset modal position with left and top + $modal.css({ + left: left, + top: top, + right: '', + bottom: '' + }); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !PUBLIC_VARS['isMoving'] && !PUBLIC_VARS['isResizing'] && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + $modal.css({ + left: relativeX + left, + top: relativeY + top + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + + // Focus must be executed after drag end + $modal[0].focus(); + }; + $(dragHandle).on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } + }; + + var ELEMS_WITH_GRABBING_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button, .").concat(NS, "-resizable-handle"); + var movable = { + /** + * Image movable + * + * 1. No movable + * 2. Vertical movable + * 3. Horizontal movable + * 4. Vertical & Horizontal movable + * + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + */ + movable: function movable($stage, $image) { + var _this = this; + var isDragging = false; + var startX = 0; + var startY = 0; + var left = 0; + var top = 0; + var widthDiff = 0; + var heightDiff = 0; + var δ = 0; + var dragStart = function dragStart(e) { + e = e || window.event; + e.preventDefault(); + var imageWidth = $image.width(); + var imageHeight = $image.height(); + var stageWidth = $stage.width(); + var stageHeight = $stage.height(); + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageWidth - imageHeight) / 2; + + // Width or height difference can be use to limit image right or top position + widthDiff = !_this.isRotated ? imageWidth - stageWidth : imageHeight - stageWidth; + heightDiff = !_this.isRotated ? imageHeight - stageHeight : imageWidth - stageHeight; + + // Modal can be dragging if image is smaller to stage + isDragging = widthDiff > 0 || heightDiff > 0 ? true : false; + PUBLIC_VARS['isMoving'] = widthDiff > 0 || heightDiff > 0 ? true : false; + + // Reclac the element position when mousedown + // Fix the issue of stage with a border + left = $image.position().left - δ; + top = $image.position().top + δ; + + // Add grabbing cursor + if ($stage.hasClass('is-grab')) { + $(ELEMS_WITH_GRABBING_CURSOR).addClass('is-grabbing'); + } + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var newLeft = relativeX + left; + var newTop = relativeY + top; + + // Vertical limit + if (heightDiff > 0) { + if (relativeY + top > δ) { + newTop = δ; + } else if (relativeY + top < -heightDiff + δ) { + newTop = -heightDiff + δ; + } + } else { + newTop = top; + } + // Horizontal limit + if (widthDiff > 0) { + if (relativeX + left > -δ) { + newLeft = -δ; + } else if (relativeX + left < -widthDiff - δ) { + newLeft = -widthDiff - δ; + } + } else { + newLeft = left; + } + $image.css({ + left: newLeft, + top: newTop + }); + + // Update image initial data + $.extend(_this.imageData, { + left: newLeft, + top: newTop + }); + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + isDragging = false; + PUBLIC_VARS['isMoving'] = false; + + // Remove grabbing cursor + $(ELEMS_WITH_GRABBING_CURSOR).removeClass('is-grabbing'); + }; + $stage.on(TOUCH_START_EVENT + EVENT_NS, dragStart); + } + }; + + var ELEMS_WITH_RESIZE_CURSOR = "html, body, .".concat(NS, "-modal, .").concat(NS, "-stage, .").concat(NS, "-button"); + var resizable = { + /** + * Modal resizable + * + * 1. Can be resized in 8 directions + * 2. Keep image in stage center + * 3. Other restrictions for image + * + * @param {object} $modal - The modal element of domq + * @param {object} $stage - The stage element of domq + * @param {object} $image - The image element of domq + * @param {number} minWidth - The modalWidth option + * @param {number} minHeight - The modalHeight option + */ + resizable: function resizable($modal, $stage, $image, minWidth, minHeight) { + var _this = this; + var resizableHandleE = $("")); + var resizableHandleW = $("")); + var resizableHandleS = $("")); + var resizableHandleN = $("")); + var resizableHandleSE = $("")); + var resizableHandleSW = $("")); + var resizableHandleNE = $("")); + var resizableHandleNW = $("")); + var resizableHandles = { + e: resizableHandleE, + s: resizableHandleS, + se: resizableHandleSE, + n: resizableHandleN, + w: resizableHandleW, + nw: resizableHandleNW, + ne: resizableHandleNE, + sw: resizableHandleSW + }; + $modal.append(resizableHandleE, resizableHandleW, resizableHandleS, resizableHandleN, resizableHandleSE, resizableHandleSW, resizableHandleNE, resizableHandleNW); + var isDragging = false; + var startX = 0; + var startY = 0; + var modalData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var stageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + var imageData = { + w: 0, + h: 0, + x: 0, + y: 0 + }; + // δ is the difference between image width and height + var δ = 0; + var imgWidth = 0; + var imgHeight = 0; + var direction = ''; + + // Modal CSS options + var getModalOpts = function getModalOpts(dir, offsetX, offsetY) { + // Modal should not move when its width to the minwidth + var modalLeft = -offsetX + modalData.w > minWidth ? offsetX + modalData.x : modalData.x + modalData.w - minWidth; + var modalTop = -offsetY + modalData.h > minHeight ? offsetY + modalData.y : modalData.y + modalData.h - minHeight; + var opts = { + e: { + width: Math.max(offsetX + modalData.w, minWidth) + }, + s: { + height: Math.max(offsetY + modalData.h, minHeight) + }, + se: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight) + }, + w: { + width: Math.max(-offsetX + modalData.w, minWidth), + left: modalLeft + }, + n: { + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + nw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop, + left: modalLeft + }, + ne: { + width: Math.max(offsetX + modalData.w, minWidth), + height: Math.max(-offsetY + modalData.h, minHeight), + top: modalTop + }, + sw: { + width: Math.max(-offsetX + modalData.w, minWidth), + height: Math.max(offsetY + modalData.h, minHeight), + left: modalLeft + } + }; + return opts[dir]; + }; + + // Image CSS options + var getImageOpts = function getImageOpts(dir, offsetX, offsetY) { + // Image should not move when modal width to the min width + // The minwidth is modal width, so we should clac the stage minwidth + var widthDiff = offsetX + modalData.w > minWidth ? stageData.w - imgWidth + offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff = offsetY + modalData.h > minHeight ? stageData.h - imgHeight + offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + var widthDiff2 = -offsetX + modalData.w > minWidth ? stageData.w - imgWidth - offsetX - δ : minWidth - (modalData.w - stageData.w) - imgWidth - δ; + var heightDiff2 = -offsetY + modalData.h > minHeight ? stageData.h - imgHeight - offsetY + δ : minHeight - (modalData.h - stageData.h) - imgHeight + δ; + + // Get image position in dragging + var imgLeft = (widthDiff > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop = (heightDiff > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var imgLeft2 = (widthDiff2 > 0 ? $image.position().left : $image.position().left < 0 ? $image.position().left : 0) - δ; + var imgTop2 = (heightDiff2 > 0 ? $image.position().top : $image.position().top < 0 ? $image.position().top : 0) + δ; + var opts = { + e: { + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + s: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff + }, + se: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + w: { + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + n: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2 + }, + nw: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + }, + ne: { + top: heightDiff2 >= δ ? (heightDiff2 + δ) / 2 : imgTop2 > heightDiff2 ? imgTop2 : heightDiff2, + left: widthDiff >= -δ ? (widthDiff - δ) / 2 : imgLeft > widthDiff ? imgLeft : widthDiff + }, + sw: { + top: heightDiff >= δ ? (heightDiff + δ) / 2 : imgTop > heightDiff ? imgTop : heightDiff, + left: widthDiff2 >= -δ ? (widthDiff2 - δ) / 2 : imgLeft2 > widthDiff2 ? imgLeft2 : widthDiff2 + } + }; + return opts[dir]; + }; + var dragStart = function dragStart(dir, e) { + e = e || window.event; + e.preventDefault(); + isDragging = true; + PUBLIC_VARS['isResizing'] = true; + startX = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.clientX; + startY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.clientY; + + // Reclac the modal data when mousedown + modalData = { + w: $modal.width() + (isBorderBox($modal) ? _this._modalEdgeValue.horizontal : 0), + h: $modal.height() + (isBorderBox($modal) ? _this._modalEdgeValue.vertical : 0), + x: $modal.position().left, + y: $modal.position().top + }; + stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.position().left, + y: $stage.position().top + }; + imageData = { + w: $image.width(), + h: $image.height(), + x: $image.position().left, + y: $image.position().top + }; + + // δ is the difference between image width and height + δ = !_this.isRotated ? 0 : (imageData.w - imageData.h) / 2; + imgWidth = !_this.isRotated ? imageData.w : imageData.h; + imgHeight = !_this.isRotated ? imageData.h : imageData.w; + direction = dir; + + // Add resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', dir + '-resize'); + $D.on(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).on(TOUCH_END_EVENT + EVENT_NS, dragEnd); + }; + var dragMove = function dragMove(e) { + e = e || window.event; + e.preventDefault(); + if (isDragging && !_this.isMaximized) { + var endX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.clientX; + var endY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.clientY; + var relativeX = endX - startX; + var relativeY = endY - startY; + var modalOpts = getModalOpts(direction, relativeX, relativeY); + $modal.css(modalOpts); + var imageOpts = getImageOpts(direction, relativeX, relativeY); + $image.css(imageOpts); + _this.isDoResize = true; + } + }; + var dragEnd = function dragEnd() { + $D.off(TOUCH_MOVE_EVENT + EVENT_NS, dragMove).off(TOUCH_END_EVENT + EVENT_NS, dragEnd); + + // Set grab cursor + if (PUBLIC_VARS['isResizing']) { + setGrabCursor({ + w: imgWidth, + h: imgHeight + }, { + w: $stage.width(), + h: $stage.height() + }, $stage); + } + isDragging = false; + PUBLIC_VARS['isResizing'] = false; + + // Remove resizable cursor + $(ELEMS_WITH_RESIZE_CURSOR).css('cursor', ''); + + // Update image initial data + var scale = _this.getImageScale($stage.width(), $stage.height()); + $.extend(_this.imageData, { + initWidth: _this.img.width * scale, + initHeight: _this.img.height * scale, + initLeft: ($stage.width() - _this.img.width * scale) / 2, + initTop: ($stage.height() - _this.img.height * scale) / 2 + }); + }; + $.each(resizableHandles, function (dir, handle) { + handle.on(TOUCH_START_EVENT + EVENT_NS, function (e) { + dragStart(dir, e); + }); + }); + } + }; + + /** + * PhotoViewer class + */ + var PhotoViewer = /*#__PURE__*/function () { + function PhotoViewer(items, options, el) { + _classCallCheck(this, PhotoViewer); + this.options = $.extend(true, {}, DEFAULTS, options); + if (options && $.isArray(options.footerToolbar)) { + this.options.footerToolbar = options.footerToolbar; + } + if (options && $.isArray(options.headerToolbar)) { + this.options.headerToolbar = options.headerToolbar; + } + + // Store element of clicked + this.$el = $(el); + + // As we have multiple instances, so every instance has the following variables. + + // Whether modal opened + this.isOpened = false; + + // Whether modal maximized + this.isMaximized = false; + + // Whether image rotated (`90*(2n+1)`) + this.isRotated = false; + + // Image rotation degree + this.rotationDegree = 0; + + // Whether modal do resize + this.isDoResize = false; + + // Store image data in every instance + this.imageData = {}; + + // Store modal data in every instance + this.modalData = { + width: null, + height: null, + left: null, + top: null + }; + + // Used for time comparison + this._lastTimestamp = 0; + this.init(items, this.options); + } + _createClass(PhotoViewer, [{ + key: "init", + value: function init(items, opts) { + this.groupData = items; + this.groupIndex = opts['index']; + + // Reset public z-index with option + PUBLIC_VARS['zIndex'] = PUBLIC_VARS['zIndex'] === 0 ? opts['zIndex'] : PUBLIC_VARS['zIndex']; + + // Get image src + var imgSrc = items[this.groupIndex]['src']; + this.open(); + this.loadImage(imgSrc); + if (opts.draggable) { + this.draggable(this.$photoviewer, this.dragHandle, CLASS_NS + '-button'); + } + if (opts.movable) { + this.movable(this.$stage, this.$image); + } + if (opts.resizable) { + this.resizable(this.$photoviewer, this.$stage, this.$image, opts.modalWidth, opts.modalHeight); + } + } + }, { + key: "_createBtns", + value: function _createBtns(toolbar) { + var _this = this; + var btns = ['minimize', 'maximize', 'close', 'zoomIn', 'zoomOut', 'prev', 'next', 'fullscreen', 'actualSize', 'rotateLeft', 'rotateRight']; + var btnsHTML = ''; + $.each(toolbar, function (index, item) { + var btnClass = "".concat(NS, "-button ").concat(NS, "-button-").concat(item); + if (btns.indexOf(item) >= 0) { + btnsHTML += "\n ").concat(_this.options.icons[item], "\n "); + } else if (_this.options.customButtons[item]) { + btnsHTML += "\n ").concat(_this.options.customButtons[item].text, "\n "); + } + }); + return btnsHTML; + } + }, { + key: "_createTitle", + value: function _createTitle() { + return this.options.title ? "") : ''; + } + }, { + key: "_createTemplate", + value: function _createTemplate() { + // PhotoViewer base HTML + var photoviewerHTML = "\n \n \n \n ").concat(this._createBtns(this.options.headerToolbar), "\n \n ").concat(this._createTitle(), "\n \n \n \n \n \n \n ").concat(this._createBtns(this.options.footerToolbar), "\n \n \n \n "); + return photoviewerHTML; + } + }, { + key: "build", + value: function build() { + // Create PhotoViewer HTML string + var photoviewerHTML = this._createTemplate(); + + // Make PhotoViewer HTML string to jQuery element + var $photoviewer = $(photoviewerHTML); + + // Get all PhotoViewer elements + this.$photoviewer = $photoviewer; + this.$stage = $photoviewer.find(CLASS_NS + '-stage'); + this.$title = $photoviewer.find(CLASS_NS + '-title'); + this.$image = $photoviewer.find(CLASS_NS + '-image'); + this.$close = $photoviewer.find(CLASS_NS + '-button-close'); + this.$maximize = $photoviewer.find(CLASS_NS + '-button-maximize'); + this.$minimize = $photoviewer.find(CLASS_NS + '-button-minimize'); + this.$zoomIn = $photoviewer.find(CLASS_NS + '-button-zoomIn'); + this.$zoomOut = $photoviewer.find(CLASS_NS + '-button-zoomOut'); + this.$actualSize = $photoviewer.find(CLASS_NS + '-button-actualSize'); + this.$fullscreen = $photoviewer.find(CLASS_NS + '-button-fullscreen'); + this.$rotateLeft = $photoviewer.find(CLASS_NS + '-button-rotateLeft'); + this.$rotateRight = $photoviewer.find(CLASS_NS + '-button-rotateRight'); + this.$prev = $photoviewer.find(CLASS_NS + '-button-prev'); + this.$next = $photoviewer.find(CLASS_NS + '-button-next'); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + + // Reset modal `z-index` of multiple instances + this.$photoviewer.css('z-index', PUBLIC_VARS['zIndex']); + if (this.options.positionFixed) { + this.$photoviewer.css({ + position: 'fixed' + }); + } + + // Set handle element of draggable + if (!this.options.dragHandle || this.options.dragHandle === CLASS_NS + '-modal') { + this.dragHandle = this.$photoviewer; + } else { + this.dragHandle = this.$photoviewer.find(this.options.dragHandle); + } + + // Add PhotoViewer to DOM + $(this.options.appendTo).eq(0).append(this.$photoviewer); + + // Store the edge value of stage + this._stageEdgeValue = { + horizontal: getCSSValueSum(this.$stage, ['left', 'right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$stage, ['top', 'bottom', 'border-top-width', 'border-bottom-width']) + }; + + // Store the edge value of modal + this._modalEdgeValue = { + horizontal: getCSSValueSum(this.$photoviewer, ['padding-left', 'padding-right', 'border-left-width', 'border-right-width']), + vertical: getCSSValueSum(this.$photoviewer, ['padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width']) + }; + this._addEvents(); + this._addCustomButtonEvents(); + } + }, { + key: "open", + value: function open() { + this._triggerHook('beforeOpen', this); + if (!this.options.multiInstances) { + $(CLASS_NS + '-modal').eq(0).remove(); + } + this.build(); + this.setInitModalPos(); + this._triggerHook('opened', this); + } + }, { + key: "close", + value: function close() { + this._triggerHook('beforeClose', this); + + // Remove PhotoViewer instance + this.$photoviewer.remove(); + this.isOpened = false; + this.isMaximized = false; + this.isRotated = false; + this.rotationDegree = 0; + if (!$(CLASS_NS + '-modal').length) { + // Reset `z-index` after close + if (this.options.multiInstances) { + PUBLIC_VARS['zIndex'] = this.options.zIndex; + } + + // Off resize event + $W.off(RESIZE_EVENT + EVENT_NS); + } + this._triggerHook('closed', this); + } + }, { + key: "_getOffsetParentData", + value: function _getOffsetParentData() { + var offsetParent = $(this.options.appendTo)[0]; + return { + width: this.options.positionFixed || isRootNode(offsetParent) ? $W.width() : offsetParent.clientWidth, + height: this.options.positionFixed || isRootNode(offsetParent) ? $W.height() : offsetParent.clientHeight, + scrollLeft: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollLeft() : offsetParent.scrollLeft, + scrollTop: this.options.positionFixed ? 0 : isRootNode(offsetParent) ? $D.scrollTop() : offsetParent.scrollTop + }; + } + }, { + key: "setModalToCenter", + value: function setModalToCenter() { + var initLeft, initTop, initRight, initBottom; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (!isBorderBox(this.$photoviewer)) { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + if ($.isPlainObject(this.options.initModalPos)) { + initLeft = this.options.initModalPos.left; + initTop = this.options.initModalPos.top; + initRight = this.options.initModalPos.right; + initBottom = this.options.initModalPos.bottom; + } else { + var offsetParentData = this._getOffsetParentData(); + initLeft = (offsetParentData.width - this.options.modalWidth - extraWidth) / 2 + offsetParentData.scrollLeft; + initTop = (offsetParentData.height - this.options.modalHeight - extraHeight) / 2 + offsetParentData.scrollTop; + } + var modalInitCSS = { + width: this.modalData.width || this.options.modalWidth, + height: this.modalData.height || this.options.modalHeight, + left: this.modalData.left || initLeft, + top: this.modalData.top || initTop, + right: this.modalData.right || initRight, + bottom: this.modalData.bottom || initBottom + }; + this.$photoviewer.css(modalInitCSS); + } + }, { + key: "setInitModalPos", + value: function setInitModalPos() { + if (this.options.initMaximized) { + this.maximize(); + this.isOpened = true; + } else { + this.setModalToCenter(); + } + + // The focus must be set after opening + this.$photoviewer[0].focus(); + } + }, { + key: "setModalSize", + value: function setModalSize(img) { + var _this2 = this; + var offsetParentData = this._getOffsetParentData(); + + // Modal size should calculate with stage css value + var modalWidth = img.width + this._stageEdgeValue.horizontal; + var modalHeight = img.height + this._stageEdgeValue.vertical; + + // Extra width/height for `content-box` + var extraWidth = 0, + extraHeight = 0; + if (isBorderBox(this.$photoviewer)) { + modalWidth += this._modalEdgeValue.horizontal; + modalHeight += this._modalEdgeValue.vertical; + } else { + extraWidth += this._modalEdgeValue.horizontal; + extraHeight += this._modalEdgeValue.vertical; + } + var gapThreshold = (this.options.gapThreshold > 0 ? this.options.gapThreshold : 0) + 1; + + // Modal scale relative to parent element + var scale = Math.min(offsetParentData.width / ((modalWidth + extraWidth) * gapThreshold), offsetParentData.height / ((modalHeight + extraHeight) * gapThreshold), 1); + var minWidth = Math.max(modalWidth * scale, this.options.modalWidth); + var minHeight = Math.max(modalHeight * scale, this.options.modalHeight); + minWidth = this.options.fixedModalSize ? this.options.modalWidth : Math.round(minWidth); + minHeight = this.options.fixedModalSize ? this.options.modalHeight : Math.round(minHeight); + var transLeft, transTop, transRight, transBottom; + if ($.isPlainObject(this.options.initModalPos)) { + transLeft = this.options.initModalPos.left; + transTop = this.options.initModalPos.top; + transRight = this.options.initModalPos.right; + transBottom = this.options.initModalPos.bottom; + } else { + var _offsetParentData = this._getOffsetParentData(); + transLeft = (_offsetParentData.width - minWidth - extraWidth) / 2 + _offsetParentData.scrollLeft; + transTop = (_offsetParentData.height - minHeight - extraHeight) / 2 + _offsetParentData.scrollTop; + } + var modalTransCSS = { + width: minWidth, + height: minHeight, + left: transLeft, + top: transTop, + right: transRight, + bottom: transBottom + }; + + // Add init animation for modal + if (this.options.initAnimation) { + this.$photoviewer.animate(modalTransCSS, this.options.animationDuration, 'ease-in-out', function () { + _this2.setImageSize(img); + }); + } else { + this.$photoviewer.css(modalTransCSS); + this.setImageSize(img); + } + this.isOpened = true; + } + }, { + key: "getImageScale", + value: function getImageScale(stageWidth, stageHeight) { + var scale = 1; + if (!this.isRotated) { + scale = Math.min(stageWidth / this.img.width, stageHeight / this.img.height, 1); + } else { + scale = Math.min(stageWidth / this.img.height, stageHeight / this.img.width, 1); + } + return scale; + } + }, { + key: "setImageSize", + value: function setImageSize(img) { + var stageData = { + w: this.$stage.width(), + h: this.$stage.height() + }; + var scale = this.getImageScale(stageData.w, stageData.h); + this.$image.css({ + width: Math.round(img.width * scale), + height: Math.round(img.height * scale), + left: (stageData.w - Math.round(img.width * scale)) / 2, + top: (stageData.h - Math.round(img.height * scale)) / 2 + }); + + // Store image initial data + $.extend(this.imageData, { + initWidth: img.width * scale, + initHeight: img.height * scale, + initLeft: (stageData.w - img.width * scale) / 2, + initTop: (stageData.h - img.height * scale) / 2, + width: img.width * scale, + height: img.height * scale, + left: (stageData.w - img.width * scale) / 2, + top: (stageData.h - img.height * scale) / 2 + }); + + // Set grab cursor + setGrabCursor({ + w: this.$image.width(), + h: this.$image.height() + }, { + w: this.$stage.width(), + h: this.$stage.height() + }, this.$stage, this.isRotated); + + // Just execute before image loaded + if (!this.imageLoaded) { + // Loader end + this.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Remove class after image loaded + this.$stage.removeClass('stage-ready'); + this.$image.removeClass('image-ready'); + + // Add init animation for image + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.fadeIn(); + } + this.imageLoaded = true; + } + } + }, { + key: "loadImage", + value: function loadImage(imgSrc, fn, err) { + var _this3 = this; + // Reset image + this.$image.removeAttr('style').attr('src', ''); + this.isRotated = false; + this.rotationDegree = 0; + this.imageLoaded = false; + + // Loader start + this.$photoviewer.append("")); + + // Add class before image loaded + this.$stage.addClass('stage-ready'); + this.$image.addClass('image-ready'); + if (this.options.initAnimation && !this.options.progressiveLoading) { + this.$image.hide(); + } + this.$image.attr('src', imgSrc); + preloadImage(imgSrc, function (img) { + // Store HTMLImageElement + _this3.img = img; + + // Store original data + _this3.imageData = { + originalWidth: img.width, + originalHeight: img.height + }; + if (_this3.isMaximized || _this3.isOpened && _this3.options.fixedModalPos) { + _this3.setImageSize(img); + } else { + _this3.setModalSize(img); + } + + // Callback of image loaded successfully + if (fn) { + fn.call(); + } + }, function () { + // Loader end + _this3.$photoviewer.find(CLASS_NS + '-loader').remove(); + + // Callback of image loading failed + if (err) { + err.call(); + } + }); + if (this.options.title) { + this.setImageTitle(imgSrc); + } + } + }, { + key: "setImageTitle", + value: function setImageTitle(url) { + var title = this.groupData[this.groupIndex].title || getImageNameFromUrl(url); + this.$title.html(title); + } + }, { + key: "jump", + value: function jump(step) { + this._triggerHook('beforeChange', [this, this.groupIndex]); + + // Make sure change image after the modal animation has finished + var now = Date.now(); + if (now - this._lastTimestamp >= this.options.animationDuration) { + this.groupIndex = this.groupIndex + step; + this.jumpTo(this.groupIndex); + this._lastTimestamp = now; + } + } + }, { + key: "jumpTo", + value: function jumpTo(index) { + var _this4 = this; + index = index % this.groupData.length; + if (index >= 0) { + index = index % this.groupData.length; + } else if (index < 0) { + index = (this.groupData.length + index) % this.groupData.length; + } + this.groupIndex = index; + this.loadImage(this.groupData[index].src, function () { + _this4._triggerHook('changed', [_this4, index]); + }, function () { + _this4._triggerHook('changed', [_this4, index]); + }); + } + }, { + key: "wheel", + value: function wheel(e) { + e.preventDefault(); + var delta = 1; + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + // Ratio threshold + var ratio = -delta * this.options.ratioThreshold; + + // Mouse point position relative to stage + var pointer = { + x: e.clientX - this.$stage.offset().left + $D.scrollLeft(), + y: e.clientY - this.$stage.offset().top + $D.scrollTop() + }; + this.zoom(ratio, pointer); + } + }, { + key: "zoom", + value: function zoom(ratio, origin) { + // Zoom out ratio & Zoom in ratio + ratio = ratio < 0 ? 1 / (1 - ratio) : 1 + ratio; + + // Image ratio + ratio = this.$image.width() / this.imageData.originalWidth * ratio; + if (ratio > this.options.maxRatio || ratio < this.options.minRatio) { + return; + } + this.zoomTo(ratio, origin); + } + }, { + key: "zoomTo", + value: function zoomTo(ratio, origin) { + var $image = this.$image; + var $stage = this.$stage; + var imgData = { + w: this.imageData.width, + h: this.imageData.height, + x: this.imageData.left, + y: this.imageData.top + }; + + // Image stage position + // We will use it to calc the relative position of image + var stageData = { + w: $stage.width(), + h: $stage.height(), + x: $stage.offset().left, + y: $stage.offset().top + }; + + // Set default origin coordinates (center of stage) + if (origin === void 0) { + origin = { + x: $stage.width() / 2, + y: $stage.height() / 2 + }; + } + var newWidth = this.imageData.originalWidth * ratio; + var newHeight = this.imageData.originalHeight * ratio; + // Think about it for a while + var newLeft = origin.x - (origin.x - imgData.x) / imgData.w * newWidth; + var newTop = origin.y - (origin.y - imgData.y) / imgData.h * newHeight; + + // δ is the difference between image new width and new height + var δ = !this.isRotated ? 0 : (newWidth - newHeight) / 2; + var imgNewWidth = !this.isRotated ? newWidth : newHeight; + var imgNewHeight = !this.isRotated ? newHeight : newWidth; + var offsetX = stageData.w - newWidth; + var offsetY = stageData.h - newHeight; + + // Zoom out & Zoom in condition + // It's important and it takes me a lot of time to get it + // The conditions with image rotate 90 degree drive me crazy alomst! + if (imgNewHeight <= stageData.h) { + newTop = (stageData.h - newHeight) / 2; + } else { + newTop = newTop > δ ? δ : newTop > offsetY - δ ? newTop : offsetY - δ; + } + if (imgNewWidth <= stageData.w) { + newLeft = (stageData.w - newWidth) / 2; + } else { + newLeft = newLeft > -δ ? -δ : newLeft > offsetX + δ ? newLeft : offsetX + δ; + } + + // Whether the image scale get to the critical point + if (Math.abs(this.imageData.initWidth - newWidth) < this.imageData.initWidth * 0.05) { + this.setImageSize(this.img); + } else { + $image.css({ + width: Math.round(newWidth), + height: Math.round(newHeight), + left: Math.round(newLeft), + top: Math.round(newTop) + }); + + // Set grab cursor + setGrabCursor({ + w: Math.round(imgNewWidth), + h: Math.round(imgNewHeight) + }, { + w: stageData.w, + h: stageData.h + }, this.$stage); + } + + // Update image initial data + $.extend(this.imageData, { + width: newWidth, + height: newHeight, + left: newLeft, + top: newTop + }); + } + }, { + key: "rotate", + value: function rotate(degree) { + this.rotationDegree = this.rotationDegree + degree; + if (this.rotationDegree / 90 % 2 === 0) { + this.isRotated = false; + } else { + this.isRotated = true; + } + this.rotateTo(this.rotationDegree); + } + }, { + key: "rotateTo", + value: function rotateTo(degree) { + this.$image.css({ + transform: 'rotate(' + degree + 'deg)' + }); + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + + // Remove grab cursor when rotate + this.$stage.removeClass('is-grab'); + } + }, { + key: "resize", + value: function resize() { + if (this.isOpened) { + if (this.isMaximized) { + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } else { + this.setModalSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + } + } + } + }, { + key: "maximize", + value: function maximize() { + this.$photoviewer.addClass(NS + '-maximized'); + this.$photoviewer.css({ + width: 'auto', + height: 'auto', + top: 0, + right: 0, + bottom: 0, + left: 0 + }); + this.isMaximized = true; + } + }, { + key: "exitMaximize", + value: function exitMaximize() { + this.$photoviewer.removeClass(NS + '-maximized'); + this.setModalToCenter(); + this.isMaximized = false; + } + }, { + key: "toggleMaximize", + value: function toggleMaximize() { + if (!this.isMaximized) { + var originalWidth = this.$photoviewer.width(); + var originalHeight = this.$photoviewer.height(); + if (isBorderBox(this.$photoviewer)) { + originalWidth += this._modalEdgeValue.horizontal; + originalHeight += this._modalEdgeValue.vertical; + } + + // Store modal's size and position before maximized + this.modalData = { + width: originalWidth, + height: originalHeight, + left: parseFloat(this.$photoviewer.css('left')), + top: parseFloat(this.$photoviewer.css('top')) + }; + this.maximize(); + } else { + this.exitMaximize(); + } + this.setImageSize({ + width: this.imageData.originalWidth, + height: this.imageData.originalHeight + }); + this.$photoviewer[0].focus(); + } + }, { + key: "fullscreen", + value: function fullscreen() { + requestFullscreen(this.$photoviewer[0]); + this.$photoviewer[0].focus(); + } + }, { + key: "_keydown", + value: function _keydown(e) { + if (!this.options.keyboard) { + return false; + } + e.preventDefault(); + var keyCode = e.keyCode || e.which || e.charCode; + var ctrlKey = e.ctrlKey || e.metaKey; + var altKey = e.altKey; + switch (keyCode) { + // ← + case 37: + this.jump(-1); + break; + // → + case 39: + this.jump(1); + break; + // + + case 187: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - + case 189: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // + Firefox + case 61: + this.zoom(this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // - Firefox + case 173: + this.zoom(-this.options.ratioThreshold * 3, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + break; + // Ctrl + Alt + 0 + case 48: + if (ctrlKey && altKey) { + this.zoomTo(1, { + x: this.$stage.width() / 2, + y: this.$stage.height() / 2 + }, e); + } + break; + // Ctrl + , + case 188: + if (ctrlKey) { + this.rotate(-90); + } + break; + // Ctrl + . + case 190: + if (ctrlKey) { + this.rotate(90); + } + break; + // Q + case 81: + this.close(); + break; + // Alt + X + case 88: + if (altKey) { + this.toggleMaximize(); + } + break; + // F + case 70: + this.fullscreen(); + break; + } + } + }, { + key: "_addEvents", + value: function _addEvents() { + var _this5 = this; + this.$close.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.close(); + }); + this.$stage.off(WHEEL_EVENT + EVENT_NS).on(WHEEL_EVENT + EVENT_NS, function (e) { + _this5.wheel(e); + }); + this.$zoomIn.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(_this5.options.ratioThreshold * 3); + }); + this.$zoomOut.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoom(-_this5.options.ratioThreshold * 3); + }); + this.$actualSize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.zoomTo(1); + }); + this.$prev.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(-1); + }); + this.$fullscreen.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.fullscreen(); + }); + this.$next.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.jump(1); + }); + this.$rotateLeft.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(-90); + }); + this.$rotateRight.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.rotate(90); + }); + this.$maximize.off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function () { + _this5.toggleMaximize(); + }); + this.$photoviewer.off(KEYDOWN_EVENT + EVENT_NS).on(KEYDOWN_EVENT + EVENT_NS, function (e) { + _this5._keydown(e); + }); + $W.on(RESIZE_EVENT + EVENT_NS, debounce(function () { + return _this5.resize(); + }, 500)); + } + }, { + key: "_addCustomButtonEvents", + value: function _addCustomButtonEvents() { + var _this6 = this; + var _loop = function _loop(btnKey) { + _this6.$photoviewer.find(CLASS_NS + '-button-' + btnKey).off(CLICK_EVENT + EVENT_NS).on(CLICK_EVENT + EVENT_NS, function (e) { + _this6.options.customButtons[btnKey].click.apply(_this6, [_this6, e]); + }); + }; + for (var btnKey in this.options.customButtons) { + _loop(btnKey); + } + } + }, { + key: "_triggerHook", + value: function _triggerHook(e, data) { + if (this.options.callbacks[e]) { + this.options.callbacks[e].apply(this, $.isArray(data) ? data : [data]); + } + } + }]); + return PhotoViewer; + }(); + /** + * Add methods to PhotoViewer + */ + $.extend(PhotoViewer.prototype, draggable, movable, resizable); + + /** + * Add PhotoViewer to globle + */ + window.PhotoViewer = PhotoViewer; + + return PhotoViewer; + +})); diff --git a/WebRoot/html/ypzs/view/js/photoviewer.min.css b/WebRoot/html/ypzs/view/js/photoviewer.min.css new file mode 100644 index 0000000..0323804 --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.min.css @@ -0,0 +1,16 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */.photoviewer-modal{position:absolute;z-index:1090;width:320px;height:320px;overflow:visible !important;color:#333;cursor:default;background-color:rgba(255,255,255,.92);border:1px solid rgba(0,0,0,.64);border-radius:6px;outline:none;box-shadow:0 2px 10px 2px rgba(0,0,0,.32)}.photoviewer-inner{position:absolute;top:0;left:0;right:0;bottom:0}.photoviewer-maximized{position:fixed;top:0;right:0;bottom:0;left:0;width:auto;height:auto}.photoviewer-maximized.photoviewer-modal{border-width:0;border-radius:0}.photoviewer-maximized .photoviewer-header{border-radius:0}.photoviewer-maximized .photoviewer-resizable-handle{display:none}.photoviewer-toolbar{font-size:0}.photoviewer-button{display:inline-block;min-width:40px;height:40px;box-sizing:border-box;margin:0;font-size:16px;line-height:1;text-align:center;background:none;border-width:0;border-radius:0;color:inherit;cursor:pointer;outline:none}.photoviewer-button:hover{color:#111}.photoviewer-button:focus{background-color:rgba(0,0,0,.08)}.photoviewer-button svg{display:inline-block;font-size:inherit;width:1em;height:1em;overflow:visible;vertical-align:-0.125em}.photoviewer-header{position:relative;z-index:2;height:30px;border-radius:5px 5px 0 0;overflow:hidden}.photoviewer-header .photoviewer-toolbar{float:right}[dir=rtl] .photoviewer-header .photoviewer-toolbar{float:left}.photoviewer-header .photoviewer-button{height:30px}.photoviewer-header .photoviewer-button:hover{background-color:rgba(0,0,0,.08)}.photoviewer-header .photoviewer-button-close:hover{color:#fff;background-color:#ff4545}.photoviewer-title{padding:8px 10px;font-size:14px;line-height:1;white-space:nowrap;text-overflow:ellipsis;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden}.photoviewer-stage{position:absolute;top:30px;right:0;bottom:40px;left:0;z-index:1;border-top:1px solid rgba(0,0,0,.64);border-bottom:1px solid rgba(0,0,0,.64);background-color:#fff;overflow:hidden}.photoviewer-stage.stage-ready{text-align:center;font-size:0}.photoviewer-stage.stage-ready::before{content:"";display:inline-block;height:100%;vertical-align:middle;overflow:hidden}.photoviewer-image{position:absolute;display:inline-block;min-width:auto;max-width:none}.photoviewer-image.image-ready{position:static;max-width:100%;max-height:100%;vertical-align:middle}.photoviewer-footer{position:absolute;bottom:0;z-index:2;width:100%;height:40px;text-align:center}.photoviewer-footer .photoviewer-toolbar{display:inline-block}[dir=rtl] .photoviewer-button-prev,[dir=rtl] .photoviewer-button-next{-ms-transform:rotate(180deg);transform:rotate(180deg)}.photoviewer-resizable-handle{position:absolute;z-index:10}.photoviewer-resizable-handle-e{top:0;right:-5px;bottom:0;left:auto;width:10px;cursor:e-resize}.photoviewer-resizable-handle-s{top:auto;right:0;bottom:-5px;left:0;height:10px;cursor:s-resize}.photoviewer-resizable-handle-w{top:0;right:auto;bottom:0;left:-5px;width:10px;cursor:w-resize}.photoviewer-resizable-handle-n{top:-5px;right:0;bottom:auto;left:0;height:10px;cursor:n-resize}.photoviewer-resizable-handle-se{top:auto;right:-5px;bottom:-5px;left:auto;width:10px;height:10px;cursor:se-resize}.photoviewer-resizable-handle-sw{top:auto;right:auto;bottom:-5px;left:-5px;width:10px;height:10px;cursor:sw-resize}.photoviewer-resizable-handle-nw{top:-5px;right:auto;bottom:auto;left:-5px;width:10px;height:10px;cursor:nw-resize}.photoviewer-resizable-handle-ne{top:-5px;right:-5px;bottom:auto;left:auto;width:10px;height:10px;cursor:ne-resize}:-webkit-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-webkit-full-screen .photoviewer-header,:-webkit-full-screen .photoviewer-footer,:-webkit-full-screen .photoviewer-resizable-handle{display:none}:-webkit-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-moz-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-moz-full-screen .photoviewer-header,:-moz-full-screen .photoviewer-footer,:-moz-full-screen .photoviewer-resizable-handle{display:none}:-moz-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-ms-fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-ms-fullscreen .photoviewer-header,:-ms-fullscreen .photoviewer-footer,:-ms-fullscreen .photoviewer-resizable-handle{display:none}:-ms-fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:full-screen .photoviewer-header,:full-screen .photoviewer-footer,:full-screen .photoviewer-resizable-handle{display:none}:full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-webkit-full-screen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-ms-fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:fullscreen{top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;width:100% !important;height:100% !important;background-color:rgba(0,0,0,0);border-width:0;border-radius:0}:-webkit-full-screen .photoviewer-header, :-webkit-full-screen .photoviewer-footer, :-webkit-full-screen .photoviewer-resizable-handle{display:none}:-ms-fullscreen .photoviewer-header, :-ms-fullscreen .photoviewer-footer, :-ms-fullscreen .photoviewer-resizable-handle{display:none}:fullscreen .photoviewer-header,:fullscreen .photoviewer-footer,:fullscreen .photoviewer-resizable-handle{display:none}:-webkit-full-screen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:-ms-fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}:fullscreen .photoviewer-stage{top:0;right:0;bottom:0;left:0;border-width:0;background-color:#000}::backdrop{background-color:#000}::-ms-backdrop{background-color:#000}.is-grab{cursor:move;cursor:grab}.is-grabbing{cursor:move;cursor:grabbing}.photoviewer-loader{position:absolute;top:30px;left:0;right:0;bottom:40px;z-index:2;text-align:center;color:#333}.photoviewer-loader::before{content:"";position:relative;display:inline-block;width:36px;height:36px;box-sizing:border-box;border-width:5px;border-style:solid;border-color:rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(255,255,255,.5);border-radius:100%;vertical-align:middle;animation:photoviewerLoading 1s infinite linear}.photoviewer-loader::after{content:"";display:inline-block;width:0;height:100%;vertical-align:middle;overflow:hidden}@keyframes photoviewerLoading{0%{transform:rotateZ(0deg) translate3d(0, 0, 0)}100%{transform:rotateZ(360deg) translate3d(0, 0, 0)}} + +/*# sourceMappingURL=photoviewer.min.css.map */ \ No newline at end of file diff --git a/WebRoot/html/ypzs/view/js/photoviewer.min.css.map b/WebRoot/html/ypzs/view/js/photoviewer.min.css.map new file mode 100644 index 0000000..43846e2 --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["","../src/sass/_general.scss","../src/sass/_resizable.scss","../src/sass/_fullscreen.scss","../src/sass/_helpers.scss","../src/sass/_loader.scss"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAAA,ACAA,mBACE,iBAAA,CACA,YAAA,CACA,WAAA,CACA,YAAA,CACA,2BAAA,CACA,UAAA,CACA,cAAA,CACA,sCAAA,CACA,gCAAA,CACA,iBAAA,CACA,YAAA,CACA,yCAAA,CAGF,mBACE,iBAAA,CACA,KAAA,CACA,MAAA,CACA,OAAA,CACA,QAAA,CAGF,uBACE,cAAA,CACA,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,UAAA,CACA,WAAA,CAEA,yCACE,cAAA,CACA,eAAA,CAGF,2CACE,eAAA,CAGF,qDACE,YAAA,CAIJ,qBACE,WAAA,CAGF,oBACE,oBAAA,CACA,cAAA,CACA,WAAA,CACA,qBAAA,CACA,QAAA,CACA,cAAA,CACA,aAAA,CACA,iBAAA,CACA,eAAA,CACA,cAAA,CACA,eAAA,CACA,aAAA,CACA,cAAA,CACA,YAAA,CAEA,0BACE,UAAA,CAGF,0BACE,gCAAA,CAGF,wBACE,oBAAA,CACA,iBAAA,CACA,SAAA,CACA,UAAA,CACA,gBAAA,CACA,uBAAA,CAIJ,oBACE,iBAAA,CACA,SAAA,CACA,WAAA,CACA,yBAAA,CACA,eAAA,CAEA,yCACE,WAAA,CAEA,mDACE,UAAA,CAIJ,wCACE,WAAA,CAEA,8CACE,gCAAA,CAKF,oDACE,UAAA,CACA,wBAAA,CAKN,mBACE,gBAAA,CACA,cAAA,CACA,aAAA,CACA,kBAAA,CACA,sBAAA,CACA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBAAA,CACA,eAAA,CAGF,mBACE,iBAAA,CACA,QAAA,CACA,OAAA,CACA,WAAA,CACA,MAAA,CACA,SAAA,CACA,oCAAA,CACA,uCAAA,CACA,qBAAA,CACA,eAAA,CAEA,+BACE,iBAAA,CACA,WAAA,CAEA,uCACE,UAAA,CACA,oBAAA,CACA,WAAA,CACA,qBAAA,CACA,eAAA,CAKN,mBACE,iBAAA,CACA,oBAAA,CACA,cAAA,CACA,cAAA,CAEA,+BACE,eAAA,CACA,cAAA,CACA,eAAA,CACA,qBAAA,CAIJ,oBACE,iBAAA,CACA,QAAA,CACA,SAAA,CACA,UAAA,CACA,WAAA,CACA,iBAAA,CAEA,yCACE,oBAAA,CAKF,sEAEE,wBAAA,CCrLJ,8BACE,iBAAA,CACA,UAAA,CAGF,gCACE,KAAA,CACA,UAAA,CACA,QAAA,CACA,SAAA,CACA,UAAA,CACA,eAAA,CAGF,gCACE,QAAA,CACA,OAAA,CACA,WAAA,CACA,MAAA,CACA,WAAA,CACA,eAAA,CAGF,gCACE,KAAA,CACA,UAAA,CACA,QAAA,CACA,SAAA,CACA,UAAA,CACA,eAAA,CAGF,gCACE,QAAA,CACA,OAAA,CACA,WAAA,CACA,MAAA,CACA,WAAA,CACA,eAAA,CAGF,iCACE,QAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CAGF,iCACE,QAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CAGF,iCACE,QAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CAGF,iCACE,QAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CACA,UAAA,CACA,WAAA,CACA,gBAAA,CC1EA,qBACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CAEA,qIAGE,YAAA,CAGF,wCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CAvBJ,kBACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CAEA,4HAGE,YAAA,CAGF,qCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CAvBJ,gBACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CAEA,sHAGE,YAAA,CAGF,mCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CAvBJ,aACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CAEA,6GAGE,YAAA,CAGF,gCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CAvBJ,qBACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CATF,gBACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CATF,YACE,gBAAA,CACA,kBAAA,CACA,mBAAA,CACA,iBAAA,CACA,qBAAA,CACA,sBAAA,CACA,8BAAA,CACA,cAAA,CACA,eAAA,CAEA,uIAGE,YAAA,CAHF,wHAGE,YAAA,CAHF,0GAGE,YAAA,CAGF,wCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CANF,mCACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CANF,+BACE,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,cAAA,CACA,qBAAA,CAMJ,WACE,qBAAA,CADF,eACE,qBAAA,CClCJ,SACE,WAAA,CAEA,WAAA,CAGF,aACE,WAAA,CAEA,eAAA,CCTF,oBACE,iBAAA,CACA,QAAA,CACA,MAAA,CACA,OAAA,CACA,WAAA,CACA,SAAA,CACA,iBAAA,CACA,UAAA,CAEA,4BACE,UAAA,CACA,iBAAA,CACA,oBAAA,CACA,UAAA,CACA,WAAA,CACA,qBAAA,CACA,gBAAA,CACA,kBAAA,CACA,8EAAA,CACA,kBAAA,CACA,qBAAA,CACA,+CAAA,CAGF,2BACE,UAAA,CACA,oBAAA,CACA,OAAA,CACA,WAAA,CACA,qBAAA,CACA,eAAA,CAIJ,8BACE,GACE,4CAAA,CAGF,KACE,8CAAA,CAAA","file":"photoviewer.min.css"} \ No newline at end of file diff --git a/WebRoot/html/ypzs/view/js/photoviewer.min.js b/WebRoot/html/ypzs/view/js/photoviewer.min.js new file mode 100644 index 0000000..c1ba8dd --- /dev/null +++ b/WebRoot/html/ypzs/view/js/photoviewer.min.js @@ -0,0 +1,15 @@ +/*! + * ____ __ ______ __________ _ _____________ ____________ + * / __ \/ / / / __ \/_ __/ __ \ | / / _/ ____/ | / / ____/ __ \ + * / /_/ / /_/ / / / / / / / / / / | / // // __/ | | /| / / __/ / /_/ / + * / ____/ __ / /_/ / / / / /_/ /| |/ // // /___ | |/ |/ / /___/ _, _/ + * /_/ /_/ /_/\____/ /_/ \____/ |___/___/_____/ |__/|__/_____/_/ |_| + * + * photoviewer - v3.7.1 + * A JS plugin to view images just like in Windows. + * https://nzbin.github.io/photoviewer/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).photoviewer=e()}(this,function(){"use strict";function D(t,e){for(var i=0;i]*>/,N=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,X=/^(?:body|html)$/i,W=["val","css","html","text","data","width","height","offset"],t=y.createElement("table"),e=y.createElement("tr"),q={tr:y.createElement("tbody"),tbody:t,thead:t,tfoot:t,td:e,th:e,"*":y.createElement("div")},Z=/^[\w-]*$/,U={},K=U.toString,Q=y.createElement("div"),l=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)},x=y.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e=e&&e.parentNode;)if(e===t)return!0;return!1};function h(t){return null==t?String(t):U[K.call(t)]||"object"}function c(t){return"function"==h(t)}function n(t){return null!=t&&t==t.window}function G(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function s(t){return"object"==h(t)}function u(t){return s(t)&&!n(t)&&Object.getPrototypeOf(t)==Object.prototype}function J(t){var e=!!t&&"length"in t&&t.length,i=h(t);return"function"!=i&&!n(t)&&("array"==i||0===e||"number"==typeof e&&0$2>")),void 0===e&&(e=B.test(t)&&RegExp.$1),(s=q[e=e in q?e:"*"]).innerHTML=""+t,o=w.each(b.call(s.childNodes),function(){s.removeChild(this)})),u(i)&&(n=w(o),w.each(i,function(t,e){-1\n \n ',maximize:'\n \n ',close:'\n \n ',zoomIn:'\n \n ',zoomOut:'\n \n ',prev:'\n \n ',next:'\n \n ',fullscreen:'\n \n ',actualSize:'\n \n ',rotateLeft:'\n \n ',rotateRight:'\n \n '},i18n:{minimize:"Minimize",maximize:"Maximize (Alt+X)",close:"Close (Q)",zoomIn:"Zoom-in (+)",zoomOut:"Zoom-out (-)",prev:"Prev (←)",next:"Next (→)",fullscreen:"Fullscreen (F)",actualSize:"Actual-size (Ctrl+Alt+0)",rotateLeft:"Rotate-left (Ctrl+,)",rotateRight:"Rotate-right (Ctrl+.)"},multiInstances:!0,initAnimation:!0,animationDuration:400,fixedModalPos:!1,zIndex:1090,dragHandle:null,callbacks:{beforeOpen:H.noop,opened:H.noop,beforeClose:H.noop,closed:H.noop,beforeChange:H.noop,changed:H.noop},index:0,progressiveLoading:!0,appendTo:"body",customButtons:{},positionFixed:!0,initModalPos:null}),Rt=window.document;function St(t,e,i,o){var n=o?t.h:t.w,o=o?t.w:t.h;(o>e.h||n>e.w)&&i.addClass("is-grab"),o<=e.h&&n<=e.w&&i.removeClass("is-grab")}function At(){return"ontouchstart"in window||window.DocumentTouch&&Rt instanceof window.DocumentTouch}function v(t){return/^(?:body|html)$/i.test(t.nodeName)}function T(i,t){return t.reduce(function(t,e){return t+parseFloat(i.css(e))},0)}function k(t){return"border-box"===t.css("box-sizing")}var Ot=H(window),V=H(Rt),C="click",Ft="keydown",jt="wheel mousewheel DOMMouseScroll",Bt=At()?"touchstart":"mousedown",E=At()?"touchmove":"mousemove",P=At()?"touchend":"mouseup",I="photoviewer",L="."+I,_="."+I,R={isMoving:!1,isResizing:!1,zIndex:0},t={draggable:function(i,t,e){var o=this,n=!1,s=0,a=0,r=0,h=0,l=function(t){var e;(t=t||window.event).preventDefault(),!n||R.isMoving||R.isResizing||o.isMaximized||(e="touchmove"===t.type?t.targetTouches[0].pageX:t.clientX,t="touchmove"===t.type?t.targetTouches[0].pageY:t.clientY,e=e-s,t=t-a,i.css({left:e+r,top:t+h}))},c=function t(){V.off(E+_,l).off(P+_,t),n=!1,i[0].focus()};H(t).on(Bt+_,function(t){if(t=t||window.event,i[0].blur(),H(t.target).closest(e).length)return!0;o.options.multiInstances&&i.css("z-index",++R.zIndex),n=!0,s="touchstart"===t.type?t.targetTouches[0].pageX:t.clientX,a="touchstart"===t.type?t.targetTouches[0].pageY:t.clientY,r=parseFloat(i.css("left")),h=parseFloat(i.css("top")),i.css({left:r,top:h,right:"",bottom:""}),V.on(E+_,l).on(P+_,c)})}},Nt="html, body, .".concat(I,"-modal, .").concat(I,"-stage, .").concat(I,"-button, .").concat(I,"-resizable-handle"),e={movable:function(s,a){function r(){V.off(E+_,v).off(P+_,r),l=!1,R.isMoving=!1,H(Nt).removeClass("is-grabbing")}var h=this,l=!1,c=0,u=0,d=0,f=0,p=0,g=0,m=0,v=function(t){var e,i,o;(t=t||window.event).preventDefault(),l&&(e="touchmove"===t.type?t.targetTouches[0].pageX:t.clientX,t="touchmove"===t.type?t.targetTouches[0].pageY:t.clientY,i=(e=e-c)+d,o=(t=t-u)+f,0')),e=H('')),i=H('')),a=H('')),r=H('')),h=H('')),d=H('')),f=H('')),p={e:t,s:i,se:r,n:a,w:e,nw:f,ne:d,sw:h},g=(o.append(t,e,i,a,r,h,d,f),!1),m=0,v=0,w={w:0,h:0,x:0,y:0},y={w:0,h:0,x:0,y:0},b={w:0,h:0,x:0,y:0},x=0,z=0,$=0,M="",T=function(t,e,i){var o=-e+w.w>c?e+w.x:w.x+w.w-c,n=-i+w.h>u?i+w.y:w.y+w.h-u;return{e:{width:Math.max(e+w.w,c)},s:{height:Math.max(i+w.h,u)},se:{width:Math.max(e+w.w,c),height:Math.max(i+w.h,u)},w:{width:Math.max(-e+w.w,c),left:o},n:{height:Math.max(-i+w.h,u),top:n},nw:{width:Math.max(-e+w.w,c),height:Math.max(-i+w.h,u),top:n,left:o},ne:{width:Math.max(e+w.w,c),height:Math.max(-i+w.h,u),top:n},sw:{width:Math.max(-e+w.w,c),height:Math.max(i+w.h,u),left:o}}[t]},C=function(t,e,i){var o=e+w.w>c?y.w-z+e-x:c-(w.w-y.w)-z-x,n=i+w.h>u?y.h-$+i+x:u-(w.h-y.h)-$+x,e=-e+w.w>c?y.w-z-e-x:c-(w.w-y.w)-z-x,i=-i+w.h>u?y.h-$-i+x:u-(w.h-y.h)-$+x,s=(0\n ').concat(o.options.icons[e],"\n "):o.options.customButtons[e]&&(s+='\n ').concat(o.options.customButtons[e].text,"\n "))}),s}},{key:"_createTitle",value:function(){return this.options.title?''):""}},{key:"_createTemplate",value:function(){return'\n \n \n \n ').concat(this._createBtns(this.options.headerToolbar),"\n \n ").concat(this._createTitle(),'\n \n \n \n \n \n \n ")}},{key:"build",value:function(){var t=this._createTemplate(),t=H(t);this.$photoviewer=t,this.$stage=t.find(L+"-stage"),this.$title=t.find(L+"-title"),this.$image=t.find(L+"-image"),this.$close=t.find(L+"-button-close"),this.$maximize=t.find(L+"-button-maximize"),this.$minimize=t.find(L+"-button-minimize"),this.$zoomIn=t.find(L+"-button-zoomIn"),this.$zoomOut=t.find(L+"-button-zoomOut"),this.$actualSize=t.find(L+"-button-actualSize"),this.$fullscreen=t.find(L+"-button-fullscreen"),this.$rotateLeft=t.find(L+"-button-rotateLeft"),this.$rotateRight=t.find(L+"-button-rotateRight"),this.$prev=t.find(L+"-button-prev"),this.$next=t.find(L+"-button-next"),this.$stage.addClass("stage-ready"),this.$image.addClass("image-ready"),this.$photoviewer.css("z-index",R.zIndex),this.options.positionFixed&&this.$photoviewer.css({position:"fixed"}),this.options.dragHandle&&this.options.dragHandle!==L+"-modal"?this.dragHandle=this.$photoviewer.find(this.options.dragHandle):this.dragHandle=this.$photoviewer,H(this.options.appendTo).eq(0).append(this.$photoviewer),this._stageEdgeValue={horizontal:T(this.$stage,["left","right","border-left-width","border-right-width"]),vertical:T(this.$stage,["top","bottom","border-top-width","border-bottom-width"])},this._modalEdgeValue={horizontal:T(this.$photoviewer,["padding-left","padding-right","border-left-width","border-right-width"]),vertical:T(this.$photoviewer,["padding-top","padding-bottom","border-top-width","border-bottom-width"])},this._addEvents(),this._addCustomButtonEvents()}},{key:"open",value:function(){this._triggerHook("beforeOpen",this),this.options.multiInstances||H(L+"-modal").eq(0).remove(),this.build(),this.setInitModalPos(),this._triggerHook("opened",this)}},{key:"close",value:function(){this._triggerHook("beforeClose",this),this.$photoviewer.remove(),this.isOpened=!1,this.isMaximized=!1,this.isRotated=!1,this.rotationDegree=0,H(L+"-modal").length||(this.options.multiInstances&&(R.zIndex=this.options.zIndex),Ot.off("resize"+_)),this._triggerHook("closed",this)}},{key:"_getOffsetParentData",value:function(){var t=H(this.options.appendTo)[0];return{width:this.options.positionFixed||v(t)?Ot.width():t.clientWidth,height:this.options.positionFixed||v(t)?Ot.height():t.clientHeight,scrollLeft:this.options.positionFixed?0:v(t)?V.scrollLeft():t.scrollLeft,scrollTop:this.options.positionFixed?0:v(t)?V.scrollTop():t.scrollTop}}},{key:"setModalToCenter",value:function(){var t,e,i,o,n,s=0,a=0,s=(k(this.$photoviewer)||(s+=this._modalEdgeValue.horizontal,a+=this._modalEdgeValue.vertical),H.isPlainObject(this.options.initModalPos)?(o=this.options.initModalPos.left,n=this.options.initModalPos.top,t=this.options.initModalPos.right,e=this.options.initModalPos.bottom):(o=((i=this._getOffsetParentData()).width-this.options.modalWidth-s)/2+i.scrollLeft,n=(i.height-this.options.modalHeight-a)/2+i.scrollTop),{width:this.modalData.width||this.options.modalWidth,height:this.modalData.height||this.options.modalHeight,left:this.modalData.left||o,top:this.modalData.top||n,right:this.modalData.right||t,bottom:this.modalData.bottom||e});this.$photoviewer.css(s)}},{key:"setInitModalPos",value:function(){this.options.initMaximized?(this.maximize(),this.isOpened=!0):this.setModalToCenter(),this.$photoviewer[0].focus()}},{key:"setModalSize",value:function(t){var e,i,o,n,s=this,a=this._getOffsetParentData(),r=t.width+this._stageEdgeValue.horizontal,h=t.height+this._stageEdgeValue.vertical,l=0,c=0,u=(k(this.$photoviewer)?(r+=this._modalEdgeValue.horizontal,h+=this._modalEdgeValue.vertical):(l+=this._modalEdgeValue.horizontal,c+=this._modalEdgeValue.vertical),(0')),this.$stage.addClass("stage-ready"),this.$image.addClass("image-ready"),this.options.initAnimation&&!this.options.progressiveLoading&&this.$image.hide(),this.$image.attr("src",t),o=t,n=function(t){r.img=t,r.imageData={originalWidth:t.width,originalHeight:t.height},r.isMaximized||r.isOpened&&r.options.fixedModalPos?r.setImageSize(t):r.setModalSize(t),e&&e.call()},s=function(){r.$photoviewer.find(L+"-loader").remove(),i&&i.call()},(a=new Image).onload=function(){n(a)},a.onerror=function(){s(a)},a.src=o,this.options.title&&this.setImageTitle(t)}},{key:"setImageTitle",value:function(t){t=this.groupData[this.groupIndex].title||t.replace(/^.*?\/*([^/?]*)\.[a-z]+(\?.+|$)/gi,"$1");this.$title.html(t)}},{key:"jump",value:function(t){this._triggerHook("beforeChange",[this,this.groupIndex]);var e=Date.now();e-this._lastTimestamp>=this.options.animationDuration&&(this.groupIndex=this.groupIndex+t,this.jumpTo(this.groupIndex),this._lastTimestamp=e)}},{key:"jumpTo",value:function(t){var e=this;0<=(t%=this.groupData.length)?t%=this.groupData.length:t<0&&(t=(this.groupData.length+t)%this.groupData.length),this.groupIndex=t,this.loadImage(this.groupData[t].src,function(){e._triggerHook("changed",[e,t])},function(){e._triggerHook("changed",[e,t])})}},{key:"wheel",value:function(t){t.preventDefault();var e=1,e=(t.deltaY?e=0this.options.maxRatio||t + + + + @@ -32,6 +52,7 @@ + + + + + - - - - 综合演示 - - - - - - - - 复选框 - - - - - + + + + - - - - - - - - - - - - - - - - + + + + + \ No newline at end of file