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-behavior": "PolymerElements/iron-a11y-keys-behavior#^1.0.0",
"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": {
"polymer": "^1.4.0",

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

@ -14,10 +14,10 @@
@apply --photo-thumbnail;
display: inline-block;
position: relative;
background-color: #ccc;
background-repeat: no-repeat;
background-size: cover;
background-position: 50% 50%;
border-radius: 3px;
cursor: pointer;
color: white;
overflow: hidden;
@ -71,11 +71,15 @@
observers: [
"widthChanged(width)",
"thumbChanged(thumbpath)"
"thumbChanged(thumbpath, visible)"
],
thumbChanged: function(thumbpath) {
thumbChanged: function(thumbpath, visible) {
if (visible) {
this.style.backgroundImage = "url(" + thumbpath + ")";
} else {
this.style.backgroundImage = "";
}
},
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-spinner/paper-spinner.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" />
@ -101,29 +102,34 @@
*/
.date-line {
display: block;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0.5em 0;
width: 100%;
font-weight: bold;
}
.album-line {
display: block;
padding: 0.5em 0;
width: 100%;
.date-line .album-line {
cursor: pointer;
color: #ddd;
}
.album-line > div {
.album-line > div:not(:last-child) {
margin-right: 0.5em;
}
.album-line > div:first-child {
margin-left: 0.5em;
}
.album-line > div:hover {
text-decoration: underline;
}
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-album">By album</paper-radio-button>
</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>
</div>
<div id="breadcrumb" class="horizontal layout center"><template is="dom-repeat" items="[[breadcrumb(path)]]">
@ -166,7 +171,7 @@
</div>
</app-header>
<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 class="layout horizontal">
<paper-button disabled$="[[!prev]]" on-tap="loadPrevPhotos">prev</paper-button>
@ -205,11 +210,6 @@
value: true,
reflectToAttribute: true
},
limitPerFolder: {
type: Boolean,
value: false,
reflectToAttribute: true
},
showAlbums: {
type: Boolean,
computed: "shouldShowAlbums(order)"
@ -259,17 +259,6 @@
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) {
if (!this.photos) {
return;
@ -308,11 +297,37 @@
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) {
if (this.disableScrolling) {
event.preventDefault();
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) {
@ -422,17 +437,12 @@
return;
}
var thisDay, lastPath = null;
if (this.limitPerFolder) {
console.log("Max per day: " + this.cols);
}
var lastPath = null;
var albums = this.querySelectorAll(".album-line");
if (albums.length) {
lastPath = albums[albums.length - 1];
}
thisDay = 0;
for (var i = 0; i < photos.length; i++) {
var photo = photos[i],
thumbnail = document.createElement("photo-thumbnail"),
@ -443,6 +453,34 @@
thumbnail.addEventListener("load-album", this.loadAlbum.bind(this));
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 (lastPath != photo.path) {
lastPath = photo.path;
@ -459,52 +497,15 @@
albumBlock.appendChild(div);
}.bind(this));
Polymer.dom(this.$.thumbnails).appendChild(albumBlock);
var header = dateBlock.querySelector(".header");
Polymer.dom(header).appendChild(albumBlock);
}
}
if (this.breakOnDayChange) {
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--;
}
}
}
Polymer.dom(thumbnails).appendChild(thumbnail);
}
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;
}
}
this.triggerVisibilityChecks();
},
pathTapped: function(event) {
@ -617,6 +618,7 @@
},
onResize: function(event) {
this.triggerVisibilityChecks();
this.debounce("resize", function() {
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);
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);
}).then(function() {
console.log("Done scanning. Opening server.");
server.listen(serverConfig.port);
console.log("Scanning completed.");
}).catch(function(error) {
console.error(error);
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, {
replacements: {
cursor: cursor,