added support for custom listers in PathList(..)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2015-08-31 20:13:29 +03:00
parent 21c46d5b75
commit 09a67ee983
3 changed files with 161 additions and 52 deletions

View File

@ -247,11 +247,36 @@ requirejs(['../lib/keyboard', '../object', './browse-dialog'], function(k, o, br
// XXX need a way to trigger open ecents with touch/mouse...
'/dir 1': function(_, p){ console.log('dir:', p) },
'dir 1/option 1': function(_, p){ console.log('option:', p) },
'dir 1/option 2': function(_, p){ console.log('option:', p) },
'dir 1/option 2/': function(_, p){ console.log('option:', p) },
'dir 2/option 3': function(_, p){ console.log('option:', p) },
'option 4': function(_, p){ console.log('option:', p) },
'option 5': function(_, p){ console.log('option:', p) },
'option 6': function(_, p){ console.log('option:', p) },
// XXX this is the wrong way to do this, but it shows a bug...
// XXX BUG: for some reason 2 and 3 are set to traversable while
// 1 is not...
'option 5': function(_, p){
console.log('option:', p)
f3.update(p + '/', function(){ return [1, 2, 3] })
},
// render a custom sub-tree...
'dynamic/*': function(path, make){
console.log('option:', path)
return [1,2,3]
.map(function(e){
make(e, true)
return e
})
},
// this will override the 'dynamic/*' in case of longer
// matches...
'dynamic/1/1/*': function(path, make){
make('mooo!/')
make('fooo!')
},
})
})

View File

@ -503,11 +503,12 @@ var BrowserPrototype = {
// path due to an error, we need to be able to render the new
// path both in the path and list sections...
// NOTE: current behaviour is not wrong, it just not too flexible...
update: function(path){
update: function(path, list){
path = path || this.path
var browser = this.dom
var that = this
var focus = browser.find(':focus').length > 0
list = list || this.list
// string path and terminated with '/' -- no selection...
if(typeof(path) == typeof('str') && !/[\\\/]/.test(path.trim().slice(-1))){
@ -519,7 +520,7 @@ var BrowserPrototype = {
var selection = null
}
// clear the ui...
var p = browser.find('.path').empty()
var l = browser.find('.list').empty()
@ -583,11 +584,18 @@ var BrowserPrototype = {
}
// fill the children list...
// NOTE: this will be set to true if make(..) is called at least once...
var interactive = false
var make = function(p, traversable){
traversable = traversable == null ? true : traversable
p = p + ''
var dir = /[\\\/]\s*$/
traversable = dir.test(p) && traversable == null ? true : traversable
traversable = traversable == null ? false : traversable
p = p.replace(dir, '')
interactive = true
var res = $('<div>')
// handle clicks ONLY when not disabled...
.click(function(){
@ -603,8 +611,11 @@ var BrowserPrototype = {
return res
}
var res = this.list(path, make)
// build the list...
var res = list.call(this, path, make)
// second API: make is not called and .list(..) returns an Array
// that will get loaded as list items...
if(!interactive){
res.forEach(make)
}
@ -665,7 +676,7 @@ var BrowserPrototype = {
// every element that was rejected by the predicate / not matching
// the pattern.
//
// By default, <ignore-disabled> is false, thus this will ignore
// By default, <ignore-disabled> is true, thus this will ignore
// disabled elements. If <ignore_disabled> is false then disabled
// elements will be searched too.
//
@ -1640,22 +1651,65 @@ module.makeList = function(elem, list){
/*********************************************************************/
// This full compatible with List(..) but will parse paths in keys...
// This is similar to List(..) but will parse paths in keys...
//
// For example:
// Format:
// {
// 'a/b': ..,
// 'a/c': ..,
// 'd': ..,
// // basic 'file' path...
// // NOTE: this path is non-traversable by default, but if a
// // sub-path handler is defined (e.g. 'dir/file/x') then this
// // will be set traversable...
// 'dir/file': function(evt, path){ .. },
//
// // file object at the tree root...
// // NOTE: the leading '/' is optional...
// 'file': function(evt, path){ .. },
//
// // a directory handler is defined by path ending with '/',
// // set traversable...
// 'dir/dir/': function(evt, path){ .. },
//
//
// // path lister...
// 'dynamic/*': function(path, make){ .. }
// }
//
// will translate into:
// a/
// b
// c
// d
// The above definition will be interpreted into the following tree:
//
// /
// dir/
// file
// dir/
// file
// dynamic/
// ..
//
// Here the contents of the '/dynamic/' path are generated by the matching
// lister for that pattern path...
//
// NOTE: there may be multiple matching patterns/listers or a given path
// the one used is the longest match.
//
//
// Handler format:
// function(evt, path){ .. }
//
// This function will be called on the 'open' event for the defined
// item.
//
//
// Lister format:
// function(path, make){ .. } -> list
//
// This function will get called on .update(..) of the matching path.
//
// make(text, traversable) is a list item constructor.
// for more docs see: Browser.list(..)
//
//
// NOTE: currently only trailing '*' are supported.
//
// XXX add support for '*' and '**' glob patterns...
var PathListPrototype = Object.create(BrowserPrototype)
PathListPrototype.options = {
@ -1670,48 +1724,71 @@ PathListPrototype.options = {
var visited = []
return keys
.map(function(k){
var kp = k.split(/[\\\/]+/g)
kp[0] == '' && kp.shift()
// get the '*' listers...
var lister = keys
.filter(function(k){ return k.trim().slice(-1) == '*' })
.filter(function(k){
return k
.split(/[\\\/]+/)
// remove the '*'...
.slice(0, -1)
// do the match...
.filter(function(e, i){ return e != path[i] }).length == 0 })
.sort(function(a, b){ return a.length - b.length})
.pop()
// get and check current path, continue if relevant...
var p = kp.splice(0, path.length)
if(kp.length == 0
|| p.length < path.length
|| p.filter(function(e, i){ return e != path[i] }).length > 0){
return false
}
// use the custom lister (defined by trailing '*')...
if(data !== keys && lister){
return data[lister].call(this, '/' + path.join('/'), make)
// list via provided paths...
} else {
return keys
.map(function(k){
var kp = k.split(/[\\\/]+/g)
kp[0] == '' && kp.shift()
// get current path element if one exists and we did not create it already...
cur = kp.shift()
if(cur == undefined){
return false
}
// see if we have a star...
var star = kp.slice(-1)[0] == '*'
star && kp.pop()
if(visited.indexOf(cur) >= 0){
// set element to traversable...
if(kp.length > 0){
that.filter(cur).removeClass('not-traversable')
// get and check current path, continue if relevant...
var p = kp.splice(0, path.length)
if(kp.length == 0
|| p.length < path.length
|| p.filter(function(e, i){ return e != path[i] }).length > 0){
return false
}
return false
}
visited.push(cur)
// build the element....
var e = make(cur, kp.length > 0)
// get current path element if one exists and we did not create it already...
cur = kp.shift()
if(cur == undefined){
return false
}
// setup handlers...
if(data !== keys && kp.length == 0){
e.on('open', function(){
return that.options.data[k].apply(this, arguments)
})
}
if(visited.indexOf(cur) >= 0){
// set element to traversable...
if(kp.length > 0){
that.filter(cur).removeClass('not-traversable')
}
return false
}
visited.push(cur)
return cur
})
.filter(function(e){ return e !== false })
// build the element....
var e = make(cur, star || kp.length > 0)
// setup handlers...
if(!star && data !== keys && kp.length == 0){
e.on('open', function(){
return that.options.data[k].apply(this, arguments)
})
}
return cur
})
.filter(function(e){ return e !== false })
}
},
}
PathListPrototype.options.__proto__ = BrowserPrototype.options

View File

@ -64,6 +64,13 @@ function makeConstructor(name, a, b){
}
// super equivalent...
var parent =
module.parent =
function parent(obj){
return obj.__proto__.__proto__
}
/**********************************************************************
* vim:set ts=4 sw=4 : */