Merge branch 'master' of github.com:flynx/ImageGrid

This commit is contained in:
Alex A. Naanou 2019-10-02 02:55:55 +03:00
commit c09b055ee5
8 changed files with 441 additions and 93 deletions

View File

@ -1,5 +1,18 @@
sync-flash.sh
Syncs a camera flash card to an archive folder.
Dependencies:
- process-archive.sh
- compress-archive.sh (optional)
- bash
For more info see:
sync-flash.sh --help
process-archive.sh process-archive.sh
Processes and prepares the archive folder for viewing. Processes and prepares the archive folder for viewing via
ImageGrid.Viewer.
Dependencies: Dependencies:
- exiftool - exiftool
@ -9,17 +22,19 @@ process-archive.sh
XXX add self dependency check... XXX add self dependency check...
For more info see:
process-archive.bat -- windows version of process-archive.sh (partial) process-archive.sh --help
sync-flash.sh compress-archive.sh
Syncs a camera flash card to an archive folder. compresses raw files.
By default this will NTFS compress sony ARW files, but other
compression methods and raw formats are supported...
For more info see:
compress-archive.sh --help
Dependencies:
- process-archive.sh
- bash
update-exif.sh update-exif.sh
Updates processed preview metadata from appropriate .PSD files. Updates processed preview metadata from appropriate .PSD files.
@ -27,6 +42,12 @@ update-exif.sh
Dependencies: Dependencies:
- exiv2 (to be deprecated) - exiv2 (to be deprecated)
For more info see:
update-exif.sh --help
---
flatten.sh flatten.sh
Flatten flickr/instagram favorite folder structure created by Flatten flickr/instagram favorite folder structure created by
@ -34,11 +55,13 @@ flatten.sh
./<author>/<filename> -> ./ALL/<author> - <filename> ./<author>/<filename> -> ./ALL/<author> - <filename>
vips-tn.sh vips-tn.sh
cleannwcache.bat cleannwcache.bat
extract-metadata.sh extract-metadata.sh
process-archive.bat -- windows version of process-archive.sh (partial)

View File

@ -29,11 +29,11 @@ printhelp(){
echo "Arguments:" echo "Arguments:"
echo " -h --help - print this help and exit." echo " -h --help - print this help and exit."
echo echo
echo " -bz -bzip2 - use bzip2 to compress (default)." echo " -bz -bzip2 - use bzip2 to compress`[[ $ARCH == $ARCH_BZIP2 ]] && echo " (default)" || echo ""`."
echo " -gz -gzip - use gzip to compress." echo " -gz -gzip - use gzip to compress`[[ $ARCH == $ARCH_GZIP ]] && echo " (default)" || echo ""`."
echo " -c -compact - use ntfs compression." echo " -c -compact - use ntfs compression`[[ $ARCH == $ARCH_NTFS ]] && echo " (default)" || echo ""`."
echo echo
echo " -ext EXT - set file extension to compress (default: ARW)" echo " -ext EXT - set file extension to compress (default: ${EXT})"
echo " NOTE: only one -ext is supported now". echo " NOTE: only one -ext is supported now".
echo echo
} }

View File

