diff --git a/Viewer/features/filesystem.js b/Viewer/features/filesystem.js index 479f88fd..ba0bb811 100755 --- a/Viewer/features/filesystem.js +++ b/Viewer/features/filesystem.js @@ -3095,15 +3095,28 @@ var FileSystemWriterUIActions = actions.Actions({ 'exportDialog: "images"'], - // XXX export using a preset... // XXX TODO: // - format the element into: title (optional) + info + // XXX add a 'name' field to the exportDialog(..)??? + // XXX button icons... + // XXX button shortcuts... exportPresets: ['- File/Export history...', widgets.makeUIDialog(function(mode){ var that = this + var logger = this.logger && this.logger.push('exportPresets') + + // XXX these should be type-specific... + var getName = function(preset){ + return preset.name + || `${ preset.mode }: "${ preset.path }"` } // presets... var presets = that.config['export-presets'] || [] + var index = presets + .reduce(function(res, e, i){ + res[getName(e)] = i + return res }, {}) + var keys = Object.keys(index) // history... // XXX @@ -3111,56 +3124,73 @@ var FileSystemWriterUIActions = actions.Actions({ var history_index = {} var history_keys = Object.keys(history_index) - // XXX var getPreset = function(title, presets, index){ return presets[index[title]] } return browse.makeLister(null, function(path, make){ - - var index = presets - .reduce(function(res, e, i){ - name = e.name - // XXX these should be type-specific... - || `${ e.mode }: "${ e.path }"` - res[name] = i - return res }, {}) - var keys = Object.keys(index) - - // presets... - //make.Separator() + // preset list... keys.length == 0 ? make.Empty('No presets...') : make.EditableList(keys, { list_id: 'presets', sortable: true, + update_merge: 'live', new_item: false, + // NOTE: we use empty to restore the automatic value... + allow_empty: true, + itemedit: function(evt, from, to){ + var preset = getPreset(from, presets, index) + // clear... + if(to.trim() == ''){ + delete preset.name + to = keys[keys.indexOf(from)] = getName(preset) + // set... + } else { + to = preset.name = to.trim() } + // update index... + index[to] = index[from] + delete index[from] + // select item... + // NOTE: this is not done automatically because + // we are changing the title .EditableList(..) + // is expecting... + make.dialog.one('update', + function(){ + make.dialog.select(to) }) }, buttons: [ - // XXX new export or should this be edit??? - ['E', function(title){ - that.exportDialog(getPreset(title, presets, index)) + ['edit', function(title){ + var preset = getPreset(title, presets, index) + that.exportDialog(preset) .close(function(){ - // XXX for some reason on update when - // name affected the item does not - // get updated... - make.dialog.update() })}], - // XXX not sure about the default icon... - ['T', 'TO_TOP'], - 'REMOVE', - ], - // XXX export... + var n = getName(preset) + // update the list if name is affected... + if(n != title){ + keys[keys.indexOf(title)] = n + index[n] = index[title] + delete index[title] + make.dialog.select(n) + make.dialog.update() } })}], + ['♦', 'TO_TOP'], + 'REMOVE'], + // export... open: function(evt, title){ - that.exportAs(getPreset(title, presets, index)) - make.dialog.close() }, - // XXX handle rename -> update index... - // XXX - }) + var preset = getPreset(title, presets, index) + // export only if we get a good preset... + if(preset && getName(preset) == title){ + that.exportAs(preset) + return make.dialog.close() } + // error... + logger + && logger.emit('error', 'preset not found.') }, }) // export dialog... make.Separator({ style: { opacity: '0.1' } }) make('E$xport...', { open: function(){ - that.exportDialog() - make.dialog.close() }, }) + that.exportDialog() + .close(function(evt, reason){ + reason != 'reject' + && make.dialog.close() }) }, }) // history... make.Separator() @@ -3186,30 +3216,49 @@ var FileSystemWriterUIActions = actions.Actions({ }) .run(function(){ var that = this - // XXX + // XXX this does not work yet... this.keyboard.on('E', function(){ console.log('!!!!!!!!!!!!!', that.selected) }) - }) - .close(function(){ - - // XXX need to merge history/presets back when dialog closes... - // XXX - }) })], // XXX these do note need the ui -- move to a separate feature... // XXX these are essentially the same as the history API, make a // generic list manager??? + // XXX need to check preset uniqueness... exportPresetSave: ['- File/', - function(){}], + function(settings){ + settings = settings + || this.config['export-settings'] + // XXX need to check preset uniqueness... + settings + && (this.config['export-presets'] = + this.config['export-presets'] + || []) + .push(settings) }], + + // XXX need a way to reference a preset... exportPresetDelete: ['- File/', function(){}], exportPresetRun: ['- File/', function(){}], + // XXX need to check item uniqueness... exportHistoryPush: ['- File/', - function(){}], + function(settings){ + settings = settings + || this.config['export-settings'] + var l = this.config['export-history-length'] || 50 + var history = + this.config['export-history'] = + this.config['export-history'] || [] + // add... + // XXX need to check item uniqueness... + settings + && history.push(settings) + // trim the history... + history.length > l + && history.splice(0, history.length - l) }], }) @@ -3226,6 +3275,13 @@ module.FileSystemWriterUI = core.ImageGridFeatures.Feature({ ], actions: FileSystemWriterUIActions, + + handlers: [ + [[ + 'exportIndex', + 'exportDirs', + ], function(_, settings){}] + ], }) diff --git a/Viewer/features/ui-widgets.js b/Viewer/features/ui-widgets.js index 5bcad2d6..9ff4d38b 100755 --- a/Viewer/features/ui-widgets.js +++ b/Viewer/features/ui-widgets.js @@ -842,8 +842,7 @@ var DialogsActions = actions.Actions({ : options.sortable return browse.makeLister(null, function(path, make){ - make.EditableList(list, options) - }, + make.EditableList(list, options) }, options) })], showActionList: ['- Interface/', core.doc`Show list of actions dialog... diff --git a/Viewer/lib/widget/browse.js b/Viewer/lib/widget/browse.js index ea667ec3..d964b277 100755 --- a/Viewer/lib/widget/browse.js +++ b/Viewer/lib/widget/browse.js @@ -600,7 +600,14 @@ function(data, options){ // // // Item edit event handler... // // -// itemedit: function(from, to){ ... }, +// itemedit: function(evt, from, to){ ... }, +// +// // If true allow saving and triggering options.itemedit(..) on an +// // empty value after editing the item... (default: null) +// // +// // NOTE: this will not save the empty value (see .Editable(..)) +// // this will only trigger the handler on an empty value... +// allow_empty: null | , // // // Item open event handler... // // @@ -659,10 +666,11 @@ function(data, options){ // // Merge list state and external list mode on update... // // // // This can be: -// // null - keep dialog state, ignore external state (default) +// // 'keep_changes' - keep dialog state, ignore external state (default) +// // null - same as 'keep_changes' // // 'drop_changes' - replace dialog state with input state -// // 'keep_changes' - keep dialog state (ignoring input) // // 'merge' - merge dialog state and input state +// // 'live' - live edit // // - merge the changes // // // update_merge: null | 'drop_changes' | 'keep_changes' | 'merge' | , @@ -861,19 +869,15 @@ function(list, options){ ], }) .on('edit-commit', function(evt, to){ - if(to.trim() != ''){ + if(options.allow_empty || to.trim() != ''){ to = saveItem(to, from) - options.itemedit - && options.itemedit.call(elem, evt, from, to) - } - }) + && options.itemedit.call(elem, evt, from, to) } }) .on('edit-abort edit-commit', function(_, title){ title = title.trim() == '' ? from : title title = title.replace(/\$/g, '') dialog.update() - .then(function(){ dialog.select(`"${title}"`) }) - }) } + .then(function(){ dialog.select(`"${title}"`) }) }) } dialog.__list = dialog.__list || {} dialog.__editable = dialog.__editable || {} @@ -893,8 +897,7 @@ function(list, options){ options = options || {} var opts = {} for(var k in options){ - opts[k] = options[k] - } + opts[k] = options[k] } options = opts var lst = @@ -903,7 +906,9 @@ function(list, options){ (list instanceof Function ? list() : list) // load dialog state (ignore input)... - : (options.update_merge == null || options.update_merge == 'keep_changes') ? + : (options.update_merge == null + || options.update_merge == 'keep_changes' + || options.update_merge == 'live') ? dialog.__list[id] // load input/external state (ignore dialog state)... @@ -922,8 +927,7 @@ function(list, options){ // via their position in local... i = i == -1 ? input.indexOf(a) : i j = j == -1 ? input.indexOf(b) : j - return i - j - }) + return i - j }) })(dialog.__list[id] || [], list instanceof Function ? list() : list) // user merge... @@ -940,7 +944,11 @@ function(list, options){ var editable = dialog.__editable[id] = lst instanceof Array // NOTE: we .slice() here to make the changes a bit better packaged // or discrete and not done as they come in... - lst = lst instanceof Array ? lst.slice() : Object.keys(lst) + lst = lst instanceof Array ? + (options.update_merge == 'live' ? + lst + : lst.slice()) + : Object.keys(lst) dialog.__list[id] = lst @@ -959,8 +967,7 @@ function(list, options){ options.to_top_button && buttons.push('TO_TOP') options.to_bottom_button - && buttons.push('TO_BOTTOM') - } + && buttons.push('TO_BOTTOM') } // remove... editable && options.delete_button !== false @@ -1055,8 +1062,7 @@ function(list, options){ var key = button instanceof Array ? button[1] : button // skip seen buttons... if(seen.indexOf(key) >= 0){ - return key - } + return key } var res = button in __buttons ? __buttons[button] : button[1] in __buttons ? @@ -1065,12 +1071,9 @@ function(list, options){ // group if at least one sort button is present... if(res !== button){ options.groupList = true - // avoid duplicates... - seen.push(key) - } - return res.slice() - }) + seen.push(key) } + return res.slice() }) // clear out the unused button placeholders... .filter(function(b){ return ['UP', 'DOWN', 'TO_TOP', 'TO_BOTTOM', 'REMOVE'].indexOf(b) < 0 }) @@ -1260,8 +1263,8 @@ function(list, pins, options){ // link the to_remove lists of pins and the main list... dialog.__to_remove = dialog.__to_remove || {} if(dialog.__to_remove[id] == null){ - dialog.__to_remove[id] = dialog.__to_remove[pins_id] = [] - } + dialog.__to_remove[id] = + dialog.__to_remove[pins_id] = [] } // XXX redraw.... // - sort - within one list this is trivial (history.js) @@ -2027,8 +2030,7 @@ var BrowserPrototype = { if(e.length <= 0){ return null } - return e.find('.text').text() - }, + return e.find('.text').text() }, set selected(value){ return this.select(value) },