Browse Source

Merge pull request #238 from electerious/v2.6.3

v2.6.3
Tobias Reich 9 years ago
parent
commit
056842ba8f

+ 2 - 1
README.md

@@ -50,6 +50,7 @@ Here's a list of all available Plugins and Extensions:
 | Name | Description | |
 | Name | Description | |
 |:-----------|:------------|:------------|
 |:-----------|:------------|:------------|
 | lycheesync | Sync Lychee with any directory containing photos | [More »](https://github.com/GustavePate/lycheesync) |
 | lycheesync | Sync Lychee with any directory containing photos | [More »](https://github.com/GustavePate/lycheesync) |
+| lycheeupload | Upload photos to Lychee via SSH | [More »](https://github.com/r0x0r/lycheeupload) |
 | Jekyll | Liquid tag for Jekyll sites that allows embedding Lychee albums | [More »](https://gist.github.com/tobru/9171700) |
 | Jekyll | Liquid tag for Jekyll sites that allows embedding Lychee albums | [More »](https://gist.github.com/tobru/9171700) |
 | lychee-redirect | Redirect from an album-name to a Lychee-album | [More »](https://github.com/electerious/lychee-redirect) |
 | lychee-redirect | Redirect from an album-name to a Lychee-album | [More »](https://github.com/electerious/lychee-redirect) |
 | lychee-watermark | Adds a second watermarked photo when uploading images | [More »](https://github.com/electerious/lychee-watermark) |
 | lychee-watermark | Adds a second watermarked photo when uploading images | [More »](https://github.com/electerious/lychee-watermark) |
@@ -73,7 +74,7 @@ I am working hard on continuously developing and maintaining Lychee. Please cons
 
 
 (MIT License)
 (MIT License)
 
 
-Copyright (C) 2014 [Tobias Reich](http://electerious.com)  
+Copyright (C) 2014 [Tobias Reich](http://electerious.com)
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
 

+ 20 - 3
assets/js/album.js

@@ -113,8 +113,12 @@ album = {
 
 
 					if (data===true) data = 1; // Avoid first album to be true
 					if (data===true) data = 1; // Avoid first album to be true
 
 
-					if (data!==false&&isNumber(data)) lychee.goto(data);
-					else lychee.error(null, params, data);
+					if (data!==false&&isNumber(data)) {
+						albums.refresh();
+						lychee.goto(data);
+					} else {
+						lychee.error(null, params, data);
+					}
 
 
 				});
 				});
 
 
@@ -146,9 +150,15 @@ album = {
 						albumIDs.forEach(function(id) {
 						albumIDs.forEach(function(id) {
 							albums.json.num--;
 							albums.json.num--;
 							view.albums.content.delete(id);
 							view.albums.content.delete(id);
+							delete albums.json.content[id];
 						});
 						});
 
 
-					} else lychee.goto("");
+					} else {
+
+						albums.refresh();
+						lychee.goto("");
+
+					}
 
 
 					if (data!==true) lychee.error(null, params, data);
 					if (data!==true) lychee.error(null, params, data);
 
 
@@ -222,6 +232,11 @@ album = {
 					album.json.title = newTitle;
 					album.json.title = newTitle;
 					view.album.title();
 					view.album.title();
 
 
+					if (albums.json) {
+						var id = albumIDs[0];
+						albums.json.content[id].title = newTitle;
+					}
+
 				} else if (visible.albums()) {
 				} else if (visible.albums()) {
 
 
 					albumIDs.forEach(function(id) {
 					albumIDs.forEach(function(id) {
@@ -290,6 +305,8 @@ album = {
 			listed = false,
 			listed = false,
 			downloadable = false;
 			downloadable = false;
 
 
+		albums.refresh();
+
 		if (!visible.message()&&album.json.public==0) {
 		if (!visible.message()&&album.json.public==0) {
 
 
 			modal.show("Share Album", "This album will be shared with the following properties:</p><form><div class='choice'><input type='checkbox' name='listed' value='listed' checked><h2>Visible</h2><p>Listed to visitors of your Lychee.</p></div><div class='choice'><input type='checkbox' name='downloadable' value='downloadable'><h2>Downloadable</h2><p>Visitors of your Lychee can download this album.</p></div><div class='choice'><input type='checkbox' name='password' value='password'><h2>Password protected</h2><p>Only accessible with a valid password.<input class='text' type='password' placeholder='password' value='' style='display: none;'></p></div></form><p style='display: none;'>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]], -170);
 			modal.show("Share Album", "This album will be shared with the following properties:</p><form><div class='choice'><input type='checkbox' name='listed' value='listed' checked><h2>Visible</h2><p>Listed to visitors of your Lychee.</p></div><div class='choice'><input type='checkbox' name='downloadable' value='downloadable'><h2>Downloadable</h2><p>Visitors of your Lychee can download this album.</p></div><div class='choice'><input type='checkbox' name='password' value='password'><h2>Password protected</h2><p>Only accessible with a valid password.<input class='text' type='password' placeholder='password' value='' style='display: none;'></p></div></form><p style='display: none;'>", [["Share Album", function() { album.setPublic(album.getID(), e) }], ["Cancel", function() {}]], -170);

+ 68 - 54
assets/js/albums.js

@@ -20,66 +20,74 @@ albums = {
 
 
 		startTime = new Date().getTime();
 		startTime = new Date().getTime();
 
 
-		lychee.api("getAlbums", function(data) {
-
-			/* Smart Albums */
-			data.unsortedAlbum = {
-				id: 0,
-				title: "Unsorted",
-				sysdate: data.unsortedNum + " photos",
-				unsorted: 1,
-				thumb0: data.unsortedThumb0,
-				thumb1: data.unsortedThumb1,
-				thumb2: data.unsortedThumb2
-			};
-
-			data.starredAlbum = {
-				id: "f",
-				title: "Starred",
-				sysdate: data.starredNum + " photos",
-				star: 1,
-				thumb0: data.starredThumb0,
-				thumb1: data.starredThumb1,
-				thumb2: data.starredThumb2
-			};
-
-			data.publicAlbum = {
-				id: "s",
-				title: "Public",
-				sysdate: data.publicNum + " photos",
-				public: 1,
-				thumb0: data.publicThumb0,
-				thumb1: data.publicThumb1,
-				thumb2: data.publicThumb2
-			};
-
-			data.recentAlbum = {
-				id: "r",
-				title: "Recent",
-				sysdate: data.recentNum + " photos",
-				recent: 1,
-				thumb0: data.recentThumb0,
-				thumb1: data.recentThumb1,
-				thumb2: data.recentThumb2
-			};
-
-			albums.json = data;
-
-			durationTime = (new Date().getTime() - startTime);
-			if (durationTime>300) waitTime = 0; else waitTime = 300 - durationTime;
-			if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
-			if (visible.album()&&lychee.content.html()==="") waitTime = 0;
+		if(albums.json===null) {
+
+			lychee.api("getAlbums", function(data) {
+
+				/* Smart Albums */
+				data.unsortedAlbum = {
+					id: 0,
+					title: "Unsorted",
+					sysdate: data.unsortedNum + " photos",
+					unsorted: 1,
+					thumb0: data.unsortedThumb0,
+					thumb1: data.unsortedThumb1,
+					thumb2: data.unsortedThumb2
+				};
+
+				data.starredAlbum = {
+					id: "f",
+					title: "Starred",
+					sysdate: data.starredNum + " photos",
+					star: 1,
+					thumb0: data.starredThumb0,
+					thumb1: data.starredThumb1,
+					thumb2: data.starredThumb2
+				};
+
+				data.publicAlbum = {
+					id: "s",
+					title: "Public",
+					sysdate: data.publicNum + " photos",
+					public: 1,
+					thumb0: data.publicThumb0,
+					thumb1: data.publicThumb1,
+					thumb2: data.publicThumb2
+				};
+
+				data.recentAlbum = {
+					id: "r",
+					title: "Recent",
+					sysdate: data.recentNum + " photos",
+					recent: 1,
+					thumb0: data.recentThumb0,
+					thumb1: data.recentThumb1,
+					thumb2: data.recentThumb2
+				};
+
+				albums.json = data;
+
+				durationTime = (new Date().getTime() - startTime);
+				if (durationTime>300) waitTime = 0; else waitTime = 300 - durationTime;
+				if (!visible.albums()&&!visible.photo()&&!visible.album()) waitTime = 0;
+				if (visible.album()&&lychee.content.html()==="") waitTime = 0;
+
+				setTimeout(function() {
+					view.header.mode("albums");
+					view.albums.init();
+					lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
+				}, waitTime);
+			});
 
 
-			setTimeout(function() {
+		} else {
 
 
+			setTimeout(function() {
 				view.header.mode("albums");
 				view.header.mode("albums");
 				view.albums.init();
 				view.albums.init();
 				lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
 				lychee.animate(".album:nth-child(-n+50), .photo:nth-child(-n+50)", "contentZoomIn");
+			}, 300);
 
 
-			}, waitTime);
-
-		});
-
+		}
 	},
 	},
 
 
 	parse: function(album) {
 	parse: function(album) {
@@ -94,6 +102,12 @@ albums = {
 			if (!album.thumb2) album.thumb2 = "assets/img/no_images.svg";
 			if (!album.thumb2) album.thumb2 = "assets/img/no_images.svg";
 		}
 		}
 
 
+	},
+
+	refresh: function() {
+
+		albums.json = null;
+
 	}
 	}
 
 
 };
 };

+ 4 - 4
assets/js/build.js

@@ -34,7 +34,7 @@ build = {
 			title = albumJSON.title,
 			title = albumJSON.title,
 			typeThumb = "";
 			typeThumb = "";
 
 
-		if (title.length>18) {
+		if (title!==null&&title.length>18) {
 			title = albumJSON.title.substr(0, 18) + "...";
 			title = albumJSON.title.substr(0, 18) + "...";
 			longTitle = albumJSON.title;
 			longTitle = albumJSON.title;
 		}
 		}
@@ -76,7 +76,7 @@ build = {
 			longTitle = "",
 			longTitle = "",
 			title = photoJSON.title;
 			title = photoJSON.title;
 
 
-		if (title.length>18) {
+		if (title!==null&&title.length>18) {
 			title = photoJSON.title.substr(0, 18) + "...";
 			title = photoJSON.title.substr(0, 18) + "...";
 			longTitle = photoJSON.title;
 			longTitle = photoJSON.title;
 		}
 		}
@@ -195,8 +195,8 @@ build = {
 		modal +=		"<h1><a class='icon-lock'></a> Sign In</h1>";
 		modal +=		"<h1><a class='icon-lock'></a> Sign In</h1>";
 		modal +=		"<a class='close icon-remove-sign'></a>";
 		modal +=		"<a class='close icon-remove-sign'></a>";
 		modal +=		"<div class='sign_in'>";
 		modal +=		"<div class='sign_in'>";
-		modal +=			"<input id='username' type='text' name='' value='' placeholder='username'>";
-		modal +=			"<input id='password' type='password' name='' value='' placeholder='password'>";
+		modal +=			"<input id='username' type='text' value='' placeholder='username' autocapitalize='off' autocorrect='off'>";
+		modal +=			"<input id='password' type='password' value='' placeholder='password'>";
 		modal +=		"</div>";
 		modal +=		"</div>";
 		modal +=		"<div id='version'>Version " + lychee.version + "<span> &#8211; <a target='_blank' href='" + lychee.updateURL + "'>Update available!</a><span></div>";
 		modal +=		"<div id='version'>Version " + lychee.version + "<span> &#8211; <a target='_blank' href='" + lychee.updateURL + "'>Update available!</a><span></div>";
 		modal +=		"<a onclick='lychee.login()' class='button active'>Sign in</a>";
 		modal +=		"<a onclick='lychee.login()' class='button active'>Sign in</a>";

+ 10 - 0
assets/js/init.js

@@ -99,6 +99,7 @@ $(document).ready(function(){
 		})
 		})
 		.bind(['i', 'ctrl+i'], function() {
 		.bind(['i', 'ctrl+i'], function() {
 			if (visible.infobox()) view.infobox.hide();
 			if (visible.infobox()) view.infobox.hide();
+			else if (visible.multiselect()) return false;
 			else if (visible.infoboxbutton()) view.infobox.show();
 			else if (visible.infoboxbutton()) view.infobox.show();
 		})
 		})
 		.bind(['command+backspace', 'ctrl+backspace'], function() {
 		.bind(['command+backspace', 'ctrl+backspace'], function() {
@@ -182,11 +183,20 @@ $(document).ready(function(){
 		.on(event_name, ".upload_message a.close", upload.close)
 		.on(event_name, ".upload_message a.close", upload.close)
 		.on("dragover", function(e) { e.preventDefault(); }, false)
 		.on("dragover", function(e) { e.preventDefault(); }, false)
 		.on("drop", function(e) {
 		.on("drop", function(e) {
+
 			e.stopPropagation();
 			e.stopPropagation();
 			e.preventDefault();
 			e.preventDefault();
+
+			// Close open overlays or views which are correlating with the upload
+			if (visible.photo()) lychee.goto(album.getID());
+			if (visible.contextMenu()) contextMenu.close();
+
+			// Detect if dropped item is a file or a link
 			if (e.originalEvent.dataTransfer.files.length>0)				upload.start.local(e.originalEvent.dataTransfer.files);
 			if (e.originalEvent.dataTransfer.files.length>0)				upload.start.local(e.originalEvent.dataTransfer.files);
 			else if (e.originalEvent.dataTransfer.getData('Text').length>3)	upload.start.url(e.originalEvent.dataTransfer.getData('Text'));
 			else if (e.originalEvent.dataTransfer.getData('Text').length>3)	upload.start.url(e.originalEvent.dataTransfer.getData('Text'));
+
 			return true;
 			return true;
+
 		});
 		});
 
 
 	/* Init */
 	/* Init */

+ 13 - 6
assets/js/lychee.js

@@ -8,8 +8,8 @@
 var lychee = {
 var lychee = {
 
 
 	title: "",
 	title: "",
-	version: "2.6.2",
-	version_code: "020602",
+	version: "2.6.3",
+	version_code: "020603",
 
 
 	api_path: "php/api.php",
 	api_path: "php/api.php",
 	update_path: "http://lychee.electerious.com/version/index.php",
 	update_path: "http://lychee.electerious.com/version/index.php",
@@ -119,13 +119,23 @@ var lychee = {
 
 
 		params = "login&user=" + user + "&password=" + password;
 		params = "login&user=" + user + "&password=" + password;
 		lychee.api(params, function(data) {
 		lychee.api(params, function(data) {
+
 			if (data===true) {
 			if (data===true) {
-				localStorage.setItem("lychee_username", user);
+
+				// Use 'try' to catch a thrown error when Safari is in private mode
+				try { localStorage.setItem("lychee_username", user); }
+				catch (err) {}
+
 				window.location.reload();
 				window.location.reload();
+
 			} else {
 			} else {
+
+				// Show error and reactive button
 				$("#password").val("").addClass("error").focus();
 				$("#password").val("").addClass("error").focus();
 				$(".message .button.active").removeClass("pressed");
 				$(".message .button.active").removeClass("pressed");
+
 			}
 			}
+
 		});
 		});
 
 
 	},
 	},
@@ -181,7 +191,6 @@ var lychee = {
 		if (albumID&&photoID) {
 		if (albumID&&photoID) {
 
 
 			// Trash data
 			// Trash data
-			albums.json = null;
 			photo.json = null;
 			photo.json = null;
 
 
 			// Show Photo
 			// Show Photo
@@ -194,7 +203,6 @@ var lychee = {
 		} else if (albumID) {
 		} else if (albumID) {
 
 
 			// Trash data
 			// Trash data
-			albums.json = null;
 			photo.json = null;
 			photo.json = null;
 
 
 			// Show Album
 			// Show Album
@@ -205,7 +213,6 @@ var lychee = {
 		} else {
 		} else {
 
 
 			// Trash data
 			// Trash data
-			albums.json = null;
 			album.json = null;
 			album.json = null;
 			photo.json = null;
 			photo.json = null;
 			search.code = "";
 			search.code = "";

+ 41 - 1
assets/js/photo.js

@@ -8,6 +8,7 @@
 photo = {
 photo = {
 
 
 	json: null,
 	json: null,
+	cache: null,
 
 
 	getID: function() {
 	getID: function() {
 
 
@@ -43,12 +44,41 @@ photo = {
 			view.photo.init();
 			view.photo.init();
 
 
 			lychee.imageview.show();
 			lychee.imageview.show();
-			setTimeout(function() { lychee.content.show() }, 300);
+			setTimeout(function() {
+				lychee.content.show();
+				//photo.preloadNext(photoID, albumID);
+			}, 300);
 
 
 		});
 		});
 
 
 	},
 	},
 
 
+	//preload the next photo for better response time
+	preloadNext: function(photoID) {
+
+		var nextPhoto,
+			url;
+
+		// Never preload on mobile devices with bare RAM and
+		// mostly mobile internet
+		if (mobileBrowser()) return false;
+
+		if (album.json &&
+		   album.json.content &&
+		   album.json.content[photoID] &&
+		   album.json.content[photoID].nextPhoto!="") {
+
+			nextPhoto	= album.json.content[photoID].nextPhoto;
+			url			= album.json.content[nextPhoto].url;
+
+			photo.cache			= new Image();
+			photo.cache.src		= url;
+			photo.cache.onload	= function() { photo.cache = null };
+
+		}
+
+	},
+
 	parse: function() {
 	parse: function() {
 
 
 		if (!photo.json.title) photo.json.title = "Untitled";
 		if (!photo.json.title) photo.json.title = "Untitled";
@@ -124,6 +154,8 @@ photo = {
 		if (!photoIDs) return false;
 		if (!photoIDs) return false;
 		if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
 		if (photoIDs instanceof Array===false) photoIDs = [photoIDs];
 
 
+		albums.refresh();
+
 		params = "duplicatePhoto&photoIDs=" + photoIDs;
 		params = "duplicatePhoto&photoIDs=" + photoIDs;
 		lychee.api(params, function(data) {
 		lychee.api(params, function(data) {
 
 
@@ -177,6 +209,8 @@ photo = {
 				// Only when search is not active
 				// Only when search is not active
 				if (!visible.albums()) lychee.goto(album.getID());
 				if (!visible.albums()) lychee.goto(album.getID());
 
 
+				albums.refresh();
+
 				params = "deletePhoto&photoIDs=" + photoIDs;
 				params = "deletePhoto&photoIDs=" + photoIDs;
 				lychee.api(params, function(data) {
 				lychee.api(params, function(data) {
 
 
@@ -286,6 +320,8 @@ photo = {
 
 
 		});
 		});
 
 
+		albums.refresh();
+
 		params = "setPhotoAlbum&photoIDs=" + photoIDs + "&albumID=" + albumID;
 		params = "setPhotoAlbum&photoIDs=" + photoIDs + "&albumID=" + albumID;
 		lychee.api(params, function(data) {
 		lychee.api(params, function(data) {
 
 
@@ -310,6 +346,8 @@ photo = {
 			view.album.content.star(id);
 			view.album.content.star(id);
 		});
 		});
 
 
+		albums.refresh();
+
 		params = "setPhotoStar&photoIDs=" + photoIDs;
 		params = "setPhotoStar&photoIDs=" + photoIDs;
 		lychee.api(params, function(data) {
 		lychee.api(params, function(data) {
 
 
@@ -341,6 +379,8 @@ photo = {
 		album.json.content[photoID].public = (album.json.content[photoID].public==0) ? 1 : 0;
 		album.json.content[photoID].public = (album.json.content[photoID].public==0) ? 1 : 0;
 		view.album.content.public(photoID);
 		view.album.content.public(photoID);
 
 
+		albums.refresh();
+
 		params = "setPhotoPublic&photoID=" + photoID;
 		params = "setPhotoPublic&photoID=" + photoID;
 		lychee.api(params, function(data) {
 		lychee.api(params, function(data) {
 
 

+ 2 - 0
assets/js/settings.js

@@ -215,6 +215,8 @@ var settings = {
 				sorting[0] = $("select#settings_type").val();
 				sorting[0] = $("select#settings_type").val();
 				sorting[1] = $("select#settings_order").val();
 				sorting[1] = $("select#settings_order").val();
 
 
+				albums.refresh();
+
 				params = "setSorting&type=" + sorting[0] + "&order=" + sorting[1];
 				params = "setSorting&type=" + sorting[0] + "&order=" + sorting[1];
 				lychee.api(params, function(data) {
 				lychee.api(params, function(data) {
 
 

+ 8 - 0
assets/js/upload.js

@@ -65,6 +65,8 @@ upload = {
 
 
 							}
 							}
 
 
+							albums.refresh();
+
 							if (album.getID()===false) lychee.goto("0");
 							if (album.getID()===false) lychee.goto("0");
 							else album.load(albumID);
 							else album.load(albumID);
 
 
@@ -259,6 +261,8 @@ upload = {
 							upload.close();
 							upload.close();
 							upload.notify("Import complete");
 							upload.notify("Import complete");
 
 
+							albums.refresh();
+
 							if (album.getID()===false) lychee.goto("0");
 							if (album.getID()===false) lychee.goto("0");
 							else album.load(albumID);
 							else album.load(albumID);
 
 
@@ -306,6 +310,8 @@ upload = {
 						upload.close();
 						upload.close();
 						upload.notify("Import complete");
 						upload.notify("Import complete");
 
 
+						albums.refresh();
+
 						if (data==="Notice: Import only contains albums!") {
 						if (data==="Notice: Import only contains albums!") {
 							if (visible.albums()) lychee.load();
 							if (visible.albums()) lychee.load();
 							else lychee.goto("");
 							else lychee.goto("");
@@ -365,6 +371,8 @@ upload = {
 							upload.close();
 							upload.close();
 							upload.notify("Import complete");
 							upload.notify("Import complete");
 
 
+							albums.refresh();
+
 							if (album.getID()===false) lychee.goto("0");
 							if (album.getID()===false) lychee.goto("0");
 							else album.load(albumID);
 							else album.load(albumID);
 
 

+ 30 - 6
assets/js/view.js

@@ -54,15 +54,21 @@ view = {
 			var albumID = album.getID();
 			var albumID = album.getID();
 
 
 			switch (mode) {
 			switch (mode) {
+
 				case "albums":
 				case "albums":
+
 					lychee.header.removeClass("view");
 					lychee.header.removeClass("view");
 					$("#tools_album, #tools_photo").hide();
 					$("#tools_album, #tools_photo").hide();
 					$("#tools_albums").show();
 					$("#tools_albums").show();
+
 					break;
 					break;
+
 				case "album":
 				case "album":
+
 					lychee.header.removeClass("view");
 					lychee.header.removeClass("view");
 					$("#tools_albums, #tools_photo").hide();
 					$("#tools_albums, #tools_photo").hide();
 					$("#tools_album").show();
 					$("#tools_album").show();
+
 					album.json.content === false ? $("#button_archive").hide() : $("#button_archive").show();
 					album.json.content === false ? $("#button_archive").hide() : $("#button_archive").show();
 					if (lychee.publicMode&&album.json.downloadable==="0") $("#button_archive").hide();
 					if (lychee.publicMode&&album.json.downloadable==="0") $("#button_archive").hide();
 					if (albumID==="s"||albumID==="f"||albumID==="r") {
 					if (albumID==="s"||albumID==="f"||albumID==="r") {
@@ -73,11 +79,15 @@ view = {
 					} else {
 					} else {
 						$("#button_info_album, #button_trash_album, #button_share_album").show();
 						$("#button_info_album, #button_trash_album, #button_share_album").show();
 					}
 					}
+
 					break;
 					break;
+
 				case "photo":
 				case "photo":
+
 					lychee.header.addClass("view");
 					lychee.header.addClass("view");
 					$("#tools_albums, #tools_album").hide();
 					$("#tools_albums, #tools_album").hide();
 					$("#tools_photo").show();
 					$("#tools_photo").show();
+
 					break;
 					break;
 
 
 			}
 			}
@@ -122,27 +132,32 @@ view = {
 
 
 		content: {
 		content: {
 
 
+			scrollPosition: 0,
+
 			init: function() {
 			init: function() {
 
 
 				var smartData = "",
 				var smartData = "",
 					albumsData = "";
 					albumsData = "";
 
 
-				/*  Smart Albums */
+				/* Smart Albums */
 				albums.parse(albums.json.unsortedAlbum);
 				albums.parse(albums.json.unsortedAlbum);
 				albums.parse(albums.json.publicAlbum);
 				albums.parse(albums.json.publicAlbum);
 				albums.parse(albums.json.starredAlbum);
 				albums.parse(albums.json.starredAlbum);
 				albums.parse(albums.json.recentAlbum);
 				albums.parse(albums.json.recentAlbum);
 				if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum) + build.album(albums.json.recentAlbum);
 				if (!lychee.publicMode) smartData = build.divider("Smart Albums") + build.album(albums.json.unsortedAlbum) + build.album(albums.json.starredAlbum) + build.album(albums.json.publicAlbum) + build.album(albums.json.recentAlbum);
 
 
-				/*  Albums */
+				/* Albums */
 				if (albums.json.content) {
 				if (albums.json.content) {
 
 
-					if (!lychee.publicMode) albumsData = build.divider("Albums");
 					$.each(albums.json.content, function() {
 					$.each(albums.json.content, function() {
 						albums.parse(this);
 						albums.parse(this);
-						albumsData += build.album(this);
+
+						//display albums in reverse order
+						albumsData = build.album(this) + albumsData;
 					});
 					});
 
 
+					if (!lychee.publicMode) albumsData = build.divider("Albums") + albumsData;
+
 				}
 				}
 
 
 				if (smartData===""&&albumsData==="") {
 				if (smartData===""&&albumsData==="") {
@@ -154,6 +169,11 @@ view = {
 
 
 				$("img[data-type!='nonretina']").retina();
 				$("img[data-type!='nonretina']").retina();
 
 
+				/* Restore scroll position */
+				if (view.albums.content.scrollPosition!==null) {
+					$("html, body").scrollTop(view.albums.content.scrollPosition);
+				}
+
 			},
 			},
 
 
 			title: function(albumID) {
 			title: function(albumID) {
@@ -163,7 +183,7 @@ view = {
 					title = albums.json.content[albumID].title;
 					title = albums.json.content[albumID].title;
 
 
 				if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
 				if (albums.json.content[albumID].password) prefix = "<span class='icon-lock'></span> ";
-				if (title.length>18) {
+				if (title!==null&&title.length>18) {
 					longTitle = title;
 					longTitle = title;
 					title = title.substr(0, 18) + "...";
 					title = title.substr(0, 18) + "...";
 				}
 				}
@@ -251,6 +271,10 @@ view = {
 
 
 				$("img[data-type!='svg']").retina();
 				$("img[data-type!='svg']").retina();
 
 
+				/* Save and reset scroll position */
+				view.albums.content.scrollPosition = $(document).scrollTop();
+				$("html, body").scrollTop(0);
+
 			},
 			},
 
 
 			title: function(photoID) {
 			title: function(photoID) {
@@ -258,7 +282,7 @@ view = {
 				var longTitle = "",
 				var longTitle = "",
 					title = album.json.content[photoID].title;
 					title = album.json.content[photoID].title;
 
 
-				if (title.length>18) {
+				if (title!==null&&title.length>18) {
 					longTitle = title;
 					longTitle = title;
 					title = title.substr(0, 18) + "...";
 					title = title.substr(0, 18) + "...";
 				}
 				}

File diff suppressed because it is too large
+ 0 - 0
assets/min/main.js


File diff suppressed because it is too large
+ 0 - 0
assets/min/view.js


+ 13 - 4
build/gulpfile.js

@@ -1,7 +1,7 @@
 var	gulp = require('gulp'),
 var	gulp = require('gulp'),
 	plugins = require("gulp-load-plugins")();
 	plugins = require("gulp-load-plugins")();
 
 
-paths = {
+var paths = {
 	view: [
 	view: [
 		'bower_components/jQuery/dist/jquery.min.js',
 		'bower_components/jQuery/dist/jquery.min.js',
 		'bower_components/js-md5/js/md5.min.js',
 		'bower_components/js-md5/js/md5.min.js',
@@ -23,7 +23,14 @@ paths = {
 	]
 	]
 }
 }
 
 
-gulp.task('view', function () {
+var catchError = function(err) {
+
+	console.log(err.toString());
+	this.emit('end');
+
+}
+
+gulp.task('view', function() {
 
 
 	gulp.src(paths.view)
 	gulp.src(paths.view)
 		.pipe(plugins.concat('view.js', {newLine: "\n"}))
 		.pipe(plugins.concat('view.js', {newLine: "\n"}))
@@ -32,19 +39,21 @@ gulp.task('view', function () {
 
 
 });
 });
 
 
-gulp.task('js', function () {
+gulp.task('js', function() {
 
 
 	gulp.src(paths.js)
 	gulp.src(paths.js)
 		.pipe(plugins.concat('main.js', {newLine: "\n"}))
 		.pipe(plugins.concat('main.js', {newLine: "\n"}))
 		.pipe(plugins.uglify())
 		.pipe(plugins.uglify())
+		.on('error', catchError)
 		.pipe(gulp.dest('../assets/min/'));
 		.pipe(gulp.dest('../assets/min/'));
 
 
 });
 });
 
 
-gulp.task('css', function () {
+gulp.task('css', function() {
 
 
 	gulp.src(paths.css)
 	gulp.src(paths.css)
 		.pipe(plugins.sass())
 		.pipe(plugins.sass())
+		.on('error', catchError)
 		.pipe(plugins.concat('main.css', {newLine: "\n"}))
 		.pipe(plugins.concat('main.css', {newLine: "\n"}))
 		.pipe(plugins.autoprefixer('last 4 versions', '> 5%'))
 		.pipe(plugins.autoprefixer('last 4 versions', '> 5%'))
 		.pipe(plugins.minifyCss())
 		.pipe(plugins.minifyCss())

+ 6 - 6
build/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "Lychee",
   "name": "Lychee",
-  "version": "2.6.2",
+  "version": "2.6.3",
   "description": "Self-hosted photo-management done right.",
   "description": "Self-hosted photo-management done right.",
   "authors": "Tobias Reich <tobias.reich.ich@gmail.com>",
   "authors": "Tobias Reich <tobias.reich.ich@gmail.com>",
   "license": "MIT",
   "license": "MIT",
@@ -10,11 +10,11 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "gulp": "^3.8.8",
     "gulp": "^3.8.8",
-    "gulp-autoprefixer": "1.0.0",
-    "gulp-concat": "^2.4.0",
-    "gulp-load-plugins": "^0.6.0",
-    "gulp-minify-css": "^0.3.8",
-    "gulp-sass": "^0.7.3",
+    "gulp-autoprefixer": "1.0.1",
+    "gulp-concat": "^2.4.1",
+    "gulp-load-plugins": "^0.7.0",
+    "gulp-minify-css": "^0.3.10",
+    "gulp-sass": "^1.0.0",
     "gulp-uglify": "^1.0.1"
     "gulp-uglify": "^1.0.1"
   }
   }
 }
 }

+ 13 - 0
docs/Changelog.md

@@ -1,3 +1,16 @@
+## v2.6.3
+
+Released ??, 2014
+
+- `New` Caching for albums (Thanks @r0x0r, #232)
+- `New` Save scroll position of albums (Thanks @r0x0r, #232)
+- `New` Added Dockerfile (@renfredxh, #236)
+- `Improved` Newest album on the top (Thanks @r0x0r, #232)
+- `Fixed` Login in private mode (Safari)
+- `Fixed` Drag & Drop with open photo
+- `Fixed` Wrong modified date of the photo files
+- `Fixed` Search function always returned all photos (Thanks @powentan, #234)
+
 ## v2.6.2
 ## v2.6.2
 
 
 Released September 12, 2014
 Released September 12, 2014

+ 1 - 1
index.html

@@ -16,7 +16,7 @@
 		<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-iphone.png" sizes="120x120">
 		<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-iphone.png" sizes="120x120">
 		<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-ipad.png" sizes="152x152">
 		<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-ipad.png" sizes="152x152">
 
 
-		<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
+		<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0">
 		<meta name="apple-mobile-web-app-status-bar-style" content="black">
 		<meta name="apple-mobile-web-app-status-bar-style" content="black">
 		<meta name="apple-mobile-web-app-capable" content="yes">
 		<meta name="apple-mobile-web-app-capable" content="yes">
 
 

+ 6 - 0
php/autoload.php

@@ -10,6 +10,9 @@ if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
 
 
 function lycheeAutoloaderModules($class_name) {
 function lycheeAutoloaderModules($class_name) {
 
 
+	$modules = array('Album', 'Database', 'Import', 'Log', 'Module', 'Photo', 'Plugins', 'Session', 'Settings');
+	if (!in_array($class_name, $modules)) return false;
+
 	$file = LYCHEE . 'php/modules/' . $class_name . '.php';
 	$file = LYCHEE . 'php/modules/' . $class_name . '.php';
 	if (file_exists($file)!==false) require $file;
 	if (file_exists($file)!==false) require $file;
 
 
@@ -17,6 +20,9 @@ function lycheeAutoloaderModules($class_name) {
 
 
 function lycheeAutoloaderAccess($class_name) {
 function lycheeAutoloaderAccess($class_name) {
 
 
+	$access = array('Access', 'Admin', 'Guest', 'Installation');
+	if (!in_array($class_name, $access)) return false;
+
 	$file = LYCHEE . 'php/access/' . $class_name . '.php';
 	$file = LYCHEE . 'php/access/' . $class_name . '.php';
 	if (file_exists($file)!==false) require $file;
 	if (file_exists($file)!==false) require $file;
 
 

+ 10 - 7
php/modules/Album.php

@@ -65,27 +65,27 @@ class Album extends Module {
 		switch ($this->albumIDs) {
 		switch ($this->albumIDs) {
 
 
 			case 'f':	$return['public'] = false;
 			case 'f':	$return['public'] = false;
-						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp FROM ? WHERE star = 1 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
+						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE star = 1 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
 						break;
 						break;
 
 
 			case 's':	$return['public'] = false;
 			case 's':	$return['public'] = false;
-						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp FROM ? WHERE public = 1 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
+						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE public = 1 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
 						break;
 						break;
 
 
 			case 'r':	$return['public'] = false;
 			case 'r':	$return['public'] = false;
-						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
+						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
 						break;
 						break;
 
 
 			case '0':	$return['public'] = false;
 			case '0':	$return['public'] = false;
-						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp FROM ? WHERE album = 0 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
+						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = 0 " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS));
 						break;
 						break;
 
 
 			default:	$query	= Database::prepare($this->database, "SELECT * FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
 			default:	$query	= Database::prepare($this->database, "SELECT * FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs));
 						$albums = $this->database->query($query);
 						$albums = $this->database->query($query);
 						$return = $albums->fetch_assoc();
 						$return = $albums->fetch_assoc();
-						$return['sysdate']		= date('d M. Y', $return['sysstamp']);
-						$return['password']		= ($return['password']=='' ? false : true);
-						$query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp FROM ? WHERE album = '?' " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
+						$return['sysdate']	= date('d M. Y', $return['sysstamp']);
+						$return['password']	= ($return['password']=='' ? false : true);
+						$query	= Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = '?' " . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs));
 						break;
 						break;
 
 
 		}
 		}
@@ -101,6 +101,9 @@ class Album extends Module {
 			$photo['nextPhoto']			= '';
 			$photo['nextPhoto']			= '';
 			$photo['thumbUrl']			= LYCHEE_URL_UPLOADS_THUMB . $photo['thumbUrl'];
 			$photo['thumbUrl']			= LYCHEE_URL_UPLOADS_THUMB . $photo['thumbUrl'];
 
 
+			# Parse url
+			$photo['url'] = LYCHEE_URL_UPLOADS_BIG . $photo['url'];
+
 			if (isset($photo['takestamp'])&&$photo['takestamp']!=='0') {
 			if (isset($photo['takestamp'])&&$photo['takestamp']!=='0') {
 				$photo['cameraDate']	= 1;
 				$photo['cameraDate']	= 1;
 				$photo['sysdate']		= date('d F Y', $photo['takestamp']);
 				$photo['sysdate']		= date('d F Y', $photo['takestamp']);

+ 5 - 1
php/modules/Database.php

@@ -24,6 +24,9 @@ class Database extends Module {
 		if ($database->server_version<50500) $database->set_charset('GBK');
 		if ($database->server_version<50500) $database->set_charset('GBK');
 		else $database->set_charset("utf8");
 		else $database->set_charset("utf8");
 
 
+		# Set unicode
+		$database->query('SET NAMES utf8;');
+
 		# Check database
 		# Check database
 		if (!$database->select_db($name))
 		if (!$database->select_db($name))
 			if (!Database::createDatabase($database, $name)) exit('Error: Could not create database!');
 			if (!Database::createDatabase($database, $name)) exit('Error: Could not create database!');
@@ -41,6 +44,7 @@ class Database extends Module {
 
 
 		# Check dependencies
 		# Check dependencies
 		Module::dependencies(isset($database, $dbName));
 		Module::dependencies(isset($database, $dbName));
+		if (!isset($version)) return true;
 
 
 		# List of updates
 		# List of updates
 		$updates = array(
 		$updates = array(
@@ -56,7 +60,7 @@ class Database extends Module {
 		# For each update
 		# For each update
 		foreach ($updates as $update) {
 		foreach ($updates as $update) {
 
 
-			if (isset($version)&&$update<=$version) continue;
+			if ($update<=$version) continue;
 
 
 			# Load update
 			# Load update
 			include(__DIR__ . '/../database/update_' . $update . '.php');
 			include(__DIR__ . '/../database/update_' . $update . '.php');

+ 1 - 1
php/modules/Photo.php

@@ -161,7 +161,7 @@ class Photo extends Module {
 				}
 				}
 
 
 				# Set original date
 				# Set original date
-				if ($info['takestamp']!=='') @touch($path, $info['takestamp']);
+				if ($info['takestamp']!==''&&$info['takestamp']!==0) @touch($path, $info['takestamp']);
 
 
 				# Create Thumb
 				# Create Thumb
 				if (!$this->createThumb($path, $photo_name)) {
 				if (!$this->createThumb($path, $photo_name)) {

+ 3 - 2
plugins/check/index.php

@@ -99,7 +99,8 @@ $imagick = extension_loaded('imagick');
 if ($imagick===false) $imagick = '-';
 if ($imagick===false) $imagick = '-';
 
 
 if ($imagick===true) $imagickVersion = @Imagick::getVersion();
 if ($imagick===true) $imagickVersion = @Imagick::getVersion();
-if (!isset($imagickVersion)||$imagickVersion==='') $imagickVersion = '-';
+if (!isset($imagickVersion, $imagickVersion['versionNumber'])||$imagickVersion==='') $imagickVersion = '-';
+else $imagickVersion = $imagickVersion['versionNumber'];
 
 
 $gdVersion = gd_info();
 $gdVersion = gd_info();
 
 
@@ -111,7 +112,7 @@ echo('PHP Version:     ' . floatval(phpversion()) . PHP_EOL);
 echo('MySQL Version:   ' . $database->server_version . PHP_EOL);
 echo('MySQL Version:   ' . $database->server_version . PHP_EOL);
 echo('Imagick:         ' . $imagick . PHP_EOL);
 echo('Imagick:         ' . $imagick . PHP_EOL);
 echo('Imagick Active:  ' . $settings['imagick'] . PHP_EOL);
 echo('Imagick Active:  ' . $settings['imagick'] . PHP_EOL);
-echo('Imagick Version: ' . $imagickVersion['versionNumber'] . PHP_EOL);
+echo('Imagick Version: ' . $imagickVersion . PHP_EOL);
 echo('GD Version:      ' . $gdVersion['GD Version'] . PHP_EOL);
 echo('GD Version:      ' . $gdVersion['GD Version'] . PHP_EOL);
 
 
 ?>
 ?>

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