Merge pull request #354 from electerious/develop

v3.0.1
pull/355/merge v3.0.1
Tobias Reich 9 years ago
commit d4c724b02c

2
dist/main.css vendored

File diff suppressed because one or more lines are too long

12
dist/main.js vendored

File diff suppressed because one or more lines are too long

6
dist/view.js vendored

File diff suppressed because one or more lines are too long

@ -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.

@ -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;
}

@ -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

@ -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;

@ -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 '',

@ -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','');

@ -0,0 +1,70 @@
<?php
###
# @name Update to version 3.0.1
# @copyright 2015 by Tobias Reich
###
if (!defined('LYCHEE')) exit('Error: Direct access is not allowed!');
# Change length of photo title
$query = Database::prepare($database, "ALTER TABLE `?` CHANGE `title` `title` VARCHAR( 100 ) NOT NULL DEFAULT ''", array(LYCHEE_TABLE_PHOTOS));
$result = $database->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;
?>

@ -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));

@ -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

@ -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));

@ -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

@ -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) {

@ -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

@ -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"

@ -1,6 +1,6 @@
{
"name": "Lychee",
"version": "3.0.0",
"version": "3.0.1",
"description": "Self-hosted photo-management done right.",
"authors": "Tobias Reich <tobias@electerious.com>",
"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"
}
}

@ -138,7 +138,7 @@ album.add = function() {
}
basicModal.show({
body: "<p>Enter a title for the new album: <input class='text' data-name='title' type='text' maxlength='30' placeholder='Title' value='Untitled'></p>",
body: "<p>Enter a title for the new album: <input class='text' data-name='title' type='text' maxlength='50' placeholder='Title' value='Untitled'></p>",
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 = "<p>Are you sure you want to delete the album '" + albumTitle + "' and all of the photos it contains? This action can't be undone!</p>";
@ -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, '&apos;');
@ -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 class='text' data-name='title' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>";
input = "<input class='text' data-name='title' type='text' maxlength='50' placeholder='Title' value='" + oldTitle + "'>";
if (albumIDs.length===1) msg = "<p>Enter a new title for this album: " + input + "</p>";
else msg = "<p>Enter a title for all " + albumIDs.length + " selected albums: " + input +"</p>";
@ -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, '&apos;');
@ -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, '&apos;');

@ -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;

@ -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) {
<img src='${ data.thumbs[1] }' width='200' height='200' alt='thumb' data-retina='false'>
<img src='${ thumbPath }' width='200' height='200' alt='thumb' data-retina='${ thumbRetina }'>
<div class='overlay'>
<h1 title='${ longTitle }'>${ title }</h1>
<h1 title='${ data.title }'>${ data.title }</h1>
<a>${ data.sysdate }</a>
</div>
`
@ -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) {
<div class='photo' data-album-id='${ data.album }' data-id='${ data.id }'>
<img src='${ thumbPath }' width='200' height='200' alt='thumb'>
<div class='overlay'>
<h1 title='${ longTitle }'>${ title }</h1>
<h1 title='${ data.title }'>${ data.title }</h1>
`
if (data.cameraDate==='1') html += `<a><span title='Camera Date'>${ build.iconic('camera-slr') }</span>${ data.sysdate }</a>`;

@ -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 = "<img class='cover' width='16' height='16' src='" + that.thumbs[0] + "'><div class='title'>" + that.title + "</div>";
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) {
if (data.albums&&data.num>1) {
$.each(data.albums, function(){
$.each(data.albums, function(){
var that = this;
var that = this;
if (!that.thumbs[0]) that.thumbs[0] = 'src/images/no_cover.svg';
that.contextTitle = "<img class='cover' width='16' height='16' src='" + that.thumbs[0] + "'><div class='title'>" + that.title + "</div>";
if (!that.thumbs[0]) that.thumbs[0] = 'src/images/no_cover.svg';
that.contextTitle = "<img class='cover' width='16' height='16' src='" + that.thumbs[0] + "'><div class='title'>" + that.title + "</div>";
if (that.id!=albumID) items.push({ type: 'item', title: that.contextTitle, fn: function() { album.merge([albumID, that.id]) } });
if (that.id!=album.getID()) {
items.unshift({ type: 'item', title: that.contextTitle, fn: function() { album.merge([albumID, that.id]) } });
}
});
});
}
if (items.length===0) return false;
if (items.length===0) return false;
basicContext.show(items, e, contextMenu.close);
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 = "<img class='cover' width='16' height='16' src='" + that.thumbs[0] + "'><div class='title'>" + that.title + "</div>";
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) } });
});

@ -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);

@ -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;
}

@ -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

@ -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 class='text' data-name='title' type='text' maxlength='30' placeholder='Title' value='" + oldTitle + "'>";
input = "<input class='text' data-name='title' type='text' maxlength='50' placeholder='Title' value='" + oldTitle + "'>";
if (photoIDs.length===1) msg = "<p>Enter a new title for this photo: " + input + "</p>";
else msg = "<p>Enter a title for all " + photoIDs.length + " selected photos: " + input + "</p>";

@ -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);
@ -312,22 +319,45 @@ settings.setSorting = function() {
}
msg = `
<p>
Sort albums by
<span class="select">
<select id='settings_albums_type'>
<option value='id'>Creation Time</option>
<option value='title'>Title</option>
<option value='description'>Description</option>
<option value='public'>Public</option>
</select>
</span>
in an
<span class="select">
<select id='settings_albums_order'>
<option value='ASC'>Ascending</option>
<option value='DESC'>Descending</option>
</select>
</span>
order.
</p>
<p>
Sort photos by
<select id='settings_type'>
<option value='id'>Upload Time</option>
<option value='takestamp'>Take Date</option>
<option value='title'>Title</option>
<option value='description'>Description</option>
<option value='public'>Public</option>
<option value='star'>Star</option>
<option value='type'>Photo Format</option>
</select>
<span class="select">
<select id='settings_photos_type'>
<option value='id'>Upload Time</option>
<option value='takestamp'>Take Date</option>
<option value='title'>Title</option>
<option value='description'>Description</option>
<option value='public'>Public</option>
<option value='star'>Star</option>
<option value='type'>Photo Format</option>
</select>
</span>
in an
<select id='settings_order'>
<option value='ASC'>Ascending</option>
<option value='DESC'>Descending</option>
</select>
<span class="select">
<select id='settings_photos_order'>
<option value='ASC'>Ascending</option>
<option value='DESC'>Descending</option>
</select>
</span>
order.
</p>
`
@ -346,12 +376,21 @@ settings.setSorting = function() {
}
});
if (lychee.sorting!=='') {
if (lychee.sortingAlbums!=='') {
sortingAlbums = lychee.sortingAlbums.replace('ORDER BY ', '').split(' ');
$('.basicModal select#settings_albums_type').val(sortingAlbums[0]);
$('.basicModal select#settings_albums_order').val(sortingAlbums[1]);
}
if (lychee.sortingPhotos!=='') {
sorting = lychee.sorting.replace('ORDER BY ', '').split(' ');
sortingPhotos = lychee.sortingPhotos.replace('ORDER BY ', '').split(' ');
$('.basicModal select#settings_type').val(sorting[0]);
$('.basicModal select#settings_order').val(sorting[1]);
$('.basicModal select#settings_photos_type').val(sortingPhotos[0]);
$('.basicModal select#settings_photos_order').val(sortingPhotos[1]);
}

@ -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);
},

@ -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;
}
}

@ -38,6 +38,9 @@ header {
text-align: center;
z-index: 1;
cursor: default;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.iconic {
display: none;

@ -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;

Loading…
Cancel
Save