Dynamically load items as viewed.

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-08-31 13:50:57 -07:00
parent c49310ef71
commit 35258af897
5 changed files with 93 additions and 82 deletions

View File

@ -48,7 +48,8 @@
"iron-a11y-keys": "PolymerElements/iron-a11y-keys#^1.0.0", "iron-a11y-keys": "PolymerElements/iron-a11y-keys#^1.0.0",
"iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0", "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
"es6-shim": "^0.35.3", "es6-shim": "^0.35.3",
"paper-radio-group": "PolymerElements/paper-radio-group#^2.2.0" "paper-radio-group": "PolymerElements/paper-radio-group#^2.2.0",
"moment": "^2.22.2"
}, },
"resolutions": { "resolutions": {
"polymer": "^1.4.0", "polymer": "^1.4.0",

10
frontend/elements/photo-thumbnail.html Normal file → Executable file
View File

@ -14,10 +14,10 @@
@apply --photo-thumbnail; @apply --photo-thumbnail;
display: inline-block; display: inline-block;
position: relative; position: relative;
background-color: #ccc;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
background-position: 50% 50%; background-position: 50% 50%;
border-radius: 3px;
cursor: pointer; cursor: pointer;
color: white; color: white;
overflow: hidden; overflow: hidden;
@ -71,11 +71,15 @@
observers: [ observers: [
"widthChanged(width)", "widthChanged(width)",
"thumbChanged(thumbpath)" "thumbChanged(thumbpath, visible)"
], ],
thumbChanged: function(thumbpath) { thumbChanged: function(thumbpath, visible) {
if (visible) {
this.style.backgroundImage = "url(" + thumbpath + ")"; this.style.backgroundImage = "url(" + thumbpath + ")";
} else {
this.style.backgroundImage = "";
}
}, },
widthChanged: function(width) { widthChanged: function(width) {

View File

@ -24,6 +24,7 @@
<link rel="import" href="../../bower_components/paper-radio-button/paper-radio-button.html"> <link rel="import" href="../../bower_components/paper-radio-button/paper-radio-button.html">
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html"> <link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="../../bower_components/paper-toast/paper-toast.html"> <link rel="import" href="../../bower_components/paper-toast/paper-toast.html">
<script src="../../bower_components/moment/moment.js"></script>
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" /> <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" />
@ -101,29 +102,34 @@
*/ */
.date-line { .date-line {
display: block; display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0.5em 0; padding: 0.5em 0;
width: 100%; font-weight: bold;
} }
.album-line { .date-line .album-line {
display: block;
padding: 0.5em 0;
width: 100%;
cursor: pointer; cursor: pointer;
color: #ddd;
} }
.album-line > div { .album-line > div:not(:last-child) {
margin-right: 0.5em; margin-right: 0.5em;
} }
.album-line > div:first-child {
margin-left: 0.5em;
}
.album-line > div:hover { .album-line > div:hover {
text-decoration: underline; text-decoration: underline;
} }
photo-thumbnail { photo-thumbnail {
--photo-thumbnail: { --photo-thumbnail: {
border: 3px solid rgba(0, 0, 0, 0); border: 3px solid white;
}; };
} }
@ -157,7 +163,6 @@
<paper-radio-button name="by-date">By date</paper-radio-button> <paper-radio-button name="by-date">By date</paper-radio-button>
<paper-radio-button name="by-album">By album</paper-radio-button> <paper-radio-button name="by-album">By album</paper-radio-button>
</paper-radio-group> </paper-radio-group>
<paper-checkbox checked$="[[limitPerFolder]]" on-checked-changed="onLimitPerFolderChanged">Limit per folder</paper-checkbox>
<paper-checkbox checked$="[[breakOnDayChange]]" on-checked-changed="onBreakOnDayChanged">Break on day change</paper-checkbox> <paper-checkbox checked$="[[breakOnDayChange]]" on-checked-changed="onBreakOnDayChanged">Break on day change</paper-checkbox>
</div> </div>
<div id="breadcrumb" class="horizontal layout center"><template is="dom-repeat" items="[[breadcrumb(path)]]"> <div id="breadcrumb" class="horizontal layout center"><template is="dom-repeat" items="[[breadcrumb(path)]]">
@ -166,7 +171,7 @@
</div> </div>
</app-header> </app-header>
<div id="content" fullbleed class="flex layout vertical"> <div id="content" fullbleed class="flex layout vertical">
<div id="thumbnails" class="thumbnails layout horizontal wrap"></div> <div id="thumbnails" class="layout horizontal wrap"></div>
<div id="magic"></div> <div id="magic"></div>
<div class="layout horizontal"> <div class="layout horizontal">
<paper-button disabled$="[[!prev]]" on-tap="loadPrevPhotos">prev</paper-button> <paper-button disabled$="[[!prev]]" on-tap="loadPrevPhotos">prev</paper-button>
@ -205,11 +210,6 @@
value: true, value: true,
reflectToAttribute: true reflectToAttribute: true
}, },
limitPerFolder: {
type: Boolean,
value: false,
reflectToAttribute: true
},
showAlbums: { showAlbums: {
type: Boolean, type: Boolean,
computed: "shouldShowAlbums(order)" computed: "shouldShowAlbums(order)"
@ -259,17 +259,6 @@
this.appendItems(this.photos); this.appendItems(this.photos);
}, },
onLimitPerFolderChanged: function(event) {
if (!this.photos) {
return;
}
this.limitPerFolder = event.detail.value;
Polymer.dom(this.$.thumbnails).innerHTML = "";
this.appendItems(this.photos);
},
onBreakOnDayChanged: function(event) { onBreakOnDayChanged: function(event) {
if (!this.photos) { if (!this.photos) {
return; return;
@ -308,11 +297,37 @@
this._loadPhotos(); this._loadPhotos();
}, },
isThumbInView: function(el) {
var rect = el.getBoundingClientRect(),
height = (window.innerHeight || document.documentElement.clientHeight),
width = (window.innerWidth || document.documentElement.clientWidth);
return ((rect.top <= height) && ((rect.top + rect.height) >= 0) &&
(rect.left <= width) && ((rect.left + rect.width) >= 0));
},
onScroll: function(event) { onScroll: function(event) {
if (this.disableScrolling) { if (this.disableScrolling) {
event.preventDefault(); event.preventDefault();
window.scrollTo(this.topStickX, this.topStickY); window.scrollTo(this.topStickX, this.topStickY);
return;
} }
this.triggerVisibilityChecks();
},
triggerVisibilityChecks: function() {
this.debounce("hide-or-show", function() {
var thumbs = this.querySelectorAll("photo-thumbnail"), visible;
thumbs.forEach(function(thumb) {
visible = this.isThumbInView(thumb);
if (thumb.visible != visible) {
thumb.visible = visible;
}
}.bind(this));
}, 250);
}, },
findPhoto: function(photo) { findPhoto: function(photo) {
@ -422,17 +437,12 @@
return; return;
} }
var thisDay, lastPath = null; var lastPath = null;
if (this.limitPerFolder) {
console.log("Max per day: " + this.cols);
}
var albums = this.querySelectorAll(".album-line"); var albums = this.querySelectorAll(".album-line");
if (albums.length) { if (albums.length) {
lastPath = albums[albums.length - 1]; lastPath = albums[albums.length - 1];
} }
thisDay = 0;
for (var i = 0; i < photos.length; i++) { for (var i = 0; i < photos.length; i++) {
var photo = photos[i], var photo = photos[i],
thumbnail = document.createElement("photo-thumbnail"), thumbnail = document.createElement("photo-thumbnail"),
@ -443,6 +453,34 @@
thumbnail.addEventListener("load-album", this.loadAlbum.bind(this)); thumbnail.addEventListener("load-album", this.loadAlbum.bind(this));
datetime = (photo.taken || photo.modified || photo.added).replace(/T.*$/, ""); datetime = (photo.taken || photo.modified || photo.added).replace(/T.*$/, "");
var dateBlock = this.querySelector("#date-" + datetime), thumbnails;
if (!dateBlock) {
dateBlock = document.createElement("div");
dateBlock.id = "date-" + datetime;
dateBlock.classList.add("date-line");
dateBlock.classList.add("layout");
dateBlock.classList.add("vertical");
var header = document.createElement("div");
header.classList.add("header");
header.classList.add("layout");
header.classList.add("center");
header.classList.add("horizontal");
var div = document.createElement("div");
div.classList.add("date");
div.textContent = window.moment(datetime, "YYYY-MM-DD").calendar(null, { sameElse: "MMM DD, YYYY" });
Polymer.dom(dateBlock).appendChild(header);
Polymer.dom(header).appendChild(div);
thumbnails = document.createElement("div");
thumbnails.classList.add("thumbnails");
thumbnails.classList.add("layout");
thumbnails.classList.add("horizontal");
thumbnails.classList.add("wrap");
Polymer.dom(dateBlock).appendChild(thumbnails);
Polymer.dom(this.$.thumbnails).appendChild(dateBlock);
} else {
thumbnails = Polymer.dom(dateBlock).querySelector(".thumbnails");
}
if (this.order == "by-album") { if (this.order == "by-album") {
if (lastPath != photo.path) { if (lastPath != photo.path) {
lastPath = photo.path; lastPath = photo.path;
@ -459,52 +497,15 @@
albumBlock.appendChild(div); albumBlock.appendChild(div);
}.bind(this)); }.bind(this));
Polymer.dom(this.$.thumbnails).appendChild(albumBlock); var header = dateBlock.querySelector(".header");
Polymer.dom(header).appendChild(albumBlock);
} }
} }
if (this.breakOnDayChange) { Polymer.dom(thumbnails).appendChild(thumbnail);
var dateBlock = this.querySelector("#date-" + datetime);
if (!dateBlock) {
dateBlock = document.createElement("div");
dateBlock.id = "date-" + datetime;
dateBlock.classList.add("date-line");
dateBlock.textContent = datetime;
Polymer.dom(this.$.thumbnails).appendChild(dateBlock);
thisDay = 0;
} else {
if (this.limitPerFolder) {
var thumbs = [], el = dateBlock.nextElementSibling;
while (el && el.tagName == "PHOTO-THUMBNAIL") {
thumbs.push(el);
el = el.nextElementSibling;
}
thisDay = thumbs.length;
while (thisDay > this.cols) {
Polymer.dom(thumbs[thisDay - 1].parentElement).removeChild(thumbs[thisDay - 1]);
thisDay--;
}
}
}
} }
this.triggerVisibilityChecks();
if (!this.limitPerFolder || thisDay < this.cols) {
Polymer.dom(this.$.thumbnails).appendChild(thumbnail);
thisDay++;
}
if (this.limitPerFolder && thisDay == this.cols) {
while (i + 1 < photos.length) {
photo = photos[i + 1];
if (datetime != (photo.taken || photo.modified || photo.added).replace(/T.*$/, "")) {
break;
}
i++;
}
thisDay = 0;
}
}
}, },
pathTapped: function(event) { pathTapped: function(event) {
@ -617,6 +618,7 @@
}, },
onResize: function(event) { onResize: function(event) {
this.triggerVisibilityChecks();
this.debounce("resize", function() { this.debounce("resize", function() {
var width = Math.max(this.$.placeholder.offsetWidth || 0, 200); var width = Math.max(this.$.placeholder.offsetWidth || 0, 200);

8
server/app.js Normal file → Executable file
View File

@ -84,10 +84,14 @@ app.set("port", serverConfig.port);
const server = require("http").createServer(app); const server = require("http").createServer(app);
db.then(function(photoDB) { db.then(function(photoDB) {
console.log("DB connected. Opening server.");
server.listen(serverConfig.port);
return photoDB;
}).then(function(photoDB) {
console.log("Scanning.");
return scanner.scan(photoDB); return scanner.scan(photoDB);
}).then(function() { }).then(function() {
console.log("Done scanning. Opening server."); console.log("Scanning completed.");
server.listen(serverConfig.port);
}).catch(function(error) { }).catch(function(error) {
console.error(error); console.error(error);
process.exit(-1); process.exit(-1);

2
server/routes/photos.js Normal file → Executable file
View File

@ -55,7 +55,7 @@ router.get("/*", function(req, res/*, next*/) {
} }
} }
let query = "SELECT * FROM photos WHERE path LIKE :path " + index + " ORDER BY taken " + order + ",id " + order + " LIMIT " + (limit * 2 + 1); let query = "SELECT * FROM photos WHERE path LIKE :path " + index + " ORDER BY taken " + order + ",id " + order;// + " LIMIT " + (limit * 2 + 1);
return photoDB.sequelize.query(query, { return photoDB.sequelize.query(query, {
replacements: { replacements: {
cursor: cursor, cursor: cursor,