Compare commits
10 Commits
802fe8193b
...
e0de8a9a13
| Author | SHA1 | Date | |
|---|---|---|---|
| e0de8a9a13 | |||
| 673912b219 | |||
| 3c7ed59b26 | |||
| f869066082 | |||
| b8a0146d63 | |||
| b156ba8e7b | |||
| 6a00c1e4df | |||
| 93b8f63057 | |||
| 209202945a | |||
| 03a79d3f22 |
@ -9,6 +9,15 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* dimensions */
|
/* dimensions */
|
||||||
|
--gallery-current-border-size: 0.7em;
|
||||||
|
--gallery-padding: 3em;
|
||||||
|
--gallery-padding-horizontal: var(--gallery-padding);
|
||||||
|
--gallery-padding-vertical: var(--gallery-current-border-size);
|
||||||
|
--gallery-padding-top: var(--gallery-padding-vertical);
|
||||||
|
--gallery-padding-bottom: var(--gallery-padding-vertical);
|
||||||
|
--gallery-padding-left: var(--gallery-padding-horizontal);
|
||||||
|
--gallery-padding-right: var(--gallery-padding-horizontal);
|
||||||
|
--gallery-image-scroll-margin: 1em;
|
||||||
--gallery-scrollbar-width: 0.5em;
|
--gallery-scrollbar-width: 0.5em;
|
||||||
|
|
||||||
--lightbox-frame-size: 5vmin;
|
--lightbox-frame-size: 5vmin;
|
||||||
@ -22,6 +31,7 @@
|
|||||||
|
|
||||||
--lightbox-text-color: black;
|
--lightbox-text-color: black;
|
||||||
--lightbox-background-color: white;
|
--lightbox-background-color: white;
|
||||||
|
/*--lightbox-background-color: rgba(0,0,0,0.8);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.gallery-dark {
|
.gallery-dark {
|
||||||
@ -62,30 +72,72 @@ body {
|
|||||||
|
|
||||||
/* XXX need to account for scrollbar popping in and out */
|
/* XXX need to account for scrollbar popping in and out */
|
||||||
.gallery {
|
.gallery {
|
||||||
|
padding-top: var(--gallery-padding-top);
|
||||||
|
padding-bottom: var(--gallery-padding-bottom);
|
||||||
|
padding-left: calc(
|
||||||
|
var(--gallery-scrollbar-width)
|
||||||
|
+ var(--gallery-padding-left) );
|
||||||
|
padding-right: var(--gallery-padding-right);
|
||||||
|
|
||||||
|
color: var(--gallery-text-color);
|
||||||
|
background: var(--gallery-background-color);
|
||||||
|
}
|
||||||
|
.gallery .images {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
flex-flow: row wrap;
|
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 img {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
scroll-margin: var(--gallery-image-scroll-margin);
|
||||||
image-rendering: crisp-edges;
|
image-rendering: crisp-edges;
|
||||||
box-sizing: border-box;
|
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.gallery>img {
|
|
||||||
cursor: hand;
|
/* selection marker... */
|
||||||
|
.gallery .images img.current {
|
||||||
|
z-index: 1;
|
||||||
|
box-shadow:
|
||||||
|
0px 0px 0px var(--gallery-current-border-size) rgba(255,255,255,1),
|
||||||
|
0.4em 0.4em 3em 0em rgba(0,0,0,0.8);
|
||||||
}
|
}
|
||||||
.gallery img.current {
|
|
||||||
border: solid 2px red;
|
|
||||||
|
/*************************************************** Image markers ***/
|
||||||
|
|
||||||
|
.gallery .images img+.mark {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.gallery.lightboxed .images img+.mark {
|
||||||
|
z-index: 2;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
box-shadow: 0em 0em 0em 0.05em rgba(255,255,255,1);
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************* Lightbox ****/
|
/******************************************************* Lightbox ****/
|
||||||
@ -97,20 +149,24 @@ body {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
color: var(--lightbox-text-color);
|
color: var(--lightbox-text-color);
|
||||||
background: var(--lightbox-background-color);
|
background: var(--lightbox-background-color);
|
||||||
}
|
}
|
||||||
.gallery .lightbox.show-caption:after {
|
.gallery.lightboxed .lightbox {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.gallery .lightbox.show-caption:before {
|
||||||
content: attr(caption);
|
content: attr(caption);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0.5em;
|
bottom: 0.5em;
|
||||||
left: 0.5em;
|
left: 0.5em;
|
||||||
}
|
}
|
||||||
.gallery .lightbox.clickable {
|
.gallery .lightbox.clickable {
|
||||||
cursor: hand;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
/* XXX add metadata display... */
|
/* XXX add metadata display... */
|
||||||
.gallery .lightbox img {
|
.gallery .lightbox img {
|
||||||
@ -126,14 +182,14 @@ body {
|
|||||||
* var(--lightbox-image-margin-top));
|
* var(--lightbox-image-margin-top));
|
||||||
}
|
}
|
||||||
/* controls: next/prev... */
|
/* controls: next/prev... */
|
||||||
.lightbox .button {
|
.gallery .lightbox .button {
|
||||||
cursor: hand;
|
cursor: pointer;
|
||||||
font-size: var(--lightbox-button-size);
|
font-size: var(--lightbox-button-size);
|
||||||
padding: 0 0.25em;
|
padding: 0 0.25em;
|
||||||
filter: saturate(0);
|
filter: saturate(0);
|
||||||
opacity: 0.1;
|
opacity: 0.1;
|
||||||
}
|
}
|
||||||
.lightbox .button:hover {
|
.gallery .lightbox .button:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
filter: saturate(1);
|
filter: saturate(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,26 +18,55 @@
|
|||||||
</head>
|
</head>
|
||||||
<body onload="setup()">
|
<body onload="setup()">
|
||||||
|
|
||||||
|
<h3>ToDo</h3>
|
||||||
|
<pre>
|
||||||
|
- <s>Gallery: Adaptable image justification in grid</s>
|
||||||
|
- Can we make this passive??? (i.e. CSS only)
|
||||||
|
- <s>Make more accurate -- align right side to pixel...</s>
|
||||||
|
- <s>Gallery: Spacial navigation (up/down/left/right)</s>
|
||||||
|
- <b>option: .loop_images (in porgress)</b>
|
||||||
|
- Up/Down: might be a good idea to err slightly to the left
|
||||||
|
- Gallery: PageUp/PageDown, home/end + allow page navigation
|
||||||
|
- <b>Gallery: focus visible (if no current)...</b>
|
||||||
|
- <s>Gallery/Lightbox: Selection of images (space / ctrl-a / ctrl-d / ctrl-i)</s>
|
||||||
|
- <s>Lightbox: show selection marker</s>
|
||||||
|
- <b>Gallery: constructor (list of urls)</b>
|
||||||
|
- <b>Gallery: views</b>
|
||||||
|
- "make view from selection"
|
||||||
|
- close view
|
||||||
|
- multiple view stack
|
||||||
|
- Gallery: drop images
|
||||||
|
- Gallery: drag to sort
|
||||||
|
- Gallery: remove image
|
||||||
|
- <b>Gallery: serialize / deserialize</b>
|
||||||
|
- <s>Lightbox: navigation (keyboard / mouse)</s>
|
||||||
|
- Lightbox: fullscreen mode
|
||||||
|
- Gallery: element (???)
|
||||||
|
- ...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
<div class="gallery">
|
<div class="gallery">
|
||||||
|
<!-- gallery: content -->
|
||||||
|
<div class="images">
|
||||||
|
<img src="images/500px/1.JPG" caption="Caption text">
|
||||||
|
<img src="images/500px/2.JPG">
|
||||||
|
<img src="images/500px/3.JPG">
|
||||||
|
<img src="images/500px/DSC08102.jpg">
|
||||||
|
<img src="images/500px/4.JPG">
|
||||||
|
<img src="images/500px/5.JPG">
|
||||||
|
<img src="images/500px/DSC08102.jpg">
|
||||||
|
<img src="images/500px/6.JPG">
|
||||||
|
<img src="images/500px/DSC08102.jpg">
|
||||||
|
<img src="images/500px/2.JPG">
|
||||||
|
<img src="images/500px/5.JPG">
|
||||||
|
</div>
|
||||||
<!-- lightbox -->
|
<!-- lightbox -->
|
||||||
<div class="lightbox">
|
<div class="lightbox">
|
||||||
<img>
|
<img>
|
||||||
<div class="button close"></div>
|
<div class="button close"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- gallery: content -->
|
|
||||||
<img src="images/500px/1.JPG" caption="Caption text">
|
|
||||||
<img src="images/500px/2.JPG">
|
|
||||||
<img src="images/500px/3.JPG">
|
|
||||||
<img src="images/500px/DSC08102.jpg">
|
|
||||||
<img src="images/500px/4.JPG">
|
|
||||||
<img src="images/500px/5.JPG">
|
|
||||||
<img src="images/500px/DSC08102.jpg">
|
|
||||||
<img src="images/500px/6.JPG">
|
|
||||||
<img src="images/500px/DSC08102.jpg">
|
|
||||||
<img src="images/500px/2.JPG">
|
|
||||||
<img src="images/500px/5.JPG">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
275
grid-n-view.js
275
grid-n-view.js
@ -19,8 +19,9 @@
|
|||||||
|
|
||||||
// XXX need to account for scrollbar -- add hysteresis???
|
// XXX need to account for scrollbar -- add hysteresis???
|
||||||
var patchFlexRows =
|
var patchFlexRows =
|
||||||
function(elems){
|
function(elems, prevent_row_expansion=false){
|
||||||
var W = elems[0].parentElement.clientWidth - 2
|
// NOTE: -1 here is to compensate for rounding errors...
|
||||||
|
var W = elems[0].parentElement.clientWidth - 1
|
||||||
var w = 0
|
var w = 0
|
||||||
var h
|
var h
|
||||||
var row = []
|
var row = []
|
||||||
@ -37,21 +38,26 @@ function(elems){
|
|||||||
if(elem.offsetTop == top){
|
if(elem.offsetTop == top){
|
||||||
w += elem.offsetWidth
|
w += elem.offsetWidth
|
||||||
row.push(elem)
|
row.push(elem)
|
||||||
// next row...
|
// row donw + prep for next...
|
||||||
} else {
|
} else {
|
||||||
// NOTE: we are checking which will require a lesser resize
|
// NOTE: we are checking which will require a lesser resize
|
||||||
// the current row or it with the next image...
|
// the current row or it with the next image...
|
||||||
var r1 = W / w
|
var r1 = W / w
|
||||||
var r2 = W / (w + elem.offsetWidth)
|
var r2 = W / (w + elem.offsetWidth)
|
||||||
var expanded_row = 1/r1 < r2
|
var expanded_row =
|
||||||
|
prevent_row_expansion ?
|
||||||
|
false
|
||||||
|
: 1/r1 < r2
|
||||||
if(!expanded_row){
|
if(!expanded_row){
|
||||||
var r = r1
|
var r = r1
|
||||||
} else {
|
} else {
|
||||||
var r = r2
|
var r = r2
|
||||||
row.push(elem) }
|
row.push(elem) }
|
||||||
// patch the row...
|
// patch the row...
|
||||||
|
var nw = 0
|
||||||
for(var e of row){
|
for(var e of row){
|
||||||
e.style.height = Math.floor(h * r) + 'px' }
|
e.style.height = (h * r) + 'px'
|
||||||
|
nw += e.offsetWidth }
|
||||||
// prep for next row...
|
// prep for next row...
|
||||||
if(!expanded_row){
|
if(!expanded_row){
|
||||||
w = elem.offsetWidth
|
w = elem.offsetWidth
|
||||||
@ -87,6 +93,7 @@ function(elem) {
|
|||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
// XXX add shift+arrow to select...
|
||||||
// XXX add home/end, pageup/pagedown...
|
// XXX add home/end, pageup/pagedown...
|
||||||
var keyboard = {
|
var keyboard = {
|
||||||
ArrowLeft: function(){
|
ArrowLeft: function(){
|
||||||
@ -108,8 +115,31 @@ var keyboard = {
|
|||||||
Enter: function(){
|
Enter: function(){
|
||||||
gallery.lightbox.toggle() },
|
gallery.lightbox.toggle() },
|
||||||
Escape: function(){
|
Escape: function(){
|
||||||
gallery.lightbox.shown
|
gallery.lightbox.shown ?
|
||||||
&& gallery.lightbox.hide() },
|
gallery.lightbox.hide()
|
||||||
|
// XXX should we remember which image was current and select
|
||||||
|
// it again when needed???
|
||||||
|
: gallery.deselect_current ?
|
||||||
|
(gallery.current = null)
|
||||||
|
: null },
|
||||||
|
// 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() } },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -117,6 +147,27 @@ var keyboard = {
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
var Gallery = {
|
var Gallery = {
|
||||||
|
|
||||||
|
// options...
|
||||||
|
//
|
||||||
|
deselect_current: true,
|
||||||
|
loop_images: true,
|
||||||
|
allow_row_expansion: true,
|
||||||
|
click_to_select: true,
|
||||||
|
|
||||||
|
|
||||||
|
code: `
|
||||||
|
<div class="gallery">
|
||||||
|
<!-- gallery: content -->
|
||||||
|
<div class="images">
|
||||||
|
</div>
|
||||||
|
<!-- lightbox -->
|
||||||
|
<div class="lightbox">
|
||||||
|
<img>
|
||||||
|
<div class="button close"></div>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
|
||||||
dom: undefined,
|
dom: undefined,
|
||||||
|
|
||||||
__lightbox: undefined,
|
__lightbox: undefined,
|
||||||
@ -131,44 +182,70 @@ var Gallery = {
|
|||||||
return undefined },
|
return undefined },
|
||||||
|
|
||||||
get current(){
|
get current(){
|
||||||
return this.dom.querySelector('img.current') },
|
return this.dom.querySelector('.images img.current') },
|
||||||
set current(img){
|
set current(img){
|
||||||
for(var i of this.dom.querySelectorAll('img.current')){
|
// unset...
|
||||||
|
if(img == null){
|
||||||
|
this.current?.classList.remove('current')
|
||||||
|
return }
|
||||||
|
// set...
|
||||||
|
for(var i of this.dom.querySelectorAll('.images img.current')){
|
||||||
i.classList.remove('current') }
|
i.classList.remove('current') }
|
||||||
img.classList.add('current')
|
img.classList.add('current')
|
||||||
|
// XXX add offsets from borders...
|
||||||
img.scrollIntoView({
|
img.scrollIntoView({
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
block: 'nearest',
|
block: 'nearest',
|
||||||
|
offset: 10,
|
||||||
}) },
|
}) },
|
||||||
|
|
||||||
|
// XXX should this be writable???
|
||||||
|
get images(){
|
||||||
|
return [...this.dom.querySelectorAll('.images img')] },
|
||||||
|
|
||||||
|
get urls(){
|
||||||
|
return this.images
|
||||||
|
.map(function(img){
|
||||||
|
// XXX not sure if we should remove the preview dir...
|
||||||
|
return img.src }) },
|
||||||
|
/*/
|
||||||
|
return img.src
|
||||||
|
// remove preview dir...
|
||||||
|
.replace(/\/[0-9]+px\//, '/') }) },
|
||||||
|
//*/
|
||||||
|
|
||||||
|
// XXX add .loop_images support...
|
||||||
getRow: function(img, direction='current'){
|
getRow: function(img, direction='current'){
|
||||||
if(['above', 'current', 'below'].includes(img)){
|
if(['above', 'current', 'below'].includes(img)){
|
||||||
direction = img
|
direction = img
|
||||||
img = null }
|
img = this.current }
|
||||||
// get above/below row...
|
// get above/below row...
|
||||||
// XXX these are wastefull...
|
// XXX these are wastefull...
|
||||||
if(direction == 'above'){
|
if(direction == 'above'){
|
||||||
var row = this.getRow(img)
|
var row = this.getRow(img)
|
||||||
var e = row[0].previousSibling
|
var e = row[0].previousElementSibling
|
||||||
while(e && e.tagName != 'IMG'){
|
while(e && e.tagName != 'IMG'){
|
||||||
e = e.previousSibling }
|
e = e.previousElementSibling }
|
||||||
return e ?
|
return e ?
|
||||||
this.getRow(e)
|
this.getRow(e)
|
||||||
: this.getRow([...this.dom.querySelectorAll('img')].at(-1))
|
: this.getRow(this.images.at(-1))
|
||||||
} else if(direction == 'below'){
|
} else if(direction == 'below'){
|
||||||
|
// special case: nothing selected...
|
||||||
|
if(img == null){
|
||||||
|
return this.getRow() }
|
||||||
var row = this.getRow(img)
|
var row = this.getRow(img)
|
||||||
var e = row.at(-1).nextSibling
|
var e = row.at(-1).nextElementSibling
|
||||||
while(e && e.tagName != 'IMG'){
|
while(e && e.tagName != 'IMG'){
|
||||||
e = e.nextSibling }
|
e = e.nextElementSibling }
|
||||||
return e ?
|
return e ?
|
||||||
this.getRow(e)
|
this.getRow(e)
|
||||||
: this.getRow([...this.dom.querySelectorAll('img')][1]) }
|
: this.getRow(this.images[0]) }
|
||||||
// get current row...
|
// get current row...
|
||||||
var cur = img
|
var cur = img
|
||||||
?? this.current
|
?? this.current
|
||||||
if(cur == null){
|
if(cur == null){
|
||||||
var scroll = getScrollParent(this.dom).scrollTop
|
var scroll = getScrollParent(this.dom).scrollTop
|
||||||
var images = [...this.dom.querySelectorAll('img')].slice(1)
|
var images = this.images
|
||||||
for(cur of images){
|
for(cur of images){
|
||||||
if(cur.offsetTop >= scroll){
|
if(cur.offsetTop >= scroll){
|
||||||
break } } }
|
break } } }
|
||||||
@ -177,17 +254,18 @@ var Gallery = {
|
|||||||
var e = cur
|
var e = cur
|
||||||
while(e && e.offsetTop == top){
|
while(e && e.offsetTop == top){
|
||||||
row.push(e)
|
row.push(e)
|
||||||
e = e.nextSibling
|
e = e.nextElementSibling
|
||||||
while(e && e.tagName != 'IMG'){
|
while(e && e.tagName != 'IMG'){
|
||||||
e = e.nextSibling } }
|
e = e.nextElementSibling } }
|
||||||
e = cur
|
e = cur
|
||||||
while(e && e.offsetTop == top){
|
while(e && e.offsetTop == top){
|
||||||
e === cur
|
e === cur
|
||||||
|| row.unshift(e)
|
|| row.unshift(e)
|
||||||
e = e.previousSibling
|
e = e.previousElementSibling
|
||||||
while(e && e.tagName != 'IMG'){
|
while(e && e.tagName != 'IMG'){
|
||||||
e = e.previousSibling } }
|
e = e.previousElementSibling } }
|
||||||
return row },
|
return row },
|
||||||
|
// XXX add .loop_images support...
|
||||||
getImage: function(img, direction='current'){
|
getImage: function(img, direction='current'){
|
||||||
if(['left', 'above', 'current', 'below', 'right'].includes(img)){
|
if(['left', 'above', 'current', 'below', 'right'].includes(img)){
|
||||||
direction = img
|
direction = img
|
||||||
@ -196,7 +274,7 @@ var Gallery = {
|
|||||||
if(direction == 'current'){
|
if(direction == 'current'){
|
||||||
return img
|
return img
|
||||||
?? this.current
|
?? this.current
|
||||||
?? this.getRow(img)
|
?? this.getRow(img)[0]
|
||||||
// above/below...
|
// above/below...
|
||||||
} else if(direction == 'above' || direction == 'below'){
|
} else if(direction == 'above' || direction == 'below'){
|
||||||
var row = this.getRow(direction)
|
var row = this.getRow(direction)
|
||||||
@ -231,8 +309,9 @@ var Gallery = {
|
|||||||
return target },
|
return target },
|
||||||
|
|
||||||
// XXX cache image list???
|
// XXX cache image list???
|
||||||
|
// XXX add .loop_images support...
|
||||||
prev: function(){
|
prev: function(){
|
||||||
var images = [...this.dom.querySelectorAll('img')].slice(1)
|
var images = this.images
|
||||||
var i = this.current == null ?
|
var i = this.current == null ?
|
||||||
images.length-1
|
images.length-1
|
||||||
: images.indexOf(this.current)-1
|
: images.indexOf(this.current)-1
|
||||||
@ -242,7 +321,7 @@ var Gallery = {
|
|||||||
this.current = images[i]
|
this.current = images[i]
|
||||||
return this },
|
return this },
|
||||||
next: function(){
|
next: function(){
|
||||||
var images = [...this.dom.querySelectorAll('img')].slice(1)
|
var images = this.images
|
||||||
var i = this.current == null ?
|
var i = this.current == null ?
|
||||||
0
|
0
|
||||||
: images.indexOf(this.current)+1
|
: images.indexOf(this.current)+1
|
||||||
@ -276,29 +355,115 @@ var Gallery = {
|
|||||||
this.current = this.getImage('below')
|
this.current = this.getImage('below')
|
||||||
return this },
|
return this },
|
||||||
|
|
||||||
// XXX
|
// selection...
|
||||||
select: function(){
|
get selected(){
|
||||||
},
|
return this.dom.querySelectorAll('.images img.selected') },
|
||||||
|
// NOTE: this is here because we can't use :before / :after directly
|
||||||
|
// on the img tag...
|
||||||
|
// XXX make this generic and use a .marks list...
|
||||||
|
updateMarkers: function(){
|
||||||
|
var that = this
|
||||||
|
// 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')
|
||||||
|
mark.addEventListener('click', function(evt){
|
||||||
|
evt.stopPropagation()
|
||||||
|
that.deselect(mark) })
|
||||||
|
img.after(mark) } }
|
||||||
|
// clear deselected...
|
||||||
|
for(var mark of this.dom.querySelectorAll('.images img:not(.selected)+.mark')){
|
||||||
|
mark.remove() }
|
||||||
|
// update lightbox...
|
||||||
|
this.lightbox.shown
|
||||||
|
&& this.lightbox.update()
|
||||||
|
return this },
|
||||||
|
select: function(img){
|
||||||
|
img = img ?? this.current
|
||||||
|
img?.classList.add('selected')
|
||||||
|
return this.updateMarkers() },
|
||||||
|
deselect: function(img){
|
||||||
|
img = img ?? this.current
|
||||||
|
img?.classList.remove('selected')
|
||||||
|
return this.updateMarkers() },
|
||||||
|
toggleSelect: function(img){
|
||||||
|
img = img ?? this.current
|
||||||
|
img?.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(){
|
show: function(){
|
||||||
this.lightbox.show()
|
this.lightbox.show()
|
||||||
return this },
|
return this },
|
||||||
|
|
||||||
// XXX
|
update: function(){
|
||||||
|
patchFlexRows(this.images, !this.allow_row_expansion)
|
||||||
|
return this },
|
||||||
|
|
||||||
load: function(urls){
|
load: function(urls){
|
||||||
},
|
this.clear()
|
||||||
|
var images = this.dom.querySelector('.images')
|
||||||
|
for(var url of urls){
|
||||||
|
var img = document.createElement('img')
|
||||||
|
img.src = url
|
||||||
|
images.appendChild(img) }
|
||||||
|
return this },
|
||||||
|
clear: function(){
|
||||||
|
this.dom.querySelector('.images').innerHTML = ''
|
||||||
|
return this },
|
||||||
|
|
||||||
setup: function(dom){
|
setup: function(dom){
|
||||||
var that = this
|
var that = this
|
||||||
this.dom = dom
|
this.dom = dom
|
||||||
|
|
||||||
this.dom.addEventListener('click', function(evt){
|
this.dom.querySelector('.images')
|
||||||
var target = evt.target
|
.addEventListener('click', function(evt){
|
||||||
if(target.tagName == 'IMG'
|
evt.stopPropagation()
|
||||||
// skip images in lightbox...
|
var target = evt.target
|
||||||
&& target.parentElement === that.dom){
|
if(target.tagName == 'IMG'){
|
||||||
that.current = target
|
// shift+click: toggle selections...
|
||||||
that.show() } })
|
if(evt.shiftKey){
|
||||||
return this },
|
that.toggleSelect(target)
|
||||||
|
// first click selects, second shows...
|
||||||
|
} else if(that.click_to_select){
|
||||||
|
target.classList.contains('current') ?
|
||||||
|
that.show()
|
||||||
|
: (that.current = target)
|
||||||
|
// first click selects and shows...
|
||||||
|
} else {
|
||||||
|
that.current = target
|
||||||
|
that.show() }
|
||||||
|
} else if(that.deselect_current){
|
||||||
|
that.current = null } })
|
||||||
|
this.dom
|
||||||
|
.addEventListener('click', function(evt){
|
||||||
|
that.deselect_current
|
||||||
|
&& (that.current = null) })
|
||||||
|
|
||||||
|
// handle resizing...
|
||||||
|
new ResizeObserver(
|
||||||
|
function(elems){
|
||||||
|
that.update() })
|
||||||
|
.observe(this.dom)
|
||||||
|
|
||||||
|
return this
|
||||||
|
.update() },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -326,12 +491,24 @@ var Lightbox = {
|
|||||||
&& this.cache() },
|
&& this.cache() },
|
||||||
|
|
||||||
get shown(){
|
get shown(){
|
||||||
return this.dom.style.display == 'block' },
|
return this.gallery.dom.classList.contains('lightboxed') },
|
||||||
show: function(url){
|
show: function(url){
|
||||||
this.url = url
|
this.url = url
|
||||||
?? (this.gallery.current
|
?? (this.gallery.current
|
||||||
?? this.gallery.next().current
|
?? this.gallery.next().current
|
||||||
?? {}).src
|
?? {}).src
|
||||||
|
this.update()
|
||||||
|
this.gallery.dom.classList.add('lightboxed')
|
||||||
|
return this },
|
||||||
|
hide: function(){
|
||||||
|
this.gallery.dom.classList.remove('lightboxed')
|
||||||
|
return this },
|
||||||
|
toggle: function(){
|
||||||
|
return this.shown ?
|
||||||
|
this.hide()
|
||||||
|
: this.show() },
|
||||||
|
|
||||||
|
update: function(){
|
||||||
// set caption...
|
// set caption...
|
||||||
this.dom.setAttribute('caption',
|
this.dom.setAttribute('caption',
|
||||||
(this.gallery.current
|
(this.gallery.current
|
||||||
@ -339,15 +516,11 @@ var Lightbox = {
|
|||||||
?? {})
|
?? {})
|
||||||
.getAttribute('caption')
|
.getAttribute('caption')
|
||||||
?? '')
|
?? '')
|
||||||
this.dom.style.display = 'block'
|
// set selection...
|
||||||
|
this.gallery.current.classList.contains('selected') ?
|
||||||
|
this.dom.classList.add('selected')
|
||||||
|
: this.dom.classList.remove('selected')
|
||||||
return this },
|
return this },
|
||||||
hide: function(){
|
|
||||||
this.dom.style.display = ''
|
|
||||||
return this },
|
|
||||||
toggle: function(){
|
|
||||||
return this.shown ?
|
|
||||||
this.hide()
|
|
||||||
: this.show() },
|
|
||||||
|
|
||||||
prev: function(){
|
prev: function(){
|
||||||
this.gallery.prev().show()
|
this.gallery.prev().show()
|
||||||
@ -392,13 +565,14 @@ var Lightbox = {
|
|||||||
var deadzone = this.navigation_deadzone ?? 100
|
var deadzone = this.navigation_deadzone ?? 100
|
||||||
this.dom
|
this.dom
|
||||||
.addEventListener('click', function(evt){
|
.addEventListener('click', function(evt){
|
||||||
|
evt.stopPropagation()
|
||||||
// click left/right side of view...
|
// click left/right side of view...
|
||||||
// NOTE: this is vewport-relative...
|
// NOTE: this is vewport-relative...
|
||||||
evt.clientX < that.dom.offsetWidth / 2 - deadzone/2
|
evt.clientX < that.dom.offsetWidth / 2 - deadzone/2
|
||||||
&& that.prev()
|
&& that.prev()
|
||||||
evt.clientX > that.dom.offsetWidth / 2 + deadzone/2
|
evt.clientX > that.dom.offsetWidth / 2 + deadzone/2
|
||||||
&& that.next() })
|
&& that.next() })
|
||||||
// mouseofver...
|
// mousemove...
|
||||||
var hysteresis = this.caption_hysteresis ?? 10
|
var hysteresis = this.caption_hysteresis ?? 10
|
||||||
this.dom
|
this.dom
|
||||||
.addEventListener('mousemove', function(evt){
|
.addEventListener('mousemove', function(evt){
|
||||||
@ -435,8 +609,6 @@ var setupGallery = function(gallery){
|
|||||||
.setup(gallery) }
|
.setup(gallery) }
|
||||||
|
|
||||||
var setup = function(){
|
var setup = function(){
|
||||||
patchFlexRows([...document.querySelectorAll('.gallery>img')])
|
|
||||||
|
|
||||||
var galleries = document.body.querySelectorAll('.gallery')
|
var galleries = document.body.querySelectorAll('.gallery')
|
||||||
for(var gallery of galleries){
|
for(var gallery of galleries){
|
||||||
// XXX this is wrong...
|
// XXX this is wrong...
|
||||||
@ -445,10 +617,7 @@ var setup = function(){
|
|||||||
document.addEventListener('keydown', function(evt){
|
document.addEventListener('keydown', function(evt){
|
||||||
var key = evt.key
|
var key = evt.key
|
||||||
if(key in keyboard){
|
if(key in keyboard){
|
||||||
keyboard[key](evt) } })
|
keyboard[key](evt) } }) }
|
||||||
window.addEventListener('resize', function(){
|
|
||||||
patchFlexRows([...document.querySelectorAll('.gallery>img')]) })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user