From 9ff081da7f80bd05e6ee69f15b884e0f51ebef52 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Mon, 16 Mar 2015 20:40:08 +0300 Subject: [PATCH] started refactoring the browser widget... Signed-off-by: Alex A. Naanou --- ui (gen4)/experiments/browse-dialog.html | 284 ++++++++++++++++++++++- 1 file changed, 282 insertions(+), 2 deletions(-) diff --git a/ui (gen4)/experiments/browse-dialog.html b/ui (gen4)/experiments/browse-dialog.html index 7d3857ff..22f89c26 100755 --- a/ui (gen4)/experiments/browse-dialog.html +++ b/ui (gen4)/experiments/browse-dialog.html @@ -399,9 +399,289 @@ var KB = { } +//--- -requirejs(['../lib/keyboard'], function(m){ - keyboard = m +var BrowserClassPrototype = { + // construct the dom... + make: function(){ + var browser = $('
') + .addClass('browse') + // make thie widget focusable... + // NOTE: tabindex 0 means automatic tab indexing and -1 means + // focusable bot not tabable... + //.attr('tabindex', -1) + .attr('tabindex', 0) + // focus the widget if something inside is clicked... + .click(function(){ + $(this).focus() + }) + .append($('
') + .addClass('v-block title') + .text(title)) + .append($('
') + .addClass('v-block path')) + .append($('
') + .addClass('v-block list')) + .append($('
') + .addClass('v-block info')) + .append($('
') + .addClass('v-block actions')) + return browser + }, +} + +var BrowserPrototype = { + dom: null, + + keyboard: { + '.browse':{ + Up: 'prev', + Backspace: 'Up', + Down: 'next', + Left: 'pop', + Right: 'push', + + Enter: 'action', + Esc: 'close', + }, + }, + + // base api... + // NOTE: to avoid duplicating and syncing data, the actual path is + // stored in DOM... + get path(){ + var skip = false + return this.dom.find('.path .dir') + .map(function(i, e){ return $(e).text() }) + .toArray() + }, + set path(value){ + // XXX normalize path... + return this.update(path) + }, + + // update path... + update: function(path){ + var browser = this.dom + + var p = browser.find('.path').empty() + var l = browser.find('.list').empty() + + // fill the path field... + path.forEach(function(e){ + p.append($('
') + .addClass('dir') + .click(popDir) + .text(e)) + }) + + // fill the children list... + this.list(path) + .forEach(function(e){ + l.append($('
') + .click(pushDir) + .text(e)) + }) + + return this + }, + + // internal actions... + + // + // Select first/last child + // .select('first') + // .select('last') + // -> elem + // + // Select previous/lext child + // .select('prev') + // .select('next') + // -> elem + // + // Deselect + // .select('none') + // -> elem + // + // Get selected element if it exists, null otherwise... + // .select('!') + // -> elem + // -> $() + // + // Select element by sequence number + // .select() + // -> elem + // + // Select element by its text... + // .select('""') + // -> elem + // + // .select() + // -> elem + // + // This will return a jQuery object. + // + // + // XXX revise return values... + select: function(elem){ + var browser = this.dom + var elems = browser.find('.list div') + + if(elems.length == 0){ + return $() + } + + elem = elem || this.select('!') + // if none selected get the first... + elem = elem.length == 0 ? 'first' : elem + + // first/last... + if(elem == 'first' || elem == 'last'){ + return this.select(elems[elem]()) + + // prev/next... + } else if(elem == 'prev' || elem == 'next'){ + var to = this.select('!', browser)[elem]('.list div') + if(to.length == 0){ + return this.select(elem == 'prev' ? 'last' : 'first', browser) + } + this.select('none') + return this.select(to) + + // deselect... + } else if(elem == 'none'){ + return elems + .filter('.selected') + .removeClass('selected') + + // strict... + } else if(elem == '!'){ + return elems.filter('.selected') + + // number... + } else if(typeof(elem) == typeof(123)){ + return this.select($(elems[elem])) + + // string... + } else if(typeof(elem) == typeof('str') + && /^'.*'$|^".*"$/.test(elem.trim())){ + elem = elem.trim().slice(1, -1) + return this.select(browser.find('.list div') + .filter(function(i, e){ + return $(e).text() == elem + })) + + // element... + } else { + this.select('none') + return elem.addClass('selected') + } + }, + + // XXX check if we need to do the ,action when the element id not traversable... + push: function(elem){ + var browser = this.dom + var elem = this.select(elem || '!') + + // nothing selected, select first and exit... + if(elem.length == 0){ + this.select() + return this + } + + + this + .update(this.path.push(elem.text())) + .select() + + return this + }, + // pop an element off the path / go up one level... + pop: function(){ + var browser = this.dom + var path = this.path + var dir = path.pop() + + this.update(path) + + this.select('"'+dir+'"') + + return this + }, + next: function(elem){ + if(elem != null){ + this.select(elem) + } + this.select('next') + return this + }, + prev: function(elem){ + if(elem != null){ + this.select(elem) + } + this.select('prev') + return this + }, + + // XXX think about the API... + action: function(){ + var res = this.open(this.path) + + // XXX close the dialog if everything is OK... + // XXX + + return res + }, + // close the dialog... + // XXX + close: function(){ + }, + + // extension methods... + // XXX think about the API... + // needs to control closing of the dialog + open: function(){ + }, + list: function(){ + }, + isTraversable: null, + + // XXX + __init__: function(parent){ + // build the dom... + var dom = this.dom = this.constructor.make() + + // add keyboard handler... + dom.keydown( + keyboard.makeKeyboardHandler( + this.keyboard, + function(k){ window.DEBUG && console.log(k) }, + this)) + + // attach to parent... + if(parent != null){ + parent.append(dom) + } + }, +} + + +/* +var Browser = +//module.Browser = +object.makeConstructor('Browser', + BrowserClassPrototype, + BrowserPrototype) +*/ + + + +//--- + + +requirejs(['../lib/keyboard', '../object'], function(k, o){ + keyboard = k + object = o // setup base keyboard for devel, in case something breaks... //$(document)