diff --git a/ui (gen4)/features/examples.js b/ui (gen4)/features/examples.js index 8430a43d..c75111eb 100755 --- a/ui (gen4)/features/examples.js +++ b/ui (gen4)/features/examples.js @@ -824,12 +824,97 @@ var ExampleUIActions = actions.Actions({ exampleDialogListerL: ['Test/Combined dialog & lister (lister mode)/*', 'exampleDialogLister: ...'], + testList: ['Test/List/*', function(path, make){ return function(){ make('A') make('B') make('C') } }], + + + exampleEditor: ['Test/Universal $editor...', + widgets.uiDialog(function(spec, callback){ + return this.makeEditor( + spec || [ + // basic field... + [['Basic static field: ', 'value']], + + { title: '$Toggle: ', + type: 'toggle', }, + { title: 'Direct toggle: ', + type: 'toggle', + values: ['a', 'b', 'c'], + list: false, }, + { title: '$List toggle: ', + type: 'toggle', + values: ['first', 'second', 'third', 'last'], }, + { title: '$Editable list toggle: ', + type: 'toggle', + values: ['sortable', 'renamable', 'removable', 'extendable'], + list_editable: true, }, + + '---', + + { title: 'Theme (config): ', + type: 'configToggle', + key: 'theme', + values_key: 'themes', + // optional... + live_update: true, + callback: function(cfg, value){ + this.toggleTheme(value) }, }, + { title: 'Theme (toggler): ', + type: 'toggler', + toggler: 'toggleTheme', + // optional... + live_update: true, }, + { title: 'Slideshow direction: ', + type: 'toggler', + toggler: 'toggleSlideshowDirection', }, + ], + callback || function(res, spec){ + console.log('EDITED:', res, spec) }) })], + exampleEmbededEditor: ['Test/Universal editor (embeded)...', + widgets.makeUIDialog(function(){ + var that = this + var spec + + return browse.makeLister(null, function(_, make){ + + that.makeEditor(make, + // NOTE: we need to maintain the data between updates... + spec = spec + || [ + { title: '$Toggle: ', + type: 'toggle', }, + { title: 'Direct toggle: ', + type: 'toggle', + values: ['a', 'b', 'c'], + list: false, }, + { title: '$List toggle: ', + type: 'toggle', + values: ['first', 'second', 'third', 'last'], }, + { title: '$Editable list toggle: ', + type: 'toggle', + values: ['sortable', 'renamable', 'removable', 'extendable'], + list_editable: true, }, + '---', + { title: 'Theme (toggler): ', + type: 'toggler', + toggler: 'toggleTheme', + // optional... + live_update: true, }, + // XXX BUG: toggler with two values does not seem to work... + { title: 'Slideshow direction: ', + type: 'toggler', + toggler: 'toggleSlideshowDirection', }, + ]) + + make.Separator() + + make('Done', {open: function(){ make.dialog.close() }}) + }, { cls: 'table-view' }) })], }) var ExampleUI = diff --git a/ui (gen4)/features/ui-slideshow.js b/ui (gen4)/features/ui-slideshow.js index 188241c4..51f52a10 100755 --- a/ui (gen4)/features/ui-slideshow.js +++ b/ui (gen4)/features/ui-slideshow.js @@ -139,7 +139,7 @@ var SlideshowActions = actions.Actions({ suspended_timer || this.suspendSlideshowTimer() // XXX might be a good idea to make this generic... - var _makeToggleHandler = function(toggler){ + var _makeToggleHandler = function(o, toggler){ return function(){ var txt = $(this).find('.text').first().text() that[toggler]() @@ -150,7 +150,7 @@ var SlideshowActions = actions.Actions({ } } - var o = browse.makeLister(null, function(path, make){ + return browse.makeLister(null, function(path, make){ make(['$Interval: ', function(){ return that.config['slideshow-interval'] }]) .on('open', function(){ @@ -158,17 +158,17 @@ var SlideshowActions = actions.Actions({ make(['$Direction: ', function(){ return that.config['slideshow-direction'] }]) - .on('open', _makeToggleHandler('toggleSlideshowDirection')) + .on('open', _makeToggleHandler(make.dialog, 'toggleSlideshowDirection')) make(['$Looping: ', function(){ return that.config['slideshow-looping'] }]) - .on('open', _makeToggleHandler('toggleSlideshowLooping')) + .on('open', _makeToggleHandler(make.dialog, 'toggleSlideshowLooping')) // Start/stop... make([function(){ return that.toggleSlideshow('?') == 'on' ? '$Stop' : '$Start' }]) .on('open', function(){ that.toggleSlideshow() - o.close() + make.dialog.close() }) }, { @@ -180,9 +180,65 @@ var SlideshowActions = actions.Actions({ suspended_timer || that.resetSlideshowTimer() }) - - return o })], + slideshowDialog2: ['Slideshow/Slideshow (new)...', + widgets.makeUIDialog(function(){ + var that = this + // suspend the timer if it's not suspended outside... + var suspended_timer = this.__slideshow_timer == 'suspended' + suspended_timer + || this.suspendSlideshowTimer() + var spec + + return browse.makeLister(null, + function(path, make){ + // fields... + that.makeEditor(make, + spec = spec + || [ + // XXX move this to the interval editor... + { title: '$Interval: ', + type: 'configToggle', + key: 'slideshow-interval', + values_key: 'slideshow-intervals', + /* XXX + list: function(cur, set){ + this.slideshowIntervalDialog() + .close(function(){ + // XXX this works only once per dialog instance... + set() }) }, }, + /*/ + values_key: 'slideshow-intervals', + list_editable: true, + list: { + length_limit: that.config['slideshow-interval-max-count'], + check: Date.str2ms, + unique: Date.str2ms, + normalize: function(e){ return e.trim() }, + sort: function(a, b){ + return Date.str2ms(a) - Date.str2ms(b) }, + sortable: false, }, }, + //*/ + { title: '$Direction: ', + type: 'toggler', + toggler: 'toggleSlideshowDirection', }, + { title: '$Looping: ', + type: 'toggler', + toggler: 'toggleSlideshowLooping', }, ]) + // Start/stop... + make([function(){ + return that.toggleSlideshow('?') == 'on' ? '$Stop' : '$Start' }], + { open: function(){ + that.toggleSlideshow() + make.dialog.close() } }) + },{ + path: that.toggleSlideshow('?') == 'on' ? 'Stop' : 'Start', + cls: 'table-view tail-action', + close: function(){ + // reset the timer if it was not suspended outside... + suspended_timer + || that.resetSlideshowTimer() }, + }) })], slideshowButtonAction: ['- Slideshow/', core.doc`Slideshow button action diff --git a/ui (gen4)/features/ui-widgets.js b/ui (gen4)/features/ui-widgets.js index 61d010e0..c62668f8 100755 --- a/ui (gen4)/features/ui-widgets.js +++ b/ui (gen4)/features/ui-widgets.js @@ -453,6 +453,11 @@ module.makeUIDialog = function(a, b){ return uiDialog(function(){ var args = [...arguments] + // we passed a make(..) function... + // XXX revise... + if(args[0] instanceof Function && args[0].constructor === browse.Make){ + return actions.ASIS(make.call(this, ...args)) } + // see if the first arg is a container spec... var container = !(args[0] instanceof Array) && this.isUIContainer(args[0]) ? args.shift() @@ -988,18 +993,8 @@ var EditorActions = actions.Actions({ // ... // } // - // XXX we need: - // - id - // - dialog ref (make.dialog) - // - actions ref (this) - // - make - // - options - // - initial value - // - history - // - callback - // XXX Q: when do we get the data??? field: function(actions, make, options){ - make([ + return make([ options.title, options.value instanceof Function ? options.value.call(actions) @@ -1011,8 +1006,7 @@ var EditorActions = actions.Actions({ // not have any effect on the value... // XXX revise... : options.value - ], options) - }, + ], options) }, // Editable field... // @@ -1046,12 +1040,14 @@ var EditorActions = actions.Actions({ // // XXX revise... // doNotAutoUpdateDialog: , // + // ... // } // + // + // NOTE: this extends .filed(..) toggle: function(actions, make, options){ - this.field(actions, make, + return this.field(actions, make, Object.assign( - // XXX not sure about this... options, { type: 'toggle', @@ -1067,6 +1063,12 @@ var EditorActions = actions.Actions({ var current = elem.text() var set = function(v){ + // get current value... + v = arguments.length > 0 ? + v + : options.value instanceof Function ? + options.value.call(actions) + : options.value // normalize... v = values.includes(v) ? v @@ -1142,29 +1144,51 @@ var EditorActions = actions.Actions({ this.value : this.value ? 'on' - : 'off' } }))) - }, + : 'off' } }))) }, // attribute value toggle... // // options format: // { + // // object on which the attribute manipulations are done... // obj: | , + // + // // attribute name/key... // key: , // - // values_key: [, ...], - // value_dict: { - // : , - // ... - // }, + // // attribute values source attribute/key... + // values_key: , // + // + // // attribute value translation dict/func... + // value_translate: + // + // | { + // : , + // ... + // }, + // + // + // // if true the update is made on value change... // live_update: , + // + // + // // callback if set, called after an update is made... // callback: , + // + // + // // if set this will not update the config... + // // + // // NOTE: callback(..) is still called so the user can take + // // care of updating manually... // read_only: , // // ... // } // + // + // NOTE: this extends .toggle(..) + // // XXX should we support dialog.close(..)'s reject mode here??? attrToggle: function(actions, make, options){ var update = function(){ @@ -1173,36 +1197,34 @@ var EditorActions = actions.Actions({ options.obj.call(actions) : options.obj '__value' in options - //&& (options.value = obj[options.key] = options.__value) && (obj[options.key] = options.__value) '__values' in options - //&& (options.values = obj[options.values_key] = options.__values) } && (obj[options.values_key] = options.__values) } options.callback && options.callback.call(actions, obj, options.__value, options.__values) } - make.dialog.close(function(){ - options.live_update - || update() }) + make.dialog + .close(function(){ + options.live_update + || update() }) - this.toggle(actions, make, + return this.toggle(actions, make, Object.assign( - // XXX not sure about this... options, { - // XXX PROBLEM: the value of this does not get - // propagated to the original options... //__value: null, value: function(value){ var obj = options.obj instanceof Function ? options.obj.call(actions) : options.obj - var d = options.value_dict + var d = options.value_translate // get... value = arguments.length > 0 ? value : '__value' in options ? options.__value + : d instanceof Function ? + d.call(actions, obj[options.key]) : d ? d[obj[options.key]] : obj[options.key] @@ -1213,6 +1235,7 @@ var EditorActions = actions.Actions({ && options.live_update && update() return value }, + //__values: null, values: function(value){ var obj = options.obj instanceof Function ? @@ -1227,6 +1250,50 @@ var EditorActions = actions.Actions({ options)) }, + // + // options format: + // { + // toggler: , + // + // ... + // } + // + toggler: function(actions, make, options){ + var update = function(){ + '__value' in options + && actions[options.toggler](options.__value) } + + make.dialog + .close(function(){ + options.live_update + || update() }) + + return this.toggle(actions, make, + Object.assign( + options, + { + //__value: null, + value: function(value){ + // get... + value = arguments.length > 0 ? + value + : '__value' in options ? + options.__value + : actions[options.toggler]('?') + // set... + arguments.length > 0 + && (options.__value = value) + // live... + options.live_update + && update() + return value }, + values: function(value){ + return actions[options.toggler]('??') }, + list_editable: false, + }, + options)) }, + + // Config editable value... // @@ -1236,15 +1303,14 @@ var EditorActions = actions.Actions({ // Config value toggle... // + // NOTE: this is the same as .attrToggle(..) but sets options.obj + // to actions.config... configToggle: function(actions, make, options){ - this.attrToggle(actions, make, + return this.attrToggle(actions, make, Object.assign( - // XXX not sure about this... options, - { - obj: function(){ - return actions.config } - }, + { obj: function(){ + return actions.config } }, options)) }, @@ -1306,8 +1372,9 @@ var EditorActions = actions.Actions({ makeUIDialog(function(spec, callback){ var that = this - var _make = function(make, spec){ + var _build = function(make, spec, cb){ var that = this + callback = cb var fields = this.__editor_fields__ || EditorActions.__editor_fields__ || {} @@ -1318,7 +1385,7 @@ var EditorActions = actions.Actions({ make(...field) // spec... : field instanceof Object ? - fields[field.type](that, make, field) + fields[field.type || 'field'](that, make, field) // other... : make(field) }) return make } @@ -1338,76 +1405,24 @@ var EditorActions = actions.Actions({ // but passing it here is cleaner than forcing // the user to get it via closure... spec) } - - return arguments[0] instanceof Function? + + return arguments[0] instanceof Function ? // inline... - _make.call(this, ...arguments) + _build.call(this, ...arguments) // dialog... : browse.makeLister(null, function(p, make){ - _make.call(that, make, spec) - }, { + _build.call(that, make, spec, callback) + }, { cls: 'table-view', - }) - // pass the results... - .close(function(){ - _callback - && _callback(spec) - // XXX fixing a double .close() bug... - _callback = null + close: function(){ + _callback + && _callback(spec) + // prevent calling the callback more than once... + // XXX fixing a double .close() bug... + _callback = null + }, }) })], - - - // XXX move this to examples.js - testEditor: ['Test/Universal $editor test...', - uiDialog(function(spec, callback){ - return this.makeEditor( - spec || [ - // basic field... - [['Basic static field: ', 'value']], - - { - type: 'toggle', - title: '$Toggle: ', - }, - - { - type: 'toggle', - title: 'Direct toggle: ', - values: ['a', 'b', 'c'], - list: false, - }, - - { - type: 'toggle', - title: '$List toggle: ', - values: ['first', 'second', 'third', 'last'], - }, - - { - type: 'toggle', - title: '$Editable list toggle: ', - values: ['sortable', 'renamable', 'removable', 'extendable'], - list_editable: true, - }, - - '---', - - { - type: 'configToggle', - title: 'Theme: ', - key: 'theme', - values_key: 'themes', - - // optional stuff... - live_update: true, - callback: function(cfg, value){ - this.toggleTheme(value) }, - }, - - ], - callback || function(res, spec){ - console.log('EDITED:', res, spec) }) })], }) var Editor = diff --git a/ui (gen4)/lib/widget/browse.js b/ui (gen4)/lib/widget/browse.js index 759a8011..d8f198a0 100755 --- a/ui (gen4)/lib/widget/browse.js +++ b/ui (gen4)/lib/widget/browse.js @@ -84,7 +84,9 @@ function makeSimpleAction(direction){ //--------------------------------------------------------------------- // NOTE: all item constructors/helpers abide by either the new-style // make protocol, i.e. make(content[, options]) or their own... -var Items = module.items = function(){} +var Items = +module.items = +module.Make = function(){} // Empty list place holder... // @@ -2790,6 +2792,11 @@ var BrowserPrototype = { } make.__proto__ = Items + Object.defineProperty(make, 'constructor', { + value: Items, + enumerable: false, + }) + // align the dialog... make.done = function(){ var s = l.find('.selected')