diff --git a/dist/main.css b/dist/main.css index b4197b5..8cacfed 100644 Binary files a/dist/main.css and b/dist/main.css differ diff --git a/dist/main.js b/dist/main.js index c663dd0..d061bdd 100644 Binary files a/dist/main.js and b/dist/main.js differ diff --git a/dist/view.js b/dist/view.js index 1ee5761..fcc6ebb 100644 Binary files a/dist/view.js and b/dist/view.js differ diff --git a/docs/Changelog.md b/docs/Changelog.md index bf05827..73a205e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,6 +1,15 @@ +## v3.0.1 + +Released May 24, 2015 + +- `New` Album Sorting (Thanks @ophian, #98) +- `New` Identifier to prevent login of multiple instances of lychee (#344) +- `Improved` Albums and photos now can have a title with up to 50 chars (#332) +- `Fixed` Removing last Tag from photo not possible in Firefox (#269) + ## v3.0.0 -Released April 6, 2015 +Released May 6, 2015 **Warning**: You need to enter a new username and password when upgrading from a previous version. Your installation is accessible for everyone till you enter a new login by visiting your Lychee. Both fields are now stored in a secure way. Legacy md5 code has been removed. diff --git a/php/access/Admin.php b/php/access/Admin.php index 9713a5c..f2ba009 100644 --- a/php/access/Admin.php +++ b/php/access/Admin.php @@ -279,9 +279,14 @@ class Admin extends Access { private function setSorting() { - Module::dependencies(isset($_POST['type'], $_POST['order'])); + Module::dependencies(isset($_POST['typeAlbums'], $_POST['orderAlbums'], $_POST['typePhotos'], $_POST['orderPhotos'])); $this->settings = new Settings($this->database); - echo $this->settings->setSorting($_POST['type'], $_POST['order']); + + $sA = $this->settings->setSortingAlbums($_POST['typeAlbums'], $_POST['orderAlbums']); + $sP = $this->settings->setSortingPhotos($_POST['typePhotos'], $_POST['orderPhotos']); + + if ($sA===true&&$sP===true) echo true; + else echo false; } diff --git a/php/api.php b/php/api.php index affa33a..cb089e5 100755 --- a/php/api.php +++ b/php/api.php @@ -63,7 +63,8 @@ if (!empty($_POST['function'])||!empty($_GET['function'])) { if (isset($_POST['function'])) $fn = $_POST['function']; else $fn = $_GET['function']; - if (isset($_SESSION['login'])&&$_SESSION['login']==true) { + if ((isset($_SESSION['login'])&&$_SESSION['login']===true)&& + (isset($_SESSION['identifier'])&&$_SESSION['identifier']===$settings['identifier'])) { ### # Admin Access diff --git a/php/database/albums_table.sql b/php/database/albums_table.sql index 4f3b5c5..b949e2e 100644 --- a/php/database/albums_table.sql +++ b/php/database/albums_table.sql @@ -4,12 +4,12 @@ CREATE TABLE IF NOT EXISTS `?` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `title` varchar(50) NOT NULL, + `title` varchar(100) NOT NULL DEFAULT '', `description` varchar(1000) DEFAULT '', `sysstamp` int(11) NOT NULL, `public` tinyint(1) NOT NULL DEFAULT '0', `visible` tinyint(1) NOT NULL DEFAULT '1', `downloadable` tinyint(1) NOT NULL DEFAULT '0', - `password` varchar(100) DEFAULT '', + `password` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; \ No newline at end of file diff --git a/php/database/photos_table.sql b/php/database/photos_table.sql index 058e3b3..b8d5ef9 100644 --- a/php/database/photos_table.sql +++ b/php/database/photos_table.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS `?` ( `id` bigint(14) NOT NULL, - `title` varchar(50) NOT NULL, + `title` varchar(100) NOT NULL, `description` varchar(1000) DEFAULT '', `url` varchar(100) NOT NULL, `tags` varchar(1000) NOT NULL DEFAULT '', diff --git a/php/database/settings_content.sql b/php/database/settings_content.sql index 63d9a69..60d178f 100644 --- a/php/database/settings_content.sql +++ b/php/database/settings_content.sql @@ -9,6 +9,10 @@ VALUES ('password',''), ('thumbQuality','90'), ('checkForUpdates','1'), - ('sorting','ORDER BY id DESC'), + ('sortingPhotos','ORDER BY id DESC'), + ('sortingAlbums','ORDER BY id DESC'), + ('medium','1'), + ('imagick','1'), ('dropboxKey',''), + ('identifier',''), ('plugins',''); \ No newline at end of file diff --git a/php/database/update_030001.php b/php/database/update_030001.php new file mode 100644 index 0000000..24a0191 --- /dev/null +++ b/php/database/update_030001.php @@ -0,0 +1,70 @@ +query($query); +if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')'); + return false; +} + +# Change length of album title +$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_ALBUMS)); +$result = $database->query($query); +if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')'); + return false; +} + +# Add album sorting to settings +$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'sortingAlbums' LIMIT 1", array(LYCHEE_TABLE_SETTINGS)); +$result = $database->query($query); +if ($result->num_rows===0) { + $query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('sortingAlbums', 'ORDER BY id DESC')", array(LYCHEE_TABLE_SETTINGS)); + $result = $database->query($query); + if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')'); + return false; + } +} + +# Rename sorting to sortingPhotos +$query = Database::prepare($database, "UPDATE ? SET `key` = 'sortingPhotos' WHERE `key` = 'sorting' LIMIT 1", array(LYCHEE_TABLE_SETTINGS)); +$result = $database->query($query); +if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')'); + return false; +} + +# Add identifier to settings +$query = Database::prepare($database, "SELECT `key` FROM `?` WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS)); +$result = $database->query($query); +if ($result->num_rows===0) { + $identifier = md5(microtime(true)); + $query = Database::prepare($database, "INSERT INTO `?` (`key`, `value`) VALUES ('identifier', '?')", array(LYCHEE_TABLE_SETTINGS, $identifier)); + $result = $database->query($query); + if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not update database (' . $database->error . ')'); + return false; + } +} else { + $identifier = md5(microtime(true)); + $query = Database::prepare($database, "UPDATE `?` SET `value` = '?' WHERE `key` = 'identifier' LIMIT 1", array(LYCHEE_TABLE_SETTINGS, $identifier)); + $result = $database->query($query); + if (!$result) { + Log::error($database, 'update_030001', __LINE__, 'Could not reset public albums (' . $database->error . ')'); + return false; + } +} + +# Set version +if (Database::setVersion($database, '030001')===false) return false; + +?> \ No newline at end of file diff --git a/php/modules/Album.php b/php/modules/Album.php index 1d4e6ec..d91ac04 100644 --- a/php/modules/Album.php +++ b/php/modules/Album.php @@ -94,19 +94,19 @@ class Album extends Module { switch ($this->albumIDs) { case 'f': $return['public'] = '0'; - $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)); + $query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE star = 1 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); break; case 's': $return['public'] = '0'; - $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)); + $query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE public = 1 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); break; case 'r': $return['public'] = '0'; - $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)); + $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['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); break; case '0': $return['public'] = '0'; - $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)); + $query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = 0 " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); break; default: $query = Database::prepare($this->database, "SELECT * FROM ? WHERE id = '?' LIMIT 1", array(LYCHEE_TABLE_ALBUMS, $this->albumIDs)); @@ -114,7 +114,7 @@ class Album extends Module { $return = $albums->fetch_assoc(); $return['sysdate'] = date('d M. Y', $return['sysstamp']); $return['password'] = ($return['password']=='' ? '0' : '1'); - $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)); + $query = Database::prepare($this->database, "SELECT id, title, tags, public, star, album, thumbUrl, takestamp, url FROM ? WHERE album = '?' " . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS, $this->albumIDs)); break; } @@ -189,8 +189,8 @@ class Album extends Module { if ($public===false) $return['smartalbums'] = $this->getSmartInfo(); # Albums query - $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ? WHERE public = 1 AND visible <> 0', array(LYCHEE_TABLE_ALBUMS)); - if ($public===false) $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ?', array(LYCHEE_TABLE_ALBUMS)); + if ($public===false) $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ? ' . $this->settings['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS)); + else $query = Database::prepare($this->database, 'SELECT id, title, public, sysstamp, password FROM ? WHERE public = 1 AND visible <> 0 ' . $this->settings['sortingAlbums'], array(LYCHEE_TABLE_ALBUMS)); # Execute query $albums = $this->database->query($query); @@ -210,7 +210,7 @@ class Album extends Module { ($public===false)) { # Execute query - $query = Database::prepare($this->database, "SELECT thumbUrl FROM ? WHERE album = '?' ORDER BY star DESC, " . substr($this->settings['sorting'], 9) . " LIMIT 3", array(LYCHEE_TABLE_PHOTOS, $album['id'])); + $query = Database::prepare($this->database, "SELECT thumbUrl FROM ? WHERE album = '?' ORDER BY star DESC, " . substr($this->settings['sortingPhotos'], 9) . " LIMIT 3", array(LYCHEE_TABLE_PHOTOS, $album['id'])); $thumbs = $this->database->query($query); # For each thumb @@ -223,7 +223,7 @@ class Album extends Module { } # Add to return - $return['albums'][$album['id']] = $album; + $return['albums'][] = $album; } @@ -254,7 +254,7 @@ class Album extends Module { # Unsorted ### - $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE album = 0 ' . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS)); + $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE album = 0 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); $unsorted = $this->database->query($query); $i = 0; @@ -274,7 +274,7 @@ class Album extends Module { # Starred ### - $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE star = 1 ' . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS)); + $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE star = 1 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); $starred = $this->database->query($query); $i = 0; @@ -294,7 +294,7 @@ class Album extends Module { # Public ### - $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE public = 1 ' . $this->settings['sorting'], array(LYCHEE_TABLE_PHOTOS)); + $query = Database::prepare($this->database, 'SELECT thumbUrl FROM ? WHERE public = 1 ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); $public = $this->database->query($query); $i = 0; @@ -314,7 +314,7 @@ class Album extends Module { # Recent ### - $query = Database::prepare($this->database, 'SELECT thumbUrl 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 thumbUrl FROM ? WHERE LEFT(id, 10) >= unix_timestamp(DATE_SUB(NOW(), INTERVAL 1 DAY)) ' . $this->settings['sortingPhotos'], array(LYCHEE_TABLE_PHOTOS)); $recent = $this->database->query($query); $i = 0; @@ -484,7 +484,7 @@ class Album extends Module { $this->plugins(__METHOD__, 0, func_get_args()); # Parse - if (strlen($title)>50) $title = substr($title, 0, 50); + if (strlen($title)>100) $title = substr($title, 0, 100); # Execute query $query = Database::prepare($this->database, "UPDATE ? SET title = '?' WHERE id IN (?)", array(LYCHEE_TABLE_ALBUMS, $title, $this->albumIDs)); diff --git a/php/modules/Database.php b/php/modules/Database.php index 999d293..66c1124 100755 --- a/php/modules/Database.php +++ b/php/modules/Database.php @@ -55,7 +55,8 @@ class Database extends Module { '020601', #2.6.1 '020602', #2.6.2 '020700', #2.7.0 - '030000' #3.0.0 + '030000', #3.0.0 + '030001' #3.0.1 ); # For each update diff --git a/php/modules/Photo.php b/php/modules/Photo.php index 26d7f11..8d1c292 100755 --- a/php/modules/Photo.php +++ b/php/modules/Photo.php @@ -842,7 +842,7 @@ class Photo extends Module { $this->plugins(__METHOD__, 0, func_get_args()); # Parse - if (strlen($title)>50) $title = substr($title, 0, 50); + if (strlen($title)>100) $title = substr($title, 0, 100); # Set title $query = Database::prepare($this->database, "UPDATE ? SET title = '?' WHERE id IN (?)", array(LYCHEE_TABLE_PHOTOS, $title, $this->photoIDs)); diff --git a/php/modules/Session.php b/php/modules/Session.php index 6bb32bc..16916c9 100755 --- a/php/modules/Session.php +++ b/php/modules/Session.php @@ -44,6 +44,9 @@ class Session extends Module { unset($return['config']['username']); unset($return['config']['password']); + # Remove identifier from response + unset($return['config']['identifier']); + # Path to Lychee for the server-import dialog $return['config']['location'] = LYCHEE; @@ -67,10 +70,13 @@ class Session extends Module { # Unset unused vars unset($return['config']['thumbQuality']); - unset($return['config']['sorting']); + unset($return['config']['sortingAlbums']); + unset($return['config']['sortingPhotos']); unset($return['config']['dropboxKey']); unset($return['config']['login']); unset($return['config']['location']); + unset($return['config']['imagick']); + unset($return['config']['medium']); unset($return['config']['plugins']); } @@ -96,15 +102,13 @@ class Session extends Module { # Check login with crypted hash if ($this->settings['username']===$username&& $this->settings['password']===$password) { - $_SESSION['login'] = true; + $_SESSION['login'] = true; + $_SESSION['identifier'] = $this->settings['identifier']; return true; } # No login - if ($this->noLogin()===true) { - $_SESSION['login'] = true; - return true; - } + if ($this->noLogin()===true) return true; # Call plugins $this->plugins(__METHOD__, 1, func_get_args()); @@ -121,7 +125,8 @@ class Session extends Module { # Check if login credentials exist and login if they don't if ($this->settings['username']===''&& $this->settings['password']==='') { - $_SESSION['login'] = true; + $_SESSION['login'] = true; + $_SESSION['identifier'] = $this->settings['identifier']; return true; } @@ -134,6 +139,9 @@ class Session extends Module { # Call plugins $this->plugins(__METHOD__, 0, func_get_args()); + $_SESSION['login'] = null; + $_SESSION['identifier'] = null; + session_destroy(); # Call plugins diff --git a/php/modules/Settings.php b/php/modules/Settings.php index e53a5a4..f0f57f4 100755 --- a/php/modules/Settings.php +++ b/php/modules/Settings.php @@ -129,7 +129,7 @@ class Settings extends Module { } - public function setSorting($type, $order) { + public function setSortingPhotos($type, $order) { # Check dependencies self::dependencies(isset($this->database, $type, $order)); @@ -182,7 +182,64 @@ class Settings extends Module { # Execute query # Do not prepare $sorting because it is a true statement # Preparing (escaping) the sorting would destroy it - $query = Database::prepare($this->database, "UPDATE ? SET value = '$sorting' WHERE `key` = 'sorting'", array(LYCHEE_TABLE_SETTINGS)); + # $sorting is save and can't contain user-input + $query = Database::prepare($this->database, "UPDATE ? SET value = '$sorting' WHERE `key` = 'sortingPhotos'", array(LYCHEE_TABLE_SETTINGS)); + $result = $this->database->query($query); + + if (!$result) { + Log::error($this->database, __METHOD__, __LINE__, $this->database->error); + return false; + } + return true; + + } + + public function setSortingAlbums($type, $order) { + + # Check dependencies + self::dependencies(isset($this->database, $type, $order)); + + $sorting = 'ORDER BY '; + + # Set row + switch ($type) { + + case 'id': $sorting .= 'id'; + break; + + case 'title': $sorting .= 'title'; + break; + + case 'description': $sorting .= 'description'; + break; + + case 'public': $sorting .= 'public'; + break; + + default: exit('Error: Unknown type for sorting!'); + + } + + $sorting .= ' '; + + # Set order + switch ($order) { + + case 'ASC': $sorting .= 'ASC'; + break; + + case 'DESC': $sorting .= 'DESC'; + break; + + default: exit('Error: Unknown order for sorting!'); + + } + + # Execute query + # Do not prepare $sorting because it is a true statement + # Preparing (escaping) the sorting would destroy it + # $sorting is save and can't contain user-input + $query = Database::prepare($this->database, "UPDATE ? SET value = '$sorting' WHERE `key` = 'sortingAlbums'", array(LYCHEE_TABLE_SETTINGS)); $result = $this->database->query($query); if (!$result) { diff --git a/php/modules/misc.php b/php/modules/misc.php index f5b9ba3..f763144 100755 --- a/php/modules/misc.php +++ b/php/modules/misc.php @@ -47,7 +47,7 @@ function search($database, $settings, $term) { $album = Album::prepareData($album); # Thumbs - $query = Database::prepare($database, "SELECT thumbUrl FROM ? WHERE album = '?' " . $settings['sorting'] . " LIMIT 0, 3", array(LYCHEE_TABLE_PHOTOS, $album['id'])); + $query = Database::prepare($database, "SELECT thumbUrl FROM ? WHERE album = '?' " . $settings['sortingPhotos'] . " LIMIT 0, 3", array(LYCHEE_TABLE_PHOTOS, $album['id'])); $thumbs = $database->query($query); # For each thumb diff --git a/src/bower.json b/src/bower.json index 4a13665..d26114f 100644 --- a/src/bower.json +++ b/src/bower.json @@ -2,7 +2,7 @@ "name": "Lychee", "private": true, "dependencies": { - "jQuery": "~2.1.3", + "jQuery": "~2.1.4", "mousetrap": "~1.5.2", "basicContext": "~2.0.9", "basicModal": "~2.0.8" diff --git a/src/package.json b/src/package.json index 533ca57..5a94281 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "Lychee", - "version": "3.0.0", + "version": "3.0.1", "description": "Self-hosted photo-management done right.", "authors": "Tobias Reich ", "license": "MIT", @@ -18,7 +18,7 @@ "gulp-load-plugins": "^0.10.0", "gulp-minify-css": "^1.1.1", "gulp-rimraf": "^0.1.1", - "gulp-sass": "^1.3.3", + "gulp-sass": "^2.0.1", "gulp-uglify": "^1.2.0" } } diff --git a/src/scripts/album.js b/src/scripts/album.js index a97e47d..e1f56b2 100644 --- a/src/scripts/album.js +++ b/src/scripts/album.js @@ -138,7 +138,7 @@ album.add = function() { } basicModal.show({ - body: "

