diff --git a/ui (gen4)/features/filesystem.js b/ui (gen4)/features/filesystem.js index c9994fe1..59aadcc3 100755 --- a/ui (gen4)/features/filesystem.js +++ b/ui (gen4)/features/filesystem.js @@ -1168,6 +1168,31 @@ var FileSystemWriterUIActions = actions.Actions({ // Export dialog... // + // Export is set by: + // .config['export-mode'] + // + // The fields used and their order is determined by: + // .config['export-modes'][].data (list) + // + // The action used to export is determined by: + // .config['export-modes'][].action + // + // + // Dialog fields... + // + // Format: + // { + // // Arguments: + // // actions - the actions object + // // make - browse item constructor + // // (see: browse.Browser.update(..) for more info) + // // overlay - the containing overlay object + // : function(actions, make, overlay){ ... }, + // ... + // } + // + // NOTE: .__export_dialog_fields__ can be defined both in the feature + // as well as in the instance. __export_dialog_fields__: { 'pattern': function(actions, make, overlay){ return make(['Filename pattern: ', @@ -1201,7 +1226,7 @@ var FileSystemWriterUIActions = actions.Actions({ // XXX make this editable on open and remove "new" from history... // XXX add "history" button... 'target_dir': function(actions, make, overlay){ - return make(['To: ', + var elem = make(['To: ', function(){ return actions.config['export-path'] || './' }], { buttons: [ ['browse', function(p){ @@ -1232,14 +1257,28 @@ var FileSystemWriterUIActions = actions.Actions({ })], ]}) // XXX make this editable??? - .on('open', - widgets.makeNestedConfigListEditor(actions, overlay, - 'export-paths', - 'export-path', - { - // XXX add 'edit' button... - //itemButtons: [] - })) + .on('open', function(){ + event.preventDefault() + + var path = elem.find('.text').last() + .makeEditable({ + clear_on_edit: false, + abort_keys: [ + 'Esc', + ], + }) + .on('edit-done', function(_, path){ + actions.config['export-path'] = path + actions.config['export-paths'].splice(0, 0, path) + + }) + .on('edit-aborted edit-done', function(evt, path){ + overlay.client.update() + .then(function(){ + overlay.client.select(path) + }) + }) + }) } }, // XXX indicate export state: index, crop, image... @@ -1280,9 +1319,10 @@ var FileSystemWriterUIActions = actions.Actions({ // XXX indicate export state: index, crop, image... return 'Export'}]) .on('open', function(){ + var mode = that.config['export-dialog-modes'][that.config['export-dialog-mode']] // XXX is this correct??? // XXX handle relative paths!!! - that[that.config['export-mode'].action]( + that[mode.action]( that.config['export-path'] || that.location.path) o.close() }) diff --git a/ui (gen4)/features/ui-widgets.js b/ui (gen4)/features/ui-widgets.js index 83b6ad1c..caa55697 100755 --- a/ui (gen4)/features/ui-widgets.js +++ b/ui (gen4)/features/ui-widgets.js @@ -69,79 +69,67 @@ function(actions, list_key, options){ new_button = new_button === true ? 'New...' : new_button var _makeEditable = function(elem){ - $(elem).find('.text') - .prop('contenteditable', true) - .text('') - .selectText() - .keydown(function(){ - event.stopPropagation() - - var n = keyboard.toKeyName(event.keyCode) - - // reset to original value... - if(n == 'Esc'){ - list.update() - - // save value... - } else if(n == 'Enter'){ - event.preventDefault() - var txt = $(this).text() - - // invalid format... - if(options.check && !options.check(txt)){ - list.update() - return - } - - // list length limit - if(options.length_limit - && (lst.length >= options.length_limit)){ - - options.callback && options.callback.call(list, txt) - - return - } - - // prevent editing non-arrays... - if(!(actions.config[list_key] instanceof Array)){ - return - } - - // save the new version... - actions.config[list_key] = actions.config[list_key].slice() - // add new value and sort list... - actions.config[list_key] - .push(txt) - - // unique... - if(options.unique == null || options.unique){ - actions.config[list_key] = actions.config[list_key] - .unique(typeof(options.unique) == typeof(function(){}) ? - options.unique - : undefined) - } - - // sort... - if(options.sort){ - actions.config[list_key] = actions.config[list_key] - .sort(typeof(options.sort) == typeof(function(){}) ? - options.sort - : undefined) - } - - // update the list data... - list.options.data - = actions.config[list_key] - .concat(new_button ? [ new_button ] : []) - - // update list and select new value... - list.update() - .done(function(){ - list.select('"'+txt+'"') - }) - } + return $(elem).find('.text') + .makeEditable() + .on('edit-aborted', function(){ + list.update() + }) + .on('edit-done', function(evt, text){ + var txt = $(this).text() + + // invalid format... + if(options.check && !options.check(txt)){ + list.update() + return + } + + // list length limit + if(options.length_limit + && (lst.length >= options.length_limit)){ + + options.callback && options.callback.call(list, txt) + + return + } + + // prevent editing non-arrays... + if(!(actions.config[list_key] instanceof Array)){ + return + } + + // save the new version... + actions.config[list_key] = actions.config[list_key].slice() + // add new value and sort list... + actions.config[list_key] + .push(txt) + + // unique... + if(options.unique == null || options.unique){ + actions.config[list_key] = actions.config[list_key] + .unique(typeof(options.unique) == typeof(function(){}) ? + options.unique + : undefined) + } + + // sort... + if(options.sort){ + actions.config[list_key] = actions.config[list_key] + .sort(typeof(options.sort) == typeof(function(){}) ? + options.sort + : undefined) + } + + // update the list data... + list.options.data + = actions.config[list_key] + .concat(new_button ? [ new_button ] : []) + + // update list and select new value... + list.update() + .done(function(){ + list.select('"'+txt+'"') + }) }) - return $(elem) } var to_remove = [] @@ -177,6 +165,13 @@ function(actions, list_key, options){ _makeEditable(elem) } }) + // restore striked-out items... + .on('update', function(){ + to_remove.forEach(function(e){ + list.filter('"'+ e +'"') + .toggleClass('strike-out') + }) + }) .open(function(evt, path){ // we clicked the 'New' button -- select it... if(new_button && (path == new_button || path == '')){ diff --git a/ui (gen4)/lib/util.js b/ui (gen4)/lib/util.js index 80138de6..c5ee6db2 100755 --- a/ui (gen4)/lib/util.js +++ b/ui (gen4)/lib/util.js @@ -9,6 +9,7 @@ define(function(require){ var module = {} //var DEBUG = DEBUG != null ? DEBUG : true + /*********************************************************************/ String.prototype.capitalize = function(){ @@ -220,6 +221,7 @@ if(typeof(jQuery) != typeof(undefined)){ }) } + jQuery.fn.selectText = function(){ var range = document.createRange() @@ -235,6 +237,84 @@ if(typeof(jQuery) != typeof(undefined)){ } + var keyboard = require('lib/keyboard') + + // Make element editable... + // + // Options format: + // { + // multiline: false, + // + // reset_on_abort: true, + // clear_on_edit: true, + // + // abort_keys: [ + // 'Esc', + // ... + // ], + // } + // + // XXX should we just use form elements??? + // ...it's a trade-off, here we add editing functionality and fight + // a bit the original function, in an input we'll need to fight part + // of the editing functionality and add our own navigation... + // XXX move this to a more generic spot... + jQuery.fn.makeEditable = function(options){ + options = options || {} + var that = this + + var original = this.text() + + if(options.clear_on_edit == null || options.clear_on_edit){ + this.text('') + } + + this + .prop('contenteditable', true) + // make the element focusable and selectable... + .attr('tabindex', '0') + // NOTE: this will also focus the element... + .selectText() + .keydown(function(){ + if(!that.prop('contenteditable')){ + return + } + + event.stopPropagation() + + var n = keyboard.toKeyName(event.keyCode) + + // abort... + if((options.abort_keys || ['Esc']).indexOf(n) >= 0){ + // reset original value... + (options.reset_on_abort == null || options.reset_on_abort) + && that.text(original) + + that + .trigger('edit-aborted', original) + + // done -- single line... + } else if(n == 'Enter' + && !options.multiline){ + event.preventDefault() + + that.trigger('edit-done', that.text()) + + // done -- multiline... + } else if(n == 'Enter' + && (event.ctrlKey || event.metaKey) + && options.multiline){ + event.preventDefault() + + that.trigger('edit-done', that.text()) + } + }) + + return this + } + + + }