Browse Source

V1.3

New:
- Protect public albums with passwords
- Export to Dropbox
- Sharing-Link is displayed directly inside the sharing-dropdown
- Delete photos with cmd+backspace

Improved:
- Massive speed improvements
- Changing the title, starring, description, etc. is now instant
- Longer filenames for pictures (more security)

ShortLinks are removed for more independency and privacy.
There are a lot of changes under the hood, including a lot of bug fixes and improvements. Please report every bug you find!

How to update:
1. Replace all files, excluding `uploads/` and `php/config.php`
2. Open `php/update.php` in your browser
Tobias Reich 10 years ago
parent
commit
34413640e4
25 changed files with 2090 additions and 1049 deletions
  1. 0 22
      css/animations.css
  2. 50 37
      css/style.css
  3. 21 17
      index.html
  4. 0 1
      js/frameworks.js
  5. 0 0
      js/functions.js
  6. 71 59
      js/main.js
  7. 244 0
      js/modules/album.js
  8. 55 298
      js/modules/albums.js
  9. 76 72
      js/modules/build.js
  10. 139 57
      js/modules/contextMenu.js
  11. 5 5
      js/modules/loadingBar.js
  12. 131 208
      js/modules/lychee.js
  13. 37 0
      js/modules/modal.js
  14. 105 0
      js/modules/password.js
  15. 403 0
      js/modules/photo.js
  16. 27 10
      js/modules/search.js
  17. 395 0
      js/modules/view.js
  18. 18 3
      js/modules/visible.js
  19. 9 7
      js/view.js
  20. 25 18
      php/api.php
  21. 0 2
      php/config.php
  22. 271 223
      php/functions.php
  23. 1 0
      php/update.php
  24. 5 8
      readme.md
  25. 2 2
      view.php

+ 0 - 22
css/animations.css

@@ -427,28 +427,6 @@
 	}
 }
 
