ketr.photos/frontend/elements/photo-lightbox.html
2018-10-23 18:56:21 -07:00

367 lines
8.0 KiB
HTML

<!doctype html>
<html>
<head>
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/iron-iconset/iron-iconset.html">
<link rel="import" href="../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="../bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
</head>
<dom-module id="photo-lightbox">
<template>
<style is="custom-style" include="iron-flex iron-flex-alignment iron-positioning">
:host {
display: none;
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
transition: opacity 0.5s ease-in-out;
-webkit-transition: opacity 0.5s ease-in-out;
box-sizing: border-box;
pointer-events: all;
}
#image {
display: inline-block;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
transition: opacity 0.5s ease-in-out;
-webkit-transition: opacity 0.5s ease-in-out;
}
#image paper-icon-button {
color: white;
}
#overlay {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
pointer-events: none;
}
#overlay > div {
height: 100%;
}
#info {
color: white;
position: absolute;
padding: 0.5em;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
bottom: 0px;
left: 0px;
right: 0px;
font-size: 0.6em;
pointer-events: none;
transition: opacity 0.5s ease-in-out;
}
#actions {
display: flex;
padding: 0.5em;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
font-size: 0.6em;
color: #ddd;
pointer-events: none;
transition: opacity 0.5s ease-in-out;
}
:host([active]) #info,
:host([active]) #actions {
opacity: 1;
pointer-events: all;
}
</style>
<div id="image" class="layout vertical" on-tap="onTap">
<div id="actions" on-tap="_hideActions" class="flex horziontal layout center end-justified">
<paper-icon-button on-tap="download" class="start-end" icon="file-download"></paper-icon-button>
<template is="dom-repeat" items="[[actions]]">
<paper-icon-button on-tap="_fireAction" icon="[[item]]"></paper-icon-button>
</template>
</div>
<div id="info" on-tap="_hideActions" class="layout vertical start">
<div>[[item.name]] ([[item.id]])</div>
<div>[[item.taken]]</div>
<div on-tap="_pathTap">[[item.path]]</div>
</div>
</div>
<div id="overlay" class="layout vertical center">
<div class="layout horizontal center">
<paper-spinner hidden$="[[!loading]]" active$="[[loading]]" class="thin"></paper-spinner>
</div>
</div>
</template>
<script>
"use strict";
Polymer({
is: "photo-lightbox",
properties: {
"active": {
type: Boolean,
reflectToAttribute: true,
value: false
},
"src": {
type: String,
value: ""
},
"thumb": {
type: String
},
"loading": {
type: Boolean,
value: false
},
"unique": {
type: String,
value: ""
}
},
observers: [
"srcChanged(src, unique)"
],
listeners: {
"keydown": "onKeyDown",
"blur": "onBlur",
"focus": "onFocus",
"scroll": "onScroll"
},
onScroll: function(event) {
console.log("Scroll attempt in lightbox");
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
},
onFocus: function() {
this.hasFocus = true;
},
onBlur: function() {
this.hasFocus = false;
},
delete: function() {
this.fire("action", "delete");
},
next: function() {
this.fire("next");
},
previous: function() {
this.fire("previous");
},
onKeyDown: function(e) {
if (!this.active) {
return;
}
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) {
return;
}
if (this.hasFocus) {
e.preventDefault();
e.stopPropagation();
}
switch (e.keyCode) {
case 46: /* delete */
if (this.hasFocus) {
this.delete();
}
break;
case 39: /* right */
if (this.hasFocus) {
this.next();
}
break;
case 37: /* left */
if (this.hasFocus) {
this.previous();
}
break;
case 27: /* escape */
this.hasFocus = false;
this.close();
break;
default:
console.log(e.keyCode);
break;
}
},
reload: function() {
this.unique = parseInt(this.unique || 0) + 1;
},
_fireAction: function(event) {
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
this.fire("action", event.model.item);
},
download: function(event) {
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
console.log("Download tapped");
var anchor = document.createElement('a');
anchor.href = this.base + this.item.path + this.item.filename;
anchor.setAttribute("download", this.src.replace(/.*\/([^/]+)$/, "$1"));
anchor.style.display = "none";
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
},
close: function() {
if (this.closed) {
return;
}
this.style.opacity = 0;
this.async(function() {
this.setActive(false);
this.style.display = 'none';
this.image = undefined;
this.$.image.style.opacity = 0;
this.$.image.style.removeProperty('background-image');
this.closed = true;
this.opened = false;
this.fire("close");
}, 250);
},
srcChanged: function(src) {
if (!src) {
return;
}
this.loadImage(src);
},
onTap: function(event) {
if (!this.style.display || this.style.display == "none") {
return;
}
if ((event.detail.y < this.$.actions.offsetHeight) ||
(event.detail.y > this.offsetHeight - this.$.info.offsetHeight)) {
this.setActive(true);
return;
}
if (event.detail.x <= 0.1 * this.offsetWidth) {
this.previous();
return;
}
if (event.detail.x >= 0.9 * this.offsetWidth) {
this.next();
return;
}
this.close();
},
open: function() {
this.setActive(true);
this.closed = false;
this.opened = true;
this.loadImage(this.src);
this.style.opacity = 1;
this.style.display = 'block';
this.focus();
},
_hideActions: function(event) {
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
this.setActive(false);
},
setActive: function(active) {
this.active = active;
},
loadImage: function(path) {
if (this.$.image.style.opacity != 0) {
this.waitUntil = (Date.now() / 1000) + 500;
} else {
this.waitUntil = 0;
}
this.$.image.style.opacity = 0;
this.image = new Image();
this.requested = path;
this.loading = true;
this.image.onload = function(path) {
this.loading = false;
var remaining = Math.max(this.waitUntil - Date.now() / 1000, 0);
this.async(function() {
if (!this.image || this.requested != path) {
return;
}
this.$.image.style.backgroundImage = 'url("' + this.image.src + '")';
this.$.image.style.opacity = 1;
this.image = undefined;
this.setActive(true);
}, remaining);
}.bind(this, path);
this.image.src = path + (this.unique ? ("?" + this.unique) : "");
},
attached: function() {
var base = document.querySelector("base");
if (base) {
this.base = new URL(base.href).pathname.replace(/\/$/, "") + "/"; /* Make sure there is a trailing slash */
} else {
this.base = "/";
}
}
});
</script>
</dom-module>
</html>