lychee/assets/min/main.js

4323 lines
203 KiB
JavaScript
Raw Normal View History

/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"num
},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new
},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.par
//# sourceMappingURL=jquery.min.map
!function(a){"use strict";function b(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function c(a,b){return a<<b|a>>>32-b}function d(a,d,e,f,g,h){return b(c(b(b(d,a),b(f,h)),g),e)}function e(a,b,c,e,f,g,h){return d(b&c|~b&e,a,b,f,g,h)}function f(a,b,c,e,f,g,h){return d(b&e|c&~e,a,b,f,g,h)}function g(a,b,c,e,f,g,h){return d(b^c^e,a,b,f,g,h)}function h(a,b,c,e,f,g,h){return d(c^(b|~e),a,b,f,g,h)}function i(a,c){a[c>>5]|=128<<c%32,a[(c+64>>>9<<4)+14]=c;var d,i,j,k,l,m=1732584193,n=-271733879,o=-1732584194,p=271733878;for(d=0;d<a.length;d+=16)i=m,j=n,k=o,l=p,m=e(m,n,o,p,a[d],7,-680876936),p=e(p,m,n,o,a[d+1],12,-389564586),o=e(o,p,m,n,a[d+2],17,606105819),n=e(n,o,p,m,a[d+3],22,-1044525330),m=e(m,n,o,p,a[d+4],7,-176418897),p=e(p,m,n,o,a[d+5],12,1200080426),o=e(o,p,m,n,a[d+6],17,-1473231341),n=e(n,o,p,m,a[d+7],22,-45705983),m=e(m,n,o,p,a[d+8],7,1770035416),p=e(p,m,n,o,a[d+9],12,-1958414417),o=e(o,p,m,n,a[d+10],17,-42063),n=e(n,o,p,m,a[d+11],22,-1990404162),m=e(m,n,o,p,a[d+12],7,1804603682),p=e(p,m,n,o,a[d+13],12,-40341101),o=e(o,p,m,n,a[d+14],17,-1502002290),n=e(n,o,p,m,a[d+15],22,1236535329),m=f(m,n,o,p,a[d+1],5,-165796510),p=f(p,m,n,o,a[d+6],9,-1069501632),o=f(o,p,m,n,a[d+11],14,643717713),n=f(n,o,p,m,a[d],20,-373897302),m=f(m,n,o,p,a[d+5],5,-701558691),p=f(p,m,n,o,a[d+10],9,38016083),o=f(o,p,m,n,a[d+15],14,-660478335),n=f(n,o,p,m,a[d+4],20,-405537848),m=f(m,n,o,p,a[d+9],5,568446438),p=f(p,m,n,o,a[d+14],9,-1019803690),o=f(o,p,m,n,a[d+3],14,-187363961),n=f(n,o,p,m,a[d+8],20,1163531501),m=f(m,n,o,p,a[d+13],5,-1444681467),p=f(p,m,n,o,a[d+2],9,-51403784),o=f(o,p,m,n,a[d+7],14,1735328473),n=f(n,o,p,m,a[d+12],20,-1926607734),m=g(m,n,o,p,a[d+5],4,-378558),p=g(p,m,n,o,a[d+8],11,-2022574463),o=g(o,p,m,n,a[d+11],16,1839030562),n=g(n,o,p,m,a[d+14],23,-35309556),m=g(m,n,o,p,a[d+1],4,-1530992060),p=g(p,m,n,o,a[d+4],11,1272893353),o=g(o,p,m,n,a[d+7],16,-155497632),n=g(n,o,p,m,a[d+10],23,-1094730640),m=g(m,n,o,p,a[d+13],4,681279174),p=g(p,m,n,o,a[d],11,-358537222),o=g(o,p,m,n,a[d+3],16,-722521979),n=g(n,o,p,m,a[d+6],23,76029189),m=g(m,n,o,p,a[d+9],4,-640364487),p=g(p,m,n,o,a[d+12],11,-421815835),o=g(o,p,m,n,a[d+15],16,530742520),n=g(n,o,p,m,a[d+2],23,-995338651),m=h(m,n,o,p,a[d],6,-198630844),p=h(p,m,n,o,a[d+7],10,1126891415),o=h(o,p,m,n,a[d+14],15,-1416354905),n=h(n,o,p,m,a[d+5],21,-57434055),m=h(m,n,o,p,a[d+12],6,1700485571),p=h(p,m,n,o,a[d+3],10,-1894986606),o=h(o,p,m,n,a[d+10],15,-1051523),n=h(n,o,p,m,a[d+1],21,-2054922799),m=h(m,n,o,p,a[d+8],6,1873313359),p=h(p,m,n,o,a[d+15],10,-30611744),o=h(o,p,m,n,a[d+6],15,-1560198380),n=h(n,o,p,m,a[d+13],21,1309151649),m=h(m,n,o,p,a[d+4],6,-145523070),p=h(p,m,n,o,a[d+11],10,-1120210379),o=h(o,p,m,n,a[d+2],15,718787259),n=h(n,o,p,m,a[d+9],21,-343485551),m=b(m,i),n=b(n,j),o=b(o,k),p=b(p,l);return[m,n,o,p]}function j(a){var b,c="";for(b=0;b<32*a.length;b+=8)c+=String.fromCharCode(a[b>>5]>>>b%32&255);return c}function k(a){var b,c=[];for(c[(a.length>>2)-1]=void 0,b=0;b<c.length;b+=1)c[b]=0;for(b=0;b<8*a.length;b+=8)c[b>>5]|=(255&a.charCodeAt(b/8))<<b%32;return c}function l(a){return j(i(k(a),8*a.length))}function m(a,b){var c,d,e=k(a),f=[],g=[];for(f[15]=g[15]=void 0,e.length>16&&(e=i(e,8*a.length)),c=0;16>c;c+=1)f[c]=909522486^e[c],g[c]=1549556828^e[c];return d=i(f.concat(k(b)),512+8*b.length),j(i(g.concat(d),640))}function n(a){var b,c,d="0123456789abcdef",e="";for(c=0;c<a.length;c+=1)b=a.charCodeAt(c),e+=d.charAt(b>>>4&15)+d.charAt(15&b);return e}function o(a){return unescape(encodeURIComponent(a))}function p(a){return l(o(a))}function q(a){return n(p(a))}function r(a,b){return m(o(a),o(b))}function s(a,b){return n(r(a,b))}function t(a,b,c){return b?c?r(b,a):s(b,a):c?p(a):q(a)}"function"==typeof define&&define.amd?define(function(){return t}):a.md5=t}(this);
/* mousetrap v1.4.6 craig.is/killing/mice */
(function(J,r,f){function s(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,d;for(d in n)a[d]?b=!0:n[d]=0;b||(u=!1)}function C(a,b,d,c,e,v){var g,k,f=[],h=d.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;g<l[a].length;++g)if(k=
l[a][g],!(!c&&k.seq&&n[k.seq]!=k.level||h!=k.action||("keypress"!=h||d.metaKey||d.ctrlKey)&&b.sort().join(",")!==k.modifiers.sort().join(","))){var m=c&&k.seq==c&&k.level==v;(!c&&k.combo==e||m)&&l[a].splice(g,1);f.push(k)}return f}function K(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function x(a,b,d,c){m.stopCallback(b,b.target||b.srcElement,d,c)||!1!==a(b,d)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?
b.stopPropagation():b.cancelBubble=!0)}function y(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=A(a);b&&("keyup"==a.type&&z===b?z=!1:m.handleKey(b,K(a),a))}function w(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function L(a,b,d,c){function e(b){return function(){u=b;++n[a];clearTimeout(D);D=setTimeout(t,1E3)}}function v(b){x(d,b,a);"keyup"!==c&&(z=A(b));setTimeout(t,10)}for(var g=n[a]=0;g<b.length;++g){var f=g+1===b.length?v:e(c||E(b[g+1]).action);F(b[g],f,c,a,g)}}function E(a,b){var d,
c,e,f=[];d="+"===a?["+"]:a.split("+");for(e=0;e<d.length;++e)c=d[e],G[c]&&(c=G[c]),b&&"keypress"!=b&&H[c]&&(c=H[c],f.push("shift")),w(c)&&f.push(c);d=c;e=b;if(!e){if(!p){p={};for(var g in h)95<g&&112>g||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1<f.length?L(a,f,b,d):(d=E(a,d),l[d.key]=l[d.key]||[],C(d.key,d.modifiers,{type:d.action},
c,a,e),l[d.key][c?"unshift":"push"]({callback:b,modifiers:d.modifiers,action:d.action,seq:c,level:e,combo:a}))}var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},B={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},H={"~":"`","!":"1",
"@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;c<a.length;++c)F(a[c],b,d);return this},
unbind:function(a,b){return m.bind(a,function(){},b)},trigger:function(a,b){if(q[a+":"+b])q[a+":"+b]({},a);return this},reset:function(){l={};q={};return this},stopCallback:function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable},handleKey:function(a,b,d){var c=C(a,b,d),e;b={};var f=0,g=!1;for(e=0;e<c.length;++e)c[e].seq&&(f=Math.max(f,c[e].level));for(e=0;e<c.length;++e)c[e].seq?c[e].level==f&&(g=!0,
b[c[e].seq]=1,x(c[e].callback,d,c[e].combo,c[e].seq)):g||x(c[e].callback,d,c[e].combo);c="keypress"==d.type&&I;d.type!=u||w(a)||c||t(b);I=g&&"keydown"==d.type}};J.Mousetrap=m;"function"===typeof define&&define.amd&&define(m)})(window,document);
Mousetrap=function(a){var d={},e=a.stopCallback;a.stopCallback=function(b,c,a){return d[a]?!1:e(b,c,a)};a.bindGlobal=function(b,c,e){a.bind(b,c,e);if(b instanceof Array)for(c=0;c<b.length;c++)d[b[c]]=!0;else d[b]=!0};return a}(Mousetrap);
/* ToolTips */
(function(c){function b(e,d){return(typeof e=="function")?(e.call(d)):e}function a(e,d){this.$element=c(e);this.options=d;this.enabled=true;this.fixTitle()}a.prototype={show:function(){var g=this.getTitle();if(g&&this.enabled){var f=this.tip();f.find(".tipsy-inner")[this.options.html?"html":"text"](g);f[0].className="tipsy";f.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var j=c.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight});
var d=f[0].offsetWidth,i=f[0].offsetHeight,h=b(this.options.gravity,this.$element[0]);var e;switch(h.charAt(0)){case"n":e={top:j.top+j.height+this.options.offset,left:j.left+j.width/2-d/2};break;case"s":e={top:j.top-i-this.options.offset,left:j.left+j.width/2-d/2};break;case"e":e={top:j.top+j.height/2-i/2,left:j.left-d-this.options.offset};break;case"w":e={top:j.top+j.height/2-i/2,left:j.left+j.width+this.options.offset};break}if(h.length==2){if(h.charAt(1)=="w"){e.left=j.left+j.width/2-15}else{e.left=j.left+j.width/2-d+15
}}f.css(e).addClass("tipsy-"+h);f.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+h.charAt(0);if(this.options.className){f.addClass(b(this.options.className,this.$element[0]))}if(this.options.fade){f.stop().css({opacity:0,display:"block",visibility:"visible"}).animate({opacity:this.options.opacity})}else{f.css({visibility:"visible",opacity:this.options.opacity})}}},hide:function(){if(this.options.fade){this.tip().stop().fadeOut(function(){c(this).remove()})}else{this.tip().remove()}},fixTitle:function(){var d=this.$element;
if(d.attr("title")||typeof(d.attr("original-title"))!="string"){d.attr("original-title",d.attr("title")||"").removeAttr("title")}},getTitle:function(){var f,d=this.$element,e=this.options;this.fixTitle();var f,e=this.options;if(typeof e.title=="string"){f=d.attr(e.title=="title"?"original-title":e.title)}else{if(typeof e.title=="function"){f=e.title.call(d[0])}}f=(""+f).replace(/(^\s*|\s*$)/,"");return f||e.fallback},tip:function(){if(!this.$tip){this.$tip=c('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>')
}return this.$tip},validate:function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}},enable:function(){this.enabled=true},disable:function(){this.enabled=false},toggleEnabled:function(){this.enabled=!this.enabled}};c.fn.tipsy=function(h){if(h===true){return this.data("tipsy")}else{if(typeof h=="string"){var j=this.data("tipsy");if(j){j[h]()}return this}}h=c.extend({},c.fn.tipsy.defaults,h);function g(l){var m=c.data(l,"tipsy");if(!m){m=new a(l,c.fn.tipsy.elementOptions(l,h));
c.data(l,"tipsy",m)}return m}function k(){var l=g(this);l.hoverState="in";if(h.delayIn==0){l.show()}else{l.fixTitle();setTimeout(function(){if(l.hoverState=="in"){l.show()}},h.delayIn)}}function f(){var l=g(this);l.hoverState="out";if(h.delayOut==0){l.hide()}else{setTimeout(function(){if(l.hoverState=="out"){l.hide()}},h.delayOut)}}if(!h.live){this.each(function(){g(this)})}if(h.trigger!="manual"){var d=h.live?"live":"bind",i=h.trigger=="hover"?"mouseenter":"focus",e=h.trigger=="hover"?"mouseleave":"blur";
this[d](i,k)[d](e,f)}return this};c.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:false,fallback:"",gravity:"n",html:false,live:false,offset:0,opacity:0.8,title:"title",trigger:"hover"};c.fn.tipsy.elementOptions=function(e,d){return c.metadata?c.extend({},d,c(e).metadata()):d};c.fn.tipsy.autoNS=function(){return c(this).offset().top>(c(document).scrollTop()+c(window).height()/2)?"s":"n"};c.fn.tipsy.autoWE=function(){return c(this).offset().left>(c(document).scrollLeft()+c(window).width()/2)?"e":"w"
};c.fn.tipsy.autoBounds=function(e,d){return function(){var f={ns:d[0],ew:(d.length>1?d[1]:false)},i=c(document).scrollTop()+e,g=c(document).scrollLeft()+e,h=c(this);if(h.offset().top<i){f.ns="n"}if(h.offset().left<g){f.ew="w"}if(c(window).width()+c(document).scrollLeft()-h.offset().left<e){f.ew="e"}if(c(window).height()+c(document).scrollTop()-h.offset().top<e){f.ns="s"}return f.ns+(f.ew?f.ew:"")}}})(jQuery);
/* Browser Detection */
var BrowserDetect={init:function(){this.browser=this.searchString(this.dataBrowser)||"An unknown browser";this.version=this.searchVersion(navigator.userAgent)||this.searchVersion(navigator.appVersion)||"an unknown version";this.OS=this.searchString(this.dataOS)||"an unknown OS"},searchString:function(d){for(var a=0;a<d.length;a++){var b=d[a].string;var c=d[a].prop;this.versionSearchString=d[a].versionSearch||d[a].identity;if(b){if(b.indexOf(d[a].subString)!=-1){return d[a].identity}}else{if(c){return d[a].identity}}}},searchVersion:function(b){var a=b.indexOf(this.versionSearchString);if(a==-1){return}return parseFloat(b.substring(a+this.versionSearchString.length+1))},dataBrowser:[{string:navigator.userAgent,subString:"Chrome",identity:"Chrome"},{string:navigator.userAgent,subString:"OmniWeb",versionSearch:"OmniWeb/",identity:"OmniWeb"},{string:navigator.vendor,subString:"Apple",identity:"Safari",versionSearch:"Version"},{prop:window.opera,identity:"Opera"},{string:navigator.vendor,subString:"iCab",identity:"iCab"},{string:navigator.vendor,subString:"KDE",identity:"Konqueror"},{string:navigator.userAgent,subString:"Firefox",identity:"Firefox"},{string:navigator.vendor,subString:"Camino",identity:"Camino"},{string:navigator.userAgent,subString:"Netscape",identity:"Netscape"},{string:navigator.userAgent,subString:"MSIE",identity:"Explorer",versionSearch:"MSIE"},{string:navigator.userAgent,subString:"Gecko",identity:"Mozilla",versionSearch:"rv"},{string:navigator.userAgent,subString:"Mozilla",identity:"Netscape",versionSearch:"Mozilla"}],dataOS:[{string:navigator.platform,subString:"Win",identity:"Windows"},{string:navigator.platform,subString:"Mac",identity:"Mac"},{string:navigator.userAgent,subString:"iPhone",identity:"iPhone/iPod"},{string:navigator.platform,subString:"Linux",identity:"Linux"}]};BrowserDetect.init();
function mobileBrowser() { if (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) return true; else return false; }
/* GET */
function gup(b){b=b.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");var a="[\\?&]"+b+"=([^&#]*)",d=new RegExp(a),c=d.exec(window.location.href);if(c===null){return""}else{return c[1]}};
/*! jQuery Retina Plugin */
(function(a){a.fn.retina=function(c){var d={"retina-background":false,"retina-suffix":"@2x"};if(c){a.extend(d,c)}var b=function(f,g){var e=new Image();e.onload=function(){g(e)};e.src=f};if(window.devicePixelRatio>1){this.each(function(){var e=a(this);if(this.tagName.toLowerCase()=="img"&&e.attr("src")){var g=e.attr("src").replace(/\.(?!.*\.)/,d["retina-suffix"]+".");b(g,function(h){e.attr("src",h.src);var i=a("<div>").append(e.clone()).remove().html();if(!(/(width|height)=["']\d+["']/.test(i))){e.attr("width",h.width/2)
}})}if(d["retina-background"]){var f=e.css("background-image");if(/^url\(.*\)$/.test(f)){var g=f.substring(4,f.length-1).replace(/\.(?!.*\.)/,d["retina-suffix"]+".");b(g,function(h){e.css("background-image","url("+h.src+")");if(e.css("background-size")=="auto auto"){e.css("background-size",(h.width/2)+"px auto")}})}}})}}})(jQuery);
(function($) {
var Swipe = function(el) {
var self = this;
this.el = $(el);
this.pos = { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
this.startTime;
el.on('touchstart', function(e) { self.touchStart(e); });
el.on('touchmove', function(e) { self.touchMove(e); });
el.on('touchend', function(e) { self.swipeEnd(); });
el.on('mousedown', function(e) { self.mouseDown(e); });
};
Swipe.prototype = {
touchStart: function(e) {
var touch = e.originalEvent.touches[0];
this.swipeStart(e, touch.pageX, touch.pageY);
},
touchMove: function(e) {
var touch = e.originalEvent.touches[0];
this.swipeMove(e, touch.pageX, touch.pageY);
},
mouseDown: function(e) {
var self = this;
this.swipeStart(e, e.pageX, e.pageY);
this.el.on('mousemove', function(e) { self.mouseMove(e); });
this.el.on('mouseup', function() { self.mouseUp(); });
},
mouseMove: function(e) {
this.swipeMove(e, e.pageX, e.pageY);
},
mouseUp: function(e) {
this.swipeEnd(e);
this.el.off('mousemove');
this.el.off('mouseup');
},
swipeStart: function(e, x, y) {
this.pos.start.x = x;
this.pos.start.y = y;
this.pos.end.x = x;
this.pos.end.y = y;
this.startTime = new Date().getTime();
this.trigger('swipeStart', e);
},
swipeMove: function(e, x, y) {
this.pos.end.x = x;
this.pos.end.y = y;
this.trigger('swipeMove', e);
},
swipeEnd: function(e) {
this.trigger('swipeEnd', e);
},
trigger: function(e, originalEvent) {
var self = this;
var
event = $.Event(e),
x = self.pos.start.x - self.pos.end.x,
y = self.pos.end.y - self.pos.start.y,
radians = Math.atan2(y, x),
direction = 'up',
distance = Math.round(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))),
angle = Math.round(radians * 180 / Math.PI),
speed = Math.round(distance / ( new Date().getTime() - self.startTime ) * 1000);
if ( angle < 0 ) {
angle = 360 - Math.abs(angle);
}
if ( ( angle <= 45 && angle >= 0 ) || ( angle <= 360 && angle >= 315 ) ) {
direction = 'left';
} else if ( angle >= 135 && angle <= 225 ) {
direction = 'right';
} else if ( angle > 45 && angle < 135 ) {
direction = 'down';
}
event.originalEvent = originalEvent;
event.swipe = { x: x, y: y, direction: direction, distance: distance, angle: angle, speed: speed };
$(self.el).trigger(event);
}
};
$.fn.swipe = function() {
var swipe = new Swipe(this);
return this;
};
})(jQuery);
/**
* @name Album Module
* @description Takes care of every action an album can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
album = {
json: null,
getID: function() {
var id;
if (photo.json) id = photo.json.album;
else if (album.json) id = album.json.id;
else id = $(".album:hover, .album.active").attr("data-id");
// Search
if (!id) id = $(".album:hover, .album.active").attr("data-id");
if (!id) id = $(".photo:hover, .photo.active").attr("data-album-id");
if (id) return id;
else return false;
},
load: function(albumID, refresh) {
var startTime,
params,
durationTime,
waitTime;
password.get(albumID, function() {
if (!refresh) {
loadingBar.show();
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomOut");
lychee.animate(".divider", "fadeOut");
}
startTime = new Date().getTime();
params = "getAlbum&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Album private!") {
if (document.location.hash.replace("#", "").split("/")[1]!=undefined) {
// Display photo only
lychee.setMode("view");
} else {
// Album not public
lychee.content.show();
lychee.goto("");
}
return false;
}
if (data==="Warning: Wrong password!") {
album.load(albumID, refresh);
return false;
}
album.json = data;
durationTime = (new Date().getTime() - startTime);
if (durationTime>300) waitTime = 0; else if (refresh) waitTime = 0; else waitTime = 300 - durationTime;
if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
setTimeout(function() {
view.album.init();
if (!refresh) {
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
view.header.mode("album");
}
}, waitTime);
});
});
},
parse: function(photo) {
if (!album.json.title) album.json.title = "Untitled";
},
add: function() {
var title,
params,
buttons,
isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n) };
buttons = [
["Create Album", function() {
title = $(".message input.text").val();
if (title.length===0) title = "Untitled";
modal.close();
params = "addAlbum&title=" + escape(encodeURI(title));
lychee.api(params, function(data) {
if (data===true) data = 1; // Avoid first album to be true
if (data!==false&&isNumber(data)) lychee.goto(data);
else lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("New Album", "Enter a title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='Untitled'>", buttons);
},
delete: function(albumIDs) {
var params,
buttons,
albumTitle;
if (!albumIDs) return false;
if (albumIDs instanceof Array===false) albumIDs = [albumIDs];
buttons = [
["", function() {
params = "deleteAlbum&albumIDs=" + albumIDs;
lychee.api(params, function(data) {
if (visible.albums()) {
albumIDs.forEach(function(id, index, array) {
albums.json.num--;
view.albums.content.delete(id);
});
} else lychee.goto("");
if (data!==true) lychee.error(null, params, data);
});
}],
["", function() {}]
];
if (albumIDs.toString()==="0") {
buttons[0][0] = "Clear Unsorted";
buttons[1][0] = "Keep Unsorted";
modal.show("Clear Unsorted", "Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!", buttons);
} else if (albumIDs.length===1) {
buttons[0][0] = "Delete Album and Photos";
buttons[1][0] = "Keep Album";
// Get title
if (album.json) albumTitle = album.json.title;
else if (albums.json) albumTitle = albums.json.content[albumIDs].title;
modal.show("Delete Album", "Are you sure you want to delete the album '" + albumTitle + "' and all of the photos it contains? This action can't be undone!", buttons);
} else {
buttons[0][0] = "Delete Albums and Photos";
buttons[1][0] = "Keep Albums";
modal.show("Delete Albums", "Are you sure you want to delete all " + albumIDs.length + " selected albums and all of the photos they contain? This action can't be undone!", buttons);
}
},
setTitle: function(albumIDs) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!albumIDs) return false;
if (albumIDs instanceof Array===false) albumIDs = [albumIDs];
if (albumIDs.length===1) {
// Get old title if only one album is selected
if (album.json) oldTitle = album.json.title;
else if (albums.json) oldTitle = albums.json.content[albumIDs].title;
if (!oldTitle) oldTitle = "";
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [
["Set Title", function() {
// Get input
newTitle = $(".message input.text").val();
// Remove html from input
newTitle = lychee.removeHTML(newTitle);
// Set to Untitled when empty
newTitle = (newTitle==="") ? "Untitled" : newTitle;
if (visible.album()) {
album.json.title = newTitle;
view.album.title();
} else if (visible.albums()) {
albumIDs.forEach(function(id, index, array) {
albums.json.content[id].title = newTitle;
view.albums.content.title(id);
});
}
params = "setAlbumTitle&albumIDs=" + albumIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
if (albumIDs.length===1) modal.show("Set Title", "Enter a new title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
else modal.show("Set Titles", "Enter a title for all " + albumIDs.length + " selected album: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
},
setDescription: function(photoID) {
var oldDescription = album.json.description.replace("'", "&apos;"),
description,
params,
buttons;
buttons = [
["Set Description", function() {
// Get input
description = $(".message input.text").val();
// Remove html from input
description = lychee.removeHTML(description);
if (visible.album()) {
album.json.description = description;
view.album.description();
}
params = "setAlbumDescription&albumID=" + photoID + "&description=" + escape(encodeURI(description));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
setPublic: function(albumID, e) {
var params,
password = "",
listed = false,
downloadable = false;
albums.refresh();
if (!visible.message()&&album.json.public==0) {
modal.show("Share Album", "This album will be shared with the following properties:</p><form><div class='choice'><input type='checkbox' name='listed' value='listed' checked><h2>Visible</h2><p>Listed to visitors of your Lychee.</p></div><div class='choice'><input type='checkbox' name='downloadable' value='downloadable'><h2>Downloadable</h2><p>Visitors of your Lychee can download this album.</p></div><div class='choice'><input type='checkbox' name='password' value='password'><h2>Password protected</h2><p>Only accessible with a valid password.<input class='text' type='password' placeholder='password' value='' style='display: none;'></p></div></form><p style='display: none;'>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]], -170);
$(".message .choice input[name='password']").on("change", function() {
if ($(this).prop('checked')===true) $(".message .choice input.text").show();
else $(".message .choice input.text").hide();
});
return true;
}
if (visible.message()) {
if ($(".message .choice input[name='password']:checked").val()==="password") {
password = md5($(".message input.text").val());
album.json.password = 1;
} else {
password = "";
album.json.password = 0;
}
if ($(".message .choice input[name='listed']:checked").val()==="listed") listed = true;
if ($(".message .choice input[name='downloadable']:checked").val()==="downloadable") downloadable = true;
}
params = "setAlbumPublic&albumID=" + albumID + "&password=" + password + "&visible=" + listed + "&downloadable=" + downloadable;
if (visible.album()) {
album.json.public = (album.json.public==0) ? 1 : 0;
album.json.password = (album.json.public==0) ? 0 : album.json.password;
view.album.public();
view.album.password();
if (album.json.public==1) contextMenu.shareAlbum(albumID, e);
}
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
share: function(service) {
var link = "",
url = location.href;
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(album.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(album.json.title) + "&body=" + encodeURI(url);
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
getArchive: function(albumID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getAlbumArchive&albumID=" + albumID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getAlbumArchive&albumID=" + albumID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
}
};
/**
* @name Albums Module
* @description Takes care of every action albums can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
albums = {
json: null,
load: function() {
var startTime,
durationTime,
waitTime;
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomOut");
lychee.animate(".divider", "fadeOut");
startTime = new Date().getTime();
if(this.json == null) {
lychee.api("getAlbums", function(data) {
/* Smart Albums */
data.unsortedAlbum = {
id: 0,
title: "Unsorted",
sysdate: data.unsortedNum + " photos",
unsorted: 1,
thumb0: data.unsortedThumb0,
thumb1: data.unsortedThumb1,
thumb2: data.unsortedThumb2
};
data.starredAlbum = {
id: "f",
title: "Starred",
sysdate: data.starredNum + " photos",
star: 1,
thumb0: data.starredThumb0,
thumb1: data.starredThumb1,
thumb2: data.starredThumb2
};
data.publicAlbum = {
id: "s",
title: "Public",
sysdate: data.publicNum + " photos",
public: 1,
thumb0: data.publicThumb0,
thumb1: data.publicThumb1,
thumb2: data.publicThumb2
};
data.recentAlbum = {
id: "r",
title: "Recent",
sysdate: data.recentNum + " photos",
recent: 1,
thumb0: data.recentThumb0,
thumb1: data.recentThumb1,
thumb2: data.recentThumb2
};
albums.json = data;
durationTime = (new Date().getTime() - startTime);
if (durationTime>300) waitTime = 0; else waitTime = 300 - durationTime;
if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
if (visible.album()&&lychee.content.html()==="") waitTime = 0;
setTimeout(function() {
view.header.mode("albums");
view.albums.init();
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
}, waitTime);
});
} else {
view.header.mode("albums");
view.albums.init();
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
}
},
parse: function(album) {
if (album.password&&lychee.publicMode) {
album.thumb0 = "assets/img/password.svg";
album.thumb1 = "assets/img/password.svg";
album.thumb2 = "assets/img/password.svg";
} else {
if (!album.thumb0) album.thumb0 = "assets/img/no_images.svg";
if (!album.thumb1) album.thumb1 = "assets/img/no_images.svg";
if (!album.thumb2) album.thumb2 = "assets/img/no_images.svg";
}
},
refresh: function() {
this.json = null;
}
};
/**
* @name Build Module
* @description This module is used to generate HTML-Code.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
build = {
divider: function(title) {
return "<div class='divider fadeIn'><h1>" + title + "</h1></div>";
},
editIcon: function(id) {
return "<div id='" + id + "' class='edit'><a class='icon-pencil'></a></div>";
},
multiselect: function(top, left) {
return "<div id='multiselect' style='top: " + top + "px; left: " + left + "px;'></div>";
},
album: function(albumJSON) {
if (!albumJSON) return "";
var album = "",
longTitle = "",
title = albumJSON.title,
typeThumb = "";
if (title != null && title.length>18) {
title = albumJSON.title.substr(0, 18) + "...";
longTitle = albumJSON.title;
}
if (albumJSON.thumb0.split('.').pop()==="svg") typeThumb = "nonretina";
album += "<div class='album' data-id='" + albumJSON.id + "' data-password='" + albumJSON.password + "'>";
album += "<img src='" + albumJSON.thumb2 + "' width='200' height='200' alt='thumb' data-type='nonretina'>";
album += "<img src='" + albumJSON.thumb1 + "' width='200' height='200' alt='thumb' data-type='nonretina'>";
album += "<img src='" + albumJSON.thumb0 + "' width='200' height='200' alt='thumb' data-type='" + typeThumb + "'>";
album += "<div class='overlay'>";
if (albumJSON.password&&!lychee.publicMode) album += "<h1><span class='icon-lock'></span> " + title + "</h1>";
else album += "<h1 title='" + longTitle + "'>" + title + "</h1>";
album += "<a>" + albumJSON.sysdate + "</a>";
album += "</div>";
if (!lychee.publicMode) {
if(albumJSON.star==1) album += "<a class='badge red icon-star'></a>";
if(albumJSON.public==1) album += "<a class='badge red icon-share'></a>";
if(albumJSON.unsorted==1) album += "<a class='badge red icon-reorder'></a>";
if(albumJSON.recent==1) album += "<a class='badge red icon-time'></a>";
}
album += "</div>";
return album;
},
photo: function(photoJSON) {
if (!photoJSON) return "";
var photo = "",
longTitle = "",
title = photoJSON.title;
if (title != null && title.length>18) {
title = photoJSON.title.substr(0, 18) + "...";
longTitle = photoJSON.title;
}
photo += "<div class='photo' data-album-id='" + photoJSON.album + "' data-id='" + photoJSON.id + "'>";
photo += "<img src='" + photoJSON.thumbUrl + "' width='200' height='200' alt='thumb'>";
photo += "<div class='overlay'>";
photo += "<h1 title='" + longTitle + "'>" + title + "</h1>";
if (photoJSON.cameraDate==1) {
photo += "<a><span class='icon-camera' title='Photo Date'></span>" + photoJSON.sysdate + "</a>";
} else {
photo += "<a>" + photoJSON.sysdate + "</a>";
}
photo += "</div>";
if (photoJSON.star==1) photo += "<a class='badge red icon-star'></a>";
if (!lychee.publicMode&&photoJSON.public==1&&album.json.public!=1) photo += "<a class='badge red icon-share'></a>";
photo += "</div>";
return photo;
},
imageview: function(photoJSON, isSmall, visibleControls) {
if (!photoJSON) return "";
var view = "";
view += "<div class='arrow_wrapper previous'><a id='previous' class='icon-caret-left'></a></div>";
view += "<div class='arrow_wrapper next'><a id='next' class='icon-caret-right'></a></div>";
if (isSmall) {
if (visibleControls)
view += "<div id='image' class='small' style='background-image: url(" + photoJSON.url + "); width: " + photoJSON.width + "px; height: " + photoJSON.height + "px; margin-top: -" + parseInt(photoJSON.height/2-20) + "px; margin-left: -" + photoJSON.width/2 + "px;'></div>";
else
view += "<div id='image' class='small' style='background-image: url(" + photoJSON.url + "); width: " + photoJSON.width + "px; height: " + photoJSON.height + "px; margin-top: -" + parseInt(photoJSON.height/2) + "px; margin-left: -" + photoJSON.width/2 + "px;'></div>";
} else {
if (visibleControls)
view += "<div id='image' style='background-image: url(" + photoJSON.url + ")'></div>";
else
view += "<div id='image' style='background-image: url(" + photoJSON.url + ");' class='full'></div>";
}
return view;
},
no_content: function(typ) {
var no_content = "";
no_content += "<div class='no_content fadeIn'>";
no_content += "<a class='icon icon-" + typ + "'></a>";
if (typ==="search") no_content += "<p>No results</p>";
else if (typ==="share") no_content += "<p>No public albums</p>";
else if (typ==="cog") no_content += "<p>No configuration</p>";
no_content += "</div>";
return no_content;
},
modal: function(title, text, button, marginTop, closeButton) {
var modal = "",
custom_style = "";
if (marginTop) custom_style = "style='margin-top: " + marginTop + "px;'";
modal += "<div class='message_overlay fadeIn'>";
modal += "<div class='message center'" + custom_style + ">";
modal += "<h1>" + title + "</h1>";
if (closeButton!==false) {
modal += "<a class='close icon-remove-sign'></a>";
}
modal += "<p>" + text + "</p>";
$.each(button, function(index) {
if (this[0]!=="") {
if (index===0) modal += "<a class='button active'>" + this[0] + "</a>";
else modal += "<a class='button'>" + this[0] + "</a>";
}
});
modal += "</div>";
modal += "</div>";
return modal;
},
signInModal: function() {
var modal = "";
modal += "<div class='message_overlay'>";
modal += "<div class='message center'>";
modal += "<h1><a class='icon-lock'></a> Sign In</h1>";
modal += "<a class='close icon-remove-sign'></a>";
modal += "<div class='sign_in'>";
modal += "<input id='username' type='text' name='username' value='' placeholder='username'>";
modal += "<input id='password' type='password' name='password' value='' placeholder='password'>";
modal += "</div>";
modal += "<div id='version'>Version " + lychee.version + "<span> &#8211; <a target='_blank' href='" + lychee.updateURL + "'>Update available!</a><span></div>";
modal += "<a onclick='lychee.login()' class='button active'>Sign in</a>";
modal += "</div>";
modal += "</div>";
return modal;
},
uploadModal: function(title, files) {
var modal = "";
modal += "<div class='upload_overlay fadeIn'>";
modal += "<div class='upload_message center'>";
modal += "<h1>" + title + "</h1>";
modal += "<a class='close icon-remove-sign'></a>";
modal += "<div class='rows'>";
for (var i = 0; i < files.length; i++) {
if (files[i].name.length>40) files[i].name = files[i].name.substr(0, 17) + "..." + files[i].name.substr(files[i].name.length-20, 20);
modal += "<div class='row'>";
modal += "<a class='name'>" + lychee.escapeHTML(files[i].name) + "</a>";
if (files[i].supported===true) modal += "<a class='status'></a>";
else modal += "<a class='status error'>Not supported</a>";
modal += "<p class='notice'></p>";
modal += "</div>";
}
modal += "</div>";
modal += "</div>";
modal += "</div>";
return modal;
},
contextMenu: function(items) {
var menu = "";
menu += "<div class='contextmenu_bg'></div>";
menu += "<div class='contextmenu'>";
menu += "<table>";
menu += "<tbody>";
$.each(items, function(index) {
if (items[index][0]==="separator"&&items[index][1]===-1) menu += "<tr class='separator'></tr>";
else if (items[index][1]===-1) menu += "<tr class='no_hover'><td>" + items[index][0] + "</td></tr>";
else if (items[index][2]!=undefined) menu += "<tr><td onclick='" + items[index][2] + "; window.contextMenu.close();'>" + items[index][0] + "</td></tr>";
else menu += "<tr><td onclick='window.contextMenu.fns[" + items[index][1] + "](); window.contextMenu.close();'>" + items[index][0] + "</td></tr>";
});
menu += "</tbody>";
menu += "</table>";
menu += "</div>";
return menu;
},
tags: function(tags, forView) {
var html = "",
editTagsHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_tags");
if (tags!=="") {
tags = tags.split(",");
tags.forEach(function(tag, index, array) {
html += "<a class='tag'>" + tag + "<span class='icon-remove' data-index='" + index + "'></span></a>";
});
html += editTagsHTML;
} else {
html = "<div class='empty'>No Tags" + editTagsHTML + "</div>";
}
return html;
},
infoboxPhoto: function(photoJSON, forView) {
if (!photoJSON) return "";
var infobox = "",
public,
editTitleHTML,
editDescriptionHTML,
infos;
infobox += "<div class='header'><h1>About</h1><a class='icon-remove-sign'></a></div>";
infobox += "<div class='wrapper'>";
switch (photoJSON.public) {
case "0":
public = "No";
break;
case "1":
public = "Yes";
break;
case "2":
public = "Yes (Album)";
break;
default:
public = "-";
break;
}
editTitleHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_title");
editDescriptionHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_description");
infos = [
["", "Basics"],
["Title", photoJSON.title + editTitleHTML],
["Uploaded", photoJSON.sysdate],
["Description", photoJSON.description + editDescriptionHTML],
["", "Image"],
["Size", photoJSON.size],
["Format", photoJSON.type],
["Resolution", photoJSON.width + " x " + photoJSON.height],
["Tags", build.tags(photoJSON.tags, forView)]
];
if ((photoJSON.takestamp+photoJSON.make+photoJSON.model+photoJSON.shutter+photoJSON.aperture+photoJSON.focal+photoJSON.iso)!="0") {
infos = infos.concat([
["", "Camera"],
["Captured", photoJSON.takedate],
["Make", photoJSON.make],
["Type/Model", photoJSON.model],
["Shutter Speed", photoJSON.shutter],
["Aperture", photoJSON.aperture],
["Focal Length", photoJSON.focal],
["ISO", photoJSON.iso]
]);
}
infos = infos.concat([
["", "Share"],
["Public", public]
]);
$.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
switch (infos[index][0]) {
case "": // Separator
infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][1] + "</h1></div>";
infobox += "<table>";
break;
case "Tags": // Tags
if (forView!==true&&!lychee.publicMode) {
infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][0] + "</h1></div>";
infobox += "<div id='tags'>" + infos[index][1] + "</div>";
}
break;
default: // Item
infobox += "<tr>";
infobox += "<td>" + infos[index][0] + "</td>";
infobox += "<td class='attr_" + infos[index][0].toLowerCase() + "'>" + infos[index][1] + "</td>";
infobox += "</tr>";
break;
}
});
infobox += "</table>";
infobox += "<div class='bumper'></div>";
infobox += "</div>";
return infobox;
},
infoboxAlbum: function(albumJSON, forView) {
if (!albumJSON) return "";
var infobox = "",
public = "-",
password = "-",
downloadable = "-",
editTitleHTML,
editDescriptionHTML,
infos;
infobox += "<div class='header'><h1>About</h1><a class='icon-remove-sign'></a></div>";
infobox += "<div class='wrapper'>";
switch (albumJSON.public) {
case "0":
public = "No";
break;
case "1":
public = "Yes";
break;
}
switch (albumJSON.password) {
case false:
password = "No";
break;
case true:
password = "Yes";
break;
}
switch (albumJSON.downloadable) {
case "0":
downloadable = "No";
break;
case "1":
downloadable = "Yes";
break;
}
editTitleHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_title_album");
editDescriptionHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_description_album");
infos = [
["", "Basics"],
["Title", albumJSON.title + editTitleHTML],
["Description", albumJSON.description + editDescriptionHTML],
["", "Album"],
["Created", albumJSON.sysdate],
["Images", albumJSON.num],
["", "Share"],
["Public", public],
["Downloadable", downloadable],
["Password", password]
];
$.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
if (infos[index][0]==="") {
infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][1] + "</h1></div>";
infobox += "<table id='infos'>";
} else {
infobox += "<tr>";
infobox += "<td>" + infos[index][0] + "</td>";
infobox += "<td class='attr_" + infos[index][0].toLowerCase() + "'>" + infos[index][1] + "</td>";
infobox += "</tr>";
}
});
infobox += "</table>";
infobox += "<div class='bumper'></div>";
infobox += "</div>";
return infobox;
}
};
/**
* @name ContextMenu Module
* @description This module is used for the context menu.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
contextMenu = {
fns: null,
show: function(items, mouse_x, mouse_y, orientation) {
contextMenu.close();
$("body")
.css("overflow", "hidden")
.append(build.contextMenu(items));
// Do not leave the screen
if ((mouse_x+$(".contextmenu").outerWidth(true))>$("html").width()) orientation = "left";
if ((mouse_y+$(".contextmenu").outerHeight(true))>$("html").height()) mouse_y -= (mouse_y+$(".contextmenu").outerHeight(true)-$("html").height());
if (mouse_x>$(document).width()) mouse_x = $(document).width();
if (mouse_x<0) mouse_x = 0;
if (mouse_y>$(document).height()) mouse_y = $(document).height();
if (mouse_y<0) mouse_y = 0;
if (orientation==="left") mouse_x -= $(".contextmenu").outerWidth(true);
if (mouse_x===null||
mouse_x===undefined||
isNaN(mouse_x)||
mouse_y===null||
mouse_y===undefined||
isNaN(mouse_y)) {
mouse_x = "10px";
mouse_y = "10px";
}
$(".contextmenu").css({
"top": mouse_y,
"left": mouse_x,
"opacity": 0.98
});
},
add: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
upload.notify();
contextMenu.fns = [
function() { $("#upload_files").click() },
function() { upload.start.url() },
function() { upload.start.dropbox() },
function() { upload.start.server() },
function() { album.add() }
];
items = [
["<a class='icon-picture'></a> Upload Photo", 0],
["separator", -1],
["<a class='icon-link'></a> Import from Link", 1],
["<a class='icon-folder-open'></a> Import from Dropbox", 2],
["<a class='icon-hdd'></a> Import from Server", 3],
["separator", -1],
["<a class='icon-folder-close'></a> New Album", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "left");
},
settings: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
contextMenu.fns = [
function() { settings.setLogin() },
function() { settings.setSorting() },
function() { settings.setDropboxKey() },
function() { window.open(lychee.website); },
function() { window.open("plugins/check/"); },
function() { window.open("plugins/displaylog/"); },
function() { lychee.logout() }
];
items = [
["<a class='icon-user'></a> Change Login", 0],
["<a class='icon-sort'></a> Change Sorting", 1],
["<a class='icon-folder-open'></a> Set Dropbox", 2],
["separator", -1],
["<a class='icon-info-sign'></a> About Lychee", 3],
["<a class='icon-dashboard'></a> Diagnostics", 4],
["<a class='icon-list'></a> Show Log", 5],
["separator", -1],
["<a class='icon-signout'></a> Sign Out", 6]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
album: function(albumID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
if (albumID==="0"||albumID==="f"||albumID==="s"||albumID==="r") return false;
contextMenu.fns = [
function() { album.setTitle([albumID]) },
function() { album.delete([albumID]) }
];
items = [
["<a class='icon-edit'></a> Rename", 0],
["<a class='icon-trash'></a> Delete", 1]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
$(".album[data-id='" + albumID + "']").addClass("active");
},
albumMulti: function(albumIDs, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
multiselect.stopResize();
contextMenu.fns = [
function() { album.setTitle(albumIDs) },
function() { album.delete(albumIDs) },
];
items = [
["<a class='icon-edit'></a> Rename All", 0],
["<a class='icon-trash'></a> Delete All", 1]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
photo: function(photoID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
contextMenu.fns = [
function() { photo.setStar([photoID]) },
function() { photo.editTags([photoID]) },
function() { photo.setTitle([photoID]) },
function() { contextMenu.move([photoID], e, "right") },
function() { photo.delete([photoID]) }
];
items = [
["<a class='icon-star'></a> Star", 0],
["<a class='icon-tags'></a> Tags", 1],
["separator", -1],
["<a class='icon-edit'></a> Rename", 2],
["<a class='icon-folder-open'></a> Move", 3],
["<a class='icon-trash'></a> Delete", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
$(".photo[data-id='" + photoID + "']").addClass("active");
},
photoMulti: function(photoIDs, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
multiselect.stopResize();
contextMenu.fns = [
function() { photo.setStar(photoIDs) },
function() { photo.editTags(photoIDs) },
function() { photo.setTitle(photoIDs) },
function() { contextMenu.move(photoIDs, e, "right") },
function() { photo.delete(photoIDs) }
];
items = [
["<a class='icon-star'></a> Star All", 0],
["<a class='icon-tags'></a> Tag All", 1],
["separator", -1],
["<a class='icon-edit'></a> Rename All", 2],
["<a class='icon-folder-open'></a> Move All", 3],
["<a class='icon-trash'></a> Delete All", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
photoMore: function(photoID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items;
contextMenu.fns = [
function() { window.open(photo.getDirectLink()) },
function() { photo.getArchive(photoID) }
];
items = [["<a class='icon-resize-full'></a> Full Photo", 0]];
if ((album.json&&album.json.downloadable&&album.json.downloadable==="1"&&lychee.publicMode)||!lychee.publicMode) items.push(["<a class='icon-circle-arrow-down'></a> Download", 1]);
contextMenu.show(items, mouse_x, mouse_y, "right");
},
move: function(photoIDs, e, orientation) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items = [];
contextMenu.close(true);
if (album.getID()!=="0") {
items = [
["Unsorted", 0, "photo.setAlbum([" + photoIDs + "], 0)"],
["separator", -1]
];
}
lychee.api("getAlbums", function(data) {
if (data.num===0) {
items = [["New Album", 0, "album.add()"]];
} else {
$.each(data.content, function(index) {
if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum([" + photoIDs + "], " + this.id + ")"]);
});
}
if (!visible.photo()) contextMenu.show(items, mouse_x, mouse_y, "right");
else contextMenu.show(items, mouse_x, mouse_y, "left");
});
},
sharePhoto: function(photoID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
items;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [
function() { photo.setPublic(photoID) },
function() { photo.share(photoID, 0) },
function() { photo.share(photoID, 1) },
function() { photo.share(photoID, 2) },
function() { photo.share(photoID, 3) },
function() { window.open(photo.getDirectLink()) }
];
link = photo.getViewLink(photoID);
if (photo.json.public==="2") link = location.href;
items = [
["<input readonly id='link' value='" + link + "'>", -1],
["separator", -1],
["<a class='icon-eye-close'></a> Make Private", 0],
["separator", -1],
["<a class='icon-twitter'></a> Twitter", 1],
["<a class='icon-facebook'></a> Facebook", 2],
["<a class='icon-envelope'></a> Mail", 3],
["<a class='icon-hdd'></a> Dropbox", 4],
["<a class='icon-link'></a> Direct Link", 5]
];
contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus().select();
},
shareAlbum: function(albumID, e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
items;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [
function() { album.setPublic(albumID) },
function() { album.share(0) },
function() { album.share(1) },
function() { album.share(2) },
function() { password.remove(albumID) }
];
items = [
["<input readonly id='link' value='" + location.href + "'>", -1],
["separator", -1],
["<a class='icon-eye-close'></a> Make Private", 0],
["separator", -1],
["<a class='icon-twitter'></a> Twitter", 1],
["<a class='icon-facebook'></a> Facebook", 2],
["<a class='icon-envelope'></a> Mail", 3],
];
contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus().select();
},
close: function(leaveSelection) {
if (!visible.contextMenu()) return false;
contextMenu.fns = [];
$(".contextmenu_bg, .contextmenu").remove();
$("body").css("overflow", "auto");
if (leaveSelection!==true) {
$(".photo.active, .album.active").removeClass("active");
if (visible.multiselect()) multiselect.close();
}
}
};
/**
* @name Init Module
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
$(document).ready(function(){
/* Event Name */
var event_name = (mobileBrowser()) ? "touchend" : "click";
/* Disable ContextMenu */
$(document).bind("contextmenu", function(e) { e.preventDefault() });
/* Tooltips */
if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1});
/* Multiselect */
$("#content").on("mousedown", multiselect.show);
$(document).on("mouseup", multiselect.getSelection);
/* Header */
$("#hostedwith").on(event_name, function() { window.open(lychee.website) });
$("#button_signin").on(event_name, lychee.loginDialog);
$("#button_settings").on("click", contextMenu.settings);
$("#button_share").on(event_name, function(e) {
if (photo.json.public==1||photo.json.public==2) contextMenu.sharePhoto(photo.getID(), e);
else photo.setPublic(photo.getID(), e);
});
$("#button_share_album").on(event_name, function(e) {
if (album.json.public==1) contextMenu.shareAlbum(album.getID(), e);
else album.setPublic(album.getID(), e);
});
$("#button_more").on(event_name, function(e) { contextMenu.photoMore(photo.getID(), e) });
$("#button_trash_album").on(event_name, function() { album.delete([album.getID()]) });
$("#button_move").on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
$("#button_trash").on(event_name, function() { photo.delete([photo.getID()]) });
$("#button_info_album").on(event_name, function() { view.infobox.show() });
$("#button_info").on(event_name, function() { view.infobox.show() });
$("#button_archive").on(event_name, function() { album.getArchive(album.getID()) });
$("#button_star").on(event_name, function() { photo.setStar([photo.getID()]) });
/* Search */
$("#search").on("keyup click", function() { search.find($(this).val()) });
/* Clear Search */
$("#clearSearch").on(event_name, function () {
$("#search").focus();
search.reset();
});
/* Back Buttons */
$("#button_back_home").on(event_name, function() { lychee.goto("") });
$("#button_back").on(event_name, function() { lychee.goto(album.getID()) });
/* Image View */
lychee.imageview
.on(event_name, ".arrow_wrapper.previous", photo.previous)
.on(event_name, ".arrow_wrapper.next", photo.next);
/* Infobox */
$("#infobox")
.on(event_name, ".header a", function() { view.infobox.hide() })
.on(event_name, "#edit_title_album", function() { album.setTitle([album.getID()]) })
.on(event_name, "#edit_description_album", function() { album.setDescription(album.getID()) })
.on(event_name, "#edit_title", function() { photo.setTitle([photo.getID()]) })
.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) })
.on(event_name, "#edit_tags", function() { photo.editTags([photo.getID()]) })
.on(event_name, "#tags .tag span", function() { photo.deleteTag(photo.getID(), $(this).data('index')) });
/* Keyboard */
Mousetrap
.bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() })
.bind('right', function() { if (visible.photo()) $("#imageview a#next").click() })
.bind(['u', 'ctrl+u'], function() { $("#upload_files").click() })
.bind(['s', 'ctrl+s', 'f', 'ctrl+f'], function(e) {
if (visible.photo()) {
$("#button_star").click();
} else if (visible.albums()) {
e.preventDefault();
$("#search").focus();
}
})
.bind(['r', 'ctrl+r'], function(e) {
e.preventDefault();
if (visible.album()) album.setTitle(album.getID());
else if (visible.photo()) photo.setTitle([photo.getID()]);
})
.bind(['d', 'ctrl+d'], function(e) {
e.preventDefault();
if (visible.photo()) photo.setDescription(photo.getID());
else if (visible.album()) album.setDescription(album.getID());
})
.bind(['t', 'ctrl+t'], function(e) {
if (visible.photo()) {
e.preventDefault();
photo.editTags([photo.getID()]);
}
})
.bind(['i', 'ctrl+i'], function() {
if (visible.infobox()) view.infobox.hide();
else if (visible.infoboxbutton()) view.infobox.show();
})
.bind(['command+backspace', 'ctrl+backspace'], function() {
if (visible.photo()&&!visible.message()) photo.delete([photo.getID()]);
else if (visible.album()&&!visible.message()) album.delete([album.getID()]);
});
Mousetrap.bindGlobal('enter', function() {
if ($(".message .button.active").length) $(".message .button.active").addClass("pressed").click()
});
Mousetrap.bindGlobal(['esc', 'command+up'], function(e) {
e.preventDefault();
if (visible.message()&&$(".message .close").length>0) modal.close();
else if (visible.contextMenu()) contextMenu.close();
else if (visible.infobox()) view.infobox.hide();
else if (visible.photo()) lychee.goto(album.getID());
else if (visible.album()) lychee.goto("");
else if (visible.albums()&&$("#search").val().length!==0) search.reset();
});
if (mobileBrowser()) {
$(document)
/* Fullscreen on mobile */
.on('touchend', '#image', function(e) {
if (swipe.obj===null||(swipe.offset>=-5&&swipe.offset<=5)) {
if (visible.controls()) view.header.hide(e, 0);
else view.header.show();
}
})
/* Swipe on mobile */
.swipe().on('swipeStart', function() { if (visible.photo()) swipe.start($("#image")) })
.swipe().on('swipeMove', function(e) { if (visible.photo()) swipe.move(e.swipe) })
.swipe().on('swipeEnd', function(e) { if (visible.photo()) swipe.stop(e.swipe, photo.previous, photo.next) });
}
/* Document */
$(document)
/* Login */
.on("keyup", "#password", function() { if ($(this).val().length>0) $(this).removeClass("error") })
/* Header */
.on(event_name, "#title.editable", function() {
if (visible.photo()) photo.setTitle([photo.getID()]);
else album.setTitle([album.getID()]);
})
/* Navigation */
.on("click", ".album", function() { lychee.goto($(this).attr("data-id")) })
.on("click", ".photo", function() { lychee.goto(album.getID() + "/" + $(this).attr("data-id")) })
/* Modal */
.on(event_name, ".message .close", modal.close)
.on(event_name, ".message .button:first", function() { if (modal.fns!==null) modal.fns[0](); if (!visible.signin()) modal.close() })
.on(event_name, ".message .button:last", function() { if (modal.fns!==null) modal.fns[1](); if (!visible.signin()) modal.close() })
/* Add Dialog */
.on(event_name, ".button_add", function(e) { contextMenu.add(e) })
/* Context Menu */
.on("contextmenu", ".photo", function(e) { contextMenu.photo(photo.getID(), e) })
.on("contextmenu", ".album", function(e) { contextMenu.album(album.getID(), e) })
.on(event_name, ".contextmenu_bg", contextMenu.close)
.on("contextmenu", ".contextmenu_bg", contextMenu.close)
/* Infobox */
.on(event_name, "#infobox_overlay", view.infobox.hide)
/* Upload */
.on("change", "#upload_files", function() { modal.close(); upload.start.local(this.files) })
.on(event_name, ".upload_message a.close", upload.close)
.on("dragover", function(e) { e.preventDefault(); }, false)
.on("drop", function(e) {
e.stopPropagation();
e.preventDefault();
if (e.originalEvent.dataTransfer.files.length>0) upload.start.local(e.originalEvent.dataTransfer.files);
else if (e.originalEvent.dataTransfer.getData('Text').length>3) upload.start.url(e.originalEvent.dataTransfer.getData('Text'));
return true;
});
/* Init */
lychee.init();
});
/**
* @name LoadingBar Module
* @description This module is used to show and hide the loading bar.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
loadingBar = {
status: null,
show: function(status, errorText) {
if (status==='error') {
// Set status
loadingBar.status = 'error';
// Parse text
if (errorText) errorText = errorText.replace('<br>', '');
if (!errorText) errorText = 'Whoops, it looks like something went wrong. Please reload the site and try again!';
// Move header down
if (visible.controls()) lychee.header.addClass('error');
// Modify loading
lychee.loadingBar
.removeClass('loading uploading error')
.addClass(status)
.html('<h1>Error: <span>' + errorText + '</span></h1>')
.show()
.css('height', '40px');
// Set timeout
clearTimeout(lychee.loadingBar.data('timeout'));
lychee.loadingBar.data('timeout', setTimeout(function() { loadingBar.hide(true) }, 3000));
return true;
}
if (loadingBar.status===null) {
// Set status
loadingBar.status = 'loading';
// Set timeout
clearTimeout(lychee.loadingBar.data('timeout'));
lychee.loadingBar.data('timeout', setTimeout(function() {
// Move header down
if (visible.controls()) lychee.header.addClass('loading');
// Modify loading
lychee.loadingBar
.removeClass('loading uploading error')
.addClass('loading')
.show();
}, 1000));
return true;
}
},
hide: function(force) {
if ((loadingBar.status!=='error'&&loadingBar.status!==null)||force) {
// Remove status
loadingBar.status = null;
// Move header up
if (visible.controls()) lychee.header.removeClass('error loading');
// Modify loading
lychee.loadingBar
.html('')
.css('height', '3px');
// Set timeout
clearTimeout(lychee.loadingBar.data('timeout'));
setTimeout(function() { lychee.loadingBar.hide() }, 300);
}
}
};
/**
* @name Lychee Module
* @description This module provides the basic functions of Lychee.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
var lychee = {
title: "",
version: "2.6.1",
version_code: "020601",
api_path: "php/api.php",
update_path: "http://lychee.electerious.com/version/index.php",
updateURL: "https://github.com/electerious/Lychee",
website: "http://lychee.electerious.com",
publicMode: false,
viewMode: false,
debugMode: false,
username: "",
checkForUpdates: false,
sorting: "",
location: "",
dropbox: false,
dropboxKey: '',
loadingBar: $("#loading"),
header: $("header"),
content: $("#content"),
imageview: $("#imageview"),
infobox: $("#infobox"),
init: function() {
var params;
params = "init&version=" + lychee.version_code;
lychee.api(params, function(data) {
if (data.loggedIn!==true) {
lychee.setMode("public");
} else {
lychee.username = data.config.username || '';
lychee.sorting = data.config.sorting || '';
lychee.dropboxKey = data.config.dropboxKey || '';
lychee.location = data.config.location || '';
}
// No configuration
if (data==="Warning: No configuration!") {
lychee.header.hide();
lychee.content.hide();
$("body").append(build.no_content("cog"));
settings.createConfig();
return true;
}
// No login
if (data.config.login===false) {
settings.createLogin();
}
lychee.checkForUpdates = data.config.checkForUpdates;
$(window).bind("popstate", lychee.load);
lychee.load();
});
},
api: function(params, callback, loading) {
if (loading===undefined) loadingBar.show();
$.ajax({
type: "POST",
url: lychee.api_path,
data: "function=" + params,
dataType: "text",
success: function(data) {
setTimeout(function() { loadingBar.hide() }, 100);
if (typeof data==="string"&&data.substring(0, 7)==="Error: ") {
lychee.error(data.substring(7, data.length), params, data);
upload.close(true);
return false;
}
if (data==="1") data = true;
else if (data==="") data = false;
if (typeof data==="string"&&data.substring(0, 1)==="{"&&data.substring(data.length-1, data.length)==="}") data = $.parseJSON(data);
if (lychee.debugMode) console.log(data);
callback(data);
},
error: function(jqXHR, textStatus, errorThrown) {
lychee.error("Server error or API not found.", params, errorThrown);
upload.close(true);
}
});
},
login: function() {
var user = $("input#username").val(),
password = md5($("input#password").val()),
params;
params = "login&user=" + user + "&password=" + password;
lychee.api(params, function(data) {
if (data===true) {
localStorage.setItem("lychee_username", user);
window.location.reload();
} else {
$("#password").val("").addClass("error").focus();
$(".message .button.active").removeClass("pressed");
}
});
},
loginDialog: function() {
var local_username;
$("body").append(build.signInModal());
$("#username").focus();
if (localStorage) {
local_username = localStorage.getItem("lychee_username");
if (local_username!==null) {
if (local_username.length>0) $("#username").val(local_username);
$("#password").focus();
}
}
if (lychee.checkForUpdates==="1") lychee.getUpdate();
},
logout: function() {
lychee.api("logout", function(data) {
window.location.reload();
});
},
goto: function(url) {
if (url===undefined) url = "#";
else url = "#" + url;
history.pushState(null, null, url);
lychee.load();
},
load: function() {
var albumID = "",
photoID = "",
hash = document.location.hash.replace("#", "").split("/");
$(".no_content").remove();
contextMenu.close();
multiselect.close();
if (hash[0]!==undefined) albumID = hash[0];
if (hash[1]!==undefined) photoID = hash[1];
if (albumID&&photoID) {
// Trash data
//albums.json = null;
photo.json = null;
// Show Photo
if (lychee.content.html()===""||($("#search").length&&$("#search").val().length!==0)) {
lychee.content.hide();
album.load(albumID, true);
}
photo.load(photoID, albumID);
photo.preloadNext(photoID,albumID);
} else if (albumID) {
// Trash data
//albums.json = null;
photo.json = null;
// Show Album
if (visible.photo()) view.photo.hide();
if (album.json&&albumID==album.json.id) view.album.title();
else album.load(albumID);
} else {
// Trash data
//albums.json = null;
album.json = null;
photo.json = null;
search.code = "";
// Show Albums
if (visible.album()) view.album.hide();
if (visible.photo()) view.photo.hide();
albums.load();
}
},
getUpdate: function() {
$.ajax({
url: lychee.update_path,
success: function(data) { if (parseInt(data)>parseInt(lychee.version_code)) $("#version span").show(); }
});
},
setTitle: function(title, editable) {
if (lychee.title==="") lychee.title = document.title;
if (title==="Albums") document.title = lychee.title;
else document.title = lychee.title + " - " + title;
if (editable) $("#title").addClass("editable");
else $("#title").removeClass("editable");
$("#title").html(title);
},
setMode: function(mode) {
$("#button_settings, #button_settings, #button_search, #search, #button_trash_album, #button_share_album, .button_add, .button_divider").remove();
$("#button_trash, #button_move, #button_share, #button_star").remove();
$(document)
.on("mouseenter", "#title.editable", function() { $(this).removeClass("editable") })
.off("click", "#title.editable")
.off("touchend", "#title.editable")
.off("contextmenu", ".photo")
.off("contextmenu", ".album")
.off("drop");
Mousetrap
.unbind(['u', 'ctrl+u'])
.unbind(['s', 'ctrl+s'])
.unbind(['r', 'ctrl+r'])
.unbind(['d', 'ctrl+d'])
.unbind(['t', 'ctrl+t'])
.unbind(['command+backspace', 'ctrl+backspace']);
if (mode==="public") {
$("header #button_signin, header #hostedwith").show();
lychee.publicMode = true;
} else if (mode==="view") {
Mousetrap.unbind('esc');
$("#button_back, a#next, a#previous").remove();
$(".no_content").remove();
lychee.publicMode = true;
lychee.viewMode = true;
}
},
animate: function(obj, animation) {
var animations = [
["fadeIn", "fadeOut"],
["contentZoomIn", "contentZoomOut"]
];
if (!obj.jQuery) obj = $(obj);
for (var i = 0; i < animations.length; i++) {
for (var x = 0; x < animations[i].length; x++) {
if (animations[i][x]==animation) {
obj.removeClass(animations[i][0] + " " + animations[i][1]).addClass(animation);
return true;
}
}
}
return false;
},
escapeHTML: function(s) {
return s.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
},
loadDropbox: function(callback) {
if (!lychee.dropbox&&lychee.dropboxKey) {
loadingBar.show();
var g = document.createElement("script"),
s = document.getElementsByTagName("script")[0];
g.src = "https://www.dropbox.com/static/api/1/dropins.js";
g.id = "dropboxjs";
g.type = "text/javascript";
g.async = "true";
g.setAttribute("data-app-key", lychee.dropboxKey);
g.onload = g.onreadystatechange = function() {
var rs = this.readyState;
if (rs&&rs!=="complete"&&rs!=="loaded") return;
lychee.dropbox = true;
loadingBar.hide();
callback();
};
s.parentNode.insertBefore(g, s);
} else if (lychee.dropbox&&lychee.dropboxKey) {
callback();
} else {
settings.setDropboxKey(callback);
}
},
removeHTML: function(html) {
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText;
},
error: function(errorThrown, params, data) {
console.error({
description: errorThrown,
params: params,
response: data
});
loadingBar.show("error", errorThrown);
}
};
/**
* @name Modal Module
* @description Build, show and hide a modal.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
modal = {
fns: null,
show: function(title, text, buttons, marginTop, closeButton) {
if (!buttons) {
buttons = [
["", function() {}],
["", function() {}]
];
}
modal.fns = [buttons[0][1], buttons[1][1]];
$("body").append(build.modal(title, text, buttons, marginTop, closeButton));
$(".message input:first-child").focus().select();
},
close: function() {
modal.fns = null;
$(".message_overlay").removeClass("fadeIn").css("opacity", 0);
setTimeout(function() { $(".message_overlay").remove() }, 300);
}
};
/**
* @name Multiselect Module
* @description Select multiple albums or photos.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
multiselect = {
position: {
top: null,
right: null,
bottom: null,
left: null
},
show: function(e) {
if (mobileBrowser()) return false;
if (lychee.publicMode) return false;
if (visible.search()) return false;
if ($('.album:hover, .photo:hover').length!==0) return false;
if (visible.multiselect()) $('#multiselect').remove();
multiselect.position.top = e.pageY;
multiselect.position.right = -1 * (e.pageX - $(document).width());
multiselect.position.bottom = -1 * (multiselect.position.top - $(window).height());
multiselect.position.left = e.pageX;
$('body').append(build.multiselect(multiselect.position.top, multiselect.position.left));
$(document).on('mousemove', multiselect.resize);
},
resize: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
newHeight,
newWidth;
if (multiselect.position.top===null||
multiselect.position.right===null||
multiselect.position.bottom===null||
multiselect.position.left===null) return false;
if (mouse_y>=multiselect.position.top) {
// Do not leave the screen
newHeight = e.pageY - multiselect.position.top;
if ((multiselect.position.top+newHeight)>=$(document).height())
newHeight -= (multiselect.position.top + newHeight) - $(document).height() + 2;
$('#multiselect').css({
top: multiselect.position.top,
bottom: 'inherit',
height: newHeight
});
} else {
$('#multiselect').css({
top: 'inherit',
bottom: multiselect.position.bottom,
height: multiselect.position.top - e.pageY
});
}
if (mouse_x>=multiselect.position.left) {
// Do not leave the screen
newWidth = e.pageX - multiselect.position.left;
if ((multiselect.position.left+newWidth)>=$(document).width())
newWidth -= (multiselect.position.left + newWidth) - $(document).width() + 2;
$('#multiselect').css({
right: 'inherit',
left: multiselect.position.left,
width: newWidth
});
} else {
$('#multiselect').css({
right: multiselect.position.right,
left: 'inherit',
width: multiselect.position.left - e.pageX
});
}
},
stopResize: function() {
$(document).off('mousemove');
},
getSize: function() {
if (!visible.multiselect()) return false;
return {
top: $('#multiselect').offset().top,
left: $('#multiselect').offset().left,
width: parseInt($('#multiselect').css('width').replace('px', '')),
height: parseInt($('#multiselect').css('height').replace('px', ''))
};
},
getSelection: function(e) {
var tolerance = 150,
id,
ids = [],
offset,
size = multiselect.getSize();
if (visible.contextMenu()) return false;
if (!visible.multiselect()) return false;
$('.photo, .album').each(function() {
offset = $(this).offset();
if (offset.top>=(size.top-tolerance)&&
offset.left>=(size.left-tolerance)&&
(offset.top+206)<=(size.top+size.height+tolerance)&&
(offset.left+206)<=(size.left+size.width+tolerance)) {
id = $(this).data('id');
if (id!=='0'&&id!==0&&id!=='f'&&id!=='s'&&id!=='r'&&id!==null&id!==undefined) {
ids.push(id);
$(this).addClass('active');
}
}
});
if (ids.length!==0&&visible.album()) contextMenu.photoMulti(ids, e);
else if (ids.length!==0&&visible.albums()) contextMenu.albumMulti(ids, e);
else multiselect.close();
},
close: function() {
multiselect.stopResize();
multiselect.position.top = null;
multiselect.position.right = null;
multiselect.position.bottom = null;
multiselect.position.left = null;
lychee.animate('#multiselect', 'fadeOut');
setTimeout(function() {
$('#multiselect').remove();
}, 300);
}
};
/**
* @name Password Module
* @description Controls the access to password-protected albums and photos.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
password = {
value: "",
get: function(albumID, callback) {
var passwd = $(".message input.text").val(),
params;
if (!lychee.publicMode) callback();
else if (album.json&&album.json.password==false) callback();
else if (albums.json&&albums.json.content[albumID].password==false) callback();
else if (!albums.json&&!album.json) {
// Continue without password
album.json = {password: true};
callback("");
} else if (passwd==undefined) {
// Request password
password.getDialog(albumID, callback);
} else {
// Check password
params = "checkAlbumAccess&albumID=" + albumID + "&password=" + md5(passwd);
lychee.api(params, function(data) {
if (data===true) {
password.value = md5(passwd);
callback();
} else {
lychee.goto("");
loadingBar.show("error", "Access denied. Wrong password!");
}
});
}
},
getDialog: function(albumID, callback) {
var buttons;
buttons = [
["Enter", function() { password.get(albumID, callback) }],
["Cancel", lychee.goto]
];
modal.show("<a class='icon-lock'></a> Enter Password", "This album is protected by a password. Enter the password below to view the photos of this album: <input class='text' type='password' placeholder='password' value=''>", buttons, -110, false);
}
};
/**
* @name Photo Module
* @description Takes care of every action a photo can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
cache = null;
photo = {
json: null,
getID: function() {
var id;
if (photo.json) id = photo.json.id;
else id = $(".photo:hover, .photo.active").attr("data-id");
if (id) return id;
else return false;
},
load: function(photoID, albumID) {
var params,
checkPasswd;
params = "getPhoto&photoID=" + photoID + "&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Wrong password!") {
checkPasswd = function() {
if (password.value!=="") photo.load(photoID, albumID);
else setTimeout(checkPasswd, 250);
};
checkPasswd();
return false;
}
photo.json = data;
if (!visible.photo()) view.photo.show();
view.photo.init();
lychee.imageview.show();
setTimeout(function() { lychee.content.show() }, 300);
});
},
//preload the next photo for better response time
preloadNext: function(photoID) {
if(album.json &&
album.json.content &&
album.json.content[photoID] &&
album.json.content[photoID].nextPhoto!="") {
var nextPhoto = album.json.content[photoID].nextPhoto;
var url = album.json.content[nextPhoto].url;
cache = new Image();
cache.src = url;
}
},
parse: function() {
if (!photo.json.title) photo.json.title = "Untitled";
},
previous: function(animate) {
var delay = 0;
if (photo.getID()!==false&&
album.json&&
album.json.content[photo.getID()]&&
album.json.content[photo.getID()].previousPhoto!=="") {
if (animate===true) {
delay = 200;
$("#image").css({
WebkitTransform: 'translateX(100%)',
MozTransform: 'translateX(100%)',
transform: 'translateX(100%)',
opacity: 0
});
}
setTimeout(function() {
if (photo.getID()===false) return false;
lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].previousPhoto)
}, delay);
}
},
next: function(animate) {
var delay = 0;
if (photo.getID()!==false&&
album.json&&
album.json.content[photo.getID()]&&
album.json.content[photo.getID()].nextPhoto!=="") {
if (animate===true) {
delay = 200;
$("#image").css({
WebkitTransform: 'translateX(-100%)',
MozTransform: 'translateX(-100%)',
transform: 'translateX(-100%)',
opacity: 0
});
}
setTimeout(function() {
if (photo.getID()===false) return false;
lychee.goto(album.getID() + "/" + album.json.content[photo.getID()].nextPhoto);
}, delay);
}
},
delete: function(photoIDs) {
var params,
buttons,
photoTitle;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get title if only one photo is selected
if (visible.photo()) photoTitle = photo.json.title;
else photoTitle = album.json.content[photoIDs].title;
if (photoTitle==="") photoTitle = "Untitled";
}
buttons = [
["", function() {
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
// Only when search is not active
if (!visible.albums()) lychee.goto(album.getID());
params = "deletePhoto&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["", function() {}]
];
if (photoIDs.length===1) {
buttons[0][0] = "Delete Photo";
buttons[1][0] = "Keep Photo";
modal.show("Delete Photo", "Are you sure you want to delete the photo '" + photoTitle + "'?<br>This action can't be undone!", buttons);
} else {
buttons[0][0] = "Delete Photos";
buttons[1][0] = "Keep Photos";
modal.show("Delete Photos", "Are you sure you want to delete all " + photoIDs.length + " selected photo?<br>This action can't be undone!", buttons);
}
},
setTitle: function(photoIDs) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get old title if only one photo is selected
if (photo.json) oldTitle = photo.json.title;
else if (album.json) oldTitle = album.json.content[photoIDs].title;
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [
["Set Title", function() {
// Get input
newTitle = $(".message input.text").val();
// Remove html from input
newTitle = lychee.removeHTML(newTitle);
if (visible.photo()) {
photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
view.photo.title();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].title = newTitle;
view.album.content.title(id);
});
params = "setPhotoTitle&photoIDs=" + photoIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
if (photoIDs.length===1) modal.show("Set Title", "Enter a new title for this photo: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
else modal.show("Set Titles", "Enter a title for all " + photoIDs.length + " selected photos: <input class='text' type='text' maxlength='30' placeholder='Title' value=''>", buttons);
},
setAlbum: function(photoIDs, albumID) {
var params,
nextPhoto,
previousPhoto;
if (!photoIDs) return false;
if (visible.photo) lychee.goto(album.getID());
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
params = "setPhotoAlbum&photoIDs=" + photoIDs + "&albumID=" + albumID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setStar: function(photoIDs) {
var params;
if (!photoIDs) return false;
if (visible.photo()) {
photo.json.star = (photo.json.star==0) ? 1 : 0;
view.photo.star();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].star = (album.json.content[id].star==0) ? 1 : 0;
view.album.content.star(id);
});
params = "setPhotoStar&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
albums.refresh();
},
setPublic: function(photoID, e) {
var params;
if (photo.json.public==2) {
modal.show("Public Album", "This photo is located in a public album. To make this photo private or public, edit the visibility of the associated album.", [["Show Album", function() { lychee.goto(photo.json.original_album) }], ["Close", function() {}]]);
return false;
}
albums.refresh();
if (visible.photo()) {
photo.json.public = (photo.json.public==0) ? 1 : 0;
view.photo.public();
if (photo.json.public==1) contextMenu.sharePhoto(photoID, e);
}
album.json.content[photoID].public = (album.json.content[photoID].public==0) ? 1 : 0;
view.album.content.public(photoID);
params = "setPhotoPublic&photoID=" + photoID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setDescription: function(photoID) {
var oldDescription = photo.json.description.replace("'", "&apos;"),
description,
params,
buttons;
buttons = [
["Set Description", function() {
// Get input
description = $(".message input.text").val();
// Remove html from input
description = lychee.removeHTML(description);
if (visible.photo()) {
photo.json.description = description;
view.photo.description();
}
params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(encodeURI(description));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Enter a description for this photo: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
editTags: function(photoIDs) {
var oldTags = "",
tags = "",
buttons;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
// Get tags
if (visible.photo()) oldTags = photo.json.tags;
if (visible.album()&&photoIDs.length===1) oldTags = album.json.content[photoIDs].tags;
if (visible.album()&&photoIDs.length>1) {
var same = true;
photoIDs.forEach(function(id, index, array) {
if(album.json.content[id].tags===album.json.content[photoIDs[0]].tags&&same===true) same = true;
else same = false;
});
if (same) oldTags = album.json.content[photoIDs[0]].tags;
}
// Improve tags
oldTags = oldTags.replace(/,/g, ', ');
buttons = [
["Set Tags", function() {
tags = $(".message input.text").val();
photo.setTags(photoIDs, tags);
}],
["Cancel", function() {}]
];
if (photoIDs.length===1) modal.show("Set Tags", "Enter your tags for this photo. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
else modal.show("Set Tags", "Enter your tags for all " + photoIDs.length + " selected photos. Existing tags will be overwritten. You can add multiple tags by separating them with a comma: <input class='text' type='text' maxlength='800' placeholder='Tags' value='" + oldTags + "'>", buttons);
},
setTags: function(photoIDs, tags) {
var params;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
// Parse tags
tags = tags.replace(/(\ ,\ )|(\ ,)|(,\ )|(,{1,}\ {0,})|(,$|^,)/g, ',');
tags = tags.replace(/,$|^,|(\ ){0,}$/g, '');
// Remove html from input
tags = lychee.removeHTML(tags);
if (visible.photo()) {
photo.json.tags = tags;
view.photo.tags();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].tags = tags;
});
params = "setPhotoTags&photoIDs=" + photoIDs + "&tags=" + tags;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
deleteTag: function(photoID, index) {
var tags;
// Remove
tags = photo.json.tags.split(',');
tags.splice(index, 1);
// Save
photo.json.tags = tags.toString();
photo.setTags([photoID], photo.json.tags);
},
share: function(photoID, service) {
var link = "",
url = photo.getViewLink(photoID),
filename = "unknown";
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(photo.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(photo.json.title) + "&body=" + encodeURI(url);
break;
case 3:
lychee.loadDropbox(function() {
filename = photo.json.title + "." + photo.getDirectLink().split('.').pop();
Dropbox.save(photo.getDirectLink(), filename);
});
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
isSmall: function() {
var size = {
width: false,
height: false
};
if (photo.json.width<$(window).width()-60) size.width = true;
if (photo.json.height<$(window).height()-100) size.height = true;
if (size.width&&size.height) return true;
else return false;
},
getArchive: function(photoID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getPhotoArchive&photoID=" + photoID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getPhotoArchive&photoID=" + photoID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
},
getDirectLink: function() {
return $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
},
getViewLink: function(photoID) {
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, "view.php?p=" + photoID);
else return location.href.replace(location.hash, "view.php?p=" + photoID);
}
};
/**
* @name Search Module
* @description Searches through your photos and albums.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
search = {
code: null,
find: function(term) {
var params,
albumsData = "",
photosData = "",
code;
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
if ($("#search").val().length!==0) {
params = "search&term=" + term;
lychee.api(params, function(data) {
if (data&&data.albums) {
albums.json = { content: data.albums };
$.each(albums.json.content, function() {
albums.parse(this);
albumsData += build.album(this);
});
}
if (data&&data.photos) {
album.json = { content: data.photos };
$.each(album.json.content, function() {
photosData += build.photo(this);
});
}
if (albumsData===""&&photosData==="") code = "error";
else if (albumsData==="") code = build.divider("Photos")+photosData;
else if (photosData==="") code = build.divider("Albums")+albumsData;
else code = build.divider("Photos")+photosData+build.divider("Albums")+albumsData;
if (search.code!==md5(code)) {
$(".no_content").remove();
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomOut");
lychee.animate(".divider", "fadeOut");
search.code = md5(code);
setTimeout(function() {
if (code==="error") $("body").append(build.no_content("search"));
else {
lychee.content.html(code);
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
$("img[data-type!='svg']").retina();
}
}, 300);
}
});
} else search.reset();
}, 250));
},
reset: function() {
$("#search").val("");
$(".no_content").remove();
if (search.code!=="") {
// Trash data
albums.json = null;
album.json = null;
photo.json = null;
search.code = "";
lychee.animate(".divider", "fadeOut");
albums.load();
}
}
};
/**
* @name Settings Module
* @description Lets you change settings.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
var settings = {
createConfig: function() {
var dbName,
dbUser,
dbPassword,
dbHost,
buttons,
params;
buttons = [
["Connect", function() {
dbHost = $(".message input.text#dbHost").val();
dbUser = $(".message input.text#dbUser").val();
dbPassword = $(".message input.text#dbPassword").val();
dbName = $(".message input.text#dbName").val();
if (dbHost.length<1) dbHost = "localhost";
if (dbName.length<1) dbName = "lychee";
params = "dbCreateConfig&dbName=" + escape(dbName) + "&dbUser=" + escape(dbUser) + "&dbPassword=" + escape(dbPassword) + "&dbHost=" + escape(dbHost);
lychee.api(params, function(data) {
if (data!==true) {
// Configuration failed
setTimeout(function() {
// Connection failed
if (data.indexOf("Warning: Connection failed!")!==-1) {
buttons = [
["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}]
];
modal.show("Connection Failed", "Unable to connect to host database because access was denied. Double-check your host, username and password and ensure that access from your current location is permitted.", buttons, null, false);
return false;
}
// Creation failed
if (data.indexOf("Warning: Creation failed!")!==-1) {
buttons = [
["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}]
];
modal.show("Creation Failed", "Unable to create the database. Double-check your host, username and password and ensure that the specified user has the rights to modify and add content to the database.", buttons, null, false);
return false;
}
// Could not create file
if (data.indexOf("Warning: Could not create file!")!==-1) {
buttons = [
["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}]
];
modal.show("Saving Failed", "Unable to save this configuration. Permission denied in <b>'data/'</b>. Please set the read, write and execute rights for others in <b>'data/'</b> and <b>'uploads/'</b>. Take a look the readme for more information.", buttons, null, false);
return false;
}
// Something went wrong
buttons = [
["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}]
];
modal.show("Configuration Failed", "Something unexpected happened. Please try again and check your installation and server. Take a look the readme for more information.", buttons, null, false);
return false;
}, 400);
} else {
// Configuration successful
window.location.reload();
}
});
}],
["", function() {}]
];
modal.show("Configuration", "Enter your database connection details below: <input id='dbHost' class='text less' type='text' placeholder='Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Password' value=''><br>Lychee will create its own database. If required, you can enter the name of an existing database instead:<input id='dbName' class='text more' type='text' placeholder='Database (optional)' value=''>", buttons, -215, false);
},
createLogin: function() {
var username,
password,
params,
buttons;
buttons = [
["Create Login", function() {
username = $(".message input.text#username").val();
password = $(".message input.text#password").val();
if (username.length<1||password.length<1) {
setTimeout(function() {
buttons = [
["Retry", function() { setTimeout(settings.createLogin, 400) }],
["", function() {}]
];
modal.show("Wrong Input", "The username or password you entered is not long enough. Please try again with another username and password!", buttons, null, false);
return false;
}, 400);
} else {
params = "setLogin&username=" + escape(username) + "&password=" + md5(password);
lychee.api(params, function(data) {
if (data!==true) {
setTimeout(function() {
buttons = [
["Retry", function() { setTimeout(settings.createLogin, 400) }],
["", function() {}]
];
modal.show("Creation Failed", "Unable to save login. Please try again with another username and password!", buttons, null, false);
return false;
}, 400);
}
});
}
}],
["", function() {}]
];
modal.show("Create Login", "Enter a username and password for your installation: <input id='username' class='text less' type='text' placeholder='New Username' value=''><input id='password' class='text' type='password' placeholder='New Password' value=''>", buttons, -122, false);
},
setLogin: function() {
var old_password,
username,
password,
params,
buttons;
buttons = [
["Change Login", function() {
old_password = $(".message input.text#old_password").val();
username = $(".message input.text#username").val();
password = $(".message input.text#password").val();
if (old_password.length<1) {
loadingBar.show("error", "Your old password was entered incorrectly. Please try again!");
return false;
}
if (username.length<1) {
loadingBar.show("error", "Your new username was entered incorrectly. Please try again!");
return false;
}
if (password.length<1) {
loadingBar.show("error", "Your new password was entered incorrectly. Please try again!");
return false;
}
params = "setLogin&oldPassword=" + md5(old_password) + "&username=" + escape(username) + "&password=" + md5(password);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Change Login", "Enter your current password: <input id='old_password' class='text more' type='password' placeholder='Current Password' value=''><br>Your username and password will be changed to the following: <input id='username' class='text less' type='text' placeholder='New Username' value=''><input id='password' class='text' type='password' placeholder='New Password' value=''>", buttons, -171);
},
setSorting: function() {
var buttons,
sorting,
params;
buttons = [
["Change Sorting", function() {
sorting[0] = $("select#settings_type").val();
sorting[1] = $("select#settings_order").val();
params = "setSorting&type=" + sorting[0] + "&order=" + sorting[1];
lychee.api(params, function(data) {
if (data===true) {
lychee.sorting = "ORDER BY " + sorting[0] + " " + sorting[1];
lychee.load();
} else lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Change Sorting",
"Sort photos by \
<select id='settings_type'> \
<option value='id'>Upload Time</option> \
<option value='takestamp'>Take Date</option> \
<option value='title'>Title</option> \
<option value='description'>Description</option> \
<option value='public'>Public</option> \
<option value='star'>Star</option> \
<option value='type'>Photo Format</option> \
</select> \
in an \
<select id='settings_order'> \
<option value='ASC'>Ascending</option> \
<option value='DESC'>Descending</option> \
</select> \
order.\
", buttons);
if (lychee.sorting!=="") {
sorting = lychee.sorting.replace("ORDER BY ", "").split(" ");
$("select#settings_type").val(sorting[0]);
$("select#settings_order").val(sorting[1]);
}
},
setDropboxKey: function(callback) {
var buttons,
params,
key;
buttons = [
["Set Key", function() {
key = $(".message input.text#key").val();
params = "setDropboxKey&key=" + key;
lychee.api(params, function(data) {
if (data===true) {
lychee.dropboxKey = key;
if (callback) lychee.loadDropbox(callback);
} else lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Set Dropbox Key", "In order to import photos from your Dropbox, you need a valid drop-ins app key from <a href='https://www.dropbox.com/developers/apps/create'>their website</a>. Generate yourself a personal key and enter it below: <input id='key' class='text' type='text' placeholder='Dropbox API Key' value='" + lychee.dropboxKey + "'>", buttons);
}
};
/**
* @name Swipe Module
* @description Swipes and moves an object.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
swipe = {
obj: null,
tolerance: 150,
offset: 0,
start: function(obj, tolerance) {
if (obj) swipe.obj = obj;
if (tolerance) swipe.tolerance = tolerance;
return true;
},
move: function(e) {
if (swipe.obj===null) return false;
swipe.offset = -1 * e.x;
swipe.obj.css({
WebkitTransform: 'translateX(' + swipe.offset + 'px)',
MozTransform: 'translateX(' + swipe.offset + 'px)',
transform: 'translateX(' + swipe.offset + 'px)'
});
},
stop: function(e, left, right) {
if (e.x<=-swipe.tolerance) left(true);
else if (e.x>=swipe.tolerance) right(true);
else if (swipe.obj!==null) {
swipe.obj.css({
WebkitTransform: 'translateX(0px)',
MozTransform: 'translateX(0px)',
transform: 'translateX(0px)'
});
}
swipe.obj = null;
swipe.offset = 0;
}
};
/**
* @name Album Module
* @description Takes care of every action an album can handle and execute.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
upload = {
show: function(title, files, callback) {
upload.close(true);
$("body").append(build.uploadModal(title, files));
if (callback!=null&&callback!=undefined) callback();
},
notify: function(title, text) {
var popup;
if (!text||text==="") text = "You can now manage your new photo(s).";
if (!window.webkitNotifications) return false;
if (window.webkitNotifications.checkPermission()!==0) window.webkitNotifications.requestPermission();
if (window.webkitNotifications.checkPermission()===0&&title) {
popup = window.webkitNotifications.createNotification("", title, text);
popup.show();
}
},
start: {
local: function(files) {
var albumID = album.getID(),
error = false,
process = function(files, file) {
var formData = new FormData(),
xhr = new XMLHttpRequest(),
pre_progress = 0,
progress,
finish = function() {
window.onbeforeunload = null;
$("#upload_files").val("");
if (error===false) {
// Success
upload.close();
upload.notify("Upload complete");
} else {
// Error
$(".upload_message a.close").show();
upload.notify("Upload complete", "Failed to upload one or more photos.");
}
if (album.getID()===false) lychee.goto("0");
else album.load(albumID);
};
// Check if file is supported
if (file.supported===false) {
// Skip file
if (file.next!==null) process(files, file.next);
else {
// Look for supported files
// If zero files are supported, hide the upload after a delay
var hasSupportedFiles = false;
for (var i = 0; i < files.length; i++) {
if (files[i].supported===true) {
hasSupportedFiles = true;
break;
}
}
if (hasSupportedFiles===false) setTimeout(finish, 2000);
}
return false;
}
formData.append("function", "upload");
formData.append("albumID", albumID);
formData.append(0, file);
xhr.open("POST", lychee.api_path);
xhr.onload = function() {
var wait = false;
file.ready = true;
// Set status
if (xhr.status===200&&xhr.responseText==="1") {
// Success
$(".upload_message .rows .row:nth-child(" + (file.num+1) + ") .status")
.html("Finished")
.addClass("success");
} else {
// Error
$(".upload_message .rows .row:nth-child(" + (file.num+1) + ") .status")
.html("Error")
.addClass("error");
$(".upload_message .rows .row:nth-child(" + (file.num+1) + ") p.notice")
.html("Server returned an unknown response. Please take a look at the console of your browser for further details.")
.show();
// Set global error
error = true;
// Throw error
lychee.error("Upload failed. Server returned the status code " + xhr.status + "!", xhr, xhr.responseText);
}
// Check if there are file which are not finished
for (var i = 0; i < files.length; i++) {
if (files[i].ready===false) {
wait = true;
break;
}
}
// Finish upload when all files are finished
if (wait===false) finish();
};
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
// Calculate progress
progress = (e.loaded / e.total * 100 | 0);
// Set progress when progress has changed
if (progress>pre_progress) {
$(".upload_message .rows .row:nth-child(" + (file.num+1) + ") .status").html(progress + "%");
pre_progress = progress;
}
if (progress>=100) {
// Scroll to the uploading file
var scrollPos = 0;
if ((file.num+1)>4) scrollPos = (file.num + 1 - 4) * 40
$(".upload_message .rows").scrollTop(scrollPos);
// Set status to processing
$(".upload_message .rows .row:nth-child(" + (file.num+1) + ") .status").html("Processing");
// Upload next file
if (file.next!==null) process(files, file.next);
}
}
};
xhr.send(formData);
};
if (files.length<=0) return false;
if (albumID===false||visible.albums()===true) albumID = 0;
for (var i = 0; i < files.length; i++) {
files[i].num = i;
files[i].ready = false;
files[i].supported = true;
if (i < files.length-1) files[i].next = files[i+1];
else files[i].next = null;
// Check if file is supported
if (files[i].type!=="image/jpeg"&&files[i].type!=="image/jpg"&&files[i].type!=="image/png"&&files[i].type!=="image/gif") {
files[i].ready = true;
files[i].supported = false;
}
}
window.onbeforeunload = function() { return "Lychee is currently uploading!"; };
upload.show("Uploading", files);
// Upload first file
process(files, files[0]);
},
url: function() {
var albumID = album.getID(),
params,
extension,
buttons,
link,
files = [];
if (albumID===false) albumID = 0;
buttons = [
["Import", function() {
link = $(".message input.text").val();
if (link&&link.length>3) {
extension = link.split('.').pop();
if (extension!=="jpeg"&&extension!=="jpg"&&extension!=="png"&&extension!=="gif"&&extension!=="webp") {
loadingBar.show("error", "The file format of this link is not supported.");
return false;
}
files[0] = {
name: link,
supported: true
}
upload.show("Importing URL", files, function() {
$(".upload_message .rows .row .status").html("Importing");
});
params = "importUrl&url=" + escape(encodeURI(link)) + "&albumID=" + albumID;
lychee.api(params, function(data) {
upload.close();
upload.notify("Import complete");
if (album.getID()===false) lychee.goto("0");
else album.load(albumID);
if (data!==true) lychee.error(null, params, data);
});
} else loadingBar.show("error", "Link to short or too long. Please try another one!");
}],
["Cancel", function() {}]
];
modal.show("Import from Link", "Please enter the direct link to a photo to import it: <input class='text' type='text' placeholder='http://' value='http://'>", buttons);
},
server: function() {
var albumID = album.getID(),
params,
buttons,
files = [],
path;
if (albumID===false) albumID = 0;
buttons = [
["Import", function() {
path = $(".message input.text").val();
files[0] = {
name: path,
supported: true
};
upload.show("Importing from server", files, function() {
$(".upload_message .rows .row .status").html("Importing");
});
params = "importServer&albumID=" + albumID + "&path=" + escape(encodeURI(path));
lychee.api(params, function(data) {
upload.close();
upload.notify("Import complete");
if (data==="Notice: Import only contains albums!") {
if (visible.albums()) lychee.load();
else lychee.goto("");
}
else if (album.getID()===false) lychee.goto("0");
else album.load(albumID);
if (data==="Notice: Import only contains albums!") return true;
else if (data==="Warning: Folder empty!") lychee.error("Folder empty. No photos imported!", params, data);
else if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
modal.show("Import from Server", "This action will import all photos, folders and sub-folders which are located in the following directory. The <b>original files will be deleted</b> after the import when possible. <input class='text' type='text' maxlength='100' placeholder='Absolute path to directory' value='" + lychee.location + "uploads/import/'>", buttons);
},
dropbox: function() {
var albumID = album.getID(),
params,
links = "";
if (albumID===false) albumID = 0;
lychee.loadDropbox(function() {
Dropbox.choose({
linkType: "direct",
multiselect: true,
success: function(files) {
for (var i = 0; i < files.length; i++) {
links += files[i].link + ",";
files[i] = {
name: files[i].link,
supported: true
};
}
// Remove last comma
links = links.substr(0, links.length-1);
upload.show("Importing from Dropbox", files, function() {
$(".upload_message .rows .row .status").html("Importing");
});
params = "importUrl&url=" + escape(links) + "&albumID=" + albumID;
lychee.api(params, function(data) {
upload.close();
upload.notify("Import complete");
if (album.getID()===false) lychee.goto("0");
else album.load(albumID);
if (data!==true) lychee.error(null, params, data);
});
}
});
});
}
},
close: function(force) {
if (force===true) {
$(".upload_overlay").remove();
} else {
$(".upload_overlay").removeClass("fadeIn").css("opacity", 0);
setTimeout(function() { $(".upload_overlay").remove() }, 300);
}
}
};
/**
* @name UI View
* @description Responsible to reflect data changes to the UI.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
view = {
header: {
show: function() {
var newMargin = -1*($("#imageview #image").height()/2)+20;
clearTimeout($(window).data("timeout"));
lychee.imageview.removeClass("full");
lychee.header.removeClass("hidden");
lychee.loadingBar.css("opacity", 1);
if ($("#imageview #image.small").length>0) $("#imageview #image").css('margin-top', newMargin);
else $("#imageview #image").removeClass('full');
},
hide: function(e, delay) {
var newMargin = -1*($("#imageview #image").height()/2);
if (delay===undefined) delay = 500;
if (visible.photo()&&!visible.infobox()&&!visible.contextMenu()&&!visible.message()) {
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
lychee.imageview.addClass("full");
lychee.header.addClass("hidden");
lychee.loadingBar.css("opacity", 0);
if ($("#imageview #image.small").length>0) $("#imageview #image").css('margin-top', newMargin);
else $("#imageview #image").addClass('full');
}, delay));
}
},
mode: function(mode) {
var albumID = album.getID();
switch (mode) {
case "albums":
lychee.header.removeClass("view");
$("#tools_album, #tools_photo").hide();
$("#tools_albums").show();
break;
case "album":
lychee.header.removeClass("view");
$("#tools_albums, #tools_photo").hide();
$("#tools_album").show();
album.json.content === false ? $("#button_archive").hide() : $("#button_archive").show();
if (lychee.publicMode&&album.json.downloadable==="0") $("#button_archive").hide();
if (albumID==="s"||albumID==="f"||albumID==="r") {
$("#button_info_album, #button_trash_album, #button_share_album").hide();
} else if (albumID==="0") {
$("#button_info_album, #button_share_album").hide();
$("#button_trash_album").show();
} else {
$("#button_info_album, #button_trash_album, #button_share_album").show();
}
break;
case "photo":
lychee.header.addClass("view");
$("#tools_albums, #tools_album").hide();
$("#tools_photo").show();
break;
}
}
},
infobox: {
show: function() {
if (!visible.infobox()) $("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
lychee.infobox.addClass("active");
},
hide: function() {
lychee.animate("#infobox_overlay", "fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
lychee.infobox.removeClass("active");
}
},
albums: {
init: function() {
view.albums.title();
view.albums.content.init();
},
title: function() {
lychee.setTitle("Albums", false);
},
content: {
2014-09-14 12:36:23 +00:00
scroll_pos: 0,
init: function() {
var smartData = "",
albumsData = "";
/* Smart Albums */
albums.parse(albums.json.unsortedAlbum);
albums.parse(albums.json.publicAlbum);
albums.parse(albums.json.starredAlbum);
albums.parse(albums.json.recentAlbum);
if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum) + build.album(albums.json.recentAlbum);
/* Albums */
if (albums.json.content) {
$.each(albums.json.content, function() {
albums.parse(this);
//display albums in reverse order
albumsData = build.album(this) + albumsData;
});
if (!lychee.publicMode) albumsData = build.divider("Albums") + albumsData;
}
if (smartData===""&&albumsData==="") {
lychee.content.html('');
$("body").append(build.no_content("share"));
} else {
lychee.content.html(smartData + albumsData);
}
$("img[data-type!='nonretina']").retina();
2014-09-14 12:36:23 +00:00
//restore scroll
if (view.albums.content.scroll_pos != null) {
//$("html, body").setanimate({ scrollTop: view.albums.content.scroll_pos }, "slow");
$("html, body").scrollTop(view.albums.content.scroll_pos);
}
},
title: function(albumID) {
var prefix = "",
longTitle = "",
title = albums.json.content[albumID].title;
if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
if (title != null && title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".album[data-id='" + albumID + "'] .overlay h1")
.html(prefix + title)
.attr("title", longTitle);
},
delete: function(albumID) {
$(".album[data-id='" + albumID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
if (albums.json.num<=0) lychee.animate(".divider:last-of-type", "fadeOut");
});
}
}
},
album: {
init: function() {
album.parse();
view.album.infobox();
view.album.title();
view.album.public();
view.album.content.init();
album.json.init = 1;
},
hide: function() {
view.infobox.hide();
},
title: function() {
if ((visible.album()||!album.json.init)&&!visible.photo()) {
switch (album.getID()) {
case "f":
lychee.setTitle("Starred", false);
break;
case "s":
lychee.setTitle("Public", false);
break;
case "r":
lychee.setTitle("Recent", false);
break;
case "0":
lychee.setTitle("Unsorted", false);
break;
default:
if (album.json.init) $("#infobox .attr_title").html(album.json.title + " " + build.editIcon("edit_title_album"));
lychee.setTitle(album.json.title, true);
break;
}
}
},
content: {
init: function() {
var photosData = "";
$.each(album.json.content, function() {
photosData += build.photo(this);
});
lychee.content.html(photosData);
$("img[data-type!='svg']").retina();
2014-09-14 12:36:23 +00:00
view.albums.content.scroll_pos = $(document).scrollTop();
//scroll to top
$("html, body").animate({ scrollTop: 0 }, "slow");
},
title: function(photoID) {
var longTitle = "",
title = album.json.content[photoID].title;
if (title != null && title.length>18) {
longTitle = title;
title = title.substr(0, 18) + "...";
}
$(".photo[data-id='" + photoID + "'] .overlay h1")
.html(title)
.attr("title", longTitle);
},
star: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-star").remove();
if (album.json.content[photoID].star==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-star'></a>");
},
public: function(photoID) {
$(".photo[data-id='" + photoID + "'] .icon-share").remove();
if (album.json.content[photoID].public==1) $(".photo[data-id='" + photoID + "']").append("<a class='badge red icon-share'></a>");
},
delete: function(photoID) {
$(".photo[data-id='" + photoID + "']").css("opacity", 0).animate({
width: 0,
marginLeft: 0
}, 300, function() {
$(this).remove();
// Only when search is not active
if (!visible.albums()) {
album.json.num--;
view.album.num();
view.album.title();
}
});
}
},
description: function() {
$("#infobox .attr_description").html(album.json.description + " " + build.editIcon("edit_description_album"));
},
num: function() {
$("#infobox .attr_images").html(album.json.num);
},
public: function() {
if (album.json.public==1) {
$("#button_share_album a").addClass("active");
$("#button_share_album").attr("title", "Share Album");
$(".photo .icon-share").remove();
if (album.json.init) $("#infobox .attr_visibility").html("Public");
} else {
$("#button_share_album a").removeClass("active");
$("#button_share_album").attr("title", "Make Public");
if (album.json.init) $("#infobox .attr_visibility").html("Private");
}
},
password: function() {
if (album.json.password==1) $("#infobox .attr_password").html("Yes");
else $("#infobox .attr_password").html("No");
},
infobox: function() {
if ((visible.album()||!album.json.init)&&!visible.photo()) lychee.infobox.html(build.infoboxAlbum(album.json)).show();
}
},
photo: {
init: function() {
photo.parse();
view.photo.infobox();
view.photo.title();
view.photo.star();
view.photo.public();
view.photo.photo();
photo.json.init = 1;
},
show: function() {
// Change header
lychee.content.addClass("view");
view.header.mode("photo");
// Make body not scrollable
$("body").css("overflow", "hidden");
// Fullscreen
$(document)
.bind("mouseenter", view.header.show)
.bind("mouseleave", view.header.hide);
lychee.animate(lychee.imageview, "fadeIn");
},
hide: function() {
view.header.show();
if (visible.infobox) view.infobox.hide();
lychee.content.removeClass("view");
view.header.mode("album");
// Make body scrollable
$("body").css("overflow", "auto");
// Disable Fullscreen
$(document)
.unbind("mouseenter")
.unbind("mouseleave");
// Hide Photo
lychee.animate(lychee.imageview, "fadeOut");
setTimeout(function() {
lychee.imageview.hide();
view.album.infobox();
}, 300);
},
title: function() {
if (photo.json.init) $("#infobox .attr_title").html(photo.json.title + " " + build.editIcon("edit_title"));
lychee.setTitle(photo.json.title, true);
},
description: function() {
if (photo.json.init) $("#infobox .attr_description").html(photo.json.description + " " + build.editIcon("edit_description"));
},
star: function() {
$("#button_star a").removeClass("icon-star-empty icon-star");
if (photo.json.star==1) {
// Starred
$("#button_star a").addClass("icon-star");
$("#button_star").attr("title", "Unstar Photo");
} else {
// Unstarred
$("#button_star a").addClass("icon-star-empty");
$("#button_star").attr("title", "Star Photo");
}
},
public: function() {
if (photo.json.public==1||photo.json.public==2) {
// Photo public
$("#button_share a").addClass("active");
$("#button_share").attr("title", "Share Photo");
if (photo.json.init) $("#infobox .attr_visibility").html("Public");
} else {
// Photo private
$("#button_share a").removeClass("active");
$("#button_share").attr("title", "Make Public");
if (photo.json.init) $("#infobox .attr_visibility").html("Private");
}
},
tags: function() {
$("#infobox #tags").html(build.tags(photo.json.tags));
},
photo: function() {
lychee.imageview.html(build.imageview(photo.json, photo.isSmall(), visible.controls()));
if ((album.json&&album.json.content&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto==="")||lychee.viewMode) $("a#next").hide();
if ((album.json&&album.json.content&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].previousPhoto==="")||lychee.viewMode) $("a#previous").hide();
},
infobox: function() {
lychee.infobox.html(build.infoboxPhoto(photo.json)).show();
}
}
};
/**
* @name Visible Module
* @description This module is used to check if elements are visible or not.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
visible = {
albums: function() {
if ($('#tools_albums').css('display')==='block') return true;
else return false;
},
album: function() {
if ($('#tools_album').css('display')==='block') return true;
else return false;
},
photo: function() {
if ($('#imageview.fadeIn').length>0) return true;
else return false;
},
search: function() {
if (search.code!==null&&search.code!=='') return true;
else return false;
},
infobox: function() {
if ($('#infobox.active').length>0) return true;
else return false;
},
infoboxbutton: function() {
if (visible.albums()) return false;
if (visible.photo()) return true;
if (visible.album()&&$('#button_info_album:visible').length>0) return true;
else return false;
},
controls: function() {
if (lychee.loadingBar.css('opacity')<1) return false;
else return true;
},
message: function() {
if ($('.message').length>0) return true;
else return false;
},
signin: function() {
if ($('.message .sign_in').length>0) return true;
else return false;
},
contextMenu: function() {
if ($('.contextmenu').length>0) return true;
else return false;
},
multiselect: function() {
if ($('#multiselect').length>0) return true;
else return false;
}
};