Merge pull request #6 from electerious/develop

Develop
This commit is contained in:
Quentin Ligier 2016-04-17 21:02:10 +02:00
commit 55577e1c39
40 changed files with 222 additions and 131 deletions

BIN
dist/main.css vendored

Binary file not shown.

BIN
dist/main.js vendored Executable file → Normal file

Binary file not shown.

BIN
dist/view.js vendored

Binary file not shown.

View File

@ -1,6 +1,6 @@
## v3.1.0 ## v3.1.0
Released March ??, 2016 Released March 29, 2016
**Warning**: It's no longer possible to update from Lychee versions older than 2.7. **Warning**: It's no longer possible to update from Lychee versions older than 2.7.
@ -14,7 +14,8 @@ This updates includes a huge rewrite of the back-end. We are now using namespace
- `New` Empty titles for albums - `New` Empty titles for albums
- `New` Share albums as hidden so they are only viewable with a direct link (#27) - `New` Share albums as hidden so they are only viewable with a direct link (#27)
- `Improved` Error messages and log output - `New` Log failed and successful login attempts (Thanks @qligier, #382 #246)
- `Improved` error messages and log output
- `Improved` The search shows albums above photos (#434) - `Improved` The search shows albums above photos (#434)
- `Improved` Album id now based on the current microtime (#27) - `Improved` Album id now based on the current microtime (#27)
- `Improved` Back-end modules and plugins - `Improved` Back-end modules and plugins
@ -22,6 +23,10 @@ This updates includes a huge rewrite of the back-end. We are now using namespace
- `Improved` Default photo title now "Untitled" - `Improved` Default photo title now "Untitled"
- `Improved` Move to next photo after after moving a picture (#437) - `Improved` Move to next photo after after moving a picture (#437)
- `Improved` Return to album overview when canceling album password input - `Improved` Return to album overview when canceling album password input
- `Improved` URL import now accepts photo URLs containing "?" and ":" (Thanks @qligier, #482)
- `Improved` Replaced date by strftime to simplify date translations (Thanks @qligier, #461)
- `Fixed` Missing icons in Safari 9.1
- `Fixed` duplicate uploads (Thanks @qligier, #433)
- `Fixed` incorrect escaping when using backslashes - `Fixed` incorrect escaping when using backslashes
- `Fixed` session_start() after sending headers (#433) - `Fixed` session_start() after sending headers (#433)
- `Fixed` error when deleting last open photo in album - `Fixed` error when deleting last open photo in album

View File

@ -55,4 +55,7 @@ Yes. Lychee uses ImageMagick when available.
There's a problem with images compressed by ImageOptim. [Read more.](https://github.com/electerious/Lychee/issues/175#issuecomment-47403992) There's a problem with images compressed by ImageOptim. [Read more.](https://github.com/electerious/Lychee/issues/175#issuecomment-47403992)
#### How to change the title of the site? #### How to change the title of the site?
[#455](https://github.com/electerious/Lychee/issues/455) [#455](https://github.com/electerious/Lychee/issues/455)
#### How to reset username and password?
Simply delete the whole `lychee_settings` table from the database. Lychee will regenerate it and ask you to enter a new username and password.

View File

@ -93,7 +93,7 @@ final class Admin extends Access {
Validator::required(isset($_POST['title']), __METHOD__); Validator::required(isset($_POST['title']), __METHOD__);
$album = new Album(null); $album = new Album(null);
Response::json($album->add($_POST['title'])); Response::json($album->add($_POST['title']), JSON_NUMERIC_CHECK);
} }
@ -231,7 +231,7 @@ final class Admin extends Access {
Validator::required(isset($_FILES, $_POST['albumID']), __METHOD__); Validator::required(isset($_FILES, $_POST['albumID']), __METHOD__);
$photo = new Photo(null); $photo = new Photo(null);
Response::json($photo->add($_FILES, $_POST['albumID'])); Response::json($photo->add($_FILES, $_POST['albumID']), JSON_NUMERIC_CHECK);
} }
@ -249,7 +249,7 @@ final class Admin extends Access {
Validator::required(isset($_POST['albumID'], $_POST['path']), __METHOD__); Validator::required(isset($_POST['albumID'], $_POST['path']), __METHOD__);
$import = new Import(); $import = new Import();
echo $import->server($_POST['path'], $_POST['albumID']); Response::json($import->server($_POST['path'], $_POST['albumID']));
} }

View File

@ -26,7 +26,7 @@ final class Installation extends Access {
Validator::required(isset($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']), __METHOD__); Validator::required(isset($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']), __METHOD__);
echo Config::create($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']); Response::json(Config::create($_POST['dbHost'], $_POST['dbUser'], $_POST['dbPassword'], $_POST['dbName'], $_POST['dbTablePrefix']));
} }

View File

@ -21,7 +21,7 @@ final class Album {
} }
/** /**
* @return integer|false ID of the created album. * @return string|false ID of the created album.
*/ */
public function add($title = 'Untitled') { public function add($title = 'Untitled') {

View File

@ -42,7 +42,7 @@ $config = "<?php
?>"; ?>";
// Save file // Save file
if (file_put_contents(LYCHEE_CONFIG_FILE, $config)===false) return 'Warning: Could not create file!'; if (@file_put_contents(LYCHEE_CONFIG_FILE, $config)===false) return 'Warning: Could not create file!';
return true; return true;

View File

@ -56,7 +56,7 @@ final class Database {
$connection = self::connect($host, $user, $password); $connection = self::connect($host, $user, $password);
// Check if the connection was successful // Check if the connection was successful
if ($connection===false) Response::error('' . $connection->connect_error); if ($connection===false) Response::error($connection->connect_error);
if (self::setCharset($connection)===false) Response::error('Could not set database charset!'); if (self::setCharset($connection)===false) Response::error('Could not set database charset!');
@ -81,7 +81,7 @@ final class Database {
public static function connect($host = 'localhost', $user, $password) { public static function connect($host = 'localhost', $user, $password) {
// Open a new connection to the MySQL server // Open a new connection to the MySQL server
$connection = new Mysqli($host, $user, $password); $connection = @new Mysqli($host, $user, $password);
// Check if the connection was successful // Check if the connection was successful
if ($connection->connect_errno) return false; if ($connection->connect_errno) return false;

View File

@ -39,7 +39,7 @@ final class Photo {
* Creats new photo(s). * Creats new photo(s).
* Exits on error. * Exits on error.
* Use $returnOnError if you want to handle errors by your own. * Use $returnOnError if you want to handle errors by your own.
* @return boolean Returns true when successful. * @return string|false ID of the added photo.
*/ */
public function add(array $files, $albumID = 0, $returnOnError = false) { public function add(array $files, $albumID = 0, $returnOnError = false) {
@ -251,7 +251,7 @@ final class Photo {
// Call plugins // Call plugins
Plugins::get()->activate(__METHOD__, 1, func_get_args()); Plugins::get()->activate(__METHOD__, 1, func_get_args());
return true; return $id;
} }

View File

@ -6,19 +6,19 @@ final class Response {
public static function warning($msg) { public static function warning($msg) {
exit('Warning: ' . $msg); exit(json_encode('Warning: ' . $msg));
} }
public static function error($msg) { public static function error($msg) {
exit('Error: ' . $msg); exit(json_encode('Error: ' . $msg));
} }
public static function json($str) { public static function json($str, $options = 0) {
exit(json_encode($str)); exit(json_encode($str, $options));
} }

View File

@ -14,6 +14,6 @@ $result = Database::execute($connection, $query, 'update_030100', __LINE__);
if ($result===false) Response::error('Could not adjust the length of the album id field!'); if ($result===false) Response::error('Could not adjust the length of the album id field!');
// Set version // Set version
// if (Database::setVersion($connection, '030100')===false) Response::error('Could not update version of database!'); if (Database::setVersion($connection, '030100')===false) Response::error('Could not update version of database!');
?> ?>

View File

@ -26,7 +26,7 @@ define('LYCHEE_URL_UPLOADS_BIG', 'uploads/big/');
define('LYCHEE_URL_UPLOADS_MEDIUM', 'uploads/medium/'); define('LYCHEE_URL_UPLOADS_MEDIUM', 'uploads/medium/');
define('LYCHEE_URL_UPLOADS_THUMB', 'uploads/thumb/'); define('LYCHEE_URL_UPLOADS_THUMB', 'uploads/thumb/');
function defineTablePrefix($dbTablePrefix = '') { function defineTablePrefix($dbTablePrefix) {
// This part is wrapped into a function, because it needs to be called // This part is wrapped into a function, because it needs to be called
// after the config-file has been loaded. Other defines are available // after the config-file has been loaded. Other defines are available
@ -34,6 +34,7 @@ function defineTablePrefix($dbTablePrefix = '') {
// Parse table prefix // Parse table prefix
// Old users do not have the table prefix stored in their config-file // Old users do not have the table prefix stored in their config-file
if (isset($dbTablePrefix)===false) $dbTablePrefix = '';
if ($dbTablePrefix!=='') $dbTablePrefix .= '_'; if ($dbTablePrefix!=='') $dbTablePrefix .= '_';
// Define tables // Define tables

View File

@ -1,5 +1,8 @@
<?php <?php
/**
* @return string Generated ID.
*/
function generateID() { function generateID() {
// Generate id based on the current microtime // Generate id based on the current microtime
@ -8,8 +11,9 @@ function generateID() {
// Ensure that the id has a length of 14 chars // Ensure that the id has a length of 14 chars
while(strlen($id)<14) $id .= 0; while(strlen($id)<14) $id .= 0;
// Return the integer value of the id // Return id as a string. Don't convert the id to an integer
return intval($id); // as 14 digits are too big for 32bit PHP versions.
return $id;
} }

View File

@ -28,6 +28,7 @@ paths.view = {
], ],
scripts: [ scripts: [
'node_modules/jquery/dist/jquery.min.js', 'node_modules/jquery/dist/jquery.min.js',
'node_modules/basiccontext/dist/basicContext.min.js',
'../dist/_view--javascript.js' '../dist/_view--javascript.js'
], ],
svg: [ svg: [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><title>Group</title><desc>Created with Sketch.</desc><g sketch:type="MSShapeGroup" fill="none"><path d="M0 0h16v16h-16v-16z" id="Shape" fill="#444"/><path id="Rectangle-path" stroke="#aaa" d="M4 4h5v5h-5z"/><path d="M6 6h8v7h-8v-7z" fill="#444"/><path stroke="#aaa" d="M7 7h5v5h-5z"/></g></svg> <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path d="M0 0h16v16h-16v-16z" fill="#444"/><path stroke="#aaa" d="M4 4h5v5h-5z"/><path d="M6 6h8v7h-8v-7z" fill="#444"/><path stroke="#aaa" d="M7 7h5v5h-5z"/></g></svg>

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 266 B

View File

@ -1 +1 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><title>Group</title><desc>Created with Sketch.</desc><g sketch:type="MSLayerGroup" fill="none"><path d="M0 0h200v200h-200v-200z" id="Shape" fill="#222" sketch:type="MSShapeGroup"/><g sketch:type="MSShapeGroup"><path id="Rectangle-path" stroke="#B4B4B4" stroke-width="4" d="M68 52h50v42h-50z"/><path d="M79 63h44v36h-44v-36z" fill="#222"/><path stroke="#B4B4B4" stroke-width="4" d="M88 72h50v42h-50z"/></g></g></svg> <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path d="M0 0h200v200h-200v-200z" fill="#222"/><g><path stroke="#B4B4B4" stroke-width="4" d="M68 52h50v42h-50z"/><path d="M79 63h44v36h-44v-36z" fill="#222"/><path stroke="#B4B4B4" stroke-width="4" d="M88 72h50v42h-50z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 557 B

After

Width:  |  Height:  |  Size: 337 B

View File

@ -1 +1 @@
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"><title>Group</title><desc>Created with Sketch.</desc><g sketch:type="MSLayerGroup" fill="none"><path d="M0 0h200v200h-200v-200z" id="Shape" fill="#222" sketch:type="MSShapeGroup"/><path d="M100.5 49c-10.45 0-19 8.614-19 19.143v9.571h-9.5v38.286h57v-38.286h-9.5v-9.571c0-10.529-8.55-19.143-19-19.143zm0 9.571c5.32 0 9.5 4.211 9.5 9.571v9.571h-19v-9.571c0-5.36 4.18-9.571 9.5-9.571z" fill="#B4B4B4" sketch:type="MSShapeGroup"/></g></svg> <svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path d="M0 0h200v200h-200v-200z" id="Shape" fill="#222"/><path d="M100.5 49c-10.45 0-19 8.614-19 19.143v9.571h-9.5v38.286h57v-38.286h-9.5v-9.571c0-10.529-8.55-19.143-19-19.143zm0 9.571c5.32 0 9.5 4.211 9.5 9.571v9.571h-19v-9.571c0-5.36 4.18-9.571 9.5-9.571z" fill="#B4B4B4"/></g></svg>

Before

Width:  |  Height:  |  Size: 577 B

After

Width:  |  Height:  |  Size: 388 B

View File

@ -32,6 +32,11 @@
"from": "ansi-styles@>=2.1.0 <3.0.0", "from": "ansi-styles@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz" "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz"
}, },
"any-promise": {
"version": "1.1.0",
"from": "any-promise@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.1.0.tgz"
},
"archy": { "archy": {
"version": "1.0.0", "version": "1.0.0",
"from": "archy@>=1.0.0 <2.0.0", "from": "archy@>=1.0.0 <2.0.0",
@ -42,6 +47,11 @@
"from": "are-we-there-yet@>=1.1.2 <1.2.0", "from": "are-we-there-yet@>=1.1.2 <1.2.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz" "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz"
}, },
"arr-flatten": {
"version": "1.0.1",
"from": "arr-flatten@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz"
},
"array-differ": { "array-differ": {
"version": "1.0.0", "version": "1.0.0",
"from": "array-differ@>=1.0.0 <2.0.0", "from": "array-differ@>=1.0.0 <2.0.0",
@ -67,6 +77,11 @@
"from": "array-uniq@>=1.0.2 <2.0.0", "from": "array-uniq@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz" "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
}, },
"arrify": {
"version": "1.0.1",
"from": "arrify@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
},
"asn1": { "asn1": {
"version": "0.2.3", "version": "0.2.3",
"from": "asn1@>=0.2.3 <0.3.0", "from": "asn1@>=0.2.3 <0.3.0",
@ -341,8 +356,8 @@
"from": "basiccontext@>=3.5.1 <4.0.0" "from": "basiccontext@>=3.5.1 <4.0.0"
}, },
"basicmodal": { "basicmodal": {
"version": "3.3.3", "version": "3.3.4",
"from": "basicmodal@>=3.3.3 <4.0.0" "from": "basicmodal@>=3.3.4 <4.0.0"
}, },
"beeper": { "beeper": {
"version": "1.1.0", "version": "1.1.0",
@ -751,6 +766,18 @@
"from": "get-stdin@>=4.0.1 <5.0.0", "from": "get-stdin@>=4.0.1 <5.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
}, },
"get-value": {
"version": "1.3.1",
"from": "get-value@>=1.1.5 <2.0.0",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-1.3.1.tgz",
"dependencies": {
"lazy-cache": {
"version": "0.2.7",
"from": "lazy-cache@>=0.2.4 <0.3.0",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz"
}
}
},
"glob": { "glob": {
"version": "5.0.15", "version": "5.0.15",
"from": "glob@>=5.0.0 <5.1.0", "from": "glob@>=5.0.0 <5.1.0",
@ -840,6 +867,18 @@
"from": "graceful-readlink@>=1.0.0", "from": "graceful-readlink@>=1.0.0",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
}, },
"group-array": {
"version": "0.3.0",
"from": "group-array@>=0.3.0 <0.4.0",
"resolved": "https://registry.npmjs.org/group-array/-/group-array-0.3.0.tgz",
"dependencies": {
"kind-of": {
"version": "2.0.1",
"from": "kind-of@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz"
}
}
},
"gulp": { "gulp": {
"version": "3.9.1", "version": "3.9.1",
"from": "gulp@>=3.9.1 <4.0.0", "from": "gulp@>=3.9.1 <4.0.0",
@ -880,9 +919,9 @@
} }
}, },
"gulp-inject": { "gulp-inject": {
"version": "3.0.0", "version": "4.0.0",
"from": "gulp-inject@>=3.0.0 <4.0.0", "from": "gulp-inject@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-3.0.0.tgz" "resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-4.0.0.tgz"
}, },
"gulp-load-plugins": { "gulp-load-plugins": {
"version": "1.2.0", "version": "1.2.0",
@ -1074,6 +1113,11 @@
"from": "is-builtin-module@>=1.0.0 <2.0.0", "from": "is-builtin-module@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz" "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz"
}, },
"is-extendable": {
"version": "0.1.1",
"from": "is-extendable@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
},
"is-finite": { "is-finite": {
"version": "1.0.1", "version": "1.0.1",
"from": "is-finite@>=1.0.0 <2.0.0", "from": "is-finite@>=1.0.0 <2.0.0",
@ -1140,9 +1184,9 @@
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
}, },
"jquery": { "jquery": {
"version": "2.2.1", "version": "2.2.3",
"from": "jquery@>=2.2.1 <3.0.0", "from": "jquery@>=2.2.3 <3.0.0",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.1.tgz" "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.3.tgz"
}, },
"js-base64": { "js-base64": {
"version": "2.1.9", "version": "2.1.9",
@ -1466,6 +1510,11 @@
"from": "node-uuid@>=1.4.7 <1.5.0", "from": "node-uuid@>=1.4.7 <1.5.0",
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
}, },
"noncharacters": {
"version": "1.1.0",
"from": "noncharacters@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/noncharacters/-/noncharacters-1.1.0.tgz"
},
"nopt": { "nopt": {
"version": "3.0.6", "version": "3.0.6",
"from": "nopt@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", "from": "nopt@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
@ -1856,6 +1905,11 @@
"from": "stream-consume@>=0.1.0 <0.2.0", "from": "stream-consume@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz" "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz"
}, },
"stream-to-array": {
"version": "2.3.0",
"from": "stream-to-array@>=2.3.0 <3.0.0",
"resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz"
},
"string_decoder": { "string_decoder": {
"version": "0.10.31", "version": "0.10.31",
"from": "string_decoder@>=0.10.0 <0.11.0", "from": "string_decoder@>=0.10.0 <0.11.0",

View File

@ -16,18 +16,18 @@
"dependencies": { "dependencies": {
"babel-preset-es2015": "^6.6.0", "babel-preset-es2015": "^6.6.0",
"basiccontext": "^3.5.1", "basiccontext": "^3.5.1",
"basicmodal": "^3.3.3", "basicmodal": "^3.3.4",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-autoprefixer": "3.1.0", "gulp-autoprefixer": "3.1.0",
"gulp-babel": "^6.1.2", "gulp-babel": "^6.1.2",
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.0",
"gulp-inject": "^3.0.0", "gulp-inject": "^4.0.0",
"gulp-load-plugins": "^1.2.0", "gulp-load-plugins": "^1.2.0",
"gulp-minify-css": "^1.2.4", "gulp-minify-css": "^1.2.4",
"gulp-rimraf": "^0.2.0", "gulp-rimraf": "^0.2.0",
"gulp-sass": "^2.2.0", "gulp-sass": "^2.2.0",
"gulp-uglify": "^1.5.3", "gulp-uglify": "^1.5.3",
"jquery": "^2.2.1", "jquery": "^2.2.3",
"mousetrap": "^1.5.3" "mousetrap": "^1.5.3"
} }
} }

View File

@ -116,9 +116,6 @@ album.add = function() {
api.post('Album::add', params, function(data) { api.post('Album::add', params, function(data) {
// Avoid first album to be true
if (data===true) data = 1
if (data!==false && isNumber(data)) { if (data!==false && isNumber(data)) {
albums.refresh() albums.refresh()
lychee.goto(data) lychee.goto(data)
@ -512,26 +509,20 @@ album.setPublic = function(albumID, modal, e) {
album.share = function(service) { album.share = function(service) {
let link = ''
let url = location.href let url = location.href
switch (service) { switch (service) {
case 'twitter': case 'twitter':
link = `https://twitter.com/share?url=${ encodeURI(url) }` window.open(`https://twitter.com/share?url=${ encodeURI(url) }`)
break break
case 'facebook': case 'facebook':
link = `http://www.facebook.com/sharer.php?u=${ encodeURI(url) }&t=${ encodeURI(album.json.title) }` window.open(`http://www.facebook.com/sharer.php?u=${ encodeURI(url) }&t=${ encodeURI(album.json.title) }`)
break break
case 'mail': case 'mail':
link = `mailto:?subject=${ encodeURI(album.json.title) }&body=${ encodeURI(url) }` location.href = `mailto:?subject=${ encodeURI(album.json.title) }&body=${ encodeURI(url) }`
break
default:
link = ''
break break
} }
if (link!=='') location.href = link
} }
album.getArchive = function(albumID) { album.getArchive = function(albumID) {

View File

@ -26,15 +26,6 @@ api.post = function(fn, params, callback) {
return false return false
} }
// Convert 1 to true and an empty string to false
if (data==='true') data = true
else if (data==='false') data = false
// Convert to JSON if string start with '{' and ends with '}'
if (typeof data==='string' && data.substring(0, 1)==='{' && data.substring(data.length - 1, data.length)==='}') {
data = $.parseJSON(data)
}
callback(data) callback(data)
} }
@ -49,7 +40,7 @@ api.post = function(fn, params, callback) {
type: 'POST', type: 'POST',
url: api.path, url: api.path,
data: params, data: params,
dataType: 'text', dataType: 'json',
success, success,
error error
}) })

View File

@ -304,10 +304,10 @@ contextMenu.sharePhoto = function(photoID, e) {
{ title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => photo.share(photoID, 'twitter') }, { title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => photo.share(photoID, 'twitter') },
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => photo.share(photoID, 'facebook') }, { title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => photo.share(photoID, 'facebook') },
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => photo.share(photoID, 'mail') }, { title: build.iconic('envelope-closed') + 'Mail', fn: () => photo.share(photoID, 'mail') },
{ title: build.iconic('dropbox', iconClass) + 'Dropbox', fn: () => photo.share(photoID, 'dropbox') }, { title: build.iconic('dropbox', iconClass) + 'Dropbox', visible: lychee.publicMode===false, fn: () => photo.share(photoID, 'dropbox') },
{ title: build.iconic('link-intact') + 'Direct Link', fn: () => window.open(photo.getDirectLink()) }, { title: build.iconic('link-intact') + 'Direct Link', fn: () => window.open(photo.getDirectLink()) },
{ }, { visible: lychee.publicMode===false },
{ title: build.iconic('ban') + 'Make Private', fn: () => photo.setPublic(photoID) } { title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => photo.setPublic(photoID) }
] ]
basicContext.show(items, e.originalEvent) basicContext.show(items, e.originalEvent)
@ -325,9 +325,9 @@ contextMenu.shareAlbum = function(albumID, e) {
{ title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => album.share('twitter') }, { title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => album.share('twitter') },
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => album.share('facebook') }, { title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => album.share('facebook') },
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => album.share('mail') }, { title: build.iconic('envelope-closed') + 'Mail', fn: () => album.share('mail') },
{ }, { visible: lychee.publicMode===false },
{ title: build.iconic('pencil') + 'Edit Sharing', fn: () => album.setPublic(albumID, true, e) }, { title: build.iconic('pencil') + 'Edit Sharing', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, true, e) },
{ title: build.iconic('ban') + 'Make Private', fn: () => album.setPublic(albumID, false) } { title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, false) }
] ]
basicContext.show(items, e.originalEvent) basicContext.show(items, e.originalEvent)

View File

@ -236,8 +236,14 @@ lychee.setTitle = function(title, editable) {
lychee.setMode = function(mode) { lychee.setMode = function(mode) {
$('#button_settings, #button_trash_album, #button_share_album, .button_add, .header__divider').remove() $('#button_settings, #button_trash_album, .button_add, .header__divider').remove()
$('#button_trash, #button_move, #button_share, #button_star').remove() $('#button_trash, #button_move, #button_star').remove()
$('#button_share, #button_share_album')
.removeClass('button--eye')
.addClass('button--share')
.find('use')
.attr('xlink:href', '#share')
$(document) $(document)
.off('click', '.header__title--editable') .off('click', '.header__title--editable')

View File

@ -610,18 +610,17 @@ photo.deleteTag = function(photoID, index) {
photo.share = function(photoID, service) { photo.share = function(photoID, service) {
let link = ''
let url = photo.getViewLink(photoID) let url = photo.getViewLink(photoID)
switch (service) { switch (service) {
case 'twitter': case 'twitter':
link = `https://twitter.com/share?url=${ encodeURI(url) }` window.open(`https://twitter.com/share?url=${ encodeURI(url) }`)
break break
case 'facebook': case 'facebook':
link = `http://www.facebook.com/sharer.php?u=${ encodeURI(url) }&t=${ encodeURI(photo.json.title) }` window.open(`http://www.facebook.com/sharer.php?u=${ encodeURI(url) }&t=${ encodeURI(photo.json.title) }`)
break break
case 'mail': case 'mail':
link = `mailto:?subject=${ encodeURI(photo.json.title) }&body=${ encodeURI(url) }` location.href = `mailto:?subject=${ encodeURI(photo.json.title) }&body=${ encodeURI(url) }`
break break
case 'dropbox': case 'dropbox':
lychee.loadDropbox(function() { lychee.loadDropbox(function() {
@ -629,13 +628,8 @@ photo.share = function(photoID, service) {
Dropbox.save(photo.getDirectLink(), filename) Dropbox.save(photo.getDirectLink(), filename)
}) })
break break
default:
link = ''
break
} }
if (link!=='') location.href = link
} }
photo.getArchive = function(photoID) { photo.getArchive = function(photoID) {

View File

@ -36,7 +36,7 @@ settings.createConfig = function() {
if (data!==true) { if (data!==true) {
// Connection failed // Connection failed
if (data.indexOf('Warning: Connection failed!')!==-1) { if (data==='Warning: Connection failed!') {
basicModal.show({ basicModal.show({
body: '<p>Unable to connect to host database because access was denied. Double-check your host, username and password and ensure that access from your current location is permitted.</p>', body: '<p>Unable to connect to host database because access was denied. Double-check your host, username and password and ensure that access from your current location is permitted.</p>',
@ -53,7 +53,7 @@ settings.createConfig = function() {
} }
// Creation failed // Creation failed
if (data.indexOf('Warning: Creation failed!')!==-1) { if (data==='Warning: Creation failed!') {
basicModal.show({ basicModal.show({
body: '<p>Unable to create the database. Double-check your host, username and password and ensure that the specified user has the rights to modify and add content to the database.</p>', body: '<p>Unable to create the database. Double-check your host, username and password and ensure that the specified user has the rights to modify and add content to the database.</p>',
@ -70,7 +70,7 @@ settings.createConfig = function() {
} }
// Could not create file // Could not create file
if (data.indexOf('Warning: Could not create file!')!==-1) { if (data==='Warning: Could not create file!') {
basicModal.show({ basicModal.show({
body: "<p>Unable to save this configuration. Permission denied in <b>'data/'</b>. Please set the read, write and execute rights for others in <b>'data/'</b> and <b>'uploads/'</b>. Take a look at the readme for more information.</p>", body: "<p>Unable to save this configuration. Permission denied in <b>'data/'</b>. Please set the read, write and execute rights for others in <b>'data/'</b> and <b>'uploads/'</b>. Take a look at the readme for more information.</p>",

View File

@ -93,13 +93,22 @@ upload.start = {
xhr.onload = function() { xhr.onload = function() {
let data = null
let wait = false let wait = false
let errorText = '' let errorText = ''
const isNumber = (n) => (!isNaN(parseFloat(n)) && isFinite(n))
try {
data = JSON.parse(xhr.responseText)
} catch(e) {
data = ''
}
file.ready = true file.ready = true
// Set status // Set status
if (xhr.status===200 && xhr.responseText==='true') { if (xhr.status===200 && isNumber(data)) {
// Success // Success
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status') $('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') .status')
@ -108,9 +117,9 @@ upload.start = {
} else { } else {
if (xhr.responseText.substr(0, 6)==='Error:') { if (data.substr(0, 6)==='Error:') {
errorText = xhr.responseText.substr(6) + ' Please take a look at the console of your browser for further details.' errorText = data.substr(6) + ' Please take a look at the console of your browser for further details.'
error = true error = true
// Error Status // Error Status
@ -118,9 +127,12 @@ upload.start = {
.html('Failed') .html('Failed')
.addClass('error') .addClass('error')
} else if (xhr.responseText.substr(0, 8)==='Warning:') { // Throw error
if (error===true) lychee.error('Upload failed. Server returned an error!', xhr, data)
errorText = xhr.responseText.substr(8) } else if (data.substr(0, 8)==='Warning:') {
errorText = data.substr(8)
warning = true warning = true
// Warning Status // Warning Status
@ -128,6 +140,9 @@ upload.start = {
.html('Skipped') .html('Skipped')
.addClass('warning') .addClass('warning')
// Throw error
if (error===true) lychee.error('Upload failed. Server returned a warning!', xhr, data)
} else { } else {
errorText = 'Server returned an unknown response. Please take a look at the console of your browser for further details.' errorText = 'Server returned an unknown response. Please take a look at the console of your browser for further details.'
@ -138,15 +153,15 @@ upload.start = {
.html('Failed') .html('Failed')
.addClass('error') .addClass('error')
// Throw error
if (error===true) lychee.error('Upload failed. Server returned an unkown error!', xhr, data)
} }
$('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') p.notice') $('.basicModal .rows .row:nth-child(' + (file.num + 1) + ') p.notice')
.html(errorText) .html(errorText)
.show() .show()
// Throw error
if (error===true) lychee.error('Upload failed. Server returned the status code ' + xhr.status + '!', xhr, xhr.responseText)
} }
// Check if there are file which are not finished // Check if there are file which are not finished
@ -206,8 +221,8 @@ upload.start = {
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
files[i].num = i files[i].num = i
files[i].ready = false files[i].ready = false
if (i < files.length-1) files[i].next = files[i + 1] if (i < files.length-1) files[i].next = files[i + 1]
else files[i].next = null else files[i].next = null
@ -242,7 +257,7 @@ upload.start = {
basicModal.close() basicModal.close()
files[0] = { files[0] = {
name : data.link name: data.link
} }
upload.show('Importing URL', files, function() { upload.show('Importing URL', files, function() {
@ -321,7 +336,7 @@ upload.start = {
let files = [] let files = []
files[0] = { files[0] = {
name : data.path name: data.path
} }
upload.show('Importing from server', files, function() { upload.show('Importing from server', files, function() {

View File

@ -3,21 +3,12 @@
* @copyright 2015 by Tobias Reich * @copyright 2015 by Tobias Reich
*/ */
// Sub-implementation of Lychee -------------------------------------------------------------- // // Sub-implementation of lychee -------------------------------------------------------------- //
let lychee = {} let lychee = {}
lychee.content = $('.content') lychee.content = $('.content')
lychee.getEventName = function() {
let touchendSupport = (/Android|iPhone|iPad|iPod/i).test(navigator.userAgent || navigator.vendor || window.opera) && ('ontouchend' in document.documentElement)
let eventName = (touchendSupport===true ? 'touchend' : 'click')
return eventName
}
lychee.escapeHTML = function(html = '') { lychee.escapeHTML = function(html = '') {
// Ensure that html is a string // Ensure that html is a string
@ -69,31 +60,76 @@ lychee.html = function(literalSections, ...substs) {
} }
// Sub-implementation of photo -------------------------------------------------------------- //
let photo = {}
photo.share = function(photoID, service) {
let url = location.toString()
switch (service) {
case 'twitter':
window.open(`https://twitter.com/share?url=${ encodeURI(url) }`)
break
case 'facebook':
window.open(`http://www.facebook.com/sharer.php?u=${ encodeURI(url) }`)
break
case 'mail':
location.href = `mailto:?subject=&body=${ encodeURI(url) }`
break
}
}
photo.getDirectLink = function() {
return $('#imageview img').attr('src').replace(/"/g,'').replace(/url\(|\)$/ig, '')
}
// Sub-implementation of contextMenu -------------------------------------------------------------- //
let contextMenu = {}
contextMenu.sharePhoto = function(photoID, e) {
let iconClass = 'ionicons'
let items = [
{ title: build.iconic('twitter', iconClass) + 'Twitter', fn: () => photo.share(photoID, 'twitter') },
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => photo.share(photoID, 'facebook') },
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => photo.share(photoID, 'mail') },
{ title: build.iconic('link-intact') + 'Direct Link', fn: () => window.open(photo.getDirectLink(), '_newtab') }
]
basicContext.show(items, e.originalEvent)
}
// Main -------------------------------------------------------------- // // Main -------------------------------------------------------------- //
let loadingBar = { show() {}, hide() {} }, let loadingBar = { show() {}, hide() {} }
imageview = $('#imageview') let imageview = $('#imageview')
$(document).ready(function() { $(document).ready(function() {
// Event Name // Save ID of photo
let eventName = lychee.getEventName() let photoID = gup('p')
// Set API error handler // Set API error handler
api.onError = error api.onError = error
// Infobox // Share
header.dom('#button_info').on(eventName, sidebar.toggle) header.dom('#button_share').on('click', function(e) {
contextMenu.sharePhoto(photoID, e)
// Direct Link
header.dom('#button_direct').on(eventName, function() {
let link = $('#imageview img').attr('src').replace(/"/g,'').replace(/url\(|\)$/ig, '')
window.open(link, '_newtab')
}) })
loadPhotoInfo(gup('p')) // Infobox
header.dom('#button_info').on('click', sidebar.toggle)
// Load photo
loadPhotoInfo(photoID)
}) })

View File

@ -12,7 +12,6 @@
&__item { &__item {
margin-bottom: 2px; margin-bottom: 2px;
font-size: 14px; font-size: 14px;
text-shadow: $shadowLight;
&--separator { &--separator {
margin: 4px 0; margin: 4px 0;

View File

@ -57,10 +57,10 @@
width: 200px; width: 200px;
height: 200px; height: 200px;
background: #222; background: #222;
color: #222;
box-shadow: 0 2px 5px black(.5); box-shadow: 0 2px 5px black(.5);
border: 1px solid white(.5); border: 1px solid white(.5);
transition: opacity .3s ease-out, transform .3s ease-out, border-color .3s ease-out; transition: opacity .3s ease-out, transform .3s ease-out, border-color .3s ease-out;
will-change: transform;
} }
&:hover img, &:hover img,
@ -146,7 +146,6 @@
margin: 0 5px 0 0; margin: 0 5px 0 0;
width: 8px; width: 8px;
height: 8px; height: 8px;
filter: drop-shadow(0 1px 3px black(.4));
} }
.album img[data-overlay='false'] + .overlay h1, .album img[data-overlay='false'] + .overlay h1,
@ -185,7 +184,6 @@
fill: #fff; fill: #fff;
width: 16px; width: 16px;
height: 16px; height: 16px;
filter: drop-shadow($shadowLight);
} }
} }
@ -225,7 +223,6 @@
left: 50%; left: 50%;
padding-top: 20px; padding-top: 20px;
color: white(.35); color: white(.35);
text-shadow: 0 -1px 0 black(.4);
text-align: center; text-align: center;
transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%);
@ -234,7 +231,6 @@
margin: 0 0 10px; margin: 0 0 10px;
width: 50px; width: 50px;
height: 50px; height: 50px;
filter: drop-shadow(0 -1px 0 black(.4));
} }
p { p {

View File

@ -95,6 +95,8 @@
&--eye.active .iconic { fill: #ff9737; } &--eye.active .iconic { fill: #ff9737; }
&--share .iconic { height: 18px; }
&--info.active .iconic { fill: $colorBlue; } &--info.active .iconic { fill: $colorBlue; }
} }

View File

@ -27,7 +27,6 @@
width: auto; width: auto;
height: auto; height: auto;
transition: top .3s, right .3s, bottom .3s, left .3s, max-width .3s, max-height .3s; transition: top .3s, right .3s, bottom .3s, left .3s, max-width .3s, max-height .3s;
will-change: transform;
animation-name: zoomIn; animation-name: zoomIn;
animation-duration: .3s; animation-duration: .3s;
@ -105,7 +104,6 @@
.iconic { .iconic {
fill: white(.8); fill: white(.8);
filter: drop-shadow(0 1px 0 black(.4));
} }
} }

View File

@ -26,7 +26,6 @@
color: white(.9); color: white(.9);
font-size: 14px; font-size: 14px;
text-align: left; text-align: left;
text-shadow: $shadow;
line-height: 20px; line-height: 20px;
b { b {
@ -56,7 +55,6 @@
padding: 13px 0 15px; padding: 13px 0 15px;
background: black(.02); background: black(.02);
color: white(.5); color: white(.5);
text-shadow: $shadow;
border-top: 1px solid black(.2); border-top: 1px solid black(.2);
box-shadow: inset 0 1px 0 white(.02); box-shadow: inset 0 1px 0 white(.02);
cursor: default; cursor: default;
@ -85,7 +83,6 @@
width: 100%; width: 100%;
background-color: transparent; background-color: transparent;
color: #fff; color: #fff;
text-shadow: $shadow;
border: none; border: none;
// Do not use rgba() for border-bottom // Do not use rgba() for border-bottom
// to avoid a blurry line in Safari on non-retina screens // to avoid a blurry line in Safari on non-retina screens
@ -116,7 +113,6 @@
color: white(1); color: white(1);
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
text-shadow: $shadow;
} }
label input { label input {
@ -258,7 +254,6 @@
color: #fff; color: #fff;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
text-shadow: $shadow;
text-align: center; text-align: center;
} }

View File

@ -92,6 +92,7 @@
table { table {
float: left; float: left;
margin: 10px 0 15px 20px; margin: 10px 0 15px 20px;
width: calc(100% - 20px);
} }
table tr td { table tr td {

View File

@ -12,8 +12,7 @@
} }
// Properties -------------------------------------------------------------- // // Properties -------------------------------------------------------------- //
$shadowLight : 0 -1px 0 black(.1); $shadow: 0 -1px 0 black(.2);
$shadow : 0 -1px 0 black(.2);
// Colors ------------------------------------------------------------------ // // Colors ------------------------------------------------------------------ //
$colorBlue : #2293EC; $colorBlue : #2293EC;

View File

@ -48,12 +48,12 @@
<a class="header__title"></a> <a class="header__title"></a>
<a class="button button--share" id="button_share" title="Share Photo">
<svg class="iconic"><use xlink:href="#share"></use></svg>
</a>
<a class="button button--info" id="button_info" title="About Photo"> <a class="button button--info" id="button_info" title="About Photo">
<svg class="iconic"><use xlink:href="#info"></use></svg> <svg class="iconic"><use xlink:href="#info"></use></svg>
</a> </a>
<a class="button" id="button_direct" title="Direct Link">
<svg class="iconic"><use xlink:href="#link-intact"></use></svg>
</a>
</div> </div>