started making editor components modular and generic...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2016-04-17 00:58:21 +03:00
parent 261a8690f4
commit b5011ffaa5
3 changed files with 197 additions and 82 deletions

View File

@ -1168,6 +1168,31 @@ var FileSystemWriterUIActions = actions.Actions({
// Export dialog... // Export dialog...
// //
// Export <mode> is set by:
// .config['export-mode']
//
// The fields used and their order is determined by:
// .config['export-modes'][<mode>].data (list)
//
// The action used to export is determined by:
// .config['export-modes'][<mode>].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
// <key>: function(actions, make, overlay){ ... },
// ...
// }
//
// NOTE: .__export_dialog_fields__ can be defined both in the feature
// as well as in the instance.
__export_dialog_fields__: { __export_dialog_fields__: {
'pattern': function(actions, make, overlay){ 'pattern': function(actions, make, overlay){
return make(['Filename pattern: ', return make(['Filename pattern: ',
@ -1201,7 +1226,7 @@ var FileSystemWriterUIActions = actions.Actions({
// XXX make this editable on open and remove "new" from history... // XXX make this editable on open and remove "new" from history...
// XXX add "history" button... // XXX add "history" button...
'target_dir': function(actions, make, overlay){ 'target_dir': function(actions, make, overlay){
return make(['To: ', var elem = make(['To: ',
function(){ return actions.config['export-path'] || './' }], function(){ return actions.config['export-path'] || './' }],
{ buttons: [ { buttons: [
['browse', function(p){ ['browse', function(p){
@ -1232,14 +1257,28 @@ var FileSystemWriterUIActions = actions.Actions({
})], })],
]}) ]})
// XXX make this editable??? // XXX make this editable???
.on('open', .on('open', function(){
widgets.makeNestedConfigListEditor(actions, overlay, event.preventDefault()
'export-paths',
'export-path', var path = elem.find('.text').last()
{ .makeEditable({
// XXX add 'edit' button... clear_on_edit: false,
//itemButtons: [] 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... // XXX indicate export state: index, crop, image...
@ -1280,9 +1319,10 @@ var FileSystemWriterUIActions = actions.Actions({
// XXX indicate export state: index, crop, image... // XXX indicate export state: index, crop, image...
return 'Export'}]) return 'Export'}])
.on('open', function(){ .on('open', function(){
var mode = that.config['export-dialog-modes'][that.config['export-dialog-mode']]
// XXX is this correct??? // XXX is this correct???
// XXX handle relative paths!!! // XXX handle relative paths!!!
that[that.config['export-mode'].action]( that[mode.action](
that.config['export-path'] || that.location.path) that.config['export-path'] || that.location.path)
o.close() o.close()
}) })

View File

@ -69,79 +69,67 @@ function(actions, list_key, options){
new_button = new_button === true ? 'New...' : new_button new_button = new_button === true ? 'New...' : new_button
var _makeEditable = function(elem){ var _makeEditable = function(elem){
$(elem).find('.text') return $(elem).find('.text')
.prop('contenteditable', true) .makeEditable()
.text('') .on('edit-aborted', function(){
.selectText() list.update()
.keydown(function(){ })
event.stopPropagation() .on('edit-done', function(evt, text){
var txt = $(this).text()
var n = keyboard.toKeyName(event.keyCode)
// invalid format...
// reset to original value... if(options.check && !options.check(txt)){
if(n == 'Esc'){ list.update()
list.update() return
}
// save value...
} else if(n == 'Enter'){ // list length limit
event.preventDefault() if(options.length_limit
var txt = $(this).text() && (lst.length >= options.length_limit)){
// invalid format... options.callback && options.callback.call(list, txt)
if(options.check && !options.check(txt)){
list.update() return
return }
}
// prevent editing non-arrays...
// list length limit if(!(actions.config[list_key] instanceof Array)){
if(options.length_limit return
&& (lst.length >= options.length_limit)){ }
options.callback && options.callback.call(list, txt) // save the new version...
actions.config[list_key] = actions.config[list_key].slice()
return // add new value and sort list...
} actions.config[list_key]
.push(txt)
// prevent editing non-arrays...
if(!(actions.config[list_key] instanceof Array)){ // unique...
return if(options.unique == null || options.unique){
} actions.config[list_key] = actions.config[list_key]
.unique(typeof(options.unique) == typeof(function(){}) ?
// save the new version... options.unique
actions.config[list_key] = actions.config[list_key].slice() : undefined)
// add new value and sort list... }
actions.config[list_key]
.push(txt) // sort...
if(options.sort){
// unique... actions.config[list_key] = actions.config[list_key]
if(options.unique == null || options.unique){ .sort(typeof(options.sort) == typeof(function(){}) ?
actions.config[list_key] = actions.config[list_key] options.sort
.unique(typeof(options.unique) == typeof(function(){}) ? : undefined)
options.unique }
: undefined)
} // update the list data...
list.options.data
// sort... = actions.config[list_key]
if(options.sort){ .concat(new_button ? [ new_button ] : [])
actions.config[list_key] = actions.config[list_key]
.sort(typeof(options.sort) == typeof(function(){}) ? // update list and select new value...
options.sort list.update()
: undefined) .done(function(){
} list.select('"'+txt+'"')
})
// 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 = [] var to_remove = []
@ -177,6 +165,13 @@ function(actions, list_key, options){
_makeEditable(elem) _makeEditable(elem)
} }
}) })
// restore striked-out items...
.on('update', function(){
to_remove.forEach(function(e){
list.filter('"'+ e +'"')
.toggleClass('strike-out')
})
})
.open(function(evt, path){ .open(function(evt, path){
// we clicked the 'New' button -- select it... // we clicked the 'New' button -- select it...
if(new_button && (path == new_button || path == '')){ if(new_button && (path == new_button || path == '')){

View File

@ -9,6 +9,7 @@ define(function(require){ var module = {}
//var DEBUG = DEBUG != null ? DEBUG : true //var DEBUG = DEBUG != null ? DEBUG : true
/*********************************************************************/ /*********************************************************************/
String.prototype.capitalize = function(){ String.prototype.capitalize = function(){
@ -220,6 +221,7 @@ if(typeof(jQuery) != typeof(undefined)){
}) })
} }
jQuery.fn.selectText = function(){ jQuery.fn.selectText = function(){
var range = document.createRange() 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
}
} }