From 03a79d3f225269845e77818d949f7abcb635e366 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Thu, 20 Jul 2023 21:42:17 +0300 Subject: [PATCH] added selection... Signed-off-by: Alex A. Naanou --- css/grid-n-view.css | 40 +++++++++++++---- grid-n-view.html | 28 ++++++------ grid-n-view.js | 104 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 128 insertions(+), 44 deletions(-) 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')]) }) }