mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 18:30:09 +00:00
refactored item rendering + features and tweaks...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
c1eac80503
commit
9c0f48ea3b
@ -52,6 +52,12 @@ body {
|
|||||||
text-decoration-skip-ink: none;
|
text-decoration-skip-ink: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.browse-widget .list .item .button.toggle-collapse {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* XXX stub...
|
/* XXX stub...
|
||||||
.browse-widget:not(.flat) .list .text:first-child:before {
|
.browse-widget:not(.flat) .list .text:first-child:before {
|
||||||
@ -216,6 +222,9 @@ requirejs([
|
|||||||
// XXX this is not supported by .map(..)...
|
// XXX this is not supported by .map(..)...
|
||||||
make.nest('$ne$sted', browser.Browser(function(make){
|
make.nest('$ne$sted', browser.Browser(function(make){
|
||||||
make('ab')
|
make('ab')
|
||||||
|
make($('<img src="../../experiments/grayscale.jpg">'))
|
||||||
|
//make($('<img src="../../experiments/grayscale.jpg">')[0])
|
||||||
|
//make('<img src="../../experiments/grayscale.jpg">')
|
||||||
})),
|
})),
|
||||||
])
|
])
|
||||||
make('in between two $subtrees...')
|
make('in between two $subtrees...')
|
||||||
@ -259,7 +268,8 @@ requirejs([
|
|||||||
['–',
|
['–',
|
||||||
'buttonAction: item button focused -- example button action...'],
|
'buttonAction: item button focused -- example button action...'],
|
||||||
['□',
|
['□',
|
||||||
function(){ console.log('BUTTON:', ...arguments) }],
|
function(){ console.log('BUTTON:', ...arguments) },
|
||||||
|
{ keys: 'r' }],
|
||||||
'ToggleCollapse',
|
'ToggleCollapse',
|
||||||
'ToggleDisabled',
|
'ToggleDisabled',
|
||||||
],
|
],
|
||||||
|
|||||||
@ -172,26 +172,37 @@ var buttons = Items.buttons = {}
|
|||||||
// Checkbox('!attr')
|
// Checkbox('!attr')
|
||||||
//
|
//
|
||||||
// XXX rename -- distinguish from actual button...
|
// XXX rename -- distinguish from actual button...
|
||||||
buttons.Checkbox = function(attr){
|
buttons.Checkbox = function(item, attr){
|
||||||
return function(item){
|
return (attr[0] == '!'
|
||||||
return (attr[0] == '!'
|
&& !item[attr.slice(1)])
|
||||||
&& !item[attr.slice(1)])
|
|| item[attr] ?
|
||||||
|| item[attr] ?
|
'☐'
|
||||||
'☐'
|
: '☑' }
|
||||||
: '☑' } }
|
|
||||||
|
|
||||||
|
|
||||||
// XXX can we make these not use the same icon...
|
// XXX can we make these not use the same icon...
|
||||||
buttons.ToggleDisabled = [
|
buttons.ToggleDisabled = [
|
||||||
'Checkbox: "disabled"',
|
'Checkbox: "disabled"',
|
||||||
'toggleDisabled: item',
|
'toggleDisabled: item',
|
||||||
true]
|
true,
|
||||||
|
{
|
||||||
|
alt: 'Disable/enable item',
|
||||||
|
cls: 'toggle-disabled',
|
||||||
|
}]
|
||||||
buttons.ToggleHidden = [
|
buttons.ToggleHidden = [
|
||||||
'Checkbox: "hidden"',
|
'Checkbox: "hidden"',
|
||||||
'toggleHidden: item']
|
'toggleHidden: item',
|
||||||
|
{
|
||||||
|
alt: 'Show/hide item',
|
||||||
|
cls: 'toggle-hidden',
|
||||||
|
}]
|
||||||
buttons.ToggleSelected = [
|
buttons.ToggleSelected = [
|
||||||
'Checkbox: "selected"',
|
'Checkbox: "selected"',
|
||||||
'toggleSelect: item']
|
'toggleSelect: item',
|
||||||
|
{
|
||||||
|
alt: 'Select/deselect item',
|
||||||
|
cls: 'toggle-select',
|
||||||
|
}]
|
||||||
// NOTE: this button is disabled for all items but the ones with .children...
|
// NOTE: this button is disabled for all items but the ones with .children...
|
||||||
buttons.ToggleCollapse = [
|
buttons.ToggleCollapse = [
|
||||||
function(item){
|
function(item){
|
||||||
@ -204,8 +215,24 @@ buttons.ToggleCollapse = [
|
|||||||
'toggleCollapse: item',
|
'toggleCollapse: item',
|
||||||
// disable button for all items that do not have children...
|
// disable button for all items that do not have children...
|
||||||
function(item){
|
function(item){
|
||||||
return 'children' in item }]
|
return 'children' in item },
|
||||||
|
{
|
||||||
|
alt: 'Collapse/expand item',
|
||||||
|
cls: function(item){
|
||||||
|
return 'children' in item ?
|
||||||
|
'toggle-collapse'
|
||||||
|
: ['toggle-collapse', 'blank'] },
|
||||||
|
}]
|
||||||
|
|
||||||
|
// XXX delete button -- requires .markDelete(..) action...
|
||||||
|
buttons.Delete = [
|
||||||
|
'×',
|
||||||
|
'markDelete: item',
|
||||||
|
{
|
||||||
|
alt: 'Mark item for deletion',
|
||||||
|
cls: 'toggle-delete',
|
||||||
|
//keys: ['Delete', 'd'],
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -3151,7 +3178,7 @@ var BrowserPrototype = {
|
|||||||
// ['html',
|
// ['html',
|
||||||
// <handler>],
|
// <handler>],
|
||||||
//
|
//
|
||||||
// // action button handler...
|
// // full button handler...
|
||||||
// //
|
// //
|
||||||
// // <arg> can be:
|
// // <arg> can be:
|
||||||
// // - item - item containing the button
|
// // - item - item containing the button
|
||||||
@ -3164,13 +3191,28 @@ var BrowserPrototype = {
|
|||||||
// // - number/string/list/object
|
// // - number/string/list/object
|
||||||
// // - any values...
|
// // - any values...
|
||||||
// //
|
// //
|
||||||
// // <force> (optional, bool), of true the button will
|
// // <force> (optional, bool or function), of true the button will
|
||||||
// // be active while the item is disabled...
|
// // be active while the item is disabled...
|
||||||
// //
|
// //
|
||||||
// // NOTE: for more doc see keyboard.Keyboard.parseStringHandler(..)
|
// // NOTE: for more doc see keyboard.Keyboard.parseStringHandler(..)
|
||||||
// ['html',
|
// [
|
||||||
// '<action>: <arg> .. -- comment',
|
// // button view...
|
||||||
// <force>],
|
// 'text or html'
|
||||||
|
// | '<button-generator>: <arg> .. -- comment'
|
||||||
|
// | <function>
|
||||||
|
// | <HTMLElement>,
|
||||||
|
//
|
||||||
|
// // button action...
|
||||||
|
// '<action>: <arg> .. -- comment'
|
||||||
|
// | <function>,
|
||||||
|
//
|
||||||
|
// // force active (optional)...
|
||||||
|
// bool
|
||||||
|
// | <function>,
|
||||||
|
//
|
||||||
|
// // button metadata (optional)...
|
||||||
|
// <metadata>,
|
||||||
|
// ],
|
||||||
//
|
//
|
||||||
// ...
|
// ...
|
||||||
// ]
|
// ]
|
||||||
@ -3216,6 +3258,9 @@ var BrowserPrototype = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// If true will disable button shortcut key handling...
|
||||||
|
//disableButtonSortcuts: false,
|
||||||
|
|
||||||
// debug and testing options...
|
// debug and testing options...
|
||||||
//keyboardReportUnhandled: false,
|
//keyboardReportUnhandled: false,
|
||||||
},
|
},
|
||||||
@ -3254,6 +3299,10 @@ var BrowserPrototype = {
|
|||||||
&& console.log('KEY:', ...arguments) },
|
&& console.log('KEY:', ...arguments) },
|
||||||
this)) },
|
this)) },
|
||||||
|
|
||||||
|
// Proxy to .keyboard.parseStringHandler(..)
|
||||||
|
parseStringHandler: function(code, context){
|
||||||
|
return this.keyboard.parseStringHandler(code, context || this) },
|
||||||
|
|
||||||
|
|
||||||
// DOM props..
|
// DOM props..
|
||||||
//
|
//
|
||||||
@ -3650,6 +3699,25 @@ var BrowserPrototype = {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helpers...
|
||||||
|
var resolveValue = function(value, context, exec_context){
|
||||||
|
var htmlhandler = typeof(value) == typeof('str') ?
|
||||||
|
that.parseStringHandler(value, exec_context)
|
||||||
|
: null
|
||||||
|
return value instanceof Function ?
|
||||||
|
value.call(that, item)
|
||||||
|
: htmlhandler && htmlhandler.action in context ?
|
||||||
|
context[htmlhandler.action]
|
||||||
|
.call(that, item, ...htmlhandler.arguments)
|
||||||
|
: value }
|
||||||
|
var setDOMValue = function(target, value){
|
||||||
|
value instanceof HTMLElement ?
|
||||||
|
target.appendChild(value)
|
||||||
|
: (typeof(jQuery) != 'undefined' && value instanceof jQuery) ?
|
||||||
|
value.appendTo(target)
|
||||||
|
: (target.innerHTML = value)
|
||||||
|
return target }
|
||||||
|
|
||||||
// special-case: item shorthands...
|
// special-case: item shorthands...
|
||||||
if(item.value in (options.elementShorthand || {})){
|
if(item.value in (options.elementShorthand || {})){
|
||||||
// XXX need to merge and not overwrite -- revise...
|
// XXX need to merge and not overwrite -- revise...
|
||||||
@ -3699,24 +3767,26 @@ var BrowserPrototype = {
|
|||||||
// values...
|
// values...
|
||||||
text != null
|
text != null
|
||||||
&& (item.value instanceof Array ? item.value : [item.value])
|
&& (item.value instanceof Array ? item.value : [item.value])
|
||||||
// XXX handle $keys and other stuff...
|
// handle $keys and other stuff...
|
||||||
.map(function(v){
|
.map(function(v){
|
||||||
// handle key-shortcuts $K...
|
// handle key-shortcuts $K...
|
||||||
v = typeof(v) == typeof('str') ?
|
v = typeof(v) == typeof('str') ?
|
||||||
v.replace(/\$\w/g,
|
v.replace(/\$\w/g,
|
||||||
function(k){
|
function(k){
|
||||||
k = k[1]
|
k = k[1]
|
||||||
return (item.keys || [])
|
return (item.keys || [])
|
||||||
.includes(that.keyboard.normalizeKey(k)) ?
|
.includes(that.keyboard.normalizeKey(k)) ?
|
||||||
`<u class="key-hint">${k}</u>`
|
`<u class="key-hint">${k}</u>`
|
||||||
: k })
|
: k })
|
||||||
: v
|
: v
|
||||||
|
|
||||||
var value = document.createElement('span')
|
var value = document.createElement('span')
|
||||||
value.classList.add('text')
|
value.classList.add('text')
|
||||||
value.innerHTML = v != null ?
|
|
||||||
v
|
// set the value...
|
||||||
: (item || '')
|
setDOMValue(value,
|
||||||
|
resolveValue(v, that))
|
||||||
|
|
||||||
elem.appendChild(value)
|
elem.appendChild(value)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -3724,6 +3794,8 @@ var BrowserPrototype = {
|
|||||||
elem.addEventListener('click',
|
elem.addEventListener('click',
|
||||||
function(evt){
|
function(evt){
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
|
// NOTE: if an item is disabled we retain its expand/collapse
|
||||||
|
// functionality...
|
||||||
// XXX revise...
|
// XXX revise...
|
||||||
item.disabled ?
|
item.disabled ?
|
||||||
that.toggleCollapse(item)
|
that.toggleCollapse(item)
|
||||||
@ -3750,6 +3822,7 @@ var BrowserPrototype = {
|
|||||||
&& elem.addEventListener(evt, handler.bind(that)) })
|
&& elem.addEventListener(evt, handler.bind(that)) })
|
||||||
|
|
||||||
// buttons...
|
// buttons...
|
||||||
|
var button_keys = {}
|
||||||
// XXX migrate the default buttons functionality and button inheritance...
|
// XXX migrate the default buttons functionality and button inheritance...
|
||||||
var buttons = (item.buttons || options.itemButtons || [])
|
var buttons = (item.buttons || options.itemButtons || [])
|
||||||
// resolve buttons from library...
|
// resolve buttons from library...
|
||||||
@ -3760,28 +3833,43 @@ var BrowserPrototype = {
|
|||||||
: Items.buttons[button] instanceof Function ?
|
: Items.buttons[button] instanceof Function ?
|
||||||
Items.buttons[button].call(that, item)
|
Items.buttons[button].call(that, item)
|
||||||
: Items.buttons[button] || button })
|
: Items.buttons[button] || button })
|
||||||
// NOTE: keep the order unsurprising...
|
// NOTE: keep the order unsurprising -- first defined, first from left...
|
||||||
.reverse()
|
.reverse()
|
||||||
var stopPropagation = function(evt){ evt.stopPropagation() }
|
var stopPropagation = function(evt){ evt.stopPropagation() }
|
||||||
buttons
|
buttons
|
||||||
// XXX add option to use a shortcut key...
|
|
||||||
// XXX use keyword to inherit buttons...
|
// XXX use keyword to inherit buttons...
|
||||||
.forEach(function([html, handler, force]){
|
.forEach(function([html, handler, ...rest]){
|
||||||
|
var force = (rest[0] === true
|
||||||
|
|| rest[0] === false
|
||||||
|
|| rest[0] instanceof Function) ?
|
||||||
|
rest.shift()
|
||||||
|
: undefined
|
||||||
|
var metadata = rest.shift() || {}
|
||||||
|
|
||||||
|
// resolve metadata...
|
||||||
|
var cls = metadata.cls || []
|
||||||
|
cls = cls instanceof Function ?
|
||||||
|
cls.call(that, item)
|
||||||
|
: cls
|
||||||
|
cls = cls instanceof Array ?
|
||||||
|
cls
|
||||||
|
: cls.split(/\s+/g)
|
||||||
|
var alt = metadata.alt
|
||||||
|
alt = alt instanceof Function ?
|
||||||
|
alt.call(that, item)
|
||||||
|
: alt
|
||||||
|
var keys = metadata.keys
|
||||||
|
|
||||||
var button = document.createElement('div')
|
var button = document.createElement('div')
|
||||||
button.classList.add('button')
|
button.classList.add('button', ...cls)
|
||||||
|
alt
|
||||||
|
&& button.setAttribute('alt', alt)
|
||||||
|
|
||||||
var htmlhandler = typeof(html) == typeof('str') ?
|
// button content...
|
||||||
that.keyboard.parseStringHandler(html, {item})
|
setDOMValue(button,
|
||||||
: null
|
resolveValue(html, Items.buttons, {item}))
|
||||||
button.innerHTML = html instanceof Function ?
|
|
||||||
html.call(that, item)
|
|
||||||
// XXX reference the actual make(..) and not Items...
|
|
||||||
: htmlhandler && htmlhandler.action in Items.buttons ?
|
|
||||||
Items.buttons[htmlhandler.action]
|
|
||||||
.call(that, ...htmlhandler.arguments)
|
|
||||||
.call(that, item)
|
|
||||||
: html
|
|
||||||
|
|
||||||
|
// active button...
|
||||||
if(force instanceof Function ?
|
if(force instanceof Function ?
|
||||||
force.call(that, item)
|
force.call(that, item)
|
||||||
: (force || !item.disabled) ){
|
: (force || !item.disabled) ){
|
||||||
@ -3790,6 +3878,14 @@ var BrowserPrototype = {
|
|||||||
;(options.buttonLocalEvents || options.localEvents || [])
|
;(options.buttonLocalEvents || options.localEvents || [])
|
||||||
.forEach(function(evt){
|
.forEach(function(evt){
|
||||||
button.addEventListener(evt, stopPropagation) })
|
button.addEventListener(evt, stopPropagation) })
|
||||||
|
// button keys...
|
||||||
|
keys && !options.disableButtonSortcuts
|
||||||
|
&& (keys instanceof Array ? keys : [keys])
|
||||||
|
.forEach(function(key){
|
||||||
|
// XXX should we break or warn???
|
||||||
|
if(key in button_keys){
|
||||||
|
throw new Error(`renderItem(..): button key already used: ${key}`) }
|
||||||
|
button_keys[keyboard.joinKey(keyboard.normalizeKey(key))] = button })
|
||||||
// keep focus on the item containing the button -- i.e. if
|
// keep focus on the item containing the button -- i.e. if
|
||||||
// we tab out of the item focus the item we get to...
|
// we tab out of the item focus the item we get to...
|
||||||
button.addEventListener('focus', function(){
|
button.addEventListener('focus', function(){
|
||||||
@ -3803,7 +3899,7 @@ var BrowserPrototype = {
|
|||||||
handler
|
handler
|
||||||
// string handler -> that.<handler>(item)
|
// string handler -> that.<handler>(item)
|
||||||
: function(evt, ...args){
|
: function(evt, ...args){
|
||||||
var a = that.keyboard.parseStringHandler(
|
var a = that.parseStringHandler(
|
||||||
handler,
|
handler,
|
||||||
// button handler arg namespace...
|
// button handler arg namespace...
|
||||||
{
|
{
|
||||||
@ -3828,9 +3924,20 @@ var BrowserPrototype = {
|
|||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
func.call(that, evt, item) } }) }
|
func.call(that, evt, item) } }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
elem.appendChild(button)
|
elem.appendChild(button)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// button shortcut keys...
|
||||||
|
Object.keys(button_keys).length > 0
|
||||||
|
&& elem.addEventListener('keydown',
|
||||||
|
function(evt){
|
||||||
|
var k = keyboard.joinKey(keyboard.event2key(evt))
|
||||||
|
if(k in button_keys){
|
||||||
|
evt.preventDefault()
|
||||||
|
evt.stopPropagation()
|
||||||
|
button_keys[k].click() } })
|
||||||
|
|
||||||
item.dom = elem
|
item.dom = elem
|
||||||
|
|
||||||
return elem
|
return elem
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user