Merge pull request #92 from electerious/2.1

v2.1
This commit is contained in:
Tobias Reich 2014-03-04 13:17:31 +01:00
commit 0f533151db
82 changed files with 2896 additions and 2218 deletions

2
.gitignore vendored
View File

@ -6,7 +6,9 @@ data/config.php
uploads/import/* uploads/import/*
uploads/big/* uploads/big/*
uploads/thumb/* uploads/thumb/*
plugins/*
!uploads/import/index.html !uploads/import/index.html
!uploads/big/index.html !uploads/big/index.html
!uploads/thumb/index.html !uploads/thumb/index.html
!plugins/check.php

1
assets/build/main.css Normal file

File diff suppressed because one or more lines are too long

6
assets/build/main.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@
* @copyright 2014 by Tobias Reich * @copyright 2014 by Tobias Reich
*/ */
/* Gradient ------------------------------------------------*/
#content::before { #content::before {
content: ""; content: "";
position: absolute; position: absolute;
@ -26,6 +27,7 @@
position: absolute; position: absolute;
padding: 50px 0px 33px 0px; padding: 50px 0px 33px 0px;
width: 100%; width: 100%;
min-height: calc(100% - 90px);
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
@ -115,7 +117,10 @@
background: linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* W3C */ background: linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* W3C */
} }
.photo .overlay { .photo .overlay {
background: rgba(0, 0, 0, .6); background: -moz-linear-gradient(top, 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%); /* FF3.6+ */
background: -webkit-linear-gradient(top, 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%); /* Chrome10+,Safari5.1+ */
background: -ms-linear-gradient(top, 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%); /* IE10+ */
background: linear-gradient(top, 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%); /* W3C */
opacity: 0; opacity: 0;
} }
.photo:hover .overlay, .photo:hover .overlay,

View File

@ -23,8 +23,8 @@
*/ */
@font-face { @font-face {
font-family: 'FontAwesome'; font-family: 'FontAwesome';
src: url('../../font/fontawesome-webfont.eot'); src: url('../font/fontawesome-webfont.eot');
src: url('../../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../../font/fontawesome-webfont.woff') format('woff'), url('../../font/fontawesome-webfont.ttf') format('truetype'), url('../../font/fontawesome-webfont.svg#FontAwesome') format('svg'); src: url('../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }

View File

@ -27,10 +27,6 @@
-moz-transform: translateX(320px); -moz-transform: translateX(320px);
transform: translateX(320px); transform: translateX(320px);
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
-webkit-transition: -webkit-transform .5s cubic-bezier(.225,.5,.165,1); -webkit-transition: -webkit-transform .5s cubic-bezier(.225,.5,.165,1);
-moz-transition: -moz-transform .5s cubic-bezier(.225,.5,.165,1); -moz-transition: -moz-transform .5s cubic-bezier(.225,.5,.165,1);
transition: transform .5s cubic-bezier(.225,.5,.165,1); transition: transform .5s cubic-bezier(.225,.5,.165,1);
@ -121,6 +117,10 @@
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
line-height: 19px; line-height: 19px;
-webkit-user-select: text;
-moz-user-select: text;
user-select: text;
} }
#infobox table tr td:first-child { #infobox table tr td:first-child {
width: 110px; width: 110px;
@ -131,10 +131,24 @@
/* Tags ------------------------------------------------*/ /* Tags ------------------------------------------------*/
#infobox #tags { #infobox #tags {
margin: 20px 20px 15px 20px; width: calc(100% - 40px);
margin: 16px 20px 12px 20px;
color: #fff; color: #fff;
display: inline-block; display: inline-block;
} }
#infobox #tags .empty {
font-size: 14px;
margin-bottom: 8px;
}
#infobox #tags .edit {
display: inline-block;
}
#infobox #tags .empty .edit {
display: inline;
}
#infobox .tag { #infobox .tag {
float: left; float: left;
padding: 4px 7px; padding: 4px 7px;
@ -156,7 +170,7 @@
padding: 0px; padding: 0px;
margin: 0px 0px -2px 0px; margin: 0px 0px -2px 0px;
color: red; color: red;
font-size: 12px; font-size: 11px;
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
-webkit-transform: scale(0); -webkit-transform: scale(0);

File diff suppressed because one or more lines are too long

View File

@ -7,9 +7,6 @@
html, html,
body { body {
min-height: 100%; min-height: 100%;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
} }
body { body {
background-color: #222; background-color: #222;
@ -29,7 +26,15 @@ body.view {
top:50%; top:50%;
} }
* { * {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-transition: color .3s, opacity .3s ease-out, -webkit-transform .3s ease-out, box-shadow .3s; -webkit-transition: color .3s, opacity .3s ease-out, -webkit-transform .3s ease-out, box-shadow .3s;
-moz-transition: opacity .3s ease-out, -moz-transform .3s ease-out, box-shadow .3s; -moz-transition: opacity .3s ease-out, -moz-transform .3s ease-out, box-shadow .3s;
transition: color .3s, opacity .3s ease-out, transform .3s ease-out, box-shadow .3s; 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;
}

View File

@ -0,0 +1,13 @@
/**
* @name multiselect.css
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
#multiselect {
position: absolute;
background-color: rgba(0, 94, 204, .3);
border: 1px solid rgba(0, 94, 204, 1);
border-radius: 3px;
z-index: 3;
}

View File

@ -46,7 +46,14 @@ album = {
lychee.api(params, function(data) { lychee.api(params, function(data) {
if (data==="Warning: Album private!") { if (data==="Warning: Album private!") {
if (document.location.hash.replace("#", "").split("/")[1]!=undefined) {
// Display photo only
lychee.setMode("view"); lychee.setMode("view");
} else {
// Album not public
lychee.content.show();
lychee.goto("");
}
return false; return false;
} }
@ -96,9 +103,7 @@ album = {
title = $(".message input.text").val(); title = $(".message input.text").val();
if (title==="") title = "Untitled"; if (title.length===0) title = "Untitled";
if (title.length>0&&title.length<31) {
modal.close(); modal.close();
@ -112,30 +117,36 @@ album = {
}); });
} else loadingBar.show("error", "Title too short or too long. Please try again!");
}], }],
["Cancel", function() {}] ["Cancel", function() {}]
]; ];
modal.show("New Album", "Please enter a title for this album: <input class='text' type='text' placeholder='Title' value='Untitled'>", buttons);
modal.show("New Album", "Enter a title for this album: <input class='text' type='text' maxlength='30' placeholder='Title' value='Untitled'>", buttons);
}, },
delete: function(albumID) { delete: function(albumIDs) {
var params, var params,
buttons, buttons,
albumTitle; albumTitle;
buttons = [ if (!albumIDs) return false;
["Delete Album and Photos", function() { if (albumIDs instanceof Array===false) albumIDs = [albumIDs];
params = "deleteAlbum&albumID=" + albumID; buttons = [
["", function() {
params = "deleteAlbum&albumIDs=" + albumIDs;
lychee.api(params, function(data) { lychee.api(params, function(data) {
if (visible.albums()) { if (visible.albums()) {
albumIDs.forEach(function(id, index, array) {
albums.json.num--; albums.json.num--;
view.albums.content.delete(albumID); view.albums.content.delete(id);
});
} else lychee.goto(""); } else lychee.goto("");
if (data!==true) lychee.error(null, params, data); if (data!==true) lychee.error(null, params, data);
@ -143,75 +154,93 @@ album = {
}); });
}], }],
["Keep Album", function() {}] ["", function() {}]
]; ];
if (albumID==="0") { if (albumIDs==="0") {
buttons[0][0] = "Clear Unsorted"; buttons[0][0] = "Clear Unsorted";
modal.show("Clear Unsorted", "Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!", buttons) 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 { } else {
if (album.json) albumTitle = album.json.title; buttons[0][0] = "Delete Albums and Photos";
else if (albums.json) albumTitle = albums.json.content[albumID].title; buttons[1][0] = "Keep Albums";
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);
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(albumID) { setTitle: function(albumIDs) {
var oldTitle = "", var oldTitle = "",
newTitle, newTitle,
params, params,
buttons; buttons;
if (!albumID) return false; 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; if (album.json) oldTitle = album.json.title;
else if (albums.json) oldTitle = albums.json.content[albumID].title; else if (albums.json) oldTitle = albums.json.content[albumIDs].title;
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [ buttons = [
["Set Title", function() { ["Set Title", function() {
newTitle = $(".message input.text").val(); newTitle = ($(".message input.text").val()==="") ? "Untitled" : $(".message input.text").val();
if (newTitle==="") newTitle = "Untitled";
if (albumID!==""&&albumID!=null&&albumID&&newTitle.length<31) {
if (visible.album()) { if (visible.album()) {
album.json.title = newTitle; album.json.title = newTitle;
view.album.title(oldTitle); view.album.title();
} else if (visible.albums()) { } else if (visible.albums()) {
albums.json.content[albumID].title = newTitle; albumIDs.forEach(function(id, index, array) {
view.albums.content.title(albumID); albums.json.content[id].title = newTitle;
view.albums.content.title(id);
});
} }
params = "setAlbumTitle&albumID=" + albumID + "&title=" + escape(encodeURI(newTitle)); params = "setAlbumTitle&albumIDs=" + albumIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) { lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data); if (data!==true) lychee.error(null, params, data);
}); });
} else if (newTitle.length>0) loadingBar.show("error", "New title too short or too long. Please try again!");
}], }],
["Cancel", function() {}] ["Cancel", function() {}]
]; ];
modal.show("Set Title", "Please enter a new title for this album: <input class='text' type='text' placeholder='Title' value='" + oldTitle + "'>", buttons);
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) { setDescription: function(photoID) {
var oldDescription = album.json.description, var oldDescription = album.json.description.replace("'", "&apos;"),
description, description,
params, params,
buttons; buttons;
@ -221,8 +250,6 @@ album = {
description = $(".message input.text").val(); description = $(".message input.text").val();
if (description.length<800) {
if (visible.album()) { if (visible.album()) {
album.json.description = description; album.json.description = description;
view.album.description(); view.album.description();
@ -235,12 +262,11 @@ album = {
}); });
} else loadingBar.show("error", "Description too long. Please try again!");
}], }],
["Cancel", function() {}] ["Cancel", function() {}]
]; ];
modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' placeholder='Description' value='" + oldDescription + "'>", buttons);
modal.show("Set Description", "Please enter a description for this album: <input class='text' type='text' maxlength='800' placeholder='Description' value='" + oldDescription + "'>", buttons);
}, },
@ -314,4 +340,4 @@ album = {
} }
} };

View File

@ -31,7 +31,7 @@ albums = {
thumb0: data.unsortedThumb0, thumb0: data.unsortedThumb0,
thumb1: data.unsortedThumb1, thumb1: data.unsortedThumb1,
thumb2: data.unsortedThumb2 thumb2: data.unsortedThumb2
} };
data.starredAlbum = { data.starredAlbum = {
id: "f", id: "f",
@ -41,7 +41,7 @@ albums = {
thumb0: data.starredThumb0, thumb0: data.starredThumb0,
thumb1: data.starredThumb1, thumb1: data.starredThumb1,
thumb2: data.starredThumb2 thumb2: data.starredThumb2
} };
data.publicAlbum = { data.publicAlbum = {
id: "s", id: "s",
@ -51,7 +51,7 @@ albums = {
thumb0: data.publicThumb0, thumb0: data.publicThumb0,
thumb1: data.publicThumb1, thumb1: data.publicThumb1,
thumb2: data.publicThumb2 thumb2: data.publicThumb2
} };
albums.json = data; albums.json = data;
@ -67,7 +67,7 @@ albums = {
}, waitTime); }, waitTime);
}) });
}, },
@ -85,4 +85,4 @@ albums = {
} }
} };

View File

@ -19,6 +19,12 @@ build = {
}, },
multiselect: function(top, left) {
return "<div id='multiselect' style='top: " + top + "px; left: " + left + "px;'></div>";
},
album: function(albumJSON) { album: function(albumJSON) {
if (!albumJSON) return ""; if (!albumJSON) return "";
@ -144,7 +150,7 @@ build = {
modal += "<div class='message center'" + custom_style + ">"; modal += "<div class='message center'" + custom_style + ">";
modal += "<h1>" + title + "</h1>"; modal += "<h1>" + title + "</h1>";
if (closeButton!=false) { if (closeButton!==false) {
modal += "<a class='close icon-remove-sign'></a>"; modal += "<a class='close icon-remove-sign'></a>";
@ -154,7 +160,7 @@ build = {
$.each(button, function(index) { $.each(button, function(index) {
if (this[0]!="") { if (this[0]!=="") {
if (index===0) modal += "<a class='button active'>" + this[0] + "</a>"; if (index===0) modal += "<a class='button active'>" + this[0] + "</a>";
else modal += "<a class='button'>" + this[0] + "</a>"; else modal += "<a class='button'>" + this[0] + "</a>";
@ -235,6 +241,34 @@ build = {
}, },
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) { infoboxPhoto: function(photoJSON, forView) {
if (!photoJSON) return ""; if (!photoJSON) return "";
@ -266,7 +300,6 @@ build = {
editTitleHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_title"); editTitleHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_title");
editDescriptionHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_description"); editDescriptionHTML = (forView===true||lychee.publicMode) ? "" : " " + build.editIcon("edit_description");
//["Tags", "<a class='tag'>Abstract<span class='icon-remove'></span></a><a class='tag'>Colors<span class='icon-remove'></span></a><a class='tag'>Photoshop<span class='icon-remove'></span></a><a class='tag'>Something<span class='icon-remove'></span></a><a class='tag'>Lychee<span class='icon-remove'></span></a><a class='tag'>Tags<span class='icon-remove'></span></a><a class='tag icon-plus'></a>"]
infos = [ infos = [
["", "Basics"], ["", "Basics"],
["Name", photoJSON.title + editTitleHTML], ["Name", photoJSON.title + editTitleHTML],
@ -275,7 +308,8 @@ build = {
["", "Image"], ["", "Image"],
["Size", photoJSON.size], ["Size", photoJSON.size],
["Format", photoJSON.type], ["Format", photoJSON.type],
["Resolution", photoJSON.width + " x " + photoJSON.height] ["Resolution", photoJSON.width + " x " + photoJSON.height],
["Tags", build.tags(photoJSON.tags, forView)]
]; ];
if ((photoJSON.takedate+photoJSON.make+photoJSON.model+photoJSON.shutter+photoJSON.aperture+photoJSON.focal+photoJSON.iso)!="") { if ((photoJSON.takedate+photoJSON.make+photoJSON.model+photoJSON.shutter+photoJSON.aperture+photoJSON.focal+photoJSON.iso)!="") {
@ -300,7 +334,7 @@ build = {
$.each(infos, function(index) { $.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]==undefined||infos[index][1]==null) infos[index][1] = "-"; if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
switch (infos[index][0]) { switch (infos[index][0]) {
@ -311,11 +345,11 @@ build = {
break; break;
case "Tags": // Tags case "Tags": // Tags
if (forView!==true&&!lychee.publicMode) {
infobox += "</table>"; infobox += "</table>";
infobox += "<div class='separator'><h1>" + infos[index][0] + "</h1></div>"; infobox += "<div class='separator'><h1>" + infos[index][0] + "</h1></div>";
infobox += "<tr>";
infobox += "<div id='tags'>" + infos[index][1] + "</div>"; infobox += "<div id='tags'>" + infos[index][1] + "</div>";
infobox += "</tr>"; }
break; break;
default: // Item default: // Item
@ -392,7 +426,7 @@ build = {
$.each(infos, function(index) { $.each(infos, function(index) {
if (infos[index][1]===""||infos[index][1]==undefined||infos[index][1]==null) infos[index][1] = "-"; if (infos[index][1]===""||infos[index][1]===undefined||infos[index][1]===null) infos[index][1] = "-";
if (infos[index][0]==="") { if (infos[index][0]==="") {
@ -419,4 +453,4 @@ build = {
} }
} };

View File

@ -11,18 +11,29 @@ contextMenu = {
show: function(items, mouse_x, mouse_y, orientation) { show: function(items, mouse_x, mouse_y, orientation) {
if (visible.contextMenu()) contextMenu.close(); contextMenu.close();
$("body") $("body")
.css("overflow", "hidden") .css("overflow", "hidden")
.append(build.contextMenu(items)); .append(build.contextMenu(items));
// Do not leave the screen
if ((mouse_x+$(".contextmenu").outerWidth(true))>$("html").width()) orientation = "left"; 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_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 (orientation==="left") mouse_x -= $(".contextmenu").outerWidth(true);
if (!mouse_x||!mouse_y) { if (mouse_x===null||
mouse_x===undefined||
isNaN(mouse_x)||
mouse_y===null||
mouse_y===undefined||
isNaN(mouse_y)) {
mouse_x = "10px"; mouse_x = "10px";
mouse_y = "10px"; mouse_y = "10px";
} }
@ -30,7 +41,7 @@ contextMenu = {
$(".contextmenu").css({ $(".contextmenu").css({
"top": mouse_y, "top": mouse_y,
"left": mouse_x, "left": mouse_x,
"opacity": .98 "opacity": 0.98
}); });
}, },
@ -38,11 +49,9 @@ contextMenu = {
add: function(e) { add: function(e) {
var mouse_x = e.pageX, var mouse_x = e.pageX,
mouse_y = e.pageY, mouse_y = e.pageY - $(document).scrollTop(),
items; items;
mouse_y -= $(document).scrollTop();
upload.notify(); upload.notify();
contextMenu.fns = [ contextMenu.fns = [
@ -70,24 +79,27 @@ contextMenu = {
settings: function(e) { settings: function(e) {
var mouse_x = e.pageX, var mouse_x = e.pageX,
mouse_y = e.pageY, mouse_y = e.pageY - $(document).scrollTop(),
items; items;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [ contextMenu.fns = [
function() { settings.setLogin() }, function() { settings.setLogin() },
function() { settings.setSorting() }, function() { settings.setSorting() },
function() { settings.setDropboxKey() },
function() { window.open(lychee.website, "_newtab"); }, function() { window.open(lychee.website, "_newtab"); },
function() { window.open("plugins/check.php", "_newtab"); },
function() { lychee.logout() } function() { lychee.logout() }
]; ];
items = [ items = [
["<a class='icon-user'></a> Change Login", 0], ["<a class='icon-user'></a> Change Login", 0],
["<a class='icon-sort'></a> Change Sorting", 1], ["<a class='icon-sort'></a> Change Sorting", 1],
["<a class='icon-info-sign'></a> About Lychee", 2], ["<a class='icon-folder-open'></a> Set Dropbox", 2],
["separator", -1], ["separator", -1],
["<a class='icon-signout'></a> Sign Out", 3] ["<a class='icon-info-sign'></a> About Lychee", 3],
["<a class='icon-dashboard'></a> Diagnostics", 4],
["separator", -1],
["<a class='icon-signout'></a> Sign Out", 5]
]; ];
contextMenu.show(items, mouse_x, mouse_y, "right"); contextMenu.show(items, mouse_x, mouse_y, "right");
@ -97,16 +109,14 @@ contextMenu = {
album: function(albumID, e) { album: function(albumID, e) {
var mouse_x = e.pageX, var mouse_x = e.pageX,
mouse_y = e.pageY, mouse_y = e.pageY - $(document).scrollTop(),
items; items;
if (albumID==="0"||albumID==="f"||albumID==="s") return false; if (albumID==="0"||albumID==="f"||albumID==="s") return false;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [ contextMenu.fns = [
function() { album.setTitle(albumID) }, function() { album.setTitle([albumID]) },
function() { album.delete(albumID) } function() { album.delete([albumID]) }
]; ];
items = [ items = [
@ -120,27 +130,49 @@ contextMenu = {
}, },
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) { photo: function(photoID, e) {
var mouse_x = e.pageX, var mouse_x = e.pageX,
mouse_y = e.pageY, mouse_y = e.pageY - $(document).scrollTop(),
items; items;
mouse_y -= $(document).scrollTop();
contextMenu.fns = [ contextMenu.fns = [
function() { photo.setStar(photoID) }, function() { photo.setStar([photoID]) },
function() { photo.setTitle(photoID) }, function() { photo.editTags([photoID]) },
function() { contextMenu.move(photoID, e, "right") }, function() { photo.setTitle([photoID]) },
function() { photo.delete(photoID) } function() { contextMenu.move([photoID], e, "right") },
function() { photo.delete([photoID]) }
]; ];
items = [ items = [
["<a class='icon-star'></a> Star", 0], ["<a class='icon-star'></a> Star", 0],
["<a class='icon-tags'></a> Tags", 1],
["separator", -1], ["separator", -1],
["<a class='icon-edit'></a> Rename", 1], ["<a class='icon-edit'></a> Rename", 2],
["<a class='icon-folder-open'></a> Move", 2], ["<a class='icon-folder-open'></a> Move", 3],
["<a class='icon-trash'></a> Delete", 3] ["<a class='icon-trash'></a> Delete", 4]
]; ];
contextMenu.show(items, mouse_x, mouse_y, "right"); contextMenu.show(items, mouse_x, mouse_y, "right");
@ -149,35 +181,60 @@ contextMenu = {
}, },
move: function(photoID, e, orientation) { photoMulti: function(photoIDs, e) {
var mouse_x = e.pageX, var mouse_x = e.pageX,
mouse_y = e.pageY, mouse_y = e.pageY - $(document).scrollTop(),
items;
multiselect.stopResize();
contextMenu.fns = [
function() { photo.setStar(photoIDs) },
function() { photo.editTags(photoIDs) },
function() { photo.setTitle(photoIDs) },
function() { contextMenu.move(photoIDs, e, "right") },
function() { photo.delete(photoIDs) }
];
items = [
["<a class='icon-star'></a> Star All", 0],
["<a class='icon-tags'></a> Tag All", 1],
["separator", -1],
["<a class='icon-edit'></a> Rename All", 2],
["<a class='icon-folder-open'></a> Move All", 3],
["<a class='icon-trash'></a> Delete All", 4]
];
contextMenu.show(items, mouse_x, mouse_y, "right");
},
move: function(photoIDs, e, orientation) {
var mouse_x = e.pageX,
mouse_y = e.pageY - $(document).scrollTop(),
items = []; items = [];
contextMenu.fns = []; contextMenu.close(true);
if (album.getID()!=="0") { if (album.getID()!=="0") {
items = [ items = [
["Unsorted", 0, "photo.setAlbum(0, " + photoID + ")"], ["Unsorted", 0, "photo.setAlbum([" + photoIDs + "], 0)"],
["separator", -1] ["separator", -1]
]; ];
} }
lychee.api("getAlbums", function(data) { lychee.api("getAlbums", function(data) {
if (!data.albums) { if (data.num===0) {
items = [["New Album", 0, "album.add()"]]; items = [["New Album", 0, "album.add()"]];
} else { } else {
$.each(data.content, function(index) { $.each(data.content, function(index) {
if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum(" + this.id + ", " + photoID + ")"]); if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum([" + photoIDs + "], " + this.id + ")"]);
}); });
} }
contextMenu.close();
$(".photo[data-id='" + photoID + "']").addClass("active");
if (!visible.photo()) contextMenu.show(items, mouse_x, mouse_y, "right"); if (!visible.photo()) contextMenu.show(items, mouse_x, mouse_y, "right");
else contextMenu.show(items, mouse_x, mouse_y, "left"); else contextMenu.show(items, mouse_x, mouse_y, "left");
@ -218,7 +275,7 @@ contextMenu = {
]; ];
contextMenu.show(items, mouse_x, mouse_y, "left"); contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus(); $(".contextmenu input").focus().select();
}, },
@ -253,18 +310,24 @@ contextMenu = {
if (album.json.password==true) items[3] = ["<a class='icon-unlock'></a> Remove Password", 5]; if (album.json.password==true) items[3] = ["<a class='icon-unlock'></a> Remove Password", 5];
contextMenu.show(items, mouse_x, mouse_y, "left"); contextMenu.show(items, mouse_x, mouse_y, "left");
$(".contextmenu input").focus(); $(".contextmenu input").focus().select();
}, },
close: function() { close: function(leaveSelection) {
contextMenu.js = null; if (!visible.contextMenu()) return false;
contextMenu.fns = [];
$(".contextmenu_bg, .contextmenu").remove(); $(".contextmenu_bg, .contextmenu").remove();
$(".photo.active, .album.active").removeClass("active");
$("body").css("overflow", "auto"); $("body").css("overflow", "auto");
if (leaveSelection!==true) {
$(".photo.active, .album.active").removeClass("active");
if (visible.multiselect()) multiselect.close();
} }
} }
};

View File

@ -15,6 +15,10 @@ $(document).ready(function(){
/* Tooltips */ /* Tooltips */
if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1}); if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n', fade: false, delayIn: 0, opacity: 1});
/* Multiselect */
$("#content").on("mousedown", multiselect.show);
$(document).on("mouseup", multiselect.getSelection);
/* Header */ /* Header */
$("#hostedwith").on(event_name, function() { window.open(lychee.website,"_newtab") }); $("#hostedwith").on(event_name, function() { window.open(lychee.website,"_newtab") });
$("#button_signin").on(event_name, lychee.loginDialog); $("#button_signin").on(event_name, lychee.loginDialog);
@ -28,13 +32,13 @@ $(document).ready(function(){
else modal.show("Share Album", "All photos inside this album will be public and visible for everyone. Existing public photos will have the same sharing permission as this album. Are your sure you want to share this album? <input class='text' type='password' placeholder='password (optional)' value=''>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]); else modal.show("Share Album", "All photos inside this album will be public and visible for everyone. Existing public photos will have the same sharing permission as this album. Are your sure you want to share this album? <input class='text' type='password' placeholder='password (optional)' value=''>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]);
}); });
$("#button_download").on(event_name, function() { photo.getArchive(photo.getID()) }); $("#button_download").on(event_name, function() { photo.getArchive(photo.getID()) });
$("#button_trash_album").on(event_name, function() { album.delete(album.getID()) }); $("#button_trash_album").on(event_name, function() { album.delete([album.getID()]) });
$("#button_move").on(event_name, function(e) { contextMenu.move(photo.getID(), e) }); $("#button_move").on(event_name, function(e) { contextMenu.move([photo.getID()], e) });
$("#button_trash").on(event_name, function() { photo.delete(photo.getID()) }); $("#button_trash").on(event_name, function() { photo.delete([photo.getID()]) });
$("#button_info_album").on(event_name, function() { view.infobox.show() }); $("#button_info_album").on(event_name, function() { view.infobox.show() });
$("#button_info").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_archive").on(event_name, function() { album.getArchive(album.getID()) });
$("#button_star").on(event_name, function() { photo.setStar(photo.getID()) }); $("#button_star").on(event_name, function() { photo.setStar([photo.getID()]) });
/* Search */ /* Search */
$("#search").on("keyup click", function() { search.find($(this).val()) }); $("#search").on("keyup click", function() { search.find($(this).val()) });
@ -61,16 +65,18 @@ $(document).ready(function(){
/* Infobox */ /* Infobox */
$("#infobox") $("#infobox")
.on(event_name, ".header a", function() { view.infobox.hide() }) .on(event_name, ".header a", function() { view.infobox.hide() })
.on(event_name, "#edit_title_album", function() { album.setTitle(album.getID()) }) .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_description_album", function() { album.setDescription(album.getID()) })
.on(event_name, "#edit_title", function() { photo.setTitle(photo.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_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 */ /* Keyboard */
Mousetrap Mousetrap
.bind('u', function() { $("#upload_files").click() }) .bind('u', function() { $("#upload_files").click() })
.bind('s', function() { if (visible.photo()) $("#button_star").click() }) .bind('s', function() { if (visible.photo()) $("#button_star").click() })
.bind('command+backspace', function() { if (visible.photo()&&!visible.message()) photo.delete(photo.getID()) }) .bind('command+backspace', function() { if (visible.photo()&&!visible.message()) photo.delete([photo.getID()]) })
.bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() }) .bind('left', function() { if (visible.photo()) $("#imageview a#previous").click() })
.bind('right', function() { if (visible.photo()) $("#imageview a#next").click() }) .bind('right', function() { if (visible.photo()) $("#imageview a#next").click() })
.bind('i', function() { .bind('i', function() {
@ -100,8 +106,8 @@ $(document).ready(function(){
/* Header */ /* Header */
.on(event_name, "#title.editable", function() { .on(event_name, "#title.editable", function() {
if (visible.photo()) photo.setTitle(photo.getID()); if (visible.photo()) photo.setTitle([photo.getID()]);
else album.setTitle(album.getID()); else album.setTitle([album.getID()]);
}) })
/* Navigation */ /* Navigation */
@ -110,8 +116,8 @@ $(document).ready(function(){
/* Modal */ /* Modal */
.on(event_name, ".message .close", modal.close) .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: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() }) .on(event_name, ".message .button:last", function() { if (modal.fns!==null) modal.fns[1](); if (!visible.signin()) modal.close() })
/* Add Dialog */ /* Add Dialog */
.on(event_name, ".button_add", function(e) { contextMenu.add(e) }) .on(event_name, ".button_add", function(e) { contextMenu.add(e) })

View File

@ -15,7 +15,7 @@ loadingBar = {
loadingBar.status = "error"; loadingBar.status = "error";
if (!errorText) errorText = "Whoops, it looks like something went wrong. Please reload the site and try again!" if (!errorText) errorText = "Whoops, it looks like something went wrong. Please reload the site and try again!";
lychee.loadingBar lychee.loadingBar
.removeClass("loading uploading error") .removeClass("loading uploading error")
@ -28,7 +28,7 @@ loadingBar = {
clearTimeout(lychee.loadingBar.data("timeout")); clearTimeout(lychee.loadingBar.data("timeout"));
lychee.loadingBar.data("timeout", setTimeout(function() { loadingBar.hide(true) }, 3000)); lychee.loadingBar.data("timeout", setTimeout(function() { loadingBar.hide(true) }, 3000));
} else if (loadingBar.status==null) { } else if (loadingBar.status===null) {
loadingBar.status = "loading"; loadingBar.status = "loading";
@ -47,7 +47,7 @@ loadingBar = {
hide: function(force_hide) { hide: function(force_hide) {
if ((loadingBar.status!=="error"&&loadingBar.status!=null)||force_hide) { if ((loadingBar.status!=="error"&&loadingBar.status!==null)||force_hide) {
loadingBar.status = null; loadingBar.status = null;
clearTimeout(lychee.loadingBar.data("timeout")); clearTimeout(lychee.loadingBar.data("timeout"));
@ -59,4 +59,4 @@ loadingBar = {
} }
} };

View File

@ -7,7 +7,7 @@
var lychee = { var lychee = {
version: "2.0.3", version: "2.1",
api_path: "php/api.php", api_path: "php/api.php",
update_path: "http://lychee.electerious.com/version/index.php", update_path: "http://lychee.electerious.com/version/index.php",
@ -26,6 +26,7 @@ var lychee = {
sorting: "", sorting: "",
dropbox: false, dropbox: false,
dropboxKey: '',
loadingBar: $("#loading"), loadingBar: $("#loading"),
header: $("header"), header: $("header"),
@ -35,13 +36,17 @@ var lychee = {
init: function() { init: function() {
lychee.api("init", function(data) { var params;
params = "init&version=" + escape(lychee.version);
lychee.api(params, function(data) {
if (data.loggedIn!==true) { if (data.loggedIn!==true) {
lychee.setMode("public"); lychee.setMode("public");
} else { } else {
lychee.username = data.config.username; lychee.username = data.config.username || '';
lychee.sorting = data.config.sorting; lychee.sorting = data.config.sorting || '';
lychee.dropboxKey = data.config.dropboxKey || '';
} }
// No configuration // No configuration
@ -68,7 +73,7 @@ var lychee = {
api: function(params, callback, loading) { api: function(params, callback, loading) {
if (loading==undefined) loadingBar.show(); if (loading===undefined) loadingBar.show();
$.ajax({ $.ajax({
type: "POST", type: "POST",
@ -115,7 +120,7 @@ var lychee = {
localStorage.setItem("username", user); localStorage.setItem("username", user);
window.location.reload(); window.location.reload();
} else { } else {
$("#password").val("").addClass("error"); $("#password").val("").addClass("error").focus();
$(".message .button.active").removeClass("pressed"); $(".message .button.active").removeClass("pressed");
} }
}); });
@ -130,7 +135,7 @@ var lychee = {
$("#username").focus(); $("#username").focus();
if (localStorage) { if (localStorage) {
local_username = localStorage.getItem("username"); local_username = localStorage.getItem("username");
if (local_username!=null) { if (local_username!==null) {
if (local_username.length>0) $("#username").val(local_username); if (local_username.length>0) $("#username").val(local_username);
$("#password").focus(); $("#password").focus();
} }
@ -149,7 +154,7 @@ var lychee = {
goto: function(url) { goto: function(url) {
if (url==undefined) url = ""; if (url===undefined) url = "";
document.location.hash = url; document.location.hash = url;
}, },
@ -161,6 +166,7 @@ var lychee = {
hash = document.location.hash.replace("#", "").split("/"); hash = document.location.hash.replace("#", "").split("/");
contextMenu.close(); contextMenu.close();
multiselect.close();
if (hash[0]!==undefined) albumID = hash[0]; if (hash[0]!==undefined) albumID = hash[0];
if (hash[1]!==undefined) photoID = hash[1]; if (hash[1]!==undefined) photoID = hash[1];
@ -255,6 +261,7 @@ var lychee = {
Mousetrap.unbind('esc'); Mousetrap.unbind('esc');
$("#button_back, a#next, a#previous").remove(); $("#button_back, a#next, a#previous").remove();
$(".no_content").remove();
lychee.publicMode = true; lychee.publicMode = true;
lychee.viewMode = true; lychee.viewMode = true;
@ -287,7 +294,7 @@ var lychee = {
loadDropbox: function(callback) { loadDropbox: function(callback) {
if (!lychee.dropbox) { if (!lychee.dropbox&&lychee.dropboxKey) {
loadingBar.show(); loadingBar.show();
@ -298,7 +305,7 @@ var lychee = {
g.id = "dropboxjs"; g.id = "dropboxjs";
g.type = "text/javascript"; g.type = "text/javascript";
g.async = "true"; g.async = "true";
g.setAttribute("data-app-key", "iq7lioj9wu0ieqs"); g.setAttribute("data-app-key", lychee.dropboxKey);
g.onload = g.onreadystatechange = function() { g.onload = g.onreadystatechange = function() {
var rs = this.readyState; var rs = this.readyState;
if (rs&&rs!=="complete"&&rs!=="loaded") return; if (rs&&rs!=="complete"&&rs!=="loaded") return;
@ -308,7 +315,15 @@ var lychee = {
}; };
s.parentNode.insertBefore(g, s); s.parentNode.insertBefore(g, s);
} else callback(); } else if (lychee.dropbox&&lychee.dropboxKey) {
callback();
} else {
settings.setDropboxKey(callback);
}
}, },
@ -321,4 +336,4 @@ var lychee = {
} }
} };

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@ modal = {
show: function(title, text, buttons, marginTop, closeButton) { show: function(title, text, buttons, marginTop, closeButton) {
if (!buttons) { if (!buttons) {
var buttons = [ buttons = [
["", function() {}], ["", function() {}],
["", function() {}] ["", function() {}]
]; ];
@ -20,7 +20,7 @@ modal = {
modal.fns = [buttons[0][1], buttons[1][1]]; modal.fns = [buttons[0][1], buttons[1][1]];
$("body").append(build.modal(title, text, buttons, marginTop, closeButton)); $("body").append(build.modal(title, text, buttons, marginTop, closeButton));
$(".message input:first-child").focus(); $(".message input:first-child").focus().select();
}, },
@ -32,4 +32,4 @@ modal = {
} }
} };

View File

@ -1,339 +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,
getID: function() {
var id;
if (photo.json) id = photo.json.id;
else id = $(".photo:hover, .photo.active").attr("data-id");
if (id) return id;
else return false;
},
load: function(photoID, albumID) {
var params,
checkPasswd;
params = "getPhoto&photoID=" + photoID + "&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Wrong password!") {
checkPasswd = function() {
if (password.value!=="") photo.load(photoID, albumID);
else setTimeout(checkPasswd, 250);
}
checkPasswd();
return false;
}
photo.json = data;
if (!visible.photo()) view.photo.show();
view.photo.init();
lychee.imageview.show();
setTimeout(function() { lychee.content.show() }, 300);
});
},
parse: function() {
if (!photo.json.title) photo.json.title = "Untitled";
photo.json.url = lychee.upload_path_big + photo.json.url;
},
delete: function(photoID) {
var params,
buttons,
photoTitle;
if (!photoID) return false;
if (visible.photo()) photoTitle = photo.json.title;
else photoTitle = album.json.content[photoID].title;
if (photoTitle=="") photoTitle = "Untitled";
buttons = [
["Delete Photo", function() {
// Change reference for the next and previous photo
if (album.json.content[photoID].nextPhoto!==""||album.json.content[photoID].previousPhoto!=="") {
nextPhoto = album.json.content[photoID].nextPhoto;
previousPhoto = album.json.content[photoID].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[photoID] = null;
view.album.content.delete(photoID);
// Only when search is not active
if (!visible.albums()) lychee.goto(album.getID());
params = "deletePhoto&photoID=" + photoID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Keep Photo", function() {}]
];
modal.show("Delete Photo", "Are you sure you want to delete the photo '" + photoTitle + "'?<br>This action can't be undone!", buttons);
},
setTitle: function(photoID) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!photoID) return false;
if (photo.json) oldTitle = photo.json.title;
else if (album.json) oldTitle = album.json.content[photoID].title;
buttons = [
["Set Title", function() {
newTitle = $(".message input.text").val();
if (photoID!=null&&photoID&&newTitle.length<31) {
if (visible.photo()) {
photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
view.photo.title(oldTitle);
}
album.json.content[photoID].title = newTitle;
view.album.content.title(photoID);
params = "setPhotoTitle&photoID=" + photoID + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
} else if (newTitle.length>0) loadingBar.show("error", "New title to short or too long. Please try another one!");
}],
["Cancel", function() {}]
];
modal.show("Set Title", "Please enter a new title for this photo: <input class='text' type='text' placeholder='Title' value='" + oldTitle + "'>", buttons);
},
setAlbum: function(albumID, photoID) {
var params;
if (albumID>=0) {
// Change reference for the next and previous photo
if (album.json.content[photoID].nextPhoto!==""||album.json.content[photoID].previousPhoto!=="") {
nextPhoto = album.json.content[photoID].nextPhoto;
previousPhoto = album.json.content[photoID].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
if (visible.photo) lychee.goto(album.getID());
album.json.content[photoID] = null;
view.album.content.delete(photoID);
params = "setAlbum&photoID=" + photoID + "&albumID=" + albumID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}
},
setStar: function(photoID) {
var params;
if (visible.photo()) {
photo.json.star = (photo.json.star==0) ? 1 : 0;
view.photo.star();
}
album.json.content[photoID].star = (album.json.content[photoID].star==0) ? 1 : 0;
view.album.content.star(photoID);
params = "setPhotoStar&photoID=" + photoID;
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);
params = "setPhotoPublic&photoID=" + photoID + "&url=" + photo.getViewLink(photoID);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setDescription: function(photoID) {
var oldDescription = photo.json.description,
description,
params,
buttons;
buttons = [
["Set Description", function() {
description = $(".message input.text").val();
if (description.length<800) {
if (visible.photo()) {
photo.json.description = description;
view.photo.description();
}
params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
} else loadingBar.show("error", "Description too long. Please try again!");
}],
["Cancel", function() {}]
];
modal.show("Set Description", "Please enter a description for this photo: <input class='text' type='text' placeholder='Description' value='" + oldDescription + "'>", buttons);
},
share: function(photoID, service) {
var link = "",
url = photo.getViewLink(photoID),
filename = "unknown";
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(photo.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(photo.json.title) + "&body=" + encodeURI(url);
break;
case 3:
lychee.loadDropbox(function() {
filename = photo.json.title + "." + photo.getDirectLink().split('.').pop();
Dropbox.save(photo.getDirectLink(), filename);
});
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
isSmall: function() {
var size = [
["width", false],
["height", false]
];
if (photo.json.width<$(window).width()-60) size["width"] = true;
if (photo.json.height<$(window).height()-100) size["height"] = true;
if (size["width"]&&size["height"]) return true;
else return false;
},
getArchive: function(photoID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getPhotoArchive&photoID=" + photoID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getPhotoArchive&photoID=" + photoID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
},
getDirectLink: function() {
return $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
},
getViewLink: function(photoID) {
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, "view.php?p=" + photoID);
else return location.href.replace(location.hash, "view.php?p=" + photoID);
}
}

View File

@ -1,468 +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() {
clearTimeout($(window).data("timeout"));
if (visible.photo()) {
lychee.imageview.removeClass("full");
lychee.loadingBar.css("opacity", 1);
lychee.header.removeClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)+20
});
} else {
$("#imageview #image").css({
top: 60,
right: 30,
bottom: 30,
left: 30
});
}
}
},
hide: function() {
if (visible.photo()&&!visible.infobox()&&!visible.contextMenu()&&!visible.message()) {
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
lychee.imageview.addClass("full");
lychee.loadingBar.css("opacity", 0);
lychee.header.addClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)
});
} else {
$("#imageview #image").css({
top: 0,
right: 0,
bottom: 0,
left: 0
});
}
}, 500));
}
},
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 (albumID==="s"||albumID==="f") {
$("#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: {
init: function() {
var smartData = "",
albumsData = "";
/* Smart Albums */
albums.parse(albums.json.unsortedAlbum);
albums.parse(albums.json.publicAlbum);
albums.parse(albums.json.starredAlbum);
if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum);
/* Albums */
if (albums.json.content) {
if (!lychee.publicMode) albumsData = build.divider("Albums");
$.each(albums.json.content, function() {
albums.parse(this);
albumsData += build.album(this);
});
}
if (smartData===""&&albumsData==="") $("body").append(build.no_content("picture"));
else lychee.content.html(smartData + albumsData);
$("img[data-type!='svg']").retina();
},
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.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(oldTitle) {
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 "0":
lychee.setTitle("Unsorted", false);
break;
default:
if (album.json.init) $("#infobox .attr_name").html(album.json.title + " " + build.editIcon("edit_title_album"));
lychee.setTitle(album.json.title, true);
break;
}
}
},
description: function() {
$("#infobox .attr_description").html(album.json.description + " " + build.editIcon("edit_description_album"));
},
content: {
init: function() {
var photosData = "";
$.each(album.json.content, function() {
album.parse(this);
photosData += build.photo(this);
});
lychee.content.html(photosData);
$("img[data-type!='svg']").retina();
},
title: function(photoID) {
var longTitle = "",
title = album.json.content[photoID].title;
if (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();
}
});
}
},
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() {
if (!visible.controls()) 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(oldTitle) {
if (photo.json.init) $("#infobox .attr_name").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");
}
},
photo: function() {
lychee.imageview.html(build.imageview(photo.json, photo.isSmall(), visible.controls()));
if ((album.json&&album.json.content[photo.getID()]&&album.json.content[photo.getID()].nextPhoto==="")||lychee.viewMode) $("a#next").hide();
if ((album.json&&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();
}
}
}

View File

@ -1,50 +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;
},
infobox: function() {
if ($("#infobox.active").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;
}
}

171
assets/js/multiselect.js Normal file
View File

@ -0,0 +1,171 @@
/**
* @name Multiselect Module
* @description Select multiple albums or photos.
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
multiselect = {
position: {
top: null,
right: null,
bottom: null,
left: null
},
show: function(e) {
if (mobileBrowser()) return false;
if (lychee.publicMode) return false;
if (visible.search()) return false;
if ($('.album:hover, .photo:hover').length!==0) return false;
if (visible.multiselect()) $('#multiselect').remove();
multiselect.position.top = e.pageY;
multiselect.position.right = -1 * (e.pageX - $(document).width());
multiselect.position.bottom = -1 * (multiselect.position.top - $(window).height());
multiselect.position.left = e.pageX;
$('body').append(build.multiselect(multiselect.position.top, multiselect.position.left));
$(document).on('mousemove', multiselect.resize);
},
resize: function(e) {
var mouse_x = e.pageX,
mouse_y = e.pageY,
newHeight,
newWidth;
if (multiselect.position.top===null||
multiselect.position.right===null||
multiselect.position.bottom===null||
multiselect.position.left===null) return false;
if (mouse_y>=multiselect.position.top) {
// Do not leave the screen
newHeight = e.pageY - multiselect.position.top;
if ((multiselect.position.top+newHeight)>=$(document).height())
newHeight -= (multiselect.position.top + newHeight) - $(document).height() + 2;
$('#multiselect').css({
top: multiselect.position.top,
bottom: 'inherit',
height: newHeight
});
} else {
$('#multiselect').css({
top: 'inherit',
bottom: multiselect.position.bottom,
height: multiselect.position.top - e.pageY
});
}
if (mouse_x>=multiselect.position.left) {
// Do not leave the screen
newWidth = e.pageX - multiselect.position.left;
if ((multiselect.position.left+newWidth)>=$(document).width())
newWidth -= (multiselect.position.left + newWidth) - $(document).width() + 2;
$('#multiselect').css({
right: 'inherit',
left: multiselect.position.left,
width: newWidth
});
} else {
$('#multiselect').css({
right: multiselect.position.right,
left: 'inherit',
width: multiselect.position.left - e.pageX
});
}
},
stopResize: function() {
$(document).off('mousemove');
},
getSize: function() {
if (!visible.multiselect()) return false;
return {
top: $('#multiselect').offset().top,
left: $('#multiselect').offset().left,
width: parseInt($('#multiselect').css('width').replace('px', '')),
height: parseInt($('#multiselect').css('height').replace('px', ''))
};
},
getSelection: function(e) {
var tolerance = 150,
id,
ids = [],
offset,
size = multiselect.getSize();
if (visible.contextMenu()) return false;
if (!visible.multiselect()) return false;
$('.photo, .album').each(function() {
offset = $(this).offset();
if (offset.top>=(size.top-tolerance)&&
offset.left>=(size.left-tolerance)&&
(offset.top+206)<=(size.top+size.height+tolerance)&&
(offset.left+206)<=(size.left+size.width+tolerance)) {
id = $(this).data('id');
if (id!=='0'&&id!==0&&id!=='f'&&id!=='s'&&id!==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);
}
};

View File

@ -105,4 +105,4 @@ password = {
} }
} };

454
assets/js/photo.js Normal file
View File

@ -0,0 +1,454 @@
/**
* @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,
getID: function() {
var id;
if (photo.json) id = photo.json.id;
else id = $(".photo:hover, .photo.active").attr("data-id");
if (id) return id;
else return false;
},
load: function(photoID, albumID) {
var params,
checkPasswd;
params = "getPhoto&photoID=" + photoID + "&albumID=" + albumID + "&password=" + password.value;
lychee.api(params, function(data) {
if (data==="Warning: Wrong password!") {
checkPasswd = function() {
if (password.value!=="") photo.load(photoID, albumID);
else setTimeout(checkPasswd, 250);
};
checkPasswd();
return false;
}
photo.json = data;
if (!visible.photo()) view.photo.show();
view.photo.init();
lychee.imageview.show();
setTimeout(function() { lychee.content.show() }, 300);
});
},
parse: function() {
if (!photo.json.title) photo.json.title = "Untitled";
photo.json.url = lychee.upload_path_big + photo.json.url;
},
delete: function(photoIDs) {
var params,
buttons,
photoTitle;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get title if only one photo is selected
if (visible.photo()) photoTitle = photo.json.title;
else photoTitle = album.json.content[photoIDs].title;
if (photoTitle==="") photoTitle = "Untitled";
}
buttons = [
["", function() {
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
// Only when search is not active
if (!visible.albums()) lychee.goto(album.getID());
params = "deletePhoto&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["", function() {}]
];
if (photoIDs.length===1) {
buttons[0][0] = "Delete Photo";
buttons[1][0] = "Keep Photo";
modal.show("Delete Photo", "Are you sure you want to delete the photo '" + photoTitle + "'?<br>This action can't be undone!", buttons);
} else {
buttons[0][0] = "Delete Photos";
buttons[1][0] = "Keep Photos";
modal.show("Delete Photos", "Are you sure you want to delete all " + photoIDs.length + " selected photo?<br>This action can't be undone!", buttons);
}
},
setTitle: function(photoIDs) {
var oldTitle = "",
newTitle,
params,
buttons;
if (!photoIDs) return false;
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
if (photoIDs.length===1) {
// Get old title if only one photo is selected
if (photo.json) oldTitle = photo.json.title;
else if (album.json) oldTitle = album.json.content[photoIDs].title;
oldTitle = oldTitle.replace("'", "&apos;");
}
buttons = [
["Set Title", function() {
newTitle = $(".message input.text").val();
if (visible.photo()) {
photo.json.title = (newTitle==="") ? "Untitled" : newTitle;
view.photo.title();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].title = newTitle;
view.album.content.title(id);
});
params = "setPhotoTitle&photoIDs=" + photoIDs + "&title=" + escape(encodeURI(newTitle));
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
}],
["Cancel", function() {}]
];
if (photoIDs.length===1) modal.show("Set Title", "Enter a new title for this photo: <input class='text' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>", buttons);
else modal.show("Set Titles", "Enter a title for all " + photoIDs.length + " selected photos: <input class='text' type='text' maxlength='30' placeholder='Title' value=''>", buttons);
},
setAlbum: function(photoIDs, albumID) {
var params,
nextPhoto,
previousPhoto;
if (!photoIDs) return false;
if (visible.photo) lychee.goto(album.getID());
if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
photoIDs.forEach(function(id, index, array) {
// Change reference for the next and previous photo
if (album.json.content[id].nextPhoto!==""||album.json.content[id].previousPhoto!=="") {
nextPhoto = album.json.content[id].nextPhoto;
previousPhoto = album.json.content[id].previousPhoto;
album.json.content[previousPhoto].nextPhoto = nextPhoto;
album.json.content[nextPhoto].previousPhoto = previousPhoto;
}
album.json.content[id] = null;
view.album.content.delete(id);
});
params = "setPhotoAlbum&photoIDs=" + photoIDs + "&albumID=" + albumID;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setStar: function(photoIDs) {
var params;
if (!photoIDs) return false;
if (visible.photo()) {
photo.json.star = (photo.json.star==0) ? 1 : 0;
view.photo.star();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].star = (album.json.content[id].star==0) ? 1 : 0;
view.album.content.star(id);
});
params = "setPhotoStar&photoIDs=" + photoIDs;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
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);
params = "setPhotoPublic&photoID=" + photoID + "&url=" + photo.getViewLink(photoID);
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
setDescription: function(photoID) {
var oldDescription = photo.json.description.replace("'", "&apos;"),
description,
params,
buttons;
buttons = [
["Set Description", function() {
description = $(".message input.text").val();
if (visible.photo()) {
photo.json.description = description;
view.photo.description();
}
params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(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 = "";
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(/,$|^,/g, '');
if (visible.photo()) {
photo.json.tags = tags;
view.photo.tags();
}
photoIDs.forEach(function(id, index, array) {
album.json.content[id].tags = tags;
});
params = "setPhotoTags&photoIDs=" + photoIDs + "&tags=" + tags;
lychee.api(params, function(data) {
if (data!==true) lychee.error(null, params, data);
});
},
deleteTag: function(photoID, index) {
var tags;
// Remove
tags = photo.json.tags.split(',');
tags.splice(index, 1);
// Save
photo.json.tags = tags.toString();
photo.setTags([photoID], photo.json.tags);
},
share: function(photoID, service) {
var link = "",
url = photo.getViewLink(photoID),
filename = "unknown";
switch (service) {
case 0:
link = "https://twitter.com/share?url=" + encodeURI(url);
break;
case 1:
link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(photo.json.title);
break;
case 2:
link = "mailto:?subject=" + encodeURI(photo.json.title) + "&body=" + encodeURI(url);
break;
case 3:
lychee.loadDropbox(function() {
filename = photo.json.title + "." + photo.getDirectLink().split('.').pop();
Dropbox.save(photo.getDirectLink(), filename);
});
break;
default:
link = "";
break;
}
if (link.length>5) location.href = link;
},
isSmall: function() {
var size = {
width: false,
height: false
};
if (photo.json.width<$(window).width()-60) size.width = true;
if (photo.json.height<$(window).height()-100) size.height = true;
if (size.width&&size.height) return true;
else return false;
},
getArchive: function(photoID) {
var link;
if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getPhotoArchive&photoID=" + photoID);
else link = location.href.replace(location.hash, "") + "php/api.php?function=getPhotoArchive&photoID=" + photoID;
if (lychee.publicMode) link += "&password=" + password.value;
location.href = link;
},
getDirectLink: function() {
return $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
},
getViewLink: function(photoID) {
if (location.href.indexOf("index.html")>0) return location.href.replace("index.html" + location.hash, "view.php?p=" + photoID);
else return location.href.replace(location.hash, "view.php?p=" + photoID);
}
};

View File

@ -90,4 +90,4 @@ search = {
} }
} };

View File

@ -26,7 +26,7 @@ var settings = {
if (dbHost.length<1) dbHost = "localhost"; if (dbHost.length<1) dbHost = "localhost";
if (dbName.length<1) dbName = "lychee"; if (dbName.length<1) dbName = "lychee";
params = "createConfig&dbName=" + escape(dbName) + "&dbUser=" + escape(dbUser) + "&dbPassword=" + escape(dbPassword) + "&dbHost=" + escape(dbHost); params = "dbCreateConfig&dbName=" + escape(dbName) + "&dbUser=" + escape(dbUser) + "&dbPassword=" + escape(dbPassword) + "&dbHost=" + escape(dbHost) + "&version=" + escape(lychee.version);
lychee.api(params, function(data) { lychee.api(params, function(data) {
if (data!==true) { if (data!==true) {
@ -53,7 +53,7 @@ var settings = {
["Retry", function() { setTimeout(settings.createConfig, 400) }], ["Retry", function() { setTimeout(settings.createConfig, 400) }],
["", function() {}] ["", function() {}]
]; ];
modal.show("Saving Failed", "Unable to save this configuration. Permission denied in <b>'php/'</b>. Please set the read, write and execute rights for others in <b>'php/'</b> and <b>'uploads/'</b>. Take a look the readme for more information.", buttons, null, false); 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; return false;
} }
@ -71,7 +71,7 @@ var settings = {
} else { } else {
// Configuration successful // Configuration successful
lychee.api("update", function(data) { window.location.reload() }); window.location.reload();
} }
@ -80,6 +80,7 @@ var settings = {
}], }],
["", function() {}] ["", function() {}]
]; ];
modal.show("Configuration", "Enter your database connection details below: <input id='dbHost' class='text less' type='text' placeholder='Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Password' value=''><br>Lychee will create its own database. If required, you can enter the name of an existing database instead:<input id='dbName' class='text more' type='text' placeholder='Database (optional)' value=''>", buttons, -215, false); modal.show("Configuration", "Enter your database connection details below: <input id='dbHost' class='text less' type='text' placeholder='Host (optional)' value=''><input id='dbUser' class='text less' type='text' placeholder='Username' value=''><input id='dbPassword' class='text more' type='password' placeholder='Password' value=''><br>Lychee will create its own database. If required, you can enter the name of an existing database instead:<input id='dbName' class='text more' type='text' placeholder='Database (optional)' value=''>", buttons, -215, false);
}, },
@ -137,6 +138,7 @@ var settings = {
}], }],
["", function() {}] ["", 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); 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);
}, },
@ -181,6 +183,7 @@ var settings = {
}], }],
["Cancel", function() {}] ["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); 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);
}, },
@ -227,12 +230,41 @@ var settings = {
order.\ order.\
", buttons); ", buttons);
if (lychee.sorting!="") { if (lychee.sorting!=="") {
sorting = lychee.sorting.replace("ORDER BY ", "").replace(" ", ";").split(";"); sorting = lychee.sorting.replace("ORDER BY ", "").replace(" ", ";").split(";");
$("select#settings_type").val(sorting[0]); $("select#settings_type").val(sorting[0]);
$("select#settings_order").val(sorting[1]); $("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);
} }
};

View File

@ -42,9 +42,9 @@ upload = {
if (!window.webkitNotifications) return false; if (!window.webkitNotifications) return false;
if (window.webkitNotifications.checkPermission()!=0) window.webkitNotifications.requestPermission(); if (window.webkitNotifications.checkPermission()!==0) window.webkitNotifications.requestPermission();
if (window.webkitNotifications.checkPermission()==0&&title) { if (window.webkitNotifications.checkPermission()===0&&title) {
popup = window.webkitNotifications.createNotification("", title, "You can now manage your new photo(s)."); popup = window.webkitNotifications.createNotification("", title, "You can now manage your new photo(s).");
popup.show(); popup.show();
} }
@ -170,6 +170,7 @@ upload = {
}], }],
["Cancel", function() {}] ["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); 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);
}, },
@ -194,10 +195,15 @@ upload = {
upload.close(); upload.close();
upload.notify("Import complete"); upload.notify("Import complete");
if (album.getID()===false) lychee.goto("0"); 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); else album.load(albumID);
if (data==="Warning: Folder empty!") lychee.error("Folder empty. No photos imported!", params, data); 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); else if (data!==true) lychee.error(null, params, data);
}); });
@ -205,7 +211,8 @@ upload = {
}], }],
["Cancel", function() {}] ["Cancel", function() {}]
]; ];
modal.show("Import from Server", "This action will import all photos which are located in <b>'uploads/import/'</b> of your Lychee installation.", buttons);
modal.show("Import from Server", "This action will import all photos and albums which are located in <b>'uploads/import/'</b> of your Lychee installation.", buttons);
}, },
@ -263,4 +270,4 @@ upload = {
} }
} };

View File

@ -1,112 +1,474 @@
/** /**
* @name View * @name UI View
* @description Used to view single photos with view.php * @description Responsible to reflect data changes to the UI.
* @author Tobias Reich * @author Tobias Reich
* @copyright 2014 by Tobias Reich * @copyright 2014 by Tobias Reich
*/ */
var header = $("header"), view = {
headerTitle = $("#title"),
imageview = $("#imageview"),
api_path = "php/api.php",
infobox = $("#infobox");
$(document).ready(function(){ header: {
/* Event Name */ show: function() {
if (mobileBrowser()) event_name = "touchend";
else event_name = "click";
/* Window */ clearTimeout($(window).data("timeout"));
$(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");
if (visible.photo()) {
lychee.imageview.removeClass("full");
lychee.loadingBar.css("opacity", 1);
lychee.header.removeClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)+20
}); });
} else {
loadPhotoInfo(gup("p")); $("#imageview #image").css({
top: 60,
right: 30,
bottom: 30,
left: 30
}); });
}
}
function key(e) { },
code = (e.keyCode ? e.keyCode : e.which); hide: function() {
if (code===27&&visibleInfobox()) { hideInfobox(); e.preventDefault(); }
if (visible.photo()&&!visible.infobox()&&!visible.contextMenu()&&!visible.message()) {
clearTimeout($(window).data("timeout"));
$(window).data("timeout", setTimeout(function() {
lychee.imageview.addClass("full");
lychee.loadingBar.css("opacity", 0);
lychee.header.addClass("hidden");
if ($("#imageview #image.small").length>0) {
$("#imageview #image").css({
marginTop: -1*($("#imageview #image").height()/2)
});
} else {
$("#imageview #image").css({
top: 0,
right: 0,
bottom: 0,
left: 0
});
}
}, 500));
}
},
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 (albumID==="s"||albumID==="f") {
$("#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;
} }
function visibleInfobox() {
if (parseInt(infobox.css("right").replace("px", ""))<0) return false;
else return true;
} }
function isPhotoSmall(photo) { },
size = [ infobox: {
["width", false],
["height", false]
];
if (photo.width<$(window).width()-60) size["width"] = true; show: function() {
if (photo.height<$(window).height()-100) size["height"] = true;
if (size["width"]&&size["height"]) return true; if (!visible.infobox()) $("body").append("<div id='infobox_overlay' class='fadeIn'></div>");
else return false; lychee.infobox.addClass("active");
} },
function showInfobox() { hide: function() {
$("body").append("<div id='infobox_overlay' class='fadeIn'></div>"); lychee.animate("#infobox_overlay", "fadeOut");
infobox.addClass("active");
}
function hideInfobox() {
$("#infobox_overlay").removeClass("fadeIn").addClass("fadeOut");
setTimeout(function() { $("#infobox_overlay").remove() }, 300); setTimeout(function() { $("#infobox_overlay").remove() }, 300);
infobox.removeClass("active"); lychee.infobox.removeClass("active");
} }
function loadPhotoInfo(photoID) { },
params = "function=getPhoto&photoID=" + photoID + "&albumID=0&password=''"; albums: {
$.ajax({type: "POST", url: api_path, data: params, dataType: "json", success: function(data) {
if (!data.title) data.title = "Untitled"; init: function() {
document.title = "Lychee - " + data.title;
headerTitle.html(data.title);
data.url = "uploads/big/" + data.url; view.albums.title();
view.albums.content.init();
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(); title: function() {
}, error: ajaxError }); lychee.setTitle("Albums", false);
},
content: {
init: function() {
var smartData = "",
albumsData = "";
/* Smart Albums */
albums.parse(albums.json.unsortedAlbum);
albums.parse(albums.json.publicAlbum);
albums.parse(albums.json.starredAlbum);
if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum);
/* Albums */
if (albums.json.content) {
if (!lychee.publicMode) albumsData = build.divider("Albums");
$.each(albums.json.content, function() {
albums.parse(this);
albumsData += build.album(this);
});
} }
function ajaxError(jqXHR, textStatus, errorThrown) { if (smartData===""&&albumsData==="") $("body").append(build.no_content("picture"));
else lychee.content.html(smartData + albumsData);
console.log(jqXHR); $("img[data-type!='svg']").retina();
console.log(textStatus);
console.log(errorThrown); },
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.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 "0":
lychee.setTitle("Unsorted", false);
break;
default:
if (album.json.init) $("#infobox .attr_name").html(album.json.title + " " + build.editIcon("edit_title_album"));
lychee.setTitle(album.json.title, true);
break;
}
}
},
description: function() {
$("#infobox .attr_description").html(album.json.description + " " + build.editIcon("edit_description_album"));
},
content: {
init: function() {
var photosData = "";
$.each(album.json.content, function() {
album.parse(this);
photosData += build.photo(this);
});
lychee.content.html(photosData);
$("img[data-type!='svg']").retina();
},
title: function(photoID) {
var longTitle = "",
title = album.json.content[photoID].title;
if (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();
}
});
}
},
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() {
if (!visible.controls()) 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_name").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();
}
}
};

112
assets/js/view/main.js Normal file
View File

@ -0,0 +1,112 @@
/**
* @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);
data.url = "uploads/big/" + data.url;
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);
}

60
assets/js/visible.js Executable file
View File

@ -0,0 +1,60 @@
/**
* @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;
},
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;
}
};

4
data/.gitignore vendored Executable file
View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

20
docs/Build.md Normal file
View File

@ -0,0 +1,20 @@
### Dependencies
First you have to install the following dependencies:
- [CSS Optimizer](https://github.com/css/csso) `csso`
- [UglifyJS](https://github.com/mishoo/UglifyJS2) `uglifyjs`
These dependencies can be installed using `npm`:
npm install csso uglify-js -g;
### Build
The Makefile is located in `etc/` and can be easily executed, using the following command. Make sure your run this from the root of Lychee:
make -f etc/Makefile
### Use uncompressed files
While developing, you might want to use the uncompressed files. This is possible by editing the `index.html`. Simply change the linked CSS and JS files. There are already out-commented link-tags for development and production.

View File

@ -1,3 +1,20 @@
## v2.1
Released March 4, 2014
- `New` Multi-select (#32)
- `New` Multi-folder import from server (#47)
- `New` Tagging (#5)
- `New` Import of original image name (#39)
- `New` Makefile
- `Improved` Upload-process
- `Improved` Documentation
- `Improved` Overlay for photos
- `Fixed` Dropbox import (#84)
- `Fixed` Wrong login or password annotation (#71)
- `Fixed` Escaping issue (#89)
- `Moved` Config now located in `data/`
## v2.0.3 ## v2.0.3
Released February 26, 2014 Released February 26, 2014

View File

@ -1,5 +1,5 @@
#### Lychee is not working #### Lychee is not working
If Lychee is not working properly, try to open `plugins/check.php`. This script will display all errors it can find. Everything should work if you can see the message "Lychee is ready. Lets rock!". If Lychee is not working properly, try to open `plugins/check.php`. This script will display all errors it can find.
#### What do I need to run Lychee on my server? #### What do I need to run Lychee on my server?
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
@ -18,7 +18,7 @@ If possible, change these settings directly in your `php.ini`. We recommend to i
Lychee supports the latest versions of Google Chrome, Apple Safari, Mozilla Firefox and Opera. Photos you share with others can be viewed from every browser. Lychee supports the latest versions of Google Chrome, Apple Safari, Mozilla Firefox and Opera. Photos you share with others can be viewed from every browser.
#### How can I set thumbnails for my albums? #### How can I set thumbnails for my albums?
Thumbnails are chosen automatically by the photos you have starred and in the order you uploaded them. Star a photo inside a album to set it as an thumbnail. Thumbnails are chosen automatically by the photos you have starred and in the order you uploaded them. Star a photo inside an album to set it as a thumbnail.
#### What is new? #### What is new?
Take a look at the [Changelog](Changelog.md) to see whats new. Take a look at the [Changelog](Changelog.md) to see whats new.

View File

@ -1,7 +1,7 @@
### Requirements ### 1. Requirements
Everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
### PHP configuration `php.ini` ### 2. PHP configuration `php.ini`
The following extensions must be activated: The following extensions must be activated:
@ -17,13 +17,21 @@ To use Lychee without restrictions, we recommend to increase the values of the f
upload_max_filesize = 20M upload_max_filesize = 20M
max_file_uploads = 100 max_file_uploads = 100
### Folder permissions ### 3. Download
Change the permissions of `uploads/` and `php/` to 777, including all subfolders: The easiest way to download Lychee is with `git`:
chmod -R 777 uploads/ php/ git clone https://github.com/electerious/Lychee.git
### Lychee installation You can also use the [direct download](https://github.com/electerious/Lychee/archive/master.zip).
### 4. Permissions
Change the permissions of `uploads/` and `data/` to 777, including all subfolders:
chmod -R 777 uploads/ data/
### 5. Finish
Open Lychee in your browser and follow the given steps. Open Lychee in your browser and follow the given steps.
If you have trouble, take a look at the [FAQ](FAQ.md). If you have trouble, take a look at the [FAQ](FAQ.md).

47
docs/Settings.md Normal file
View File

@ -0,0 +1,47 @@
### Database Details
Your MySQL details are stored in `data/config.php`. This file doesn't exist until you installed Lychee. If you need to change your connection details, you can edit this file manually.
$dbHost = Your MySQL host (in most cases you can use localhost)
$dbUser = Your MySQL username
$dbPassword = Your MySQL password
$dbName = The name of the database you want to use
Fill these properties with your MySQL information. Lychee will create the database and tables for you, if they doesn't exist.
### Settings
All settings are stored in the database. You can change the properties manually, but we recommend to use the menu in Lychee. You can find this menu on the top left corner after you signed in. Some of these settings are only changeable directly in the database.
#### Login
username = Username for Lychee
password = Password for Lychee, saved as an md5 hash
Your photos and albums are protected by an username and password you need to set. If both rows are empty, Lychee will prompt you to set them.
#### Thumb Quality
thumbQuality = [0-100]
Less means an inferiority quality of your thumbs, but faster loading. More means a better quality of your thumbs, but slower loading. The default value is 90. The allowed values are between 0 and 100.
#### Check For Updates
checkForUpdates = [0|1]
If `1`, Lychee will check if you are using the latest version. The notice will be displayed beside the version-number when you sign in.
#### Sorting
sorting = ORDER BY [row] [ASC|DESC]
A typical part of a MySQL statement. This string will be appended to mostly every MySQL query.
#### Dropbox Key
This key is required to use the Dropbox import feature from your server. Lychee will ask you for this key, the first time you try to use the import. You can get your personal drop-ins app key from [their website](https://www.dropbox.com/developers/apps/create).
dropboxKey = Your personal App Key

11
docs/Update.md Normal file
View File

@ -0,0 +1,11 @@
### Update with `git`
The easiest way to update Lychee is with `git`:
git pull
### Update manually
1. Download the [newest Version](https://github.com/electerious/Lychee/archive/master.zip)
2. Replace all existing files, excluding `uploads/` and `data/`
3. Open Lychee (and enter your database details)

View File

@ -1,32 +0,0 @@
#!/bin/bash
folderCSS="../assets/css"
folderJS="../assets/js"
if [ -e "$folderCSS/modules/" ]
then
echo "Compiling CSS ..."
awk 'FNR==1{print ""}1' $folderCSS/modules/*.css > $folderCSS/min/main.css
csso $folderCSS/min/main.css $folderCSS/min/main.css
echo "CSS compiled!"
else
echo "CSS files not found in $folderCSS"
fi
if [ -e "$folderJS/modules/" ]
then
echo "Compiling JS ..."
awk 'FNR==1{print ""}1' $folderJS/modules/*.js > $folderJS/min/main.js
uglifyjs $folderJS/min/main.js -o $folderJS/min/main.js
echo "JS compiled!"
else
echo "JS files not found in $folderJS"
fi

View File

@ -1,40 +0,0 @@
#!/bin/sh
VERSION='2.0'
echo 'Press ENTER to continue or any other key to abort'
read -s -n 1 key
if [[ "$key" = "" ]]
then
if [ -e Lychee-$VERSION ]
then
echo "The folder 'Lychee-$VERSION' already exists. Please delete it before you try to install Lychee."
exit 1
fi
if [ -e lychee ]
then
echo "The folder 'lychee' already exists. Please delete it before you try to install Lychee."
exit 1
fi
echo 'Downloading and installing Lychee...' && \
curl -sS https://codeload.github.com/electerious/Lychee/zip/v$VERSION > lychee.zip && \
echo 'Downloaded.' && \
echo 'Unzipping...' && \
unzip lychee.zip && \
rm lychee.zip && \
mv Lychee-$VERSION lychee && \
cd lychee && \
echo 'The required directories will be made writable and executable for others. Please enter your password if prompted to do so.' && \
sudo chmod -R 777 uploads php && \
echo 'Installation successful!' && \
exit 0
fi

View File

@ -1,15 +0,0 @@
### Import from server
To import photos from your server (photos you have uploaded via FTP to your server), sign in and click the add-icon on the top right. Then choose 'Import from Server'.
### Upload and share single photos [Depreciated]
Important: This feature is depreciated and will be removed with the next major version. Do not use it anymore! It will be replaced by a plugin.
You can upload photos directly with every FTP client into Lychee. This feature helps you to share single images quickly with others.
1. Upload an image to `uploads/import/`
2. Navigate your browser to the place where Lychee is located (e.g. `http://example.com/view.php?p=filename.png`). `filename.png` must be replaced with the filename of your uploaded file.
3. Share the link.
Lychee will import the file as an public image, delete the original (unused) file and display it in the browser. [Sample FTP configuration](http://l.electerious.com/view.php?p=13657692738813).

View File

@ -1,41 +0,0 @@
### Database Details
Your MySQL details are stored in `php/config.php`. This file doesn't exist until you installed Lychee. If you need to change your connection details, you can edit this file manually.
$dbHost = Your MySQL host (in most cases you can use localhost)
$dbUser = Your MySQL username
$dbPassword = Your MySQL password
$dbName = The name of the database you want to use
Fill these properties with your MySQL information. Lychee will create the database and tables for you, if they doesn't exist.
### Settings
All settings are stored in the database. You can change the properties manually, but we recommend to use the menu in Lychee. You can find this menu on the top left corner after you signed in.
#### Login
username = Username for Lychee
password = Password for Lychee, saved as an md5 hash
Your photos and albums are protected by a username and password you need to set. If both rows are empty, Lychee will prompt you to set them.
#### Thumb Quality
thumbQuality = [0-100]
Less means a inferiority quality of your thumbs, but faster loading. More means a better quality of your thumbs, but slower loading. The default value is 90. The allowed values are between 0 and 100.
#### Check For Updates
checkForUpdates = [0|1]
If `1`, Lychee will check if you are using the latest version. The notice will be displayed beside the version-number when you sign in.
#### Sorting
sorting = ORDER BY [row] [ASC|DESC]
A typical part of an MySQL statement. This string will be appended to mostly every MySQL query.

35
etc/Makefile Normal file
View File

@ -0,0 +1,35 @@
NO_COLOR=\x1b[0m
OK_COLOR=\x1b[32;01m
ERROR_COLOR=\x1b[31;01m
WARN_COLOR=\x1b[33;01m
OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR)
ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR)
RUN_STRING=$(WARN_COLOR)[RUN]$(NO_COLOR)
ROOT = .
CSS = '$(ROOT)/assets/css'
JS = '$(ROOT)/assets/js'
BUILD = '$(ROOT)/assets/build'
all: clean create css js
clean:
rm -f -R $(BUILD)
@echo "$(OK_STRING) Clean build"
create: clean
mkdir $(BUILD)
@echo "$(OK_STRING) Create build"
css: create
@echo "$(RUN_STRING) Compiling CSS"
awk 'FNR==1{print ""}1' $(CSS)/*.css > $(BUILD)/main.css
csso $(BUILD)/main.css $(BUILD)/main.css
@echo "$(OK_STRING) CSS compiled"
js: create
@echo "$(RUN_STRING) Compiling JS"
awk 'FNR==1{print ""}1' $(JS)/*.js > $(BUILD)/main.js
uglifyjs $(BUILD)/main.js -o $(BUILD)/main.js
@echo "$(OK_STRING) JS compiled"

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -9,28 +9,27 @@
<meta name="keywords" content=""> <meta name="keywords" content="">
<meta name="description" content=""> <meta name="description" content="">
<!-- CSS --> <!-- Development -->
<link type="text/css" rel="stylesheet" href="assets/css/min/reset.css"> <link type="text/css" rel="stylesheet" href="assets/css/_reset.css">
<link type="text/css" rel="stylesheet" href="assets/css/upload.css">
<link type="text/css" rel="stylesheet" href="assets/css/tooltip.css">
<link type="text/css" rel="stylesheet" href="assets/css/misc.css">
<link type="text/css" rel="stylesheet" href="assets/css/message.css">
<link type="text/css" rel="stylesheet" href="assets/css/mediaquery.css">
<link type="text/css" rel="stylesheet" href="assets/css/loading.css">
<link type="text/css" rel="stylesheet" href="assets/css/infobox.css">
<link type="text/css" rel="stylesheet" href="assets/css/imageview.css">
<link type="text/css" rel="stylesheet" href="assets/css/header.css">
<link type="text/css" rel="stylesheet" href="assets/css/font.css">
<link type="text/css" rel="stylesheet" href="assets/css/contextmenu.css">
<link type="text/css" rel="stylesheet" href="assets/css/content.css">
<link type="text/css" rel="stylesheet" href="assets/css/animations.css">
<link type="text/css" rel="stylesheet" href="assets/css/multiselect.css">
<!-- Development <!-- Production
<link type="text/css" rel="stylesheet" href="assets/css/modules/upload.css"> <link type="text/css" rel="stylesheet" href="assets/build/main.css"> -->
<link type="text/css" rel="stylesheet" href="assets/css/modules/tooltip.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/misc.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/message.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/mediaquery.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/loading.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/infobox.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/imageview.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/header.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/font.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/contextmenu.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/content.css">
<link type="text/css" rel="stylesheet" href="assets/css/modules/animations.css"> -->
<!-- Production --> <link rel="shortcut icon" href="favicon.ico">
<link type="text/css" rel="stylesheet" href="assets/css/min/main.css">
<link rel="shortcut icon" href="assets/img/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-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="assets/img/apple-touch-icon-ipad.png" sizes="152x152">
@ -96,28 +95,27 @@
<input id="upload_files" type="file" name="fileElem[]" multiple accept="image/*"> <input id="upload_files" type="file" name="fileElem[]" multiple accept="image/*">
</div> </div>
<!-- JS --> <!-- Development -->
<script defer type="text/javascript" src="assets/js/min/frameworks.js"></script> <script defer type="text/javascript" src="assets/js/_frameworks.js"></script>
<script defer type="text/javascript" src="assets/js/init.js"></script>
<script defer type="text/javascript" src="assets/js/lychee.js"></script>
<script defer type="text/javascript" src="assets/js/build.js"></script>
<script defer type="text/javascript" src="assets/js/settings.js"></script>
<script defer type="text/javascript" src="assets/js/upload.js"></script>
<script defer type="text/javascript" src="assets/js/view.js"></script>
<script defer type="text/javascript" src="assets/js/password.js"></script>
<script defer type="text/javascript" src="assets/js/modal.js"></script>
<script defer type="text/javascript" src="assets/js/album.js"></script>
<script defer type="text/javascript" src="assets/js/albums.js"></script>
<script defer type="text/javascript" src="assets/js/photo.js"></script>
<script defer type="text/javascript" src="assets/js/visible.js"></script>
<script defer type="text/javascript" src="assets/js/loadingBar.js"></script>
<script defer type="text/javascript" src="assets/js/contextMenu.js"></script>
<script defer type="text/javascript" src="assets/js/search.js"></script>
<script defer type="text/javascript" src="assets/js/multiselect.js"></script>
<!-- Development <!-- Production
<script defer type="text/javascript" src="assets/js/modules/init.js"></script> <script defer type="text/javascript" src="assets/build/main.js"></script> -->
<script defer type="text/javascript" src="assets/js/modules/lychee.js"></script>
<script defer type="text/javascript" src="assets/js/modules/build.js"></script>
<script defer type="text/javascript" src="assets/js/modules/settings.js"></script>
<script defer type="text/javascript" src="assets/js/modules/upload.js"></script>
<script defer type="text/javascript" src="assets/js/modules/view.js"></script>
<script defer type="text/javascript" src="assets/js/modules/password.js"></script>
<script defer type="text/javascript" src="assets/js/modules/modal.js"></script>
<script defer type="text/javascript" src="assets/js/modules/album.js"></script>
<script defer type="text/javascript" src="assets/js/modules/albums.js"></script>
<script defer type="text/javascript" src="assets/js/modules/photo.js"></script>
<script defer type="text/javascript" src="assets/js/modules/visible.js"></script>
<script defer type="text/javascript" src="assets/js/modules/loadingBar.js"></script>
<script defer type="text/javascript" src="assets/js/modules/contextMenu.js"></script>
<script defer type="text/javascript" src="assets/js/modules/search.js"></script> -->
<!-- Production -->
<script defer type="text/javascript" src="assets/js/min/main.js"></script>
</body> </body>
</html> </html>

157
php/access/admin.php Normal file
View File

@ -0,0 +1,157 @@
<?php
/**
* @name Admin Access
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_ADMIN')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(false));
break;
case 'getAlbum': if (isset($_POST['albumID']))
echo json_encode(getAlbum($_POST['albumID']));
break;
case 'addAlbum': if (isset($_POST['title']))
echo addAlbum($_POST['title']);
break;
case 'setAlbumTitle': if (isset($_POST['albumIDs'])&&isset($_POST['title']))
echo setAlbumTitle($_POST['albumIDs'], $_POST['title']);
break;
case 'setAlbumDescription': if (isset($_POST['albumID'])&&isset($_POST['description']))
echo setAlbumDescription($_POST['albumID'], $_POST['description']);
break;
case 'setAlbumPublic': if (isset($_POST['albumID']))
if (!isset($_POST['password'])) $_POST['password'] = '';
echo setAlbumPublic($_POST['albumID'], $_POST['password']);
break;
case 'setAlbumPassword': if (isset($_POST['albumID'])&&isset($_POST['password']))
echo setAlbumPassword($_POST['albumID'], $_POST['password']);
break;
case 'deleteAlbum': if (isset($_POST['albumIDs']))
echo deleteAlbum($_POST['albumIDs']);
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
break;
case 'deletePhoto': if (isset($_POST['photoIDs']))
echo deletePhoto($_POST['photoIDs']);
break;
case 'setPhotoAlbum': if (isset($_POST['photoIDs'])&&isset($_POST['albumID']))
echo setPhotoAlbum($_POST['photoIDs'], $_POST['albumID']);
break;
case 'setPhotoTitle': if (isset($_POST['photoIDs'])&&isset($_POST['title']))
echo setPhotoTitle($_POST['photoIDs'], $_POST['title']);
break;
case 'setPhotoStar': if (isset($_POST['photoIDs']))
echo setPhotoStar($_POST['photoIDs']);
break;
case 'setPhotoPublic': if (isset($_POST['photoID'])&&isset($_POST['url']))
echo setPhotoPublic($_POST['photoID'], $_POST['url']);
break;
case 'setPhotoDescription': if (isset($_POST['photoID'])&&isset($_POST['description']))
echo setPhotoDescription($_POST['photoID'], $_POST['description']);
break;
case 'setPhotoTags': if (isset($_POST['photoIDs'])&&isset($_POST['tags']))
echo setPhotoTags($_POST['photoIDs'], $_POST['tags']);
break;
// Add Functions
case 'upload': if (isset($_FILES)&&isset($_POST['albumID']))
echo upload($_FILES, $_POST['albumID']);
break;
case 'importUrl': if (isset($_POST['url'])&&isset($_POST['albumID']))
echo importUrl($_POST['url'], $_POST['albumID']);
break;
case 'importServer': if (isset($_POST['albumID']))
echo importServer($_POST['albumID']);
break;
// Search Function
case 'search': if (isset($_POST['term']))
echo json_encode(search($_POST['term']));
break;
// Session Function
case 'init': echo json_encode(init('admin', $_POST['version']));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
case 'logout': logout();
break;
// Settings
case 'setLogin': if (isset($_POST['username'])&&isset($_POST['password']))
if (!isset($_POST['oldPassword'])) $_POST['oldPassword'] = '';
echo setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']);
break;
case 'setSorting': if (isset($_POST['type'])&&isset($_POST['order']))
echo setSorting($_POST['type'], $_POST['order']);
break;
case 'setDropboxKey': if (isset($_POST['key']))
echo setDropboxKey($_POST['key']);
break;
// Miscellaneous
default: switch ($_GET['function']) {
case 'getFeed': if (isset($_GET['albumID']))
echo getFeed($_GET['albumID']);
break;
case 'getAlbumArchive': if (isset($_GET['albumID']))
getAlbumArchive($_GET['albumID']);
break;
case 'getPhotoArchive': if (isset($_GET['photoID']))
getPhotoArchive($_GET['photoID']);
break;
case 'update': echo update();
break;
default: exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
break;
}
?>

126
php/access/guest.php Normal file
View File

@ -0,0 +1,126 @@
<?php
/**
* @name Guest Access (Public Mode)
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_GUEST')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(true));
break;
case 'getAlbum': if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo json_encode(getAlbum($_POST['albumID']));
else
echo 'Warning: Wrong password!';
} else {
// Album Private
echo 'Warning: Album private!';
}
}
break;
case 'checkAlbumAccess':if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo true;
else
echo false;
} else {
// Album Private
echo false;
}
}
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isPhotoPublic($_POST['photoID'], $_POST['password']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
else
echo 'Warning: Wrong password!';
}
break;
// Session Functions
case 'init': echo json_encode(init('public', $_POST['version']));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
// Miscellaneous
default: switch ($_GET['function']) {
case 'getFeed': if (isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Feed
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
echo getFeed($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private!');
}
}
break;
case 'getAlbumArchive': if (isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Download
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
getAlbumArchive($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private or not downloadable!');
}
}
break;
case 'getPhotoArchive': if (isset($_GET['photoID'])&&isset($_GET['password'])) {
// Photo Download
if (isPhotoPublic($_GET['photoID'], $_GET['password']))
// Photo Public
getPhotoArchive($_GET['photoID']);
else
// Photo Private
exit('Warning: Photo private or not downloadable!');
}
break;
default: exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
break;
}
?>

View File

@ -0,0 +1,23 @@
<?php
/**
* @name Installation Access
* @author Tobias Reich
* @copyright 2014 by Tobias Reich
*/
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
if (!defined('LYCHEE_ACCESS_INSTALLATION')) exit('Error: You are not allowed to access this area!');
switch ($_POST['function']) {
case 'dbCreateConfig': if (isset($_POST['dbHost'])&&isset($_POST['dbUser'])&&isset($_POST['dbPassword'])&&isset($_POST['dbName'])&&isset($_POST['version']))
echo dbCreateConfig($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['version']);
break;
default: echo 'Warning: No configuration!';
break;
}
?>

View File

@ -2,9 +2,8 @@
/** /**
* @name API * @name API
* @author Philipp Maurer
* @author Tobias Reich * @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich * @copyright 2014 by Tobias Reich
*/ */
@ini_set('max_execution_time', '200'); @ini_set('max_execution_time', '200');
@ -17,290 +16,68 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) {
session_start(); session_start();
define('LYCHEE', true); define('LYCHEE', true);
date_default_timezone_set('UTC');
// Load modules
require('modules/album.php');
require('modules/db.php'); require('modules/db.php');
require('modules/misc.php');
require('modules/photo.php');
require('modules/session.php'); require('modules/session.php');
require('modules/settings.php'); require('modules/settings.php');
require('modules/upload.php'); require('modules/upload.php');
require('modules/album.php');
require('modules/photo.php');
require('modules/misc.php');
if (file_exists('config.php')) require('config.php'); if (file_exists('../data/config.php')) require('../data/config.php');
else { else {
/** /**
* Installation Mode * Installation Access
* Limited access to configure Lychee. Only available when the config.php file is missing. * Limited access to configure Lychee. Only available when the config.php file is missing.
*/ */
switch ($_POST['function']) { define('LYCHEE_ACCESS_INSTALLATION', true);
require('access/installation.php');
case 'createConfig': if (isset($_POST['dbHost'])&&isset($_POST['dbUser'])&&isset($_POST['dbPassword'])&&isset($_POST['dbName']))
echo createConfig($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName']);
break;
default: echo 'Warning: No configuration!';
break;
}
exit(); exit();
} }
// Connect to DB // Connect and get settings
$database = dbConnect(); $database = dbConnect();
// Get Settings
$settings = getSettings(); $settings = getSettings();
// Security // Escape
if (isset($_POST['albumID'])&&($_POST['albumID']==''||$_POST['albumID']<0||$_POST['albumID']>10000)) exit('Error: Wrong parameter type for albumID!');
if (isset($_POST['photoID'])&&$_POST['photoID']=='') exit('Error: Wrong parameter type for photoID!');
foreach(array_keys($_POST) as $key) $_POST[$key] = mysqli_real_escape_string($database, urldecode($_POST[$key])); foreach(array_keys($_POST) as $key) $_POST[$key] = mysqli_real_escape_string($database, urldecode($_POST[$key]));
foreach(array_keys($_GET) as $key) $_GET[$key] = mysqli_real_escape_string($database, urldecode($_GET[$key])); foreach(array_keys($_GET) as $key) $_GET[$key] = mysqli_real_escape_string($database, urldecode($_GET[$key]));
// Validate parameters
if (isset($_POST['albumIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['albumIDs'])!==1) exit('Error: Wrong parameter type for albumIDs!');
if (isset($_POST['photoIDs'])&&preg_match('/^[0-9\,]{1,}$/', $_POST['photoIDs'])!==1) exit('Error: Wrong parameter type for photoIDs!');
if (isset($_POST['albumID'])&&preg_match('/^[0-9sf]{1,}$/', $_POST['albumID'])!==1) exit('Error: Wrong parameter type for albumID!');
if (isset($_POST['photoID'])&&preg_match('/^[0-9]{14}$/', $_POST['photoID'])!==1) exit('Error: Wrong parameter type for photoID!');
// Fallback for switch statement
if (!isset($_POST['function'])) $_POST['function'] = '';
if (!isset($_GET['function'])) $_GET['function'] = '';
if (isset($_SESSION['login'])&&$_SESSION['login']==true) { if (isset($_SESSION['login'])&&$_SESSION['login']==true) {
/** /**
* Admin Mode * Admin Access
* Full access to Lychee. Only with correct password/session. * Full access to Lychee. Only with correct password/session.
*/ */
switch ($_POST['function']) { define('LYCHEE_ACCESS_ADMIN', true);
require('access/admin.php');
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(false));
break;
case 'getAlbum': if (isset($_POST['albumID']))
echo json_encode(getAlbum($_POST['albumID']));
break;
case 'addAlbum': if (isset($_POST['title']))
echo addAlbum($_POST['title']);
break;
case 'setAlbumTitle': if (isset($_POST['albumID'])&&isset($_POST['title']))
echo setAlbumTitle($_POST['albumID'], $_POST['title']);
break;
case 'setAlbumDescription': if (isset($_POST['albumID'])&&isset($_POST['description']))
echo setAlbumDescription($_POST['albumID'], $_POST['description']);
break;
case 'setAlbumPublic': if (isset($_POST['albumID']))
if (!isset($_POST['password'])) $_POST['password'] = '';
echo setAlbumPublic($_POST['albumID'], $_POST['password']);
break;
case 'setAlbumPassword':if (isset($_POST['albumID'])&&isset($_POST['password']))
echo setAlbumPassword($_POST['albumID'], $_POST['password']);
break;
case 'deleteAlbum': if (isset($_POST['albumID']))
echo deleteAlbum($_POST['albumID']);
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
break;
case 'deletePhoto': if (isset($_POST['photoID']))
echo deletePhoto($_POST['photoID']);
break;
case 'setAlbum': if (isset($_POST['photoID'])&&isset($_POST['albumID']))
echo setAlbum($_POST['photoID'], $_POST['albumID']);
break;
case 'setPhotoTitle': if (isset($_POST['photoID'])&&isset($_POST['title']))
echo setPhotoTitle($_POST['photoID'], $_POST['title']);
break;
case 'setPhotoStar': if (isset($_POST['photoID']))
echo setPhotoStar($_POST['photoID']);
break;
case 'setPhotoPublic': if (isset($_POST['photoID'])&&isset($_POST['url']))
echo setPhotoPublic($_POST['photoID'], $_POST['url']);
break;
case 'setPhotoDescription': if (isset($_POST['photoID'])&&isset($_POST['description']))
echo setPhotoDescription($_POST['photoID'], $_POST['description']);
break;
// Add Functions
case 'upload': if (isset($_FILES)&&isset($_POST['albumID']))
echo upload($_FILES, $_POST['albumID']);
break;
case 'importUrl': if (isset($_POST['url'])&&isset($_POST['albumID']))
echo importUrl($_POST['url'], $_POST['albumID']);
break;
case 'importServer': if (isset($_POST['albumID']))
echo importServer($_POST['albumID']);
break;
// Search Function
case 'search': if (isset($_POST['term']))
echo json_encode(search($_POST['term']));
break;
// Session Function
case 'init': echo json_encode(init('admin'));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
case 'logout': logout();
break;
// Settings
case 'setLogin': if (isset($_POST['username'])&&isset($_POST['password']))
if (!isset($_POST['oldPassword'])) $_POST['oldPassword'] = '';
echo setLogin($_POST['oldPassword'], $_POST['username'], $_POST['password']);
break;
case 'setSorting': if (isset($_POST['type'])&&isset($_POST['order']))
echo setSorting($_POST['type'], $_POST['order']);
break;
// Miscellaneous
case 'update': echo update();
default: if (isset($_GET['function'])&&$_GET['function']=='getAlbumArchive'&&isset($_GET['albumID']))
// Album Download
getAlbumArchive($_GET['albumID']);
else if (isset($_GET['function'])&&$_GET['function']=='getPhotoArchive'&&isset($_GET['photoID']))
// Photo Download
getPhotoArchive($_GET['photoID']);
else if (isset($_GET['function'])&&$_GET['function']=='update')
// Update Lychee
echo update();
else
// Function unknown
exit('Error: Function not found! Please check the spelling of the called function.');
break;
}
} else { } else {
/** /**
* Public Mode * Guest Access
* Access to view all public folders and photos in Lychee. * Access to view all public folders and photos in Lychee.
*/ */
switch ($_POST['function']) { define('LYCHEE_ACCESS_GUEST', true);
require('access/guest.php');
// Album Functions
case 'getAlbums': echo json_encode(getAlbums(true));
break;
case 'getAlbum': if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo json_encode(getAlbum($_POST['albumID']));
else
echo 'Warning: Wrong password!';
} else {
// Album Private
echo 'Warning: Album private!';
}
}
break;
case 'checkAlbumAccess':if (isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isAlbumPublic($_POST['albumID'])) {
// Album Public
if (checkAlbumPassword($_POST['albumID'], $_POST['password']))
echo true;
else
echo false;
} else {
// Album Private
echo false;
}
}
break;
// Photo Functions
case 'getPhoto': if (isset($_POST['photoID'])&&isset($_POST['albumID'])&&isset($_POST['password'])) {
if (isPhotoPublic($_POST['photoID'], $_POST['password']))
echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
else
echo 'Warning: Wrong password!';
}
break;
// Session Functions
case 'init': echo json_encode(init('public'));
break;
case 'login': if (isset($_POST['user'])&&isset($_POST['password']))
echo login($_POST['user'], $_POST['password']);
break;
// Miscellaneous
default: if (isset($_GET['function'])&&$_GET['function']=='getAlbumArchive'&&isset($_GET['albumID'])&&isset($_GET['password'])) {
// Album Download
if (isAlbumPublic($_GET['albumID'])) {
// Album Public
if (checkAlbumPassword($_GET['albumID'], $_GET['password']))
getAlbumArchive($_GET['albumID']);
else
exit('Warning: Wrong password!');
} else {
// Album Private
exit('Warning: Album private or not downloadable!');
}
} else if (isset($_GET['function'])&&$_GET['function']=='getPhotoArchive'&&isset($_GET['photoID'])&&isset($_GET['password'])) {
// Photo Download
if (isPhotoPublic($_GET['photoID'], $_GET['password']))
// Photo Public
getPhotoArchive($_GET['photoID']);
else
// Photo Private
exit('Warning: Photo private or not downloadable!');
} else {
// Function unknown
exit('Error: Function not found! Please check the spelling of the called function.');
}
break;
}
} }

View File

@ -13,11 +13,12 @@ function addAlbum($title) {
global $database; global $database;
if (strlen($title)<1||strlen($title)>30) return false; if (strlen($title)<1||strlen($title)>50) return false;
$sysdate = date("d.m.Y"); $sysdate = date("d.m.Y");
$result = $database->query("INSERT INTO lychee_albums (title, sysdate) VALUES ('$title', '$sysdate');"); $result = $database->query("INSERT INTO lychee_albums (title, sysdate) VALUES ('$title', '$sysdate');");
if (!$result) return false;
if (!$result) return false;
return $database->insert_id; return $database->insert_id;
} }
@ -30,10 +31,12 @@ function getAlbums($public) {
if (!$public) $return = getSmartInfo(); if (!$public) $return = getSmartInfo();
// Albums // Albums
if ($public) $query = "SELECT * FROM lychee_albums WHERE public = 1"; if ($public) $query = "SELECT id, title, public, sysdate, password FROM lychee_albums WHERE public = 1";
else $query = "SELECT * FROM lychee_albums"; else $query = "SELECT id, title, public, sysdate, password FROM lychee_albums";
$result = $database->query($query) OR exit("Error: $result <br>".$database->error); $result = $database->query($query) OR exit("Error: $result <br>".$database->error);
$i = 0; $i = 0;
while($row = $result->fetch_object()) { while($row = $result->fetch_object()) {
// Info // Info
@ -41,11 +44,14 @@ function getAlbums($public) {
$return["content"][$row->id]['title'] = $row->title; $return["content"][$row->id]['title'] = $row->title;
$return["content"][$row->id]['public'] = $row->public; $return["content"][$row->id]['public'] = $row->public;
$return["content"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate)); $return["content"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
// Password
if ($row->password=="") $return["content"][$row->id]['password'] = false; if ($row->password=="") $return["content"][$row->id]['password'] = false;
else $return["content"][$row->id]['password'] = true; else $return["content"][$row->id]['password'] = true;
// Thumbs // Thumbs
if (($public&&$row->password=="")||(!$public)) { if (($public&&$row->password=="")||(!$public)) {
$albumID = $row->id; $albumID = $row->id;
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY star DESC, " . substr($settings['sorting'], 9) . " LIMIT 0, 3"); $result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY star DESC, " . substr($settings['sorting'], 9) . " LIMIT 0, 3");
$k = 0; $k = 0;
@ -56,6 +62,7 @@ function getAlbums($public) {
if (!isset($return["content"][$row->id]["thumb0"])) $return["content"][$row->id]["thumb0"] = ""; if (!isset($return["content"][$row->id]["thumb0"])) $return["content"][$row->id]["thumb0"] = "";
if (!isset($return["content"][$row->id]["thumb1"])) $return["content"][$row->id]["thumb1"] = ""; if (!isset($return["content"][$row->id]["thumb1"])) $return["content"][$row->id]["thumb1"] = "";
if (!isset($return["content"][$row->id]["thumb2"])) $return["content"][$row->id]["thumb2"] = ""; if (!isset($return["content"][$row->id]["thumb2"])) $return["content"][$row->id]["thumb2"] = "";
} }
// Album count // Album count
@ -65,9 +72,6 @@ function getAlbums($public) {
$return["num"] = $i; $return["num"] = $i;
if ($i==0) $return["albums"] = false;
else $return["albums"] = true;
return $return; return $return;
} }
@ -115,15 +119,15 @@ function getAlbum($albumID) {
switch($albumID) { switch($albumID) {
case "f": $return['public'] = false; case "f": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting']; $query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 " . $settings['sorting'];
break; break;
case "s": $return['public'] = false; case "s": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting']; $query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 " . $settings['sorting'];
break; break;
case "0": $return['public'] = false; case "0": $return['public'] = false;
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting']; $query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 " . $settings['sorting'];
break; break;
default: $result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';"); default: $result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
@ -132,9 +136,8 @@ function getAlbum($albumID) {
$return['description'] = $row->description; $return['description'] = $row->description;
$return['sysdate'] = date('d M. Y', strtotime($row->sysdate)); $return['sysdate'] = date('d M. Y', strtotime($row->sysdate));
$return['public'] = $row->public; $return['public'] = $row->public;
if ($row->password=="") $return['password'] = false; $return['password'] = ($row->password=="" ? false : true);
else $return['password'] = true; $query = "SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' " . $settings['sorting'];
break; break;
} }
@ -150,6 +153,7 @@ function getAlbum($albumID) {
$return['content'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate'])); $return['content'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
$return['content'][$row['id']]['public'] = $row['public']; $return['content'][$row['id']]['public'] = $row['public'];
$return['content'][$row['id']]['star'] = $row['star']; $return['content'][$row['id']]['star'] = $row['star'];
$return['content'][$row['id']]['tags'] = $row['tags'];
$return['content'][$row['id']]['album'] = $row['album']; $return['content'][$row['id']]['album'] = $row['album'];
$return['content'][$row['id']]['thumbUrl'] = $row['thumbUrl']; $return['content'][$row['id']]['thumbUrl'] = $row['thumbUrl'];
@ -189,14 +193,14 @@ function getAlbum($albumID) {
} }
function setAlbumTitle($albumID, $title) { function setAlbumTitle($albumIDs, $title) {
global $database; global $database;
if (strlen($title)<1||strlen($title)>30) return false; if (strlen($title)<1||strlen($title)>50) return false;
$result = $database->query("UPDATE lychee_albums SET title = '$title' WHERE id = '$albumID';"); $result = $database->query("UPDATE lychee_albums SET title = '$title' WHERE id IN ($albumIDs);");
if (!$result) return false;
if (!$result) return false;
return true; return true;
} }
@ -206,7 +210,7 @@ function setAlbumDescription($albumID, $description) {
global $database; global $database;
$description = htmlentities($description); $description = htmlentities($description);
if (strlen($description)>800) return false; if (strlen($description)>1000) return false;
$result = $database->query("UPDATE lychee_albums SET description = '$description' WHERE id = '$albumID';"); $result = $database->query("UPDATE lychee_albums SET description = '$description' WHERE id = '$albumID';");
if (!$result) return false; if (!$result) return false;
@ -214,23 +218,21 @@ function setAlbumDescription($albumID, $description) {
} }
function deleteAlbum($albumID) { function deleteAlbum($albumIDs) {
global $database; global $database;
$error = false; $error = false;
$result = $database->query("SELECT id FROM lychee_photos WHERE album IN ($albumIDs);");
$result = $database->query("SELECT id FROM lychee_photos WHERE album = '$albumID';"); // Delete photos
while($row = $result->fetch_object()) { while ($row = $result->fetch_object())
if (!deletePhoto($row->id)) $error = true; if (!deletePhoto($row->id)) $error = true;
}
if ($albumID!=0) { // Delete album
$result = $database->query("DELETE FROM lychee_albums WHERE id = '$albumID';"); $result = $database->query("DELETE FROM lychee_albums WHERE id IN ($albumIDs);");
if (!$result) return false;
}
if ($error) return false; if ($error||!$result) return false;
return true; return true;
} }
@ -241,31 +243,32 @@ function getAlbumArchive($albumID) {
switch($albumID) { switch($albumID) {
case 's': case 's':
$query = "SELECT * FROM lychee_photos WHERE public = '1';"; $query = "SELECT url FROM lychee_photos WHERE public = '1';";
$zipTitle = "Public"; $zipTitle = "Public";
break; break;
case 'f': case 'f':
$query = "SELECT * FROM lychee_photos WHERE star = '1';"; $query = "SELECT url FROM lychee_photos WHERE star = '1';";
$zipTitle = "Starred"; $zipTitle = "Starred";
break; break;
default: default:
$query = "SELECT * FROM lychee_photos WHERE album = '$albumID';"; $query = "SELECT url FROM lychee_photos WHERE album = '$albumID';";
$zipTitle = "Unsorted"; $zipTitle = "Unsorted";
} }
$zip = new ZipArchive();
$result = $database->query($query); $result = $database->query($query);
$files = array(); $files = array();
$i = 0; $i = 0;
while($row = $result->fetch_object()) { while($row = $result->fetch_object()) {
$files[$i] = "../uploads/big/".$row->url; $files[$i] = "../uploads/big/".$row->url;
$i++; $i++;
} }
$result = $database->query("SELECT * FROM lychee_albums WHERE id = '$albumID';");
$result = $database->query("SELECT title FROM lychee_albums WHERE id = '$albumID' LIMIT 1;");
$row = $result->fetch_object(); $row = $result->fetch_object();
if ($albumID!=0&&is_numeric($albumID)) $zipTitle = $row->title; if ($albumID!=0&&is_numeric($albumID)) $zipTitle = $row->title;
$filename = "../uploads/".$zipTitle.".zip"; $filename = "../data/$zipTitle.zip";
$zip = new ZipArchive();
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
return false; return false;
@ -295,20 +298,18 @@ function setAlbumPublic($albumID, $password) {
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';"); $result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
if ($row->public == 0){ $public = ($row->public=='0' ? 1 : 0);
$public = 1;
} else {
$public = 0;
}
$result = $database->query("UPDATE lychee_albums SET public = '$public', password = NULL WHERE id = '$albumID';"); $result = $database->query("UPDATE lychee_albums SET public = '$public', password = NULL WHERE id = '$albumID';");
if (!$result) return false; if (!$result) return false;
if ($public==1) { if ($public==1) {
$result = $database->query("UPDATE lychee_photos SET public = 0 WHERE album = '$albumID';"); $result = $database->query("UPDATE lychee_photos SET public = 0 WHERE album = '$albumID';");
if (!$result) return false; if (!$result) return false;
} }
if (strlen($password)>0) return setAlbumPassword($albumID, $password); if (strlen($password)>0) return setAlbumPassword($albumID, $password);
else return true; return true;
} }
@ -329,10 +330,10 @@ function checkAlbumPassword($albumID, $password) {
$result = $database->query("SELECT password FROM lychee_albums WHERE id = '$albumID';"); $result = $database->query("SELECT password FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
if ($row->password=="") return true;
if ($row->password=="") return true;
else if ($row->password==$password) return true; else if ($row->password==$password) return true;
else return false; return false;
} }
@ -343,8 +344,9 @@ function isAlbumPublic($albumID) {
$result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';"); $result = $database->query("SELECT public FROM lychee_albums WHERE id = '$albumID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
if ($albumID==='0'||$albumID==='s'||$albumID==='f') return false;
if ($row->public==1) return true; if ($row->public==1) return true;
else return false; return false;
} }

View File

@ -15,52 +15,42 @@ function dbConnect() {
$database = new mysqli($dbHost, $dbUser, $dbPassword); $database = new mysqli($dbHost, $dbUser, $dbPassword);
if (mysqli_connect_errno()) { if ($database->connect_errno) exit('Error: ' . $database->connect_error);
echo mysqli_connect_errno().': '.mysqli_connect_error();
return false;
}
if (!$database->select_db($dbName))
if (!createDatabase($dbName, $database)) exit('Error: Could not create database!');
if (!$database->query("SELECT * FROM lychee_photos, lychee_albums, lychee_settings LIMIT 1;"))
if (!createTables($database)) exit('Error: Could not create tables!');
// Avoid sql injection on older MySQL versions // Avoid sql injection on older MySQL versions
if ($database->server_version<50500) $database->set_charset('GBK'); if ($database->server_version<50500) $database->set_charset('GBK');
if (!$database->select_db($dbName))
if (!dbCreate($dbName, $database)) exit('Error: Could not create database!');
if (!$database->query('SELECT * FROM lychee_photos, lychee_albums, lychee_settings LIMIT 0;'))
if (!dbCreateTables($database)) exit('Error: Could not create tables!');
return $database; return $database;
} }
function dbClose() { function dbCreateConfig($dbHost = 'localhost', $dbUser, $dbPassword, $dbName = 'lychee', $version) {
global $database;
if (!$database->close()) exit("Error: Closing the connection failed!");
return true;
}
function createConfig($dbHost = 'localhost', $dbUser, $dbPassword, $dbName = 'lychee') {
$dbPassword = urldecode($dbPassword); $dbPassword = urldecode($dbPassword);
$database = new mysqli($dbHost, $dbUser, $dbPassword); $database = new mysqli($dbHost, $dbUser, $dbPassword);
if (mysqli_connect_errno()||$dbUser=="") return "Warning: Connection failed!"; if ($database->connect_errno) return 'Warning: Connection failed!';
else { else {
$config = "<?php $config = "<?php
/** /**
* @name Config * @name Config
* @author Philipp Maurer
* @author Tobias Reich * @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich * @copyright 2014 Tobias Reich
*/ */
if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!'); if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
// Config version
\$configVersion = '';
// Database configurations // Database configurations
\$dbHost = '$dbHost'; //Host of the Database \$dbHost = '$dbHost'; //Host of the Database
\$dbUser = '$dbUser'; //Username of the database \$dbUser = '$dbUser'; //Username of the database
@ -69,8 +59,7 @@ if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
?>"; ?>";
if (file_put_contents("config.php", $config)===false) return "Warning: Could not create file!"; if (file_put_contents('../data/config.php', $config)===false) return 'Warning: Could not create file!';
else {
$_SESSION['login'] = true; $_SESSION['login'] = true;
return true; return true;
@ -79,9 +68,7 @@ if(!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
} }
} function dbCreate($dbName, $database) {
function createDatabase($dbName, $database) {
$result = $database->query("CREATE DATABASE IF NOT EXISTS $dbName;"); $result = $database->query("CREATE DATABASE IF NOT EXISTS $dbName;");
$database->select_db($dbName); $database->select_db($dbName);
@ -91,9 +78,9 @@ function createDatabase($dbName, $database) {
} }
function createTables($database) { function dbCreateTables($database) {
if (!$database->query("SELECT * FROM lychee_settings;")) { if (!$database->query('SELECT * FROM lychee_settings LIMIT 0;')) {
$query = " $query = "
@ -114,7 +101,8 @@ function createTables($database) {
('password',''), ('password',''),
('thumbQuality','90'), ('thumbQuality','90'),
('checkForUpdates','1'), ('checkForUpdates','1'),
('sorting','ORDER BY id DESC'); ('sorting','ORDER BY id DESC'),
('dropboxKey','');
"; ";
@ -122,7 +110,7 @@ function createTables($database) {
} }
if (!$database->query("SELECT * FROM lychee_albums;")) { if (!$database->query('SELECT * FROM lychee_albums LIMIT 0;')) {
$query = " $query = "
@ -142,7 +130,7 @@ function createTables($database) {
} }
if (!$database->query("SELECT * FROM lychee_photos;")) { if (!$database->query('SELECT * FROM lychee_photos LIMIT 0;')) {
$query = " $query = "
@ -151,6 +139,7 @@ function createTables($database) {
`title` varchar(50) NOT NULL, `title` varchar(50) NOT NULL,
`description` varchar(1000) NOT NULL DEFAULT '', `description` varchar(1000) NOT NULL DEFAULT '',
`url` varchar(100) NOT NULL, `url` varchar(100) NOT NULL,
`tags` varchar(1000) NOT NULL DEFAULT '',
`public` tinyint(1) NOT NULL, `public` tinyint(1) NOT NULL,
`type` varchar(10) NOT NULL, `type` varchar(10) NOT NULL,
`width` int(11) NOT NULL, `width` int(11) NOT NULL,
@ -183,4 +172,14 @@ function createTables($database) {
} }
function dbClose() {
global $database;
if (!$database->close()) exit('Error: Closing the connection failed!');
return true;
}
?> ?>

View File

@ -14,9 +14,8 @@ function openGraphHeader($photoID) {
global $database; global $database;
$photoID = mysqli_real_escape_string($database, $photoID); $photoID = mysqli_real_escape_string($database, $photoID);
if (!is_numeric($photoID)) return false;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';"); $result = $database->query("SELECT title, description, url FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
$parseUrl = parse_url("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); $parseUrl = parse_url("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
@ -44,31 +43,35 @@ function search($term) {
global $database, $settings; global $database, $settings;
$return["albums"] = ""; $return['albums'] = '';
$result = $database->query("SELECT * FROM lychee_photos WHERE title like '%$term%' OR description like '%$term%';"); // Photos
$result = $database->query("SELECT id, title, tags, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE title like '%$term%' OR description like '%$term%' OR tags like '%$term%';");
while($row = $result->fetch_array()) { while($row = $result->fetch_array()) {
$return['photos'][$row['id']] = $row; $return['photos'][$row['id']] = $row;
$return['photos'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate'])); $return['photos'][$row['id']]['sysdate'] = date('d F Y', strtotime($row['sysdate']));
} }
$result = $database->query("SELECT * FROM lychee_albums WHERE title like '%$term%';"); // Albums
$result = $database->query("SELECT id, title, public, sysdate, password FROM lychee_albums WHERE title like '%$term%' OR description like '%$term%';");
$i = 0; $i = 0;
while($row = $result->fetch_object()) { while($row = $result->fetch_object()) {
$return["albums"][$row->id]['id'] = $row->id; // Info
$return["albums"][$row->id]['title'] = $row->title; $return['albums'][$row->id]['id'] = $row->id;
$return["albums"][$row->id]['public'] = $row->public; $return['albums'][$row->id]['title'] = $row->title;
$return["albums"][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate)); $return['albums'][$row->id]['public'] = $row->public;
if ($row->password=="") $return["albums"][$row->id]['password'] = false; $return['albums'][$row->id]['sysdate'] = date('F Y', strtotime($row->sysdate));
else $return["albums"][$row->id]['password'] = true; $return['albums'][$row->id]['password'] = ($row->password=='' ? false : true);
// Thumbs
$result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '" . $row->id . "' " . $settings['sorting'] . " LIMIT 0, 3;"); $result2 = $database->query("SELECT thumbUrl FROM lychee_photos WHERE album = '" . $row->id . "' " . $settings['sorting'] . " LIMIT 0, 3;");
$k = 0; $k = 0;
while($row2 = $result2->fetch_object()){ while($row2 = $result2->fetch_object()){
$return['albums'][$row->id]["thumb$k"] = $row2->thumbUrl; $return['albums'][$row->id]["thumb$k"] = $row2->thumbUrl;
$k++; $k++;
} }
$i++; $i++;
} }
@ -77,19 +80,32 @@ function search($term) {
} }
function update() { function update($version = '') {
global $database; global $database, $configVersion;
if(!$database->query("SELECT `public` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `public` TINYINT( 1 ) NOT NULL DEFAULT '0'"); // Albums
if(!$database->query("SELECT `password` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `password` VARCHAR( 100 ) NULL DEFAULT ''"); if(!$database->query("SELECT `public` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `public` TINYINT( 1 ) NOT NULL DEFAULT '0'");
if(!$database->query("SELECT `description` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` ADD `description` VARCHAR( 1000 ) NULL DEFAULT ''"); if(!$database->query("SELECT `password` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `password` VARCHAR( 100 ) NULL DEFAULT ''");
if($database->query("SELECT `password` FROM `lychee_albums`;")) $database->query("ALTER TABLE `lychee_albums` CHANGE `password` `password` VARCHAR( 100 ) NULL DEFAULT ''"); if(!$database->query("SELECT `description` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` ADD `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if($database->query("SELECT `password` FROM `lychee_albums` LIMIT 1;")) $database->query("ALTER TABLE `lychee_albums` CHANGE `password` `password` VARCHAR( 100 ) NULL DEFAULT ''");
if($database->query("SELECT `description` FROM `lychee_photos`;")) $database->query("ALTER TABLE `lychee_photos` CHANGE `description` `description` VARCHAR( 1000 ) NULL DEFAULT ''"); // Photos
if($database->query("SELECT `shortlink` FROM `lychee_photos`;")) $database->query("ALTER TABLE `lychee_photos` DROP `shortlink`"); if($database->query("SELECT `description` FROM `lychee_photos` LIMIT 1;")) $database->query("ALTER TABLE `lychee_photos` CHANGE `description` `description` VARCHAR( 1000 ) NULL DEFAULT ''");
if(!$database->query("SELECT `tags` FROM `lychee_photos` LIMIT 1;")) $database->query("ALTER TABLE `lychee_photos` ADD `tags` VARCHAR( 1000 ) NULL DEFAULT ''");
$database->query("UPDATE `lychee_photos` SET url = replace(url, 'uploads/big/', ''), thumbUrl = replace(thumbUrl, 'uploads/thumb/', '')"); $database->query("UPDATE `lychee_photos` SET url = replace(url, 'uploads/big/', ''), thumbUrl = replace(thumbUrl, 'uploads/thumb/', '')");
// Settings
$result = $database->query("SELECT `key` FROM `lychee_settings` WHERE `key` = 'dropboxKey' LIMIT 1;");
if ($result->num_rows===0) $database->query("INSERT INTO `lychee_settings` (`key`, `value`) VALUES ('dropboxKey', '')");
// Config
if ($version!==''&&$configVersion!==$version) {
$data = file_get_contents('../data/config.php');
$data = preg_replace('/\$configVersion = \'[\w. ]*\';/', "\$configVersion = '$version';", $data);
if (file_put_contents('../data/config.php', $data)===false) return 'Error: Could not save updated config!';
}
return true; return true;
} }

View File

@ -13,20 +13,7 @@ function getPhoto($photoID, $albumID) {
global $database; global $database;
if (!is_numeric($photoID)) {
$result = $database->query("SELECT COUNT(*) AS quantity FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';");
$row = $result->fetch_object();
if ($row->quantity == 0) {
importPhoto($photoID, 's');
}
if (is_file("../uploads/import/$photoID")) {
importPhoto($photoID, 's');
}
$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID' ORDER BY ID DESC;";
} else {
$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';"; $query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
}
$result = $database->query($query); $result = $database->query($query);
$return = $result->fetch_array(); $return = $result->fetch_array();
@ -59,11 +46,7 @@ function setPhotoPublic($photoID, $url) {
$result = $database->query("SELECT public FROM lychee_photos WHERE id = '$photoID';"); $result = $database->query("SELECT public FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
if ($row->public == 0){ $public = ($row->public==0 ? 1 : 0);
$public = 1;
} else {
$public = 0;
}
$result = $database->query("UPDATE lychee_photos SET public = '$public' WHERE id = '$photoID';"); $result = $database->query("UPDATE lychee_photos SET public = '$public' WHERE id = '$photoID';");
if (!$result) return false; if (!$result) return false;
@ -71,42 +54,46 @@ function setPhotoPublic($photoID, $url) {
} }
function setPhotoStar($photoID) { function setPhotoStar($photoIDs) {
global $database; global $database;
$result = $database->query("SELECT star FROM lychee_photos WHERE id = '$photoID';"); $error = false;
$row = $result->fetch_object(); $result = $database->query("SELECT id, star FROM lychee_photos WHERE id IN ($photoIDs);");
if ($row->star == 0) {
$star = 1; while ($row = $result->fetch_object()) {
} else {
$star = 0; $star = ($row->star==0 ? 1 : 0);
$star = $database->query("UPDATE lychee_photos SET star = '$star' WHERE id = '$row->id';");
if (!$star) $error = true;
} }
$result = $database->query("UPDATE lychee_photos SET star = '$star' WHERE id = '$photoID';");
if ($error) return false;
return true; return true;
} }
function setAlbum($photoID, $newAlbum) { function setPhotoAlbum($photoIDs, $albumID) {
global $database; global $database;
$result = $database->query("UPDATE lychee_photos SET album = '$newAlbum' WHERE id = '$photoID';"); $result = $database->query("UPDATE lychee_photos SET album = '$albumID' WHERE id IN ($photoIDs);");
if (!$result) return false; if (!$result) return false;
else return true; return true;
} }
function setPhotoTitle($photoID, $title) { function setPhotoTitle($photoIDs, $title) {
global $database; global $database;
if (strlen($title)>30) return false; if (strlen($title)>50) return false;
$result = $database->query("UPDATE lychee_photos SET title = '$title' WHERE id = '$photoID';"); $result = $database->query("UPDATE lychee_photos SET title = '$title' WHERE id IN ($photoIDs);");
if (!$result) return false; if (!$result) return false;
else return true; return true;
} }
@ -115,7 +102,8 @@ function setPhotoDescription($photoID, $description) {
global $database; global $database;
$description = htmlentities($description); $description = htmlentities($description);
if (strlen($description)>800) return false; if (strlen($description)>1000) return false;
$result = $database->query("UPDATE lychee_photos SET description = '$description' WHERE id = '$photoID';"); $result = $database->query("UPDATE lychee_photos SET description = '$description' WHERE id = '$photoID';");
if (!$result) return false; if (!$result) return false;
@ -123,21 +111,47 @@ function setPhotoDescription($photoID, $description) {
} }
function deletePhoto($photoID) { function setPhotoTags($photoIDs, $tags) {
global $database; global $database;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';"); // Parse tags
if (!$result) return false; $tags = preg_replace('/(\ ,\ )|(\ ,)|(,\ )|(,{1,}\ {0,})|(,$|^,)/', ',', $tags);
$row = $result->fetch_object(); $tags = preg_replace('/,$|^,/', ',', $tags);
$retinaUrl = explode(".", $row->thumbUrl);
$unlink1 = unlink("../uploads/big/".$row->url);
$unlink2 = unlink("../uploads/thumb/".$row->thumbUrl);
$unlink3 = unlink("../uploads/thumb/".$retinaUrl[0].'@2x.'.$retinaUrl[1]);
$result = $database->query("DELETE FROM lychee_photos WHERE id = '$photoID';");
if (!$unlink1 || !$unlink2 || !$unlink3) return false;
if (!$result) return false;
if (strlen($tags)>1000) return false;
$result = $database->query("UPDATE lychee_photos SET tags = '$tags' WHERE id IN ($photoIDs);");
if (!$result) return false;
return true;
}
function deletePhoto($photoIDs) {
global $database;
$result = $database->query("SELECT id, url, thumbUrl FROM lychee_photos WHERE id IN ($photoIDs);");
while ($row = $result->fetch_object()) {
// Get retina thumb url
$thumbUrl2x = explode(".", $row->thumbUrl);
$thumbUrl2x = $thumbUrl2x[0] . '@2x.' . $thumbUrl2x[1];
// Delete files
if (!unlink('../uploads/big/' . $row->url)) return false;
if (!unlink('../uploads/thumb/' . $row->thumbUrl)) return false;
if (!unlink('../uploads/thumb/' . $thumbUrl2x)) return false;
// Delete db entry
$delete = $database->query("DELETE FROM lychee_photos WHERE id = $row->id;");
if (!$delete) return false;
}
if (!$result) return false;
return true; return true;
} }
@ -146,20 +160,17 @@ function isPhotoPublic($photoID, $password) {
global $database; global $database;
if (is_numeric($photoID)) { $query = "SELECT public, album FROM lychee_photos WHERE id = '$photoID';";
$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
} else {
$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';";
}
$result = $database->query($query); $result = $database->query($query);
$row = $result->fetch_object(); $row = $result->fetch_object();
if (!is_numeric($photoID)&&!$row) return true;
if ($row->public==1) return true; if ($row->public==1) return true;
else { else {
$cAP = checkAlbumPassword($row->album, $password); $cAP = checkAlbumPassword($row->album, $password);
$iAP = isAlbumPublic($row->album); $iAP = isAlbumPublic($row->album);
if ($iAP&&$cAP) return true; if ($iAP&&$cAP) return true;
else return false; return false;
} }
} }
@ -168,7 +179,7 @@ function getPhotoArchive($photoID) {
global $database; global $database;
$result = $database->query("SELECT * FROM lychee_photos WHERE id = '$photoID';"); $result = $database->query("SELECT title, url FROM lychee_photos WHERE id = '$photoID';");
$row = $result->fetch_object(); $row = $result->fetch_object();
$extension = array_reverse(explode('.', $row->url)); $extension = array_reverse(explode('.', $row->url));

View File

@ -9,9 +9,13 @@
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!'); if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
function init($mode) { function init($mode, $version) {
global $settings; global $settings, $configVersion;
// Update
if ($configVersion!==$version)
if (!update($version)) exit('Error: Updating the database failed!');
$return['config'] = $settings; $return['config'] = $settings;
unset($return['config']['password']); unset($return['config']['password']);
@ -26,6 +30,7 @@ function init($mode) {
unset($return['config']['username']); unset($return['config']['username']);
unset($return['config']['thumbQuality']); unset($return['config']['thumbQuality']);
unset($return['config']['sorting']); unset($return['config']['sorting']);
unset($return['config']['dropboxKey']);
unset($return['config']['login']); unset($return['config']['login']);
$return['loggedIn'] = false; $return['loggedIn'] = false;
} }

View File

@ -66,22 +66,18 @@ function setPassword($password) {
} }
/*function setCheckForUpdates() { function setDropboxKey($key) {
global $database; global $database;
$result = $database->query("SELECT value FROM lychee_settings WHERE `key` = 'checkForUpdates';"); if (strlen($key)<1||strlen($key)>50) return false;
$row = $result->fetch_object();
if ($row->value==0) $checkForUpdates = 1; $result = $database->query("UPDATE lychee_settings SET value = '$key' WHERE `key` = 'dropboxKey';");
else $checkForUpdates = 0;
$result = $database->query("UPDATE lychee_settings SET value = '$checkForUpdates' WHERE `key` = 'checkForUpdates';");
if (!$result) return false; if (!$result) return false;
return true; return true;
}*/ }
function setSorting($type, $order) { function setSorting($type, $order) {

View File

@ -11,7 +11,7 @@ if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
function upload($files, $albumID) { function upload($files, $albumID) {
global $database; global $database, $settings;
switch($albumID) { switch($albumID) {
// s for public (share) // s for public (share)
@ -33,34 +33,39 @@ function upload($files, $albumID) {
foreach ($files as $file) { foreach ($files as $file) {
if ($file['type']!=='image/jpeg'&&
$file['type']!=='image/png'&&
$file['type']!=='image/gif')
return false;
$id = str_replace('.', '', microtime(true)); $id = str_replace('.', '', microtime(true));
while(strlen($id)<14) $id .= 0; while(strlen($id)<14) $id .= 0;
$tmp_name = $file["tmp_name"]; $tmp_name = $file['tmp_name'];
$extension = array_reverse(explode('.', $file['name']));
$type = getimagesize($tmp_name); $extension = $extension[0];
if (($type[2]!=1)&&($type[2]!=2)&&($type[2]!=3)) return false; $photo_name = md5($id) . ".$extension";
$data = array_reverse(explode('.', $file["name"]));
$data = $data[0];
$photo_name = md5($id) . ".$data";
// Import if not uploaded via web // Import if not uploaded via web
if (!is_uploaded_file($tmp_name)) { if (!is_uploaded_file($tmp_name)) {
if (copy($tmp_name, "../uploads/big/" . $photo_name)) { if (copy($tmp_name, '../uploads/big/' . $photo_name)) {
unlink($tmp_name); @unlink($tmp_name);
$import_name = $tmp_name; $import_name = $tmp_name;
} }
} else { } else {
move_uploaded_file($tmp_name, "../uploads/big/" . $photo_name); move_uploaded_file($tmp_name, '../uploads/big/' . $photo_name);
$import_name = ""; $import_name = '';
} }
// Read infos // Read infos
$info = getInfo($photo_name); $info = getInfo($photo_name);
// Use title of file if IPTC title missing
if ($info['title']==='')
$info['title'] = mysqli_real_escape_string($database, substr(basename($file['name'], ".$extension"), 0, 30));
// Set orientation based on EXIF data // Set orientation based on EXIF data
if (isset($info['orientation'])&&isset($info['width'])&&isset($info['height'])) { if ($file['type']==='image/jpeg'&&isset($info['orientation'])&&isset($info['width'])&&isset($info['height'])) {
if ($info['orientation']==3||$info['orientation']==6||$info['orientation']==8) { if ($info['orientation']==3||$info['orientation']==6||$info['orientation']==8) {
@ -187,10 +192,10 @@ function getInfo($filename) {
$iptcInfo = iptcparse($iptcArray['APP13']); $iptcInfo = iptcparse($iptcArray['APP13']);
if (is_array($iptcInfo)) { if (is_array($iptcInfo)) {
$temp = $iptcInfo['2#105'][0]; $temp = @$iptcInfo['2#105'][0];
if (isset($temp)&&strlen($temp)>0) $return['title'] = $temp; if (isset($temp)&&strlen($temp)>0) $return['title'] = $temp;
$temp = $iptcInfo['2#120'][0]; $temp = @$iptcInfo['2#120'][0];
if (isset($temp)&&strlen($temp)>0) $return['description'] = $temp; if (isset($temp)&&strlen($temp)>0) $return['description'] = $temp;
} }
@ -208,33 +213,35 @@ function getInfo($filename) {
$return['takeDate'] = ''; $return['takeDate'] = '';
$return['takeTime'] = ''; $return['takeTime'] = '';
// Read EXIF
if ($info['mime']=='image/jpeg') $exif = exif_read_data($url, 'EXIF', 0);
else $exif = false;
// EXIF Metadata // EXIF Metadata
if ($info['mime']=='image/jpeg'&&function_exists('exif_read_data')&&@exif_read_data($url, 'EXIF', 0)) { if ($exif!==false) {
$exif = exif_read_data($url, 'EXIF', 0); $temp = @$exif['Orientation'];
$temp = $exif['Orientation'];
if (isset($temp)) $return['orientation'] = $temp; if (isset($temp)) $return['orientation'] = $temp;
$temp = $exif['ISOSpeedRatings']; $temp = @$exif['ISOSpeedRatings'];
if (isset($temp)) $return['iso'] = $temp; if (isset($temp)) $return['iso'] = $temp;
$temp = $exif['COMPUTED']['ApertureFNumber']; $temp = @$exif['COMPUTED']['ApertureFNumber'];
if (isset($temp)) $return['aperture'] = $temp; if (isset($temp)) $return['aperture'] = $temp;
$temp = $exif['Make']; $temp = @$exif['Make'];
if (isset($temp)) $return['make'] = $exif['Make']; if (isset($temp)) $return['make'] = $exif['Make'];
$temp = $exif['Model']; $temp = @$exif['Model'];
if (isset($temp)) $return['model'] = $temp; if (isset($temp)) $return['model'] = $temp;
$temp = $exif['ExposureTime']; $temp = @$exif['ExposureTime'];
if (isset($temp)) $return['shutter'] = $exif['ExposureTime'] . ' Sec.'; if (isset($temp)) $return['shutter'] = $exif['ExposureTime'] . ' Sec.';
$temp = $exif['FocalLength']; $temp = @$exif['FocalLength'];
if (isset($temp)) $return['focal'] = ($temp/1) . ' mm'; if (isset($temp)) $return['focal'] = ($temp/1) . ' mm';
$temp = $exif['DateTimeOriginal']; $temp = @$exif['DateTimeOriginal'];
if (isset($temp)) { if (isset($temp)) {
$exifDate = explode(' ', $temp); $exifDate = explode(' ', $temp);
$date = explode(':', $exifDate[0]); $date = explode(':', $exifDate[0]);
@ -259,8 +266,8 @@ function createThumb($filename, $width = 200, $height = 200) {
$info = getimagesize($url); $info = getimagesize($url);
$photoName = explode(".", $filename); $photoName = explode(".", $filename);
$newUrl = "../uploads/thumb/".$photoName[0].".jpeg"; $newUrl = "../uploads/thumb/$photoName[0].jpeg";
$newUrl2x = "../uploads/thumb/".$photoName[0]."@2x.jpeg"; $newUrl2x = "../uploads/thumb/$photoName[0]@2x.jpeg";
// Set position and size // Set position and size
$thumb = imagecreatetruecolor($width, $height); $thumb = imagecreatetruecolor($width, $height);
@ -297,21 +304,19 @@ function createThumb($filename, $width = 200, $height = 200) {
} }
function importPhoto($name, $albumID = 0) { function importPhoto($path, $albumID = 0) {
$info = getimagesize($path);
$size = filesize($path);
$tmp_name = "../uploads/import/$name";
$info = getimagesize($tmp_name);
$size = filesize($tmp_name);
$nameFile = array(array()); $nameFile = array(array());
$nameFile[0]['name'] = $name; $nameFile[0]['name'] = $path;
$nameFile[0]['type'] = $info['mime']; $nameFile[0]['type'] = $info['mime'];
$nameFile[0]['tmp_name'] = $tmp_name; $nameFile[0]['tmp_name'] = $path;
$nameFile[0]['error'] = 0; $nameFile[0]['error'] = 0;
$nameFile[0]['size'] = $size; $nameFile[0]['size'] = $size;
if (upload($nameFile, $albumID)) return true; return upload($nameFile, $albumID);
return false;
} }
@ -332,6 +337,7 @@ function importUrl($url, $albumID = 0) {
$pathinfo = pathinfo($key); $pathinfo = pathinfo($key);
$filename = $pathinfo['filename'].".".$pathinfo['extension']; $filename = $pathinfo['filename'].".".$pathinfo['extension'];
$tmp_name = "../uploads/import/$filename"; $tmp_name = "../uploads/import/$filename";
copy($key, $tmp_name); copy($key, $tmp_name);
} }
@ -351,8 +357,10 @@ function importUrl($url, $albumID = 0) {
$pathinfo = pathinfo($url); $pathinfo = pathinfo($url);
$filename = $pathinfo['filename'].".".$pathinfo['extension']; $filename = $pathinfo['filename'].".".$pathinfo['extension'];
$tmp_name = "../uploads/import/$filename"; $tmp_name = "../uploads/import/$filename";
copy($url, $tmp_name); copy($url, $tmp_name);
return importPhoto($filename, $albumID);
return importPhoto($tmp_name, $albumID);
} }
@ -362,23 +370,36 @@ function importUrl($url, $albumID = 0) {
} }
function importServer($albumID = 0) { function importServer($albumID = 0, $path = '../uploads/import/') {
global $database; global $database;
$i = 0; $files = glob($path . '*');
$files = glob('../uploads/import/*'); $contains['photos'] = false;
$contains['albums'] = false;
foreach ($files as $file) { foreach ($files as $file) {
if (@getimagesize($file)) { if (@getimagesize($file)) {
if (!importPhoto(basename($file), $albumID)) return false;
$i++; // Photo
if (!importPhoto($file, $albumID)) return false;
$contains['photos'] = true;
} else if (is_dir($file)) {
$name = mysqli_real_escape_string($database, basename($file));
$newAlbumID = addAlbum('[Import] ' . $name);
if ($newAlbumID!==false) importServer($newAlbumID, $file . '/');
$contains['albums'] = true;
} }
} }
if ($i===0) return "Warning: Folder empty!"; if ($contains['photos']===false&&$contains['albums']===false) return "Warning: Folder empty!";
if ($contains['photos']===false&&$contains['albums']===true) return "Notice: Import only contains albums!";
return true; return true;
} }

View File

@ -2,11 +2,9 @@
/** /**
* @name check.php * @name check.php
* @author Philipp Maurer
* @author Tobias Reich * @author Tobias Reich
* @copyright 2014 by Philipp Maurer, Tobias Reich * @copyright 2014 by Tobias Reich
* @description This file takes a look at your Lychee-configuration and displays all errors it can find. * @description This file takes a look at your Lychee-configuration and displays all errors it can find.
* Everything should work if you can see the message 'Lychee is ready!'.
*/ */
define('LYCHEE', true); define('LYCHEE', true);
@ -16,8 +14,8 @@ header('content-type: text/plain');
$error = ''; $error = '';
// Include // Include
if (!file_exists('../php/config.php')) exit('Error 001: Configuration not found. Please install Lychee first.'); if (!file_exists('../data/config.php')) exit('Error 001: Configuration not found. Please install Lychee first.');
require('../php/config.php'); require('../data/config.php');
require('../php/modules/settings.php'); require('../php/modules/settings.php');
// Database // Database
@ -35,6 +33,7 @@ if (!extension_loaded('exif')) $error .= ('Error 300: PHP exif extension not act
if (!extension_loaded('mbstring')) $error .= ('Error 301: PHP mbstring extension not activated' . PHP_EOL); if (!extension_loaded('mbstring')) $error .= ('Error 301: PHP mbstring extension not activated' . PHP_EOL);
if (!extension_loaded('gd')) $error .= ('Error 302: PHP gd extension not activated' . PHP_EOL); if (!extension_loaded('gd')) $error .= ('Error 302: PHP gd extension not activated' . PHP_EOL);
if (!extension_loaded('mysqli')) $error .= ('Error 303: PHP mysqli extension not activated' . PHP_EOL); if (!extension_loaded('mysqli')) $error .= ('Error 303: PHP mysqli extension not activated' . PHP_EOL);
if (!extension_loaded('json')) $error .= ('Error 304: PHP json extension not activated' . PHP_EOL);
// Config // Config
if (!isset($dbName)||$dbName=='') $error .= ('Error 400: No property for $dbName in config.php' . PHP_EOL); if (!isset($dbName)||$dbName=='') $error .= ('Error 400: No property for $dbName in config.php' . PHP_EOL);
@ -45,21 +44,22 @@ if (!isset($dbHost)||$dbHost=='') $error .= ('Error 403: No property for $dbHost
// Database Config // Database Config
if (!$settings['username']||$settings['username']=='') $error .= ('Error 404: Username empty or not set' . PHP_EOL); if (!$settings['username']||$settings['username']=='') $error .= ('Error 404: Username empty or not set' . PHP_EOL);
if (!$settings['password']||$settings['password']=='') $error .= ('Error 405: Password empty or not set' . PHP_EOL); if (!$settings['password']||$settings['password']=='') $error .= ('Error 405: Password empty or not set' . PHP_EOL);
if (!$settings['checkForUpdates']||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error 406: No or wrong property for checkForUpdates' . PHP_EOL);
if (!$settings['thumbQuality']||$settings['thumbQuality']=='') $error .= ('Error 407: No or wrong property for thumbQuality' . PHP_EOL); if (!$settings['thumbQuality']||$settings['thumbQuality']=='') $error .= ('Error 407: No or wrong property for thumbQuality' . PHP_EOL);
if (!$settings['sorting']||$settings['sorting']=='') $error .= ('Error 408: Wrong property for sorting' . PHP_EOL); if (!$settings['sorting']||$settings['sorting']=='') $error .= ('Error 408: Wrong property for sorting' . PHP_EOL);
if (!$settings['dropboxKey']) $error .= ('Error 409: No property for dropboxKey' . PHP_EOL);
if (!$settings['checkForUpdates']||($settings['checkForUpdates']!='0'&&$settings['checkForUpdates']!='1')) $error .= ('Error 406: No or wrong property for checkForUpdates' . PHP_EOL);
// Permissions // Permissions
if (substr(sprintf('%o', @fileperms('../uploads/big/')), -4)!='0777') $error .= ('Error 500: Wrong permissions for \'uploads/big\' (777 required)' . PHP_EOL); if (substr(sprintf('%o', @fileperms('../uploads/big/')), -4)!='0777') $error .= ('Error 500: Wrong permissions for \'uploads/big\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/thumb/')), -4)!='0777') $error .= ('Error 501: Wrong permissions for \'uploads/thumb\' (777 required)' . PHP_EOL); if (substr(sprintf('%o', @fileperms('../uploads/thumb/')), -4)!='0777') $error .= ('Error 501: Wrong permissions for \'uploads/thumb\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/import/')), -4)!='0777')$error .= ('Error 502: Wrong permissions for \'uploads/import\' (777 required)' . PHP_EOL); if (substr(sprintf('%o', @fileperms('../uploads/import/')), -4)!='0777')$error .= ('Error 502: Wrong permissions for \'uploads/import\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../uploads/')), -4)!='0777') $error .= ('Error 503: Wrong permissions for \'uploads/\' (777 required)' . PHP_EOL); if (substr(sprintf('%o', @fileperms('../uploads/')), -4)!='0777') $error .= ('Error 503: Wrong permissions for \'uploads/\' (777 required)' . PHP_EOL);
if (substr(sprintf('%o', @fileperms('../php/')), -4)!='0777') $error .= ('Error 504: Wrong permissions for \'php/\' (777 required)' . PHP_EOL); if (substr(sprintf('%o', @fileperms('../data/')), -4)!='0777') $error .= ('Error 504: Wrong permissions for \'data/\' (777 required)' . PHP_EOL);
if ($error=='') echo('Lychee is ready. Lets rock!' . PHP_EOL . PHP_EOL); else echo $error; if ($error=='') echo('Everything is fine. Lychee should work without problems!' . PHP_EOL . PHP_EOL); else echo $error;
// Check php.ini Settings // Check php.ini Settings
if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')!==true) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL); if (ini_get('max_execution_time')<200&&ini_set('upload_max_filesize', '20M')===false) echo('Warning: You may experience problems when uploading a large amount of photos. Take a look in the FAQ for details.' . PHP_EOL);
// Check mysql version // Check mysql version
if ($database->server_version<50500) echo('Warning: Lychee uses the GBK charset to avoid sql injections on your MySQL version. Please update to MySQL 5.5 or higher to enable UTF-8 support.' . PHP_EOL); if ($database->server_version<50500) echo('Warning: Lychee uses the GBK charset to avoid sql injections on your MySQL version. Please update to MySQL 5.5 or higher to enable UTF-8 support.' . PHP_EOL);

View File

@ -9,7 +9,7 @@ Lychee is a free photo-management tool, which runs on your server or web-space.
## Installation ## Installation
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation &#187;](docs/md/Installation.md) To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database. Follow the instructions to install Lychee on your server. [Installation &#187;](docs/Installation.md)
## How to use ## How to use
@ -17,20 +17,23 @@ You can use Lychee right after the installation. Here are some advanced features
### Settings ### Settings
Sign in and click the gear on the top left corner to change your settings. If you want to edit them manually: MySQL details are stored in `php/config.php`. Other options and settings are stored directly in the database. [Settings &#187;](docs/md/Settings.md) Sign in and click the gear on the top left corner to change your settings. If you want to edit them manually: MySQL details are stored in `data/config.php`. Other options and hidden settings are stored directly in the database. [Settings &#187;](docs/Settings.md)
### Update ### Update
1. Replace all files, excluding `uploads/` Updating is as easy as it should be. [Update &#187;](docs/Update.md)
2. Open Lychee and enter your database details
### FTP Upload ### Build
You can import photos from your server or upload photos directly with every FTP client into Lychee. [FTP Upload &#187;](docs/md/FTP Upload.md) Lychee is ready to use, right out of the box. If you want to contribute and edit CSS or JS files, you need to rebuild Lychee. [Build &#187;](docs/Build.md)
### Keyboard Shortcuts ### Keyboard Shortcuts
These shortcuts will help you to use Lychee even faster. [Keyboard Shortcuts &#187;](docs/md/Keyboard Shortcuts.md) These shortcuts will help you to use Lychee even faster. [Keyboard Shortcuts &#187;](docs/Keyboard Shortcuts.md)
### Dropbox import
In order to use the Dropbox import from your server, you need a valid drop-ins app key from [their website](https://www.dropbox.com/developers/apps/create). Lychee will ask you for this key, the first time you try to use the import. Want to change your code? Take a loot at [the settings](docs/Settings.md) of Lychee.
### Twitter Cards ### Twitter Cards
@ -38,7 +41,7 @@ Lychee supports [Twitter Cards](https://dev.twitter.com/docs/cards) and [Open Gr
## Troubleshooting ## Troubleshooting
Take a look at the [FAQ](docs/md/FAQ.md) if you have problems. Take a look at the [FAQ](docs/FAQ.md) if you have problems.
## Extensions ## Extensions
@ -53,6 +56,10 @@ Take a look at the [FAQ](docs/md/FAQ.md) if you have problems.
| 1.2, 1.3, 2.x | [Tobias Reich](http://electerious.com)| | 1.2, 1.3, 2.x | [Tobias Reich](http://electerious.com)|
| 1.0, 1.1 | [Tobias Reich](http://electerious.com)<br>[Philipp Maurer](http://phinal.net) | | 1.0, 1.1 | [Tobias Reich](http://electerious.com)<br>[Philipp Maurer](http://phinal.net) |
## Donate
I am working hard on continuously developing and maintaining Lychee. Please consider making a donation via [Flattr](https://flattr.com/submit/auto?user_id=electerious&url=http%3A%2F%2Flychee.electerious.com&title=Lychee&category=software) or PayPal (from [our site](http://lychee.electerious.com/)) to keep the project going strong and me motivated.
## License ## License
(MIT License) (MIT License)

View File

@ -9,10 +9,9 @@
<meta name="keywords" content=""> <meta name="keywords" content="">
<meta name="description" content=""> <meta name="description" content="">
<link type="text/css" rel="stylesheet" href="assets/css/min/reset.css"> <link type="text/css" rel="stylesheet" href="assets/build/main.css">
<link type="text/css" rel="stylesheet" href="assets/css/min/main.css">
<link rel="shortcut icon" href="assets/img/favicon.ico"> <link rel="shortcut icon" href="favicon.ico">
<meta name="apple-mobile-web-app-status-bar-style" content="black" > <meta name="apple-mobile-web-app-status-bar-style" content="black" >
<meta name="viewport" content="user-scalable=no, initial-scale=1"> <meta name="viewport" content="user-scalable=no, initial-scale=1">
@ -24,7 +23,7 @@
define("LYCHEE", true); define("LYCHEE", true);
require("php/config.php"); require("data/config.php");
require("php/modules/db.php"); require("php/modules/db.php");
require("php/modules/misc.php"); require("php/modules/misc.php");
@ -57,10 +56,9 @@
<div id="infobox"></div> <div id="infobox"></div>
<!-- JS --> <!-- JS -->
<script type="text/javascript" src="assets/js/min/frameworks.js"></script> <script type="text/javascript" src="assets/js/_frameworks.js"></script>
<script type="text/javascript" src="assets/js/modules/build.js"></script> <script type="text/javascript" src="assets/js/build.js"></script>
<script type="text/javascript" src="assets/js/view.js"></script> <script type="text/javascript" src="assets/js/view/main.js"></script>
</body> </body>
</html> </html>