From: dsc Date: Fri, 17 Dec 2010 12:00:33 +0000 (-0800) Subject: Config UI scaffold. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=693c3ded68a712f277990a3d6ed369ac2f586d19;p=tanks.git Config UI scaffold. --- diff --git a/src/tanks/util/config.cjs b/src/Y/modules/y.config.cjs similarity index 59% copy from src/tanks/util/config.cjs copy to src/Y/modules/y.config.cjs index 2b90bba..ff41a55 100644 --- a/src/tanks/util/config.cjs +++ b/src/Y/modules/y.config.cjs @@ -1,23 +1,31 @@ var Y = require('Y').Y -, Emitter = require('Y/modules/y.event').Emitter +, getNested = require('Y/types/object').getNested +, Emitter = require('Y/modules/y.event').Emitter , Config = -exports.Config = -Y.YObject.subclass('Config', function(){ +exports['Config'] = +Y.YObject.subclass('Config', function(Config){ Y.core.extend(this, { init : function initConfig(defaults){ - this._defaults = defaults; - this._o = Y({}, defaults); + this._defaults = defaults || {}; + this._o = Y({}, this._defaults); this.__emitter__ = new Emitter(this); }, + clone : function clone(){ + var c = new Config(); + c._defaults = this._defaults; + c._o = c._o.clone(); + return c; + }, + set : function set(key, value, def){ if ( key !== undefined ){ - var meta = this.ensure(key).getNested(key, def, true) + var meta = this.ensure(key).getNestedMeta(key, def) , old = meta.value ; def = (def === undefined ? old : def); value = (value === undefined ? def : value); @@ -31,7 +39,7 @@ Y.YObject.subclass('Config', function(){ remove : function remove(key){ if ( key !== undefined ){ var sentinel = {} - , meta = this.getNested(key, sentinel, true) + , meta = this.getNestedMeta(key, sentinel) , old = (meta.value === sentinel ? undefined : old); if ( meta.obj ) { @@ -67,6 +75,7 @@ Y.YObject.subclass('Config', function(){ context = context || this; var ret = Y.reduce(this._o, this._reducer, { + 'fn' : fn, 'acc' : acc, 'path' : new Y.YArray(), 'cxt' : context @@ -89,12 +98,46 @@ Y.YObject.subclass('Config', function(){ // Normal value -- invoke iterator else - state.acc = fn.call(state.cxt, state.acc, v, chain, this); + state.acc = state.fn.call(state.cxt, state.acc, v, chain, this); state.path.pop(); return state; + }, + + /** + * Iterates over both items and groups of the config object. + */ + parts : function parts(groupFn, itemFn, acc, context){ + context = context || this; + + var path = new Y.YArray(); + return Y.reduce(this._o, + function _parts(acc, v, k, o){ + var chain = path.push(k).join('.'); + + // Nested object -- recurse + if ( Y.isPlainObject(v) ){ + acc = groupFn.call(context, acc, v, chain, this); + acc = Y.reduce(v, _parts, acc, this); + + // Normal value -- invoke iterator + } else + acc = itemFn.call(context, acc, v, chain, this); + + path.pop(); + return acc; + }, + acc, this); + }, + + getDefault : function getDefault(k, def){ + return getNested(this._defaults, k, def); } }); + this['get'] = this.getNested; + }); + +Y['config'] = exports; diff --git a/src/Y/modules/y.scaffold.cjs b/src/Y/modules/y.scaffold.cjs new file mode 100644 index 0000000..45a9d5c --- /dev/null +++ b/src/Y/modules/y.scaffold.cjs @@ -0,0 +1,151 @@ +//#ensure "jquery" +var Y = require('Y').Y +, Emitter = require('Y/modules/y.event').Emitter +, op = Y.op + + +, upperPat = /^[A-Z]+$/ +, symbolPat = /^[^a-zA-Z]+$/ +, +camelToSpaces = +exports['camelToSpaces'] = +function camelToSpaces(s){ + return Y(s).reduce( + function(acc, ch, i){ + return acc + ( + symbolPat.test(ch) ? '' : + (upperPat.test(ch) ? ' '+ch : ch) ); + }, ''); +} +, + +type2parser = { + 'Boolean' : op.parseBool, + 'Number' : parseFloat, + 'String' : String +} +, + +type2el = { + 'Boolean' : 'checkbox', + 'Number' : 'text', + 'String' : 'text' + // 'Array' : 'select', + // 'Date' : 'datepicker', + // 'RegExp' : 'text' +} +, + + + +Field = +exports['Field'] = +Y.subclass('Field', { + + init : function initField(chain, def, val, options){ + options = options || {}; + this.__emitter__ = new Emitter(this); + + this.id = chain; + this.def = def; + this.val = this.old = val === undefined ? def : val; + this.key = chain.split('.').pop(); + this.label = camelToSpaces(this.key); + + var T = Y(Y.type(val)).getName(); + this.cast = options.cast || type2parser[T]; + this.type = options.type || type2el[T]; + + if (!this.cast) + throw new Error('No parser defined for type "'+T+'"'); + if (!this.type) + throw new Error('No field element defined for type "'+T+'"'); + + this.build() + .update(this.val); + + this.elField.bind('change', this.onChange.bind(this)); + }, + + build : function build(){ + var el = + this.el = + jQuery('
') + .addClass('field'); + this.elLabel = + jQuery('