reworked generating sections...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2019-06-29 01:20:02 +03:00
parent 9c6f39ea9f
commit 3c7de1f2c3
2 changed files with 206 additions and 187 deletions

View File

@ -171,109 +171,118 @@ requirejs([
// XXX split this into several dialogues, show each and then combine... // XXX split this into several dialogues, show each and then combine...
dialog = browser.Browser(function(make){ dialog = browser.Browser(
// XXX put this in the header... function(make, options){
// ways to do this: make('CURRENT_PATH', {
// - a different handler id: 'current_path',
// .__header__(..) is like .__list__(..) but can be cls: 'path',
// called less often... buttons: (options || {}).headerButtons
// - a group like thing/constructor... || (this.options || {}).headerButtons
// make.Header( || [],
// make(..), }) },
// .. function(make){
// ) // XXX put this in the header...
// - both??? // ways to do this:
make('path', { // - a different handler
id:'selected_path', // .__header__(..) is like .__list__(..) but can be
//cls: 'path sticky', // called less often...
cls: 'path', // - a group like thing/constructor...
}) // make.Header(
// make(..),
make.Separator() // ..
// )
make(['list', 'of', 'text']) // - both???
make.group( make('path', {
make('$group item 0 (open event)', id:'selected_path',
function(){ console.log('##', ...arguments) }), //cls: 'path sticky',
'group item 1 (bare)') cls: 'path',
// XXX Q: should we show only one if multiple lines are in sequence???
make('---')
// embeded browser...
make(browser.Browser(function(make){
make('inlined browser item 0 (open/menu events)', {
open: function(){ console.log('!!! OPEN', ...arguments) },
menu: function(){ console.log('!!! MENU', ...arguments) },
}) })
make(1)
make(2) make.Separator()
}))
// basic nested list... make(['list', 'of', 'text'])
make.nest('$nested', [ make.group(
make('mo$o', {disabled: true}), make('$group item 0 (open event)',
2, function(){ console.log('##', ...arguments) }),
// XXX this is not supported by .map(..)... 'group item 1 (bare)')
make.nest('$ne$sted', browser.Browser(function(make){ // XXX Q: should we show only one if multiple lines are in sequence???
make('ab') make('---')
//make('<img src="../../experiments/grayscale.jpg">', // embeded browser...
//make($('<img src="../../experiments/grayscale.jpg">')[0], make(browser.Browser(function(make){
make($('<img src="../../experiments/grayscale.jpg">'), make('inlined browser item 0 (open/menu events)', {
{ open: function(){ console.log('!!! OPEN', ...arguments) },
alt: 'image item example' menu: function(){ console.log('!!! MENU', ...arguments) },
}) })
})), make(1)
]) make(2)
make('in between two $subtrees...') }))
// nested browser... // basic nested list...
make.nest('B', make.nest('$nested', [
browser.Browser(function(make){ make('mo$o', {disabled: true}),
make('xx') 2,
make.nest('C', browser.Browser(function(make){ // XXX this is not supported by .map(..)...
make('aaa') make.nest('$ne$sted', browser.Browser(function(make){
make.nest('D', browser.Browser(function(make){ make('ab')
make('a') //make('<img src="../../experiments/grayscale.jpg">',
make('---') //make($('<img src="../../experiments/grayscale.jpg">')[0],
make('b') make($('<img src="../../experiments/grayscale.jpg">'),
{
alt: 'image item example'
})
})),
])
make('in between two $subtrees...')
// nested browser...
make.nest('B',
browser.Browser(function(make){
make('xx')
make.nest('C', browser.Browser(function(make){
make('aaa')
make.nest('D', browser.Browser(function(make){
make('a')
make('---')
make('b')
}))
make('bbb', {buttons: [
['test', 'focus: "parent"'],
]})
make('bbb')
})) }))
make('bbb', {buttons: [ }), {
['test', 'focus: "parent"'], //collapsed: true,
]}) // XXX this does not appear to survive attaching an item
make('bbb') // to the document...
})) open: function(e){
}), { e.preventDefault()
//collapsed: true, console.log('test: open: default prevented...') },
// XXX this does not appear to survive attaching an item //cls: ['heading'],
// to the document... })
open: function(e){
e.preventDefault()
console.log('test: open: default prevented...') },
//cls: ['heading'],
})
make.Separator() make.Separator()
make.nest( make.nest(
'scroll testing', 'scroll testing',
(new Array(100)) (new Array(100))
.fill(1) .fill(1)
.map(function(_, i){ .map(function(_, i){
return make(i) })) return make(i) }))
}, { }, {
itemButtons: [ itemButtons: [
['&ndash;', ['&ndash;',
'buttonAction: item button focused -- example button action...'], 'buttonAction: item button focused -- example button action...'],
['&square;', ['&square;',
function(){ console.log('BUTTON:', ...arguments) }, function(){ console.log('BUTTON:', ...arguments) },
{ keys: 'r' }], { keys: 'r' }],
'ToggleCollapse', 'ToggleCollapse',
'ToggleDisabled', 'ToggleDisabled',
], ],
}) })
// XXX EXPEREMENT -- need to wrap this into partial .update(..) // XXX EXPEREMENT -- need to wrap this into partial .update(..)
.focus(function(){ .focus(function(){
var e = this.get({id: 'selected_path'}) var e = this.get({id: 'selected_path'})
e.value = this.pathArray e.value = this.pathArray
this.renderItem(e) }) this.renderItem(e) })
dialog.container = $('.container').first()[0] dialog.container = $('.container').first()[0]

View File

@ -787,13 +787,20 @@ var makeItemEventToggler2 = function(get_state, set_state, unset_state, default_
var BaseBrowserClassPrototype = { var BaseBrowserClassPrototype = {
} }
// XXX Q: should we be able to add/remove/change items outside of .__list__(..)??? // XXX Q: should we be able to add/remove/change items outside of .__items__(..)???
// ...only some item updates (how .collapsed is handled) make // ...only some item updates (how .collapsed is handled) make
// sense at this time -- need to think about this more // sense at this time -- need to think about this more
// carefully + strictly document the result... // carefully + strictly document the result...
var BaseBrowserPrototype = { var BaseBrowserPrototype = {
// XXX should we mix item/list options or separate them into sub-objects??? // XXX should we mix item/list options or separate them into sub-objects???
options: { options: {
sections: [
'header',
'items',
// XXX do we need this?
//'footer',
],
focusDisabled: false, focusDisabled: false,
// If true item keys must be unique... // If true item keys must be unique...
@ -838,6 +845,7 @@ var BaseBrowserPrototype = {
// NOTE: this may or may not be a Browser object. // NOTE: this may or may not be a Browser object.
parent: null, parent: null,
// Section containers...
// //
// Format: // Format:
// [ // [
@ -855,13 +863,12 @@ var BaseBrowserPrototype = {
// NOTE: this can't be a map/dict as we need both order manipulation // NOTE: this can't be a map/dict as we need both order manipulation
// and nested structures which would overcomplicate things, as // and nested structures which would overcomplicate things, as
// a compromise we use .index below for item identification. // a compromise we use .index below for item identification.
// XXX should the header be restricted to being separate???
__header: null, __header: null,
get header(){ get header(){
this.__header this.__header
// XXX should this be .makeHeader(..) ??? || (this.__header__
|| this.make() && this.make({section: 'header'}))
return this.__header }, return this.__header || [] },
set header(value){ set header(value){
this.__header = value }, this.__header = value },
__items: null, __items: null,
@ -871,6 +878,14 @@ var BaseBrowserPrototype = {
return this.__items }, return this.__items },
set items(value){ set items(value){
this.__items = value }, this.__items = value },
__footer: null,
get footer(){
this.__footer
|| (this.__footer__
&& this.make({section: 'footer'}))
return this.__footer || [] },
set footer(value){
this.__footer = value },
// Clear cached data... // Clear cached data...
@ -1059,9 +1074,11 @@ var BaseBrowserPrototype = {
__item__: BaseItem, __item__: BaseItem,
// Item list constructor... // Section item list constructor...
// //
// .__list__(make, options) // .__header__(make, options)
// .__items__(make, options)
// .__footer__(make, options)
// -> undefined // -> undefined
// -> list // -> list
// //
@ -1085,14 +1102,14 @@ var BaseBrowserPrototype = {
// When calling make(..) (mode #1) the item is built by combining // When calling make(..) (mode #1) the item is built by combining
// the following in order: // the following in order:
// - original item (.items[key]) if present, // - original item (.items[key]) if present,
// - options passed to .make(<options>) method calling .__list__(..), // - options passed to .make(<options>) method calling .__items__(..),
// - options passed to make(.., <options>) constructing the item, // - options passed to make(.., <options>) constructing the item,
// - {value: <value>} where <value> passed to make(<value>, ..) // - {value: <value>} where <value> passed to make(<value>, ..)
// //
// Each of the above will override values of the previous sections. // Each of the above will override values of the previous sections.
// //
// The resulting item is stored in: // The resulting item is stored in:
// .items // .header, .items or .footer
// .index (keyed via .id or JSONified .value) // .index (keyed via .id or JSONified .value)
// //
// Each of the above structures is reset on each call to .make(..) // Each of the above structures is reset on each call to .make(..)
@ -1126,19 +1143,19 @@ var BaseBrowserPrototype = {
// //
// //
// NOTE: this is not designed to be called directly... // NOTE: this is not designed to be called directly...
__list__: function(make, options){
throw new Error('.__list__(..): Not implemented.') },
// XXX header constructor, same as .__list__(..) but optional...
__header__: null, __header__: null,
__items__: function(make, options){
throw new Error('.__items__(..): Not implemented.') },
__footer__: null,
// Make extension... // Make extension...
// //
// This is called per item created by make(..) in .__list__(..) // This is called per item created by make(..) in .__items__(..)
// //
// NOTE: this can update/modify the item but it can not replace it. // NOTE: this can update/modify the item but it can not replace it.
//__make__: function(item){ //__make__: function(section, item){
//}, //},
@ -1148,7 +1165,7 @@ var BaseBrowserPrototype = {
// .make(options) // .make(options)
// -> this // -> this
// //
// The items are constructed by passing a make function to .__list__(..) // The items are constructed by passing a make function to .__items__(..)
// which in turn will call this make(..) per item created. // which in turn will call this make(..) per item created.
// //
// For more doc on item construction see: .__init__(..) // For more doc on item construction see: .__init__(..)
@ -1159,7 +1176,7 @@ var BaseBrowserPrototype = {
// identify an item thus no state is maintained between .make(..) // identify an item thus no state is maintained between .make(..)
// calls for such items... // calls for such items...
// //
// XXX revise options handling for .__list__(..) // XXX revise options handling for .__items__(..)
// XXX might be a good idea to enable the user to merge the state // XXX might be a good idea to enable the user to merge the state
// manually... // manually...
// one way to do: // one way to do:
@ -1167,19 +1184,30 @@ var BaseBrowserPrototype = {
// - update it // - update it
// - pass it to make(..) // - pass it to make(..)
// Example: // Example:
// // just a rough example in .__list__(..)... // // just a rough example in .__items__(..)...
// make(value, // make(value,
// value in this.index ? // value in this.index ?
// Object.assign( // Object.assign(
// this.index[value], // this.index[value],
// opts) // opts)
// : opts) // : opts)
// XXX revise if stage 2 is applicable to sections other than .items
make: function(options){ make: function(options){
var that = this var that = this
options = Object.assign( options = Object.assign(
Object.create(this.options || {}), Object.create(this.options || {}),
options || {}) options || {})
// sections to make...
var sections = options.section == '*' ?
(options.sections || ['header', 'items', 'footer'])
: (options.section || 'items')
sections = (sections instanceof Array ?
sections
: [sections])
// keep only sections we know how to make...
.filter(function(name){
return that[`__${name}__`] instanceof Function })
// item constructor... // item constructor...
// //
@ -1203,9 +1231,10 @@ var BaseBrowserPrototype = {
// while the latter stores a list of items. // while the latter stores a list of items.
// ...would be more logical to store the object (i.e. browser/list) // ...would be more logical to store the object (i.e. browser/list)
// directly as the element... // directly as the element...
var section
var make_called = false var make_called = false
var list = []
var ids = new Set() var ids = new Set()
var list = []
var keys = options.uniqueKeys ? var keys = options.uniqueKeys ?
new Set() new Set()
: null : null
@ -1278,8 +1307,8 @@ var BaseBrowserPrototype = {
// user extended make... // user extended make...
// XXX differentiate this for header and list... // XXX differentiate this for header and list...
//this.__make__ this.__make__
// && this.__make__(item) && this.__make__(section, item)
// store the item... // store the item...
list.push(item) list.push(item)
@ -1290,22 +1319,17 @@ var BaseBrowserPrototype = {
make.__proto__ = Items make.__proto__ = Items
make.dialog = this make.dialog = this
// build the lists... // build the sections...
//* XXX sections
;[...(this.__header__ ? .forEach(function(name){
[['__header__', 'header']]
: []),
['__list__', 'items']]
.forEach(function([method, name]){
// setup closure for make(..)... // setup closure for make(..)...
section = name
make_called = false make_called = false
ids = new Set() ids = new Set()
list = make.items = that[name] = [] list = make.items = that[name] = []
// build list... // build list...
// XXX check that this is enough... var res = that[`__${name}__`](make,
// ...do we index header items???
var res = that[method](make,
// XXX not sure about this -- revise options handling... // XXX not sure about this -- revise options handling...
options ? options ?
Object.assign( Object.assign(
@ -1313,50 +1337,36 @@ var BaseBrowserPrototype = {
options || {}) options || {})
: null) : null)
// if make was not called use the .__list__(..) return value... // if make was not called use the .__items__(..) return value...
that[name] = make_called ? that[name] = make_called ?
that[name] that[name]
: res }) : res })
/*/
// setup closure for make(..)...
list = make.items = this.items = []
// XXX not sure about this -- revise options handling...
var res = this.__list__(make,
options ?
Object.assign(
Object.create(this.options || {}),
options || {})
: null)
// if make was not called use the .__list__(..) return value...
this.items = make_called ?
this.items
: res
//*/
// reset the index/cache... // reset the index/cache...
var old_index = this.__item_index_cache || {} // XXX should this be only for .items???
this.clearCache() // ...should this be global (all items?)
if(sections.includes('items')){
var old_index = this.__item_index_cache || {}
this.clearCache()
// 2'nd pass -> make item index (unique id's)... // 2'nd pass -> make item index (unique id's)...
// NOTE: we are doing this in a separate pass as items can get // NOTE: we are doing this in a separate pass as items can get
// rearranged during the make phase (Items.nest(..) ...), // rearranged during the make phase (Items.nest(..) ...),
// thus avoiding odd duplicate index numbering... // thus avoiding odd duplicate index numbering...
// XXX should we also index header??? var index = this.__item_index_cache = this.index
var index = this.__item_index_cache = this.index
// post process the items... // post process the items...
Object.entries(index) Object.entries(index)
.forEach(function([id, e]){ .forEach(function([id, e]){
// update item.id of items with duplicate keys... // update item.id of items with duplicate keys...
!id.endsWith(that.__key__(e)) !id.endsWith(that.__key__(e))
&& (e.id = id.split(/[\/]/g).pop()) && (e.id = id.split(/[\/]/g).pop())
// merge old item state... // merge old item state...
id in old_index id in old_index
// XXX this is not very elegant(???), revise... // XXX this is not very elegant(???), revise...
&& Object.assign(e, && Object.assign(e,
old_index[id], old_index[id],
e) }) e) }) }
return this return this
}, },
@ -1539,7 +1549,16 @@ var BaseBrowserPrototype = {
context.index = context.index || 0 context.index = context.index || 0
// options specifics... // options specifics...
var source = options.source || 'items' // NOTE: we include header/footer only for the root context...
var sections = context.root === this ?
'items'
: options.section == '*' ?
(options.sections || 'items')
: (options.section || 'items')
sections = sections instanceof Array ?
sections
: [sections]
var iterateNonIterable = options.iterateAll || options.iterateNonIterable var iterateNonIterable = options.iterateAll || options.iterateNonIterable
var iterateCollapsed = options.iterateAll || options.iterateCollapsed var iterateCollapsed = options.iterateAll || options.iterateCollapsed
var skipNested = !options.iterateAll && options.skipNested var skipNested = !options.iterateAll && options.skipNested
@ -1710,11 +1729,14 @@ var BaseBrowserPrototype = {
}, },
[], [],
// input items... // input items...
...(reverse ? ...(sections
this[source] .map(function(name){
.slice() return that[name] || [] })
.reverse() .flat()
: this[source])) }, .run(function(){
return reverse ?
this.reverse()
: this }))) },
// Test/Example Text renders... // Test/Example Text renders...
@ -3083,10 +3105,10 @@ var BaseBrowserPrototype = {
// XXX should we update on init.... // XXX should we update on init....
__init__: function(func, options){ __init__: function(func, options){
var args = [...arguments] var args = [...arguments]
this.__list__ = args.shift() this.__items__ = args.shift()
if(args[0] instanceof Function){ if(args[0] instanceof Function){
this.__header__ = this.__list__ this.__header__ = this.__items__
this.__list__ = args.shift() this.__items__ = args.shift()
} }
this.options = Object.assign( this.options = Object.assign(
Object.create(this.options || {}), Object.create(this.options || {}),
@ -3555,18 +3577,6 @@ var HTMLBrowserPrototype = {
this.__dom = value }, this.__dom = value },
// XXX header...
// XXX might be a good idea to make this expandable -- show/hide options...
__header__: function(make, options){
make('CURRENT_PATH', {
id: 'current_path',
cls: 'path',
buttons: (options || {}).headerButtons
|| (this.options || {}).headerButtons
|| [],
}) },
// Extending query... // Extending query...
// //
// Extended .search(..) to support: // Extended .search(..) to support: