diff --git a/ui (gen4)/css/experimenting.css b/ui (gen4)/css/experimenting.css index f24d8533..21523acd 100755 --- a/ui (gen4)/css/experimenting.css +++ b/ui (gen4)/css/experimenting.css @@ -241,21 +241,6 @@ body { display: none; } -/* new item... */ -.browse-widget .list>.action { - margin-top: 0.2em; - border-top: solid 1px rgba(255,255,255, 0.2); -} -.browse-widget .list>.action .text { - font-style: italic; -} -/* do not show top border if after another action or separator... */ -.browse-widget .list>.action:first-child, -.browse-widget .list>.action+.action, -.browse-widget .list>.separator+.action { - border-top: none; -} - /* do not show top border if after another action or separator... */ .browse-widget .list>.warn { background-color: yellow !important; @@ -327,33 +312,6 @@ body { background-color: rgba(0, 0, 0, 0.1); } -.browse-widget.key-bindings .list>.mode { - color: white; - font-weight: bold; - background: rgba(0, 0, 0, 0.5); -} -.browse-widget.key-bindings .list>.mode span:first-child { - margin-left: -0.5em; -} -/* doc */ -.not-traversable.not-filtered-out.mode[doc]:after { - display: block; - content: attr(doc); - - whitespace: pre; - font-size: small; - font-style: italic; - - margin-top: 2em; - - opacity: 0.5; -} -.browse-widget.key-bindings .list>.mode.selected { - color: white; - font-weight: bold; - background: rgba(0, 0, 0, 0.7); -} - .browse-widget.key-bindings .list>.drop-list .text:first-child { font-weight: bold; font-style: italic; @@ -407,10 +365,8 @@ body { .browse-widget.key-bindings .list>.new.selected { } + /* dark theme... */ -.dark .browse-widget.key-bindings .list>.mode { - background: rgba(255, 255, 255, 0.1); -} .dark .browse-widget.key-bindings .list>div:not(.selected):not(.mode):nth-child(even) { background: rgba(255, 255, 255, 0.03); } diff --git a/ui (gen4)/css/widget/browse.css b/ui (gen4)/css/widget/browse.css index 09b5dfa7..ec460af1 100755 --- a/ui (gen4)/css/widget/browse.css +++ b/ui (gen4)/css/widget/browse.css @@ -354,6 +354,61 @@ display: none; } + +/* Action... */ +.browse-widget .list>.action { + margin-top: 0.2em; + border-top: solid 1px rgba(255,255,255, 0.2); +} +.browse-widget .list>.action .text { + font-style: italic; +} +/* do not show top border if after another action or separator... */ +.browse-widget .list>.action:first-child, +.browse-widget .list>.action+.action, +.browse-widget .list>.separator+.action { + border-top: none; +} + + +/* Heading... */ +.browse-widget .list>.heading { + color: white; + font-weight: bold; + background: rgba(0, 0, 0, 0.5); +} +.browse-widget .list>.heading:not(:first-child) { + margin-top: 0.5em; +} +.browse-widget .list>.heading span:first-child { + margin-left: -0.5em; +} +/* doc */ +.browse-widget .list>.heading[doc]:after { + display: block; + content: attr(doc); + + white-space: pre; + font-size: small; + font-style: italic; + + margin-top: 2em; + + opacity: 0.5; +} +.browse-widget .list>div.heading:hover { + background: rgba(0, 0, 0, 0.6); +} +.browse-widget .list>div.heading.selected { + background: rgba(0, 0, 0, 0.7); +} + +/* dark theme... */ +.dark .browse-widget .list>.heading { + background: rgba(255, 255, 255, 0.1); +} + + /* Show item part on hover... */ .browse-widget .list>div .show-on-hover { opacity: 0; diff --git a/ui (gen4)/features/keyboard.js b/ui (gen4)/features/keyboard.js index 55ee13d2..c55ac650 100755 --- a/ui (gen4)/features/keyboard.js +++ b/ui (gen4)/features/keyboard.js @@ -926,18 +926,16 @@ var KeyboardUIActions = actions.Actions({ var dropped = keybindings[mode].drop || [] var bound_ignored = [] - var attrs = {mode: mode} - keybindings[mode].doc - && (attrs['doc'] = keybindings[mode].doc) // section heading (mode)... - make(mode, { + make.Heading(mode, { + doc: keybindings[mode].doc, not_filtered_out: true, // XXX should sections be searchable??? //not_searchable: true, buttons: options.mode_buttons, }) - .attr(attrs) + .attr({ mode: mode }) .addClass('mode') // bindings... diff --git a/ui (gen4)/features/ui-widgets.js b/ui (gen4)/features/ui-widgets.js index 052ae1dd..96972d74 100755 --- a/ui (gen4)/features/ui-widgets.js +++ b/ui (gen4)/features/ui-widgets.js @@ -1419,6 +1419,7 @@ var WidgetTestActions = actions.Actions({ background: 'white', focusable: true, })], + // XXX show new features... testBrowse: ['Test/-99: Demo new style dialog...', makeUIDialog(function(){ var actions = this @@ -1509,7 +1510,48 @@ var WidgetTestActions = actions.Actions({ console.log('Dialog closing...') }) })], + testList: ['Test/-99: Demo new style dialog...', + makeUIDialog(function(){ + var actions = this + // NOTE: passing things other than strings into a list editor + // is not supported... + var numbers = ['1', '2', '3', '4'] + var letters = ['a', 'b', 'c', 'd'] + + return browse.makeLister(null, function(path, make){ + var that = this + + make.Heading('Letters:', { + doc: 'List editor with all the buttons enabled...', + }) + make.EditableList(numbers, { + list_id: 'numbers', + item_order_buttons: true, + to_top_button: true, + to_bottom_button: true, + }) + + make.Heading('Numbers:') + make.EditableList(letters, { list_id: 'letters' }) + + // NOTE: the dialog's .parent is not yet set at this point... + + // This will finalize the dialog... + // + // NOTE: this is not needed here as the dialog is drawn + // on sync, but for async dialogs this will align + // the selected field correctly. + make.done() + }) + // NOTE: this is not a dialog event, it is defined by the + // container to notify us that we are closing... + .on('close', function(){ + console.log(core.doc`Lists: + - Numbers: ${numbers.join(', ')} + - Letters: ${letters.join(', ')}`) + }) + })], testProgress: ['Test/Demo progress bar...', function(text){ diff --git a/ui (gen4)/lib/widget/browse.js b/ui (gen4)/lib/widget/browse.js index d3843a37..031ff5d7 100755 --- a/ui (gen4)/lib/widget/browse.js +++ b/ui (gen4)/lib/widget/browse.js @@ -97,11 +97,59 @@ Items.Separator = function(options){ return this('---', options) } +// NOTE: this is the same as make('...'[, options]) +Items.Sepinner = +function(options){ + return this('...', options) } + +// Heading... +// +// options format: +// { +// doc: , +// +// ... +// } +// +Items.Heading = +function(text, options){ + var attrs = (options && options.doc) ? {doc: options.doc} : {} + return this(text, options) + .attr(attrs) + .addClass('heading') } + +// Action... +// +// XXX should this have a callback??? Items.Action = function(text, options){ return this(text, options) .addClass('action') } +// Action requiring confirmation... +// +// options format: +// { +// // A callback to be called when action is confirmed... +// callback: , +// +// // Time (ms) to wait for confirm before resetting... +// timeout: '2000ms', +// +// // Text to use as confirm message... +// // +// // Supported placeholders: +// // ${text} - item text +// // ${text:l} - item text in lowercase +// // ${text:u} - item text in uppercase +// // ${text:c} - item text capitalized +// // +// confirm_text: 'Confirm ${text}?', +// +// ... +// } +// +// XXX doc... Items.ConfirmAction = function(text, options){ options = options || {} @@ -110,10 +158,11 @@ function(text, options){ var callback = options.callback var timeout = options.timeout || 2000 - var confirm_text = options.confirm_text ? - options.confirm_text - : 'Confirm '+ elem.find('.text').text().toLowerCase() +'?' - var text + var confirm_text = (options.confirm_text || 'Confirm ${text:l}?') + .replace(/\$\{text\}/, text) + .replace(/\$\{text:l\}/, text.toLowerCase()) + .replace(/\$\{text:u\}/, text.toUpperCase()) + .replace(/\$\{text:c\}/, text.capitalize()) return elem .on('open', function(){ @@ -142,10 +191,13 @@ function(text, options){ }) } -// make items with auto selected text on select... +// Item with auto selected text on select... // // options format: // { +// // XXX make this generic, something like cls: ... +// action: false, +// // select_text: | 'first' | 'last' | , // // ... @@ -177,7 +229,7 @@ function(text, options){ return elem } -// make Editable on select element... +// Editable item or it's part... // // options format: // { @@ -263,12 +315,13 @@ function(text, options){ reset_on_commit: options.reset_on_commit, reset_on_abort: options.reset_on_abort, }) + // XXX not sure about this... + .on('blur', function(){ dialog.select(null) }) // deselect on abort -- if we started with a select... - start_on == 'select' && editable - .on('edit-abort', function(){ - dialog.select(null) - }) + start_on == 'select' + && editable + .on('edit-abort', function(){ dialog.select(null) }) // edit event handlers... options.editaborted @@ -291,7 +344,7 @@ function(text, options){ } -// Make list of elements... +// List of elements... // // // data format: @@ -373,7 +426,7 @@ function(data, options){ } -// Make editable list of elements... +// Editable list of elements... // // This is like .List(..) but adds functionality to add, remove and // manually sort list items. @@ -401,7 +454,8 @@ function(data, options){ // { // // List identifier, used when multiple lists are drawn in one // // dialog... -// // XXX not used yet... +// // +// // NOTE: if multiple editable lists are drawn this is required. // list_id: , // // // If true (default), display the "new..." item, if string set @@ -499,18 +553,8 @@ function(data, options){ // // NOTE: this uses .List(..) internally, see it's doc for additional // info. -// NOTE: this is not designed to be used multiple times in one dialog, -// if multiple lists need to be edited use multiple (nested) -// dialogs (one per list)... +// NOTE: the list must contain strings. // -// XXX should this be usable more than once per dialog??? -// ...would need to: -// - identify and route actions to correct list -// - optionally route actions to list combinations -// - identify lists (item attr -> list index) -// - store list data by list identifier... -// - take care of cases where lists are re-ordered or not -// drawn in some cases -- can't simply use index as id... Items.EditableList = function(list, options){ var make = this @@ -531,6 +575,7 @@ function(list, options){ dialog.__list = dialog.__list || {} dialog.__to_remove = dialog.__to_remove || {} + dialog.__editable_list_handlers = dialog.__editable_list_handlers || {} var id = options.list_id || 'default' @@ -643,6 +688,7 @@ function(list, options){ // make the list... var res = make.List(lst, options) + .attr('list-id', id) // mark items for removal -- if a list is given by user... to_remove.forEach(function(e){ @@ -728,8 +774,8 @@ function(list, options){ // dialog handlers... // NOTE: we bind these only once per dialog... - if(dialog.__editable_list_handlers == null){ - dialog.__editable_list_handlers = true + if(dialog.__editable_list_handlers[id] == null){ + dialog.__editable_list_handlers[id] = true dialog // update the striked-out items (to_remove)... .on('update', function(){ @@ -1837,11 +1883,8 @@ var BrowserPrototype = { var res = $('
') // handle clicks ONLY when not disabled... .click(function(){ - if(!$(this).hasClass('disabled')){ - //that.push(quoteWS($(this).find('.text').text())) - that.push('"'+ $(this).find('.text').text() +'"') - } - }) + !$(this).hasClass('disabled') + && that.push($(this)) }) // append text elements... .append(p)