diff --git a/ui (gen4)/lib/widget/browse2.html b/ui (gen4)/lib/widget/browse2.html
index 80741d21..6bf7ee3e 100755
--- a/ui (gen4)/lib/widget/browse2.html
+++ b/ui (gen4)/lib/widget/browse2.html
@@ -52,6 +52,12 @@ body {
text-decoration-skip-ink: none;
}
+/*
+.browse-widget .list .item .button.toggle-collapse {
+ float: left;
+}
+*/
+
/* XXX stub...
.browse-widget:not(.flat) .list .text:first-child:before {
@@ -216,6 +222,9 @@ requirejs([
// XXX this is not supported by .map(..)...
make.nest('$ne$sted', browser.Browser(function(make){
make('ab')
+ make($('
'))
+ //make($('
')[0])
+ //make('
')
})),
])
make('in between two $subtrees...')
@@ -259,7 +268,8 @@ requirejs([
['–',
'buttonAction: item button focused -- example button action...'],
['□',
- function(){ console.log('BUTTON:', ...arguments) }],
+ function(){ console.log('BUTTON:', ...arguments) },
+ { keys: 'r' }],
'ToggleCollapse',
'ToggleDisabled',
],
diff --git a/ui (gen4)/lib/widget/browse2.js b/ui (gen4)/lib/widget/browse2.js
index aca1ccaa..8decab05 100755
--- a/ui (gen4)/lib/widget/browse2.js
+++ b/ui (gen4)/lib/widget/browse2.js
@@ -172,26 +172,37 @@ var buttons = Items.buttons = {}
// Checkbox('!attr')
//
// XXX rename -- distinguish from actual button...
-buttons.Checkbox = function(attr){
- return function(item){
- return (attr[0] == '!'
- && !item[attr.slice(1)])
- || item[attr] ?
- '☐'
- : '☑' } }
+buttons.Checkbox = function(item, attr){
+ return (attr[0] == '!'
+ && !item[attr.slice(1)])
+ || item[attr] ?
+ '☐'
+ : '☑' }
// XXX can we make these not use the same icon...
buttons.ToggleDisabled = [
'Checkbox: "disabled"',
'toggleDisabled: item',
- true]
+ true,
+ {
+ alt: 'Disable/enable item',
+ cls: 'toggle-disabled',
+ }]
buttons.ToggleHidden = [
'Checkbox: "hidden"',
- 'toggleHidden: item']
+ 'toggleHidden: item',
+ {
+ alt: 'Show/hide item',
+ cls: 'toggle-hidden',
+ }]
buttons.ToggleSelected = [
'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...
buttons.ToggleCollapse = [
function(item){
@@ -204,8 +215,24 @@ buttons.ToggleCollapse = [
'toggleCollapse: item',
// disable button for all items that do not have children...
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',
// ],
//
- // // action button handler...
+ // // full button handler...
// //
// // can be:
// // - item - item containing the button
@@ -3164,13 +3191,28 @@ var BrowserPrototype = {
// // - number/string/list/object
// // - any values...
// //
- // // (optional, bool), of true the button will
+ // // (optional, bool or function), of true the button will
// // be active while the item is disabled...
// //
// // NOTE: for more doc see keyboard.Keyboard.parseStringHandler(..)
- // ['html',
- // ': .. -- comment',
- // ],
+ // [
+ // // button view...
+ // 'text or html'
+ // | ': .. -- comment'
+ // |
+ // | ,
+ //
+ // // button action...
+ // ': .. -- comment'
+ // | ,
+ //
+ // // force active (optional)...
+ // bool
+ // | ,
+ //
+ // // button metadata (optional)...
+ // ,
+ // ],
//
// ...
// ]
@@ -3216,6 +3258,9 @@ var BrowserPrototype = {
},
},
+ // If true will disable button shortcut key handling...
+ //disableButtonSortcuts: false,
+
// debug and testing options...
//keyboardReportUnhandled: false,
},
@@ -3253,6 +3298,10 @@ var BrowserPrototype = {
options.keyboardReportUnhandled
&& console.log('KEY:', ...arguments) },
this)) },
+
+ // Proxy to .keyboard.parseStringHandler(..)
+ parseStringHandler: function(code, context){
+ return this.keyboard.parseStringHandler(code, context || this) },
// DOM props..
@@ -3650,6 +3699,25 @@ var BrowserPrototype = {
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...
if(item.value in (options.elementShorthand || {})){
// XXX need to merge and not overwrite -- revise...
@@ -3699,24 +3767,26 @@ var BrowserPrototype = {
// values...
text != null
&& (item.value instanceof Array ? item.value : [item.value])
- // XXX handle $keys and other stuff...
+ // handle $keys and other stuff...
.map(function(v){
// handle key-shortcuts $K...
v = typeof(v) == typeof('str') ?
- v.replace(/\$\w/g,
- function(k){
- k = k[1]
- return (item.keys || [])
- .includes(that.keyboard.normalizeKey(k)) ?
- `${k}`
- : k })
+ v.replace(/\$\w/g,
+ function(k){
+ k = k[1]
+ return (item.keys || [])
+ .includes(that.keyboard.normalizeKey(k)) ?
+ `${k}`
+ : k })
: v
var value = document.createElement('span')
value.classList.add('text')
- value.innerHTML = v != null ?
- v
- : (item || '')
+
+ // set the value...
+ setDOMValue(value,
+ resolveValue(v, that))
+
elem.appendChild(value)
})
@@ -3724,6 +3794,8 @@ var BrowserPrototype = {
elem.addEventListener('click',
function(evt){
evt.stopPropagation()
+ // NOTE: if an item is disabled we retain its expand/collapse
+ // functionality...
// XXX revise...
item.disabled ?
that.toggleCollapse(item)
@@ -3750,6 +3822,7 @@ var BrowserPrototype = {
&& elem.addEventListener(evt, handler.bind(that)) })
// buttons...
+ var button_keys = {}
// XXX migrate the default buttons functionality and button inheritance...
var buttons = (item.buttons || options.itemButtons || [])
// resolve buttons from library...
@@ -3760,28 +3833,43 @@ var BrowserPrototype = {
: Items.buttons[button] instanceof Function ?
Items.buttons[button].call(that, item)
: Items.buttons[button] || button })
- // NOTE: keep the order unsurprising...
+ // NOTE: keep the order unsurprising -- first defined, first from left...
.reverse()
var stopPropagation = function(evt){ evt.stopPropagation() }
buttons
- // XXX add option to use a shortcut key...
// 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')
- button.classList.add('button')
+ button.classList.add('button', ...cls)
+ alt
+ && button.setAttribute('alt', alt)
- var htmlhandler = typeof(html) == typeof('str') ?
- that.keyboard.parseStringHandler(html, {item})
- : null
- 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
+ // button content...
+ setDOMValue(button,
+ resolveValue(html, Items.buttons, {item}))
+ // active button...
if(force instanceof Function ?
force.call(that, item)
: (force || !item.disabled) ){
@@ -3790,6 +3878,14 @@ var BrowserPrototype = {
;(options.buttonLocalEvents || options.localEvents || [])
.forEach(function(evt){
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
// we tab out of the item focus the item we get to...
button.addEventListener('focus', function(){
@@ -3803,7 +3899,7 @@ var BrowserPrototype = {
handler
// string handler -> that.(item)
: function(evt, ...args){
- var a = that.keyboard.parseStringHandler(
+ var a = that.parseStringHandler(
handler,
// button handler arg namespace...
{
@@ -3828,8 +3924,19 @@ var BrowserPrototype = {
event.stopPropagation()
func.call(that, evt, item) } }) }
}
+
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