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;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* marker: selected */
|
/* marker: marked */
|
||||||
.gallery .images img+.mark.selected:after {
|
.gallery .images img+.mark.marked:after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
- drop files/images
|
- drop files/images
|
||||||
- drag to sort
|
- drag to sort
|
||||||
- <s>Gallery: remove image</s>
|
- <s>Gallery: remove image</s>
|
||||||
- mark images for deletion + delete marked
|
- UI: mark images for deletion + delete marked
|
||||||
- <s>Gallery: serialize / deserialize</s>
|
- <s>Gallery: serialize / deserialize</s>
|
||||||
- <s>Lightbox: navigation (keyboard / mouse)</s>
|
- <s>Lightbox: navigation (keyboard / mouse)</s>
|
||||||
- <s>Lightbox: fullscreen mode</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 =
|
var patchFlexRows =
|
||||||
function(elems, prevent_row_expansion=false){
|
function(elems, prevent_row_expansion=false, last_row_resize=1.5){
|
||||||
if(elems.length == 0){
|
if(elems.length == 0){
|
||||||
return }
|
return }
|
||||||
// NOTE: -1 here is to compensate for rounding errors...
|
// NOTE: -1 here is to compensate for rounding errors...
|
||||||
@ -28,7 +27,44 @@ function(elems, prevent_row_expansion=false){
|
|||||||
var h
|
var h
|
||||||
var row = []
|
var row = []
|
||||||
var top = elems[0].offsetTop
|
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){
|
for(var elem of elems){
|
||||||
elem.style.height = ''
|
elem.style.height = ''
|
||||||
elem.style.width = ''
|
elem.style.width = ''
|
||||||
@ -40,26 +76,12 @@ function(elems, prevent_row_expansion=false){
|
|||||||
if(elem.offsetTop == top){
|
if(elem.offsetTop == top){
|
||||||
w += elem.offsetWidth
|
w += elem.offsetWidth
|
||||||
row.push(elem)
|
row.push(elem)
|
||||||
// row donw + prep for next...
|
// row done + prep for next...
|
||||||
} else {
|
} 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 =
|
var expanded_row =
|
||||||
prevent_row_expansion ?
|
prevent_row_expansion ?
|
||||||
false
|
handleRow()
|
||||||
: 1/r1 < r2
|
: handleRow('expand')
|
||||||
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 }
|
|
||||||
// prep for next row...
|
// prep for next row...
|
||||||
if(!expanded_row){
|
if(!expanded_row){
|
||||||
w = elem.offsetWidth
|
w = elem.offsetWidth
|
||||||
@ -70,7 +92,10 @@ function(elems, prevent_row_expansion=false){
|
|||||||
w = 0
|
w = 0
|
||||||
h = null
|
h = null
|
||||||
top = null
|
top = null
|
||||||
row = [] }}}}
|
row = [] }}}
|
||||||
|
// handle last row...
|
||||||
|
last_row_resize
|
||||||
|
&& handleRow(last_row_resize) }
|
||||||
|
|
||||||
var getScrollParent =
|
var getScrollParent =
|
||||||
function(elem){
|
function(elem){
|
||||||
@ -125,14 +150,14 @@ var keyboard = {
|
|||||||
gallery.lightbox.hide()
|
gallery.lightbox.hide()
|
||||||
// XXX should we remember which image was current and select
|
// XXX should we remember which image was current and select
|
||||||
// it again when needed???
|
// it again when needed???
|
||||||
: gallery.deselect_current ?
|
: gallery.unmark_current ?
|
||||||
(gallery.current = null)
|
(gallery.current = null)
|
||||||
: null },
|
: null },
|
||||||
// selection...
|
// selection...
|
||||||
' ': function(evt){
|
' ': function(evt){
|
||||||
gallery.current
|
gallery.current
|
||||||
&& evt.preventDefault()
|
&& evt.preventDefault()
|
||||||
gallery.toggleSelect() },
|
gallery.toggleMark() },
|
||||||
// XXX use key codes...
|
// XXX use key codes...
|
||||||
'a': function(evt){
|
'a': function(evt){
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
@ -141,11 +166,11 @@ var keyboard = {
|
|||||||
'd': function(evt){
|
'd': function(evt){
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
if(evt.ctrlKey){
|
if(evt.ctrlKey){
|
||||||
gallery.deselectAll() } },
|
gallery.unmarkAll() } },
|
||||||
'i': function(evt){
|
'i': function(evt){
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
if(evt.ctrlKey){
|
if(evt.ctrlKey){
|
||||||
gallery.selectInverse() } },
|
gallery.markInverse() } },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -156,16 +181,33 @@ var Gallery = {
|
|||||||
|
|
||||||
// Options...
|
// Options...
|
||||||
//
|
//
|
||||||
deselect_current: true,
|
unmark_current: true,
|
||||||
|
|
||||||
// If true navigation will loop over top/bottom rows and first/last
|
// If true navigation will loop over top/bottom rows and first/last
|
||||||
// images...
|
// images...
|
||||||
// This is mainly usefull for small galleries that do not need paging.
|
// 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,
|
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,
|
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,
|
click_to_select: true,
|
||||||
|
|
||||||
exit_fullscreen_on_lightbox_close: true,
|
exit_fullscreen_on_lightbox_close: true,
|
||||||
@ -261,6 +303,9 @@ var Gallery = {
|
|||||||
.replace(/\/[0-9]+px\//, '/') }) },
|
.replace(/\/[0-9]+px\//, '/') }) },
|
||||||
//*/
|
//*/
|
||||||
|
|
||||||
|
get marked(){
|
||||||
|
return [...this.dom.querySelectorAll('.images img.marked')] },
|
||||||
|
|
||||||
get length(){
|
get length(){
|
||||||
return this.images.length },
|
return this.images.length },
|
||||||
get index(){
|
get index(){
|
||||||
@ -283,7 +328,7 @@ var Gallery = {
|
|||||||
this.getRow(this.images.at(-1))
|
this.getRow(this.images.at(-1))
|
||||||
: undefined
|
: undefined
|
||||||
} else if(direction == 'below'){
|
} else if(direction == 'below'){
|
||||||
// special case: nothing selected...
|
// special case: nothing marked...
|
||||||
if(img == null){
|
if(img == null){
|
||||||
return this.getRow() }
|
return this.getRow() }
|
||||||
var row = this.getRow(img)
|
var row = this.getRow(img)
|
||||||
@ -434,56 +479,55 @@ var Gallery = {
|
|||||||
return this },
|
return this },
|
||||||
|
|
||||||
// selection...
|
// selection...
|
||||||
get selected(){
|
//
|
||||||
return this.dom.querySelectorAll('.images img.selected') },
|
|
||||||
// NOTE: this is here because we can't use :before / :after directly
|
// NOTE: this is here because we can't use :before / :after directly
|
||||||
// on the img tag...
|
// on the img tag...
|
||||||
// XXX make this generic and use a .marks list...
|
// XXX make this generic and use a .marks list...
|
||||||
updateMarkers: function(){
|
updateMarkers: function(){
|
||||||
var that = this
|
var that = this
|
||||||
// select...
|
// 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
|
var mark = img.nextElementSibling
|
||||||
while(mark && mark.tagName != 'IMG' && !mark.classList.contains('mark')){
|
while(mark && mark.tagName != 'IMG' && !mark.classList.contains('mark')){
|
||||||
mark = img.nextElementSibling }
|
mark = img.nextElementSibling }
|
||||||
if(!mark || !mark.classList.contains('mark')){
|
if(!mark || !mark.classList.contains('mark')){
|
||||||
mark = document.createElement('div')
|
mark = document.createElement('div')
|
||||||
mark.classList.add('selected', 'mark')
|
mark.classList.add('marked', 'mark')
|
||||||
mark.addEventListener('click', function(evt){
|
mark.addEventListener('click', function(evt){
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
that.deselect(mark) })
|
that.unmark(mark) })
|
||||||
img.after(mark) } }
|
img.after(mark) } }
|
||||||
// clear deselected...
|
// clear unmarked...
|
||||||
for(var mark of this.dom.querySelectorAll('.images img:not(.selected)+.mark')){
|
for(var mark of this.dom.querySelectorAll('.images img:not(.marked)+.mark')){
|
||||||
mark.remove() }
|
mark.remove() }
|
||||||
// update lightbox...
|
// update lightbox...
|
||||||
this.lightbox.shown
|
this.lightbox.shown
|
||||||
&& this.lightbox.update()
|
&& this.lightbox.update()
|
||||||
return this },
|
return this },
|
||||||
select: function(img){
|
mark: function(img){
|
||||||
img = img ?? this.current
|
img = img ?? this.current
|
||||||
img?.classList.add('selected')
|
img?.classList.add('marked')
|
||||||
return this.updateMarkers() },
|
return this.updateMarkers() },
|
||||||
deselect: function(img){
|
unmark: function(img){
|
||||||
img = img ?? this.current
|
img = img ?? this.current
|
||||||
img?.classList.remove('selected')
|
img?.classList.remove('marked')
|
||||||
return this.updateMarkers() },
|
return this.updateMarkers() },
|
||||||
toggleSelect: function(img){
|
toggleMark: function(img){
|
||||||
img = img ?? this.current
|
img = img ?? this.current
|
||||||
img?.classList.toggle('selected')
|
img?.classList.toggle('marked')
|
||||||
this.updateMarkers()
|
this.updateMarkers()
|
||||||
return this },
|
return this },
|
||||||
selectAll: function(){
|
selectAll: function(){
|
||||||
for(var img of this.images){
|
for(var img of this.images){
|
||||||
img.classList.add('selected') }
|
img.classList.add('marked') }
|
||||||
return this.updateMarkers() },
|
return this.updateMarkers() },
|
||||||
deselectAll: function(){
|
unmarkAll: function(){
|
||||||
for(var img of this.images){
|
for(var img of this.images){
|
||||||
img.classList.remove('selected') }
|
img.classList.remove('marked') }
|
||||||
return this.updateMarkers() },
|
return this.updateMarkers() },
|
||||||
selectInverse: function(){
|
markInverse: function(){
|
||||||
for(var img of this.images){
|
for(var img of this.images){
|
||||||
img.classList.toggle('selected') }
|
img.classList.toggle('marked') }
|
||||||
return this.updateMarkers() },
|
return this.updateMarkers() },
|
||||||
|
|
||||||
show: function(){
|
show: function(){
|
||||||
@ -491,7 +535,9 @@ var Gallery = {
|
|||||||
return this },
|
return this },
|
||||||
|
|
||||||
update: function(){
|
update: function(){
|
||||||
patchFlexRows(this.images, !this.allow_row_expansion)
|
patchFlexRows(this.images,
|
||||||
|
!this.allow_row_expansion,
|
||||||
|
this.last_row_resize ?? 1.2)
|
||||||
return this },
|
return this },
|
||||||
|
|
||||||
// .load(<image>)
|
// .load(<image>)
|
||||||
@ -546,9 +592,17 @@ var Gallery = {
|
|||||||
'caption',
|
'caption',
|
||||||
],
|
],
|
||||||
// XXX do we handle previews here???
|
// XXX do we handle previews here???
|
||||||
json: function(){
|
json: function(images=undefined){
|
||||||
var that = this
|
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){
|
.map(function(img){
|
||||||
var res = { url: img.src }
|
var res = { url: img.src }
|
||||||
for(var key of that.__image_attributes__){
|
for(var key of that.__image_attributes__){
|
||||||
@ -589,7 +643,7 @@ var Gallery = {
|
|||||||
if(target.tagName == 'IMG'){
|
if(target.tagName == 'IMG'){
|
||||||
// shift+click: toggle selections...
|
// shift+click: toggle selections...
|
||||||
if(evt.shiftKey){
|
if(evt.shiftKey){
|
||||||
that.toggleSelect(target)
|
that.toggleMark(target)
|
||||||
// first click selects, second shows...
|
// first click selects, second shows...
|
||||||
} else if(that.click_to_select){
|
} else if(that.click_to_select){
|
||||||
target.classList.contains('current') ?
|
target.classList.contains('current') ?
|
||||||
@ -599,11 +653,11 @@ var Gallery = {
|
|||||||
} else {
|
} else {
|
||||||
that.current = target
|
that.current = target
|
||||||
that.show() }
|
that.show() }
|
||||||
} else if(that.deselect_current){
|
} else if(that.unmark_current){
|
||||||
that.current = null } })
|
that.current = null } })
|
||||||
this.dom
|
this.dom
|
||||||
.addEventListener('click', function(evt){
|
.addEventListener('click', function(evt){
|
||||||
that.deselect_current
|
that.unmark_current
|
||||||
&& (that.current = null) })
|
&& (that.current = null) })
|
||||||
// drag...
|
// drag...
|
||||||
this.dom
|
this.dom
|
||||||
@ -692,9 +746,9 @@ var Lightbox = {
|
|||||||
.replace(/\${CAPTION}/, caption)
|
.replace(/\${CAPTION}/, caption)
|
||||||
.replace(/\${INDEX}/, index))
|
.replace(/\${INDEX}/, index))
|
||||||
// set selection...
|
// set selection...
|
||||||
this.gallery.current.classList.contains('selected') ?
|
this.gallery.current.classList.contains('marked') ?
|
||||||
this.dom.classList.add('selected')
|
this.dom.classList.add('marked')
|
||||||
: this.dom.classList.remove('selected')
|
: this.dom.classList.remove('marked')
|
||||||
return this },
|
return this },
|
||||||
|
|
||||||
prev: function(){
|
prev: function(){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user