Enter a title for the new album:

", + body: "

Enter a title for the new album:

", buttons: { action: { title: 'Create Album', @@ -180,7 +180,7 @@ album.delete = function(albumIDs) { albumIDs.forEach(function(id) { albums.json.num--; view.albums.content.delete(id); - delete albums.json.albums[id]; + albums.deleteByID(id); }); } else { @@ -210,7 +210,7 @@ album.delete = function(albumIDs) { // Get title if (album.json) albumTitle = album.json.title; - else if (albums.json) albumTitle = albums.json.albums[albumIDs].title; + else if (albums.json) albumTitle = albums.getByID(albumIDs).title; msg = "

Are you sure you want to delete the album '" + albumTitle + "' and all of the photos it contains? This action can't be undone!

"; @@ -254,7 +254,7 @@ album.setTitle = function(albumIDs) { // Get old title if only one album is selected if (album.json) oldTitle = album.json.title; - else if (albums.json) oldTitle = albums.json.albums[albumIDs].title; + else if (albums.json) oldTitle = albums.getByID(albumIDs).title; if (!oldTitle) oldTitle = ''; oldTitle = oldTitle.replace(/'/g, '''); @@ -281,13 +281,13 @@ album.setTitle = function(albumIDs) { if (albums.json) { var id = albumIDs[0]; - albums.json.albums[id].title = newTitle; + albums.getByID(id).title = newTitle; } } else if (visible.albums()) { albumIDs.forEach(function(id) { - albums.json.albums[id].title = newTitle; + albums.getByID(id).title = newTitle; view.albums.content.title(id); }); @@ -306,7 +306,7 @@ album.setTitle = function(albumIDs) { } - input = ""; + input = ""; if (albumIDs.length===1) msg = "

