16
.gitignore
vendored
@ -1,16 +1,18 @@
|
||||
build/node_modules/
|
||||
build/bower_components/
|
||||
src/node_modules/
|
||||
src/bower_components/
|
||||
|
||||
php/config.php
|
||||
data/config.php
|
||||
|
||||
uploads/import/*
|
||||
uploads/big/*
|
||||
uploads/import/*
|
||||
uploads/medium/*
|
||||
uploads/thumb/*
|
||||
plugins/*
|
||||
etc/*
|
||||
|
||||
!uploads/import/index.html
|
||||
!uploads/big/index.html
|
||||
!uploads/import/index.html
|
||||
!uploads/medium/index.html
|
||||
!uploads/thumb/index.html
|
||||
!plugins/check/
|
||||
|
||||
!plugins/check/
|
||||
!plugins/displaylog/
|
@ -13,7 +13,7 @@ When reporting a bug on GitHub, make sure you include the following information:
|
||||
- How to reproduce the issue (step-by-step)
|
||||
- What you have already tried
|
||||
- Output of the diagnostics (`plugins/check/index.php`)
|
||||
- Browser and Browser version
|
||||
- Browser and system version
|
||||
- Attach files when you have problems which specific photos
|
||||
|
||||
## Coding Guidelines
|
||||
|
28
Dockerfile
@ -4,27 +4,31 @@ FROM ubuntu:14.04
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install git curl nano wget build-essential
|
||||
|
||||
# Install apache and PHP
|
||||
RUN apt-get -y install apache2 mysql-server libapache2-mod-php5
|
||||
RUN apt-get -y install php5-mysql php5-gd php5-curl
|
||||
#RUN sed -i "s/variables_order.*/variables_order = \"EGPCS\"/g" /etc/php5/apache2/php.ini
|
||||
# Install Apache, PHP, MySQL, and ImageMagick
|
||||
RUN apt-get -y install apache2 mysql-server libapache2-mod-php5 imagemagick
|
||||
RUN apt-get -y install php5-mysql php5-gd php5-curl php5-imagick
|
||||
|
||||
# Decouple database from container
|
||||
VOLUME ["/database"]
|
||||
|
||||
# Configure the database to use our data dir
|
||||
RUN sed -i -e "s/^datadir\s*=.*/datadir = \/database/" /etc/mysql/my.cnf
|
||||
# Modify php.ini to contain the following settings:
|
||||
# max_execution_time = 200
|
||||
# post_max_size = 100M
|
||||
# upload_max_size = 100M
|
||||
# upload_max_filesize = 20M
|
||||
# memory_limit = 256M
|
||||
RUN sed -i -e "s/^max_execution_time\s*=.*/max_execution_time = 200/" \
|
||||
-e "s/^post_max_size\s*=.*/post_max_size = 100M/" \
|
||||
-e "s/^upload_max_filesize\s*=.*/upload_max_filesize = 20M\nupload_max_size = 100M/" \
|
||||
-e "s/^memory_limit\s*=.*/memory_limit = 256M/" /etc/php5/apache2/php.ini
|
||||
|
||||
# Link /var/www to /app directory
|
||||
RUN mkdir -p /app && rm -fr /var/www/html && ln -s /app /var/www/html
|
||||
WORKDIR /app
|
||||
|
||||
# Clone lychee
|
||||
RUN git clone https://github.com/renfredxh/Lychee.git .
|
||||
RUN git clone https://github.com/electerious/Lychee.git .
|
||||
|
||||
# Set file permissions
|
||||
RUN chown www-data:www-data /app -R
|
||||
RUN chown -R www-data:www-data /app
|
||||
RUN chmod -R 777 uploads/ data/
|
||||
|
||||
EXPOSE 80
|
||||
CMD scripts/start
|
||||
CMD src/commands/start
|
@ -2,8 +2,8 @@
|
||||
|
||||
#### A great looking and easy-to-use Photo-Management-System.
|
||||
|
||||
![Lychee](http://l.electerious.com/uploads/big/136b4779d133a94666d5f0d151b8ea2f.png)
|
||||
![Lychee](http://l.electerious.com/uploads/big/580f1300f884c330fa34b652decb0571.png)
|
||||
![Lychee](http://l.electerious.com/uploads/big/68375288e048658e253a7c0c964f19b9.jpg)
|
||||
![Lychee](http://l.electerious.com/uploads/big/198f237580ea004529ab7b6faad90274.jpg)
|
||||
|
||||
Lychee is a free photo-management tool, which runs on your server or web-space. Installing is a matter of seconds. Upload, manage and share photos like from a native application. Lychee comes with everything you need and all your photos are stored securely. Try the [Live Demo](http://electerious.com/lychee_demo/) or read more on our [Website](http://lychee.electerious.com).
|
||||
|
||||
@ -39,6 +39,10 @@ In order to use the Dropbox import from your server, you need a valid drop-ins a
|
||||
|
||||
Lychee supports [Twitter Cards](https://dev.twitter.com/docs/cards) and [Open Graph](http://opengraphprotocol.org) for shared images (not albums). In order to use Twitter Cards you need to request an approval for your domain. Simply share an image with Lychee, copy its link and paste it in [Twitters Card Validator](https://dev.twitter.com/docs/cards/validation/validator).
|
||||
|
||||
### Imagick
|
||||
|
||||
Lychee uses [Imagick](http://www.imagemagick.org) when installed on your server. In this case you will benefit from a faster processing of your uploads, better looking thumbnails and intermediate sized images for small screen devices. You can disable the usage of [Imagick](http://www.imagemagick.org) in [the settings](docs/Settings.md).
|
||||
|
||||
### Plugins and Extensions
|
||||
|
||||
The plugin-system of Lychee allows you to execute scripts, when a certain action fires. Plugins are hooks, which are injected directly into Lychee. [Plugin documentation »](docs/Plugins.md)
|
||||
|
@ -1 +0,0 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><title>no_images</title><g sketch:type="MSLayerGroup" fill="none"><rect fill="#222" sketch:type="MSShapeGroup" width="200" height="200"/><g transform="translate(68 52)" sketch:type="MSShapeGroup"><rect stroke="#B4B4B4" stroke-width="4" width="50" height="42" rx="3"/><rect fill="#222" x="11" y="11" width="44" height="36"/><rect stroke="#B4B4B4" stroke-width="4" x="20" y="20" width="50" height="42" rx="3"/></g></g></svg>
|
Before Width: | Height: | Size: 542 B |
@ -1 +0,0 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><title>password</title><g sketch:type="MSLayerGroup" fill="none"><rect fill="#222" sketch:type="MSShapeGroup" width="200" height="200"/><path d="M118 73h2.999c4.413 0 8.001 3.579 8.001 7.994v28.013c0 4.412-3.582 7.994-8.001 7.994h-40.999c-4.413 0-8.001-3.579-8.001-7.994v-28.013c0-4.412 3.582-7.994 8.001-7.994h2.999v-9.495c0-9.665 7.835-17.505 17.5-17.505 9.667 0 17.5 7.837 17.5 17.505v9.495zm-17.5-20c-5.799 0-10.5 4.702-10.5 10.498v9.502h21v-9.502c0-5.798-4.7-10.498-10.5-10.498zm0 0" fill="#B4B4B4" sketch:type="MSShapeGroup"/></g></svg>
|
Before Width: | Height: | Size: 662 B |
@ -1,17 +0,0 @@
|
||||
/* 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);
|
@ -1,400 +0,0 @@
|
||||
/**
|
||||
* @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() {
|
||||
|
||||
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)) {
|
||||
albums.refresh();
|
||||
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) {
|
||||
albums.json.num--;
|
||||
view.albums.content.delete(id);
|
||||
delete albums.json.content[id];
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
albums.refresh();
|
||||
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("'", "'");
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (albums.json) {
|
||||
var id = albumIDs[0];
|
||||
albums.json.content[id].title = newTitle;
|
||||
}
|
||||
|
||||
} else if (visible.albums()) {
|
||||
|
||||
albumIDs.forEach(function(id) {
|
||||
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("'", "'"),
|
||||
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,
|
||||
url = "php/api.php?function=getAlbumArchive&albumID=" + albumID;
|
||||
|
||||
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", url);
|
||||
else link = location.href.replace(location.hash, "") + url;
|
||||
|
||||
if (lychee.publicMode) link += "&password=" + password.value;
|
||||
|
||||
location.href = link;
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,113 +0,0 @@
|
||||
/**
|
||||
* @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(albums.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 {
|
||||
|
||||
setTimeout(function() {
|
||||
view.header.mode("albums");
|
||||
view.albums.init();
|
||||
lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
|
||||
}, 300);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
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() {
|
||||
|
||||
albums.json = null;
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,489 +0,0 @@
|
||||
/**
|
||||
* @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' value='' placeholder='username' autocapitalize='off' autocorrect='off'>";
|
||||
modal += "<input id='password' type='password' value='' placeholder='password'>";
|
||||
modal += "</div>";
|
||||
modal += "<div id='version'>Version " + lychee.version + "<span> – <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,
|
||||
exifHash = "";
|
||||
|
||||
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)]
|
||||
];
|
||||
|
||||
exifHash = photoJSON.takestamp+photoJSON.make+photoJSON.model+photoJSON.shutter+photoJSON.aperture+photoJSON.focal+photoJSON.iso;
|
||||
|
||||
if (exifHash!="0"&&exifHash!=="null") {
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,354 +0,0 @@
|
||||
/**
|
||||
* @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() { photo.duplicate([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-copy'></a> Duplicate", 3],
|
||||
["<a class='icon-folder-open'></a> Move", 4],
|
||||
["<a class='icon-trash'></a> Delete", 5]
|
||||
];
|
||||
|
||||
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() { photo.duplicate(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-copy'></a> Duplicate All", 3],
|
||||
["<a class='icon-folder-open'></a> Move All", 4],
|
||||
["<a class='icon-trash'></a> Delete All", 5]
|
||||
];
|
||||
|
||||
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,
|
||||
link = "";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,205 +0,0 @@
|
||||
/**
|
||||
* @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.multiselect()) return false;
|
||||
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()]);
|
||||
})
|
||||
.bind(['command+a', 'ctrl+a'], function() {
|
||||
if (visible.album()&&!visible.message()) multiselect.selectAll();
|
||||
else if (visible.albums()&&!visible.message()) multiselect.selectAll();
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
// Close open overlays or views which are correlating with the upload
|
||||
if (visible.photo()) lychee.goto(album.getID());
|
||||
if (visible.contextMenu()) contextMenu.close();
|
||||
|
||||
// Detect if dropped item is a file or a link
|
||||
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();
|
||||
|
||||
});
|
@ -1,91 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,377 +0,0 @@
|
||||
/**
|
||||
* @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.3",
|
||||
version_code: "020603",
|
||||
|
||||
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) {
|
||||
|
||||
// Use 'try' to catch a thrown error when Safari is in private mode
|
||||
try { localStorage.setItem("lychee_username", user); }
|
||||
catch (err) {}
|
||||
|
||||
window.location.reload();
|
||||
|
||||
} else {
|
||||
|
||||
// Show error and reactive button
|
||||
$("#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() {
|
||||
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
|
||||
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);
|
||||
|
||||
} else if (albumID) {
|
||||
|
||||
// Trash data
|
||||
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
|
||||
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, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
|
||||
},
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,210 +0,0 @@
|
||||
/**
|
||||
* @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 (visible.infobox()) return false;
|
||||
if (!visible.albums()&&!visible.album) 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);
|
||||
|
||||
},
|
||||
|
||||
selectAll: function() {
|
||||
|
||||
var e,
|
||||
newWidth,
|
||||
newHeight;
|
||||
|
||||
if (mobileBrowser()) return false;
|
||||
if (lychee.publicMode) return false;
|
||||
if (visible.search()) return false;
|
||||
if (visible.infobox()) return false;
|
||||
if (!visible.albums()&&!visible.album) return false;
|
||||
if (visible.multiselect()) $('#multiselect').remove();
|
||||
|
||||
multiselect.position.top = 70;
|
||||
multiselect.position.right = 40;
|
||||
multiselect.position.bottom = 90;
|
||||
multiselect.position.left = 20;
|
||||
|
||||
$('body').append(build.multiselect(multiselect.position.top, multiselect.position.left));
|
||||
|
||||
newWidth = $(document).width() - multiselect.position.right + 2;
|
||||
newHeight = $(document).height() - multiselect.position.bottom;
|
||||
|
||||
$('#multiselect').css({
|
||||
width: newWidth,
|
||||
height: newHeight
|
||||
});
|
||||
|
||||
e = {
|
||||
pageX: $(document).width() - (multiselect.position.right / 2),
|
||||
pageY: $(document).height() - multiselect.position.bottom
|
||||
};
|
||||
|
||||
multiselect.getSelection(e);
|
||||
|
||||
},
|
||||
|
||||
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 = mouse_y - 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 = mouse_x - 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);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,590 +0,0 @@
|
||||
/**
|
||||
* @name Photo Module
|
||||
* @description Takes care of every action a photo can handle and execute.
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
photo = {
|
||||
|
||||
json: null,
|
||||
cache: 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();
|
||||
//photo.preloadNext(photoID, albumID);
|
||||
}, 300);
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
//preload the next photo for better response time
|
||||
preloadNext: function(photoID) {
|
||||
|
||||
var nextPhoto,
|
||||
url;
|
||||
|
||||
// Never preload on mobile devices with bare RAM and
|
||||
// mostly mobile internet
|
||||
if (mobileBrowser()) return false;
|
||||
|
||||
if (album.json &&
|
||||
album.json.content &&
|
||||
album.json.content[photoID] &&
|
||||
album.json.content[photoID].nextPhoto!="") {
|
||||
|
||||
nextPhoto = album.json.content[photoID].nextPhoto;
|
||||
url = album.json.content[nextPhoto].url;
|
||||
|
||||
photo.cache = new Image();
|
||||
photo.cache.src = url;
|
||||
photo.cache.onload = function() { photo.cache = null };
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
duplicate: function(photoIDs) {
|
||||
|
||||
var params;
|
||||
|
||||
if (!photoIDs) return false;
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = "duplicatePhoto&photoIDs=" + photoIDs;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
else album.load(album.getID(), false);
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
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() {
|
||||
|
||||
var nextPhoto,
|
||||
previousPhoto;
|
||||
|
||||
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());
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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("'", "'");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
});
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = "setPhotoStar&photoIDs=" + photoIDs;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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("'", "'"),
|
||||
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,
|
||||
url = "php/api.php?function=getPhotoArchive&photoID=" + photoID;
|
||||
|
||||
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", url);
|
||||
else link = location.href.replace(location.hash, "") + url;
|
||||
|
||||
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) {
|
||||
|
||||
var url = "view.php?p=" + photoID;
|
||||
|
||||
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, url);
|
||||
else return location.href.replace(location.hash, url);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,97 +0,0 @@
|
||||
/**
|
||||
* @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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,292 +0,0 @@
|
||||
/**
|
||||
* @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,
|
||||
dbTablePrefix,
|
||||
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();
|
||||
dbTablePrefix = $(".message input.text#dbTablePrefix").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) + "&dbTablePrefix=" + escape(dbTablePrefix);
|
||||
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='Database Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Database Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Database 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 less' type='text' placeholder='Database Name (optional)' value=''><input id='dbTablePrefix' class='text more' type='text' placeholder='Table prefix (optional)' value=''>", buttons, -235, 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();
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,54 +0,0 @@
|
||||
/**
|
||||
* @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;
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,402 +0,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.");
|
||||
|
||||
}
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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("tags", "");
|
||||
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");
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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");
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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");
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,497 +0,0 @@
|
||||
/**
|
||||
* @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: {
|
||||
|
||||
scrollPosition: 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();
|
||||
|
||||
/* Restore scroll position */
|
||||
if (view.albums.content.scrollPosition!==null) {
|
||||
$("html, body").scrollTop(view.albums.content.scrollPosition);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
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();
|
||||
|
||||
/* Save and reset scroll position */
|
||||
view.albums.content.scrollPosition = $(document).scrollTop();
|
||||
$("html, body").scrollTop(0);
|
||||
|
||||
},
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -1,110 +0,0 @@
|
||||
/**
|
||||
* @name Main
|
||||
* @description Used to view single photos with view.php
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
var header = $("header"),
|
||||
headerTitle = $("#title"),
|
||||
imageview = $("#imageview"),
|
||||
api_path = "php/api.php",
|
||||
infobox = $("#infobox");
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
/* Event Name */
|
||||
if (mobileBrowser()) event_name = "touchend";
|
||||
else event_name = "click";
|
||||
|
||||
/* Window */
|
||||
$(window).keydown(key);
|
||||
|
||||
/* Infobox */
|
||||
$(document).on(event_name, "#infobox .header a", function() { hideInfobox() });
|
||||
$(document).on(event_name, "#infobox_overlay", function() { hideInfobox() });
|
||||
$("#button_info").on(event_name, function() { showInfobox() });
|
||||
|
||||
/* Direct Link */
|
||||
$("#button_direct").on(event_name, function() {
|
||||
|
||||
link = $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
|
||||
window.open(link,"_newtab");
|
||||
|
||||
});
|
||||
|
||||
loadPhotoInfo(gup("p"));
|
||||
|
||||
});
|
||||
|
||||
function key(e) {
|
||||
|
||||
code = (e.keyCode ? e.keyCode : e.which);
|
||||
if (code===27&&visibleInfobox()) { hideInfobox(); e.preventDefault(); }
|
||||
|
||||
}
|
||||
|
||||
function visibleInfobox() {
|
||||
|
||||
if (parseInt(infobox.css("right").replace("px", ""))<0) return false;
|
||||
else return true;
|
||||
|
||||
}
|
||||
|
||||
function isPhotoSmall(photo) {
|
||||
|
||||
size = [
|
||||
["width", false],
|
||||
["height", false]
|
||||
];
|
||||
|
||||
if (photo.width<$(window).width()-60) size["width"] = true;
|
||||
if (photo.height<$(window).height()-100) size["height"] = true;
|
||||
|
||||
if (size["width"]&&size["height"]) return true;
|
||||
else return false;
|
||||
|
||||
}
|
||||
|
||||
function showInfobox() {
|
||||
|
||||
$("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
|
||||
infobox.addClass("active");
|
||||
|
||||
}
|
||||
|
||||
function hideInfobox() {
|
||||
|
||||
$("#infobox_overlay").removeClass("fadeIn").addClass("fadeOut");
|
||||
setTimeout(function() { $("#infobox_overlay").remove() }, 300);
|
||||
infobox.removeClass("active");
|
||||
|
||||
}
|
||||
|
||||
function loadPhotoInfo(photoID) {
|
||||
|
||||
params = "function=getPhoto&photoID=" + photoID + "&albumID=0&password=''";
|
||||
$.ajax({type: "POST", url: api_path, data: params, dataType: "json", success: function(data) {
|
||||
|
||||
if (!data.title) data.title = "Untitled";
|
||||
document.title = "Lychee - " + data.title;
|
||||
headerTitle.html(data.title);
|
||||
|
||||
imageview.attr("data-id", photoID);
|
||||
if (isPhotoSmall(data)) imageview.html("<div id='image' class='small' style='background-image: url(" + data.url + "); width: " + data.width + "px; height: " + data.height + "px; margin-top: -" + parseInt((data.height/2)-20) + "px; margin-left: -" + data.width/2 + "px;'></div>");
|
||||
else imageview.html("<div id='image' style='background-image: url(" + data.url + ");'></div>");
|
||||
imageview.removeClass("fadeOut").addClass("fadeIn").show();
|
||||
|
||||
infobox.html(build.infoboxPhoto(data, true)).show();
|
||||
|
||||
}, error: ajaxError });
|
||||
|
||||
}
|
||||
|
||||
function ajaxError(jqXHR, textStatus, errorThrown) {
|
||||
|
||||
console.log(jqXHR);
|
||||
console.log(textStatus);
|
||||
console.log(errorThrown);
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
};
|
@ -1,245 +0,0 @@
|
||||
/**
|
||||
* @name content.css
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
/* Gradient ------------------------------------------------*/
|
||||
#content::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background: linear-gradient(to bottom, #262626, #222);
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
/* Modes ------------------------------------------------*/
|
||||
#content.view::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content {
|
||||
position: absolute;
|
||||
padding: 50px 0px 33px 0px;
|
||||
width: 100%;
|
||||
min-height: calc(100% - 90px);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Photo ------------------------------------------------*/
|
||||
.photo {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
width: 206px;
|
||||
height: 206px;
|
||||
margin: 30px 0px 0px 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.photo img {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #222;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #ccc;
|
||||
}
|
||||
.photo:hover img,
|
||||
.photo.active img {
|
||||
box-shadow: 0px 0px 5px #005ecc;
|
||||
}
|
||||
.photo:active {
|
||||
transition-duration: .1s;
|
||||
transform: scale(.98);
|
||||
}
|
||||
|
||||
/* Album ------------------------------------------------*/
|
||||
.album {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
width: 204px;
|
||||
height: 204px;
|
||||
margin: 30px 0px 0px 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.album img:first-child,
|
||||
.album img:nth-child(2) {
|
||||
transform: rotate(0deg) translateY(0px) translateX(0px);
|
||||
opacity: 0;
|
||||
}
|
||||
.album:hover img:first-child {
|
||||
transform: rotate(-2deg) translateY(10px) translateX(-12px);
|
||||
opacity: 1;
|
||||
}
|
||||
.album:hover img:nth-child(2) {
|
||||
transform: rotate(5deg) translateY(-8px) translateX(12px);
|
||||
opacity: 1;
|
||||
}
|
||||
.album img {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #222;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #ccc;
|
||||
}
|
||||
.album:hover img,
|
||||
.album.active img {
|
||||
box-shadow: 0px 0px 5px #005ecc;
|
||||
}
|
||||
|
||||
/* Album/Photo Overlay ------------------------------------------------*/
|
||||
.album .overlay,
|
||||
.photo .overlay {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 2px;
|
||||
}
|
||||
.album .overlay {
|
||||
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 40%,rgba(0,0,0,0.85) 100%);
|
||||
}
|
||||
.photo .overlay {
|
||||
background: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 60%, rgba(0,0,0,0.5) 80%, rgba(0,0,0,0.9) 100%);
|
||||
opacity: 0;
|
||||
}
|
||||
.photo:hover .overlay,
|
||||
.photo.active .overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
.album .overlay h1,
|
||||
.photo .overlay h1 {
|
||||
min-height: 19px;
|
||||
width: 185px;
|
||||
margin: 153px 0px 3px 15px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
.album .overlay a,
|
||||
.photo .overlay a {
|
||||
font-size: 11px;
|
||||
color: #aaa;
|
||||
}
|
||||
.album .overlay a {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.photo .overlay a {
|
||||
margin: 155px 0px 5px 15px;
|
||||
}
|
||||
.photo .overlay a span {
|
||||
margin: 0px 5px 0px 0px;
|
||||
}
|
||||
|
||||
/* Badges ------------------------------------------------*/
|
||||
.album .badge,
|
||||
.photo .badge {
|
||||
position: absolute;
|
||||
margin-top: -1px;
|
||||
margin-left: 12px;
|
||||
padding: 12px 7px 3px 7px;
|
||||
box-shadow: 0px 0px 3px rgba(0, 0, 0, .8);
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
border: 1px solid #fff;
|
||||
border-top: none;
|
||||
color: #fff;
|
||||
font-size: 24px;
|
||||
text-shadow: 0px 1px 0px rgba(0, 0, 0, .4);
|
||||
opacity: .9;
|
||||
}
|
||||
.album .badge.icon-star,
|
||||
.photo .badge.icon-star {
|
||||
padding: 12px 8px 3px 8px;
|
||||
}
|
||||
.album .badge.icon-share,
|
||||
.photo .badge.icon-share {
|
||||
padding: 12px 6px 3px 8px;
|
||||
}
|
||||
.album .badge.icon-time,
|
||||
.photo .badge.icon-time {
|
||||
padding: 12px 8px 3px 9px;
|
||||
}
|
||||
.album .badge::after,
|
||||
.photo .badge::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
margin-top: -12px;
|
||||
margin-left: -26px;
|
||||
width: 38px;
|
||||
height: 5px;
|
||||
background: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 100%);
|
||||
opacity: .4;
|
||||
}
|
||||
.album .badge.icon-star::after,
|
||||
.photo .badge.icon-star::after {
|
||||
margin-left: -29px;
|
||||
}
|
||||
.album .badge.icon-share::after,
|
||||
.photo .badge.icon-share::after {
|
||||
margin-left: -31px;
|
||||
}
|
||||
.album .badge.icon-time::after,
|
||||
.photo .badge.icon-time::after {
|
||||
margin-left: -29px;
|
||||
}
|
||||
.album .badge.icon-reorder::after {
|
||||
margin-left: -30px;
|
||||
}
|
||||
.album .badge:nth-child(2n),
|
||||
.photo .badge:nth-child(2n) {
|
||||
margin-left: 57px;
|
||||
}
|
||||
.album .badge.red,
|
||||
.photo .badge.red {
|
||||
background: linear-gradient(to bottom, #d64b4b 0%, #ab2c2c 100%);
|
||||
}
|
||||
.album .badge.blue,
|
||||
.photo .badge.blue {
|
||||
background: linear-gradient(to bottom, #347cd6 0%, #2945ab 100%);
|
||||
}
|
||||
|
||||
/* Divider ------------------------------------------------*/
|
||||
.divider {
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin-top: 50px;
|
||||
opacity: 0;
|
||||
border-top: 1px solid #2E2E2E;
|
||||
box-shadow: 0px -1px 0px #151515;
|
||||
}
|
||||
.divider:first-child {
|
||||
margin-top: 0px;
|
||||
border-top: none;
|
||||
}
|
||||
.divider h1 {
|
||||
float: left;
|
||||
margin: 20px 0px 0px 30px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
/* No Content ------------------------------------------------*/
|
||||
.no_content {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: 160px;
|
||||
width: 180px;
|
||||
margin-top: -60px;
|
||||
margin-left: -90px;
|
||||
padding-top: 20px;
|
||||
color: rgba(20, 20, 20, 1);
|
||||
text-shadow: 0px 1px 0px rgba(255, 255, 255, .05);
|
||||
text-align: center;
|
||||
}
|
||||
.no_content .icon {
|
||||
font-size: 80px;
|
||||
}
|
||||
.no_content p {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/**
|
||||
* @name contextmenu.css
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
.contextmenu_bg {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.contextmenu {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
padding: 5px 0px 6px 0px;
|
||||
background: linear-gradient(to bottom, #444 0%, #2f2f2f 100%);
|
||||
border: 1px solid rgba(0,0,0,0.5);
|
||||
border-bottom: 1px solid rgba(0,0,0,.7);
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 3px 4px rgba(0,0,0,0.25), inset 0px 1px 0px rgba(255,255,255, .1);
|
||||
opacity: 0;
|
||||
z-index: 1001;
|
||||
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/* Items ------------------------------------------------*/
|
||||
.contextmenu tr {
|
||||
font-size: 14px;
|
||||
color: #eee;
|
||||
text-shadow: 0px -1px 0px rgba(0,0,0,.2);
|
||||
cursor: pointer;
|
||||
}
|
||||
.contextmenu tr:hover {
|
||||
background: linear-gradient(to bottom, #6a84f2, #4967F0);
|
||||
}
|
||||
.contextmenu tr.no_hover:hover {
|
||||
cursor: inherit;
|
||||
background-color: inherit;
|
||||
background-image: none;
|
||||
}
|
||||
.contextmenu tr.separator {
|
||||
float: left;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background-color: #1f1f1f;
|
||||
border-bottom: 1px solid #4c4c4c;
|
||||
margin: 5px 0px;
|
||||
cursor: inherit;
|
||||
}
|
||||
.contextmenu tr.separator:hover {
|
||||
background-color: #222;
|
||||
background-image: none;
|
||||
}
|
||||
.contextmenu tr td {
|
||||
padding: 7px 30px 6px 12px;
|
||||
white-space: nowrap;
|
||||
transition: none;
|
||||
}
|
||||
.contextmenu tr:hover td {
|
||||
color: #fff;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,.05);
|
||||
text-shadow: 0px -1px 0px rgba(0,0,0,.2);
|
||||
}
|
||||
.contextmenu tr.no_hover:hover td {
|
||||
box-shadow: none;
|
||||
}
|
||||
.contextmenu tr a {
|
||||
float: left;
|
||||
width: 10px;
|
||||
margin-right: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Direct Link Input ------------------------------------------------*/
|
||||
.contextmenu #link {
|
||||
float: right;
|
||||
width: 140px;
|
||||
margin: -1px -18px -2px -1px;
|
||||
padding: 5px 7px 6px 7px;
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border: 1px solid rgba(0, 0, 0, .5);
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,.08);
|
||||
outline: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.contextmenu tr a#link_icon {
|
||||
padding-top: 4px;
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/**
|
||||
* @name imageview.css
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
#imageview {
|
||||
position: fixed;
|
||||
display: none;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background-color: rgba(10,10,10,.98);
|
||||
transition: background-color .3s;
|
||||
}
|
||||
|
||||
/* Modes ------------------------------------------------*/
|
||||
#imageview.view {
|
||||
background-color: inherit;
|
||||
}
|
||||
#imageview.full {
|
||||
background-color: rgba(0,0,0,1);
|
||||
}
|
||||
|
||||
/* ImageView ------------------------------------------------*/
|
||||
#imageview #image {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
left: 30px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
transition: top .3s, right .3s, bottom .3s, left .3s, margin-top .3s, opacity .2s, transform .3s cubic-bezier(0.51,.92,.24,1.15);
|
||||
animation-name: zoomIn;
|
||||
animation-duration: .3s;
|
||||
animation-timing-function: cubic-bezier(0.51,.92,.24,1.15);
|
||||
}
|
||||
#imageview #image.small {
|
||||
top: 50%;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: 50%;
|
||||
}
|
||||
#imageview #image.full {
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
/* Previous/Next Buttons ------------------------------------------------*/
|
||||
#imageview .arrow_wrapper {
|
||||
position: fixed;
|
||||
width: 20%;
|
||||
height: calc(100% - 60px);
|
||||
top: 60px;
|
||||
z-index: 1;
|
||||
}
|
||||
#imageview .arrow_wrapper.previous {
|
||||
left: 0;
|
||||
}
|
||||
#imageview .arrow_wrapper.next {
|
||||
right: 0;
|
||||
}
|
||||
#imageview .arrow_wrapper a {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
color: #fff;
|
||||
font-size: 50px;
|
||||
text-shadow: 0px 1px 2px #000;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
transition: opacity .2s;
|
||||
}
|
||||
#imageview .arrow_wrapper:hover a {
|
||||
opacity: .2;
|
||||
}
|
||||
#imageview .arrow_wrapper a#previous {
|
||||
left: 20px;
|
||||
}
|
||||
#imageview .arrow_wrapper a#next {
|
||||
right: 20px;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/**
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
@import "reset";
|
||||
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #222;
|
||||
font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
body.view {
|
||||
background-color: #0f0f0f;
|
||||
}
|
||||
.center {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top:50%;
|
||||
}
|
||||
* {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
transition: color .3s, opacity .3s ease-out, transform .3s ease-out, box-shadow .3s;
|
||||
}
|
||||
input {
|
||||
-webkit-user-select: text !important;
|
||||
-moz-user-select: text !important;
|
||||
user-select: text !important;
|
||||
}
|
||||
|
||||
@import "animations";
|
||||
@import "content";
|
||||
@import "contextmenu";
|
||||
@import "font";
|
||||
@import "header";
|
||||
@import "imageview";
|
||||
@import "infobox";
|
||||
@import "loading";
|
||||
@import "message";
|
||||
@import "misc";
|
||||
@import "multiselect";
|
||||
@import "tooltip";
|
||||
@import "upload";
|
||||
@import "mediaquery";
|
@ -1,210 +0,0 @@
|
||||
/**
|
||||
* @name message.css
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
.message_overlay {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-color: rgba(0,0,0,.85);
|
||||
z-index: 1000;
|
||||
}
|
||||
.message {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 500px;
|
||||
margin-left: -250px;
|
||||
margin-top: -95px;
|
||||
background-color: #444;
|
||||
background-image: linear-gradient(to bottom, rgb(75, 75, 75), rgb(45, 45, 45));
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 5px #000, inset 0px 1px 0px rgba(255,255,255,.08);
|
||||
|
||||
/* Animation */
|
||||
animation-name: moveUp;
|
||||
animation-duration: .3s;
|
||||
animation-timing-function: cubic-bezier(0.51,.92,.24,1.15);
|
||||
}
|
||||
|
||||
/* Header ------------------------------------------------*/
|
||||
.message h1 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 12px 0px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, .3);
|
||||
text-align: center;
|
||||
}
|
||||
.message .close {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
padding: 12px 14px 6px 7px;
|
||||
color: #aaa;
|
||||
font-size: 20px;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, .3);
|
||||
cursor: pointer;
|
||||
}
|
||||
.message .close:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Text ------------------------------------------------*/
|
||||
.message p {
|
||||
float: left;
|
||||
width: 90%;
|
||||
margin-top: 1px;
|
||||
padding: 12px 5% 15px 5%;
|
||||
color: #eee;
|
||||
font-size: 14px;
|
||||
text-shadow: 0px -1px 0px rgba(0, 0, 0, .3);
|
||||
line-height: 20px;
|
||||
}
|
||||
.message p b {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.message p a {
|
||||
color: #eee;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dashed #888;
|
||||
}
|
||||
|
||||
/* Button ------------------------------------------------*/
|
||||
.message .button {
|
||||
float: right;
|
||||
margin: 15px 15px 15px 0px;
|
||||
padding: 7px 10px 8px 10px;
|
||||
color: #ccc;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
text-shadow: 0px -1px 0px #222;
|
||||
border-radius: 5px;
|
||||
border: 1px solid rgba(0,0,0,.4);
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,.08), 0px 1px 0px rgba(255,255,255,.05);
|
||||
cursor: pointer;
|
||||
}
|
||||
.message .button:first-of-type {
|
||||
margin: 15px 5% 18px 0px !important;
|
||||
}
|
||||
.message .button.active {
|
||||
color: #fff;
|
||||
box-shadow: inset 0px 1px 0px rgba(255,255,255,.08), 0px 1px 0px rgba(255,255,255,.1), 0px 0px 4px #005ecc;
|
||||
}
|
||||
.message .button:hover {
|
||||
background-image: linear-gradient(to bottom, rgb(60, 60, 60), rgb(57, 57, 57));
|
||||
}
|
||||
.message .button:active,
|
||||
.message .button.pressed {
|
||||
background-color: #393939;
|
||||
background-image: linear-gradient(to bottom, rgb(57, 57, 57), rgb(60, 60, 60));
|
||||
}
|
||||
|
||||
/* Sign in ------------------------------------------------*/
|
||||
.sign_in {
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin-top: 1px;
|
||||
padding: 5px 0px;
|
||||
color: #eee;
|
||||
font-size: 14px;
|
||||
text-shadow: 0px -1px 0px #222;
|
||||
line-height: 20px;
|
||||
}
|
||||
.sign_in input {
|
||||
float: left;
|
||||
width: 88%;
|
||||
padding: 7px 1% 9px 1%;
|
||||
margin: 0px 5%;
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
text-shadow: 0px -1px 0px #222;
|
||||
border: none;
|
||||
border-bottom: 1px solid #222;
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,.1);
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
}
|
||||
.sign_in input:first-of-type {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.sign_in input.error:focus {
|
||||
box-shadow: 0px 1px 0px rgba(204, 0, 7, 0.6);
|
||||
}
|
||||
.message #version {
|
||||
display: inline-block;
|
||||
margin-top: 23px;
|
||||
margin-left: 5%;
|
||||
color: #888;
|
||||
text-shadow: 0px -1px 0px #111;
|
||||
}
|
||||
.message #version span {
|
||||
display: none;
|
||||
}
|
||||
.message #version span a {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Input Misc ------------------------------------------------*/
|
||||
.message input.text {
|
||||
float: left;
|
||||
width: calc(100% - 10px);
|
||||
padding: 17px 5px 9px 5px;
|
||||
margin-top: 10px;
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
text-shadow: 0px -1px 0px #222;
|
||||
border: none;
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,.1);
|
||||
border-bottom: 1px solid #222;
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
}
|
||||
.message input.less {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
.message input.more {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.message .copylink {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Radio Buttons ------------------------------------------------*/
|
||||
.message .choice {
|
||||
float: left;
|
||||
margin: 12px 5%;
|
||||
width: 90%;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.message .choice input {
|
||||
float: left;
|
||||
}
|
||||
.message .choice h2 {
|
||||
float: left;
|
||||
margin: 1px 0px 0px 8px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
|
||||
}
|
||||
.message .choice p {
|
||||
margin-top: 2px;
|
||||
padding: 0px 5% 0px 25px;
|
||||
color: #aaa;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.message .choice p input {
|
||||
width: 100%;
|
||||
padding: 10px 1px 9px;
|
||||
margin-top: 10px;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* @name tooltip.css
|
||||
*/
|
||||
|
||||
.tipsy {
|
||||
padding: 4px;
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
z-index: 100000;
|
||||
animation-name: fadeIn;
|
||||
animation-duration: .3s;
|
||||
}
|
||||
.tipsy-inner {
|
||||
padding: 8px 10px 7px;
|
||||
color: #fff;
|
||||
max-width: 200px;
|
||||
text-align: center;
|
||||
background: rgba(0, 0, 0, .8);
|
||||
border-radius: 25px;
|
||||
}
|
||||
.tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed rgba(0, 0, 0, .8); }
|
||||
.tipsy-arrow-n { border-bottom-color: rgba(0, 0, 0, .8); }
|
||||
.tipsy-arrow-s { border-top-color: rgba(0, 0, 0, .8); }
|
||||
.tipsy-arrow-e { border-left-color: rgba(0, 0, 0, .8); }
|
||||
.tipsy-arrow-w { border-right-color: rgba(0, 0, 0, .8); }
|
||||
.tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
|
||||
.tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
|
||||
.tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
|
||||
.tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
|
||||
.tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
|
||||
.tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
|
||||
.tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
|
||||
.tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
|
@ -1,70 +0,0 @@
|
||||
var gulp = require('gulp'),
|
||||
plugins = require("gulp-load-plugins")();
|
||||
|
||||
var paths = {
|
||||
view: [
|
||||
'bower_components/jQuery/dist/jquery.min.js',
|
||||
'bower_components/js-md5/js/md5.min.js',
|
||||
'bower_components/mousetrap/mousetrap.min.js',
|
||||
'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js',
|
||||
'../assets/js/_frameworks.js',
|
||||
'../assets/js/build.js',
|
||||
'../assets/js/view/main.js'
|
||||
],
|
||||
js: [
|
||||
'bower_components/jQuery/dist/jquery.min.js',
|
||||
'bower_components/js-md5/js/md5.min.js',
|
||||
'bower_components/mousetrap/mousetrap.min.js',
|
||||
'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js',
|
||||
'../assets/js/*.js'
|
||||
],
|
||||
css: [
|
||||
'../assets/scss/main.scss'
|
||||
]
|
||||
}
|
||||
|
||||
var catchError = function(err) {
|
||||
|
||||
console.log(err.toString());
|
||||
this.emit('end');
|
||||
|
||||
}
|
||||
|
||||
gulp.task('view', function() {
|
||||
|
||||
gulp.src(paths.view)
|
||||
.pipe(plugins.concat('view.js', {newLine: "\n"}))
|
||||
.pipe(plugins.uglify())
|
||||
.pipe(gulp.dest('../assets/min/'));
|
||||
|
||||
});
|
||||
|
||||
gulp.task('js', function() {
|
||||
|
||||
gulp.src(paths.js)
|
||||
.pipe(plugins.concat('main.js', {newLine: "\n"}))
|
||||
.pipe(plugins.uglify())
|
||||
.on('error', catchError)
|
||||
.pipe(gulp.dest('../assets/min/'));
|
||||
|
||||
});
|
||||
|
||||
gulp.task('css', function() {
|
||||
|
||||
gulp.src(paths.css)
|
||||
.pipe(plugins.sass())
|
||||
.on('error', catchError)
|
||||
.pipe(plugins.concat('main.css', {newLine: "\n"}))
|
||||
.pipe(plugins.autoprefixer('last 4 versions', '> 5%'))
|
||||
.pipe(plugins.minifyCss())
|
||||
.pipe(gulp.dest('../assets/min/'));
|
||||
|
||||
});
|
||||
|
||||
gulp.task('default', ['view', 'js', 'css']);
|
||||
|
||||
gulp.task('watch', ['default'], function() {
|
||||
gulp.watch(paths.view, ['view']);
|
||||
gulp.watch(paths.js, ['js']);
|
||||
gulp.watch(paths.css, ['css']);
|
||||
});
|
BIN
dist/main.css
vendored
Normal file
BIN
dist/main.js
vendored
Normal file
BIN
dist/view.js
vendored
Normal file
@ -15,12 +15,12 @@ After [installing Node.js](http://nodejs.org) you can use the included `npm` pac
|
||||
|
||||
### Build
|
||||
|
||||
The Gruntfile is located in `build/` and can be easily executed using the `gulp` command.
|
||||
|
||||
The Gruntfile is located in `src/` and can be easily executed using the `gulp` command.
|
||||
|
||||
### Watch for changes
|
||||
|
||||
While developing, you might want to use the following command to watch for changes in `assets/js/` and `assets/css/`:
|
||||
While developing, you might want to use the following command to watch for changes:
|
||||
|
||||
gulp watch
|
||||
|
||||
|
||||
`gulp` will automatically build Lychee everytime you save a file.
|
@ -1,3 +1,22 @@
|
||||
## v2.7
|
||||
|
||||
Released December 6, 2014
|
||||
|
||||
- `New` Intermediate sized images for small screen devices #67
|
||||
- `New` Added Docker help (@renfredxh, #252)
|
||||
- `New` Move-Photo context shows album previews
|
||||
- `Improved` Upload shows server-errors
|
||||
- `Improved` Improved thumb creation
|
||||
- `Improved` Docker (@renfredxh, #252)
|
||||
- `Improved` CSS has been rewritten partly
|
||||
- `Improved` Front-end has been rewritten partly #245
|
||||
- `Improved` Folder- and code-structure has been updated
|
||||
- `Improved` Context-menu now based on [basicContext](https://github.com/electerious/basicContext) #245
|
||||
- `Fixed` OpenGraph image too big for some sites #69
|
||||
- `Fixed` Wrong sizes after EXIF rotation
|
||||
- `Fixed` Returning to 'Albums' after searching failed
|
||||
- `Fixed` Move-Photo not scrollable #215
|
||||
|
||||
## v2.6.3
|
||||
|
||||
Released October 10, 2014
|
||||
|
41
docs/Docker.md
Normal file
@ -0,0 +1,41 @@
|
||||
### Installation using Docker
|
||||
|
||||
*Note: pre-installation of the latest version of [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker](https://docs.docker.com/installation/) is required to deploy Lychee using Docker.*
|
||||
|
||||
First, clone the latest version of Lychee and build it using the Dockerfile included in the repository.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/electerious/Lychee.git
|
||||
cd Lychee
|
||||
docker build -t lychee .
|
||||
```
|
||||
|
||||
Once this is finished, remember to set the proper permissions on the `uploads` and `data` directories, so the container can mount these directories as volumes.
|
||||
|
||||
```
|
||||
chmod -R 777 uploads/ data/
|
||||
```
|
||||
|
||||
Now you can use the `docker run` command to run your Lychee container.
|
||||
|
||||
```bash
|
||||
docker run -v /var/lib/mysql --name lychee_data \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/uploads:/app/uploads \
|
||||
-i -t -d -p 8000:80 lychee
|
||||
```
|
||||
|
||||
Browse to [localhost:8000](http://localhost:8000/) (the port can be specified via the `-p` flag) and you will see Lychee's configuration page. The default database username is `root` with no password (you can manage MySQL users by running `docker exec -i -t <container_id> mysql`). After submitting your database configuration, you can sign in and create a new username and password and start using Lychee.
|
||||
|
||||
*Note: if you are deploying on a server, you might want to forward your container to port `80` instead of `8000` so it'll be publicly accessible.*
|
||||
|
||||
### Managing Data
|
||||
|
||||
Running the container with the options above mounts three Docker [data volumes](https://docs.docker.com/userguide/dockervolumes/). The first is a named "data" volume used to store the MySQL database. The last two will mount the `/data` and `/uploads` from the container to your host `Lychee` directory. If you would like to upgrade or redeploy Lychee while preserving your data, you can kill the container and the volumes will persist. Just rebuild your new container and run it using a similar command:
|
||||
|
||||
```bash
|
||||
sudo docker run --volumes-from lychee_data \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/uploads:/app/uploads \
|
||||
-i -t -d -p 8000:80 lychee
|
||||
```
|
@ -18,6 +18,9 @@ If possible, change these settings directly in your `php.ini`. We recommend to i
|
||||
#### Which browsers are supported?
|
||||
Lychee supports the latest versions of Google Chrome, Apple Safari, Mozilla Firefox, Opera and Microsoft Internet Explorer. Make sure you are always running the newest version.
|
||||
|
||||
#### Which image file formats are supported?
|
||||
You can upload `*.png`, `*.jpeg` and `*.gif` photos.
|
||||
|
||||
#### What is new?
|
||||
Take a look at the [Changelog](Changelog.md) to see what's new.
|
||||
|
||||
|
@ -50,4 +50,10 @@ This key is required to use the Dropbox import feature from your server. Lychee
|
||||
|
||||
imagick = [0|1]
|
||||
|
||||
If `1`, Lychee will use Imagick when available. Disable [Imagick](http://www.imagemagick.org) if you have problems or if you are using an outdated version. Lychee will use [GD](http://php.net/manual/en/book.image.php) when Imagick is disabled or not available.
|
||||
If `1`, Lychee will use Imagick when available. Disable [Imagick](http://www.imagemagick.org) if you have problems or if you are using an outdated version. Lychee will use [GD](http://php.net/manual/en/book.image.php) when Imagick is disabled or not available.
|
||||
|
||||
#### Medium
|
||||
|
||||
medium = [0|1]
|
||||
|
||||
If `1`, Lychee will create a second, smaller version of your photo. This feature requires [Imagick](http://www.imagemagick.org) on your server and an activated `imagick` option the the settings table.
|
20
index.html
@ -10,11 +10,11 @@
|
||||
<meta name="description" content="">
|
||||
|
||||
<!-- CSS -->
|
||||
<link type="text/css" rel="stylesheet" href="assets/min/main.css">
|
||||
<link type="text/css" rel="stylesheet" href="dist/main.css">
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-iphone.png" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-ipad.png" sizes="152x152">
|
||||
<link rel="apple-touch-icon" href="src/images/apple-touch-icon-iphone.png" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="src/images/apple-touch-icon-ipad.png" sizes="152x152">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
@ -31,17 +31,17 @@
|
||||
|
||||
<!-- Buttons -->
|
||||
<div id="tools_albums">
|
||||
<a class="button left icon-cog" id="button_settings"></a>
|
||||
<a class="button left icon-signout" id="button_signin"></a>
|
||||
<a class="button left icon-cog" id="button_settings" title="Settings"></a>
|
||||
<a class="button left icon-signout" id="button_signin" title="Sign In"></a>
|
||||
<a id="hostedwith">Hosted with Lychee</a>
|
||||
<a class="button right icon icon-plus button_add"></a>
|
||||
<a class="button right icon icon-plus button_add" title="Add"></a>
|
||||
<a class="button_divider"></a>
|
||||
<input id="search" type="text" name="search" placeholder="Search …">
|
||||
<a id="clearSearch" class="button right">×</a>
|
||||
</div>
|
||||
<div id="tools_album">
|
||||
<a class="button left icon-arrow-left" id="button_back_home"></a>
|
||||
<a class="button right icon icon-plus button_add"></a>
|
||||
<a class="button left icon-arrow-left" id="button_back_home" title="Close Album"></a>
|
||||
<a class="button right icon icon-plus button_add" title="Add"></a>
|
||||
<a class="button_divider"></a>
|
||||
<div class="tools" id="button_trash_album" title="Delete Album"><a class="icon-trash"></a></div>
|
||||
<div class="tools" id="button_info_album" title="Show Info"><a class="icon-info-sign"></a></div>
|
||||
@ -49,7 +49,7 @@
|
||||
<div class="tools" id="button_share_album" title="Share Album"><a class="icon-share"></a></div>
|
||||
</div>
|
||||
<div id="tools_photo">
|
||||
<a class="button left icon-arrow-left" id="button_back"></a>
|
||||
<a class="button left icon-arrow-left" id="button_back" title="Close Photo"></a>
|
||||
<div class="tools" id="button_more" title="More"><a class="icon-caret-down"></a></div>
|
||||
<a class="button_divider"></a>
|
||||
<div class="tools" id="button_trash" title="Delete"><a class="icon-trash"></a></div>
|
||||
@ -79,7 +79,7 @@
|
||||
</div>
|
||||
|
||||
<!-- JS -->
|
||||
<script async type="text/javascript" src="assets/min/main.js"></script>
|
||||
<script async type="text/javascript" src="dist/main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Access
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Admin Access
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Guest Access (Public Mode)
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Installation Access
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name API
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Autoload
|
||||
# @author Tobias Reich
|
||||
# @name Autoload
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -24,5 +24,6 @@ CREATE TABLE IF NOT EXISTS `?` (
|
||||
`thumbUrl` varchar(50) NOT NULL,
|
||||
`album` varchar(30) NOT NULL DEFAULT '0',
|
||||
`checksum` VARCHAR(100) DEFAULT NULL,
|
||||
`medium` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.1
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.1.1
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.2
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.5
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.5.5
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.6.1
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Update to version 2.6.2
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
@ -35,7 +34,7 @@ if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('imagick', '1')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020100', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
Log::error($database, 'update_020602', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
41
php/database/update_020700.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Update to version 2.6.2
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
# Add medium to photos
|
||||
$query = Database::prepare($database, "SELECT `medium` FROM `?` LIMIT 1", array(LYCHEE_TABLE_PHOTOS));
|
||||
if (!$database->query($query)) {
|
||||
$query = Database::prepare($database, "ALTER TABLE `?` ADD `medium` TINYINT(1) NOT NULL DEFAULT 0", array(LYCHEE_TABLE_PHOTOS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Create medium folder
|
||||
if (is_dir(LYCHEE_UPLOADS_MEDIUM)===false) {
|
||||
# Only create the folder when it is missing
|
||||
if (@mkdir(LYCHEE_UPLOADS_MEDIUM)===false)
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not create medium-folder');
|
||||
}
|
||||
|
||||
# Add medium to settings
|
||||
$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'medium' LIMIT 1", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if ($result->num_rows===0) {
|
||||
$query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('medium', '1')", array(LYCHEE_TABLE_SETTINGS));
|
||||
$result = $database->query($query);
|
||||
if (!$result) {
|
||||
Log::error($database, 'update_020700', __LINE__, 'Could not update database (' . $database->error . ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
# Set version
|
||||
if (Database::setVersion($database, '020700')===false) return false;
|
||||
|
||||
?>
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Define
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
@ -11,7 +10,7 @@ define('LYCHEE', substr(__DIR__, 0, -3));
|
||||
|
||||
# Define dirs
|
||||
define('LYCHEE_DATA', LYCHEE . 'data/');
|
||||
define('LYCHEE_BUILD', LYCHEE . 'build/');
|
||||
define('LYCHEE_SRC', LYCHEE . 'src/');
|
||||
define('LYCHEE_UPLOADS', LYCHEE . 'uploads/');
|
||||
define('LYCHEE_UPLOADS_BIG', LYCHEE_UPLOADS . 'big/');
|
||||
define('LYCHEE_UPLOADS_MEDIUM', LYCHEE_UPLOADS . 'medium/');
|
||||
@ -23,8 +22,9 @@ define('LYCHEE_PLUGINS', LYCHEE . 'plugins/');
|
||||
define('LYCHEE_CONFIG_FILE', LYCHEE_DATA . 'config.php');
|
||||
|
||||
# Define urls
|
||||
define('LYCHEE_URL_UPLOADS_THUMB', 'uploads/thumb/');
|
||||
define('LYCHEE_URL_UPLOADS_BIG', 'uploads/big/');
|
||||
define('LYCHEE_URL_UPLOADS_MEDIUM', 'uploads/medium/');
|
||||
define('LYCHEE_URL_UPLOADS_THUMB', 'uploads/thumb/');
|
||||
|
||||
function defineTablePrefix($dbTablePrefix) {
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Album Module
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Database Module
|
||||
# @author Tobias Reich
|
||||
# @name Database Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
@ -22,7 +21,7 @@ class Database extends Module {
|
||||
|
||||
# Avoid sql injection on older MySQL versions by using GBK
|
||||
if ($database->server_version<50500) $database->set_charset('GBK');
|
||||
else $database->set_charset("utf8");
|
||||
else $database->set_charset('utf8');
|
||||
|
||||
# Set unicode
|
||||
$database->query('SET NAMES utf8;');
|
||||
@ -54,7 +53,8 @@ class Database extends Module {
|
||||
'020500', #2.5
|
||||
'020505', #2.5.5
|
||||
'020601', #2.6.1
|
||||
'020602' #2.6.2
|
||||
'020602', #2.6.2
|
||||
'020700' #2.7.0
|
||||
);
|
||||
|
||||
# For each update
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Upload Module
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Log Module
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
###
|
||||
# @name Module
|
||||
# @author Tobias Reich
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Photo Module
|
||||
# @author Tobias Reich
|
||||
# @name Photo Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
@ -44,9 +43,12 @@ class Photo extends Module {
|
||||
self::dependencies(isset($this->database));
|
||||
|
||||
# Check permissions
|
||||
if (hasPermissions(LYCHEE_UPLOADS_BIG)===false||hasPermissions(LYCHEE_UPLOADS_THUMB)===false) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Wrong permissions in uploads/');
|
||||
exit('Error: Wrong permissions in uploads-folder!');
|
||||
if (hasPermissions(LYCHEE_UPLOADS)===false||
|
||||
hasPermissions(LYCHEE_UPLOADS_BIG)===false||
|
||||
hasPermissions(LYCHEE_UPLOADS_THUMB)===false||
|
||||
hasPermissions(LYCHEE_UPLOADS_MEDIUM)===false) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'An upload-folder is missing or not readable and writable');
|
||||
exit('Error: An upload-folder is missing or not readable and writable!');
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
@ -122,6 +124,7 @@ class Photo extends Module {
|
||||
$photo_name = $exists['photo_name'];
|
||||
$path = $exists['path'];
|
||||
$path_thumb = $exists['path_thumb'];
|
||||
$medium = ($exists['medium']==='1' ? true : false);
|
||||
$exists = true;
|
||||
}
|
||||
|
||||
@ -156,27 +159,33 @@ class Photo extends Module {
|
||||
if ($exists===false) {
|
||||
|
||||
# Set orientation based on EXIF data
|
||||
if ($file['type']==='image/jpeg'&&isset($info['orientation'], $info['width'], $info['height'])&&$info['orientation']!=='') {
|
||||
if (!$this->adjustFile($path, $info)) Log::notice($this->database, __METHOD__, __LINE__, 'Could not adjust photo (' . $info['title'] . ')');
|
||||
if ($file['type']==='image/jpeg'&&isset($info['orientation'])&&$info['orientation']!=='') {
|
||||
$adjustFile = $this->adjustFile($path, $info);
|
||||
if ($adjustFile!==false) $info = $adjustFile;
|
||||
else Log::notice($this->database, __METHOD__, __LINE__, 'Skipped adjustment of photo (' . $info['title'] . ')');
|
||||
}
|
||||
|
||||
# Set original date
|
||||
if ($info['takestamp']!==''&&$info['takestamp']!==0) @touch($path, $info['takestamp']);
|
||||
|
||||
# Create Thumb
|
||||
if (!$this->createThumb($path, $photo_name)) {
|
||||
if (!$this->createThumb($path, $photo_name, $info['type'], $info['width'], $info['height'])) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not create thumbnail for photo');
|
||||
exit('Error: Could not create thumbnail for photo!');
|
||||
}
|
||||
|
||||
# Create Medium
|
||||
if ($this->createMedium($path, $photo_name, $info['width'], $info['height'])) $medium = true;
|
||||
else $medium = false;
|
||||
|
||||
# Set thumb url
|
||||
$path_thumb = md5($id) . '.jpeg';
|
||||
|
||||
}
|
||||
|
||||
# Save to DB
|
||||
$values = array(LYCHEE_TABLE_PHOTOS, $id, $info['title'], $photo_name, $description, $tags, $info['type'], $info['width'], $info['height'], $info['size'], $info['iso'], $info['aperture'], $info['make'], $info['model'], $info['shutter'], $info['focal'], $info['takestamp'], $path_thumb, $albumID, $public, $star, $checksum);
|
||||
$query = Database::prepare($this->database, "INSERT INTO ? (id, title, url, description, tags, type, width, height, size, iso, aperture, make, model, shutter, focal, takestamp, thumbUrl, album, public, star, checksum) VALUES ('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?')", $values);
|
||||
$values = array(LYCHEE_TABLE_PHOTOS, $id, $info['title'], $photo_name, $description, $tags, $info['type'], $info['width'], $info['height'], $info['size'], $info['iso'], $info['aperture'], $info['make'], $info['model'], $info['shutter'], $info['focal'], $info['takestamp'], $path_thumb, $albumID, $public, $star, $checksum, $medium);
|
||||
$query = Database::prepare($this->database, "INSERT INTO ? (id, title, url, description, tags, type, width, height, size, iso, aperture, make, model, shutter, focal, takestamp, thumbUrl, album, public, star, checksum, medium) VALUES ('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?')", $values);
|
||||
$result = $this->database->query($query);
|
||||
|
||||
if (!$result) {
|
||||
@ -199,8 +208,8 @@ class Photo extends Module {
|
||||
self::dependencies(isset($this->database, $checksum));
|
||||
|
||||
# Exclude $photoID from select when $photoID is set
|
||||
if (isset($photoID)) $query = Database::prepare($this->database, "SELECT id, url, thumbUrl FROM ? WHERE checksum = '?' AND id <> '?' LIMIT 1", array(LYCHEE_TABLE_PHOTOS, $checksum, $photoID));
|
||||
else $query = Database::prepare($this->database, "SELECT id, url, thumbUrl FROM ? WHERE checksum = '?' LIMIT 1", array(LYCHEE_TABLE_PHOTOS, $checksum));
|
||||
if (isset($photoID)) $query = Database::prepare($this->database, "SELECT id, url, thumbUrl, medium FROM ? WHERE checksum = '?' AND id <> '?' LIMIT 1", array(LYCHEE_TABLE_PHOTOS, $checksum, $photoID));
|
||||
else $query = Database::prepare($this->database, "SELECT id, url, thumbUrl, medium FROM ? WHERE checksum = '?' LIMIT 1", array(LYCHEE_TABLE_PHOTOS, $checksum));
|
||||
|
||||
$result = $this->database->query($query);
|
||||
|
||||
@ -216,7 +225,8 @@ class Photo extends Module {
|
||||
$return = array(
|
||||
'photo_name' => $result->url,
|
||||
'path' => LYCHEE_UPLOADS_BIG . $result->url,
|
||||
'path_thumb' => $result->thumbUrl
|
||||
'path_thumb' => $result->thumbUrl,
|
||||
'medium' => $result->medium
|
||||
);
|
||||
|
||||
return $return;
|
||||
@ -227,20 +237,23 @@ class Photo extends Module {
|
||||
|
||||
}
|
||||
|
||||
private function createThumb($url, $filename, $width = 200, $height = 200) {
|
||||
private function createThumb($url, $filename, $type, $width, $height) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->settings, $url, $filename));
|
||||
self::dependencies(isset($this->database, $this->settings, $url, $filename, $type, $width, $height));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
$info = getimagesize($url);
|
||||
$photoName = explode(".", $filename);
|
||||
# Size of the thumbnail
|
||||
$newWidth = 200;
|
||||
$newHeight = 200;
|
||||
|
||||
$photoName = explode('.', $filename);
|
||||
$newUrl = LYCHEE_UPLOADS_THUMB . $photoName[0] . '.jpeg';
|
||||
$newUrl2x = LYCHEE_UPLOADS_THUMB . $photoName[0] . '@2x.jpeg';
|
||||
|
||||
# create thumbnails with Imagick
|
||||
# Create thumbnails with Imagick
|
||||
if(extension_loaded('imagick')&&$this->settings['imagick']==='1') {
|
||||
|
||||
# Read image
|
||||
@ -253,34 +266,36 @@ class Photo extends Module {
|
||||
$thumb2x = clone $thumb;
|
||||
|
||||
# Create 1st version
|
||||
$thumb->cropThumbnailImage($width, $height);
|
||||
$thumb->cropThumbnailImage($newWidth, $newHeight);
|
||||
$thumb->writeImage($newUrl);
|
||||
$thumb->clear();
|
||||
$thumb->destroy();
|
||||
|
||||
# Create 2nd version
|
||||
$thumb2x->cropThumbnailImage($width*2, $height*2);
|
||||
$thumb2x->cropThumbnailImage($newWidth*2, $newHeight*2);
|
||||
$thumb2x->writeImage($newUrl2x);
|
||||
$thumb2x->clear();
|
||||
$thumb2x->destroy();
|
||||
|
||||
} else {
|
||||
|
||||
# Set position and size
|
||||
$thumb = imagecreatetruecolor($width, $height);
|
||||
$thumb2x = imagecreatetruecolor($width*2, $height*2);
|
||||
if ($info[0]<$info[1]) {
|
||||
$newSize = $info[0];
|
||||
# Create image
|
||||
$thumb = imagecreatetruecolor($newWidth, $newHeight);
|
||||
$thumb2x = imagecreatetruecolor($newWidth*2, $newHeight*2);
|
||||
|
||||
# Set position
|
||||
if ($width<$height) {
|
||||
$newSize = $width;
|
||||
$startWidth = 0;
|
||||
$startHeight = $info[1]/2 - $info[0]/2;
|
||||
$startHeight = $height/2 - $width/2;
|
||||
} else {
|
||||
$newSize = $info[1];
|
||||
$startWidth = $info[0]/2 - $info[1]/2;
|
||||
$newSize = $height;
|
||||
$startWidth = $width/2 - $height/2;
|
||||
$startHeight = 0;
|
||||
}
|
||||
|
||||
# Create new image
|
||||
switch($info['mime']) {
|
||||
switch($type) {
|
||||
case 'image/jpeg': $sourceImg = imagecreatefromjpeg($url); break;
|
||||
case 'image/png': $sourceImg = imagecreatefrompng($url); break;
|
||||
case 'image/gif': $sourceImg = imagecreatefromgif($url); break;
|
||||
@ -290,12 +305,12 @@ class Photo extends Module {
|
||||
}
|
||||
|
||||
# Create thumb
|
||||
fastimagecopyresampled($thumb, $sourceImg, 0, 0, $startWidth, $startHeight, $width, $height, $newSize, $newSize);
|
||||
fastimagecopyresampled($thumb, $sourceImg, 0, 0, $startWidth, $startHeight, $newWidth, $newHeight, $newSize, $newSize);
|
||||
imagejpeg($thumb, $newUrl, $this->settings['thumbQuality']);
|
||||
imagedestroy($thumb);
|
||||
|
||||
# Create retina thumb
|
||||
fastimagecopyresampled($thumb2x, $sourceImg, 0, 0, $startWidth, $startHeight, $width*2, $height*2, $newSize, $newSize);
|
||||
fastimagecopyresampled($thumb2x, $sourceImg, 0, 0, $startWidth, $startHeight, $newWidth*2, $newHeight*2, $newSize, $newSize);
|
||||
imagejpeg($thumb2x, $newUrl2x, $this->settings['thumbQuality']);
|
||||
imagedestroy($thumb2x);
|
||||
|
||||
@ -311,6 +326,57 @@ class Photo extends Module {
|
||||
|
||||
}
|
||||
|
||||
private function createMedium($url, $filename, $width, $height) {
|
||||
|
||||
# Check dependencies
|
||||
self::dependencies(isset($this->database, $this->settings, $url, $filename, $width, $height));
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
# Size of the medium-photo
|
||||
# When changing these values,
|
||||
# also change the size detection in the front-end
|
||||
$newWidth = 1920;
|
||||
$newHeight = 1080;
|
||||
|
||||
# Is photo big enough?
|
||||
# Is medium activated?
|
||||
# Is Imagick installed and activated?
|
||||
if (($width>$newWidth||$height>$newHeight)&&
|
||||
($this->settings['medium']==='1')&&
|
||||
(extension_loaded('imagick')&&$this->settings['imagick']==='1')) {
|
||||
|
||||
# $info = getimagesize($url);
|
||||
$newUrl = LYCHEE_UPLOADS_MEDIUM . $filename;
|
||||
|
||||
# Read image
|
||||
$medium = new Imagick();
|
||||
$medium->readImage($url);
|
||||
$medium->scaleImage($newWidth, $newHeight, true);
|
||||
$medium->writeImage($newUrl);
|
||||
$medium->clear();
|
||||
$medium->destroy();
|
||||
|
||||
$error = false;
|
||||
|
||||
} else {
|
||||
|
||||
# Photo too small or
|
||||
# Medium is deactivated or
|
||||
# Imagick not installed
|
||||
$error = true;
|
||||
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
if ($error===true) return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function adjustFile($path, $info) {
|
||||
|
||||
# Check dependencies
|
||||
@ -319,6 +385,8 @@ class Photo extends Module {
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 0, func_get_args());
|
||||
|
||||
$swapSize = false;
|
||||
|
||||
if (extension_loaded('imagick')&&$this->settings['imagick']==='1') {
|
||||
|
||||
$rotateImage = 0;
|
||||
@ -327,17 +395,20 @@ class Photo extends Module {
|
||||
|
||||
case 3:
|
||||
$rotateImage = 180;
|
||||
$imageOrientation = 1;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$rotateImage = 90;
|
||||
$imageOrientation = 1;
|
||||
$rotateImage = 90;
|
||||
$swapSize = true;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
$rotateImage = 270;
|
||||
$imageOrientation = 1;
|
||||
$rotateImage = 270;
|
||||
$swapSize = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
@ -346,7 +417,7 @@ class Photo extends Module {
|
||||
$image = new Imagick();
|
||||
$image->readImage($path);
|
||||
$image->rotateImage(new ImagickPixel(), $rotateImage);
|
||||
$image->setImageOrientation($imageOrientation);
|
||||
$image->setImageOrientation(1);
|
||||
$image->writeImage($path);
|
||||
$image->clear();
|
||||
$image->destroy();
|
||||
@ -356,7 +427,6 @@ class Photo extends Module {
|
||||
|
||||
$newWidth = $info['width'];
|
||||
$newHeight = $info['height'];
|
||||
$process = false;
|
||||
$sourceImg = imagecreatefromjpeg($path);
|
||||
|
||||
switch ($info['orientation']) {
|
||||
@ -364,6 +434,7 @@ class Photo extends Module {
|
||||
case 2:
|
||||
# mirror
|
||||
# not yet implemented
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
@ -374,11 +445,13 @@ class Photo extends Module {
|
||||
case 4:
|
||||
# rotate 180 and mirror
|
||||
# not yet implemented
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
# rotate 90 and mirror
|
||||
# not yet implemented
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
@ -386,11 +459,13 @@ class Photo extends Module {
|
||||
$sourceImg = imagerotate($sourceImg, -90, 0);
|
||||
$newWidth = $info['height'];
|
||||
$newHeight = $info['width'];
|
||||
$swapSize = true;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
# rotate -90 and mirror
|
||||
# not yet implemented
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
@ -398,30 +473,38 @@ class Photo extends Module {
|
||||
$sourceImg = imagerotate($sourceImg, 90, 0);
|
||||
$newWidth = $info['height'];
|
||||
$newHeight = $info['width'];
|
||||
$swapSize = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
# Need to adjust photo?
|
||||
if ($process===true) {
|
||||
# Recreate photo
|
||||
$newSourceImg = imagecreatetruecolor($newWidth, $newHeight);
|
||||
imagecopyresampled($newSourceImg, $sourceImg, 0, 0, 0, 0, $newWidth, $newHeight, $newWidth, $newHeight);
|
||||
imagejpeg($newSourceImg, $path, 100);
|
||||
|
||||
# Recreate photo
|
||||
$newSourceImg = imagecreatetruecolor($newWidth, $newHeight);
|
||||
imagecopyresampled($newSourceImg, $sourceImg, 0, 0, 0, 0, $newWidth, $newHeight, $newWidth, $newHeight);
|
||||
imagejpeg($newSourceImg, $path, 100);
|
||||
|
||||
# Free memory
|
||||
imagedestroy($sourceImg);
|
||||
imagedestroy($newSourceImg);
|
||||
|
||||
}
|
||||
# Free memory
|
||||
imagedestroy($sourceImg);
|
||||
imagedestroy($newSourceImg);
|
||||
|
||||
}
|
||||
|
||||
# Call plugins
|
||||
$this->plugins(__METHOD__, 1, func_get_args());
|
||||
|
||||
return true;
|
||||
# SwapSize should be true when the image has been rotated
|
||||
# Return new dimensions in this case
|
||||
if ($swapSize===true) {
|
||||
$swapSize = $info['width'];
|
||||
$info['width'] = $info['height'];
|
||||
$info['height'] = $swapSize;
|
||||
}
|
||||
|
||||
return $info;
|
||||
|
||||
}
|
||||
|
||||
@ -442,7 +525,11 @@ class Photo extends Module {
|
||||
$photo['sysdate'] = date('d M. Y', substr($photo['id'], 0, -4));
|
||||
if (strlen($photo['takestamp'])>1) $photo['takedate'] = date('d M. Y', $photo['takestamp']);
|
||||
|
||||
# Parse url
|
||||
# Parse medium
|
||||
if ($photo['medium']==='1') $photo['medium'] = LYCHEE_URL_UPLOADS_MEDIUM . $photo['url'];
|
||||
else $photo['medium'] = '';
|
||||
|
||||
# Parse paths
|
||||
$photo['url'] = LYCHEE_URL_UPLOADS_BIG . $photo['url'];
|
||||
$photo['thumbUrl'] = LYCHEE_URL_UPLOADS_THUMB . $photo['thumbUrl'];
|
||||
|
||||
@ -892,6 +979,12 @@ class Photo extends Module {
|
||||
return false;
|
||||
}
|
||||
|
||||
# Delete medium
|
||||
if (file_exists(LYCHEE_UPLOADS_MEDIUM . $photo->url)&&!unlink(LYCHEE_UPLOADS_MEDIUM . $photo->url)) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not delete photo in uploads/medium/');
|
||||
return false;
|
||||
}
|
||||
|
||||
# Delete thumb
|
||||
if (file_exists(LYCHEE_UPLOADS_THUMB . $photo->thumbUrl)&&!unlink(LYCHEE_UPLOADS_THUMB . $photo->thumbUrl)) {
|
||||
Log::error($this->database, __METHOD__, __LINE__, 'Could not delete photo in uploads/thumb/');
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Plugins Module
|
||||
# @author Tobias Reich
|
||||
# @name Plugins Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Session Module
|
||||
# @author Tobias Reich
|
||||
# @name Session Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
###
|
||||
# @name Settings Module
|
||||
# @author Tobias Reich
|
||||
# @name Settings Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @name Misc Module
|
||||
* @author Philipp Maurer
|
||||
* @author Tobias Reich
|
||||
* @copyright 2014 by Philipp Maurer, Tobias Reich
|
||||
*/
|
||||
###
|
||||
# @name Misc Module
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
|
||||
|
||||
@ -15,7 +13,7 @@ function search($database, $settings, $term) {
|
||||
|
||||
$return['albums'] = '';
|
||||
|
||||
// Photos
|
||||
# Photos
|
||||
$query = Database::prepare($database, "SELECT id, title, tags, public, star, album, thumbUrl FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%' OR tags LIKE '%?%'", array(LYCHEE_TABLE_PHOTOS, $term, $term, $term));
|
||||
$result = $database->query($query);
|
||||
while($row = $result->fetch_assoc()) {
|
||||
@ -24,20 +22,20 @@ function search($database, $settings, $term) {
|
||||
$return['photos'][$row['id']]['sysdate'] = date('d M. Y', substr($row['id'], 0, -4));
|
||||
}
|
||||
|
||||
// Albums
|
||||
# Albums
|
||||
$query = Database::prepare($database, "SELECT id, title, public, sysstamp, password FROM ? WHERE title LIKE '%?%' OR description LIKE '%?%'", array(LYCHEE_TABLE_ALBUMS, $term, $term));
|
||||
$result = $database->query($query);
|
||||
$i = 0;
|
||||
while($row = $result->fetch_object()) {
|
||||
|
||||
// Info
|
||||
# Info
|
||||
$return['albums'][$row->id]['id'] = $row->id;
|
||||
$return['albums'][$row->id]['title'] = $row->title;
|
||||
$return['albums'][$row->id]['public'] = $row->public;
|
||||
$return['albums'][$row->id]['sysdate'] = date('F Y', $row->sysstamp);
|
||||
$return['albums'][$row->id]['password'] = ($row->password=='' ? false : true);
|
||||
|
||||
// Thumbs
|
||||
# Thumbs
|
||||
$query = Database::prepare($database, "SELECT thumbUrl FROM ? WHERE album = '?' " . $settings['sorting'] . " LIMIT 0, 3", array(LYCHEE_TABLE_PHOTOS, $row->id));
|
||||
$result2 = $database->query($query);
|
||||
$k = 0;
|
||||
@ -58,12 +56,15 @@ function getGraphHeader($database, $photoID) {
|
||||
|
||||
if (!isset($database, $photoID)) return false;
|
||||
|
||||
$query = Database::prepare($database, "SELECT title, description, url FROM ? WHERE id = '?'", array(LYCHEE_TABLE_PHOTOS, $photoID));
|
||||
$query = Database::prepare($database, "SELECT title, description, url, medium FROM ? WHERE id = '?'", array(LYCHEE_TABLE_PHOTOS, $photoID));
|
||||
$result = $database->query($query);
|
||||
$row = $result->fetch_object();
|
||||
|
||||
$parseUrl = parse_url("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
|
||||
$picture = $parseUrl['scheme']."://".$parseUrl['host'].$parseUrl['path']."/../uploads/big/".$row->url;
|
||||
if ($row->medium==='1') $dir = 'medium';
|
||||
else $dir = 'big';
|
||||
|
||||
$parseUrl = parse_url('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
||||
$picture = $parseUrl['scheme'] . '://' . $parseUrl['host'] . $parseUrl['path'] . '/../uploads/' . $dir . '/' . $row->url;
|
||||
|
||||
$return = '<!-- General Meta Data -->';
|
||||
$return .= '<meta name="title" content="'.$row->title.'" />';
|
||||
@ -121,13 +122,14 @@ function get_hashed_password($password) {
|
||||
|
||||
}
|
||||
|
||||
function hasPermissions($path, $permissions = '0777') {
|
||||
function hasPermissions($path) {
|
||||
|
||||
/* assume that if running with the same uid as the owner of the directory it's ok */
|
||||
$stat = @stat($path);
|
||||
if ($stat && ($stat['uid'] == getmyuid())) return true;
|
||||
if (substr(sprintf('%o', @fileperms($path)), -4)!=$permissions) return false;
|
||||
else return true;
|
||||
// Check if the given path is readable and writable
|
||||
// Both functions are also verifying that the path exists
|
||||
if (is_readable($path)===true&&
|
||||
is_writeable($path)===true) return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
@ -68,11 +68,12 @@ if (!isset($settings['imagick'])||$settings['imagick']=='') $error .= ('Error
|
||||
if (!isset($settings['checkForUpdates'])||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error 410: No or wrong property for checkForUpdates in database' . PHP_EOL);
|
||||
|
||||
# Permissions
|
||||
if (hasPermissions(LYCHEE_UPLOADS_BIG)===false) $error .= ('Error 500: Wrong permissions for \'uploads/big\' (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_THUMB)===false) $error .= ('Error 501: Wrong permissions for \'uploads/thumb\' (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_IMPORT)===false) $error .= ('Error 502: Wrong permissions for \'uploads/import\' (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS)===false) $error .= ('Error 503: Wrong permissions for \'uploads/\' (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_DATA)===false) $error .= ('Error 504: Wrong permissions for \'data/\' (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_BIG)===false) $error .= ('Error 500: \'uploads/big\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_MEDIUM)===false) $error .= ('Error 500: \'uploads/medium\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_THUMB)===false) $error .= ('Error 501: \'uploads/thumb\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS_IMPORT)===false) $error .= ('Error 502: \'uploads/import\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_UPLOADS)===false) $error .= ('Error 503: \'uploads/\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
if (hasPermissions(LYCHEE_DATA)===false) $error .= ('Error 504: \'data/\' missing or not readable and writable (777 required)' . PHP_EOL);
|
||||
|
||||
# Check dropboxKey
|
||||
if (!$settings['dropboxKey']) echo('Warning: Dropbox import not working. No property for dropboxKey.' . PHP_EOL);
|
||||
@ -92,7 +93,7 @@ echo(PHP_EOL . PHP_EOL . 'System Information' . PHP_EOL);
|
||||
echo('------------------' . PHP_EOL);
|
||||
|
||||
# Load json
|
||||
$json = file_get_contents(LYCHEE_BUILD . 'package.json');
|
||||
$json = file_get_contents(LYCHEE_SRC . 'package.json');
|
||||
$json = json_decode($json, true);
|
||||
|
||||
$imagick = extension_loaded('imagick');
|
||||
|
8
robots.txt
Normal file
@ -0,0 +1,8 @@
|
||||
User-agent: *
|
||||
Disallow: /data/
|
||||
Disallow: /dist/
|
||||
Disallow: /docs/
|
||||
Disallow: /php/
|
||||
Disallow: /plugins/
|
||||
Disallow: /src/
|
||||
Disallow: /uploads/
|
@ -1,8 +1,10 @@
|
||||
{
|
||||
"name": "Lychee",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"jQuery": "~2.1.1",
|
||||
"js-md5": "~1.1.0",
|
||||
"mousetrap": "~1.4.6"
|
||||
"mousetrap": "~1.4.6",
|
||||
"basicContext": "~2.0.2"
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
177
src/gulpfile.js
Normal file
@ -0,0 +1,177 @@
|
||||
var gulp = require('gulp'),
|
||||
plugins = require("gulp-load-plugins")(),
|
||||
paths = {}
|
||||
|
||||
/* Error Handler -------------------------------- */
|
||||
|
||||
var catchError = function(err) {
|
||||
|
||||
console.log(err.toString());
|
||||
this.emit('end');
|
||||
|
||||
}
|
||||
|
||||
/* View ----------------------------------------- */
|
||||
|
||||
paths.view = {
|
||||
js: [
|
||||
'bower_components/jQuery/dist/jquery.min.js',
|
||||
'../src/scripts/_frameworks.js',
|
||||
'../src/scripts/view/main.js'
|
||||
],
|
||||
coffee: [
|
||||
'../src/scripts/build.coffee'
|
||||
],
|
||||
scripts: [
|
||||
'../dist/_view--javascript.js',
|
||||
'../dist/_view--coffee.js'
|
||||
]
|
||||
}
|
||||
|
||||
gulp.task('view--js', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.view.js)
|
||||
.pipe(plugins.concat('_view--javascript.js', {newLine: "\n"}))
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
gulp.task('view--coffee', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.view.coffee)
|
||||
.pipe(plugins.coffee({bare: true}))
|
||||
.on('error', catchError)
|
||||
.pipe(plugins.concat('_view--coffee.js', {newLine: "\n"}))
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
gulp.task('view--scripts', ['view--js', 'view--coffee'], function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.view.scripts)
|
||||
.pipe(plugins.concat('view.js', {newLine: "\n"}))
|
||||
.pipe(plugins.uglify())
|
||||
.on('error', catchError)
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
/* Main ----------------------------------------- */
|
||||
|
||||
paths.main = {
|
||||
js: [
|
||||
'bower_components/jQuery/dist/jquery.min.js',
|
||||
'bower_components/js-md5/js/md5.min.js',
|
||||
'bower_components/mousetrap/mousetrap.min.js',
|
||||
'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js',
|
||||
'bower_components/basicContext/dist/basicContext.min.js',
|
||||
'../src/scripts/*.js'
|
||||
],
|
||||
coffee: [
|
||||
'../src/scripts/*.coffee'
|
||||
],
|
||||
scripts: [
|
||||
'../dist/_main--javascript.js',
|
||||
'../dist/_main--coffee.js'
|
||||
],
|
||||
scss: [
|
||||
'../src/styles/*.scss'
|
||||
],
|
||||
styles: [
|
||||
'bower_components/basicContext/src/styles/main.scss',
|
||||
'../src/styles/main.scss'
|
||||
]
|
||||
}
|
||||
|
||||
gulp.task('main--js', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.main.js)
|
||||
.pipe(plugins.concat('_main--javascript.js', {newLine: "\n"}))
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
gulp.task('main--coffee', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.main.coffee)
|
||||
.pipe(plugins.coffee({bare: true}))
|
||||
.on('error', catchError)
|
||||
.pipe(plugins.concat('_main--coffee.js', {newLine: "\n"}))
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
gulp.task('main--scripts', ['main--js', 'main--coffee'], function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.main.scripts)
|
||||
.pipe(plugins.concat('main.js', {newLine: "\n"}))
|
||||
.pipe(plugins.uglify())
|
||||
.on('error', catchError)
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
gulp.task('main--styles', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src(paths.main.styles)
|
||||
.pipe(plugins.sass())
|
||||
.on('error', catchError)
|
||||
.pipe(plugins.concat('main.css', {newLine: "\n"}))
|
||||
.pipe(plugins.autoprefixer('last 4 versions', '> 5%'))
|
||||
.pipe(plugins.minifyCss())
|
||||
.pipe(gulp.dest('../dist/'));
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
/* Clean ----------------------------------------- */
|
||||
|
||||
gulp.task('clean', function() {
|
||||
|
||||
var stream =
|
||||
gulp.src('../dist/_*.*', { read: false })
|
||||
.pipe(plugins.rimraf({ force: true }))
|
||||
.on('error', catchError);
|
||||
|
||||
return stream;
|
||||
|
||||
});
|
||||
|
||||
/* Tasks ----------------------------------------- */
|
||||
|
||||
gulp.task('default', ['view--scripts', 'main--scripts', 'main--styles'], function() {
|
||||
|
||||
gulp.start('clean');
|
||||
|
||||
});
|
||||
|
||||
gulp.task('watch', ['default'], function() {
|
||||
|
||||
gulp.watch(paths.view.js, ['view--scripts']);
|
||||
gulp.watch(paths.view.coffee, ['view--scripts']);
|
||||
|
||||
gulp.watch(paths.main.js, ['main--scripts']);
|
||||
gulp.watch(paths.main.coffee, ['main--scripts']);
|
||||
gulp.watch(paths.main.scss, ['main--styles']);
|
||||
|
||||
});
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
1
src/images/no_cover.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g><path d="M0 0h16v16H0V0z" fill="#444"/><rect stroke="#aaa" x="4" y="4" width="5" height="5" rx="1"/><path fill="#444" d="M6 6h8v7H6z"/><rect stroke="#aaa" x="7" y="7" width="5" height="5" rx="1"/></g></g></svg>
|
After Width: | Height: | Size: 331 B |
1
src/images/no_images.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path fill="#222" d="M0 0h200v200H0z"/><g transform="translate(68 52)"><rect stroke="#B4B4B4" stroke-width="4" width="50" height="42" rx="3"/><path fill="#222" d="M11 11h44v36H11z"/><rect stroke="#B4B4B4" stroke-width="4" x="20" y="20" width="50" height="42" rx="3"/></g></g></svg>
|
After Width: | Height: | Size: 361 B |
1
src/images/password.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path fill="#222" d="M0 0h200v200H0z"/><path d="M118 73h3c4.412 0 8 3.58 8 7.994v28.013c0 4.412-3.582 7.994-8 7.994H80c-4.413 0-8-3.578-8-7.993V80.994C72 76.582 75.58 73 80 73h3v-9.495C83 53.84 90.833 46 100.5 46S118 53.837 118 63.505V73zm-17.5-20C94.7 53 90 57.702 90 63.498V73h21v-9.502C111 57.7 106.3 53 100.5 53zm0 0" fill="#B4B4B4"/></g></svg>
|
After Width: | Height: | Size: 428 B |
@ -1,20 +1,23 @@
|
||||
{
|
||||
"name": "Lychee",
|
||||
"version": "2.6.3",
|
||||
"version": "2.7.0",
|
||||
"description": "Self-hosted photo-management done right.",
|
||||
"authors": "Tobias Reich <tobias.reich.ich@gmail.com>",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/electerious/Lychee.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.8.8",
|
||||
"gulp-autoprefixer": "1.0.1",
|
||||
"gulp-concat": "^2.4.1",
|
||||
"gulp-load-plugins": "^0.7.0",
|
||||
"gulp-minify-css": "^0.3.10",
|
||||
"gulp-sass": "^1.0.0",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-autoprefixer": "2.0.0",
|
||||
"gulp-coffee": "^2.2.0",
|
||||
"gulp-concat": "^2.4.2",
|
||||
"gulp-load-plugins": "^0.7.1",
|
||||
"gulp-minify-css": "^0.3.11",
|
||||
"gulp-rimraf": "^0.1.1",
|
||||
"gulp-sass": "^1.2.4",
|
||||
"gulp-uglify": "^1.0.1"
|
||||
}
|
||||
}
|
8
src/scripts/_frameworks.js
Executable file
@ -0,0 +1,8 @@
|
||||
/* 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);
|
407
src/scripts/album.js
Normal file
@ -0,0 +1,407 @@
|
||||
/**
|
||||
* @description Takes care of every action an album can handle and execute.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
album = {
|
||||
|
||||
json: null
|
||||
|
||||
}
|
||||
|
||||
album.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;
|
||||
|
||||
}
|
||||
|
||||
album.load = function(albumID, refresh) {
|
||||
|
||||
var startTime,
|
||||
params,
|
||||
durationTime,
|
||||
waitTime;
|
||||
|
||||
password.get(albumID, function() {
|
||||
|
||||
if (!refresh) {
|
||||
lychee.animate('.album, .photo', '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;
|
||||
|
||||
// Calculate delay
|
||||
durationTime = (new Date().getTime() - startTime);
|
||||
if (durationTime>300) waitTime = 0;
|
||||
else waitTime = 300 - durationTime;
|
||||
|
||||
// Skip delay when refresh is true
|
||||
// Skip delay when opening a blank Lychee
|
||||
if (refresh===true) waitTime = 0;
|
||||
if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
|
||||
|
||||
setTimeout(function() {
|
||||
|
||||
view.album.init();
|
||||
|
||||
if (!refresh) {
|
||||
lychee.animate('.album, .photo', 'contentZoomIn');
|
||||
view.header.mode('album');
|
||||
}
|
||||
|
||||
}, waitTime);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
album.parse = function() {
|
||||
|
||||
if (!album.json.title) album.json.title = 'Untitled';
|
||||
|
||||
}
|
||||
|
||||
album.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) {
|
||||
|
||||
// Avoid first album to be true
|
||||
if (data===true) data = 1;
|
||||
|
||||
if (data!==false&&isNumber(data)) {
|
||||
albums.refresh();
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
album.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) {
|
||||
albums.json.num--;
|
||||
view.albums.content.delete(id);
|
||||
delete albums.json.content[id];
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
albums.refresh();
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
album.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("'", ''');
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (albums.json) {
|
||||
var id = albumIDs[0];
|
||||
albums.json.content[id].title = newTitle;
|
||||
}
|
||||
|
||||
} else if (visible.albums()) {
|
||||
|
||||
albumIDs.forEach(function(id) {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
album.setDescription = function(photoID) {
|
||||
|
||||
var oldDescription = album.json.description.replace("'", '''),
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
album.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);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
album.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;
|
||||
|
||||
}
|
||||
|
||||
album.getArchive = function(albumID) {
|
||||
|
||||
var link,
|
||||
url = 'php/api.php?function=getAlbumArchive&albumID=' + albumID;
|
||||
|
||||
if (location.href.indexOf('index.html')>0) link = location.href.replace(location.hash, '').replace('index.html', url);
|
||||
else link = location.href.replace(location.hash, '') + url;
|
||||
|
||||
if (lychee.publicMode) link += '&password=' + password.value;
|
||||
|
||||
location.href = link;
|
||||
|
||||
}
|
115
src/scripts/albums.js
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @description Takes care of every action albums can handle and execute.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
albums = {
|
||||
|
||||
json: null
|
||||
|
||||
}
|
||||
|
||||
albums.load = function() {
|
||||
|
||||
var startTime,
|
||||
durationTime,
|
||||
waitTime;
|
||||
|
||||
lychee.animate('.album, .photo', 'contentZoomOut');
|
||||
lychee.animate('.divider', 'fadeOut');
|
||||
|
||||
startTime = new Date().getTime();
|
||||
|
||||
if (albums.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;
|
||||
|
||||
// Calculate delay
|
||||
durationTime = (new Date().getTime() - startTime);
|
||||
if (durationTime>300) waitTime = 0;
|
||||
else waitTime = 300 - durationTime;
|
||||
|
||||
// Skip delay when opening a blank Lychee
|
||||
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, .photo', 'contentZoomIn');
|
||||
}, waitTime);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
setTimeout(function() {
|
||||
view.header.mode('albums');
|
||||
view.albums.init();
|
||||
lychee.animate('.album, .photo', 'contentZoomIn');
|
||||
}, 300);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
albums.parse = function(album) {
|
||||
|
||||
if (album.password&&lychee.publicMode) {
|
||||
album.thumb0 = 'src/images/password.svg';
|
||||
album.thumb1 = 'src/images/password.svg';
|
||||
album.thumb2 = 'src/images/password.svg';
|
||||
} else {
|
||||
if (!album.thumb0) album.thumb0 = 'src/images/no_images.svg';
|
||||
if (!album.thumb1) album.thumb1 = 'src/images/no_images.svg';
|
||||
if (!album.thumb2) album.thumb2 = 'src/images/no_images.svg';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
albums.refresh = function() {
|
||||
|
||||
albums.json = null;
|
||||
|
||||
}
|
424
src/scripts/build.coffee
Normal file
@ -0,0 +1,424 @@
|
||||
###
|
||||
# @description This module is used to generate HTML-Code.
|
||||
# @copyright 2014 by Tobias Reich
|
||||
###
|
||||
|
||||
window.build = {}
|
||||
|
||||
build.divider = (title) ->
|
||||
|
||||
"<div class='divider fadeIn'><h1>#{ title }</h1></div>"
|
||||
|
||||
build.editIcon = (id) ->
|
||||
|
||||
"<div id='#{ id }' class='edit'><a class='icon-pencil'></a></div>"
|
||||
|
||||
build.multiselect = (top, left) ->
|
||||
|
||||
"<div id='multiselect' style='top: #{ top }px; left: #{ left }px;'></div>"
|
||||
|
||||
build.album = (data) ->
|
||||
|
||||
return '' if not data?
|
||||
|
||||
title = data.title
|
||||
longTitle = ''
|
||||
typeThumb = ''
|
||||
|
||||
if title? and title.length > 18
|
||||
|
||||
title = data.title.substr(0, 18) + '...'
|
||||
longTitle = data.title
|
||||
|
||||
if data.thumb0.split('.').pop() is 'svg' then typeThumb = 'nonretina'
|
||||
|
||||
html = """
|
||||
<div class='album' data-id='#{ data.id }' data-password='#{ data.password }'>
|
||||
<img src='#{ data.thumb2 }' width='200' height='200' alt='thumb' data-type='nonretina'>
|
||||
<img src='#{ data.thumb1 }' width='200' height='200' alt='thumb' data-type='nonretina'>
|
||||
<img src='#{ data.thumb0 }' width='200' height='200' alt='thumb' data-type='#{ typeThumb }'>
|
||||
<div class='overlay'>
|
||||
"""
|
||||
|
||||
if data.password and lychee.publicMode is false
|
||||
html += "<h1 title='#{ longTitle }'><span class='icon-lock'></span> #{ title }</h1>";
|
||||
else
|
||||
html += "<h1 title='#{ longTitle }'>#{ title }</h1>"
|
||||
|
||||
html += """
|
||||
<a>#{ data.sysdate }</a>
|
||||
</div>
|
||||
"""
|
||||
|
||||
if lychee.publicMode is false
|
||||
|
||||
if data.star is '1' then html += "<a class='badge icon-star'></a>"
|
||||
if data.public is '1' then html += "<a class='badge icon-share'></a>"
|
||||
if data.unsorted is '1' then html += "<a class='badge icon-reorder'></a>"
|
||||
if data.recent is '1' then html += "<a class='badge icon-time'></a>"
|
||||
|
||||
html += "</div>"
|
||||
|
||||
return html
|
||||
|
||||
build.photo = (data) ->
|
||||
|
||||
return '' if not data?
|
||||
|
||||
title = data.title
|
||||
longTitle = ''
|
||||
|
||||
if title? and title.length > 18
|
||||
|
||||
title = data.title.substr(0, 18) + '...'
|
||||
longTitle = data.title
|
||||
|
||||
html = """
|
||||
<div class='photo' data-album-id='#{ data.album }' data-id='#{ data.id }'>
|
||||
<img src='#{ data.thumbUrl }' width='200' height='200' alt='thumb'>
|
||||
<div class='overlay'>
|
||||
<h1 title='#{ longTitle }'>#{ title }</h1>
|
||||
"""
|
||||
|
||||
if data.cameraDate is '1'
|
||||
html += "<a><span class='icon-camera' title='Photo Date'></span>#{ data.sysdate }</a>"
|
||||
else
|
||||
html += "<a>#{ data.sysdate }</a>"
|
||||
|
||||
html += "</div>"
|
||||
|
||||
if data.star is '1' then html += "<a class='badge icon-star'></a>"
|
||||
if lychee.publicMode is false and data.public is '1' and album.json.public isnt '1' then html += "<a class='badge icon-share'></a>"
|
||||
|
||||
html += "</div>"
|
||||
|
||||
return html
|
||||
|
||||
build.imageview = (data, size, visibleControls) ->
|
||||
|
||||
return '' if not data?
|
||||
|
||||
html = """
|
||||
<div class='arrow_wrapper previous'><a id='previous' class='icon-caret-left'></a></div>
|
||||
<div class='arrow_wrapper next'><a id='next' class='icon-caret-right'></a></div>
|
||||
"""
|
||||
|
||||
if size is 'big'
|
||||
|
||||
if visibleControls is true
|
||||
html += "<div id='image' style='background-image: url(#{ data.url })'></div>"
|
||||
else
|
||||
html += "<div id='image' style='background-image: url(#{ data.url });' class='full'></div>"
|
||||
|
||||
else if size is 'medium'
|
||||
|
||||
if visibleControls is true
|
||||
html += "<div id='image' style='background-image: url(#{ data.medium })'></div>"
|
||||
else
|
||||
html += "<div id='image' style='background-image: url(#{ data.medium });' class='full'></div>"
|
||||
|
||||
else if size is 'small'
|
||||
|
||||
if visibleControls is true
|
||||
html += "<div id='image' class='small' style='background-image: url(#{ data.url }); width: #{ data.width }px; height: #{ data.height }px; margin-top: -#{ parseInt(data.height/2-20) }px; margin-left: -#{ data.width/2 }px;'></div>"
|
||||
else
|
||||
html += "<div id='image' class='small' style='background-image: url(#{ data.url }); width: #{ data.width }px; height: #{ data.height }px; margin-top: -#{ parseInt(data.height/2) }px; margin-left: -#{ data.width/2 }px;'></div>"
|
||||
|
||||
return html
|
||||
|
||||
build.no_content = (typ) ->
|
||||
|
||||
html = """
|
||||
<div class='no_content fadeIn'>
|
||||
<a class='icon icon-#{ typ }'></a>
|
||||
"""
|
||||
|
||||
switch typ
|
||||
when 'search' then html += "<p>No results</p>"
|
||||
when 'share' then html += "<p>No public albums</p>"
|
||||
when 'cog' then html += "<p>No configuration</p>"
|
||||
|
||||
html += "</div>"
|
||||
|
||||
return html
|
||||
|
||||
build.modal = (title, text, button, marginTop, closeButton) ->
|
||||
|
||||
if marginTop? then custom_style = "style='margin-top: #{ marginTop }px;'"
|
||||
else custom_style = ''
|
||||
|
||||
html = """
|
||||
<div class='message_overlay fadeIn'>
|
||||
<div class='message center' #{ custom_style }>
|
||||
<h1>#{ title }</h1>
|
||||
"""
|
||||
|
||||
if closeButton isnt false then html += "<a class='close icon-remove-sign'></a>"
|
||||
|
||||
html += "<p>#{ text }</p>"
|
||||
|
||||
$.each button, (index) ->
|
||||
|
||||
if this[0] isnt ''
|
||||
|
||||
if index is 0 then html += "<a class='button active'>#{ this[0] }</a>"
|
||||
else html += "<a class='button'>#{ this[0] }</a>"
|
||||
|
||||
html += """
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
||||
|
||||
build.signInModal = ->
|
||||
|
||||
html = """
|
||||
<div class='message_overlay'>
|
||||
<div class='message center'>
|
||||
<h1><a class='icon-lock'></a> Sign In</h1>
|
||||
<a class='close icon-remove-sign'></a>
|
||||
<div class='sign_in'>
|
||||
<input id='username' type='text' value='' placeholder='username' autocapitalize='off' autocorrect='off'>
|
||||
<input id='password' type='password' value='' placeholder='password'>
|
||||
</div>
|
||||
<div id='version'>Version #{ lychee.version }<span> – <a target='_blank' href='#{ lychee.updateURL }'>Update available!</a><span></div>
|
||||
<a onclick='lychee.login()' class='button active'>Sign in</a>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
||||
|
||||
build.uploadModal = (title, files) ->
|
||||
|
||||
html = """
|
||||
<div class='upload_overlay fadeIn'>
|
||||
<div class='upload_message center'>
|
||||
<h1>#{ title }</h1>
|
||||
<a class='close icon-remove-sign'></a>
|
||||
<div class='rows'>
|
||||
"""
|
||||
|
||||
i = 0
|
||||
file = null
|
||||
|
||||
while i < files.length
|
||||
|
||||
file = files[i]
|
||||
|
||||
if file.name.length > 40
|
||||
file.name = file.name.substr(0, 17) + '...' + file.name.substr(file.name.length-20, 20)
|
||||
|
||||
html += """
|
||||
<div class='row'>
|
||||
<a class='name'>#{ lychee.escapeHTML(file.name) }</a>
|
||||
"""
|
||||
|
||||
if file.supported is true then html += "<a class='status'></a>"
|
||||
else html += "<a class='status error'>Not supported</a>"
|
||||
|
||||
html += """
|
||||
<p class='notice'></p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
i++
|
||||
|
||||
html += """
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
||||
|
||||
build.tags = (tags, forView) ->
|
||||
|
||||
html = ''
|
||||
|
||||
if forView is true or lychee.publicMode is true then editTagsHTML = ''
|
||||
else editTagsHTML = ' ' + build.editIcon('edit_tags')
|
||||
|
||||
if tags isnt ''
|
||||
|
||||
tags = tags.split ','
|
||||
|
||||
tags.forEach (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
|
||||
|
||||
build.infoboxPhoto = (data, forView) ->
|
||||
|
||||
html = """
|
||||
<div class='header'><h1>About</h1><a class='icon-remove-sign'></a></div>
|
||||
<div class='wrapper'>
|
||||
"""
|
||||
|
||||
switch data.public
|
||||
when '0' then visible = 'No'
|
||||
when '1' then visible = 'Yes'
|
||||
when '2' then visible = 'Yes (Album)'
|
||||
else visible = '-'
|
||||
|
||||
if forView is true or lychee.publicMode is true then editTitleHTML = ''
|
||||
else editTitleHTML = ' ' + build.editIcon('edit_title')
|
||||
|
||||
if forView is true or lychee.publicMode is true then editDescriptionHTML = ''
|
||||
else editDescriptionHTML = ' ' + build.editIcon('edit_description')
|
||||
|
||||
infos = [
|
||||
['', 'Basics']
|
||||
['Title', data.title + editTitleHTML]
|
||||
['Uploaded', data.sysdate]
|
||||
['Description', data.description + editDescriptionHTML]
|
||||
['', 'Image']
|
||||
['Size', data.size]
|
||||
['Format', data.type]
|
||||
['Resolution', data.width + ' x ' + data.height]
|
||||
['Tags', build.tags(data.tags, forView)]
|
||||
]
|
||||
|
||||
exifHash = data.takestamp+data.make+data.model+data.shutter+data.aperture+data.focal+data.iso
|
||||
|
||||
if exifHash isnt '0' or exifHash isnt '0'
|
||||
|
||||
infos = infos.concat [
|
||||
['', 'Camera']
|
||||
['Captured', data.takedate]
|
||||
['Make', data.make]
|
||||
['Type/Model', data.model]
|
||||
['Shutter Speed', data.shutter]
|
||||
['Aperture', data.aperture]
|
||||
['Focal Length', data.focal]
|
||||
['ISO', data.iso]
|
||||
]
|
||||
|
||||
infos = infos.concat [
|
||||
['', 'Share']
|
||||
['Public', visible]
|
||||
]
|
||||
|
||||
infos.forEach (info, i, items) ->
|
||||
|
||||
if info[1] is '' or
|
||||
not info[1]?
|
||||
|
||||
info[1] = '-'
|
||||
|
||||
switch info[0]
|
||||
|
||||
when ''
|
||||
|
||||
# Separator
|
||||
html += """
|
||||
</table>
|
||||
<div class='separator'><h1>#{ info[1] }</h1></div>
|
||||
<table>
|
||||
"""
|
||||
|
||||
when 'Tags'
|
||||
|
||||
# Tags
|
||||
if forView isnt true and lychee.publicMode is false
|
||||
|
||||
html += """
|
||||
</table>
|
||||
<div class='separator'><h1>#{ info[0] }</h1></div>
|
||||
<div id='tags'>#{ info[1] }</div>
|
||||
"""
|
||||
|
||||
else
|
||||
|
||||
# Item
|
||||
html += """
|
||||
<tr>
|
||||
<td>#{ info[0] }</td>
|
||||
<td class='attr_#{ info[0].toLowerCase() }'>#{ info[1] }</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
html += """
|
||||
</table>
|
||||
<div class='bumper'></div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
||||
|
||||
build.infoboxAlbum = (data, forView) ->
|
||||
|
||||
html = """
|
||||
<div class='header'><h1>About</h1><a class='icon-remove-sign'></a></div>
|
||||
<div class='wrapper'>
|
||||
"""
|
||||
|
||||
switch data.public
|
||||
when '0' then visible = 'No'
|
||||
when '1' then visible = 'Yes'
|
||||
else visible = '-'
|
||||
|
||||
switch data.password
|
||||
when false then password = 'No'
|
||||
when true then password = 'Yes'
|
||||
else password = '-'
|
||||
|
||||
switch data.downloadable
|
||||
when '0' then downloadable = 'No'
|
||||
when '1' then downloadable = 'Yes'
|
||||
else downloadable = '-'
|
||||
|
||||
if forView is true or lychee.publicMode is true then editTitleHTML = ''
|
||||
else editTitleHTML = ' ' + build.editIcon('edit_title_album')
|
||||
|
||||
if forView is true or lychee.publicMode is true then editDescriptionHTML = ''
|
||||
else editDescriptionHTML = ' ' + build.editIcon('edit_description_album')
|
||||
|
||||
infos = [
|
||||
['', 'Basics']
|
||||
['Title', data.title + editTitleHTML]
|
||||
['Description', data.description + editDescriptionHTML]
|
||||
['', 'Album']
|
||||
['Created', data.sysdate]
|
||||
['Images', data.num]
|
||||
['', 'Share']
|
||||
['Public', visible]
|
||||
['Downloadable', downloadable]
|
||||
['Password', password]
|
||||
]
|
||||
|
||||
infos.forEach (info, i, items) ->
|
||||
|
||||
if info[0] is ''
|
||||
|
||||
# Separator
|
||||
html += """
|
||||
</table>
|
||||
<div class='separator'><h1>#{ info[1] }</h1></div>
|
||||
<table id='infos'>
|
||||
"""
|
||||
|
||||
else
|
||||
|
||||
# Item
|
||||
html += """
|
||||
<tr>
|
||||
<td>#{ info[0] }</td>
|
||||
<td class='attr_#{ info[0].toLowerCase() }'>#{ info[1] }</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
html += """
|
||||
</table>
|
||||
<div class='bumper'></div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
return html
|
226
src/scripts/contextMenu.js
Normal file
@ -0,0 +1,226 @@
|
||||
/**
|
||||
* @description This module is used for the context menu.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
contextMenu = {}
|
||||
|
||||
contextMenu.add = function(e) {
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Upload Photo', icon: 'icon-picture', fn: function() { $('#upload_files').click() } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Import from Link', icon: 'icon-link', fn: upload.start.url },
|
||||
{ type: 'item', title: 'Import from Dropbox', icon: 'icon-folder-open', fn: upload.start.dropbox },
|
||||
{ type: 'item', title: 'Import from Server', icon: 'icon-hdd', fn: upload.start.server },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'New Album', icon: 'icon-folder-close', fn: album.add }
|
||||
];
|
||||
|
||||
basicContext.show(items, e);
|
||||
|
||||
upload.notify();
|
||||
|
||||
}
|
||||
|
||||
contextMenu.settings = function(e) {
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Change Login', icon: 'icon-user', fn: settings.setLogin },
|
||||
{ type: 'item', title: 'Change Sorting', icon: 'icon-sort', fn: settings.setSorting },
|
||||
{ type: 'item', title: 'Set Dropbox', icon: 'icon-folder-open', fn: settings.setDropboxKey },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'About Lychee', icon: 'icon-info-sign', fn: function() { window.open(lychee.website) } },
|
||||
{ type: 'item', title: 'Diagnostics', icon: 'icon-dashboard', fn: function() { window.open('plugins/check/') } },
|
||||
{ type: 'item', title: 'Show Log', icon: 'icon-list', fn: function() { window.open('plugins/displaylog/') } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Sign Out', icon: 'icon-signout', fn: lychee.logout }
|
||||
];
|
||||
|
||||
basicContext.show(items, e);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.album = function(albumID, e) {
|
||||
|
||||
if (albumID==='0'||albumID==='f'||albumID==='s'||albumID==='r') return false;
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Rename', icon: 'icon-edit', fn: function() { album.setTitle([albumID]) } },
|
||||
{ type: 'item', title: 'Delete', icon: 'icon-trash', fn: function() { album.delete([albumID]) } }
|
||||
];
|
||||
|
||||
$('.album[data-id="' + albumID + '"]').addClass('active');
|
||||
|
||||
basicContext.show(items, e, contextMenu.close);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.albumMulti = function(albumIDs, e) {
|
||||
|
||||
multiselect.stopResize();
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Rename All', icon: 'icon-edit', fn: function() { album.setTitle(albumIDs) } },
|
||||
{ type: 'item', title: 'Delete All', icon: 'icon-trash', fn: function() { album.delete(albumIDs) } }
|
||||
];
|
||||
|
||||
basicContext.show(items, e, contextMenu.close);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.photo = function(photoID, e) {
|
||||
|
||||
// Notice for 'Move':
|
||||
// fn must call basicContext.close() first,
|
||||
// in order to keep the selection
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Star', icon: 'icon-star', fn: function() { photo.setStar([photoID]) } },
|
||||
{ type: 'item', title: 'Tags', icon: 'icon-tags', fn: function() { photo.editTags([photoID]) } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Rename', icon: 'icon-edit', fn: function() { photo.setTitle([photoID]) } },
|
||||
{ type: 'item', title: 'Duplicate', icon: 'icon-copy', fn: function() { photo.duplicate([photoID]) } },
|
||||
{ type: 'item', title: 'Move', icon: 'icon-folder-open', fn: function() { basicContext.close(); contextMenu.move([photoID], e); } },
|
||||
{ type: 'item', title: 'Delete', icon: 'icon-trash', fn: function() { photo.delete([photoID]) } }
|
||||
];
|
||||
|
||||
$('.photo[data-id="' + photoID + '"]').addClass('active');
|
||||
|
||||
basicContext.show(items, e, contextMenu.close);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.photoMulti = function(photoIDs, e) {
|
||||
|
||||
// Notice for 'Move All':
|
||||
// fn must call basicContext.close() first,
|
||||
// in order to keep the selection and multiselect
|
||||
|
||||
multiselect.stopResize();
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Star All', icon: 'icon-star', fn: function() { photo.setStar(photoIDs) } },
|
||||
{ type: 'item', title: 'Tag All', icon: 'icon-tags', fn: function() { photo.editTags(photoIDs) } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Rename All', icon: 'icon-edit', fn: function() { photo.setTitle(photoIDs) } },
|
||||
{ type: 'item', title: 'Duplicate All', icon: 'icon-copy', fn: function() { photo.duplicate(photoIDs) } },
|
||||
{ type: 'item', title: 'Move All', icon: 'icon-folder-open', fn: function() { basicContext.close(); contextMenu.move(photoIDs, e); } },
|
||||
{ type: 'item', title: 'Delete All', icon: 'icon-trash', fn: function() { photo.delete(photoIDs) } }
|
||||
];
|
||||
|
||||
basicContext.show(items, e, contextMenu.close);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.photoMore = function(photoID, e) {
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: 'Full Photo', icon: 'icon-resize-full', fn: function() { window.open(photo.getDirectLink()) } },
|
||||
{ type: 'item', title: 'Download', icon: 'icon-circle-arrow-down', fn: function() { photo.getArchive(photoID) } }
|
||||
];
|
||||
|
||||
// Remove download-item when
|
||||
// 1) In public mode
|
||||
// 2) Downloadable not 1 or not found
|
||||
if (!(album.json&&album.json.downloadable&&album.json.downloadable==='1')&&
|
||||
lychee.publicMode===true) items.splice(1, 1);
|
||||
|
||||
basicContext.show(items, e);
|
||||
|
||||
}
|
||||
|
||||
contextMenu.move = function(photoIDs, e) {
|
||||
|
||||
var items = [];
|
||||
|
||||
// Show Unsorted when unsorted is not the current album
|
||||
if (album.getID()!=='0') {
|
||||
|
||||
items = [
|
||||
{ type: 'item', title: 'Unsorted', fn: function() { photo.setAlbum(photoIDs, 0) } },
|
||||
{ type: 'separator' }
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
lychee.api('getAlbums', function(data) {
|
||||
|
||||
if (data.num===0) {
|
||||
|
||||
// Show only 'Add album' when no album available
|
||||
items = [
|
||||
{ type: 'item', title: 'New Album', fn: album.add }
|
||||
];
|
||||
|
||||
} else {
|
||||
|
||||
// Generate list of albums
|
||||
$.each(data.content, function(index) {
|
||||
|
||||
var that = this;
|
||||
|
||||
if (!that.thumb0) that.thumb0 = 'src/images/no_cover.svg';
|
||||
that.title = "<img class='albumCover' width='16' height='16' src='" + that.thumb0 + "'><div class='albumTitle'>" + that.title + "</div>";
|
||||
|
||||
if (that.id!=album.getID()) items.push({ type: 'item', title: that.title, fn: function() { photo.setAlbum(photoIDs, that.id) } });
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
basicContext.show(items, e, contextMenu.close);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
contextMenu.sharePhoto = function(photoID, e) {
|
||||
|
||||
var link = photo.getViewLink(photoID);
|
||||
if (photo.json.public==='2') link = location.href;
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: '<input readonly id="link" value="' + link + '">', fn: function() {}, class: 'noHover' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Make Private', icon: 'icon-eye-close', fn: function() { photo.setPublic(photoID) } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Twitter', icon: 'icon-twitter', fn: function() { photo.share(photoID, 0) } },
|
||||
{ type: 'item', title: 'Facebook', icon: 'icon-facebook', fn: function() { photo.share(photoID, 1) } },
|
||||
{ type: 'item', title: 'Mail', icon: 'icon-envelope', fn: function() { photo.share(photoID, 2) } },
|
||||
{ type: 'item', title: 'Dropbox', icon: 'icon-hdd', fn: function() { photo.share(photoID, 3) } },
|
||||
{ type: 'item', title: 'Direct Link', icon: 'icon-link', fn: function() { window.open(photo.getDirectLink()) } }
|
||||
];
|
||||
|
||||
basicContext.show(items, e);
|
||||
$('.basicContext input#link').focus().select();
|
||||
|
||||
}
|
||||
|
||||
contextMenu.shareAlbum = function(albumID, e) {
|
||||
|
||||
var items = [
|
||||
{ type: 'item', title: '<input readonly id="link" value="' + location.href + '">', fn: function() {}, class: 'noHover' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Make Private', icon: 'icon-eye-close', fn: function() { album.setPublic(albumID) } },
|
||||
{ type: 'separator' },
|
||||
{ type: 'item', title: 'Twitter', icon: 'icon-twitter', fn: function() { album.share(0) } },
|
||||
{ type: 'item', title: 'Facebook', icon: 'icon-facebook', fn: function() { album.share(1) } },
|
||||
{ type: 'item', title: 'Mail', icon: 'icon-envelope', fn: function() { album.share(2) } }
|
||||
];
|
||||
|
||||
basicContext.show(items, e);
|
||||
$('.basicContext input#link').focus().select();
|
||||
|
||||
}
|
||||
|
||||
contextMenu.close = function() {
|
||||
|
||||
if (!visible.contextMenu()) return false;
|
||||
|
||||
basicContext.close();
|
||||
|
||||
$('.photo.active, .album.active').removeClass('active');
|
||||
if (visible.multiselect()) multiselect.close();
|
||||
|
||||
}
|
198
src/scripts/init.js
Executable file
@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @description This module is used for bindings.
|
||||
* @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() });
|
||||
|
||||
/* Multiselect */
|
||||
$('#content') .on('mousedown', multiselect.show);
|
||||
$(document) .on('mouseup', multiselect.getSelection);
|
||||
|
||||
/* Header */
|
||||
$('#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_signin') .on(event_name, lychee.loginDialog);
|
||||
$('#button_settings') .on(event_name, contextMenu.settings);
|
||||
$('#button_info_album') .on(event_name, view.infobox.show);
|
||||
$('#button_info') .on(event_name, view.infobox.show);
|
||||
$('#button_more') .on(event_name, function(e) { contextMenu.photoMore(photo.getID(), e) });
|
||||
$('#button_move') .on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
|
||||
$('#hostedwith') .on(event_name, function() { window.open(lychee.website) });
|
||||
$('#button_trash_album') .on(event_name, function() { album.delete([album.getID()]) });
|
||||
$('#button_trash') .on(event_name, function() { photo.delete([photo.getID()]) });
|
||||
$('#button_archive') .on(event_name, function() { album.getArchive(album.getID()) });
|
||||
$('#button_star') .on(event_name, function() { photo.setStar([photo.getID()]) });
|
||||
$('#button_back_home') .on(event_name, function() { lychee.goto('') });
|
||||
$('#button_back') .on(event_name, function() { lychee.goto(album.getID()) });
|
||||
|
||||
/* Search */
|
||||
$('#search').on('keyup click', function() { search.find($(this).val()) });
|
||||
|
||||
/* Clear Search */
|
||||
$('#clearSearch').on(event_name, function () {
|
||||
$('#search').focus();
|
||||
search.reset();
|
||||
});
|
||||
|
||||
/* 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', 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.multiselect()) return false;
|
||||
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()]);
|
||||
})
|
||||
.bind(['command+a', 'ctrl+a'], function() {
|
||||
if (visible.album()&&!visible.message()) multiselect.selectAll();
|
||||
else if (visible.albums()&&!visible.message()) multiselect.selectAll();
|
||||
});
|
||||
|
||||
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', contextMenu.add)
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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();
|
||||
|
||||
// Close open overlays or views which are correlating with the upload
|
||||
if (visible.photo()) lychee.goto(album.getID());
|
||||
if (visible.contextMenu()) contextMenu.close();
|
||||
|
||||
// Detect if dropped item is a file or a link
|
||||
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();
|
||||
|
||||
});
|
89
src/scripts/loadingBar.js
Executable file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @description This module is used to show and hide the loading bar.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
loadingBar = {
|
||||
|
||||
status: null
|
||||
|
||||
}
|
||||
|
||||
loadingBar.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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadingBar.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
392
src/scripts/lychee.js
Normal file
@ -0,0 +1,392 @@
|
||||
/**
|
||||
* @description This module provides the basic functions of Lychee.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
lychee = {
|
||||
|
||||
title: '',
|
||||
version: '2.7.0',
|
||||
version_code: '020700',
|
||||
|
||||
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,
|
||||
|
||||
checkForUpdates:false,
|
||||
username: '',
|
||||
sorting: '',
|
||||
location: '',
|
||||
|
||||
dropbox: false,
|
||||
dropboxKey: '',
|
||||
|
||||
loadingBar: $('#loading'),
|
||||
header: $('header'),
|
||||
content: $('#content'),
|
||||
imageview: $('#imageview'),
|
||||
infobox: $('#infobox')
|
||||
|
||||
}
|
||||
|
||||
lychee.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();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
lychee.api = function(params, callback) {
|
||||
|
||||
loadingBar.show();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: lychee.api_path,
|
||||
data: 'function=' + params,
|
||||
dataType: 'text',
|
||||
success: function(data) {
|
||||
|
||||
setTimeout(function() { loadingBar.hide() }, 100);
|
||||
|
||||
// Catch errors
|
||||
if (typeof data==='string'&&
|
||||
data.substring(0, 7)==='Error: ') {
|
||||
lychee.error(data.substring(7, data.length), params, data);
|
||||
upload.close(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert 1 to true and an empty string to false
|
||||
if (data==='1') data = true;
|
||||
else if (data==='') data = false;
|
||||
|
||||
// Convert to JSON if string start with '{' and ends with '}'
|
||||
if (typeof data==='string'&&
|
||||
data.substring(0, 1)==='{'&&
|
||||
data.substring(data.length-1, data.length)==='}') data = $.parseJSON(data);
|
||||
|
||||
// Output response when debug mode is enabled
|
||||
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);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
lychee.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) {
|
||||
|
||||
// Use 'try' to catch a thrown error when Safari is in private mode
|
||||
try { localStorage.setItem('lychee_username', user); }
|
||||
catch (err) {}
|
||||
|
||||
window.location.reload();
|
||||
|
||||
} else {
|
||||
|
||||
// Show error and reactive button
|
||||
$('#password').val('').addClass('error').focus();
|
||||
$('.message .button.active').removeClass('pressed');
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
lychee.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();
|
||||
|
||||
}
|
||||
|
||||
lychee.logout = function() {
|
||||
|
||||
lychee.api('logout', function() {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
lychee.goto = function(url) {
|
||||
|
||||
if (url===undefined) url = '#';
|
||||
else url = '#' + url;
|
||||
|
||||
history.pushState(null, null, url);
|
||||
lychee.load();
|
||||
|
||||
}
|
||||
|
||||
lychee.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
|
||||
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);
|
||||
|
||||
} else if (albumID) {
|
||||
|
||||
// Trash data
|
||||
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 albums.json when filled with search results
|
||||
if (search.code!=='') {
|
||||
albums.json = null;
|
||||
search.code = '';
|
||||
}
|
||||
|
||||
// Trash data
|
||||
album.json = null;
|
||||
photo.json = null;
|
||||
|
||||
// Show Albums
|
||||
if (visible.album()) view.album.hide();
|
||||
if (visible.photo()) view.photo.hide();
|
||||
albums.load();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lychee.getUpdate = function() {
|
||||
|
||||
$.ajax({
|
||||
url: lychee.update_path,
|
||||
success: function(data) { if (parseInt(data)>parseInt(lychee.version_code)) $('#version span').show(); }
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
lychee.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);
|
||||
|
||||
}
|
||||
|
||||
lychee.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(['f', 'ctrl+f'])
|
||||
.unbind(['r', 'ctrl+r'])
|
||||
.unbind(['d', 'ctrl+d'])
|
||||
.unbind(['t', 'ctrl+t'])
|
||||
.unbind(['command+backspace', 'ctrl+backspace'])
|
||||
.unbind(['command+a', 'ctrl+a']);
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lychee.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;
|
||||
|
||||
}
|
||||
|
||||
lychee.escapeHTML = function(s) {
|
||||
|
||||
return s.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
|
||||
}
|
||||
|
||||
lychee.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lychee.removeHTML = function(html) {
|
||||
|
||||
var tmp = document.createElement('DIV');
|
||||
tmp.innerHTML = html;
|
||||
return tmp.textContent || tmp.innerText;
|
||||
|
||||
}
|
||||
|
||||
lychee.error = function(errorThrown, params, data) {
|
||||
|
||||
console.error({
|
||||
description: errorThrown,
|
||||
params: params,
|
||||
response: data
|
||||
});
|
||||
|
||||
loadingBar.show('error', errorThrown);
|
||||
|
||||
}
|
34
src/scripts/modal.js
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @description Build, show and hide a modal.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
modal = {
|
||||
|
||||
fns: null
|
||||
|
||||
}
|
||||
|
||||
modal.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();
|
||||
|
||||
}
|
||||
|
||||
modal.close = function() {
|
||||
|
||||
modal.fns = null;
|
||||
$('.message_overlay').removeClass('fadeIn').css('opacity', 0);
|
||||
setTimeout(function() { $('.message_overlay').remove() }, 300);
|
||||
|
||||
}
|
206
src/scripts/multiselect.js
Normal file
@ -0,0 +1,206 @@
|
||||
/**
|
||||
* @description Select multiple albums or photos.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
multiselect = {}
|
||||
|
||||
multiselect.position = {
|
||||
|
||||
top: null,
|
||||
right: null,
|
||||
bottom: null,
|
||||
left: null
|
||||
|
||||
}
|
||||
|
||||
multiselect.show = function(e) {
|
||||
|
||||
if (mobileBrowser()) return false;
|
||||
if (lychee.publicMode) return false;
|
||||
if (visible.search()) return false;
|
||||
if (visible.infobox()) return false;
|
||||
if (!visible.albums()&&!visible.album) 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);
|
||||
|
||||
}
|
||||
|
||||
multiselect.selectAll = function() {
|
||||
|
||||
var e,
|
||||
newWidth,
|
||||
newHeight;
|
||||
|
||||
if (mobileBrowser()) return false;
|
||||
if (lychee.publicMode) return false;
|
||||
if (visible.search()) return false;
|
||||
if (visible.infobox()) return false;
|
||||
if (!visible.albums()&&!visible.album) return false;
|
||||
if (visible.multiselect()) $('#multiselect').remove();
|
||||
|
||||
multiselect.position.top = 70;
|
||||
multiselect.position.right = 40;
|
||||
multiselect.position.bottom = 90;
|
||||
multiselect.position.left = 20;
|
||||
|
||||
$('body').append(build.multiselect(multiselect.position.top, multiselect.position.left));
|
||||
|
||||
newWidth = $(document).width() - multiselect.position.right + 2;
|
||||
newHeight = $(document).height() - multiselect.position.bottom;
|
||||
|
||||
$('#multiselect').css({
|
||||
width: newWidth,
|
||||
height: newHeight
|
||||
});
|
||||
|
||||
e = {
|
||||
pageX: $(document).width() - (multiselect.position.right / 2),
|
||||
pageY: $(document).height() - multiselect.position.bottom
|
||||
};
|
||||
|
||||
multiselect.getSelection(e);
|
||||
|
||||
}
|
||||
|
||||
multiselect.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 = mouse_y - 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 = mouse_x - 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
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
multiselect.stopResize = function() {
|
||||
|
||||
$(document).off('mousemove');
|
||||
|
||||
}
|
||||
|
||||
multiselect.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', ''))
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
multiselect.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();
|
||||
|
||||
}
|
||||
|
||||
multiselect.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);
|
||||
|
||||
}
|
61
src/scripts/password.js
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @description Controls the access to password-protected albums and photos.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
password = {
|
||||
|
||||
value: ''
|
||||
|
||||
}
|
||||
|
||||
password.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!');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
625
src/scripts/photo.js
Normal file
@ -0,0 +1,625 @@
|
||||
/**
|
||||
* @description Takes care of every action a photo can handle and execute.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
photo = {
|
||||
|
||||
json: null,
|
||||
cache: null
|
||||
|
||||
}
|
||||
|
||||
photo.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;
|
||||
|
||||
}
|
||||
|
||||
photo.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();
|
||||
//photo.preloadNext(photoID, albumID);
|
||||
}, 300);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Preload the next photo for better response time
|
||||
photo.preloadNext = function(photoID) {
|
||||
|
||||
var nextPhoto,
|
||||
url;
|
||||
|
||||
// Never preload on mobile devices with bare RAM and
|
||||
// mostly mobile internet
|
||||
if (mobileBrowser()) return false;
|
||||
|
||||
if (album.json &&
|
||||
album.json.content &&
|
||||
album.json.content[photoID] &&
|
||||
album.json.content[photoID].nextPhoto!='') {
|
||||
|
||||
nextPhoto = album.json.content[photoID].nextPhoto;
|
||||
url = album.json.content[nextPhoto].url;
|
||||
|
||||
photo.cache = new Image();
|
||||
photo.cache.src = url;
|
||||
photo.cache.onload = function() { photo.cache = null };
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
photo.parse = function() {
|
||||
|
||||
if (!photo.json.title) photo.json.title = 'Untitled';
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
photo.duplicate = function(photoIDs) {
|
||||
|
||||
var params;
|
||||
|
||||
if (!photoIDs) return false;
|
||||
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = 'duplicatePhoto&photoIDs=' + photoIDs;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
else album.load(album.getID());
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
photo.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;
|
||||
|
||||
// Fallback for photos without a title
|
||||
if (photoTitle==='') photoTitle = 'Untitled';
|
||||
|
||||
}
|
||||
|
||||
buttons = [
|
||||
['', function() {
|
||||
|
||||
var nextPhoto = '',
|
||||
previousPhoto = '';
|
||||
|
||||
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);
|
||||
|
||||
});
|
||||
|
||||
albums.refresh();
|
||||
|
||||
// Go to next photo if there is a next photo and
|
||||
// next photo is not the current one. Show album otherwise.
|
||||
if (visible.photo()&&nextPhoto!==''&&nextPhoto!==photo.getID()) lychee.goto(album.getID() + '/' + nextPhoto);
|
||||
else 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
photo.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("'", ''');
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
});
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = 'setPhotoAlbum&photoIDs=' + photoIDs + '&albumID=' + albumID;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
});
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = 'setPhotoStar&photoIDs=' + photoIDs;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
photo.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;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
albums.refresh();
|
||||
|
||||
params = 'setPhotoPublic&photoID=' + photoID;
|
||||
lychee.api(params, function(data) {
|
||||
|
||||
if (data!==true) lychee.error(null, params, data);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
photo.setDescription = function(photoID) {
|
||||
|
||||
var oldDescription = photo.json.description.replace("'", '''),
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
photo.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);
|
||||
|
||||
}
|
||||
|
||||
photo.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;
|
||||
|
||||
}
|
||||
|
||||
photo.getSize = function() {
|
||||
|
||||
// Size can be 'big', 'medium' or 'small'
|
||||
// Default is big
|
||||
// Small is centered in the middle of the screen
|
||||
var size = 'big',
|
||||
scaled = false,
|
||||
hasMedium = photo.json.medium!=='',
|
||||
pixelRatio = window.devicePixelRatio,
|
||||
view = {
|
||||
width: $(window).width()-60,
|
||||
height: $(window).height()-100
|
||||
};
|
||||
|
||||
// Detect if the photo will be shown scaled,
|
||||
// because the screen size is smaller than the photo
|
||||
if (photo.json.width>view.width||
|
||||
photo.json.width>view.height) scaled = true;
|
||||
|
||||
// Calculate pixel ratio of screen
|
||||
if (pixelRatio!==undefined&&pixelRatio>1) {
|
||||
view.width = view.width * pixelRatio;
|
||||
view.height = view.height * pixelRatio;
|
||||
}
|
||||
|
||||
// Medium available and
|
||||
// Medium still bigger than screen
|
||||
if (hasMedium===true&&
|
||||
(1920>view.width&&1080>view.height)) size = 'medium';
|
||||
|
||||
// Photo not scaled
|
||||
// Photo smaller then screen
|
||||
if (scaled===false&&
|
||||
(photo.json.width<view.width&&
|
||||
photo.json.width<view.height)) size = 'small';
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
photo.getArchive = function(photoID) {
|
||||
|
||||
var link,
|
||||
url = 'php/api.php?function=getPhotoArchive&photoID=' + photoID;
|
||||
|
||||
if (location.href.indexOf('index.html')>0) link = location.href.replace(location.hash, '').replace('index.html', url);
|
||||
else link = location.href.replace(location.hash, '') + url;
|
||||
|
||||
if (lychee.publicMode) link += '&password=' + password.value;
|
||||
|
||||
location.href = link;
|
||||
|
||||
}
|
||||
|
||||
photo.getDirectLink = function() {
|
||||
|
||||
var url = '';
|
||||
|
||||
if (photo.json&&
|
||||
photo.json.url&&
|
||||
photo.json.url!=='') url = photo.json.url;
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
|
||||
photo.getViewLink = function(photoID) {
|
||||
|
||||
var url = 'view.php?p=' + photoID;
|
||||
|
||||
if (location.href.indexOf('index.html')>0) return location.href.replace('index.html' + location.hash, url);
|
||||
else return location.href.replace(location.hash, url);
|
||||
|
||||
}
|
104
src/scripts/search.js
Executable file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @description Searches through your photos and albums.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
search = {
|
||||
|
||||
code: null
|
||||
|
||||
}
|
||||
|
||||
search.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) {
|
||||
|
||||
// Build albums
|
||||
if (data&&data.albums) {
|
||||
albums.json = { content: data.albums };
|
||||
$.each(albums.json.content, function() {
|
||||
albums.parse(this);
|
||||
albumsData += build.album(this);
|
||||
});
|
||||
}
|
||||
|
||||
// Build photos
|
||||
if (data&&data.photos) {
|
||||
album.json = { content: data.photos };
|
||||
$.each(album.json.content, function() {
|
||||
photosData += build.photo(this);
|
||||
});
|
||||
}
|
||||
|
||||
// 1. No albums and photos found
|
||||
// 2. Only photos found
|
||||
// 3. Only albums found
|
||||
// 4. Albums and photos found
|
||||
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;
|
||||
|
||||
// Only refresh view when search results are different
|
||||
if (search.code!==md5(code)) {
|
||||
|
||||
$('.no_content').remove();
|
||||
|
||||
lychee.animate('.album, .photo', 'contentZoomOut');
|
||||
lychee.animate('.divider', 'fadeOut');
|
||||
|
||||
search.code = md5(code);
|
||||
|
||||
setTimeout(function() {
|
||||
|
||||
if (code==='error') {
|
||||
lychee.content.html('');
|
||||
$('body').append(build.no_content('search'));
|
||||
} else {
|
||||
lychee.content.html(code);
|
||||
lychee.animate('.album, .photo', 'contentZoomIn');
|
||||
$('img[data-type!="svg"]').retina();
|
||||
}
|
||||
|
||||
}, 300);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} else search.reset();
|
||||
|
||||
}, 250));
|
||||
|
||||
}
|
||||
|
||||
search.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();
|
||||
|
||||
}
|
||||
|
||||
}
|
289
src/scripts/settings.js
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
* @description Lets you change settings.
|
||||
* @copyright 2014 by Tobias Reich
|
||||
*/
|
||||
|
||||
settings = {}
|
||||
|
||||
settings.createConfig = function() {
|
||||
|
||||
var dbName,
|
||||
dbUser,
|
||||
dbPassword,
|
||||
dbHost,
|
||||
dbTablePrefix,
|
||||
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();
|
||||
dbTablePrefix = $('.message input.text#dbTablePrefix').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) + '&dbTablePrefix=' + escape(dbTablePrefix);
|
||||
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='Database Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Database Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Database 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 less' type='text' placeholder='Database Name (optional)' value=''><input id='dbTablePrefix' class='text more' type='text' placeholder='Table prefix (optional)' value=''>", buttons, -235, false);
|
||||
|
||||
}
|
||||
|
||||
settings.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);
|
||||
|
||||
}
|
||||
|
||||
settings.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);
|
||||
|
||||
}
|
||||
|
||||
settings.setSorting = function() {
|
||||
|
||||
var buttons,
|
||||
sorting,
|
||||
params;
|
||||
|
||||
buttons = [
|
||||
['Change Sorting', function() {
|
||||
|
||||
sorting[0] = $('select#settings_type').val();
|
||||
sorting[1] = $('select#settings_order').val();
|
||||
|
||||
albums.refresh();
|
||||
|
||||
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]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
settings.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);
|
||||
|
||||
}
|