Merge pull request #534 from electerious/develop

Lychee 3.1.1
pull/558/head v3.1.1
Tobias Reich 8 years ago
commit 75b11acab3

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

8
dist/view.js vendored

File diff suppressed because one or more lines are too long

@ -1,3 +1,17 @@
## v3.1.1
Released April 30, 2016
- `New` share button when logged out (#473)
- `New` Import of IPTC photo tags (Thanks @qligier, #514)
- `New` Added reset username and password to FAQ (#500 #128)
- `Improved` Removed will-change from the main image to improve the image rendering in Chrome (#501)
- `Improved ` scroll and rendering performance by removing will-change
- `Improved` Open Facebook and Twitter sharing sheet in new window
- `Improved` EXIF and IPTC extraction (Thanks @qligier, #518)
- `Fixed` broken URL in Update.md (#516)
- `Fixed` error 500 on database connect error (Thanks @tribut, #530)
## v3.1.0
Released March 29, 2016

@ -2,10 +2,10 @@
If Lychee is not working properly, try to open `plugins/Diagnostics/index.php`. This script will display all errors it can find.
#### What do I need to run Lychee on my server?
To run Lychee, everything you need is a web-server with PHP 5.3 or later and a MySQL-Database.
To run Lychee, everything you need is a web-server with PHP 5.5 or later and a MySQL-Database.
#### I can't upload photos
If you experience problems uploading large photos, you might want to change the PHP parameters in `.htaccess` (if you are using the PHP Apache module) or in `.user.ini` (if you are using PHP >= 5.3 with CGI or FastCGI).
If you experience problems uploading large photos, you might want to change the PHP parameters in `.htaccess` (if you are using the PHP Apache module) or in `.user.ini` (if you are using PHP >= 5.5 with CGI or FastCGI).
If possible, change these settings directly in your `php.ini`. We recommend to increase the values of the following properties:
@ -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)
#### 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.

@ -11,7 +11,7 @@ Updating Lychee with `git` is the easiest way:
### Update manually
1. Download the [newest Version](https://github.com/electerious/Lychee/release)
1. Download the [newest Version](https://github.com/electerious/Lychee/releases)
2. Replace all existing files, excluding `uploads/` and `data/`
3. Open Lychee (and enter your database details)

@ -56,7 +56,7 @@ final class Database {
$connection = self::connect($host, $user, $password);
// Check if the connection was successful
if ($connection===false) Response::error($connection->connect_error);
if ($connection===false) Response::error(self::connect_error());
if (self::setCharset($connection)===false) Response::error('Could not set database charset!');
@ -90,6 +90,15 @@ final class Database {
}
/**
* @return string Returns the string description of the last connect error
*/
private static function connect_error() {
return mysqli_connect_error();
}
/**
* @return boolean Returns true when successful.
*/

@ -239,7 +239,7 @@ final class Photo {
}
// Save to DB
$values = array(LYCHEE_TABLE_PHOTOS, $id, $info['title'], $photo_name, $info['description'], '', $info['type'], $info['width'], $info['height'], $info['size'], $info['iso'], $info['aperture'], $info['make'], $info['model'], $info['shutter'], $info['focal'], $info['takestamp'], $path_thumb, $albumID, $public, $star, $checksum, $medium);
$values = array(LYCHEE_TABLE_PHOTOS, $id, $info['title'], $photo_name, $info['description'], $info['tags'], $info['type'], $info['width'], $info['height'], $info['size'], $info['iso'], $info['aperture'], $info['make'], $info['model'], $info['shutter'], $info['focal'], $info['takestamp'], $path_thumb, $albumID, $public, $star, $checksum, $medium);
$query = Database::prepare(Database::get(), "INSERT INTO ? (id, title, url, description, tags, type, width, height, size, iso, aperture, make, model, shutter, focal, takestamp, thumbUrl, album, public, star, checksum, medium) VALUES ('?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?')", $values);
$result = Database::execute(Database::get(), $query, __METHOD__, __LINE__);
@ -307,7 +307,7 @@ final class Photo {
$newUrl2x = LYCHEE_UPLOADS_THUMB . $photoName[0] . '@2x.jpeg';
// Create thumbnails with Imagick
if(extension_loaded('imagick')&&Settings::get()['imagick']==='1') {
if(Settings::hasImagick()) {
// Read image
$thumb = new Imagick();
@ -727,86 +727,108 @@ final class Photo {
$info = getimagesize($url, $iptcArray);
// General information
$return['type'] = $info['mime'];
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['type'] = $info['mime'];
$return['width'] = $info[0];
$return['height'] = $info[1];
$return['title'] = '';
$return['description'] = '';
$return['orientation'] = '';
$return['iso'] = '';
$return['aperture'] = '';
$return['make'] = '';
$return['model'] = '';
$return['shutter'] = '';
$return['focal'] = '';
$return['takestamp'] = 0;
$return['lens'] = '';
$return['tags'] = '';
$return['position'] = '';
$return['latitude'] = '';
$return['longitude'] = '';
$return['altitude'] = '';
// Size
$size = filesize($url)/1024;
if ($size>=1024) $return['size'] = round($size/1024, 1) . ' MB';
else $return['size'] = round($size, 1) . ' KB';
// IPTC Metadata Fallback
$return['title'] = '';
$return['description'] = '';
// IPTC Metadata
// See https://www.iptc.org/std/IIM/4.2/specification/IIMV4.2.pdf for mapping
if(isset($iptcArray['APP13'])) {
$iptcInfo = iptcparse($iptcArray['APP13']);
if (is_array($iptcInfo)) {
$temp = @$iptcInfo['2#105'][0];
if (isset($temp)&&strlen($temp)>0) $return['title'] = $temp;
// Title
if (!empty($iptcInfo['2#105'][0])) $return['title'] = $iptcInfo['2#105'][0];
else if (!empty($iptcInfo['2#005'][0])) $return['title'] = $iptcInfo['2#005'][0];
$temp = @$iptcInfo['2#120'][0];
if (isset($temp)&&strlen($temp)>0) $return['description'] = $temp;
// Description
if (!empty($iptcInfo['2#120'][0])) $return['description'] = $iptcInfo['2#120'][0];
$temp = @$iptcInfo['2#005'][0];
if (isset($temp)&&strlen($temp)>0&&$return['title']==='') $return['title'] = $temp;
// Tags
if (!empty($iptcInfo['2#025'])) $return['tags'] = implode(',', $iptcInfo['2#025']);
// Position
$fields = array();
if (!empty($iptcInfo['2#090'])) $fields[] = trim($iptcInfo['2#090'][0]);
if (!empty($iptcInfo['2#092'])) $fields[] = trim($iptcInfo['2#092'][0]);
if (!empty($iptcInfo['2#095'])) $fields[] = trim($iptcInfo['2#095'][0]);
if (!empty($iptcInfo['2#101'])) $fields[] = trim($iptcInfo['2#101'][0]);
if (!empty($fields)) $return['position'] = implode(', ', $fields);
}
}
// EXIF Metadata Fallback
$return['orientation'] = '';
$return['iso'] = '';
$return['aperture'] = '';
$return['make'] = '';
$return['model'] = '';
$return['shutter'] = '';
$return['focal'] = '';
$return['takestamp'] = 0;
// Read EXIF
if ($info['mime']=='image/jpeg') $exif = @exif_read_data($url, 'EXIF', 0);
if ($info['mime']=='image/jpeg') $exif = @exif_read_data($url, 'EXIF', false, false);
else $exif = false;
// EXIF Metadata
if ($exif!==false) {
// Orientation
if (isset($exif['Orientation'])) $return['orientation'] = $exif['Orientation'];
else if (isset($exif['IFD0']['Orientation'])) $return['orientation'] = $exif['IFD0']['Orientation'];
$temp = @$exif['ISOSpeedRatings'];
if (isset($temp)) $return['iso'] = $temp;
// ISO
if (!empty($exif['ISOSpeedRatings'])) $return['iso'] = $exif['ISOSpeedRatings'];
$temp = @$exif['COMPUTED']['ApertureFNumber'];
if (isset($temp)) $return['aperture'] = $temp;
// Aperture
if (!empty($exif['COMPUTED']['ApertureFNumber'])) $return['aperture'] = $exif['COMPUTED']['ApertureFNumber'];
$temp = @$exif['Make'];
if (isset($temp)) $return['make'] = trim($temp);
// Make
if (!empty($exif['Make'])) $return['make'] = trim($exif['Make']);
$temp = @$exif['Model'];
if (isset($temp)) $return['model'] = trim($temp);
// Model
if (!empty($exif['Model'])) $return['model'] = trim($exif['Model']);
$temp = @$exif['ExposureTime'];
if (isset($temp)) $return['shutter'] = $exif['ExposureTime'] . ' s';
// Exposure
if (!empty($exif['ExposureTime'])) $return['shutter'] = $exif['ExposureTime'] . ' s';
$temp = @$exif['FocalLength'];
if (isset($temp)) {
if (strpos($temp, '/')!==FALSE) {
$temp = explode('/', $temp, 2);
// Focal Length
if (!empty($exif['FocalLength'])) {
if (strpos($exif['FocalLength'], '/')!==false) {
$temp = explode('/', $exif['FocalLength'], 2);
$temp = $temp[0] / $temp[1];
$temp = round($temp, 1);
$return['focal'] = $temp . ' mm';
} else {
$return['focal'] = $exif['FocalLength'] . ' mm';
}
$return['focal'] = $temp . ' mm';
}
$temp = @$exif['DateTimeOriginal'];
if (isset($temp)) $return['takestamp'] = strtotime($temp);
// Takestamp
if (!empty($exif['DateTimeOriginal'])) $return['takestamp'] = strtotime($exif['DateTimeOriginal']);
// Lens field from Lightroom
if (!empty($exif['UndefinedTag:0xA434'])) $return['lens'] = trim($exif['UndefinedTag:0xA434']);
// Deal with GPS coordinates
if (!empty($exif['GPSLatitude']) && !empty($exif['GPSLatitudeRef'])) $return['latitude'] = getGPSCoordinate($exif['GPSLatitude'], $exif['GPSLatitudeRef']);
if (!empty($exif['GPSLongitude']) && !empty($exif['GPSLongitudeRef'])) $return['longitude'] = getGPSCoordinate($exif['GPSLongitude'], $exif['GPSLongitudeRef']);
}

@ -221,6 +221,13 @@ final class Settings {
}
/**
* @return array Returns the Imagick setting.
*/
public static function hasImagick() {
return (bool)(extension_loaded('imagick') && self::get()['imagick'] === '1');
}
}
?>

@ -0,0 +1,30 @@
<?php
/**
* Returns the normalized coordinate from EXIF array.
* @return string Normalized coordinate as float number (degrees).
*/
function getGPSCoordinate($coordinate, $ref) {
$degrees = count($coordinate) > 0 ? formattedToFloatGPS($coordinate[0]) : 0;
$minutes = count($coordinate) > 1 ? formattedToFloatGPS($coordinate[1]) : 0;
$seconds = count($coordinate) > 2 ? formattedToFloatGPS($coordinate[2]) : 0;
$flip = ($ref == 'W' || $ref == 'S') ? -1 : 1;
return $flip * ($degrees + (float)$minutes / 60 + (float)$seconds / 3600);
}
function formattedToFloatGPS($coordinate) {
$parts = explode('/', $coordinate, 2);
if (count($parts) <= 0) return 0;
if (count($parts) == 1) return $parts[0];
return (float)$parts[0] / $parts[1];
}
?>

@ -22,6 +22,7 @@ require(__DIR__ . '/autoload.php');
require(__DIR__ . '/helpers/fastImageCopyResampled.php');
require(__DIR__ . '/helpers/generateID.php');
require(__DIR__ . '/helpers/getExtension.php');
require(__DIR__ . '/helpers/getGPSCoordinate.php');
require(__DIR__ . '/helpers/getGraphHeader.php');
require(__DIR__ . '/helpers/getHashedString.php');
require(__DIR__ . '/helpers/hasPermissions.php');

@ -28,6 +28,7 @@ paths.view = {
],
scripts: [
'node_modules/jquery/dist/jquery.min.js',
'node_modules/basiccontext/dist/basicContext.min.js',
'../dist/_view--javascript.js'
],
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

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

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

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

@ -32,6 +32,11 @@
"from": "ansi-styles@>=2.1.0 <3.0.0",
"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": {
"version": "1.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",
"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": {
"version": "1.0.0",
"from": "array-differ@>=1.0.0 <2.0.0",
@ -67,6 +77,11 @@
"from": "array-uniq@>=1.0.2 <2.0.0",
"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": {
"version": "0.2.3",
"from": "asn1@>=0.2.3 <0.3.0",
@ -341,8 +356,8 @@
"from": "basiccontext@>=3.5.1 <4.0.0"
},
"basicmodal": {
"version": "3.3.3",
"from": "basicmodal@>=3.3.3 <4.0.0"
"version": "3.3.4",
"from": "basicmodal@>=3.3.4 <4.0.0"
},
"beeper": {
"version": "1.1.0",
@ -751,6 +766,18 @@
"from": "get-stdin@>=4.0.1 <5.0.0",
"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": {
"version": "5.0.15",
"from": "glob@>=5.0.0 <5.1.0",
@ -840,6 +867,18 @@
"from": "graceful-readlink@>=1.0.0",
"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": {
"version": "3.9.1",
"from": "gulp@>=3.9.1 <4.0.0",
@ -880,9 +919,9 @@
}
},
"gulp-inject": {
"version": "3.0.0",
"from": "gulp-inject@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-3.0.0.tgz"
"version": "4.0.0",
"from": "gulp-inject@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-4.0.0.tgz"
},
"gulp-load-plugins": {
"version": "1.2.0",
@ -1074,6 +1113,11 @@
"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"
},
"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": {
"version": "1.0.1",
"from": "is-finite@>=1.0.0 <2.0.0",
@ -1140,9 +1184,9 @@
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
},
"jquery": {
"version": "2.2.1",
"from": "jquery@>=2.2.1 <3.0.0",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.1.tgz"
"version": "2.2.3",
"from": "jquery@>=2.2.3 <3.0.0",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.3.tgz"
},
"js-base64": {
"version": "2.1.9",
@ -1466,6 +1510,11 @@
"from": "node-uuid@>=1.4.7 <1.5.0",
"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": {
"version": "3.0.6",
"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",
"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": {
"version": "0.10.31",
"from": "string_decoder@>=0.10.0 <0.11.0",

@ -1,6 +1,6 @@
{
"name": "Lychee",
"version": "3.1.0",
"version": "3.1.1",
"description": "Self-hosted photo-management done right.",
"authors": "Tobias Reich <tobias@electerious.com>",
"license": "MIT",
@ -16,18 +16,18 @@
"dependencies": {
"babel-preset-es2015": "^6.6.0",
"basiccontext": "^3.5.1",
"basicmodal": "^3.3.3",
"basicmodal": "^3.3.5",
"gulp": "^3.9.1",
"gulp-autoprefixer": "3.1.0",
"gulp-babel": "^6.1.2",
"gulp-concat": "^2.6.0",
"gulp-inject": "^3.0.0",
"gulp-load-plugins": "^1.2.0",
"gulp-inject": "^4.0.0",
"gulp-load-plugins": "^1.2.2",
"gulp-minify-css": "^1.2.4",
"gulp-rimraf": "^0.2.0",
"gulp-sass": "^2.2.0",
"gulp-sass": "^2.3.1",
"gulp-uglify": "^1.5.3",
"jquery": "^2.2.1",
"jquery": "^2.2.3",
"mousetrap": "^1.5.3"
}
}

@ -509,26 +509,20 @@ album.setPublic = function(albumID, modal, e) {
album.share = function(service) {
let link = ''
let url = location.href
switch (service) {
case 'twitter':
link = `https://twitter.com/share?url=${ encodeURI(url) }`
window.open(`https://twitter.com/share?url=${ encodeURI(url) }`)
break
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
case 'mail':
link = `mailto:?subject=${ encodeURI(album.json.title) }&body=${ encodeURI(url) }`
break
default:
link = ''
location.href = `mailto:?subject=${ encodeURI(album.json.title) }&body=${ encodeURI(url) }`
break
}
if (link!=='') location.href = link
}
album.getArchive = function(albumID) {

@ -304,12 +304,14 @@ contextMenu.sharePhoto = function(photoID, e) {
{ 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('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('ban') + 'Make Private', fn: () => photo.setPublic(photoID) }
{ title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => photo.setPublic(photoID) }
]
if (lychee.publicMode===true) items.splice(7, 1)
basicContext.show(items, e.originalEvent)
$('.basicContext input#link').focus().select()
@ -326,10 +328,12 @@ contextMenu.shareAlbum = function(albumID, e) {
{ title: build.iconic('facebook', iconClass) + 'Facebook', fn: () => album.share('facebook') },
{ title: build.iconic('envelope-closed') + 'Mail', fn: () => album.share('mail') },
{ },
{ title: build.iconic('pencil') + 'Edit Sharing', fn: () => album.setPublic(albumID, true, e) },
{ title: build.iconic('ban') + 'Make Private', fn: () => album.setPublic(albumID, false) }
{ title: build.iconic('pencil') + 'Edit Sharing', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, true, e) },
{ title: build.iconic('ban') + 'Make Private', visible: lychee.publicMode===false, fn: () => album.setPublic(albumID, false) }
]
if (lychee.publicMode===true) items.splice(5, 1)
basicContext.show(items, e.originalEvent)
$('.basicContext input#link').focus().select()

@ -6,8 +6,8 @@
lychee = {
title : document.title,
version : '3.1.0',
versionCode : '030100',
version : '3.1.1',
versionCode : '030101',
updatePath : '//update.electerious.com/index.json',
updateURL : 'https://github.com/electerious/Lychee',
@ -236,8 +236,14 @@ lychee.setTitle = function(title, editable) {
lychee.setMode = function(mode) {
$('#button_settings, #button_trash_album, #button_share_album, .button_add, .header__divider').remove()
$('#button_trash, #button_move, #button_share, #button_star').remove()
$('#button_settings, #button_trash_album, .button_add, .header__divider').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)
.off('click', '.header__title--editable')

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

@ -3,21 +3,12 @@
* @copyright 2015 by Tobias Reich
*/
// Sub-implementation of Lychee -------------------------------------------------------------- //
// Sub-implementation of lychee -------------------------------------------------------------- //
let lychee = {}
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 = '') {
// Ensure that html is a string
@ -69,31 +60,85 @@ lychee.html = function(literalSections, ...substs) {
}
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
}
// 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 -------------------------------------------------------------- //
let loadingBar = { show() {}, hide() {} },
imageview = $('#imageview')
let loadingBar = { show() {}, hide() {} }
let imageview = $('#imageview')
$(document).ready(function() {
// Event Name
let eventName = lychee.getEventName()
// Save ID of photo
let photoID = gup('p')
// Set API error handler
api.onError = error
// Infobox
header.dom('#button_info').on(eventName, sidebar.toggle)
// Direct Link
header.dom('#button_direct').on(eventName, function() {
let link = $('#imageview img').attr('src').replace(/"/g,'').replace(/url\(|\)$/ig, '')
window.open(link, '_newtab')
// Share
header.dom('#button_share').on('click', function(e) {
contextMenu.sharePhoto(photoID, e)
})
loadPhotoInfo(gup('p'))
// Infobox
header.dom('#button_info').on('click', sidebar.toggle)
// Load photo
loadPhotoInfo(photoID)
})

@ -57,10 +57,10 @@
width: 200px;
height: 200px;
background: #222;
color: #222;
box-shadow: 0 2px 5px black(.5);
border: 1px solid white(.5);
transition: opacity .3s ease-out, transform .3s ease-out, border-color .3s ease-out;
will-change: transform;
}
&:hover img,

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

@ -27,7 +27,6 @@
width: auto;
height: auto;
transition: top .3s, right .3s, bottom .3s, left .3s, max-width .3s, max-height .3s;
will-change: transform;
animation-name: zoomIn;
animation-duration: .3s;

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

@ -48,12 +48,12 @@
<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">
<svg class="iconic"><use xlink:href="#info"></use></svg>
</a>
<a class="button" id="button_direct" title="Direct Link">
<svg class="iconic"><use xlink:href="#link-intact"></use></svg>
</a>
</div>

Loading…
Cancel
Save