some cleanup and refactoring...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2019-06-19 02:34:23 +03:00
parent 14b3d7aed7
commit f12b357b28

View File

@ -642,6 +642,9 @@ var BaseBrowserPrototype = {
updateTimeout: 30,
},
// Props and introspection...
// parent widget object...
//
// NOTE: this may or may not be a Browser object.
@ -809,6 +812,53 @@ var BaseBrowserPrototype = {
return this.map({iterateAll: true}).length },
// Configuration / Extension...
// XXX need a better key/path API...
//
// Normalize value...
__value2key__: function(key){
//return JSON.stringify(key)
return key instanceof Array ?
key.join(' ')
: key },
// Key getter/generator...
__key__: function(item){
return item.id
// value is a browser -> generate an unique id...
// XXX identify via structure...
|| (item.value instanceof Browser
&& this.__id__())
|| this.__value2key__(item.value) },
// ID generator...
//
// .__id__()
// .__id__(prefix)
// .__id__(prefix, count)
// -> id
//
// Format:
// "<date>"
// "<prefix>:<count>"
// "<prefix>:<date>"
//
// XXX not sure about the logic of this, should this take an item as
// input and return an id???
// ...should this check for uniqueness???
// think merging this with any of the actual ID generators would be best...
__id__: function(prefix, count){
return prefix ?
// id prefix...
//`${prefix} (${count || Date.now()})`
`${prefix}:${count || Date.now()}`
// plain id...
: `item${Date.now()}` },
// Data generation (make)...
// Item list constructor...
//
// .__list__(make, options)
@ -880,48 +930,197 @@ var BaseBrowserPrototype = {
throw new Error('.__list__(..): Not implemented.') },
// XXX need a better key/path API...
// Make extension...
//
// Normalize value...
__value2key__: function(key){
//return JSON.stringify(key)
return key instanceof Array ?
key.join(' ')
: key },
// This is called per item created by make(..) in .__list__(..)
//
// NOTE: this can update/modify the item but it can not replace it.
//__make__: function(item){
//},
// Key getter/generator...
__key__: function(item){
return item.id
// value is a browser -> generate an unique id...
// XXX identify via structure...
|| (item.value instanceof Browser
&& this.__id__())
|| this.__value2key__(item.value) },
// ID generator...
// Make .items and .index...
//
// .__id__()
// .__id__(prefix)
// .__id__(prefix, count)
// -> id
// .make()
// .make(options)
// -> this
//
// Format:
// "<date>"
// "<prefix>:<count>"
// "<prefix>:<date>"
// The items are constructed by passing a make function to .__list__(..)
// which in turn will call this make(..) per item created.
//
// XXX not sure about the logic of this, should this take an item as
// input and return an id???
// ...should this check for uniqueness???
// think merging this with any of the actual ID generators would be best...
__id__: function(prefix, count){
return prefix ?
// id prefix...
//`${prefix} (${count || Date.now()})`
`${prefix}:${count || Date.now()}`
// plain id...
: `item${Date.now()}` },
// For more doc on item construction see: .__init__(..)
//
//
// NOTE: each call to this will reset both .items and .index
// NOTE: for items with repeating values there is no way to correctly
// identify an item thus no state is maintained between .make(..)
// calls for such items...
//
// XXX revise options handling for .__list__(..)
// XXX might be a good idea to enable the user to merge the state
// manually...
// one way to do:
// - get the previous item via an index,
// - update it
// - pass it to make(..)
// Example:
// // just a rough example in .__list__(..)...
// make(value,
// value in this.index ?
// Object.assign(
// this.index[value],
// opts)
// : opts)
make: function(options){
var that = this
options = Object.assign(
Object.create(this.options || {}),
options || {})
var items = this.items = []
// item constructor...
//
// Make an item...
// make(value[, options])
// make(value, func[, options])
// -> make
//
// Inline a browser instance...
// make(browser)
// -> make
//
//
// NOTE: when inlining a browser, options are ignored.
// NOTE: when inlining a browser it's .parent will be set this
// reusing the inlined object browser may mess up this
// property...
//
// XXX problem: make(Browser(..), ..) and make.group(...) produce
// different formats -- the first stores {value: browser, ...}
// while the latter stores a list of items.
// ...would be more logical to store the object (i.e. browser/list)
// directly as the element...
var keys = options.uniqueKeys ?
new Set()
: null
var ids = new Set()
var make_called = false
var make = function(value, opts){
make_called = true
// special-case: inlined browser...
//
// NOTE: we ignore opts here...
// XXX not sure if this is the right way to go...
// ...for removal just remove the if statement and its
// first branch...
if(value instanceof Browser){
var item = value
item.parent = this
// normal item...
} else {
var args = [...arguments]
opts = opts || {}
// handle: make(.., func, ..)
opts = opts instanceof Function ?
{open: opts}
: opts
// handle trailing options...
opts = args.length > 2 ?
Object.assign({},
args.pop(),
opts)
: opts
opts = Object.assign(
{},
opts,
{value: value})
// item id...
var key = this.__key__(opts)
// duplicate keys (if .options.uniqueKeys is set)...
if(keys){
if(keys.has(key)){
throw new Error(`make(..): duplicate key "${key}": `
+`can't create multiple items with the same key `
+`when .options.uniqueKeys is set.`)
}
keys.add(key)
}
// duplicate ids...
if(opts.id && ids.has(opts.id)){
throw new Error(`make(..): duplicate id "${opts.id}": `
+`can't create multiple items with the same id.`) }
// build the item...
var item = Object.assign(
Object.create(options || {}),
opts,
{ parent: this })
// XXX do we need both this and the above ref???
item.children instanceof Browser
&& (item.children.parent = this)
}
// user extended make...
this.__make__
&& this.__make__(item)
// store the item...
items.push(item)
ids.add(key)
return make
}.bind(this)
make.__proto__ = Items
make.dialog = this
make.items = items
//var res = this.__list__(make)
// 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...
var old_index = this.__item_index_cache || {}
this.clearCache()
// 2'nd pass -> make item index (unique id's)...
// NOTE: we are doing this in a separate pass as items can get
// rearranged during the make phase (Items.nest(..) ...),
// thus avoiding odd duplicate index numbering...
var index = this.__item_index_cache = this.index
// post process the items...
Object.entries(index)
.forEach(function([id, e]){
// update item.id of items with duplicate keys...
!id.endsWith(that.__key__(e))
&& (e.id = id.split(/[\/]/g).pop())
// merge old item state...
id in old_index
// XXX this is not very elegant(???), revise...
&& Object.assign(e,
old_index[id],
e) })
return this
},
// Data access and iteration...
// Walk the browser...
//
@ -2008,198 +2207,12 @@ var BaseBrowserPrototype = {
&& that.expand([...nodes]) }) },
// XXX do we need edit ability here?
// i.e. .set(..), .remove(..), .sort(..), ...
// ...if we are going to implement editing then we'll need to
// callback the user code or update the user state...
//__make__: function(item){
//},
// Make .items and .index...
//
// .make()
// .make(options)
// -> this
//
// The items are constructed by passing a make function to .__list__(..)
// which in turn will call this make(..) per item created.
//
// For more doc on item construction see: .__init__(..)
//
//
// NOTE: each call to this will reset both .items and .index
// NOTE: for items with repeating values there is no way to correctly
// identify an item thus no state is maintained between .make(..)
// calls for such items...
//
// XXX revise options handling for .__list__(..)
// XXX might be a good idea to enable the user to merge the state
// manually...
// one way to do:
// - get the previous item via an index,
// - update it
// - pass it to make(..)
// Example:
// // just a rough example in .__list__(..)...
// make(value,
// value in this.index ?
// Object.assign(
// this.index[value],
// opts)
// : opts)
make: function(options){
var that = this
options = Object.assign(
Object.create(this.options || {}),
options || {})
var items = this.items = []
// item constructor...
//
// Make an item...
// make(value[, options])
// make(value, func[, options])
// -> make
//
// Inline a browser instance...
// make(browser)
// -> make
//
//
// NOTE: when inlining a browser, options are ignored.
// NOTE: when inlining a browser it's .parent will be set this
// reusing the inlined object browser may mess up this
// property...
//
// XXX problem: make(Browser(..), ..) and make.group(...) produce
// different formats -- the first stores {value: browser, ...}
// while the latter stores a list of items.
// ...would be more logical to store the object (i.e. browser/list)
// directly as the element...
var keys = options.uniqueKeys ?
new Set()
: null
var ids = new Set()
var make_called = false
var make = function(value, opts){
make_called = true
// special-case: inlined browser...
//
// NOTE: we ignore opts here...
// XXX not sure if this is the right way to go...
// ...for removal just remove the if statement and its
// first branch...
if(value instanceof Browser){
var item = value
item.parent = this
// normal item...
} else {
var args = [...arguments]
opts = opts || {}
// handle: make(.., func, ..)
opts = opts instanceof Function ?
{open: opts}
: opts
// handle trailing options...
opts = args.length > 2 ?
Object.assign({},
args.pop(),
opts)
: opts
opts = Object.assign(
{},
opts,
{value: value})
// item id...
var key = this.__key__(opts)
// duplicate keys (if .options.uniqueKeys is set)...
if(keys){
if(keys.has(key)){
throw new Error(`make(..): duplicate key "${key}": `
+`can't create multiple items with the same key `
+`when .options.uniqueKeys is set.`)
}
keys.add(key)
}
// duplicate ids...
if(opts.id && ids.has(opts.id)){
throw new Error(`make(..): duplicate id "${opts.id}": `
+`can't create multiple items with the same id.`) }
// build the item...
var item = Object.assign(
Object.create(options || {}),
opts,
{ parent: this })
// XXX do we need both this and the above ref???
item.children instanceof Browser
&& (item.children.parent = this)
}
// user extended make...
this.__make__
&& this.__make__(item)
// store the item...
items.push(item)
ids.add(key)
return make
}.bind(this)
make.__proto__ = Items
make.dialog = this
make.items = items
//var res = this.__list__(make)
// 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...
var old_index = this.__item_index_cache || {}
this.clearCache()
// 2'nd pass -> make item index (unique id's)...
// NOTE: we are doing this in a separate pass as items can get
// rearranged during the make phase (Items.nest(..) ...),
// thus avoiding odd duplicate index numbering...
var index = this.__item_index_cache = this.index
// post process the items...
Object.entries(index)
.forEach(function([id, e]){
// update item.id of items with duplicate keys...
!id.endsWith(that.__key__(e))
&& (e.id = id.split(/[\/]/g).pop())
// merge old item state...
id in old_index
// XXX this is not very elegant(???), revise...
&& Object.assign(e,
old_index[id],
e) })
return this
},
// Renderers...
//
// .renderFinalize(items, context)
@ -3154,6 +3167,7 @@ var BrowserPrototype = {
// Keyboard...
//
__keyboard_config: Object.assign({}, KEYBOARD_CONFIG),
get keybindings(){
return this.__keyboard_config },
@ -3185,6 +3199,8 @@ var BrowserPrototype = {
this)) },
// DOM props..
//
// parent element (optional)...
// XXX rename???
// ... should this be .containerDom or .parentDom???
@ -3210,6 +3226,9 @@ var BrowserPrototype = {
: this.container.appendChild(value))
this.__dom = value },
// Extending query...
//
// Extended .search(..) to support:
// - 'pagetop'
// - 'pagebottom'
@ -3280,7 +3299,7 @@ var BrowserPrototype = {
// call parent...
return object.parent(BrowserPrototype.search, this).call(this, pattern, ...args) },
//
// Extended .get(..) to support:
// - 'pagetop'/'pagebottom' + offset...
//
@ -3309,7 +3328,7 @@ var BrowserPrototype = {
: object.parent(BrowserPrototype.get, this).call(this, pattern, func, ...args) },
// DOM/UI Helpers...
// Copy/Paste support...
//
// NOTE: not for direct use...
// NOTE: both of these feel hackish...
@ -3728,17 +3747,6 @@ var BrowserPrototype = {
},
// scroll...
//
scrollTo: function(pattern, position){
var target = this.get(pattern)
target
&& getElem(target).scrollIntoView({
behavior: (this.options || {}).scrollBehavior || 'auto',
block: position || 'center',
}) },
// Custom events handlers...
//
// NOTE: this will also kill any user-set keys for disabled/hidden items...
@ -3838,6 +3846,17 @@ var BrowserPrototype = {
menu: makeItemEventMethod('menu'),
// Scroll...
//
scrollTo: function(pattern, position){
var target = this.get(pattern)
target
&& getElem(target).scrollIntoView({
behavior: (this.options || {}).scrollBehavior || 'auto',
block: position || 'center',
}) },
// Navigation...
//
// hold key repeat on first/last elements + reveal disabled items at