@ -5,7 +5,8 @@ COUNT=1
TITLE="" TITLE=""
RSYNC=rsync RSYNC=rsync
RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable" #RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
RSYNCFLAGS="-arpt --info=progress2,flist --human-readable"
CP=cp CP=cp
CPFLAGS=-Rpfv CPFLAGS=-Rpfv
@ -14,6 +15,10 @@ CPFLAGS=-Rpfv
COPY=$RSYNC COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS COPYFLAGS=$RSYNCFLAGS
COMPRESSOR=./compress-archive.sh
COMPRESS=1
# base mount dir... # base mount dir...
# systems with /mnt # systems with /mnt
if [ -d /mnt ] ; then if [ -d /mnt ] ; then
@ -40,10 +45,20 @@ while true ; do
echo " single shoot." echo " single shoot."
echo " -l|-last last flash card in set, run" echo " -l|-last last flash card in set, run"
echo " process-archive.sh after copying." echo " process-archive.sh after copying."
echo " -b|-base the base dir to look for drives in" echo " -b|-base BASE the base dir to look for drives in"
echo " default: $BASE" echo " default: $BASE"
echo " --rsync use rsync (default)" echo " --rsync use rsync (default)"
echo " --cp use cp" echo " --cp use cp"
if ! [ -z $COMPRESSOR ] ; then
echo " --compress toggle archive compression"
echo " default: `[[ $COMPRESS ]] && echo "on" || echo "off"`"
fi
# notes...
echo
if ! [ -z $COMPRESSOR ] ; then
echo "NOTE: the index is fully usable during the compression stage"
fi
echo "NOTE: cp under Cygwin may messup permissions, use rsync."
echo echo
exit exit
;; ;;
@ -61,17 +76,24 @@ while true ; do
shift shift
;; ;;
-b|-base|--base) -b|-base|--base)
BASE=1 BASE=$2
shift shift 2
;; ;;
-cp|--cp) -cp|--cp)
COPY=cp COPY=cp
COPYFLAGS=-Rpfv COPYFLAGS=-Rpfv
shift
break break
;; ;;
-rsync|--rsync) -rsync|--rsync)
COPY=$RSYNC COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS COPYFLAGS=$RSYNCFLAGS
shift
break
;;
-compress|--compress)
COMPRESS=`[[ $COMPRESS ]] && echo "" || echo 1`
shift
break break
;; ;;
*) *)
@ -99,7 +121,12 @@ while true ; do
echo "Enter) copy drive ${DRIVE}" echo "Enter) copy drive ${DRIVE}"
fi fi
echo "2) build." echo "2) build."
echo "3) quit." if ! [ -z $COMPRESSOR ] ; then
echo "3) compresion is `[[ $COMPRESS ]] && echo "on" || echo "off"`"
echo "4) quit."
else
echo "3) quit."
fi
read -p ": " RES read -p ": " RES
case $RES in case $RES in
@ -126,8 +153,15 @@ while true ; do
LAST=1 LAST=1
break break
;; ;;
3) 3)
if ! [ -z $COMPRESSOR ] ; then
COMPRESS=`[[ ! $COMPRESS ]] && echo 1 || echo ""`
else
exit
fi
continue
;;
4)
exit exit
;; ;;
@ -138,6 +172,17 @@ while true ; do
esac esac
fi fi
# sanity check...
if ! [ -e "${BASE}/${DRIVE}" ] ; then
echo
echo "ERR: ${BASE}/${DRIVE}: does not exist, nothing to copy."
echo
if [[ $INTERACTIVE || ! $DRIVE ]] ; then
continue
fi
exit
fi
# XXX do a real three digit count... # XXX do a real three digit count...
# single flash card... # single flash card...
SCOUNT=`printf "%03d" $COUNT` SCOUNT=`printf "%03d" $COUNT`
@ -166,7 +211,7 @@ while true ; do
mkdir -vp "$DIR" mkdir -vp "$DIR"
echo "Copying files from ${BASE}/${DRIVE}..." echo "Copying files from ${BASE}/${DRIVE} (`du -hs "${BASE}/${DRIVE}" | cut -f 1`)..."
$COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR" $COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR"
echo "Copying files: done." echo "Copying files: done."
@ -187,4 +232,13 @@ if [[ ! $MULTI || $LAST ]] ; then
echo "Building archive: done." echo "Building archive: done."
fi fi
if [[ $COMPRESS ]] ; then
echo "Compressing archive..."
${COMPRESSOR} "$BASE_DIR"
echo "Compressing archive: done."
fi
echo "`basename "$0"`: done."
# vim:set nowrap :

View File

@ -1,7 +1,32 @@
#!/bin/bash #!/bin/bash
DIR=`pwd` DIR=`pwd`
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
}
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
*)
break
;;
esac
done
exifup(){ exifup(){
PREVIEW_DIR=$1 PREVIEW_DIR=$1

View File

@ -0,0 +1,92 @@
#!/bin/bash
# TODO make this runnable from anywhere...
# - prepend paths with './' only if local/relative
BASE_PATH=.
ARCH_BZIP2='bzip2 -v {}'
ARCH_GZIP='gzip -v {}'
# XXX should we cygpath -w all the inputs???
ARCH_NTFS='compact /c /exe:lzx {}'
# default...
ARCH=$ARCH_NTFS
EXT=ARW
# HACK: this is here to avoid using windows find...
PATH=/bin:$PATH
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
echo " -bz -bzip2 - use bzip2 to compress`[[ $ARCH == $ARCH_BZIP2 ]] && echo " (default)" || echo ""`."
echo " -gz -gzip - use gzip to compress`[[ $ARCH == $ARCH_GZIP ]] && echo " (default)" || echo ""`."
echo " -c -compact - use ntfs compression`[[ $ARCH == $ARCH_NTFS ]] && echo " (default)" || echo ""`."
echo
echo " -ext EXT - set file extension to compress (default: ${EXT})"
echo " NOTE: only one -ext is supported now".
echo
}
# process args...
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
# archivers...
-bz|--bzip2)
ARCH=$ARCH_BZIP2
shift
;;
-gz|--gzip)
ARCH=$ARCH_GZIP
shift
;;
-c|--compact)
ARCH=$ARCH_NTFS
shift
;;
# extension to compress...
--ext)
EXT=$2
shift
shift
;;
*)
break
;;
esac
done
# get path...
if [ "$1" ] ; then
BASE_PATH=$1
fi
# do the work...
find "$BASE_PATH" -name \*.${EXT} -exec ${ARCH} \;
echo done.
# vim:set nowrap nospell :

View File

@ -5,7 +5,8 @@ COUNT=1
TITLE="" TITLE=""
RSYNC=rsync RSYNC=rsync
RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable" #RSYNCFLAGS="-arptgoA --info=progress2,flist --human-readable"
RSYNCFLAGS="-arpt --info=progress2,flist --human-readable"
CP=cp CP=cp
CPFLAGS=-Rpfv CPFLAGS=-Rpfv
@ -14,6 +15,10 @@ CPFLAGS=-Rpfv
COPY=$RSYNC COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS COPYFLAGS=$RSYNCFLAGS
COMPRESSOR=./compress-archive.sh
COMPRESS=1
# base mount dir... # base mount dir...
# systems with /mnt # systems with /mnt
if [ -d /mnt ] ; then if [ -d /mnt ] ; then
@ -40,10 +45,20 @@ while true ; do
echo " single shoot." echo " single shoot."
echo " -l|-last last flash card in set, run" echo " -l|-last last flash card in set, run"
echo " process-archive.sh after copying." echo " process-archive.sh after copying."
echo " -b|-base the base dir to look for drives in" echo " -b|-base BASE the base dir to look for drives in"
echo " default: $BASE" echo " default: $BASE"
echo " --rsync use rsync (default)" echo " --rsync use rsync (default)"
echo " --cp use cp" echo " --cp use cp"
if ! [ -z $COMPRESSOR ] ; then
echo " --compress toggle archive compression"
echo " default: `[[ $COMPRESS ]] && echo "on" || echo "off"`"
fi
# notes...
echo
if ! [ -z $COMPRESSOR ] ; then
echo "NOTE: the index is fully usable during the compression stage"
fi
echo "NOTE: cp under Cygwin may messup permissions, use rsync."
echo echo
exit exit
;; ;;
@ -61,17 +76,24 @@ while true ; do
shift shift
;; ;;
-b|-base|--base) -b|-base|--base)
BASE=1 BASE=$2
shift shift 2
;; ;;
-cp|--cp) -cp|--cp)
COPY=cp COPY=cp
COPYFLAGS=-Rpfv COPYFLAGS=-Rpfv
shift
break break
;; ;;
-rsync|--rsync) -rsync|--rsync)
COPY=$RSYNC COPY=$RSYNC
COPYFLAGS=$RSYNCFLAGS COPYFLAGS=$RSYNCFLAGS
shift
break
;;
-compress|--compress)
COMPRESS=`[[ $COMPRESS ]] && echo "" || echo 1`
shift
break break
;; ;;
*) *)
@ -99,7 +121,12 @@ while true ; do
echo "Enter) copy drive ${DRIVE}" echo "Enter) copy drive ${DRIVE}"
fi fi
echo "2) build." echo "2) build."
echo "3) quit." if ! [ -z $COMPRESSOR ] ; then
echo "3) compresion is `[[ $COMPRESS ]] && echo "on" || echo "off"`"
echo "4) quit."
else
echo "3) quit."
fi
read -p ": " RES read -p ": " RES
case $RES in case $RES in
@ -126,8 +153,15 @@ while true ; do
LAST=1 LAST=1
break break
;; ;;
3) 3)
if ! [ -z $COMPRESSOR ] ; then
COMPRESS=`[[ ! $COMPRESS ]] && echo 1 || echo ""`
else
exit
fi
continue
;;
4)
exit exit
;; ;;
@ -138,6 +172,17 @@ while true ; do
esac esac
fi fi
# sanity check...
if ! [ -e "${BASE}/${DRIVE}" ] ; then
echo
echo "ERR: ${BASE}/${DRIVE}: does not exist, nothing to copy."
echo
if [[ $INTERACTIVE || ! $DRIVE ]] ; then
continue
fi
exit
fi
# XXX do a real three digit count... # XXX do a real three digit count...
# single flash card... # single flash card...
SCOUNT=`printf "%03d" $COUNT` SCOUNT=`printf "%03d" $COUNT`
@ -166,7 +211,7 @@ while true ; do
mkdir -vp "$DIR" mkdir -vp "$DIR"
echo "Copying files from ${BASE}/${DRIVE}..." echo "Copying files from ${BASE}/${DRIVE} (`du -hs "${BASE}/${DRIVE}" | cut -f 1`)..."
$COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR" $COPY $COPYFLAGS ${BASE}/${DRIVE}/* "$DIR"
echo "Copying files: done." echo "Copying files: done."
@ -187,4 +232,13 @@ if [[ ! $MULTI || $LAST ]] ; then
echo "Building archive: done." echo "Building archive: done."
fi fi
if [[ $COMPRESS ]] ; then
echo "Compressing archive..."
${COMPRESSOR} "$BASE_DIR"
echo "Compressing archive: done."
fi
echo "`basename "$0"`: done."
# vim:set nowrap :

