diff --git a/css/grid-n-view.css b/css/grid-n-view.css
index 99b69ac..3e9a3b3 100644
--- a/css/grid-n-view.css
+++ b/css/grid-n-view.css
@@ -62,32 +62,54 @@ body {
/* XXX need to account for scrollbar popping in and out */
.gallery {
- position: relative;
- display: flex;
- justify-content: flex-start;
- align-content: flex-start;
- flex-flow: row wrap;
-
margin-left: var(--gallery-scrollbar-width);
margin-right: 0;
color: var(--gallery-text-color);
background: var(--gallery-background-color);
}
-.gallery img {
+.gallery .images {
+ position: relative;
+ display: flex;
+ justify-content: flex-start;
+ align-content: flex-start;
+ flex-flow: row wrap;
+}
+.gallery .images img {
height: 300px;
width: auto;
image-rendering: crisp-edges;
box-sizing: border-box;
}
-.gallery>img {
+.gallery .images img {
cursor: hand;
}
-.gallery img.current {
+.gallery .images img.current {
border: solid 2px red;
}
+/*************************************************** Image markers ***/
+
+.gallery .images img+.mark {
+ position: relative;
+}
+
+/* marker: selected */
+.gallery .images img+.mark.selected:after {
+ content: "";
+ position: absolute;
+ display: block;
+ width: 1em;
+ height: 1em;
+ right: 0.5em;
+ bottom: 0.5em;
+ border-radius: 50%;
+ background: blue;
+}
+
+
+
/******************************************************* Lightbox ****/
.gallery .lightbox {
diff --git a/grid-n-view.html b/grid-n-view.html
index 344bc34..63bb701 100644
--- a/grid-n-view.html
+++ b/grid-n-view.html
@@ -19,25 +19,25 @@
+
+
-
-
-

-

-

-

-

-

-

-

-

-

-

-
diff --git a/grid-n-view.js b/grid-n-view.js
index 7e261fe..ddb3152 100644
--- a/grid-n-view.js
+++ b/grid-n-view.js
@@ -110,6 +110,24 @@ var keyboard = {
Escape: function(){
gallery.lightbox.shown
&& gallery.lightbox.hide() },
+ // selection...
+ ' ': function(evt){
+ gallery.current
+ && evt.preventDefault()
+ gallery.toggleSelect() },
+ // XXX use key codes...
+ 'a': function(evt){
+ evt.preventDefault()
+ if(evt.ctrlKey){
+ gallery.selectAll() } },
+ 'd': function(evt){
+ evt.preventDefault()
+ if(evt.ctrlKey){
+ gallery.deselectAll() } },
+ 'i': function(evt){
+ evt.preventDefault()
+ if(evt.ctrlKey){
+ gallery.selectInverse() } },
}
@@ -131,9 +149,9 @@ var Gallery = {
return undefined },
get current(){
- return this.dom.querySelector('img.current') },
+ return this.dom.querySelector('.images img.current') },
set current(img){
- for(var i of this.dom.querySelectorAll('img.current')){
+ for(var i of this.dom.querySelectorAll('.images img.current')){
i.classList.remove('current') }
img.classList.add('current')
img.scrollIntoView({
@@ -141,34 +159,41 @@ var Gallery = {
block: 'nearest',
}) },
+ // XXX should this be writable???
+ get images(){
+ return [...this.dom.querySelectorAll('.images img')] },
+
getRow: function(img, direction='current'){
if(['above', 'current', 'below'].includes(img)){
direction = img
- img = null }
+ img = this.current }
// get above/below row...
// XXX these are wastefull...
if(direction == 'above'){
var row = this.getRow(img)
- var e = row[0].previousSibling
+ var e = row[0].previousElementSibling
while(e && e.tagName != 'IMG'){
- e = e.previousSibling }
+ e = e.previousElementSibling }
return e ?
this.getRow(e)
- : this.getRow([...this.dom.querySelectorAll('img')].at(-1))
+ : this.getRow(this.images.at(-1))
} else if(direction == 'below'){
+ // special case: nothing selected...
+ if(img == null){
+ return this.getRow() }
var row = this.getRow(img)
- var e = row.at(-1).nextSibling
+ var e = row.at(-1).nextElementSibling
while(e && e.tagName != 'IMG'){
- e = e.nextSibling }
+ e = e.nextElementSibling }
return e ?
this.getRow(e)
- : this.getRow([...this.dom.querySelectorAll('img')][1]) }
+ : this.getRow(this.images[0]) }
// get current row...
var cur = img
?? this.current
if(cur == null){
var scroll = getScrollParent(this.dom).scrollTop
- var images = [...this.dom.querySelectorAll('img')].slice(1)
+ var images = this.images
for(cur of images){
if(cur.offsetTop >= scroll){
break } } }
@@ -177,16 +202,16 @@ var Gallery = {
var e = cur
while(e && e.offsetTop == top){
row.push(e)
- e = e.nextSibling
+ e = e.nextElementSibling
while(e && e.tagName != 'IMG'){
- e = e.nextSibling } }
+ e = e.nextElementSibling } }
e = cur
while(e && e.offsetTop == top){
e === cur
|| row.unshift(e)
- e = e.previousSibling
+ e = e.previousElementSibling
while(e && e.tagName != 'IMG'){
- e = e.previousSibling } }
+ e = e.previousElementSibling } }
return row },
getImage: function(img, direction='current'){
if(['left', 'above', 'current', 'below', 'right'].includes(img)){
@@ -196,7 +221,7 @@ var Gallery = {
if(direction == 'current'){
return img
?? this.current
- ?? this.getRow(img)
+ ?? this.getRow(img)[0]
// above/below...
} else if(direction == 'above' || direction == 'below'){
var row = this.getRow(direction)
@@ -232,7 +257,7 @@ var Gallery = {
// XXX cache image list???
prev: function(){
- var images = [...this.dom.querySelectorAll('img')].slice(1)
+ var images = this.images
var i = this.current == null ?
images.length-1
: images.indexOf(this.current)-1
@@ -242,7 +267,7 @@ var Gallery = {
this.current = images[i]
return this },
next: function(){
- var images = [...this.dom.querySelectorAll('img')].slice(1)
+ var images = this.images
var i = this.current == null ?
0
: images.indexOf(this.current)+1
@@ -276,9 +301,46 @@ var Gallery = {
this.current = this.getImage('below')
return this },
- // XXX
+ // selection...
+ get selected(){
+ return this.dom.querySelectorAll('.images img.selected') },
+ updateMarkers: function(){
+ // select...
+ for(var img of this.dom.querySelectorAll('.images img.selected')){
+ var mark = img.nextElementSibling
+ while(mark && mark.tagName != 'IMG' && !mark.classList.contains('mark')){
+ mark = img.nextElementSibling }
+ if(!mark || !mark.classList.contains('mark')){
+ mark = document.createElement('div')
+ mark.classList.add('selected', 'mark')
+ img.after(mark) } }
+ // clear deselected...
+ for(var mark of this.dom.querySelectorAll('.images img:not(.selected)+.mark')){
+ mark.remove() }
+ return this },
select: function(){
- },
+ this.current?.classList.add('selected')
+ return this.updateMarkers() },
+ deselect: function(){
+ this.current?.classList.remove('selected')
+ return this.updateMarkers() },
+ toggleSelect: function(){
+ this.current?.classList.toggle('selected')
+ this.updateMarkers()
+ return this },
+ selectAll: function(){
+ for(var img of this.images){
+ img.classList.add('selected') }
+ return this.updateMarkers() },
+ deselectAll: function(){
+ for(var img of this.images){
+ img.classList.remove('selected') }
+ return this.updateMarkers() },
+ selectInverse: function(){
+ for(var img of this.images){
+ img.classList.toggle('selected') }
+ return this.updateMarkers() },
+
show: function(){
this.lightbox.show()
@@ -435,7 +497,7 @@ var setupGallery = function(gallery){
.setup(gallery) }
var setup = function(){
- patchFlexRows([...document.querySelectorAll('.gallery>img')])
+ patchFlexRows([...document.querySelectorAll('.gallery .images img')])
var galleries = document.body.querySelectorAll('.gallery')
for(var gallery of galleries){
@@ -447,7 +509,7 @@ var setup = function(){
if(key in keyboard){
keyboard[key](evt) } })
window.addEventListener('resize', function(){
- patchFlexRows([...document.querySelectorAll('.gallery>img')]) })
+ patchFlexRows([...document.querySelectorAll('.gallery .images img')]) })
}