+ CAPTION
+ TAGS
-
diff --git a/grid-n-view.js b/grid-n-view.js
index be3df0e..a2fdaa9 100644
--- a/grid-n-view.js
+++ b/grid-n-view.js
@@ -122,29 +122,36 @@ function(elem) {
// XXX add home/end, pageup/pagedown...
var keyboard = {
ArrowLeft: function(){
- gallery.lightbox.shown ?
- gallery.lightbox.prev()
- : gallery.prev() },
+ gallery.prev() },
ArrowRight: function(){
- gallery.lightbox.shown ?
- gallery.lightbox.next()
- : gallery.next() },
+ gallery.next() },
// NOTE: up/down will not prevent the default scrolling behavior
// when at top/bottom of the gallery.
ArrowUp: function(evt){
gallery.__at_top_row
|| evt.preventDefault()
+ ;(gallery.dom.classList.contains('lightboxed')
+ || gallery.dom.classList.contains('detailed'))
+ && evt.preventDefault()
gallery.lightbox.shown
+ || gallery.details.shown
|| gallery.up() },
ArrowDown: function(evt){
gallery.__at_bottom_row
|| evt.preventDefault()
+ ;(gallery.dom.classList.contains('lightboxed')
+ || gallery.dom.classList.contains('detailed'))
+ && evt.preventDefault()
gallery.lightbox.shown
+ || gallery.details.shown
|| gallery.down() },
Enter: function(){
gallery.lightbox.toggle() },
+ // XXX need a real ui stack -- close top to bottom...
Escape: function(evt){
- gallery.lightbox.shown ?
+ gallery.details.shown ?
+ gallery.details.hide()
+ : gallery.lightbox.shown ?
gallery.lightbox.hide()
// XXX should we remember which image was current and select
// it again when needed???
@@ -263,6 +270,16 @@ var Gallery = {
this)) }
delete this.__lightbox
return undefined },
+ __details: undefined,
+ get details(){
+ if(this.dom){
+ return this.__details
+ ?? (this.__details = { __proto__: Details }
+ .setup(
+ this.dom.querySelector('.details'),
+ this)) }
+ delete this.__details
+ return undefined },
__at_top_row: undefined,
__at_bottom_row: undefined,
@@ -448,6 +465,7 @@ var Gallery = {
images.length-1
: 0
this.current = images[i]
+ this.update()
return this },
next: function(images){
images ??= this.images
@@ -460,6 +478,7 @@ var Gallery = {
0
: images.length-1
this.current = images[i]
+ this.update()
return this },
// navigate images visually...
@@ -546,12 +565,25 @@ var Gallery = {
show: function(){
this.lightbox.show()
return this },
+ showLightbox: function(){
+ this.lightbox.show()
+ return this },
+ showDetails: function(){
+ this.details.show()
+ return this },
- update: function(){
+ __update_grid_size: function(){
patchFlexRows(this.images,
!this.allow_row_expansion,
this.last_row_resize ?? 1.2)
return this },
+ update: function(){
+ this.__update_grid_size()
+ this.lightbox.shown
+ && this.lightbox.update()
+ this.details.shown
+ && this.details.update()
+ return this },
// .load(
)
// .load()
@@ -690,7 +722,7 @@ var Gallery = {
// handle resizing...
new ResizeObserver(
function(elems){
- that.update() })
+ that.__update_grid_size() })
.observe(this.dom)
return this
@@ -701,16 +733,10 @@ var Gallery = {
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// XXX ignore click from blur...
-var Lightbox = {
+var Overlay = {
dom: undefined,
gallery: undefined,
-
- caption_format: '${INDEX} ${CAPTION}',
-
- navigation_deadzone: 100,
- caption_hysteresis: 10,
- cache_count: 1,
+ cls: 'overlay',
get url(){
return this.dom.querySelector('img').src },
@@ -719,31 +745,34 @@ var Lightbox = {
// remove preview dir...
.replace(/\/[0-9]+px\//, '/')
// cache...
- this.cache_count != 0
+ this.cache
+ && this.cache_count != 0
&& this.cache() },
get shown(){
- return this.gallery.dom.classList.contains('lightboxed') },
- show: function(url){
- this.url = url
- ?? (this.gallery.current
- ?? this.gallery.next().current
- ?? {}).src
+ return this.gallery.dom.classList.contains(this.cls) },
+ show: function(){
this.update()
- this.gallery.dom.classList.add('lightboxed')
+ this.gallery.dom.classList.add(this.cls)
return this },
hide: function(){
this.gallery.exit_fullscreen_on_lightbox_close
&& document.fullscreenElement
&& document.exitFullscreen()
- this.gallery.dom.classList.remove('lightboxed')
+ this.gallery.dom.classList.remove(this.cls)
return this },
toggle: function(){
return this.shown ?
this.hide()
: this.show() },
+ cache: null,
+
update: function(){
+ this.url =
+ (this.gallery.current
+ ?? this.gallery.next().current
+ ?? {}).src
var caption =
(this.gallery.current
?? this.gallery.next().current
@@ -754,7 +783,7 @@ var Lightbox = {
// set caption...
// XXX should these be separate elements???
this.dom.setAttribute('caption',
- this.caption_format
+ (this.caption_format ?? '${CAPTION}')
.replace(/\${CAPTION}/, caption)
.replace(/\${INDEX}/, index))
// set selection...
@@ -763,12 +792,67 @@ var Lightbox = {
: this.dom.classList.remove('marked')
return this },
- prev: function(){
- this.gallery.prev().show()
- return this },
- next: function(){
- this.gallery.next().show()
+ setup: function(dom, gallery){
+ var that = this
+ this.dom = dom
+ this.gallery = gallery
+
+ // controls...
+ this.dom.querySelector('.close')
+ ?.addEventListener('click', function(evt){
+ evt.stopPropagation()
+ that.hide() })
+ this.dom.querySelector('.fullscreen')
+ ?.addEventListener('click', function(evt){
+ evt.stopPropagation()
+ document.fullscreenElement ?
+ document.exitFullscreen()
+ : that.dom.requestFullscreen() })
+ this.dom.querySelector('.info')
+ ?.addEventListener('click', function(evt){
+ evt.stopPropagation()
+ that.gallery.showDetails() })
+ this.dom.querySelector('.prev')
+ ?.addEventListener('click', function(evt){
+ evt.stopPropagation()
+ that.gallery.prev() })
+ this.dom.querySelector('.next')
+ ?.addEventListener('click', function(evt){
+ evt.stopPropagation()
+ that.gallery.next() })
+ // stop body from scrolling...
+ var stop = function(evt){
+ evt.stopPropagation()
+ evt.preventDefault()
+ return false }
+ this.dom.addEventListener('touchmove', stop)
+ this.dom.addEventListener('mousewheel', stop)
+ this.dom.addEventListener('wheel', stop)
+ this.dom.addEventListener('scroll', stop)
+ // drag...
+ this.dom
+ .addEventListener('dragover', function(evt){
+ that.gallery.dom.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ })
+ that.hide() })
return this },
+}
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+var Lightbox = {
+ __proto__: Overlay,
+
+ cls: 'lightboxed',
+
+ caption_format: '${INDEX} ${CAPTION}',
+
+ navigation_deadzone: 100,
+ caption_hysteresis: 10,
+ cache_count: 1,
__cache: undefined,
cache: function(){
@@ -795,28 +879,10 @@ var Lightbox = {
setup: function(dom, gallery){
var that = this
- this.dom = dom
- this.gallery = gallery
- // controls...
- this.dom.querySelector('.close')
- .addEventListener('click', function(evt){
- evt.stopPropagation()
- that.hide() })
- this.dom.querySelector('.fullscreen')
- .addEventListener('click', function(evt){
- evt.stopPropagation()
- document.fullscreenElement ?
- document.exitFullscreen()
- : that.dom.requestFullscreen() })
- // drag...
- this.dom
- .addEventListener('dragover', function(evt){
- that.gallery.dom.scrollIntoView({
- behavior: 'smooth',
- block: 'nearest',
- })
- that.hide() })
- // click...
+
+ Overlay.setup.call(this, ...arguments)
+
+ // click zones...
var deadzone = this.navigation_deadzone ?? 100
this.dom
.addEventListener('click', function(evt){
@@ -824,10 +890,10 @@ var Lightbox = {
// click left/right side of view...
// NOTE: this is vewport-relative...
evt.clientX < that.dom.offsetWidth / 2 - deadzone/2
- && that.prev()
+ && that.gallery.prev()
evt.clientX > that.dom.offsetWidth / 2 + deadzone/2
- && that.next() })
- // mousemove...
+ && that.gallery.next() })
+ // hover zones...
var hysteresis = this.caption_hysteresis ?? 10
this.dom
.addEventListener('mousemove', function(evt){
@@ -856,6 +922,16 @@ var Lightbox = {
}
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+var Details = {
+ __proto__: Overlay,
+
+ cls: 'detailed',
+
+ // XXX
+}
+
//---------------------------------------------------------------------