better last row resizing + docs...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
cafb50054c
commit
fd3d2d2e5e
@ -129,8 +129,8 @@ body {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* marker: selected */
|
||||
.gallery .images img+.mark.selected:after {
|
||||
/* marker: marked */
|
||||
.gallery .images img+.mark.marked:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
- drop files/images
|
||||
- drag to sort
|
||||
- <s>Gallery: remove image</s>
|
||||
- mark images for deletion + delete marked
|
||||
- UI: mark images for deletion + delete marked
|
||||
- <s>Gallery: serialize / deserialize</s>
|
||||
- <s>Lightbox: navigation (keyboard / mouse)</s>
|
||||
- <s>Lightbox: fullscreen mode</s>
|
||||
|
||||
164
grid-n-view.js
164
grid-n-view.js
@ -17,9 +17,8 @@
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// XXX need to account for scrollbar -- add hysteresis???
|
||||
var patchFlexRows =
|
||||
function(elems, prevent_row_expansion=false){
|
||||
function(elems, prevent_row_expansion=false, last_row_resize=1.5){
|
||||
if(elems.length == 0){
|
||||
return }
|
||||
// NOTE: -1 here is to compensate for rounding errors...
|
||||
@ -28,7 +27,44 @@ function(elems, prevent_row_expansion=false){
|
||||
var h
|
||||
var row = []
|
||||
var top = elems[0].offsetTop
|
||||
// NOTE: this will by design skip the last row.
|
||||
// modes:
|
||||
// 'as-is' | false
|
||||
// 'expand'
|
||||
// 'close'
|
||||
// closure: W, w, h, row, elem
|
||||
var max = 0
|
||||
var handleRow = function(mode='justify'){
|
||||
if(!mode || mode == 'as-is'){
|
||||
return false }
|
||||
|
||||
if(typeof(mode) == 'number'){
|
||||
var r = Math.min(
|
||||
W / w,
|
||||
max * mode)
|
||||
} else {
|
||||
var r = W / w }
|
||||
|
||||
var expanded
|
||||
if(mode == 'expand'){
|
||||
var r2 = W / (w + elem.offsetWidth)
|
||||
// NOTE: we are checking which will require a lesser resize
|
||||
// the current row or it with the next image...
|
||||
if(1/r < r2){
|
||||
expanded = true
|
||||
var r = r2
|
||||
row.push(elem) } }
|
||||
|
||||
max = Math.max(max, r)
|
||||
|
||||
// patch the row...
|
||||
var nw = 0
|
||||
for(var e of row){
|
||||
e.style.height = (h * r) + 'px'
|
||||
nw += e.offsetWidth }
|
||||
return !!expanded }
|
||||
// NOTE: this will by design skip the last row...
|
||||
// ...because we handle the row only when we see an image at a
|
||||
// different vertical offset...
|
||||
for(var elem of elems){
|
||||
elem.style.height = ''
|
||||
elem.style.width = ''
|
||||
@ -40,26 +76,12 @@ function(elems, prevent_row_expansion=false){
|
||||
if(elem.offsetTop == top){
|
||||
w += elem.offsetWidth
|
||||
row.push(elem)
|
||||
// row donw + prep for next...
|
||||
// row done + prep for next...
|
||||
} else {
|
||||
// NOTE: we are checking which will require a lesser resize
|
||||
// the current row or it with the next image...
|
||||
var r1 = W / w
|
||||
var r2 = W / (w + elem.offsetWidth)
|
||||
var expanded_row =
|
||||
prevent_row_expansion ?
|
||||
false
|
||||
: 1/r1 < r2
|
||||
if(!expanded_row){
|
||||
var r = r1
|
||||
} else {
|
||||
var r = r2
|
||||
row.push(elem) }
|
||||
// patch the row...
|
||||
var nw = 0
|
||||
for(var e of row){
|
||||
e.style.height = (h * r) + 'px'
|
||||
nw += e.offsetWidth }
|
||||
handleRow()
|
||||
: handleRow('expand')
|
||||
// prep for next row...
|
||||
if(!expanded_row){
|
||||
w = elem.offsetWidth
|
||||
@ -70,7 +92,10 @@ function(elems, prevent_row_expansion=false){
|
||||
w = 0
|
||||
h = null
|
||||
top = null
|
||||
row = [] }}}}
|
||||
row = [] }}}
|
||||
// handle last row...
|
||||
last_row_resize
|
||||
&& handleRow(last_row_resize) }
|
||||
|
||||
var getScrollParent =
|
||||
function(elem){
|
||||
@ -125,14 +150,14 @@ var keyboard = {
|
||||
gallery.lightbox.hide()
|
||||
// XXX should we remember which image was current and select
|
||||
// it again when needed???
|
||||
: gallery.deselect_current ?
|
||||
: gallery.unmark_current ?
|
||||
(gallery.current = null)
|
||||
: null },
|
||||
// selection...
|
||||
' ': function(evt){
|
||||
gallery.current
|
||||
&& evt.preventDefault()
|
||||
gallery.toggleSelect() },
|
||||
gallery.toggleMark() },
|
||||
// XXX use key codes...
|
||||
'a': function(evt){
|
||||
evt.preventDefault()
|
||||
@ -141,11 +166,11 @@ var keyboard = {
|
||||
'd': function(evt){
|
||||
evt.preventDefault()
|
||||
if(evt.ctrlKey){
|
||||
gallery.deselectAll() } },
|
||||
gallery.unmarkAll() } },
|
||||
'i': function(evt){
|
||||
evt.preventDefault()
|
||||
if(evt.ctrlKey){
|
||||
gallery.selectInverse() } },
|
||||
gallery.markInverse() } },
|
||||
}
|
||||
|
||||
|
||||
@ -156,16 +181,33 @@ var Gallery = {
|
||||
|
||||
// Options...
|
||||
//
|
||||
deselect_current: true,
|
||||
unmark_current: true,
|
||||
|
||||
// If true navigation will loop over top/bottom rows and first/last
|
||||
// images...
|
||||
// This is mainly usefull for small galleries that do not need paging.
|
||||
// XXX might be a good idea to autodisable this when paging is required.
|
||||
// XXX might be a good idea to auto-disable this when paging is required.
|
||||
loop_images: false,
|
||||
|
||||
// If true for each row two versions will be compared, as-is and with
|
||||
// one image from the next row and the closest resiae will be chosen.
|
||||
//
|
||||
// This produses a more uniform image grid but will have greater
|
||||
// effect on gallery height / slower.
|
||||
allow_row_expansion: true,
|
||||
|
||||
// define how to handle last row
|
||||
//
|
||||
// can be:
|
||||
// 'as-is' - do not resize
|
||||
// 'justify' - fit width
|
||||
// <number> - maximum ration relative to largest row (must be >=1)
|
||||
//
|
||||
// Recomended value close to 1
|
||||
last_row_resize: 1,
|
||||
|
||||
// If true first click on image will select it the second click will
|
||||
// open it...
|
||||
click_to_select: true,
|
||||
|
||||
exit_fullscreen_on_lightbox_close: true,
|
||||
@ -261,6 +303,9 @@ var Gallery = {
|
||||
.replace(/\/[0-9]+px\//, '/') }) },
|
||||
//*/
|
||||
|
||||
get marked(){
|
||||
return [...this.dom.querySelectorAll('.images img.marked')] },
|
||||
|
||||
get length(){
|
||||
return this.images.length },
|
||||
get index(){
|
||||
@ -283,7 +328,7 @@ var Gallery = {
|
||||
this.getRow(this.images.at(-1))
|
||||
: undefined
|
||||
} else if(direction == 'below'){
|
||||
// special case: nothing selected...
|
||||
// special case: nothing marked...
|
||||
if(img == null){
|
||||
return this.getRow() }
|
||||
var row = this.getRow(img)
|
||||
@ -434,56 +479,55 @@ var Gallery = {
|
||||
return this },
|
||||
|
||||
// selection...
|
||||
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')){
|
||||
for(var img of this.dom.querySelectorAll('.images img.marked')){
|
||||
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.classList.add('marked', 'mark')
|
||||
mark.addEventListener('click', function(evt){
|
||||
evt.stopPropagation()
|
||||
that.deselect(mark) })
|
||||
that.unmark(mark) })
|
||||
img.after(mark) } }
|
||||
// clear deselected...
|
||||
for(var mark of this.dom.querySelectorAll('.images img:not(.selected)+.mark')){
|
||||
// clear unmarked...
|
||||
for(var mark of this.dom.querySelectorAll('.images img:not(.marked)+.mark')){
|
||||
mark.remove() }
|
||||
// update lightbox...
|
||||
this.lightbox.shown
|
||||
&& this.lightbox.update()
|
||||
return this },
|
||||
select: function(img){
|
||||
mark: function(img){
|
||||
img = img ?? this.current
|
||||
img?.classList.add('selected')
|
||||
img?.classList.add('marked')
|
||||
return this.updateMarkers() },
|
||||
deselect: function(img){
|
||||
unmark: function(img){
|
||||
img = img ?? this.current
|
||||
img?.classList.remove('selected')
|
||||
img?.classList.remove('marked')
|
||||
return this.updateMarkers() },
|
||||
toggleSelect: function(img){
|
||||
toggleMark: function(img){
|
||||
img = img ?? this.current
|
||||
img?.classList.toggle('selected')
|
||||
img?.classList.toggle('marked')
|
||||
this.updateMarkers()
|
||||
return this },
|
||||
selectAll: function(){
|
||||
for(var img of this.images){
|
||||
img.classList.add('selected') }
|
||||
img.classList.add('marked') }
|
||||
return this.updateMarkers() },
|
||||
deselectAll: function(){
|
||||
unmarkAll: function(){
|
||||
for(var img of this.images){
|
||||
img.classList.remove('selected') }
|
||||
img.classList.remove('marked') }
|
||||
return this.updateMarkers() },
|
||||
selectInverse: function(){
|
||||
markInverse: function(){
|
||||
for(var img of this.images){
|
||||
img.classList.toggle('selected') }
|
||||
img.classList.toggle('marked') }
|
||||
return this.updateMarkers() },
|
||||
|
||||
show: function(){
|
||||
@ -491,7 +535,9 @@ var Gallery = {
|
||||
return this },
|
||||
|
||||
update: function(){
|
||||
patchFlexRows(this.images, !this.allow_row_expansion)
|
||||
patchFlexRows(this.images,
|
||||
!this.allow_row_expansion,
|
||||
this.last_row_resize ?? 1.2)
|
||||
return this },
|
||||
|
||||
// .load(<image>)
|
||||
@ -546,9 +592,17 @@ var Gallery = {
|
||||
'caption',
|
||||
],
|
||||
// XXX do we handle previews here???
|
||||
json: function(){
|
||||
json: function(images=undefined){
|
||||
var that = this
|
||||
return this.images
|
||||
images =
|
||||
(images == 'all' || images == '*') ?
|
||||
this.images
|
||||
: images == 'marked' ?
|
||||
this.marked
|
||||
: !images ?
|
||||
this.images
|
||||
: images
|
||||
return images
|
||||
.map(function(img){
|
||||
var res = { url: img.src }
|
||||
for(var key of that.__image_attributes__){
|
||||
@ -589,7 +643,7 @@ var Gallery = {
|
||||
if(target.tagName == 'IMG'){
|
||||
// shift+click: toggle selections...
|
||||
if(evt.shiftKey){
|
||||
that.toggleSelect(target)
|
||||
that.toggleMark(target)
|
||||
// first click selects, second shows...
|
||||
} else if(that.click_to_select){
|
||||
target.classList.contains('current') ?
|
||||
@ -599,11 +653,11 @@ var Gallery = {
|
||||
} else {
|
||||
that.current = target
|
||||
that.show() }
|
||||
} else if(that.deselect_current){
|
||||
} else if(that.unmark_current){
|
||||
that.current = null } })
|
||||
this.dom
|
||||
.addEventListener('click', function(evt){
|
||||
that.deselect_current
|
||||
that.unmark_current
|
||||
&& (that.current = null) })
|
||||
// drag...
|
||||
this.dom
|
||||
@ -692,9 +746,9 @@ var Lightbox = {
|
||||
.replace(/\${CAPTION}/, caption)
|
||||
.replace(/\${INDEX}/, index))
|
||||
// set selection...
|
||||
this.gallery.current.classList.contains('selected') ?
|
||||
this.dom.classList.add('selected')
|
||||
: this.dom.classList.remove('selected')
|
||||
this.gallery.current.classList.contains('marked') ?
|
||||
this.dom.classList.add('marked')
|
||||
: this.dom.classList.remove('marked')
|
||||
return this },
|
||||
|
||||
prev: function(){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user