View File

@ -1,7 +1,32 @@
#!/bin/bash #!/bin/bash
DIR=`pwd` DIR=`pwd`
printhelp(){
echo "Usage: `basename $0` [ARGUMENTS] [PATH]"
echo
echo "Arguments:"
echo " -h --help - print this help and exit."
echo
}
while true ; do
case $1 in
-h|--help)
printhelp
exit
;;
*)
break
;;
esac
done
exifup(){ exifup(){
PREVIEW_DIR=$1 PREVIEW_DIR=$1

View File

@ -524,17 +524,52 @@ var BaseItemPrototype = {
: undefined }, : undefined },
// XXX BUG: this does not work for nested header elements... // NOTE: these should not clash with user-supplied handlers ('update' does not)...
//
// XXX BUG: calling this on a nested/inlined browser will mess things up...
// ...the issue seems to be with root options not being available
// for partial render in a nested context...
// ...one way to fix this would be to make the options inheritance
// protocol more strict:
// - if no options given use defaults (i.e. this.options)
// - if options given use as-is
// - defaults are taken from this.options if not present
//
// to reproduce: // to reproduce:
// dialog // dialog.disable('2')
// .get({children: true}) // or:
// .update() // dialog.disable('B/C/D/a')
// ...for some reason the affected element is removed from dom... //
// ...in both cases the whole nested browser disappears...
//
// but this works OK:
// dialog.disable('nested/2')
//
// This might also be a side effect of the .dom / .elem set of
// issues...
//
// This issue seems to go away after expanding/collapsing the
// nested item several times, the buttons are gone but the
// subtrees stop vanishing on update -- could this be related
// to .dom/.elem again???
update: function(options){ update: function(options){
this.parent this.parent
&& this.parent.render(this, options) && this.parent.render(this, options)
return this return this },
}, /* XXX this is disabled to avoid user confusion when a user item
// event handler would not call/replicate the top-level (this)
// functionality and this break code relying on it...
// ...for this to work well need to either:
// - separate item options form the item object,
// - force the user to follow strict protocols,
// - use a proxy when accessing items (reverse of #1)
// XXX this also applies to .update(..) above...
focus: function(){
arguments.length == 0
&& this.parent
&& this.parent.focus(this)
return this },
//*/
__init__(...state){ __init__(...state){
@ -785,6 +820,9 @@ object.Constructor('BaseRenderer', {
// placeholders... // placeholders...
root: null, root: null,
isRendered: function(){
throw new Error('.isRendered(..): Not implemented.') },
// component renderers... // component renderers...
elem: function(item, index, path, options){ elem: function(item, index, path, options){
throw new Error('.elem(..): Not implemented.') }, throw new Error('.elem(..): Not implemented.') },
@ -810,6 +848,9 @@ module.TextRenderer =
object.Constructor('TextRenderer', { object.Constructor('TextRenderer', {
__proto__: BaseRenderer.prototype, __proto__: BaseRenderer.prototype,
// always render...
isRendered: function(){ return false },
elem: function(item, index, path, options){ elem: function(item, index, path, options){
return path return path
.slice(0, -1) .slice(0, -1)
@ -840,6 +881,9 @@ module.PathRenderer =
object.Constructor('PathRenderer', { object.Constructor('PathRenderer', {
__proto__: TextRenderer.prototype, __proto__: TextRenderer.prototype,
// always render...
isRendered: function(){ return false },
elem: function(item, index, path, options){ elem: function(item, index, path, options){
return path.join('/') }, return path.join('/') },
inline: function(item, lst, index, path, options){ inline: function(item, lst, index, path, options){
@ -2654,10 +2698,14 @@ var BaseBrowserPrototype = {
return r && typeof(e) != typeof({}) }, true))){ return r && typeof(e) != typeof({}) }, true))){
// reverse index... // reverse index...
index = this index = this
.reduce(function(res, e, i, p){ .reduce(
res.set(e, [i, p]) function(res, e, i, p){
return res res.set(e, [i, p])
}, new Map(), {iterateAll: true}) return res },
new Map(),
Object.assign(
Object.flatCopy(options || {}),
{iterateAll: true}))
var res var res
var Stop = new Error('Stop iteration') var Stop = new Error('Stop iteration')
try { try {
@ -2676,7 +2724,10 @@ var BaseBrowserPrototype = {
throw Stop }) throw Stop })
: pattern ] : pattern ]
// search... // search...
: that.search(pattern, ...args.slice(1)) }) : !(pattern instanceof BaseItem) ?
that.search(pattern, ...args.slice(1))
// not found...
: [] })
.flat() .flat()
.unique() .unique()
} catch(e){ } catch(e){
@ -2946,6 +2997,13 @@ var BaseBrowserPrototype = {
__renderer__: TextRenderer, __renderer__: TextRenderer,
isRendered: function(renderer){
var render = renderer || this.__renderer__
render = render.root == null ?
new render(this, this.options)
: render
return render.isRendered() },
// //
// Render browser... // Render browser...
// .render([options]) // .render([options])
@ -3594,19 +3652,39 @@ var BaseBrowserPrototype = {
// XXX should we force calling update if options are given??? // XXX should we force calling update if options are given???
// ...and should full get passed if at least one call in sequence // ...and should full get passed if at least one call in sequence
// got a full=true??? // got a full=true???
__update_full: undefined, // XXX supported mdoes:
// 'full' | true - make - render - post-render
// 'normal' - render - post-render
// 'partial' - post-render
__update_mode: undefined,
__update_args: undefined, __update_args: undefined,
__update_timeout: undefined, __update_timeout: undefined,
__update_max_timeout: undefined, __update_max_timeout: undefined,
update: makeEventMethod('update', update: makeEventMethod('update',
function(evt, full, options){ function(evt, mode, options){
options = var modes = [
(full && full !== true && full !== false) ? 'full',
full 'normal',
: options 'partial',
full = full === options ? ]
false
: full options = mode instanceof Object ?
mode
: options
mode = mode === options ?
'normal'
: mode === true ?
'full'
: mode
// sanity check...
if(!modes.includes(mode)){
throw new Error(`.update(..): unsupported mode: ${mode}`) }
var m = this.__update_mode
// if the queued mode is deeper than the requested, ignore the requested...
if(m != null && modes.indexOf(mode) > modes.indexOf(m)){
return this }
// queue update...
// NOTE: we can't simply use _update(..) closure for this as // NOTE: we can't simply use _update(..) closure for this as
// it can be called out of two contexts (timeout and // it can be called out of two contexts (timeout and
// max_timeout), one (timeout) is renewed on each call // max_timeout), one (timeout) is renewed on each call
@ -3616,14 +3694,14 @@ var BaseBrowserPrototype = {
// its setTimeout(..)... // its setTimeout(..)...
// storing the arguments in .__update_args would remove // storing the arguments in .__update_args would remove
// this inconsistency... // this inconsistency...
this.__update_mode = mode
var args = this.__update_args = [ var args = this.__update_args = [
[evt, full, [evt, mode,
...(options ? ...(options ?
[options] [options]
: [])], : [])],
options] options]
this.__update_full = (full && args)
|| this.__update_full
var timeout = (options || {}).updateTimeout var timeout = (options || {}).updateTimeout
|| this.options.updateTimeout || this.options.updateTimeout
var max_timeout = (options || {}).updateMaxDelay var max_timeout = (options || {}).updateMaxDelay
@ -3637,20 +3715,22 @@ var BaseBrowserPrototype = {
delete this.__update_timeout }.bind(this) delete this.__update_timeout }.bind(this)
var _update = function(){ var _update = function(){
_clear_timers() _clear_timers()
var full = !!this.__update_full var mode = this.__update_mode
var [args, opts] = this.__update_full var [args, opts] = this.__update_args
|| this.__update_args
delete this.__update_full delete this.__update_mode
delete this.__update_args delete this.__update_args
full // make...
modes.indexOf(mode) <= modes.indexOf('full')
&& this.make(opts) && this.make(opts)
var context = {} // render...
this ;(!this.isRendered((opts || {}).renderer)
// XXX this needs access to render context.... || modes.indexOf(mode) <= modes.indexOf('normal'))
.preRender(opts, (opts || {}).renderer, context) && this
.render(opts, (opts || {}).renderer, context) .preRender(opts, (opts || {}).renderer)
.render(opts, (opts || {}).renderer)
// update...
this.trigger(...args) }.bind(this) this.trigger(...args) }.bind(this)
var _update_n_delay = function(){ var _update_n_delay = function(){
// call... // call...
@ -3771,6 +3851,7 @@ object.Constructor('BaseBrowser',
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// HTML-specific UI...
var KEYBOARD_CONFIG = var KEYBOARD_CONFIG =
module.KEYBOARD_CONFIG = { module.KEYBOARD_CONFIG = {
@ -4034,17 +4115,17 @@ var updateElemClass = function(action, cls, handler){
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Renderer... // HTML Renderer...
// XXX needs testing...
// - partial rendering...
// - local re-rendering...
// XXX HACK: see .nest(..) // XXX HACK: see .nest(..)
var HTMLRenderer = var HTMLRenderer =
module.HTMLRenderer = module.HTMLRenderer =
object.Constructor('HTMLRenderer', { object.Constructor('HTMLRenderer', {
__proto__: BaseRenderer.prototype, __proto__: BaseRenderer.prototype,
isRendered: function(){
return !!this.root.dom },
// secondary renderers... // secondary renderers...
// //
// base dialog... // base dialog...
@ -4654,7 +4735,6 @@ var HTMLBrowserPrototype = {
__item__: HTMLItem, __item__: HTMLItem,
__renderer__: HTMLRenderer, __renderer__: HTMLRenderer,
options: { options: {
__proto__: BaseBrowser.prototype.options, __proto__: BaseBrowser.prototype.options,
@ -5045,29 +5125,28 @@ var HTMLBrowserPrototype = {
__copy: function(text){ __copy: function(text){
navigator.clipboard.writeText(text || this.path) }, navigator.clipboard.writeText(text || this.path) },
// XXX need a better name...
_updateDOMItems: function(){ // Events extensions...
//
// XXX should tweaking DOM be done here or in the renderer???
__update__: function(){
var c = 0 var c = 0
this.forEach(function(e){ this.forEach(function(e){
// shortcut number hint... // shortcut number hint...
if(c < 10 && !e.disabled && !e.hidden){ if(c < 10 && !e.disabled && !e.hidden){
var a = e.attrs = e.attrs || {} var a = e.attrs = e.attrs || {}
c = a['shortcut-number'] = (++c) % 10
e.elem e.elem
&& e.elem.setAttribute('shortcut-number', c) && e.elem.setAttribute('shortcut-number',
a['shortcut-number'] = (c+1) % 10)
// cleanup... // cleanup...
} else { } else {
delete (e.attrs || {})['shortcut-number'] delete (e.attrs || {})['shortcut-number']
e.elem e.elem
&& e.elem.removeAttribute('shortcut-number') && e.elem.removeAttribute('shortcut-number')
} }
c++
}) }, }) },
// Events extensions...
//
// NOTE: this will also kill any user-set keys for disabled/hidden items... // NOTE: this will also kill any user-set keys for disabled/hidden items...
//
// XXX also handle global button keys... // XXX also handle global button keys...
__preRender__: function(evt, options, renderer, context){ __preRender__: function(evt, options, renderer, context){
var that = this var that = this
@ -5079,18 +5158,6 @@ var HTMLBrowserPrototype = {
var i = 0 var i = 0
this.map(function(e){ this.map(function(e){
// shortcut number hint...
// NOTE: these are just hints, the actual keys are handled
// in .keybindings...
// XXX move this to the renderer...
if(i < 10 && !e.disabled && !e.hidden){
var attrs = e.attrs = e.attrs || {}
attrs['shortcut-number'] = (++i) % 10
// cleanup...
} else {
delete (e.attrs || {})['shortcut-number']
}
// handle item keys... // handle item keys...
if(!e.disabled && !e.hidden){ if(!e.disabled && !e.hidden){
;((e.value instanceof Array ? ;((e.value instanceof Array ?
@ -5140,7 +5207,7 @@ var HTMLBrowserPrototype = {
block: 'nearest', block: 'nearest',
}) })
}) })
// set focus... // XXX do we need this???
.focus() }, .focus() },
__blur__: function(evt, elem){ __blur__: function(evt, elem){
var that = this var that = this
@ -5157,14 +5224,22 @@ var HTMLBrowserPrototype = {
// element up to reveal the expanded subtree... // element up to reveal the expanded subtree...
// ...would also be logical to "show" the expanded tree but // ...would also be logical to "show" the expanded tree but
// keeping the focused elem in view... // keeping the focused elem in view...
__expand__: function(evt, elem){ elem.update() }, __expand__: function(evt, elem){
__collapse__: function(evt, elem){ elem.update() }, elem.update()
this.update('partial') },
__collapse__: function(evt, elem){
elem.update()
this.update('partial') },
__select__: updateElemClass('add', 'selected'), __select__: updateElemClass('add', 'selected'),
__deselect__: updateElemClass('remove', 'selected'), __deselect__: updateElemClass('remove', 'selected'),
__disable__: updateElemClass('add', 'disabled', __disable__: updateElemClass('add', 'disabled',
function(evt, elem){ elem.update() }), function(evt, elem){
elem.update()
this.update('partial') }),
__enable__: updateElemClass('remove', 'disabled', __enable__: updateElemClass('remove', 'disabled',
function(evt, elem){ elem.update() }), function(evt, elem){
elem.update()
this.update('partial') }),
__hide__: updateElemClass('add', 'hidden'), __hide__: updateElemClass('add', 'hidden'),
__show__: updateElemClass('remove', 'hidden'), __show__: updateElemClass('remove', 'hidden'),