Enter a new title for this album: " + input + "

"; else msg = "

Enter a title for all " + albumIDs.length + " selected albums: " + input +"

"; @@ -580,7 +580,7 @@ album.merge = function(albumIDs) { if (albumIDs instanceof Array===false) albumIDs = [albumIDs]; // Get title of first album - if (albums.json) title = albums.json.albums[albumIDs[0]].title; + if (albums.json) title = albums.getByID(albumIDs[0]).title; if (!title) title = ''; title = title.replace(/'/g, '''); @@ -588,7 +588,7 @@ album.merge = function(albumIDs) { if (albumIDs.length===2) { // Get title of second album - if (albums.json) sTitle = albums.json.albums[albumIDs[1]].title; + if (albums.json) sTitle = albums.getByID(albumIDs[1]).title; if (!sTitle) sTitle = ''; sTitle = sTitle.replace(/'/g, '''); diff --git a/src/scripts/albums.js b/src/scripts/albums.js index cf73c72..a0288b6 100644 --- a/src/scripts/albums.js +++ b/src/scripts/albums.js @@ -105,6 +105,52 @@ albums._createSmartAlbums = function(data) { } +albums.getByID = function(albumID) { + + // Function returns the JSON of an album + + if (albumID===undefined||albumID===null) return undefined; + if (!albums.json) return undefined; + if (!albums.json.albums) return undefined; + + var json = undefined; + + $.each(albums.json.albums, function(i) { + + let elem = albums.json.albums[i]; + + if (elem.id==albumID) json = elem; + + }); + + return json; + +} + +albums.deleteByID = function(albumID) { + + // Function returns the JSON of an album + + if (albumID===undefined||albumID===null) return false; + if (!albums.json) return false; + if (!albums.json.albums) return false; + + var deleted = false; + + $.each(albums.json.albums, function(i) { + + if (albums.json.albums[i].id==albumID) { + albums.json.albums.splice(i, 1); + deleted = true; + return false; + } + + }); + + return deleted; + +} + albums.refresh = function() { albums.json = null; diff --git a/src/scripts/build.js b/src/scripts/build.js index 64c9aa6..ada7012 100644 --- a/src/scripts/build.js +++ b/src/scripts/build.js @@ -59,16 +59,7 @@ build.album = function(data) { if (data===null||data===undefined) return ''; - var html = '', - title = data.title, - longTitle = ''; - - if (title!==null&&title.length>18) { - - title = data.title.substr(0, 18) + '...'; - longTitle = data.title; - - } + var html = ''; var {path: thumbPath, hasRetina: thumbRetina} = lychee.retinize(data.thumbs[0]); @@ -78,7 +69,7 @@ build.album = function(data) { thumb thumb
-