-/* shake ------------------------------------------------*/
-@-webkit-keyframes shake {
-	0%, 100% { -webkit-transform: translateX(0); }
-	10%, 30%, 50%, 70%, 90% { -webkit-transform: translateX(-10px); }
-	20%, 40%, 60%, 80% { -webkit-transform: translateX(10px); }
-}
-@-moz-keyframes shake {
-	0%, 100% { -moz-transform: translateX(0);}
-	10%, 30%, 50%, 70%, 90% { -moz-transform: translateX(-10px); }
-	20%, 40%, 60%, 80% { -moz-transform: translateX(10px); }
-}
-@-o-keyframes shake {
-	0%, 100% { -o-transform: translateX(0);}
-	10%, 30%, 50%, 70%, 90% { -o-transform: translateX(-10px); }
-	20%, 40%, 60%, 80% { -o-transform: translateX(10px); }
-}
-@keyframes shake {
-	0%, 100% { transform: translateX(0);}
-	10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
-	20%, 40%, 60%, 80% { transform: translateX(10px); }
-}
-
 /* pulse ------------------------------------------------*/
 @-webkit-keyframes pulse {
 	0% {

+ 50 - 37
css/style.css

@@ -167,23 +167,6 @@ body { background-color: #222; background-image: url(../img/background.jpg); fon
 	animation-duration: .3s;
 	animation-fill-mode: forwards;
 }
-.shake {
-	-webkit-animation-name: shake;
-	-webkit-animation-duration: 1s;
-	-webkit-animation-timing-function: ease-out;
-	-webkit-animation-fill-mode: forwards;
-	-moz-animation-name: shake;
-	-moz-animation-duration: .3s;
-	-moz-animation-fill-mode: forwards;
-	-o-animation-name: shake;
-	-o-animation-duration: 1s;
-	-o-animation-timing-function: ease-out;
-	-o-animation-fill-mode: forwards;
-	animation-name: shake;
-	animation-duration: 1s;
-	animation-timing-function: ease-out;
-	animation-fill-mode: forwards;
-}
 
 /* Loading ------------------------------------------------*/
 #loading {
@@ -440,7 +423,7 @@ header {
 		position: absolute;
 		width: 200px;
 		height: 200px;
-		background-image: url(../img/checks.png);
+		background-color: #222;
 		border-radius: 3px;
 		box-shadow: 0px 1px 5px #111;
 		border: 3px solid #ccc;
@@ -483,7 +466,7 @@ header {
 		position: absolute;
 		width: 200px;
 		height: 200px;
-		background-image: url(../img/checks.png);
+		background-color: #222;
 		border-radius: 3px;
 		box-shadow: 0px 1px 5px #111;
 		border: 3px solid #ccc;
@@ -504,7 +487,6 @@ header {
 		background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* Opera 11.10+ */
 		background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* IE10+ */
 		background: linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 20%,rgba(0,0,0,0.9) 100%); /* W3C */
-		filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#e6000000',GradientType=0 ); /* IE6-9 */
 	}
 	.photo .overlay {
 		opacity: 0;
@@ -569,7 +551,6 @@ header {
 		background: -o-linear-gradient(top, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 100%); /* Opera 11.10+ */
 		background: -ms-linear-gradient(top, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 100%); /* IE10+ */
 		background: linear-gradient(top, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 100%); /* W3C */
-		filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#00000000',GradientType=0 ); /* IE6-9 */
 		opacity: .4;
 	}
 	.album .badge.icon-star::after {
@@ -740,6 +721,9 @@ header {
 		text-shadow: 0px -1px 0px #222;
 		line-height: 20px;
 	}
+	.message p b {
+		font-weight: bold;
+	}
 	.message .button {
 		float: right;
 		margin: 15px 15px 15px 0px;
@@ -882,24 +866,27 @@ header {
 		color: #888;
 	}
 
-	/* Copy Link ------------------------------------------------*/
-	.copylink {
+	/* Copy Link, Password ------------------------------------------------*/
+	.message .copylink, .message .password {
 		float: left;
 		width: 95%;
 		padding: 7px 10px 9px 10px;
-		margin-top: 10px;
+		margin-top: 20px;
 		background-color: #444;
 		color: #fff;
 		text-shadow: 0px 1px 0px #222;
 		border: none;
 		border: 1px solid #111;
-		box-shadow: 0px 1px 0px #777;
+		box-shadow: 0px 1px 0px #666, inset 0px 0px 3px #333, 0px 0px 5px #005ecc;
 		outline: none;
 		border-radius: 5px;
 	}
+	.message .copylink {
+		margin-bottom: 20px;
+	}
 
 /* Image View ------------------------------------------------*/
-#image_view {
+#imageview {
 	position: fixed;
 	display: none;
 	width: 100%;
@@ -908,11 +895,11 @@ header {
 	box-shadow: 0px 2px 4px #000;
 	-webkit-transition: background-color .3s;
 }
-#image_view.full {
+#imageview.full {
 	background-color: #111;
 }
 
-#image_view #image {
+#imageview #image {
 	position: absolute;
 	top: 70px;
 	right: 30px;
@@ -936,7 +923,7 @@ header {
 	animation-duration: .3s;
 	animation-fill-mode: forwards;
 }
-#image_view #image.small {
+#imageview #image.small {
 	top: 50%;
 	right: auto;
 	bottom: auto;
@@ -944,7 +931,7 @@ header {
 }
 
 	/* Previous/Next Buttons ------------------------------------------------*/
-	#image_view a {
+	#imageview a {
 		position: fixed;
 		top:  50%;
 		margin-top: -10px;
@@ -955,21 +942,21 @@ header {
 		opacity: .1;
 		z-index: 1;
 	}
-	#image_view a:hover {
+	#imageview a:hover {
 		opacity: .9;
 	}
-	#image_view a#previous {
+	#imageview a#previous {
 		left: 20px;
 		-webkit-transition: left .3s;
 	}
-	#image_view.full a#previous {
+	#imageview.full a#previous {
 		left: -50px;
 	}
-	#image_view a#next {
+	#imageview a#next {
 		right: 20px;
 		-webkit-transition: right .3s
 	}
-	#image_view.full a#next {
+	#imageview.full a#next {
 		right: -50px;
 	}
 
@@ -1153,6 +1140,11 @@ header {
 		background-image: -ms-linear-gradient(top, #6a84f2, #3959ef);
 		background-image: linear-gradient(top, #6a84f2, #3959ef);
 	}
+	.contextmenu tr.no_hover:hover {
+		cursor: inherit;
+		background-color: inherit;
+		background-image: none;
+	}
 	.contextmenu tr.separator {
 		float: left;
 		height: 1px;
@@ -1178,6 +1170,9 @@ header {
 		box-shadow: inset 0px 1px 0px rgba(255,255,255,.1);
 		text-shadow: 0px -1px 0px rgba(0,0,0,.7);
 	}
+	.contextmenu tr.no_hover:hover td {
+		box-shadow: none;
+	}
 	.contextmenu tr a {
 		float: left;
 		width: 10px;
@@ -1185,6 +1180,24 @@ header {
 		text-align: center;
 	}
 
+	/* Direct Link Input ------------------------------------------------*/
+	.contextmenu #link {
+		float: right;
+		width: 140px;
+		margin: 0px -10px -1px 0px;
+		padding: 4px 6px 5px 6px;
+		background-color: #444;
+		color: #fff;
+		border: none;
+		border: 1px solid #111;
+		box-shadow: 0px 1px 0px rgba(255,255,255,.1);
+		outline: none;
+		border-radius: 5px;
+	}
+	.contextmenu tr a#link_icon {
+		padding-top: 4px;
+	}
+
 /* Upload ------------------------------------------------*/
 #upload {
 	display: none;
@@ -1327,7 +1340,7 @@ header {
 /* Screen behavior -------------------------------------------------*/
 @media only screen and (max-width: 900px) {
 
-	#title { margin: 0px 30%; width: 50%; }
+	#title { margin: 0px 20%; width: 40%; }
 	#title.view { margin: 11px 20% 0px 20%; width: 60%;	}
 	#title span { display: none; }
 
@@ -1372,7 +1385,7 @@ header {
 		height: 100px;
 		margin: 30px 5% -10px 5%;
 	}
-	
+
 	.add_album .icon {
 		margin-top: 18px;
 		font-size: 50px;

+ 21 - 17
index.html

@@ -66,7 +66,7 @@
 	<div id="content"></div>
 
 	<!-- ImageView -->
-	<div id="image_view"></div>
+	<div id="imageview"></div>
 
 	<!-- Infobox -->
 	<div id="infobox"></div>
@@ -79,22 +79,26 @@
 	</div>
 
 	<!-- JS -->
-	<script type="text/javascript" src="js/frameworks.js"></script>
-
-		<!-- Development
-		<script type="text/javascript" src="js/modules/lychee.js"></script>
-		<script type="text/javascript" src="js/modules/build.js"></script>
-		<script type="text/javascript" src="js/modules/albums.js"></script>
-		<script type="text/javascript" src="js/modules/photos.js"></script>
-		<script type="text/javascript" src="js/modules/visible.js"></script>
-		<script type="text/javascript" src="js/modules/loadingBar.js"></script>
-		<script type="text/javascript" src="js/modules/contextMenu.js"></script>
-		<script type="text/javascript" src="js/modules/search.js"></script> -->
-
-		<!-- Production -->
-		<script type="text/javascript" src="js/functions.js"></script>
-
-	<script type="text/javascript" src="js/main.js"></script>
+	<script defer type="text/javascript" src="js/frameworks.js"></script>
+
+	<!-- Development
+	<script defer type="text/javascript" src="js/modules/lychee.js"></script>
+	<script defer type="text/javascript" src="js/modules/build.js"></script>
+	<script defer type="text/javascript" src="js/modules/view.js"></script>
+	<script defer type="text/javascript" src="js/modules/password.js"></script>
+	<script defer type="text/javascript" src="js/modules/modal.js"></script>
+	<script defer type="text/javascript" src="js/modules/album.js"></script>
+	<script defer type="text/javascript" src="js/modules/albums.js"></script>
+	<script defer type="text/javascript" src="js/modules/photo.js"></script>
+	<script defer type="text/javascript" src="js/modules/visible.js"></script>
+	<script defer type="text/javascript" src="js/modules/loadingBar.js"></script>
+	<script defer type="text/javascript" src="js/modules/contextMenu.js"></script>
+	<script defer type="text/javascript" src="js/modules/search.js"></script> -->
+
+	<!-- Production -->
+	<script defer type="text/javascript" src="js/functions.js"></script>
+
+	<script defer type="text/javascript" src="js/main.js"></script>
 
 	</body>
 </html>

File diff suppressed because it is too large
+ 0 - 1
js/frameworks.js


File diff suppressed because it is too large
+ 0 - 0
js/functions.js


+ 71 - 59
js/main.js

@@ -5,77 +5,87 @@
  * @copyright   2013 by Philipp Maurer, Tobias Reich
  */
 
-/* Modules */
-lychee.init("php/api.php", "");
-
 $(document).ready(function(){
 
+	/* Init */
+	lychee.init();
+
 	/* Event Name */
-	if (mobileBrowser()) event_name = "touchend";
-	else event_name = "click";
+	var event_name = (mobileBrowser()) ? "touchend" : "click";
 
-	/* Toolbar */
-	$("#button_signout").on(event_name, lychee.logout);
-	$("#button_download").on(event_name, function() {
-		link = $("#image_view #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
-		window.open(link,"_newtab");
-	});
+	/* Notifications */
+	if (window.webkitNotifications) window.webkitNotifications.requestPermission();
+
+	/* Tooltips */
+	if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n'});
+
+	/* Header */
 	$("#button_share").on(event_name, function(e) {
-		if ($("#button_share a.active").length) contextMenu.share(lychee.image_view.attr("data-id"), e.pageX, e.pageY);
-		else photos.setPublic(e);
+		if (photo.json.public==1||photo.json.public==2) contextMenu.sharePhoto(photo.getID(), e);
+		else photo.setPublic(photo.getID(), e);
 	});
 	$("#button_share_album").on(event_name, function(e) {
-		if ($("#button_share_album a.active").length) contextMenu.share_album(lychee.content.attr("data-id"), e.pageX, e.pageY);
-		else albums.setPublic(e);
+		if (album.json.public==1) contextMenu.shareAlbum(album.getID(), e);
+		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?", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]]);
 	});
-	$("#button_trash_album").on(event_name, function() { albums.deleteDialog(lychee.content.attr("data-id")) });
-	$("#button_move").on(event_name, function(e) { contextMenu.move(lychee.image_view.attr("data-id"), e.pageX, e.pageY) });
-	$("#button_trash").on(event_name, function() { photos.deleteDialog() });
-	$("#button_edit_album").on(event_name, function() { albums.setTitle() });
-	$("#button_edit").on(event_name, function() { photos.setTitle() });
-	$("#button_info").on(event_name, function() { photos.showInfobox() });
-	$("#button_archive").on(event_name, function() { albums.getArchive() });
-	$("#button_star").on(event_name, function() { photos.setStar() });
-	$(".copylink").on(event_name, function() { $(this).select() });
+	$("#button_signout").on(event_name, lychee.logout);
+	$("#button_download").on(event_name, function() { window.open(photo.getDirectLink(),"_newtab") });
+	$("#button_trash_album").on(event_name, function() { album.delete(album.getID()) });
+	$("#button_move").on(event_name, function(e) { contextMenu.move(photo.getID(), e) });
+	$("#button_trash").on(event_name, function() { photo.delete() });
+	$("#button_edit_album").on(event_name, function() { album.setTitle() });
+	$("#button_edit").on(event_name, function() { photo.setTitle(photo.getID()) });
+	$("#button_info").on(event_name, function() { view.photo.showInfobox() });
+	$("#button_archive").on(event_name, function() { album.getArchive(album.getID()) });
+	$("#button_star").on(event_name, function() { photo.setStar(photo.getID()) });
 
 	/* Search */
 	$("#search").on("keyup click", function() { search.find($(this).val()) });
 
 	/* Back Buttons */
 	$("#button_back_home").on(event_name, function() { lychee.goto("") });
-	$("#button_back").on(event_name, function() { lychee.goto("a" + lychee.content.attr("data-id")) });
+	$("#button_back").on(event_name, function() { lychee.goto("a" + album.getID()) });
 
 	/* Image View */
-	$("#image_view")
-		.on(event_name, "a#previous", photos.previous)
-		.on(event_name, "a#next", photos.next);
+	lychee.imageview
+		.on(event_name, "a#previous", function() {
+			if (photo.json&&photo.json.previousPhoto) lychee.goto("a" + album.getID() + "p" + photo.json.previousPhoto)
+		})
+		.on(event_name, "a#next", function() {
+			if (photo.json&&photo.json.nextPhoto) lychee.goto("a" + album.getID() + "p" + photo.json.nextPhoto)
+		});
 
 	/* Infobox */
 	$("#infobox")
-		.on(event_name, ".header a", function() { photos.hideInfobox() })
-		.on(event_name, "#edit_title", function() { photos.setTitle() })
-		.on(event_name, "#edit_description", function() { photos.setDescription() });
+		.on(event_name, ".header a", function() { view.photo.hideInfobox() })
+		.on(event_name, "#edit_title", function() { photo.setTitle(photo.getID()) })
+		.on(event_name, "#edit_description", function() { photo.setDescription(photo.getID()) });
 
 	/* Keyboard */
 	Mousetrap
-		.bind('n', function(e) { $("body").append(build.addModal) })
+		.bind('n', function(e) { if (!visible.message()) $("body").append(build.addModal) })
 		.bind('u', function(e) { $("#auswahl").html(""); $("#upload_files").click() })
-		.bind('s', function(e) { if (visible.imageview()) $("#button_star").click() })
-		.bind('f', function(e) { if (visible.imageview()) $("#button_download").click() })
-		.bind('i', function(e) { if (visible.imageview()) photos.showInfobox() })
-		.bind('backspace', function(e) { if (visible.imageview()) photos.deleteDialog() })
-		.bind('left', function(e) { if (visible.imageview()) photos.previous() })
-		.bind('right', function(e) { if (visible.imageview()) photos.next() });
+		.bind('s', function(e) { if (visible.photo()) $("#button_star").click() })
+		.bind('f', function(e) { if (visible.photo()) $("#button_download").click() })
+		.bind('command+backspace', function(e) { if (visible.photo()&&!visible.message()) photo.delete() })
+		.bind('left', function(e) { if (visible.photo()) $("#imageview a#previous").click() })
+		.bind('right', function(e) { if (visible.photo()) $("#imageview a#next").click() })
+		.bind('i', function(e) {
+			if (visible.infobox()) view.photo.hideInfobox();
+			else if (visible.photo()) view.photo.showInfobox();
+		});
 
 	Mousetrap.bindGlobal('enter', function(e) {
 		if ($(".message .button.active").length) $(".message .button.active").addClass("pressed").click()
 	});
 
-	Mousetrap.bindGlobal('esc', function(e) {
+	Mousetrap.bindGlobal(['esc', 'command+up'], function(e) {
 		e.preventDefault();
-		if ($(".message").length) lychee.closeModal();
-		else if (visible.infobox()) photos.hideInfobox();
-		else if (visible.imageview()) lychee.goto("a" + lychee.content.attr("data-id"));
+		if (visible.message()) modal.close();
+		else if (visible.contextMenu()) contextMenu.close();
+		else if (visible.infobox()) view.photo.hideInfobox();
+		else if (visible.photo()) lychee.goto("a" + album.getID());
+		else if (visible.album()) lychee.goto("");
 		else if (visible.albums()&&$("#search").val().length!=0) search.reset();
 	});
 
@@ -83,30 +93,32 @@ $(document).ready(function(){
 	$(document)
 
 		/* Login */
-		.on(event_name, "#button_signin", function() { lychee.showLogin() })
+		.on(event_name, "#button_signin", function() { lychee.loginDialog() })
 		.on("keyup", "#password", function() { if ($(this).val().length>0) $(this).removeClass("error") })
 
-		/* Toolbar */
-		.on(event_name, "#title.editable", function() { if (visible.imageview()) photos.setTitle(); else albums.setTitle(); })
+		/* Header */
+		.on(event_name, "#title.editable", function() {
+			if (visible.photo()) photo.setTitle(photo.getID());
+			else album.setTitle();
+		})
 
 		/* Navigation */
 		.on("click", ".album", function() { lychee.goto("a" + $(this).attr("data-id")) })
-		.on("click", ".photo", function() {
-			if (lychee.content.attr("data-id")!="") lychee.goto("a" + lychee.content.attr("data-id") + "p" + $(this).attr("data-id"));
-			else lychee.goto("a" + $(this).attr("data-album-id") + "p" + $(this).attr("data-id"));
-		})
+		.on("click", ".photo", function() { lychee.goto("a" + album.getID() + "p" + $(this).attr("data-id")) })
 
 		/* Modal */
-		.on(event_name, ".message .close", lychee.closeModal)
+		.on(event_name, ".message .close", modal.close)
+		.on(event_name, ".message .button:first", function() { modal.fns[0](); modal.close(); })
+		.on(event_name, ".message .button:last", function() { modal.fns[1](); modal.close(); })
 
 		/* Add Dialog */
 		.on(event_name, ".button_add", function() { $("body").append(build.addModal) })
-		.on(event_name, "#add_album", albums.add)
-		.on(event_name, "#add_link", lychee.importUrl)
+		.on(event_name, "#add_album", album.add)
+		.on(event_name, "#add_link", function() { photo.add.url() })
 		.on(event_name, "#add_photo", function() { $("#auswahl").html(""); $("#upload_files").click() })
 
 		/* Upload */
-		.on("change", "#upload_files", function() { lychee.closeModal(); lychee.upload(this.files); })
+		.on("change", "#upload_files", function() { modal.close(); photo.add.files(this.files); })
 
 		/* Context Menu */
 		.on("contextmenu", ".photo", contextMenu.photo)
@@ -114,22 +126,22 @@ $(document).ready(function(){
 		.on(event_name, ".contextmenu_bg", contextMenu.close)
 
 		/* Infobox */
-		.on(event_name, "#infobox_overlay", function() { photos.hideInfobox() })
+		.on(event_name, "#infobox_overlay", function() { view.photo.hideInfobox() })
 
 		/* Controls */
-		.bind("mouseenter", lychee.showControls)
-		.bind("mouseleave", lychee.hideControls)
+		.bind("mouseenter", view.header.show)
+		.bind("mouseleave", view.header.hide)
 
 		/* Upload */
 		.on("dragover", function(e) { e.preventDefault(); }, false)
 		.on("drop", function(e) {
 			e.stopPropagation();
 			e.preventDefault();
-			lychee.upload(e.originalEvent.dataTransfer.files);
+			photo.add.files(e.originalEvent.dataTransfer.files);
 			return true;
 		});
 
-	/* Init */
-	lychee.ready();
+	/* Run */
+	lychee.run();
 
 });

+ 244 - 0
js/modules/album.js

@@ -0,0 +1,244 @@
+/**
+ * @name        album.js
+ * @author      Philipp Maurer
+ * @author      Tobias Reich
+ * @copyright   2013 by Philipp Maurer, Tobias Reich
+ *
+ * Album Module
+ * Takes care of every action an album can handle and execute.
+ */
+
+album = {
+
+	json: null,
+
+	getID: function() {
+
+		var id;
+
+		if (photo.json) id = photo.json.album;
+		else if (album.json) id = album.json.id;
+		else id = $(".album:hover, .album.active").attr("data-id");
+
+		// Search
+		if (!id) id = $(".photo:hover, .photo.active").attr("data-album-id");
+
+		if (id) return id;
+		else return false;
+
+	},
+
+	load: function(albumID, refresh) {
+
+		var startTime,
+			params,
+			durationTime,
+			waitTime,
+			photosData = "";
+
+		password.get(albumID, function() {
+
+			if (!refresh) {
+				loadingBar.show();
+				lychee.animate(".album, .photo", "contentZoomOut");
+				lychee.animate(".divider", "fadeOut");
+			}
+
+			startTime = new Date().getTime();
+
+			params = "getAlbum&albumID=" + albumID + "&password=" + password.value;
+			lychee.api(params, "json", function(data) {
+
+				if (data=="HTTP/1.1 403 Album private!") {
+					lychee.setMode("view");
+					return false;
+				}
+
+				if (data=="HTTP/1.1 403 Wrong password!") {
+					album.load(albumID, refresh);
+					return false;
+				}
+
+				album.json = data;
+
+				durationTime = (new Date().getTime() - startTime);
+				if (durationTime>300) waitTime = 0; else if (refresh) waitTime = 0; else waitTime = 300 - durationTime;
+				if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
+
+				$.timer(waitTime, function() {
+
+					view.album.init();
+
+					if (!refresh) {
+						lychee.animate(".album, .photo", "contentZoomIn");
+						view.header.mode("album");
+					}
+
+				}, false);
+
+			});
+
+		});
+
+	},
+
+	parse: function(photo) {
+
+		if (photo&&photo.thumbUrl) photo.thumbUrl = lychee.upload_path_thumb + photo.thumbUrl;
+		else if (!album.json.title) album.json.title = "Untitled";
+
+	},
+
+	add: function() {
+
+		var title = prompt("Please enter a title for this album:", "Untitled"),
+			params;
+
+		if (title.length>0&&title.length<31) {
+
+			modal.close();
+
+			params = "addAlbum&title=" + escape(encodeURI(title));
+			lychee.api(params, "text", function(data) {
+
+				if (data) lychee.goto("a" + data);
+				else loadingBar.show("error");
+
+			});
+
+		} else if (title.length>0) loadingBar.show("error", "Error", "Title to short or too long. Please try another one!");
+
+	},
+
+	delete: function(albumID) {
+
+		var params,
+			buttons,
+			albumTitle;
+
+		buttons = [
+			["Delete Album and Photos", function() {
+
+				params = "deleteAlbum&albumID=" + albumID + "&delAll=true";
+				lychee.api(params, "text", function(data) {
+
+					if (visible.albums()) view.albums.content.delete(albumID);
+					else lychee.goto("");
+
+					if (!data) loadingBar.show("error");
+
+				});
+
+			}],
+			["Keep Album", function() {}]
+		];
+
+		if (albumID==0) {
+
+			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)
+
+		} else {
+
+			if (album.json) albumTitle = album.json.title;
+			else if (albums.json) albumTitle = albums.json.content[albumID].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);
+
+		}
+
+	},
+
+	setTitle: function(albumID) {
+
+		var oldTitle = "",
+			newTitle,
+			params;
+
+		if (!albumID) albumID = album.getID();
+		if (album.json) oldTitle = album.json.title;
+		else if (albums.json) oldTitle = albums.json.content[albumID].title;
+
+		newTitle = prompt("Please enter a new title for this album:", oldTitle);
+
+		if (albumID!=""&&albumID!=null&&albumID&&newTitle.length>0&&newTitle.length<31) {
+
+			if (visible.album()) {
+
+				album.json.title = newTitle;
+				view.album.title();
+
+			} else if (visible.albums()) {
+
+				albums.json.content[albumID].title = newTitle;
+				view.albums.content.title(albumID);
+
+			}
+
+			params = "setAlbumTitle&albumID=" + albumID + "&title=" + escape(encodeURI(newTitle));
+			lychee.api(params, "text", function(data) {
+
+				if (!data) loadingBar.show("error");
+
+			});
+
+		} else if (newTitle.length>0) loadingBar.show("error", "Error", "New title to short or too long. Please try another one!");
+
+	},
+
+	setPublic: function(albumID, e) {
+
+		var params;
+
+		if (visible.album()) {
+
+			album.json.public = (album.json.public==0) ? 1 : 0;
+			album.json.password = (album.json.public==false) ? true : false;
+			view.album.public();
+			if (album.json.public==1) contextMenu.shareAlbum(albumID, e);
+
+		}
+
+		params = "setAlbumPublic&albumID=" + albumID;
+		lychee.api(params, "text", function(data) {
+
+			if (!data) loadingBar.show("error");
+
+		});
+
+	},
+
+	share: function(service) {
+
+		var link = "",
+			url = location.href;
+
+		switch (service) {
+			case 0:
+				link = "https://twitter.com/share?url=" + encodeURI(url);
+				break;
+			case 1:
+				link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(album.json.title);
+				break;
+			case 2:
+				link = "mailto:?subject=" + encodeURI(album.json.title) + "&body=" + encodeURI("Hi! Check this out: " + url);
+				break;
+			default:
+				link = "";
+				break;
+		}
+
+		if (link.length>5) location.href = link;
+
+	},
+
+	getArchive: function(albumID) {
+
+		var link;
+
+		if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getAlbumArchive&albumID=" + albumID);
+		else link = location.href.replace(location.hash, "") + "php/api.php?function=getAlbumArchive&albumID=" + albumID;
+		location.href = link;
+
+	}
+
+}

+ 55 - 298
js/modules/albums.js

@@ -10,75 +10,67 @@
 
 albums = {
 
+	json: null,
+
 	load: function() {
 
-		lychee.animate(".album, .photo", "contentZoomOut");
+		var startTime,
+			durationTime,
+			unsortedAlbum,
+			starredAlbum,
+			publicAlbum,
+			smartData = "",
+			albumsData = "";
 
-		/* Search */
-		lychee.content.attr("data-search", "");
+		lychee.animate(".album, .photo", "contentZoomOut");
 		lychee.animate(".divider", "fadeOut");
 
 		startTime = new Date().getTime();
 
 		lychee.api("getAlbums", "json", function(data) {
 
+			/* Smart Albums */
+			data.unsortedAlbum = {
+				id: 0,
+				title: "Unsorted",
+				sysdate: data.unsortedNum + " photos",
+				unsorted: 1,
+				thumb0: data.unsortedThumb0,
+				thumb1: data.unsortedThumb1,
+				thumb2: data.unsortedThumb2
+			}
+
+			data.starredAlbum = {
+				id: "f",
+				title: "Starred",
+				sysdate: data.starredNum + " photos",
+				star: 1,
+				thumb0: data.starredThumb0,
+				thumb1: data.starredThumb1,
+				thumb2: data.starredThumb2
+			}
+
+			data.publicAlbum = {
+				id: "s",
+				title: "Public",
+				sysdate: data.publicNum + " photos",
+				public: 1,
+				thumb0: data.publicThumb0,
+				thumb1: data.publicThumb1,
+				thumb2: data.publicThumb2
+			}
+
+			albums.json = data;
+
 			durationTime = (new Date().getTime() - startTime);
 			if (durationTime>300) waitTime = 0; else waitTime = 300 - durationTime;
+			if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
 
 			$.timer(waitTime,function(){
 
-				$("#tools_album, #tools_photo").hide();
-				$("#tools_albums").show();
-
-				/* Smart Albums */
-				unsortedAlbum = new Object();
-				unsortedAlbum.id = 0;
-				unsortedAlbum.title = "Unsorted";
-				unsortedAlbum.sysdate = data.unsortNum + " photos";
-				unsortedAlbum.unsorted = 1;
-				if (data.unsortThumb0) unsortedAlbum.thumb0 = lychee.upload_path + data.unsortThumb0; else unsortedAlbum.thumb0 = "";
-				if (data.unsortThumb1) unsortedAlbum.thumb1 = lychee.upload_path + data.unsortThumb1; else unsortedAlbum.thumb1 = "";
-				if (data.unsortThumb2) unsortedAlbum.thumb2 = lychee.upload_path + data.unsortThumb2; else unsortedAlbum.thumb2 = "";
-
-				starredAlbum = new Object();
-				starredAlbum.id = "f";
-				starredAlbum.title = "Starred";
-				starredAlbum.sysdate = data.starredNum + " photos";
-				starredAlbum.star = 1;
-				if (data.starredThumb0) starredAlbum.thumb0 = lychee.upload_path + data.starredThumb0; else starredAlbum.thumb0 = "";
-				if (data.starredThumb1) starredAlbum.thumb1 = lychee.upload_path + data.starredThumb1; else starredAlbum.thumb1 = "";
-				if (data.starredThumb2) starredAlbum.thumb2 = lychee.upload_path + data.starredThumb2; else starredAlbum.thumb2 = "";
-
-				publicAlbum = new Object();
-				publicAlbum.id = "s";
-				publicAlbum.title = "Public";
-				publicAlbum.sysdate = data.publicNum + " photos";
-				publicAlbum.public = 1;
-				if (data.publicThumb0) publicAlbum.thumb0 = lychee.upload_path + data.publicThumb0; else publicAlbum.thumb0 = "";
-				if (data.publicThumb1) publicAlbum.thumb1 = lychee.upload_path + data.publicThumb1; else publicAlbum.thumb1 = "";
-				if (data.publicThumb2) publicAlbum.thumb2 = lychee.upload_path + data.publicThumb2; else publicAlbum.thumb2 = "";
-
-				if (lychee.publicMode) smartData = "";
-				else smartData = build.divider("Smart Albums") + build.album(unsortedAlbum) + build.album(starredAlbum) + build.album(publicAlbum);
-
-				/*  Albums */
-				if (data.albums) {
-
-					albumsData = build.divider("Albums");
-					$.each(data.album, function() { albumsData += build.album(this); });
-
-				} else albumsData = "";
-
-				if (smartData==""&&albumsData=="") $("body").append(build.no_content("picture"));
-				else {
-					lychee.content.html(smartData + albumsData);
-					lychee.animate(".album, .photo", "contentZoomIn");
-				}
-
-				document.title = "Lychee";
-				lychee.headerTitle.html("Albums").removeClass("editable");
-
-				$("img").retina();
+				view.header.mode("albums");
+				view.albums.init();
+				lychee.animate(".album, .photo", "contentZoomIn");
 
 			});
 
@@ -86,253 +78,18 @@ albums = {
 
 	},
 
-	loadInfo: function(albumID, password) {
-
-		if (albumID=="f"||albumID=="s"||albumID==0) {
-
-			lychee.headerTitle.removeClass("editable");
-
-			$("#button_edit_album, #button_trash_album, #button_share_album").hide();
-
-			lychee.api("getSmartInfo", "json", function(data) {
-
-				switch (albumID) {
-					case "f":
-						document.title = "Lychee - Starred";
-						lychee.headerTitle.html("Starred<span> - " + data.starredNum + " photos</span>");
-						break;
-					case "s":
-						document.title = "Lychee - Public";
-						lychee.headerTitle.html("Public<span> - " + data.publicNum + " photos</span>");
-						break;
-					case "0":
-						document.title = "Lychee - Unsorted";
-						lychee.headerTitle.html("Unsorted<span> - " + data.unsortNum + " photos</span>");
-						$("#button_trash_album").show();
-						break;
-				}
-
-			});
-
-		} else {
-
-			/*if (lychee.publicMode&&password==undefined) {
-				password = localStorage.getItem("album" + albumID);
-				if (password==null) {
-					 if (lychee.publicMode) password = prompt("Please enter a password for this album:", ""); else password = "";
-					 if (password!="") password = hex_md5(password);
-					 localStorage.setItem("album" + albumID, password);
-				}
-			}*/
-
-			password = "";
-
-			$("#button_edit_album, #button_trash_album, #button_share_album, .button_divider").show();
-
-			params = "getAlbumInfo&albumID=" + albumID + "&password=" + password;
-			lychee.api(params, "json", function(data) {
-
-				if (!data.title) data.title = "Untitled";
-				document.title = "Lychee - " + data.title;
-				lychee.headerTitle.html(data.title + "<span> - " + data.num + " photos</span>").addClass("editable");
-
-				if (data.public=="1") {
-					$("#button_share_album a").addClass("active");
-					$("#button_share_album").attr("title", "Share Album");
-				} else {
-					$("#button_share_album a").removeClass("active");
-					$("#button_share_album").attr("title", "Make Public");
-				}
-
-			});
-
-		}
-
-	},
-
-	add: function() {
-
-		title = prompt("Please enter a title for this album:", "Untitled");
-		lychee.closeModal();
-
-		if (title.length>0&&title.length<31) {
-
-			params = "addAlbum&title=" + escape(title);
-			lychee.api(params, "text", function(data) {
-
-				if (data) lychee.goto("a" + data);
-				else loadingBar.show("error");
-
-			});
-
-		} else if (title.length>0) loadingBar.show("error", "Error", "Title to short or too long. Please try another one!");
-
-	},
-
-	hide: function(albumID) {
-
-		$(".album[data-id='" + albumID + "']").css("opacity", 0).animate({
-			width: 0,
-			marginLeft: 0
-		}, 300, function() {
-			$(this).remove();
-		});
-
-	},
-
-	delete: function(albumID, delAll) {
-
-		params = "deleteAlbum&albumID=" + albumID + "&delAll=" + delAll;
-		lychee.api(params, "text", function(data) {
-
-			if (data) {
-
-				if (visible.albums()) albums.hide(albumID);
-				else lychee.goto("");
-
-			} else loadingBar.show("error");
-
-		});
-
-	},
-
-	deleteDialog: function(albumID) {
-
-		if (albumID==0) {
-
-			f1 = "albums.delete(0, true);";
-			f2 = "";
-			modal = build.modal("Clear Unsorted", "Are you sure you want to delete all photos from 'Unsorted'?<br>This action can't be undone!", ["Clear Unsorted", "Keep Photos"], [f1, f2]);
-			$("body").append(modal);
+	parse: function(album) {
 
+		if (album.password&&lychee.publicMode) {
+			album.thumb0 = "img/password.png";
+			album.thumb1 = "img/password.png";
+			album.thumb2 = "img/password.png";
 		} else {
-
-			if (visible.albums()) albumTitle = $(".album[data-id='" + albumID + "'] .overlay h1").html();
-			else albumTitle = lychee.title();
-
-			f1 = "albums.delete(" + albumID + ", true);";
-			f2 = "albums.delete(" + albumID + ", false);";
-			modal = build.modal("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!", ["Delete Album and Photos", "Keep Photos"], [f1, f2]);
-			$("body").append(modal);
-
-		}
-
-	},
-
-	setTitle: function(albumID) {
-
-		if (!albumID) oldTitle = lychee.title(); else oldTitle = "";
-		if (!albumID) albumID = lychee.content.attr("data-id");
-
-		newTitle = prompt("Please enter a new title for this album:", oldTitle);
-
-		if (albumID!=""&&albumID!=null&&albumID&&newTitle.length>0&&newTitle.length<31) {
-
-			params = "setAlbumTitle&albumID=" + albumID + "&title=" + encodeURI(newTitle);
-			lychee.api(params, "text", function(data) {
-
-				if (data) {
-					if (visible.albums()) $(".album[data-id='" + albumID + "'] .overlay h1").html(newTitle);
-					else {
-						lychee.headerTitle.html(newTitle + "<span>" + $("#title span").html() + "</span>");
-						document.title = "Lychee - " + newTitle;
-					}
-				} else loadingBar.show("error");
-
-			});
-
-		} else if (newTitle.length>0) loadingBar.show("error", "Error", "New title to short or too long. Please try another one!");
-
-	},
-
-	setPublic: function(e) {
-
-		albumID = lychee.content.attr("data-id");
-
-		params = "setAlbumPublic&albumID=" + albumID;
-		lychee.api(params, "text", function(data) {
-
-			if (data) {
-
-				if ($("#button_share_album a.active").length) {
-					$("#button_share_album a").removeClass("active");
-					$("#button_share_album").attr("title", "Make Public");
-				} else {
-					$("#button_share_album a").addClass("active");
-					$("#button_share_album").attr("title", "Share Album");
-					contextMenu.share_album(albumID, e.pageX, e.pageY);
-				}
-
-			} else loadingBar.show("error");
-
-		});
-
-	},
-
-	setPassword: function(albumID, password) {
-
-		if (!albumID) albumID = lychee.content.attr("data-id");
-		if (!password) password = prompt("Please enter a password for this album:", "");
-		if (password!="") password = hex_md5(password);
-
-		params = "setAlbumPassword&albumID=" + albumID + "&password=" + password;
-		lychee.api(params, "text", function(data) {
-
-			if (!data) loadingBar.show("error");
-
-		});
-
-	},
-
-	/*checkAlbumPassword: function(albumID, password) {
-
-		params = "checkAlbumPassword&albumID=" + albumID + "&password=" + hex_md5(password);
-		lychee.api(params, "text", function(data) {
-			if (data) {
-				if (password!="") password = hex_md5(password);
-				localStorage.setItem("album" + albumID, password);
-				return true;
-			} else return false;
-		});
-
-	},*/
-
-	share: function(service, albumID) {
-
-		link = "";
-		url = location.href;
-
-		switch (service) {
-			case 0:
-				link = "https://twitter.com/share?url=" + encodeURI(url);
-				break;
-			case 1:
-				link = "http://www.facebook.com/sharer.php?u=" + encodeURI(url) + "&t=" + encodeURI(lychee.title());
-				break;
-			case 2:
-				link = "mailto:?subject=" + encodeURI(lychee.title()) + "&body=" + encodeURI("Hi! Check this out: " + url);
-				break;
-			case 3:
-				modal = build.modal("Copy Link", "Everyone can view your public albums, but only you can edit them. Use this link to share your album with others: <input class='copylink' value='" + url + "'>", ["Close"], [""]);
-				$("body").append(modal);
-				$(".copylink").focus();
-				break;
-			default:
-				link = "";
-				break;
+			if (album.thumb0) album.thumb0 = lychee.upload_path_thumb + album.thumb0; else album.thumb0 = "img/no_images.png";
+			if (album.thumb1) album.thumb1 = lychee.upload_path_thumb + album.thumb1; else album.thumb1 = "img/no_images.png";
+			if (album.thumb2) album.thumb2 = lychee.upload_path_thumb + album.thumb2; else album.thumb2 = "img/no_images.png";
 		}
 
-		if (link.length>5) location.href = link;
-
-	},
-
-	getArchive: function() {
-
-		albumID = lychee.content.attr("data-id");
-		if (location.href.indexOf("index.html")>0) link = location.href.replace(location.hash, "").replace("index.html", "php/api.php?function=getAlbumArchive&albumID=" + albumID);
-		else link = location.href.replace(location.hash, "") + "php/api.php?function=getAlbumArchive&albumID=" + albumID;
-		location.href = link;
-
 	}
 
 }

+ 76 - 72
js/modules/build.js

@@ -18,38 +18,28 @@ build = {
 
 	album: function(albumJSON) {
 
-		var album = "";
-
-		if(!albumJSON) return "";
-
-		if (albumJSON.password&&lychee.publicMode) {
-			albumJSON.thumb0 = "img/password.png";
-			albumJSON.thumb1 = "img/password.png";
-			albumJSON.thumb2 = "img/password.png";
-		} else {
-			if(!albumJSON.thumb0) albumJSON.thumb0 = "img/no_images.png";
-			if(!albumJSON.thumb1) albumJSON.thumb1 = "img/no_images.png";
-			if(!albumJSON.thumb2) albumJSON.thumb2 = "img/no_images.png";
-		}
+		if (!albumJSON) return "";
+
+		var album = ""
+			title = albumJSON.title;
 
-		if(!albumJSON.title) albumJSON.title = "Untitled";
-		if(albumJSON.title.length>18) albumJSON.title = albumJSON.title.substr(0, 18) + "...";
+		if (title.length>18) title = albumJSON.title.substr(0, 18) + "...";
 
 		album += "<div  class='album' data-id='" + albumJSON.id + "' data-password='" + albumJSON.password + "'>";
-		album +=	"<img src='" + lychee.upload_path + albumJSON.thumb2 + "' width='200' height='200' alt='thumb'>";
-		album +=	"<img src='" + lychee.upload_path + albumJSON.thumb1 + "' width='200' height='200' alt='thumb'>";
-		album +=	"<img src='" + lychee.upload_path + albumJSON.thumb0 + "' width='200' height='200' alt='thumb'>";
+		album +=	"<img src='" + albumJSON.thumb2 + "' width='200' height='200' alt='thumb'>";
+		album +=	"<img src='" + albumJSON.thumb1 + "' width='200' height='200' alt='thumb'>";
+		album +=	"<img src='" + albumJSON.thumb0 + "' width='200' height='200' alt='thumb'>";
 		album += 	"<div class='overlay'>";
 
-		if (albumJSON.password&&!lychee.publicMode) album += "<h1><span class='icon-lock' title='Public album with password'></span> " + albumJSON.title + "</h1>";
-		else album += "<h1>" + albumJSON.title + "</h1>";
+		if (albumJSON.password&&!lychee.publicMode) album += "<h1><span class='icon-lock'></span> " + title + "</h1>";
+		else album += "<h1>" + title + "</h1>";
 
 		album += 		"<a>" + albumJSON.sysdate + "</a>";
 		album += 	"</div>";
 
-		if(!lychee.publicMode&&albumJSON.star=="1") album += "<a class='badge red icon-star'></a>";
-		if(!lychee.publicMode&&albumJSON.public=="1") album += "<a class='badge red icon-share'></a>";
-		if(!lychee.publicMode&&albumJSON.unsorted=="1") album += "<a class='badge red icon-reorder'></a>";
+		if(!lychee.publicMode&&albumJSON.star==1) album += "<a class='badge red icon-star'></a>";
+		if(!lychee.publicMode&&albumJSON.public==1) album += "<a class='badge red icon-share'></a>";
+		if(!lychee.publicMode&&albumJSON.unsorted==1) album += "<a class='badge red icon-reorder'></a>";
 
 		album += "</div>";
 
@@ -59,22 +49,22 @@ build = {
 
 	photo: function(photoJSON) {
 
-		var photo = "";
+		if (!photoJSON) return "";
+
+		var photo = "",
+			title = photoJSON.title;
 
-		if(photoJSON=="") return "";
-		if(!photoJSON.title) photoJSON.title = "";
-		if(!photoJSON.thumbUrl) photoJSON.thumbUrl = "img/no_image.png";
-		if(photoJSON.title.length>18) photoJSON.title = photoJSON.title.substr(0, 18) + "...";
+		if (title.length>18) title = photoJSON.title.substr(0, 18) + "...";
 
 		photo += "<div class='photo' data-album-id='" + photoJSON.album + "' data-id='" + photoJSON.id + "'>";
-		photo +=	"<img src='" + lychee.upload_path + photoJSON.thumbUrl + "' width='200' height='200' alt='thumb'>";
+		photo +=	"<img src='" + photoJSON.thumbUrl + "' width='200' height='200' alt='thumb'>";
 		photo += 	"<div class='overlay'>";
-		photo += 		"<h1>" + photoJSON.title + "</h1>";
+		photo += 		"<h1>" + title + "</h1>";
 		photo += 		"<a>" + photoJSON.sysdate + "</a>";
 		photo += 	"</div>";
 
-		if(photoJSON.star=="1") photo += "<a class='badge red icon-star'></a>";
-		if(!lychee.publicMode&&photoJSON.public=="1") photo += "<a class='badge red icon-share'></a>";
+		if (photoJSON.star==1) photo += "<a class='badge red icon-star'></a>";
+		if (!lychee.publicMode&&photoJSON.public==1&&album.json.public!=1) photo += "<a class='badge red icon-share'></a>";
 
 		photo += "</div>";
 
@@ -98,7 +88,7 @@ build = {
 
 	},
 
-	modal: function(title, text, button, func) {
+	modal: function(title, text, button) {
 
 		var modal = "";
 
@@ -110,28 +100,16 @@ build = {
 
 		$.each(button, function(index) {
 
-		if (index==0) modal += "<a onclick='message_click(" + index + ")' class='button active'>" + this + "</a>";
-		else modal += "<a onclick='message_click(" + index + ")' class='button'>" + this + "</a>";
-
-		});
-
-		modal += 	"</div>";
-
-		modal += 	"<script>";
-		modal += 		"function message_click(action) {";
-		modal += 		"switch (action) {";
+			if (this[0]!="") {
 
-		$.each(func, function(index) {
+				if (index==0) modal += "<a class='button active'>" + this[0] + "</a>";
+				else modal += "<a class='button'>" + this[0] + "</a>";
 
-		modal +=			"case " + index + ":";
-		modal +=			this.toString();
-		modal +=			"break;";
+			}
 
 		});
 
-		modal +=		"} lychee.closeModal(); }";
-		modal += 	"</script>";
-
+		modal += 	"</div>";
 		modal += "</div>";
 
 		return modal;
@@ -141,6 +119,7 @@ build = {
 	addModal: function() {
 
 		var modal = "";
+
 		modal += "<div class='message_overlay fadeIn'>";
 		modal += 	"<div class='message center add'>";
 		modal += 		"<h1>Add Album or Photo</h1>";
@@ -167,6 +146,7 @@ build = {
 	signInModal: function() {
 
 		var modal = "";
+
 		modal += "<div class='message_overlay'>";
 		modal += 	"<div class='message center'>";
 		modal += 		"<h1><a class='icon-lock'></a> Sign In</h1>";
@@ -186,6 +166,7 @@ build = {
 	uploadModal: function() {
 
 		var modal = "";
+
 		modal += "<div class='upload_overlay fadeIn'>";
 		modal += 	"<div class='upload_message center'>";
 		modal += 		"<a class='icon-upload'></a>";
@@ -200,6 +181,7 @@ build = {
 	contextMenu: function(items) {
 
 		var menu = "";
+
 		menu += "<div class='contextmenu_bg'></div>";
 		menu += "<div class='contextmenu'>";
 		menu +=		"<table>";
@@ -207,8 +189,10 @@ build = {
 
 		$.each(items, function(index) {
 
-			if (items[index][0]=="separator"&&items[index][1].length==0) menu += "<tr class='separator'></tr>";
-			else if (items[index][1].length!=0) menu += "<tr><td onclick='" + items[index][1] + "; contextMenu.close();'>" + items[index][0] + "</td></tr>";
+			if (items[index][0]=="separator"&&items[index][1]==-1) menu += "<tr class='separator'></tr>";
+			else if (items[index][1]==-1) menu += "<tr class='no_hover'><td>" + items[index][0] + "</td></tr>";
+			else if (items[index][2]!=undefined) menu += "<tr><td onclick='" + items[index][2] + "; window.contextMenu.close();'>" + items[index][0] + "</td></tr>";
+			else menu += "<tr><td onclick='window.contextMenu.fns[" + items[index][1] + "](); window.contextMenu.close();'>" + items[index][0] + "</td></tr>";
 
 		});
 
@@ -220,36 +204,56 @@ build = {
 
 	},
 
-	infobox: function(photo, forView) {
+	infobox: function(photoJSON, forView) {
+
+		if (!photoJSON) return "";
+
+		var infobox = "",
+			public,
+			editTitleHTML,
+			editDescriptionHTML,
+			infos;
 
-		var infobox = "";
 		infobox += "<div class='header'><h1>About</h1><a class='icon-remove-sign'></a></div>";
 		infobox += "<div class='wrapper'>";
 
-		if (photo.public==1) photo.public = "Public"; else photo.public = "Private";
-		if (forView==true||lychee.publicMode) editTitleHTML = ""; else editTitleHTML = " <div id='edit_title'><a class='icon-pencil'></a></div>";
-		if (forView==true||lychee.publicMode) editDescriptionHTML = ""; else editDescriptionHTML = " <div id='edit_description'><a class='icon-pencil'></a></div>";
+		switch (photoJSON.public) {
+			case "0":
+				public = "Private";
+				break;
+			case "1":
+				public = "Public";
+				break;
+			case "2":
+				public = "Public (Album)";
+				break;
+			default:
+				public = "-";
+				break;
+		}
+
+		editTitleHTML = (forView==true||lychee.publicMode) ? "" : " <div id='edit_title'><a class='icon-pencil'></a></div>";
+		editDescriptionHTML = (forView==true||lychee.publicMode) ? "" : " <div id='edit_description'><a class='icon-pencil'></a></div>";
 
 		infos = [
 			["", "Basics"],
-			["Name", photo.title + editTitleHTML],
-			["Uploaded", photo.sysdate],
-			["Description", photo.description + editDescriptionHTML],
+			["Name", photoJSON.title + editTitleHTML],
+			["Uploaded", photoJSON.sysdate],
+			["Description", photoJSON.description + editDescriptionHTML],
 			["", "Image"],
-			["Size", photo.size],
-			["Format", photo.type],
-			["Resolution", photo.width + " x " + photo.height],
+			["Size", photoJSON.size],
+			["Format", photoJSON.type],
+			["Resolution", photoJSON.width + " x " + photoJSON.height],
 			["", "Camera"],
-			["Captured", photo.takedate],
-			["Make", photo.make],
-			["Type/Model", photo.model],
-			["Shutter Speed", photo.shutter],
-			["Aperture", photo.aperture],
-			["Focal Length", photo.focal],
-			["ISO", photo.iso],
+			["Captured", photoJSON.takedate],
+			["Make", photoJSON.make],
+			["Type/Model", photoJSON.model],
+			["Shutter Speed", photoJSON.shutter],
+			["Aperture", photoJSON.aperture],
+			["Focal Length", photoJSON.focal],
+			["ISO", photoJSON.iso],
 			["", "Share"],
-			["Visibility", photo.public],
-			["Short Link", photo.shortlink]
+			["Visibility", public]
 		];
 
 		$.each(infos, function(index) {

+ 139 - 57
js/modules/contextMenu.js

@@ -10,26 +10,35 @@
 
 contextMenu = {
 
+	fns: null,
+
 	album: function(e) {
 
 		e.preventDefault();
-		mouse_x = e.pageX;
-		mouse_y = e.pageY;
-		albumID = $(this).attr("data-id");
+		var mouse_x = e.pageX,
+			mouse_y = e.pageY,
+			albumID = album.getID(),
+			items;
 
 		if (albumID=="0"||albumID=="f"||albumID=="s") return false;
 
 		mouse_y -= $(document).scrollTop();
 
+		contextMenu.fns = [
+			function() { album.setTitle(albumID) },
+			function() { album.delete(albumID) }
+		];
+
 		items = [
-			["Rename", "albums.setTitle(" + albumID + ")"],
-			["Delete", "albums.deleteDialog(" + albumID + ")"]
+			["<a class='icon-edit'></a> Rename", 0],
+			["<a class='icon-trash'></a> Delete", 1]
 		];
 
 		contextMenu.close();
-		$("body").css("overflow", "hidden");
 		$(".album[data-id='" + albumID + "']").addClass("active");
-		$("body").append(build.contextMenu(items));
+		$("body")
+			.css("overflow", "hidden")
+			.append(build.contextMenu(items));
 		$(".contextmenu").css({
 			"top": mouse_y,
 			"left": mouse_x
@@ -40,22 +49,33 @@ contextMenu = {
 	photo: function(e) {
 
 		e.preventDefault();
-		mouse_x = e.pageX;
-		mouse_y = e.pageY;
-		photoID = $(this).attr("data-id");
+		var mouse_x = e.pageX,
+			mouse_y = e.pageY,
+			photoID = photo.getID(),
+			items;
 
 		mouse_y -= $(document).scrollTop();
 
+		contextMenu.fns = [
+			function() { photo.setStar(photoID) },
+			function() { photo.setTitle(photoID) },
+			function() { contextMenu.move(photoID, e) },
+			function() { photo.delete(photoID) }
+		];
+
 		items = [
-			["Rename", "photos.setTitle(" + photoID + ")"],
-			["Move to Album", "contextMenu.move(" + photoID + ", " + (mouse_x+150) + ", " + (mouse_y+$(document).scrollTop()) + ")"],
-			["Delete", "photos.deleteDialog(" + photoID + ")"]
+			["<a class='icon-star'></a> Star", 0],
+			["separator", -1],
+			["<a class='icon-edit'></a> Rename", 1],
+			["<a class='icon-folder-open'></a> Move", 2],
+			["<a class='icon-trash'></a> Delete", 3]
 		];
 
 		contextMenu.close();
-		$("body").css("overflow", "hidden");
 		$(".photo[data-id='" + photoID + "']").addClass("active");
-		$("body").append(build.contextMenu(items));
+		$("body")
+			.css("overflow", "hidden")
+			.append(build.contextMenu(items));
 		$(".contextmenu").css({
 			"top": mouse_y,
 			"left": mouse_x
@@ -63,8 +83,14 @@ contextMenu = {
 
 	},
 
-	move: function(photoID, mouse_x, mouse_y) {
+	move: function(photoID, e) {
 
+		var mouse_x = e.pageX,
+			mouse_y = e.pageY,
+			items = [],
+			albumID;
+
+		contextMenu.fns = [];
 		mouse_y -= $(document).scrollTop();
 
 		if (!mouse_x||!mouse_y) {
@@ -72,35 +98,29 @@ contextMenu = {
 			mouse_y = "10px";
 		}
 
-		lychee.api("getAlbums", "json", function(data) {
+		if (album.getID()!=0) {
+			items = [
+				["Unsorted", 0, "photo.setAlbum(0, " + photoID + ")"],
+				["separator", -1]
+			];
+		}
 
-			if (lychee.content.attr("data-id")==0) {
-				items = [];
-			} else {
-				items = [
-					["Unsorted", "photos.setAlbum(" + photoID + ", 0)"]
-				];
-			}
+		lychee.api("getAlbums", "json", function(data) {
 
 			if (!data.albums) {
-				items = [
-					["New Album", "albums.add()"]
-				];
+				items = [["New Album", 0, "album.add()"]];
 			} else {
-				$.each(data.album, function(index) {
-					if (this.id!=lychee.content.attr("data-id")) {
-						if(!this.title) this.title = "Untitled";
-						items[items.length] = new Array(this.title, "photos.setAlbum(" + photoID + ", " + this.id + ")");
-					} else {
-						items[items.length] = new Array("", "");
-					}
+				$.each(data.content, function(index) {
+					if (this.id!=album.getID()) items.push([this.title, 0, "photo.setAlbum(" + this.id + ", " + photoID + ")"]);
 				});
 			}
 
 			contextMenu.close();
-			$("body").css("overflow", "hidden");
 			$(".photo[data-id='" + photoID + "']").addClass("active");
-			$("body").append(build.contextMenu(items));
+			$("body")
+				.css("overflow", "hidden")
+				.append(build.contextMenu(items));
+			if (!visible.photo()) mouse_x += $(".contextmenu").width();
 			$(".contextmenu").css({
 				"top": mouse_y,
 				"left": mouse_x-$(".contextmenu").width()
@@ -110,7 +130,11 @@ contextMenu = {
 
 	},
 
-	share: function(photoID, mouse_x, mouse_y) {
+	sharePhoto: function(photoID, e) {
+
+		var mouse_x = e.pageX,
+			mouse_y = e.pageY,
+			items;
 
 		mouse_y -= $(document).scrollTop();
 
@@ -119,30 +143,57 @@ contextMenu = {
 			mouse_y = "10px";
 		}
 
-		items = [
-			["<a class='icon-eye-close'></a> Make Private", "photos.setPublic()"],
-			["separator", ""],
-			["<a class='icon-twitter'></a> Twitter", "photos.share(0, " + photoID + ")"],
-			["<a class='icon-facebook'></a> Facebook", "photos.share(1, " + photoID + ")"],
-			["<a class='icon-envelope'></a> Mail", "photos.share(2, " + photoID + ")"],
-			["<a class='icon-link'></a> Copy Link", "photos.share(3, " + photoID + ")"]
+		contextMenu.fns = [
+			function() { photo.setPublic(photoID) },
+			function() { photo.share(photoID, 0) },
+			function() { photo.share(photoID, 1) },
+			function() { photo.share(photoID, 2) },
+			function() { photo.share(photoID, 3) }
 		];
 
-		if (lychee.bitlyUsername!="") items.push(["<a class='icon-link'></a> Copy Shortlink", "photos.share(4, " + photoID + ")"]);
+		if (document.location.hostname!="localhost") {
+
+			items = [
+				["<input readonly id='link' value='" + photo.getViewLink(photoID) + "'>", -1],
+				["separator", -1],
+				["<a class='icon-eye-close'></a> Make Private", 0],
+				["separator", -1],
+				["<a class='icon-twitter'></a> Twitter", 1],
+				["<a class='icon-facebook'></a> Facebook", 2],
+				["<a class='icon-envelope'></a> Mail", 3],
+				["<a class='icon-hdd'></a> Dropbox", 4]
+			];
+
+		} else {
+
+			items = [
+				["<input readonly id='link' value='" + photo.getViewLink(photoID) + "'>", -1],
+				["separator", -1],
+				["<a class='icon-eye-close'></a> Make Private", 0],
+				["separator", -1],
+				["<a class='icon-envelope'></a> Mail", 3]
+			];
+
+		}
 
 		contextMenu.close();
 		$("body")
 			.css("overflow", "hidden")
 			.append(build.contextMenu(items));
-		$(".photo[data-id='" + photoID + "']").addClass("active");
 		$(".contextmenu").css({
 			"top": mouse_y,
-			"left": mouse_x
+			"left": mouse_x+20-$(".contextmenu").width()
 		});
 
+		$(".contextmenu input").focus();
+
 	},
 
-	share_album: function(albumID, mouse_x, mouse_y) {
+	shareAlbum: function(albumID, e) {
+
+		var mouse_x = e.pageX,
+			mouse_y = e.pageY,
+			items;
 
 		mouse_y -= $(document).scrollTop();
 
@@ -151,29 +202,60 @@ contextMenu = {
 			mouse_y = "10px";
 		}
 
-		items = [
-			["<a class='icon-eye-close'></a> Make Private", "albums.setPublic()"],
-			//["<a class='icon-key'></a> Set Password", "albums.setPassword()"],
-			["separator", ""],
-			["<a class='icon-twitter'></a> Twitter", "albums.share(0, " + albumID + ")"],
-			["<a class='icon-facebook'></a> Facebook", "albums.share(1, " + albumID + ")"],
-			["<a class='icon-envelope'></a> Mail", "albums.share(2, " + albumID + ")"],
-			["<a class='icon-link'></a> Copy Link", "albums.share(3, " + albumID + ")"]
+		contextMenu.fns = [
+			function() { album.setPublic(albumID) },
+			function() { password.set(albumID) },
+			function() { album.share(0) },
+			function() { album.share(1) },
+			function() { album.share(2) },
+			function() { password.remove(albumID) }
 		];
 
+		if (document.location.hostname!="localhost") {
+
+			items = [
+				["<input readonly id='link' value='" + location.href + "'>", -1],
+				["separator", -1],
+				["<a class='icon-eye-close'></a> Make Private", 0],
+				["<a class='icon-lock'></a> Set Password", 1],
+				["separator", -1],
+				["<a class='icon-twitter'></a> Twitter", 2],
+				["<a class='icon-facebook'></a> Facebook", 3],
+				["<a class='icon-envelope'></a> Mail", 4],
+			];
+
+		} else {
+
+			items = [
+				["<input readonly id='link' value='" + location.href + "'>", -1],
+				["separator", -1],
+				["<a class='icon-eye-close'></a> Make Private", 0],
+				["<a class='icon-lock'></a> Set Password", 1],
+				["separator", -1],
+				["<a class='icon-envelope'></a> Mail", 4],
+			];
+
+		}
+
+		if (album.json.password==true) items[3] = ["<a class='icon-unlock'></a> Remove Password", 5];
+
 		contextMenu.close();
 		$("body")
 			.css("overflow", "hidden")
 			.append(build.contextMenu(items));
 		$(".contextmenu").css({
 			"top": mouse_y,
-			"left": mouse_x
+			"left": mouse_x+20-$(".contextmenu").width()
 		});
 
+		$(".contextmenu input").focus();
+
 	},
 
 	close: function() {
 
+		contextMenu.js = null;
+
 		$(".contextmenu_bg, .contextmenu").remove();
 		$(".photo.active, .album.active").removeClass("active");
 		$("body").css("overflow", "scroll");

+ 5 - 5
js/modules/loadingBar.js

@@ -14,9 +14,7 @@ loadingBar = {
 
 	show: function(status, errorTitle, errorText) {
 
-		clearTimeout(lychee.loadingBar.data("timeout"));
-
-		if (status=="error"&&loadingBar.status!="error") {
+		if (status=="error") {
 
 			loadingBar.status = "error";
 
@@ -31,13 +29,15 @@ loadingBar = {
 				.css("height", "40px");
 			if (visible.controls()) lychee.header.css("margin-Top", "40px");
 
-			lychee.loadingBar.data("timeout", setTimeout(function () { loadingBar.hide(true) }, 3000));
+			clearTimeout(lychee.loadingBar.data("timeout"));
+			lychee.loadingBar.data("timeout", setTimeout(function() { loadingBar.hide(true) }, 3000));
 
 		} else if (loadingBar.status==null) {
 
 			loadingBar.status = "loading";
 
-			lychee.loadingBar.data("timeout", setTimeout(function () {
+			clearTimeout(lychee.loadingBar.data("timeout"));
+			lychee.loadingBar.data("timeout", setTimeout(function() {
 				lychee.loadingBar
 					.show()
 					.removeClass("loading uploading error")

+ 131 - 208
js/modules/lychee.js

@@ -8,62 +8,44 @@
  * This module provides the basic functions of Lychee.
  */
 
-lychee = {
+var lychee = {
 
-	init: function(api_path, upload_path) {
+	init: function() {
 
-		this.version = "1.2";
-		this.api_path = api_path;
-		this.upload_path = upload_path;
+		this.version = "1.3";
+		this.api_path = "php/api.php";
 		this.update_path = "http://lychee.electerious.com/version/index.php";
 		this.updateURL = "https://github.com/electerious/Lychee";
+
+		this.upload_path_thumb = "uploads/thumb/";
+		this.upload_path_big = "uploads/big/";
+
 		this.publicMode = false;
+		this.viewMode = false;
 
 		this.checkForUpdates = false;
-		this.bitlyUsername = "";
+
+		this.dropbox = false;
 
 		this.loadingBar = $("#loading");
 		this.header = $("header");
-		this.headerTitle = $("#title");
 		this.content = $("#content");
-		this.image_view = $("#image_view");
+		this.imageview = $("#imageview");
 		this.infobox = $("#infobox");
 
 	},
 
-	ready: function() {
-
-		if (!mobileBrowser()) $(".tools").tipsy({gravity: 'n'});
-		if (window.webkitNotifications) window.webkitNotifications.requestPermission();
+	run: function() {
 
 		lychee.api("init", "json", function(data) {
 			lychee.checkForUpdates = data.config.checkForUpdates;
-			lychee.bitlyUsername = data.config.bitlyUsername;
-			if (!data.loggedIn) lychee.setPublicMode();
+			if (!data.loggedIn) lychee.setMode("public");
 			$(window).bind("popstate", lychee.load);
 			lychee.load();
 		});
 
 	},
 
-	setPublicMode: function() {
-
-		this.publicMode = true;
-
-		$("#button_signout, #search, #button_trash_album, #button_share_album, #button_edit_album, .button_add, #button_archive, .button_divider").remove();
-		$("#button_trash, #button_move, #button_edit, #button_share, #button_star").remove();
-
-		$(document)
-			.on("mouseenter", "#title.editable", function() { $(this).removeClass("editable") })
-			.off(event_name, "#title.editable")
-			.off("contextmenu", ".photo")
-			.off("contextmenu", ".album")
-			.off("drop");
-
-		$("#button_signin").show();
-
-	},
-
 	api: function(params, type, callback, loading) {
 
 		if (loading==undefined) loadingBar.show();
@@ -83,24 +65,11 @@ lychee = {
 
 	},
 
-	showLogin: function() {
-
-		$("body").append(build.signInModal());
-		$("#username").focus();
-		if (localStorage) {
-			local_username = localStorage.getItem("username");
-			if (local_username==null) return false;
-			if (local_username.length>0) $("#username").val(local_username);
-			$("#password").focus();
-		}
-		if (lychee.checkForUpdates) lychee.update();
-
-	},
-
 	login: function() {
 
-		user = $("input#username").val();
-		password = hex_md5($("input#password").val());
+		var user = $("input#username").val(),
+			password = hex_md5($("input#password").val()),
+			params;
 
 		params = "login&user=" + user + "&password=" + password;
 		lychee.api(params, "text", function(data) {
@@ -115,229 +84,156 @@ lychee = {
 
 	},
 
-	logout: function() {
+	loginDialog: function() {
 
-		lychee.api("logout", "text", function(data) {
-			window.location.reload();
-		});
+		$("body").append(build.signInModal());
+		$("#username").focus();
+		if (localStorage) {
+			local_username = localStorage.getItem("username");
+			if (local_username!=null) {
+				if (local_username.length>0) $("#username").val(local_username);
+				$("#password").focus();
+			}
+		}
+		if (lychee.checkForUpdates) lychee.getUpdate();
 
 	},
 
-	update: function() {
+	logout: function() {
 
-		$.ajax({
-			url: lychee.update_path,
-			success: function(data) { if (data!=lychee.version) $("#version span").show(); }
+		lychee.api("logout", "text", function(data) {
+			window.location.reload();
 		});
 
 	},
 
-	upload: function(files) {
-
-		pre_progress = 0;
-
-		$(".upload_overlay").remove();
-		$("body").append(build.uploadModal());
-
-	    var formData = new FormData();
-	    for (var i = 0; i < files.length; i++) formData.append(i, files[i]);
-
-	    formData.append("function", "upload");
-
-	    if (lychee.content.attr("data-id")=="") formData.append("albumID", 0);
-	    else formData.append("albumID", lychee.content.attr("data-id"));
-
-	    var xhr = new XMLHttpRequest();
-
-	    xhr.open('POST', lychee.api_path);
-	    xhr.onload = function () {
-
-	    	if (xhr.status===200) {
-
-	    		$(".progressbar div").css("width", "100%");
-				$(".upload_overlay").removeClass("fadeIn").css("opacity", 0);
-				$.timer(300,function(){ $(".upload_overlay").remove() });
-
-				if (window.webkitNotifications&&BrowserDetect.browser=="Safari") {
-					var popup = window.webkitNotifications.createNotification("", "Upload complete", "You can now manage your new photos.");
-					popup.show();
-				}
-
-				if (lychee.content.attr("data-id")=="") lychee.goto("a0");
-				else photos.load(lychee.content.attr("data-id"));
-
-	    	}
-
-	    };
-
-	    xhr.upload.onprogress = function (event) {
-
-	    	if (event.lengthComputable) {
-
-	    		var progress = (event.loaded / event.total * 100 | 0);
-
-	    		if (progress>pre_progress) {
-	    			$(".progressbar div").css("width", progress + "%");
-	    			pre_progress = progress;
-	    		}
-
-	    		if (progress>=100) $(".progressbar div").css("opacity", 0.2);
-
-	    	}
-
-	    };
-
-	    $("#upload_files").val("");
-
-	    xhr.send(formData);
-
-	},
-
-	importUrl: function() {
-
-		link = prompt("Please enter the direct link to a photo to import it:", "");
-		if (lychee.content.attr("data-id")=="") albumID = 0;
-		else albumID = lychee.content.attr("data-id");
-
-		lychee.closeModal();
-
-		if (link.length>3) {
-
-			params = "importUrl&url=" + escape(link) + "&albumID=" + albumID;
-			lychee.api(params, "text", function(data) {
-
-				if (data) {
-					if (lychee.content.attr("data-id")=="") lychee.goto("a0");
-					else photos.load(lychee.content.attr("data-id"));
-				} else loadingBar.show("error");
-
-			});
+	goto: function(url) {
 
-		} else if (link.length>0) loadingBar.show("error", "Error", "Link to short or too long. Please try another one!");
+		if (url==undefined) url = "";
+		document.location.hash = url;
 
 	},
 
 	load: function() {
 
-		contextMenu.close();
-		hash = document.location.hash.replace("#", "");
-
-		albumID = "";
-		photoID = "";
+		var albumID = "",
+			photoID = "",
+			hash = document.location.hash.replace("#", "");
 
-		if (hash.indexOf("a")!=-1) albumID = hash.split("p")[0].replace("a", ""); else albumID = "";
-		if (hash.indexOf("p")!=-1) photoID = hash.split("p")[1];  else photoID = "";
+		contextMenu.close();
 
-		lychee.content.attr("data-id", albumID);
-		lychee.image_view.attr("data-id", photoID);
+		if (hash.indexOf("a")!=-1) albumID = hash.split("p")[0].replace("a", "");
+		if (hash.indexOf("p")!=-1) photoID = hash.split("p")[1];
 
 		if (albumID&&photoID) {
 
-			// Show ImageView
+			// Trash data
+			albums.json = null;
+			photo.json = null;
+
+			// Show Photo
 			if (lychee.content.html()==""||($("#search").length&&$("#search").val().length!=0)) {
 				lychee.content.hide();
-				photos.load(albumID, true);
+				album.load(albumID, true);
 			}
-			photos.loadInfo(photoID, albumID);
+			if (!visible.photo()) view.photo.show();
+			photo.load(photoID, albumID);
 
 		} else if (albumID) {
 
+			// Trash data
+			albums.json = null;
+			photo.json = null;
+
 			// Show Album
-			if (visible.infobox) photos.hideInfobox();
-			if (!visible.controls()) lychee.showControls();
-			if (visible.imageview()) photos.hideView();
-			else photos.load(albumID, false);
+			if (visible.photo()) view.photo.hide();
+			if (album.json&&albumID==album.json.id) view.album.title();
+			else album.load(albumID);
 
 		} else {
 
+			// Trash data
+			albums.json = null;
+			album.json = null;
+			photo.json = null;
+			search.code = "";
+
 			// Show Albums
-			if (visible.infobox) photos.hideInfobox();
-			if (!visible.controls()) lychee.showControls();
-			if (visible.imageview()) photos.hideView();
+			if (visible.photo()) view.photo.hide();
 			albums.load();
 
 		}
 
 	},
 
-	goto: function(url) {
+	getUpdate: function() {
 
-		document.location.hash = url;
+		$.ajax({
+			url: lychee.update_path,
+			success: function(data) { if (data!=lychee.version) $("#version span").show(); }
+		});
 
 	},
 
-	title: function() {
+	setTitle: function(title, count, editable) {
+
+		if (title=="Albums") document.title = "Lychee";
+		else document.title = "Lychee - " + title;
+
+		if (count) title += "<span> - " + count + " photos</span>";
+		if (editable) $("#title").addClass("editable");
+		else $("#title").removeClass("editable");
 
-		return lychee.headerTitle.html().replace($("#title span").html(), "").replace("<span></span>", "");
+		$("#title").html(title);
 
 	},
 
-	showControls: function() {
+	setMode: function(mode) {
 
-		clearTimeout($(window).data("timeout"));
+		$("#button_signout, #search, #button_trash_album, #button_share_album, #button_edit_album, .button_add, #button_archive, .button_divider").remove();
+		$("#button_trash, #button_move, #button_edit, #button_share, #button_star").remove();
 
-		if (visible.imageview()) {
-			lychee.image_view.removeClass("full");
-			lychee.loadingBar.css("opacity", 1);
-			lychee.header.css("margin-Top", "0px");
-			if ($("#image_view #image.small").length>0) {
-				$("#image_view #image").css({
-					marginTop: -1*($("#image_view #image").height()/2)+20
-				});
-			} else {
-				$("#image_view #image").css({
-					top: 70,
-					right: 30,
-					bottom: 30,
-					left: 30
-				});
-			}
-		}
+		$(document)
+			.on("mouseenter", "#title.editable", function() { $(this).removeClass("editable") })
+			.off("click", "#title.editable")
+			.off("touchend", "#title.editable")
+			.off("contextmenu", ".photo")
+			.off("contextmenu", ".album")
+			.off("drop");
 
-	},
+		Mousetrap
+			.unbind('n')
+			.unbind('u')
+			.unbind('s')
+			.unbind('backspace');
 
-	hideControls: function() {
-
-		if (visible.imageview()&&!visible.infobox()) {
-			clearTimeout($(window).data("timeout"));
-			$(window).data("timeout", setTimeout(function() {
-				lychee.image_view.addClass("full");
-				lychee.loadingBar.css("opacity", 0);
-				lychee.header.css("margin-Top", "-45px");
-				if ($("#image_view #image.small").length>0) {
-					$("#image_view #image").css({
-						marginTop: -1*($("#image_view #image").height()/2)
-					});
-				} else {
-					$("#image_view #image").css({
-						top: 0,
-						right: 0,
-						bottom: 0,
-						left: 0
-					});
-				}
-			}, 500));
-		}
+		if (mode=="public") {
 
-	},
+			$("#button_signin").show();
+			lychee.publicMode = true;
+
+		} else if (mode=="view") {
 
-	closeModal: function() {
+			Mousetrap.unbind('esc');
+			$("#button_back, a#next, a#previous").remove();
 
-		$(".message_overlay").removeClass("fadeIn").css("opacity", 0);
-		$.timer(300,function(){ $(".message_overlay").remove() });
+			lychee.publicMode = true;
+			lychee.viewMode = true;
+
+		}
 
 	},
 
 	animate: function(obj, animation) {
 
-		animations = [
+		var animations = [
 			["fadeIn", "fadeOut"],
 			["contentZoomIn", "contentZoomOut"]
 		];
 
 		if (!obj.jQuery) obj = $(obj);
 
-		for (i = 0; i < animations.length; i++) {
+		for (var i = 0; i < animations.length; i++) {
 			for (var x = 0; x < animations[i].length; x++) {
 				if (animations[i][x]==animation) {
 					obj.removeClass(animations[i][0] + " " + animations[i][1]).addClass(animation);
@@ -350,6 +246,33 @@ lychee = {
 
 	},
 
+	loadDropbox: function(callback) {
+
+		if (!lychee.dropbox) {
+
+			loadingBar.show();
+
+			var g = document.createElement("script"),
+				s = document.getElementsByTagName("script")[0];
+
+			g.src = "https://www.dropbox.com/static/api/1/dropins.js";
+			g.id = "dropboxjs";
+			g.type = "text/javascript";
+			g.async = "true";
+			g.setAttribute("data-app-key", "iq7lioj9wu0ieqs");
+			g.onload = g.onreadystatechange = function() {
+				var rs = this.readyState;
+				if (rs&&rs!="complete"&&rs!="loaded") return;
+				lychee.dropbox = true;
+				loadingBar.hide();
+				callback();
+			};
+			s.parentNode.insertBefore(g, s);
+
+		} else callback();
+
+	},
+
 	error: function(jqXHR, textStatus, errorThrown) {
 
 		console.log(jqXHR);

+ 37 - 0
js/modules/modal.js

@@ -0,0 +1,37 @@
+/**
+ * @name        modal.js
+ * @author      Philipp Maurer
+ * @author      Tobias Reich
+ * @copyright   2013 by Philipp Maurer, Tobias Reich
+ *
+ * Modal Module
+ * Build, show and hide a modal.
+ */
+
+modal = {
+
+	fns: null,
+
+	show: function(title, text, buttons) {
+
+		if (!buttons) {
+			var buttons = [];
+			buttons[0] = ["", function() {}];
+			buttons[1] = ["", function() {}];
+		}
+
+		modal.fns = [buttons[0][1], buttons[1][1]];
+		$("body").append(build.modal(title, text, buttons));
+		$(".message input").focus();
+
+	},
+
+	close: function() {
+
+		modal.fns = null;
+		$(".message_overlay").removeClass("fadeIn").css("opacity", 0);
+		$.timer(300,function(){ $(".message_overlay").remove() });
+
+	}
+
+}

+ 105 - 0
js/modules/password.js

@@ -0,0 +1,105 @@
+/**
+ * @name        password.js
+ * @author      Philipp Maurer
+ * @author      Tobias Reich
+ * @copyright   2013 by Philipp Maurer, Tobias Reich
+ *
+ * Password Module
+ * Controls the access to password-protected albums and photos.
+ */
+
+password = {
+
+	value: "",
+
+	set: function(albumID) {
+
+		var buttons,
+			params;
+
+		buttons = [
+			["Set Password", function() {
+
+				if (visible.album()) album.json.password = true;
+
+				params = "setAlbumPassword&albumID=" + albumID + "&password=" + hex_md5($("input.password").val());
+				lychee.api(params, "text", function(data) {
+
+					if (!data) loadingBar.show("error");
+
+				});
+
+			}],
+			["Cancel", function() {}]
+		];
+		modal.show("Set Password", "Set a password to protect '" + album.json.title + "' from unauthorized viewers. Only people with this password can view this album. <input class='password' type='password' placeholder='password' value=''>", buttons);
+
+	},
+
+	get: function(albumID, callback) {
+
+		var passwd = $("input.password").val(),
+			params;
+
+		if (!lychee.publicMode) callback();
+		else if (album.json&&album.json.password==false) callback();
+		else if (albums.json&&albums.json.content[albumID].password==false) callback();
+		else if (!albums.json&&!album.json) {
+
+			// Continue without password
+			album.json = {password: true};
+			callback("");
+
+		} else if (passwd==undefined) {
+
+			// Request password
+			password.getDialog(albumID, callback);
+
+		} else {
+
+			// Check password
+			params = "checkAlbumAccess&albumID=" + albumID + "&password=" + hex_md5(passwd);
+			lychee.api(params, "text", function(data) {
+
+				if (data) {
+					password.value = hex_md5(passwd);
+					callback();
+				} else {
+					lychee.goto("");
+					loadingBar.show("error", "Error", "Access denied. Wrong password!");
+				}
+
+			});
+
+		}
+
+	},
+
+	getDialog: function(albumID, callback) {
+
+		var buttons;
+
+		buttons = [
+			["Enter", function() { password.get(albumID, callback) }],
+			["Cancel", lychee.goto]
+		];
+		modal.show("<a class='icon-lock'></a> Enter Password", "This album is protected with a password. Enter the password below to view the photos of this album: <input class='password' type='password' placeholder='password' value=''>", buttons);
+
+	},
+
+	remove: function(albumID) {
+
+		var params;
+
+		if (visible.album()) album.json.password = false;
+
+		params = "setAlbumPassword&albumID=" + albumID + "&password=";
+		lychee.api(params, "text", function(data) {
+
+			if (!data) loadingBar.show("error");
+
+		});
+
+	}
+
+}

+ 403 - 0
js/modules/photo.js

@@ -0,0 +1,403 @@
+/**
+ * @name        photo.js
+ * @author      Philipp Maurer
+ * @author      Tobias Reich
+ * @copyright   2013 by Philipp Maurer, Tobias Reich
+ *
+ * Photo Module
+ * Takes care of every action a photo can handle and execute.
+ */
+
+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, "json", function(data) {
+
+			if (data=="HTTP/1.1 403 Wrong password!") {
+				checkPasswd = function() {
+					if (password.value!="") photo.load(photoID, albumID);
+					else setTimeout(checkPasswd, 250);
+				}
+				checkPasswd();
+				return false;
+			}
+
+			photo.json = data;
+			view.photo.init();
+
+			lychee.imageview.show();
+			$.timer(300, function() { lychee.content.show(); });
+
+		});
+
+	},
+
+	parse: function() {
+
+		if (!photo.json.title) photo.json.title = "Untitled";
+		photo.json.url = lychee.upload_path_big + photo.json.url;
+
+	},
+
+	add: {
+
+		files: function(files) {
+
+			var pre_progress = 0,
+				formData = new FormData(),
+				xhr = new XMLHttpRequest(),
+				popup,
+				progress;
+
+			$(".upload_overlay").remove();
+			$("body").append(build.uploadModal());
+
+			window.onbeforeunload = function() { return "Lychee is currently uploading!"; };
+
+		    for (var i = 0; i < files.length; i++) formData.append(i, files[i]);
+
+		    formData.append("function", "upload");
+
+		    if (album.getID()=="") formData.append("albumID", 0);
+		    else formData.append("albumID", album.getID());
+
+		    xhr.open('POST', lychee.api_path);
+		    xhr.onload = function() {
+
+		    	if (xhr.status===200) {
+
+		    		$(".progressbar div").css("width", "100%");
+					$(".upload_overlay").removeClass("fadeIn").css("opacity", 0);
+					$.timer(300, function() { $(".upload_overlay").remove() });
+
+					if (window.webkitNotifications&&BrowserDetect.browser=="Safari") {
+						popup = window.webkitNotifications.createNotification("", "Upload complete", "You can now manage your new photo.");
+						popup.show();
+					}
+
+					window.onbeforeunload = null;
+
+					if (album.getID()=="") lychee.goto("a0");
+					else album.load(album.getID());
+
+		    	}
+
+		    };
+
+		    xhr.upload.onprogress = function(event) {
+
+		    	if (event.lengthComputable) {
+
+		    		progress = (event.loaded / event.total * 100 | 0);
+
+		    		if (progress>pre_progress) {
+		    			$(".progressbar div").css("width", progress + "%");
+		    			pre_progress = progress;
+		    		}
+
+		    		if (progress>=100) $(".progressbar div").css("opacity", 0.2);
+
+		    	}
+
+		    };
+
+		    $("#upload_files").val("");
+
+		    xhr.send(formData);
+
+		},
+
+		url: function(link) {
+
+			var albumID = album.getID();
+
+			if (!link) link = prompt("Please enter the direct link to a photo to import it:", "");
+			if (album.getID()=="") albumID = 0;
+
+			if (link&&link.length>3) {
+
+				modal.close();
+
+				$(".upload_overlay").remove();
+				$("body").append(build.uploadModal());
+				$(".progressbar div").css({
+					"opacity": 0.2,
+					"width": "100%"
+				});
+
+				params = "importUrl&url=" + escape(link) + "&albumID=" + albumID;
+				lychee.api(params, "text", function(data) {
+
+					$(".upload_overlay").removeClass("fadeIn").css("opacity", 0);
+					$.timer(300, function() { $(".upload_overlay").remove() });
+
+					if (data) {
+						if (album.getID()=="") lychee.goto("a0");
+						else album.load(album.getID());
+					} else loadingBar.show("error");
+
+				});
+
+			} else if (link.length>0) loadingBar.show("error", "Error", "Link to short or too long. Please try another one!");
+
+		},
+
+		dropbox: function() {
+
+			lychee.loadDropbox(function() {
+				Dropbox.choose({
+					linkType: "direct",
+					multiselect: false,
+					success: function(files) { photo.add.url(files[0].link) }
+				});
+			});
+
+		}
+
+	},
+
+	delete: function(photoID) {
+
+		var params,
+			buttons,
+			photoTitle;
+
+		if (!photoID) photoID = photo.getID();
+
+		if (visible.photo()) photoTitle = photo.json.title;
+		else photoTitle = album.json.content[photoID].title;
+		if (photoTitle=="") photoTitle = "Untitled";
+
+		buttons = [
+			["Delete Photo", function() {
+
+				album.json.content[photoID] = null;
+				view.album.content.delete(photoID);
+
+				// Only when search is not active
+				if (!visible.albums()) lychee.goto("a" + album.getID());
+
+				params = "deletePhoto&photoID=" + photoID;
+				lychee.api(params, "text", function(data) {
+
+					if (!data) loadingBar.show("error");
+
+				});
+
+			}],
+			["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;
+
+		if (!photoID) photoID = photo.getID();
+		if (photo.json) oldTitle = photo.json.title;
+		else if (album.json) oldTitle = album.json.content[photoID].title;
+
+		newTitle = prompt("Please enter a new title for this photo:", oldTitle);
+
+		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, "text", function(data) {
+
+				if (!data) loadingBar.show("error");
+
+			});
+
+		} else if (newTitle.length>0) loadingBar.show("error", "Error", "New title to short or too long. Please try another one!");
+
+	},
+
+	setAlbum: function(albumID, photoID) {
+
+		var params;
+
+		if (albumID>=0) {
+
+			if (visible.photo) lychee.goto("a" + album.getID());
+			album.json.content[photoID] = null;
+			view.album.content.delete(photoID);
+
+			params = "setAlbum&photoID=" + photoID + "&albumID=" + albumID;
+			lychee.api(params, "text", function(data) {
+
+				if (!data) loadingBar.show("error");
+
+			});
+
+		}
+
+	},
+
+	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, "text", function(data) {
+
+			if (!data) loadingBar.show("error");
+
+		});
+
+	},
+
+	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("a" + 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, "text", function(data) {
+
+			if (!data) loadingBar.show("error");
+
+		});
+
+	},
+
+	setDescription: function(photoID) {
+
+		var oldDescription = photo.json.description,
+			description = prompt("Please enter a description for this photo:", oldDescription),
+			params;
+
+		if (description.length>0&&description.length<160) {
+
+			if (visible.photo()) {
+				photo.json.description = description;
+				view.photo.description(oldDescription);
+			}
+
+			params = "setPhotoDescription&photoID=" + photoID + "&description=" + escape(description);
+			lychee.api(params, "text", function(data) {
+
+				if (!data) loadingBar.show("error");
+
+			});
+
+		} else if (description.length>0) loadingBar.show("error", "Error", "Description to short or too long. Please try another one!");
+
+	},
+
+	share: function(photoID, service) {
+
+		var link = "",
+			url = photo.getViewLink(photoID),
+			params,
+			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;
+
+	},
+
+	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);
+
+	}
+
+}

+ 27 - 10
js/modules/search.js

@@ -1,5 +1,5 @@
 /**
- * @name        photos.js
+ * @name        search.js
  * @author      Philipp Maurer
  * @author      Tobias Reich
  * @copyright   2013 by Philipp Maurer, Tobias Reich
@@ -10,8 +10,15 @@
 
 search = {
 
+	code: null,
+
 	find: function(term) {
 
+		var params,
+			albumsData = "",
+			photosData = "",
+			code;
+
 		clearTimeout($(window).data("timeout"));
 		$(window).data("timeout", setTimeout(function() {
 
@@ -20,27 +27,37 @@ search = {
 				params = "search&term=" + term;
 				lychee.api(params, "json", function(data) {
 
-					albumsData = "";
-					if (data&&data.albums) $.each(data.albums, function() { albumsData += build.album(this); });
+					if (data&&data.albums) {
+						albums.json = { content: data.albums };
+						$.each(albums.json.content, function() {
+							albums.parse(this);
+							albumsData += build.album(this);
+						});
+					}
 
-					photosData = "";
-					if (data&&data.photos) $.each(data.photos, function() { photosData += build.photo(this); });
+					if (data&&data.photos) {
+						album.json = { content: data.photos };
+						$.each(album.json.content, function() {
+							album.parse(this);
+							photosData += build.photo(this);
+						});
+					}
 
 					if (albumsData==""&&photosData=="") code = "error";
 					else if (albumsData=="") code = build.divider("Photos")+photosData;
 					else if (photosData=="") code = build.divider("Albums")+albumsData;
 					else code = build.divider("Photos")+photosData+build.divider("Albums")+albumsData;
 
-					if (lychee.content.attr("data-search")!=code) {
+					if (search.code!=hex_md5(code)) {
 
 						$(".no_content").remove();
 
 						lychee.animate(".album, .photo", "contentZoomOut");
 						lychee.animate(".divider", "fadeOut");
 
-						$.timer(300,function(){
+						search.code = hex_md5(code);
 
-							lychee.content.attr("data-search", code);
+						$.timer(300,function(){
 
 							if (code=="error") $("body").append(build.no_content("search"));
 							else {
@@ -65,9 +82,9 @@ search = {
 		$("#search").val("");
 		$(".no_content").remove();
 
-		if (lychee.content.attr("data-search")!="") {
+		if (search.code!="") {
 
-			lychee.content.attr("data-search", "");
+			search.code = "";
 			lychee.animate(".divider", "fadeOut");
 			albums.load();
 

+ 395 - 0
js/modules/view.js

@@ -0,0 +1,395 @@
+/**
+ * @name        view.js
+ * @author      Philipp Maurer
+ * @author      Tobias Reich
+ * @copyright   2013 by Philipp Maurer, Tobias Reich
+ *
+ * UI View
+ * Responsible to reflect data changes to the UI.
+ */
+
+view = {
+
+	header: {
+
+		show: function() {
+
+			clearTimeout($(window).data("timeout"));
+
+			if (visible.photo()) {
+				lychee.imageview.removeClass("full");
+				lychee.loadingBar.css("opacity", 1);
+				lychee.header.css("margin-Top", "0px");
+				if ($("#imageview #image.small").length>0) {
+					$("#imageview #image").css({
+						marginTop: -1*($("#imageview #image").height()/2)+20
+					});
+				} else {
+					$("#imageview #image").css({
+						top: 70,
+						right: 30,
+						bottom: 30,
+						left: 30
+					});
+				}
+			}
+
+		},
+
+		hide: function() {
+
+			if (visible.photo()&&!visible.infobox()) {
+				clearTimeout($(window).data("timeout"));
+				$(window).data("timeout", setTimeout(function() {
+					lychee.imageview.addClass("full");
+					lychee.loadingBar.css("opacity", 0);
+					lychee.header.css("margin-Top", "-45px");
+					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;
+
+			switch (mode) {
+				case "albums":
+					$("#tools_album, #tools_photo").hide();
+					$("#tools_albums").show();
+					break;
+				case "album":
+					$("#tools_albums, #tools_photo").hide();
+					$("#tools_album").show();
+					albumID = album.getID();
+					if (albumID=="s"||albumID=="f") $("#button_edit_album, #button_trash_album, #button_share_album").hide();
+					else if (albumID==0) $("#button_edit_album, #button_share_album").hide();
+					else $("#button_edit_album, #button_trash_album, #button_share_album").show();
+					break;
+				case "photo":
+					$("#tools_albums, #tools_album").hide();
+					$("#tools_photo").show();
+					break;
+			}
+
+		}
+
+	},
+
+	albums: {
+
+		init: function() {
+
+			view.albums.title();
+			view.albums.content.init();
+
+		},
+
+		title: function() {
+
+			lychee.setTitle("Albums", null, 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").retina();
+
+			},
+
+			title: function(albumID) {
+
+				var prefix = "",
+					title = albums.json.content[albumID].title;
+
+				if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
+				if (title.length>18) title = title.substr(0, 18) + "...";
+
+				$(".album[data-id='" + albumID + "'] .overlay h1").html(prefix + title);
+
+			},
+
+			delete: function(albumID) {
+
+				$(".album[data-id='" + albumID + "']").css("opacity", 0).animate({
+					width: 0,
+					marginLeft: 0
+				}, 300, function() {
+					$(this).remove();
+				});
+
+			}
+
+		}
+
+	},
+
+	album: {
+
+		init: function() {
+
+			album.parse();
+
+			view.album.title();
+			view.album.public();
+			view.album.content.init();
+
+			album.json.init = 1;
+
+		},
+
+		title: function() {
+
+			if ((visible.album()||!album.json.init)&&!visible.photo()) {
+
+				switch (album.getID()) {
+					case "f":
+						lychee.setTitle("Starred", album.json.num, false);
+						break;
+					case "s":
+						lychee.setTitle("Public", album.json.num, false);
+						break;
+					case "0":
+						lychee.setTitle("Unsorted", album.json.num, false);
+						break;
+					default:
+						lychee.setTitle(album.json.title, album.json.num, true);
+						break;
+				}
+
+			}
+
+		},
+
+		content: {
+
+			init: function() {
+
+				var photosData = "";
+
+				$.each(album.json.content, function() {
+					album.parse(this);
+					photosData += build.photo(this);
+				});
+				lychee.content.html(photosData);
+
+				$("img").retina();
+
+			},
+
+			title: function(photoID) {
+
+				var title = album.json.content[photoID].title;
+
+				if (title.length>18) title = title.substr(0, 18) + "...";
+
+				$(".photo[data-id='" + photoID + "'] .overlay h1").html(title);
+
+			},
+
+			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.title();
+					}
+				});
+
+			}
+
+		},
+
+		public: function() {
+
+			if (album.json.public==1) {
+				$("#button_share_album a").addClass("active");
+				$("#button_share_album").attr("title", "Share Album");
+				$(".photo .icon-share").remove();
+			} else {
+				$("#button_share_album a").removeClass("active");
+				$("#button_share_album").attr("title", "Make Public");
+			}
+
+		}
+
+	},
+
+	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() {
+
+			view.header.mode("photo");
+
+			// Make body not scrollable
+			$("body").css("overflow", "hidden");
+
+			lychee.animate(lychee.imageview, "fadeIn");
+
+		},
+
+		hide: function() {
+
+			if (!visible.controls()) view.header.show();
+			if (visible.infobox) view.photo.hideInfobox();
+
+			view.header.mode("album");
+
+			// Make body scrollable
+			$("body").css("overflow", "scroll");
+
+			// Hide Photo
+			lychee.animate(lychee.imageview, "fadeOut");
+			$.timer(300,function(){ lychee.imageview.hide() });
+
+		},
+
+		showInfobox: function() {
+
+			if (!visible.infobox()) $("body").append("<div id='infobox_overlay'></div>");
+			lychee.infobox.css("right", "0px");
+
+		},
+
+		hideInfobox: function() {
+
+			$("#infobox_overlay").remove();
+			lychee.infobox.css("right", "-320px");
+
+		},
+
+		title: function(oldTitle) {
+
+			if (photo.json.init) $("#infobox .attr_name").html($("#infobox .attr_name").html().replace(oldTitle, photo.json.title));
+			lychee.setTitle(photo.json.title, null, true);
+
+		},
+
+		description: function(oldDescription) {
+
+			if (photo.json.init) $("#infobox .attr_description").html($("#infobox .attr_description").html().replace(oldDescription, photo.json.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() {
+
+			if (visible.controls()&&photo.isSmall()) lychee.imageview.html("<a id='previous' class='icon-caret-left'></a><a id='next' class='icon-caret-right'></a><div id='image' class='small' style='background-image: url(" + photo.json.url + "); width: " + photo.json.width + "px; height: " + photo.json.height + "px; margin-top: -" + parseInt(photo.json.height/2-20) + "px; margin-left: -" + photo.json.width/2 + "px;'></div>");
+			else if (visible.controls()) lychee.imageview.html("<a id='previous' class='icon-caret-left'></a><a id='next' class='icon-caret-right'></a><div id='image' style='background-image: url(" + photo.json.url + ")'></div>");
+			else if (photo.isSmall()) lychee.imageview.html("<a id='previous' style='left: -50px' class='icon-caret-left'></a><a id='next' style='right: -50px' class='icon-caret-right'></a><div id='image' class='small' style='background-image: url(" + photo.json.url + "); width: " + photo.json.width + "px; height: " + photo.json.height + "px; margin-top: -" + parseInt(photo.json.height/2) + "px; margin-left: -" + photo.json.width/2 + "px;'></div>");
+			else lychee.imageview.html("<a id='previous' style='left: -50px' class='icon-caret-left'></a><a id='next' style='right: -50px' class='icon-caret-right'></a><div id='image' style='background-image: url(" + photo.json.url + "); top: 0px; right: 0px; bottom: 0px; left: 0px;'></div>");
+
+			if (!photo.json.nextPhoto||lychee.viewMode) $("a#next").hide();
+			if (!photo.json.previousPhoto||lychee.viewMode) $("a#previous").hide();
+
+		},
+
+		infobox: function() {
+
+			lychee.infobox.html(build.infobox(photo.json)).show();
+
+		}
+
+	}
+
+}

+ 18 - 3
js/modules/visible.js

@@ -15,8 +15,13 @@ visible = {
 		else return false;
 	},
 
-	imageview: function() {
-		if ($("#image_view.fadeIn").length>0) return true;
+	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;
 	},
 
@@ -26,7 +31,17 @@ visible = {
 	},
 
 	controls: function() {
-		if (lychee.loadingBar.css("opacity")>0) return true;
+		if (lychee.loadingBar.css("opacity")<1) return false;
+		else return true;
+	},
+
+	message: function() {
+		if ($(".message").length>0) return true;
+		else return false;
+	},
+
+	contextMenu: function() {
+		if ($(".contextmenu").length>0) return true;
 		else return false;
 	}
 

+ 9 - 7
js/view.js

@@ -7,7 +7,7 @@
 
 var header = $("header"),
 	headerTitle = $("#title"),
-	image_view = $("#image_view"),
+	imageview = $("#imageview"),
 	api_path = "php/api.php",
 	infobox = $("#infobox");
 
@@ -27,7 +27,7 @@ $(document).ready(function(){
 
 	/* Download */
 	$("#button_download").on(event_name, function() {
-		link = $("#image_view #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
+		link = $("#imageview #image").css("background-image").replace(/"/g,"").replace(/url\(|\)$/ig, "");
 		window.open(link,"_newtab");
 	});
 
@@ -80,17 +80,19 @@ function hideInfobox() {
 
 function loadPhotoInfo(photoID) {
 
-	params = "function=getPhotoInfo&photoID=" + photoID + "&password=''";
+	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);
 
-		image_view.attr("data-id", photoID);
-		if (isPhotoSmall(data)) image_view.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 image_view.html("<div id='image' style='background-image: url(" + data.url + "); top: 70px; right: 30px; bottom: 30px; left: 30px;'></div>");
-		image_view.removeClass("fadeOut").addClass("fadeIn").show();
+		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 + "); top: 70px; right: 30px; bottom: 30px; left: 30px;'></div>");
+		imageview.removeClass("fadeOut").addClass("fadeIn").show();
 
 		infobox.html(build.infobox(data, true)).show();
 

+ 25 - 18
php/api.php

@@ -34,8 +34,8 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) {
 		// Album Functions
 		if ($_POST['function']=='getAlbums') echo json_encode(getAlbums(false));
 		if ($_POST['function']=='getSmartInfo') echo json_encode(getSmartInfo());
+		if ($_POST['function']=='getAlbum'&&isset($_POST['albumID'])) echo json_encode(getAlbum($_POST['albumID']));
 		if ($_POST['function']=='addAlbum'&&isset($_POST['title'])) echo addAlbum($_POST['title']);
-		if ($_POST['function']=='getAlbumInfo'&&isset($_POST['albumID'])) echo json_encode(getAlbumInfo($_POST['albumID']));
 		if ($_POST['function']=='setAlbumTitle'&&isset($_POST['albumID'])&&isset($_POST['title'])) echo setAlbumTitle($_POST['albumID'], $_POST['title']);
 		if ($_POST['function']=='setAlbumPublic'&&isset($_POST['albumID'])) echo setAlbumPublic($_POST['albumID']);
 		if ($_POST['function']=='setAlbumPassword'&&isset($_POST['albumID'])&&isset($_POST['password'])) echo setAlbumPassword($_POST['albumID'], $_POST['password']);
@@ -43,17 +43,13 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) {
 		if (isset($_GET['function'])&&$_GET['function']=='getAlbumArchive'&&isset($_GET['albumID'])) getAlbumArchive($_GET['albumID']);
 
 		// Photo Functions
-		if ($_POST['function']=='getPhotos'&&isset($_POST['albumID'])) echo json_encode(getPhotos($_POST['albumID']));
-		if ($_POST['function']=='getPhotoInfo'&&isset($_POST['photoID'])) echo json_encode(getPhotoInfo($_POST['photoID']));
-		if ($_POST['function']=='getShortlink'&&isset($_POST['photoID'])) echo getShortlink($_POST['photoID']);
-		if ($_POST['function']=='setAlbum'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo setAlbum($_POST['photoID'], $_POST['albumID']);
+		if ($_POST['function']=='getPhoto'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo json_encode(getPhoto($_POST['photoID'], $_POST['albumID']));
 		if ($_POST['function']=='deletePhoto'&&isset($_POST['photoID'])) echo deletePhoto($_POST['photoID']);
+		if ($_POST['function']=='setAlbum'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo setAlbum($_POST['photoID'], $_POST['albumID']);
 		if ($_POST['function']=='setPhotoTitle'&&isset($_POST['photoID'])&&isset($_POST['title'])) echo setPhotoTitle($_POST['photoID'], $_POST['title']);
 		if ($_POST['function']=='setPhotoStar'&&isset($_POST['photoID'])) echo setPhotoStar($_POST['photoID']);
 		if ($_POST['function']=='setPhotoPublic'&&isset($_POST['photoID'])&&isset($_POST['url'])) echo setPhotoPublic($_POST['photoID'], $_POST['url']);
 		if ($_POST['function']=='setPhotoDescription'&&isset($_POST['photoID'])&&isset($_POST['description'])) echo setPhotoDescription($_POST['photoID'], $_POST['description']);
-		if ($_POST['function']=='previousPhoto'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo json_encode(previousPhoto($_POST['photoID'], $_POST['albumID'], false));
-		if ($_POST['function']=='nextPhoto'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo json_encode(nextPhoto($_POST['photoID'], $_POST['albumID'], false));
 
         // Add Function
 		if ($_POST['function']=='upload'&&isset($_FILES)&&isset($_POST['albumID'])) echo upload($_FILES, $_POST['albumID']);
@@ -76,22 +72,33 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) {
 
 		// Album Functions
 		if ($_POST['function']=='getAlbums') echo json_encode(getAlbums(true));
-		if ($_POST['function']=='getAlbumInfo'&&isset($_POST['albumID'])&&isset($_POST['password'])&&isAlbumPublic($_POST['albumID'], $_POST['password'])) echo json_encode(getAlbumInfo($_POST['albumID']));
-
-		// Photo Functions
-		if ($_POST['function']=='getPhotos') {
-			if (isset($_POST['albumID'])&&isset($_POST['password'])&&isAlbumPublic($_POST['albumID'], $_POST['password'])) echo json_encode(getPhotos($_POST['albumID']));
-			else echo json_encode('HTTP/1.1 403 Wrong password!');
+		if ($_POST['function']=='getAlbum'&&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 json_encode('HTTP/1.1 403 Wrong password!');
+			} else {
+				// Album Private
+				echo json_encode('HTTP/1.1 403 Album private!');
+			}
+		}
+		if ($_POST['function']=='checkAlbumAccess'&&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;
+			}
 		}
 
-		if ($_POST['function']=='getPhotoInfo') {
-			if (isset($_POST['photoID'])&&isset($_POST['password'])&&isPhotoPublic($_POST['photoID'], $_POST['password'])) echo json_encode(getPhotoInfo($_POST['photoID']));
+		// Photo Functions
+		if ($_POST['function']=='getPhoto'&&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 json_encode('HTTP/1.1 403 Wrong password!');
 		}
 
-		if ($_POST['function']=='previousPhoto'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo json_encode(previousPhoto($_POST['photoID'], $_POST['albumID'], false));
-		if ($_POST['function']=='nextPhoto'&&isset($_POST['photoID'])&&isset($_POST['albumID'])) echo json_encode(nextPhoto($_POST['photoID'], $_POST['albumID'], false));
-
 		// Session Functions
 		if ($_POST['function']=='init') echo json_encode(init('public'));
 		if ($_POST['function']=='login') echo login($_POST['user'], $_POST['password']);

+ 0 - 2
php/config.php

@@ -23,7 +23,5 @@ $password = '1234'; //Admin Password
 $checkForUpdates = true;
 $thumbQuality = 95; //Quality of the Thumbs (0-100). Default: 95
 $sorting = 'DESC'; //ASC or DESC sorting of albums and photos
-$bitlyUsername = ''; //Your Bit.ly Username
-$bitlyApi = ''; //Your Bit.ly API Key
 
 ?>

+ 271 - 223
php/functions.php

@@ -7,7 +7,7 @@
  * @copyright   2013 by Philipp Maurer, Tobias Reich
  */
 
-if(!defined('LYCHEE')) die('Direct access is not allowed!');
+if (!defined('LYCHEE')) die('Direct access is not allowed!');
 
 // Database Functions
 function dbConnect() {
@@ -21,12 +21,12 @@ function dbConnect() {
 		createDatabase($db, $database);
 	}
     $query = "SELECT * FROM lychee_photos, lychee_albums;";
-    if(!$database->query($query)) createTables($database);
+    if (!$database->query($query)) createTables($database);
     return $database;
 }
 function dbClose() {
 	global $database;
-    if(!$database->close()) {
+    if (!$database->close()) {
         echo "Closing the connection failed!";
         return false;
     }
@@ -35,7 +35,7 @@ function dbClose() {
 function createDatabase($db, $database) {
 	$result = $database->query("CREATE DATABASE IF NOT EXISTS $db;");
 	$database->select_db($db);
-	if(!$result) return false;
+	if (!$result) return false;
 	return true;
 }
 function createTables($database) {
@@ -48,7 +48,7 @@ function createTables($database) {
   PRIMARY KEY (`id`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
 
     $query = "CREATE TABLE `lychee_photos` (
   `id` bigint(14) NOT NULL,
@@ -56,7 +56,6 @@ function createTables($database) {
   `description` varchar(160) NOT NULL,
   `url` varchar(100) NOT NULL,
   `public` tinyint(1) NOT NULL,
-  `shortlink` varchar(20) NOT NULL,
   `type` varchar(10) NOT NULL,
   `width` int(11) NOT NULL,
   `height` int(11) NOT NULL,
@@ -78,80 +77,92 @@ function createTables($database) {
   PRIMARY KEY (`id`)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     return true;
 }
 
 // Upload Functions
 function upload($files, $albumID) {
+
 	global $database;
+
+	switch($albumID) {
+		// s for public (share)
+	    case 's':
+	        $public = 1;
+	        $star = 0;
+	        $albumID = 0;
+	        break;
+	    // f for starred (fav)
+	    case 'f':
+	        $star = 1;
+	        $public = 0;
+	        $albumID = 0;
+	        break;
+	    default:
+	        $star = 0;
+	        $public = 0;
+	}
+
 	foreach ($files as $file) {
-	    switch($albumID) {
-	    	// s for public (share)
-	        case 's':
-	            $public = 1;
-	            $star = 0;
-	            $albumID = 0;
-	            break;
-	        // f for starred (fav)
-	        case 'f':
-	            $star = 1;
-	            $public = 0;
-	            $albumID = 0;
-	            break;
-	        default:
-	            $star = 0;
-	            $public = 0;
-	    }
+
 	    $id = str_replace('.', '', microtime(true));
 	    while(strlen($id)<14) $id .= 0;
 	    $tmp_name = $file["tmp_name"];
 	    $type = getimagesize($tmp_name);
-	    if(($type[2]!=1)&&($type[2]!=2)&&($type[2]!=3)) return false;
+	    if (($type[2]!=1)&&($type[2]!=2)&&($type[2]!=3)) return false;
 	    $data = $file["name"];
 	    $data = explode('.',$data);
 	    $data = array_reverse ($data);
 	    $data = $data[0];
-	    if(!is_uploaded_file($file)) {
-	    	if (copy($tmp_name, "../uploads/big/$id.$data")) {
+
+	    // Import if not uploaded via web
+	    if (!is_uploaded_file($file)) {
+	    	if (copy($tmp_name, "../uploads/big/" . md5($id) . ".$data")) {
 				unlink($tmp_name);
 				$import_name = $tmp_name;
 			}
 	    } else {
-		    move_uploaded_file($tmp_name, "../uploads/big/$id.$data");
+		    move_uploaded_file($tmp_name, "../uploads/big/" . md5($id) . ".$data");
 		    $import_name = "";
 	    }
-	    createThumb($id.".".$data);
+
+	    // Create Thumb
+	    createThumb(md5($id).".".$data);
+
 	    // Read infos
-	    $info = getCamera($id.".".$data);
-	    $title="";
-	    if(isset($info['type'])){$type=$info['type'];}else{$type="";}
-	    if(isset($info['width'])){$width=$info['width'];}else{$width="";}
-	    if(isset($info['height'])){$height=$info['height'] OR "";}else{$height="";}
-	    if(isset($info['size'])){$size=$info['size'] OR "";}else{$size="";}
-	    if(isset($info['date'])){$sysdate=$info['date'];}else{$sysdate="";}
-	    if(isset($info['time'])){$systime=$info['time'];}else{$systime="";}
-	    if(isset($info['iso'])){$iso=$info['iso'];}else{$iso="";}
-	    if(isset($info['aperture'])){$aperture=$info['aperture'];}else{$aperture="";}
-	    if(isset($info['make'])){$make=$info['make'];}else{$make="";}
-	    if(isset($info['model'])){$model=$info['model'] OR "";}else{$model="";}
-	    if(isset($info['shutter'])){$shutter=$info['shutter'];}else{$shutter="";}
-	    if(isset($info['focal'])){$focal=$info['focal'];}else{$focal="";}
-	    if(isset($info['takeDate'])){$takeDate=$info['takeDate'];}else{$takeDate="";}
-	    if(isset($info['takeTime'])){$takeTime=$info['takeTime'];}else{$takeTime="";}
+	    $info = getCamera(md5($id).".".$data);
+	    $title = "";
+	    if (isset($info['type'])){$type=$info['type'];} else {$type="";}
+	    if (isset($info['width'])){$width=$info['width'];} else {$width="";}
+	    if (isset($info['height'])){$height=$info['height'] OR "";} else {$height="";}
+	    if (isset($info['size'])){$size=$info['size'] OR "";} else {$size="";}
+	    if (isset($info['date'])){$sysdate=$info['date'];} else {$sysdate="";}
+	    if (isset($info['time'])){$systime=$info['time'];} else {$systime="";}
+	    if (isset($info['iso'])){$iso=$info['iso'];} else {$iso="";}
+	    if (isset($info['aperture'])){$aperture=$info['aperture'];} else {$aperture="";}
+	    if (isset($info['make'])){$make=$info['make'];} else {$make="";}
+	    if (isset($info['model'])){$model=$info['model'] OR "";} else {$model="";}
+	    if (isset($info['shutter'])){$shutter=$info['shutter'];} else {$shutter="";}
+	    if (isset($info['focal'])){$focal=$info['focal'];} else {$focal="";}
+	    if (isset($info['takeDate'])){$takeDate=$info['takeDate'];} else {$takeDate="";}
+	    if (isset($info['takeTime'])){$takeTime=$info['takeTime'];} else {$takeTime="";}
 	    $query = "INSERT INTO lychee_photos (id, title, url, type, width, height, size, sysdate, systime, iso, aperture, make, model, shutter, focal, takedate, taketime, thumbUrl, album, public, star, import_name)
-	        VALUES ('$id', '$title', 'uploads/big/$id.$data', '$type', '$width', '$height', '$size', '$sysdate', '$systime', '$iso', '$aperture', '$make', '$model', '$shutter', '$focal', '$takeDate', '$takeTime', 'uploads/thumb/$id.$data', '$albumID', '$public', '$star', '$import_name');";
+	        VALUES ('$id', '$title', '" . md5($id) . ".$data', '$type', '$width', '$height', '$size', '$sysdate', '$systime', '$iso', '$aperture', '$make', '$model', '$shutter', '$focal', '$takeDate', '$takeTime', '" . md5($id) . ".$data', '$albumID', '$public', '$star', '$import_name');";
 	    $result = $database->query($query);
+
     }
+
     return true;
+
 }
-function getCamera($photoID) {
+function getCamera($filename) {
 	global $database;
-    $url = "../uploads/big/$photoID";
+    $url = "../uploads/big/$filename";
     $type = getimagesize($url);
     $type = $type['mime'];
 
-    if(($type == "image/jpeg") && function_exists('exif_read_data') ){
+    if (($type == "image/jpeg") && function_exists('exif_read_data') ){
 
         $exif = exif_read_data($url, "EXIF", 0);
 
@@ -162,35 +173,33 @@ function getCamera($photoID) {
         $return['width'] = $generalInfos[0];
         $return['height'] = $generalInfos[1];
         $size = (filesize($url) / 1024);
-        if($size >= 1024){$size=round($size/1024,1)." MB";}else{$size=round($size,1)." KB";}
+        if ($size >= 1024){$size=round($size/1024,1)." MB";} else {$size=round($size,1)." KB";}
         $return['size'] = $size;
         $return['date'] = date("d.m.Y",filectime($url));
         $return['time'] = date("H:i:s",filectime($url));
 
-        //echo $exif['FileDateTime']."<br/>".$exif['DateTimeOriginal'];
-
         // Camera Information
-        if(isset($exif['ISOSpeedRatings'])){$return['iso']="ISO-".$exif['ISOSpeedRatings'];}
-        if(isset($exif['COMPUTED']['ApertureFNumber'])){$return['aperture']=$exif['COMPUTED']['ApertureFNumber'];}
-        if(isset($exif['Make'])){$return['make']=$exif['Make'];}
-        if(isset($exif['Model'])){$return['model']=$exif['Model'];}
-        if(isset($exif['ExposureTime'])){$return['shutter']=$exif['ExposureTime']." Sek.";}
-        if(isset($exif['FocalLength'])){$return['focal']=($exif['FocalLength']/1)." mm";}
-        if(isset($exif['Software'])){$return['software']=$exif['Software'];}
-        if(isset($exif['DateTimeOriginal'])) {
+        if (isset($exif['ISOSpeedRatings'])){$return['iso']="ISO-".$exif['ISOSpeedRatings'];}
+        if (isset($exif['COMPUTED']['ApertureFNumber'])){$return['aperture']=$exif['COMPUTED']['ApertureFNumber'];}
+        if (isset($exif['Make'])){$return['make']=$exif['Make'];}
+        if (isset($exif['Model'])){$return['model']=$exif['Model'];}
+        if (isset($exif['ExposureTime'])){$return['shutter']=$exif['ExposureTime']." Sek.";}
+        if (isset($exif['FocalLength'])){$return['focal']=($exif['FocalLength']/1)." mm";}
+        if (isset($exif['Software'])){$return['software']=$exif['Software'];}
+        if (isset($exif['DateTimeOriginal'])) {
             $exifDate = explode(" ",$exif['DateTimeOriginal']);
             $date = explode(":", $exifDate[0]); $return['takeDate'] = $date[2].".".$date[1].".".$date[0];
             $return['takeTime'] = $exifDate[1];
         }
 
-    }else{
+    } else {
 
         $exif = getimagesize($url);
         $return['type'] = $exif['mime'];
         $return['width'] = $exif[0];
         $return['height'] = $exif[1];
         $size = (filesize($url) / 1024);
-        if($size >= 1024){$size=round($size/1024,1)." MB";}else{$size=round($size,1)." KB";}
+        if ($size >= 1024){$size=round($size/1024,1)." MB";} else {$size=round($size,1)." KB";}
         $return['size'] = $size;
         $return['date'] = date("d.m.Y",filectime($url));
         $return['time'] = date("H:i:s",filectime($url));
@@ -198,23 +207,20 @@ function getCamera($photoID) {
     }
     return $return;
 }
-function createThumb($photoName, $width = 200, $width2x = 400, $height = 200, $height2x = 400) {
+function createThumb($filename, $width = 200, $width2x = 400, $height = 200, $height2x = 400) {
+
 	global $database, $thumbQuality;
-    $photoUrl = "../uploads/big/$photoName";
-    $newUrl = "../uploads/thumb/$photoName";
-    $thumbPhotoName = explode(".", $photoName);
+    $photoUrl = "../uploads/big/$filename";
+    $newUrl = "../uploads/thumb/$filename";
+    $thumbPhotoName = explode(".", $filename);
     $newUrl2x = "../uploads/thumb/".$thumbPhotoName[0]."@2x.".$thumbPhotoName[1];
     $oldImg = getimagesize($photoUrl);
     $type = $oldImg['mime'];
-    switch($type) {
-        case "image/jpeg": $sourceImg = imagecreatefromjpeg($photoUrl); break;
-        case "image/png": $sourceImg = imagecreatefrompng($photoUrl); break;
-        case "image/gif": $sourceImg = imagecreatefromgif($photoUrl); break;
-        default: return false;
-    }
+
+    // Set position and size
     $thumb = imagecreatetruecolor($width, $height);
     $thumb2x = imagecreatetruecolor($width2x, $height2x);
-    if($oldImg[0]<$oldImg[1]) {
+    if ($oldImg[0]<$oldImg[1]) {
         $newSize = $oldImg[0];
         $startWidth = 0;
         $startHeight = $oldImg[1]/2 - $oldImg[0]/2;
@@ -223,6 +229,14 @@ function createThumb($photoName, $width = 200, $width2x = 400, $height = 200, $h
         $startWidth = $oldImg[0]/2 - $oldImg[1]/2;
         $startHeight = 0;
     }
+
+    // Create new image
+    switch($type) {
+        case "image/jpeg": $sourceImg = imagecreatefromjpeg($photoUrl); break;
+        case "image/png": $sourceImg = imagecreatefrompng($photoUrl); break;
+        case "image/gif": $sourceImg = imagecreatefromgif($photoUrl); break;
+        default: return false;
+    }
     imagecopyresampled($thumb,$sourceImg,0,0,$startWidth,$startHeight,$width,$height,$newSize,$newSize);
     imagecopyresampled($thumb2x,$sourceImg,0,0,$startWidth,$startHeight,$width2x,$height2x,$newSize,$newSize);
     switch($type) {
@@ -231,14 +245,15 @@ function createThumb($photoName, $width = 200, $width2x = 400, $height = 200, $h
         case "image/gif": imagegif($thumb,$newUrl); imagegif($thumb2x,$newUrl2x); break;
         default: return false;
     }
+
     return true;
+
 }
 
 // Session Functions
 function init($mode) {
-	global $checkForUpdates, $bitlyUsername;
+	global $checkForUpdates;
 	$return["config"]["checkForUpdates"] = $checkForUpdates;
-	$return["config"]["bitlyUsername"] = $bitlyUsername;
 	if ($mode=="admin") $return["loggedIn"] = true;
 	else $return["loggedIn"] = false;
 	return $return;
@@ -261,12 +276,12 @@ function logout() {
 // Album Functions
 function addAlbum($title) {
 	global $database;
-    $title = mysqli_real_escape_string($database, $title);
-    if(strlen($title)<1||strlen($title)>30) return false;
+    $title = mysqli_real_escape_string($database, urldecode($title));
+    if (strlen($title)<1||strlen($title)>30) return false;
     $sysdate = date("d.m.Y");
     $query = "INSERT INTO lychee_albums (title, sysdate) VALUES ('$title', '$sysdate');";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     return $database->insert_id;
 }
 function getAlbums($public) {
@@ -281,12 +296,12 @@ function getAlbums($public) {
     $result = $database->query($query) OR die("Error: $result <br>".$database->error);
     $i=0;
     while($row = $result->fetch_object()) {
-    	$return["album"][$i]['id'] = $row->id;
-        $return["album"][$i]['title'] = $row->title;
-        $return["album"][$i]['public'] = $row->public;
-        $return["album"][$i]['sysdate'] = $row->sysdate;
-        if ($row->password=="") $return["album"][$i]['password'] = false;
-        else $return["album"][$i]['password'] = true;
+    	$return["content"][$row->id]['id'] = $row->id;
+        $return["content"][$row->id]['title'] = $row->title;
+        $return["content"][$row->id]['public'] = $row->public;
+        $return["content"][$row->id]['sysdate'] = $row->sysdate;
+        if ($row->password=="") $return["content"][$row->id]['password'] = false;
+        else $return["content"][$row->id]['password'] = true;
 
         // Thumbs
         if (($public&&$row->password=="")||(!$public)) {
@@ -295,92 +310,120 @@ function getAlbums($public) {
 	        $result2 = $database->query($query);
 	        $k = 0;
 	        while($row2 = $result2->fetch_object()){
-	            $return["album"][$i]["thumb$k"] = $row2->thumbUrl;
+	            $return["content"][$row->id]["thumb$k"] = $row2->thumbUrl;
 	            $k++;
 	        }
-	        if(!isset($return["album"][$i]["thumb0"]))$return["album"][$i]["thumb0"]="";
-	        if(!isset($return["album"][$i]["thumb1"]))$return["album"][$i]["thumb1"]="";
-	        if(!isset($return["album"][$i]["thumb2"]))$return["album"][$i]["thumb2"]="";
+	        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]["thumb2"])) $return["content"][$row->id]["thumb2"]="";
         }
         $i++;
     }
-    if($i==0) $return["albums"] = false;
+    if ($i==0) $return["albums"] = false;
     else $return["albums"] = true;
     return $return;
 }
+function getAlbum($albumID) {
+	global $database, $sorting;
+	switch($albumID) {
+	    case "f":
+	    	$return['public'] = false;
+	    	$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 ORDER BY id $sorting;";
+	        break;
+	    case "s":
+	    	$return['public'] = false;
+	    	$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 ORDER BY id $sorting;";
+	        break;
+	    case 0:
+	    	$return['public'] = false;
+	    	$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = 0 ORDER BY id $sorting;";
+	    default:
+	    	$result = $database->query("SELECT title, public, password FROM lychee_albums WHERE id = '$albumID';");
+	    	$row = $result->fetch_object();
+	    	$return['title'] = $row->title;
+	    	$return['public'] = $row->public;
+	    	if ($row->password=="") $return['password'] = false;
+	    	else $return['password'] = true;
+	    	$query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY id $sorting;";
+	    	break;
+	}
+	$result = $database->query($query);
+	$i = 0;
+	while($row = $result->fetch_array()) {
+	    $return['content'][$row['id']] = $row;
+	    $i++;
+	}
+	if ($i==0) $return['content'] = false;
+	$return['id'] = $albumID;
+	$return['num'] = $i;
+	return $return;
+}
 function getSmartInfo() {
+
 	global $database, $sorting;
+
+	// Unsorted
     $query = "SELECT * FROM lychee_photos WHERE album = 0 ORDER BY id $sorting;";
     $result = $database->query($query);
     $i = 0;
     while($row = $result->fetch_object()) {
-        if($i<3) $return["unsortThumb$i"] = $row->thumbUrl;
+        if ($i<3) $return["unsortedThumb$i"] = $row->thumbUrl;
         $i++;
     }
-    $return['unsortNum'] = $i;
+    $return['unsortedNum'] = $i;
 
+	// Public
     $query2 = "SELECT * FROM lychee_photos WHERE public = 1 ORDER BY id $sorting;";
     $result2 = $database->query($query2);
     $i = 0;
     while($row2 = $result2->fetch_object()) {
-        if($i<3) $return["publicThumb$i"] = $row2->thumbUrl;
+        if ($i<3) $return["publicThumb$i"] = $row2->thumbUrl;
         $i++;
     }
     $return['publicNum'] = $i;
 
+	// Starred
     $query3 = "SELECT * FROM lychee_photos WHERE star = 1 ORDER BY id $sorting;";
     $result3 = $database->query($query3);
     $i = 0;
     while($row3 = $result3->fetch_object()) {
-        if($i<3) $return["starredThumb$i"] = $row3->thumbUrl;
+        if ($i<3) $return["starredThumb$i"] = $row3->thumbUrl;
         $i++;
     }
     $return['starredNum'] = $i;
+
     return $return;
-}
-function getAlbumInfo($albumID) {
-	global $database;
-    $query = "SELECT * FROM lychee_albums WHERE id = '$albumID';";
-    $result = $database->query($query);
-    $row = $result->fetch_object();
-    $return['title'] = $row->title;
-    $return['date'] = $row->sysdate;
-    $return['public'] = $row->public;
-    $query = "SELECT COUNT(*) AS num FROM lychee_photos WHERE album = '$albumID';";
-    $result = $database->query($query);
-    $row = $result->fetch_object();
-    $return['num'] = $row->num;
-    return $return;
+
 }
 function setAlbumTitle($albumID, $title) {
 	global $database;
     $title = mysqli_real_escape_string($database, urldecode($title));
-    if(strlen($title)<1||strlen($title)>30) return false;
+    if (strlen($title)<1||strlen($title)>30) return false;
     $query = "UPDATE lychee_albums SET title = '$title' WHERE id = '$albumID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     return true;
 }
 function deleteAlbum($albumID, $delAll) {
 	global $database;
-    if($delAll=="true") {
+    if ($delAll=="true") {
         $query = "SELECT id FROM lychee_photos WHERE album = '$albumID';";
         $result = $database->query($query);
         $error = false;
         while($row =  $result->fetch_object()) {
-            if(!deletePhoto($row->id)) $error = true;
+            if (!deletePhoto($row->id)) $error = true;
         }
     } else {
         $query = "UPDATE lychee_photos SET album = '0' WHERE album = '$albumID';";
         $result = $database->query($query);
-        if(!$result) return false;
+        if (!$result) return false;
     }
-    if($albumID!=0) {
+    if ($albumID!=0) {
         $query = "DELETE FROM lychee_albums WHERE id = '$albumID';";
         $result = $database->query($query);
-        if(!$result) return false;
+        if (!$result) return false;
     }
-    if($error) return false;
+    if ($error) return false;
     return true;
 }
 function getAlbumArchive($albumID) {
@@ -408,7 +451,7 @@ function getAlbumArchive($albumID) {
     $query = "SELECT * FROM lychee_albums WHERE id = '$albumID';";
     $result = $database->query($query);
     $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";
 
     $zip = new ZipArchive();
@@ -438,64 +481,57 @@ function setAlbumPublic($albumID) {
 	$query = "SELECT public FROM lychee_albums WHERE id = '$albumID';";
 	$result = $database->query($query);
 	$row = $result->fetch_object();
-	if($row->public == 0){
+	if ($row->public == 0){
 	    $public = 1;
-	}else{
+	} else {
 	    $public = 0;
 	}
 	$query = "UPDATE lychee_albums SET public = '$public', password = NULL WHERE id = '$albumID';";
 	$result = $database->query($query);
-	if(!$result) return false;
+	if (!$result) return false;
+	if ($public==1) {
+		$query = "UPDATE lychee_photos SET public = 0 WHERE album = '$albumID';";
+		$result = $database->query($query);
+		if (!$result) return false;
+	}
 	return true;
 }
 function setAlbumPassword($albumID, $password) {
 	global $database;
 	$query = "UPDATE lychee_albums SET password = '$password' WHERE id = '$albumID';";
 	$result = $database->query($query);
-	if(!$result) return false;
+	if (!$result) return false;
 	return true;
 }
-function isAlbumPublic($albumID, $password) {
+function checkAlbumPassword($albumID, $password) {
 	global $database;
 	$query = "SELECT public, password FROM lychee_albums WHERE id = '$albumID';";
 	$result = $database->query($query);
 	$row = $result->fetch_object();
-	if(($row->public == 1) && ($row->password == $password)){
-		return true;
-	}else{
-	    return false;
-	}
+	if ($row->password=="") return true;
+	else if ($row->password==$password) return true;
+	else return false;
+}
+function isAlbumPublic($albumID) {
+	global $database;
+	$query = "SELECT public, password FROM lychee_albums WHERE id = '$albumID';";
+	$result = $database->query($query);
+	$row = $result->fetch_object();
+	if ($row->public==1) return true;
+	else return false;
 }
 
 // Photo Functions
-function getPhotos($albumID) {
-	global $database, $sorting;
-    switch($albumID) {
-        case "f": $query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE star = 1 ORDER BY id $sorting;";
-            break;
-        case "s": $query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE public = 1 ORDER BY id $sorting;";
-            break;
-        default: $query = "SELECT id, title, sysdate, public, star, album, thumbUrl FROM lychee_photos WHERE album = '$albumID' ORDER BY id $sorting;";
-    }
-    $result = $database->query($query);
-    $i = 0;
-    while($row = $result->fetch_array()) {
-        $return[$i] = $row;
-        $i++;
-    }
-    if($i==0) return false;
-    return $return;
-}
-function getPhotoInfo($photoID) {
+function getPhoto($photoID, $albumID) {
 	global $database;
-	if(!is_numeric($photoID)) {
+	if (!is_numeric($photoID)) {
 		$query = "SELECT COUNT(*) AS quantity FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';";
 		$result = $database->query($query);
 		$row = $result->fetch_object();
-		if($row->quantity == 0) {
+		if ($row->quantity == 0) {
 			importPhoto($photoID, 's');
 		}
-		if(is_file("../uploads/import/$photoID")) {
+		if (is_file("../uploads/import/$photoID")) {
 			importPhoto($photoID, 's');
 		}
 		$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID' ORDER BY ID DESC;";
@@ -504,6 +540,32 @@ function getPhotoInfo($photoID) {
 	}
     $result = $database->query($query);
     $return = $result->fetch_array();
+
+    if ($albumID!='false') {
+
+    	if ($return['album']!=0) {
+
+    		$result = $database->query("SELECT public FROM lychee_albums WHERE id = " . $return['album'] . ";");
+    		$return_album = $result->fetch_array();
+    		if ($return_album['public']=="1") $return['public'] = "2";
+
+    	}
+
+    	$return['original_album'] = $return['album'];
+	    $return['album'] = $albumID;
+
+	    $nextPhoto = getNextPhotoID($photoID, $albumID, false);
+	    if ($nextPhoto==$photoID) $return['nextPhoto'] = false;
+		else $return['nextPhoto'] = $nextPhoto;
+
+		$previousPhoto = getPreviousPhotoID($photoID, $albumID, false);
+		if ($previousPhoto==$photoID) $return['previousPhoto'] = false;
+		else $return['previousPhoto'] = $previousPhoto;
+
+	}
+
+	unset($return['album_public']);
+
     return $return;
 }
 function downloadPhoto($photoID) {
@@ -532,26 +594,17 @@ function downloadPhoto($photoID) {
 }
 function setPhotoPublic($photoID, $url) {
 	global $database;
-    $query = "SELECT public, shortlink FROM lychee_photos WHERE id = '$photoID';";
+    $query = "SELECT public FROM lychee_photos WHERE id = '$photoID';";
     $result = $database->query($query);
     $row = $result->fetch_object();
-    if($row->public == 0){
+    if ($row->public == 0){
         $public = 1;
-    }else{
+    } else {
         $public = 0;
     }
-    if($public==0 || preg_match('/localhost/', $_SERVER['HTTP_REFERER']) || preg_match('\file:\/\/\/', $_SERVER['HTTP_REFERER'])) {
-        $shortlink = "";
-    }else{
-        if($row->shortlink==""){
-            $shortlink = urlShortner($url);
-        }else{
-            $shortlink = $row->shortlink;
-        }
-    }
-    $query = "UPDATE lychee_photos SET public = '$public', shortlink = '$shortlink' WHERE id = '$photoID';";
+    $query = "UPDATE lychee_photos SET public = '$public' WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     return true;
 }
 function setPhotoStar($photoID) {
@@ -559,7 +612,7 @@ function setPhotoStar($photoID) {
     $query = "SELECT star FROM lychee_photos WHERE id = '$photoID';";
     $result = $database->query($query);
     $row = $result->fetch_object();
-    if($row->star == 0) {
+    if ($row->star == 0) {
         $star = 1;
     } else {
         $star = 0;
@@ -568,95 +621,95 @@ function setPhotoStar($photoID) {
     $result = $database->query($query);
     return true;
 }
-function nextPhoto($photoID, $albumID, $innerCall) {
+function getNextPhotoID($photoID, $albumID, $innerCall) {
 	global $database, $sorting;
-	if (!$innerCall&&$sorting=="ASC") return previousPhoto($photoID, $albumID, true);
+	if (!$innerCall&&$sorting=="ASC") return getPreviousPhotoID($photoID, $albumID, true);
     switch($albumID) {
-        case 'f': $query = "SELECT * FROM lychee_photos WHERE id < '$photoID' AND star = '1' ORDER BY id DESC LIMIT 0, 1;";
+        case 'f': $query = "SELECT id FROM lychee_photos WHERE id < '$photoID' AND star = '1' ORDER BY id DESC LIMIT 0, 1;";
             break;
-        case 's': $query = "SELECT * FROM lychee_photos WHERE id < '$photoID' AND public = '1' ORDER BY id DESC LIMIT 0, 1;";
+        case 's': $query = "SELECT id FROM lychee_photos WHERE id < '$photoID' AND public = '1' ORDER BY id DESC LIMIT 0, 1;";
             break;
-        default: $query = "SELECT * FROM lychee_photos WHERE id < '$photoID' AND album = '$albumID' ORDER BY id DESC LIMIT 0, 1;";
+        default: $query = "SELECT id FROM lychee_photos WHERE id < '$photoID' AND album = '$albumID' ORDER BY id DESC LIMIT 0, 1;";
     }
     $result = $database->query($query);
     $return = $result->fetch_array();
-    if(!$return || ($return==0)) {
+    if (!$return || ($return==0)) {
         switch($albumID) {
-            case 'f': $query = "SELECT * FROM lychee_photos WHERE star = '1' ORDER BY id DESC LIMIT 0, 1;";
+            case 'f': $query = "SELECT id FROM lychee_photos WHERE star = '1' ORDER BY id DESC LIMIT 0, 1;";
                 break;
-            case 's': $query = "SELECT * FROM lychee_photos WHERE public = '1' ORDER BY id DESC LIMIT 0, 1;";
+            case 's': $query = "SELECT id FROM lychee_photos WHERE public = '1' ORDER BY id DESC LIMIT 0, 1;";
                 break;
-            default: $query = "SELECT * FROM lychee_photos WHERE album = '$albumID' ORDER BY id DESC LIMIT 0, 1;";
+            default: $query = "SELECT id FROM lychee_photos WHERE album = '$albumID' ORDER BY id DESC LIMIT 0, 1;";
         }
         $result = $database->query($query);
         $return = $result->fetch_array();
     }
-    return $return;
+    return $return['id'];
 }
-function previousPhoto($photoID, $albumID, $innerCall) {
+function getPreviousPhotoID($photoID, $albumID, $innerCall) {
 	global $database, $sorting;
-	if (!$innerCall&&$sorting=="ASC") return nextPhoto($photoID, $albumID, true);
+	if (!$innerCall&&$sorting=="ASC") return getNextPhotoID($photoID, $albumID, true);
     switch($albumID) {
-        case 'f': $query = "SELECT * FROM lychee_photos WHERE id > '$photoID' AND star = '1' ORDER BY id LIMIT 0, 1;";
+        case 'f': $query = "SELECT id FROM lychee_photos WHERE id > '$photoID' AND star = '1' ORDER BY id LIMIT 0, 1;";
             break;
-        case 's': $query = "SELECT * FROM lychee_photos WHERE id > '$photoID' AND public = '1' ORDER BY id LIMIT 0, 1;";
+        case 's': $query = "SELECT id FROM lychee_photos WHERE id > '$photoID' AND public = '1' ORDER BY id LIMIT 0, 1;";
             break;
-        default: $query = "SELECT * FROM lychee_photos WHERE id > '$photoID' AND album = '$albumID' ORDER BY id LIMIT 0, 1;";
+        default: $query = "SELECT id FROM lychee_photos WHERE id > '$photoID' AND album = '$albumID' ORDER BY id LIMIT 0, 1;";
     }
     $result = $database->query($query);
     $return = $result->fetch_array();
-    if(!$return || ($return==0)) {
+    if (!$return || ($return==0)) {
         switch($albumID) {
-            case 'f': $query = "SELECT * FROM lychee_photos WHERE star = '1' ORDER BY id LIMIT 0, 1;";
+            case 'f': $query = "SELECT id FROM lychee_photos WHERE star = '1' ORDER BY id LIMIT 0, 1;";
                 break;
-            case 's': $query = "SELECT * FROM lychee_photos WHERE public = '1' ORDER BY id LIMIT 0, 1;";
+            case 's': $query = "SELECT id FROM lychee_photos WHERE public = '1' ORDER BY id LIMIT 0, 1;";
                 break;
-            default: $query = "SELECT * FROM lychee_photos WHERE album = '$albumID' ORDER BY id LIMIT 0, 1;";
+            default: $query = "SELECT id FROM lychee_photos WHERE album = '$albumID' ORDER BY id LIMIT 0, 1;";
         }
         $result = $database->query($query);
         $return = $result->fetch_array();
     }
-    return $return;
+    return $return['id'];
 }
 function setAlbum($photoID, $newAlbum) {
 	global $database;
     $query = "UPDATE lychee_photos SET album = '$newAlbum' WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     else return true;
 }
 function setPhotoTitle($photoID, $title) {
 	global $database;
     $title = mysqli_real_escape_string($database, urldecode($title));
-    if(strlen($title)>30) return false;
+    if (strlen($title)>30) return false;
     $query = "UPDATE lychee_photos SET title = '$title' WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     else return true;
 }
 function setPhotoDescription($photoID, $description) {
 	global $database;
     $description = mysqli_real_escape_string($database, htmlentities($description));
-    if(strlen($description)>160) return false;
+    if (strlen($description)>160) return false;
     $query = "UPDATE lychee_photos SET description = '$description' WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     return true;
 }
 function deletePhoto($photoID) {
 	global $database;
     $query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$result) return false;
+    if (!$result) return false;
     $row = $result->fetch_object();
     $retinaUrl = explode(".", $row->thumbUrl);
-    $unlink1 = unlink("../".$row->url);
-    $unlink2 = unlink("../".$row->thumbUrl);
-    $unlink3 = unlink("../".$retinaUrl[0].'@2x.'.$retinaUrl[1]);
+    $unlink1 = unlink("../uploads/big/".$row->url);
+    $unlink2 = unlink("../uploads/thumb/".$row->thumbUrl);
+    $unlink3 = unlink("../uploads/thumb/".$retinaUrl[0].'@2x.'.$retinaUrl[1]);
     $query = "DELETE FROM lychee_photos WHERE id = '$photoID';";
     $result = $database->query($query);
-    if(!$unlink1 || !$unlink2 || !$unlink3) return false;
-    if(!$result) return false;
+    if (!$unlink1 || !$unlink2 || !$unlink3) return false;
+    if (!$result) return false;
     return true;
 }
 function importPhoto($name, $albumID) {
@@ -669,7 +722,7 @@ function importPhoto($name, $albumID) {
 	$nameFile[0]['tmp_name'] = $tmp_name;
 	$nameFile[0]['error'] = 0;
 	$nameFile[0]['size'] = $size;
-	if(!upload($nameFile, $albumID)) return false;
+	if (!upload($nameFile, $albumID)) return false;
 	else return true;
 }
 function importUrl($url, $albumID) {
@@ -685,28 +738,9 @@ function importUrl($url, $albumID) {
 }
 
 // Share Functions
-function urlShortner($url) {
-	global $database, $bitlyUsername, $bitlyApi;
-    if($bitlyUsername==""||$bitlyApi=="") return false;
-    $url = urlencode($url);
-    $bitlyAPI = "http://api.bit.ly/shorten?version=2.0.1&format=xml&longUrl=$url&login=$bitlyUsername&apiKey=$bitlyApi";
-
-    $data = file_get_contents($bitlyAPI);
-
-    $xml = simplexml_load_string($data);
-    $shortlink = $xml->results->nodeKeyVal->shortUrl;
-    return $shortlink;
-}
-function getShortlink($photoID) {
-	global $database;
-    $query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
-    $result = $database->query($query);
-    $row = $result->fetch_object();
-    return $row->shortlink;
-}
 function facebookHeader($photoID) {
 	$database = dbConnect();
-    if(!is_numeric($photoID)) return false;
+    if (!is_numeric($photoID)) return false;
     $query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
     $result = $database->query($query);
     $row = $result->fetch_object();
@@ -723,7 +757,7 @@ function facebookHeader($photoID) {
 function isPhotoPublic($photoID, $password) {
 	global $database;
 	$photoID = mysqli_real_escape_string($database, $photoID);
-	if(is_numeric($photoID)) {
+	if (is_numeric($photoID)) {
 		$query = "SELECT * FROM lychee_photos WHERE id = '$photoID';";
 	} else {
 		$query = "SELECT * FROM lychee_photos WHERE import_name = '../uploads/import/$photoID';";
@@ -731,34 +765,48 @@ function isPhotoPublic($photoID, $password) {
     $result = $database->query($query);
     $row = $result->fetch_object();
     if (!is_numeric($photoID)&&!$row) return true;
-    if($row->public == 1) return true;
-    else return isAlbumPublic($row->album, $password);
+    if ($row->public==1) return true;
+    else {
+    	$cAP = checkAlbumPassword($row->album, $password);
+    	$iAP = isAlbumPublic($row->album);
+    	if ($iAP&&$cAP) return true;
+    	else return false;
+    }
 }
 
 // Search Function
 function search($term) {
 	global $database, $sorting;
+	$return["albums"] = "";
     $term = mysqli_real_escape_string($database, $term);
 
     $query = "SELECT * FROM lychee_photos WHERE title like '%$term%' OR description like '%$term%';";
     $result = $database->query($query);
     while($row = $result->fetch_array()) {
-        $return['photos'][] = $row;
+        $return['photos'][$row['id']] = $row;
     }
 
     $query = "SELECT * FROM lychee_albums WHERE title like '%$term%';";
     $result = $database->query($query);
     $i=0;
-    while($row = $result->fetch_array()) {
-        $return['albums'][$i] = $row;
-        $query2 = "SELECT thumbUrl FROM lychee_photos WHERE album = '".$row['id']."' ORDER BY id $sorting LIMIT 0, 3;";
+    while($row = $result->fetch_object()) {
+
+        $return["albums"][$row->id]['id'] = $row->id;
+        $return["albums"][$row->id]['title'] = $row->title;
+        $return["albums"][$row->id]['public'] = $row->public;
+        $return["albums"][$row->id]['sysdate'] = $row->sysdate;
+        if ($row->password=="") $return["albums"][$row->id]['password'] = false;
+        else $return["albums"][$row->id]['password'] = true;
+
+        $query2 = "SELECT thumbUrl FROM lychee_photos WHERE album = '".$row->id."' ORDER BY id $sorting LIMIT 0, 3;";
         $result2 = $database->query($query2);
         $k = 0;
         while($row2 = $result2->fetch_object()){
-            $return['albums'][$i]["thumb$k"] = $row2->thumbUrl;
+            $return['albums'][$row->id]["thumb$k"] = $row2->thumbUrl;
             $k++;
         }
         $i++;
+
     }
     return $return;
 }

+ 1 - 0
php/update.php

@@ -8,6 +8,7 @@ require('check.php');
 if($error=='') {
 	if(!$database->query("SELECT `public` FROM `lychee_albums`;")) $database->query("ALTER TABLE  `lychee_albums` ADD  `public` TINYINT( 1 ) NOT NULL DEFAULT  '0'");
 	if(!$database->query("SELECT `password` FROM `lychee_albums`;")) $database->query("ALTER TABLE  `lychee_albums` ADD  `password` VARCHAR( 100 ) NULL DEFAULT NULL");
+	$database->query("UPDATE `lychee_photos` SET url = replace(url, 'uploads/big/', ''), thumbUrl = replace(thumbUrl, 'uploads/thumb/', '')");
 	echo "\nUpdate complete!";
 } else {
 	echo "\nCould not Update!";

+ 5 - 8
readme.md

@@ -2,8 +2,8 @@
 
 #### A great looking and easy-to-use Photo-Management-System.
 
-![Lychee ImageView](http://l.electerious.com/uploads/big/13582806160093.png)
-![Lychee ImageView](http://l.electerious.com/uploads/big/13582805615704.png)
+![Lychee](http://l.electerious.com/uploads/big/13582806160093.png)
+![Lychee](http://l.electerious.com/uploads/big/13582805615704.png)
 
 Lychee is a free, easy to use and great looking photo-management-system you can run on your server to manage and share photos. Just download the source and follow the instructions to install Lychee wherever you want.
 
@@ -29,18 +29,15 @@ This shortcuts will help you to use Lychee even faster. [Keyboard Shortcuts &#18
 
 ## Browser Support
 
-Lychee supports the latest versions of Google Chrome, Apple Safari and Mozilla Firefox. Photos you share with others can be viewed from every browser. For the best experience we are recommending to use Google Chrome or Apple Safari.
+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. For the best experience we are recommending to use Google Chrome or Apple Safari.
 
 ## Update
 
-####From version 1.0/1.1 to 1.2:  
+####From version 1.0/1.1/1.2 to 1.3:  
 1. Replace all files, excluding `uploads/`  
 2. Open `php/config.php` and reconfigure your installation  
 3. Open `php/update.php` in your browser  
 
-####From version 1.2 to 1.2.x:  
-Replace all files, excluding `uploads/` and `php/config.php`.
-
 ## Troubleshooting
 
 If Lychee is not working properly, try to open `php/check.php`. This file will take a look at your configuration and displays all errors it can find. Everything should work if you can see the message "Lychee is ready!".
@@ -60,4 +57,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
 
 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.SE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 2 - 2
view.php

@@ -48,7 +48,7 @@
 	</header>
 
 	<!-- ImageView -->
-	<div id="image_view"></div>
+	<div id="imageview"></div>
 
 	<!-- Infobox -->
 	<div id="infobox"></div>
@@ -60,4 +60,4 @@
 
 
 	</body>
-</html>
+</html>>

Some files were not shown because too many files changed in this diff