${ title }

+

${ data.title }

${ data.sysdate }
` @@ -103,16 +94,7 @@ build.photo = function(data) { if (data===null||data===undefined) return ''; - var html = '', - title = data.title, - longTitle = ''; - - if (title!==null&&title.length>18) { - - title = data.title.substr(0, 18) + '...'; - longTitle = data.title; - - } + var html = ''; var {path: thumbPath, hasRetina: thumbRetina} = lychee.retinize(data.thumbUrl); @@ -120,7 +102,7 @@ build.photo = function(data) {
thumb
-

${ title }

+

${ data.title }

` if (data.cameraDate==='1') html += `${ build.iconic('camera-slr') }${ data.sysdate }`; diff --git a/src/scripts/contextMenu.js b/src/scripts/contextMenu.js index 8e3da9f..aa99cdd 100644 --- a/src/scripts/contextMenu.js +++ b/src/scripts/contextMenu.js @@ -84,7 +84,7 @@ contextMenu.albumTitle = function(albumID, e) { api.post('Album::getAll', {}, function(data) { - if (data.num>1) { + if (data.albums&&data.num>1) { // Generate list of albums $.each(data.albums, function(index) { @@ -96,7 +96,7 @@ contextMenu.albumTitle = function(albumID, e) { title = "
" + that.title + "
"; - if (that.id!=albumID) items.unshift({ type: 'item', title, fn: function() { lychee.goto(that.id) } }); + if (that.id!=albumID) items.push({ type: 'item', title, fn: function() { lychee.goto(that.id) } }); }); @@ -114,28 +114,30 @@ contextMenu.albumTitle = function(albumID, e) { contextMenu.mergeAlbum = function(albumID, e) { - var items = []; + var items = []; - api.post('Album::getAll', {}, function(data) { + api.post('Album::getAll', {}, function(data) { - $.each(data.albums, function(){ + if (data.albums&&data.num>1) { - var that = this; + $.each(data.albums, function(){ - if (!that.thumbs[0]) that.thumbs[0] = 'src/images/no_cover.svg'; - that.contextTitle = "
" + that.title + "
"; + var that = this; - if (that.id!=album.getID()) { - items.unshift({ type: 'item', title: that.contextTitle, fn: function() { album.merge([albumID, that.id]) } }); - } + if (!that.thumbs[0]) that.thumbs[0] = 'src/images/no_cover.svg'; + that.contextTitle = "
" + that.title + "
"; - }); + if (that.id!=albumID) items.push({ type: 'item', title: that.contextTitle, fn: function() { album.merge([albumID, that.id]) } }); - if (items.length===0) return false; + }); - basicContext.show(items, e, contextMenu.close); + } - }) + if (items.length===0) return false; + + basicContext.show(items, e, contextMenu.close); + + }); } @@ -191,7 +193,7 @@ contextMenu.photoTitle = function(albumID, photoID, e) { var data = album.json; - if (data.num>1) { + if (data.content!==false&&data.num>1) { items.push({ type: 'separator' }); @@ -253,7 +255,7 @@ contextMenu.move = function(photoIDs, e) { if (!that.thumbs[0]) that.thumbs[0] = 'src/images/no_cover.svg'; that.title = "
" + that.title + "
"; - if (that.id!=album.getID()) items.unshift({ type: 'item', title: that.title, fn: function() { photo.setAlbum(photoIDs, that.id) } }); + if (that.id!=album.getID()) items.push({ type: 'item', title: that.title, fn: function() { photo.setAlbum(photoIDs, that.id) } }); }); diff --git a/src/scripts/loadingBar.js b/src/scripts/loadingBar.js index ad02e47..5453996 100755 --- a/src/scripts/loadingBar.js +++ b/src/scripts/loadingBar.js @@ -85,7 +85,7 @@ loadingBar.hide = function(force) { loadingBar.status = null; // Move header up - if (visible.header()) header.dom().removeClass('error loading'); + header.dom().removeClass('error loading'); // Set timeout clearTimeout(loadingBar._timeout); diff --git a/src/scripts/lychee.js b/src/scripts/lychee.js index ad3b7ee..85a4b3a 100644 --- a/src/scripts/lychee.js +++ b/src/scripts/lychee.js @@ -6,8 +6,8 @@ lychee = { title: document.title, - version: '3.0.0', - version_code: '030000', + version: '3.0.1', + version_code: '030001', update_path: 'http://lychee.electerious.com/version/index.php', updateURL: 'https://github.com/electerious/Lychee', @@ -18,7 +18,8 @@ lychee = { debugMode: false, checkForUpdates:'1', - sorting: '', + sortingPhotos: '', + sortingAlbums: '', location: '', dropbox: false, @@ -48,7 +49,8 @@ lychee.init = function() { // Logged in - lychee.sorting = data.config.sorting || ''; + lychee.sortingPhotos = data.config.sortingPhotos || ''; + lychee.sortingAlbums = data.config.sortingAlbums || ''; lychee.dropboxKey = data.config.dropboxKey || ''; lychee.location = data.config.location || ''; lychee.checkForUpdates = data.config.checkForUpdates || '1'; @@ -382,10 +384,13 @@ lychee.loadDropbox = function(callback) { } -lychee.removeHTML = function(html) { +lychee.removeHTML = function(html = '') { + + if (html==='') return html; var tmp = document.createElement('DIV'); tmp.innerHTML = html; + return tmp.textContent || tmp.innerText; } diff --git a/src/scripts/password.js b/src/scripts/password.js index 33776d0..eed704a 100644 --- a/src/scripts/password.js +++ b/src/scripts/password.js @@ -14,9 +14,9 @@ password.get = function(albumID, callback) { var passwd = $('.basicModal input.text').val(), params; - if (lychee.publicMode===false) callback(); - else if (album.json&&album.json.password==='0') callback(); - else if (albums.json&&albums.json.albums[albumID].password==='0') callback(); + if (lychee.publicMode===false) callback(); + else if (album.json&&album.json.password==='0') callback(); + else if (albums.json&&albums.getByID(albumID).password==='0') callback(); else if (!albums.json&&!album.json) { // Continue without password diff --git a/src/scripts/photo.js b/src/scripts/photo.js index 842af0a..58d2d9f 100644 --- a/src/scripts/photo.js +++ b/src/scripts/photo.js @@ -223,7 +223,7 @@ photo.delete = function(photoIDs) { } - album.json.content[id] = null; + delete album.json.content[id]; view.album.content.delete(id); }); @@ -330,7 +330,7 @@ photo.setTitle = function(photoIDs) { } - input = ""; + input = ""; if (photoIDs.length===1) msg = "

Enter a new title for this photo: " + input + "

"; else msg = "

Enter a title for all " + photoIDs.length + " selected photos: " + input + "

"; diff --git a/src/scripts/settings.js b/src/scripts/settings.js index f732b70..eda7102 100644 --- a/src/scripts/settings.js +++ b/src/scripts/settings.js @@ -281,7 +281,8 @@ settings.setLogin = function() { settings.setSorting = function() { - var sorting = [], + var sortingPhotos = [], + sortingAlbums = [], action, msg = ''; @@ -289,21 +290,27 @@ settings.setSorting = function() { var params; - sorting[0] = $('.basicModal select#settings_type').val(); - sorting[1] = $('.basicModal select#settings_order').val(); + sortingAlbums[0] = $('.basicModal select#settings_albums_type').val(); + sortingAlbums[1] = $('.basicModal select#settings_albums_order').val(); + + sortingPhotos[0] = $('.basicModal select#settings_photos_type').val(); + sortingPhotos[1] = $('.basicModal select#settings_photos_order').val(); basicModal.close(); albums.refresh(); params = { - type: sorting[0], - order: sorting[1] + typeAlbums: sortingAlbums[0], + orderAlbums: sortingAlbums[1], + typePhotos: sortingPhotos[0], + orderPhotos: sortingPhotos[1] } api.post('Settings::setSorting', params, function(data) { if (data===true) { - lychee.sorting = 'ORDER BY ' + sorting[0] + ' ' + sorting[1]; + lychee.sortingAlbums = 'ORDER BY ' + sortingAlbums[0] + ' ' + sortingAlbums[1]; + lychee.sortingPhotos = 'ORDER BY ' + sortingPhotos[0] + ' ' + sortingPhotos[1]; lychee.load(); } else lychee.error(null, params, data); @@ -313,21 +320,44 @@ settings.setSorting = function() { msg = `

- Sort photos by - + Sort albums by + + + in an - + + + + order. +

+

+ Sort photos by + + + + in an + + + order.

` @@ -346,12 +376,21 @@ settings.setSorting = function() { } }); - if (lychee.sorting!=='') { + if (lychee.sortingAlbums!=='') { - sorting = lychee.sorting.replace('ORDER BY ', '').split(' '); + sortingAlbums = lychee.sortingAlbums.replace('ORDER BY ', '').split(' '); - $('.basicModal select#settings_type').val(sorting[0]); - $('.basicModal select#settings_order').val(sorting[1]); + $('.basicModal select#settings_albums_type').val(sortingAlbums[0]); + $('.basicModal select#settings_albums_order').val(sortingAlbums[1]); + + } + + if (lychee.sortingPhotos!=='') { + + sortingPhotos = lychee.sortingPhotos.replace('ORDER BY ', '').split(' '); + + $('.basicModal select#settings_photos_type').val(sortingPhotos[0]); + $('.basicModal select#settings_photos_order').val(sortingPhotos[1]); } diff --git a/src/scripts/view.js b/src/scripts/view.js index 0b0c0fa..ead2710 100644 --- a/src/scripts/view.js +++ b/src/scripts/view.js @@ -46,9 +46,7 @@ view.albums = { $.each(albums.json.albums, function() { albums.parse(this); - - // Display albums in reverse order - albumsData = build.album(this) + albumsData; + albumsData += build.album(this); }); // Add divider @@ -73,17 +71,11 @@ view.albums = { title: function(albumID) { - var longTitle = '', - title = albums.json.albums[albumID].title; - - if (title!==null&&title.length>18) { - longTitle = title; - title = title.substr(0, 18) + '...'; - } + var title = albums.getByID(albumID).title; $('.album[data-id="' + albumID + '"] .overlay h1') .html(title) - .attr('title', longTitle); + .attr('title', title); }, @@ -94,7 +86,7 @@ view.albums = { marginLeft: 0 }, 300, function() { $(this).remove(); - if (albums.json.num<=0) lychee.animate('#content .divider:last-of-type', 'fadeOut'); + if (albums.json.num<=0) lychee.content.find('.divider:last-child').remove(); }); } @@ -155,27 +147,27 @@ view.album = { view.albums.content.scrollPosition = $(document).scrollTop(); $('html, body').scrollTop(0); - $.each(album.json.content, function() { - photosData += build.photo(this); - }); + if (album.json.content&&album.json.content!==false) { + // Build photos + $.each(album.json.content, function() { + photosData += build.photo(this); + }); + + } + + // Add photos to view lychee.content.html(photosData); }, title: function(photoID) { - var longTitle = '', - title = album.json.content[photoID].title; - - if (title!==null&&title.length>18) { - longTitle = title; - title = title.substr(0, 18) + '...'; - } + var title = album.json.content[photoID].title; $('.photo[data-id="' + photoID + '"] .overlay h1') .html(title) - .attr('title', longTitle); + .attr('title', title); }, diff --git a/src/styles/_content.scss b/src/styles/_content.scss index ed144ff..8f1c41d 100644 --- a/src/styles/_content.scss +++ b/src/styles/_content.scss @@ -125,13 +125,15 @@ .album .overlay h1, .photo .overlay h1 { min-height: 19px; - width: 185px; + width: 180px; margin: 12px 0 5px 15px; color: #fff; text-shadow: 0 1px 3px black(.4); font-size: 16px; font-weight: bold; overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .album .overlay a, @@ -218,13 +220,13 @@ .iconic { fill: white(.3); margin: 0 0 10px; - width: 60px; - height: 60px; + width: 50px; + height: 50px; filter: drop-shadow(0 -1px 0 black(.4)); } p { - font-size: 18px; + font-size: 16px; font-weight: bold; } } \ No newline at end of file diff --git a/src/styles/_header.scss b/src/styles/_header.scss index adebee2..0f050a0 100644 --- a/src/styles/_header.scss +++ b/src/styles/_header.scss @@ -38,6 +38,9 @@ header { text-align: center; z-index: 1; cursor: default; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; .iconic { display: none; diff --git a/src/styles/_message.scss b/src/styles/_message.scss index 159f49f..a3a4898 100644 --- a/src/styles/_message.scss +++ b/src/styles/_message.scss @@ -172,6 +172,65 @@ } } + /* Select ------------------------------------------------*/ + .select { + display: inline-block; + position: relative; + margin: 1px 5px; + padding: 0; + width: 110px; + background: black(.3); + color: #fff; + border-radius: 3px; + border: 1px solid black(.2); + box-shadow: 0 1px 0 white(.02); + font-size: 11px; + line-height: 16px; + overflow: hidden; + outline: 0; + vertical-align: middle; + + &::after { + position: absolute; + content: '≡'; + right: 8px; + top: 4px; + color: $colorBlue; + font-size: 16px; + line-height: 16px; + font-weight: bold; + pointer-events: none; + } + + select { + margin: 0; + padding: 4px 8px; + width: 120%; + color: #fff; + font-size: 11px; + line-height: 16px; + border: 0; + outline: 0; + box-shadow: none; + border-radius: 0; + background-color: transparent; + background-image: none; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + + &:focus { outline: none; } + } + + select option { + margin: 0; + padding: 0; + background: #fff; + color: #333; + transition: none; + } + } + /* Version ------------------------------------------------*/ .version { margin: -5px 0 0;