refactored filtering into a toggler + fixed a focus bug in filtering and found a new focus related bug with IE...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2015-07-11 19:42:13 +03:00
parent 514a14046b
commit 889e15bbf5
2 changed files with 73 additions and 50 deletions

View File

@ -108,7 +108,7 @@ var BrowserPrototype = {
//show_path: true, //show_path: true,
// Enable/disable user selection filtering... // Enable/disable user selection filtering...
// NOTE: this only affects .startFilter(..) // NOTE: this only affects starting the filter...
filter: true, filter: true,
// Enable/disable full path editing... // Enable/disable full path editing...
@ -187,7 +187,9 @@ var BrowserPrototype = {
'#1', '#2', '#3', '#4', '#5', '#6', '#7', '#8', '#9', '#1', '#2', '#3', '#4', '#5', '#6', '#7', '#8', '#9',
], ],
Enter: 'action!', // XXX should this be an action or a push????
//Enter: 'action!',
Enter: 'push!',
Esc: 'stopFilter!', Esc: 'stopFilter!',
}, },
@ -341,12 +343,6 @@ var BrowserPrototype = {
this.options.traversable = value this.options.traversable = value
}, },
// Indicate if UI in list filtering mode...
get filtering(){
return this.dom.hasClass('filtering')
//return this.dom.find('.path .dir.cur[contenteditable]').length > 0
},
// Get/set the path... // Get/set the path...
// //
// On more info on setting the path see .update(..) // On more info on setting the path see .update(..)
@ -436,6 +432,8 @@ var BrowserPrototype = {
// path due to an error, we need to be able to render the new // path due to an error, we need to be able to render the new
// path both in the path and list sections... // path both in the path and list sections...
// NOTE: current behaviour is not wrong, it just not too flexible... // NOTE: current behaviour is not wrong, it just not too flexible...
// XXX BUG (IE): clicking the filter field selects it but loses
// focus disabling text input...
update: function(path){ update: function(path){
path = path || this.path path = path || this.path
var browser = this.dom var browser = this.dom
@ -469,14 +467,19 @@ var BrowserPrototype = {
var txt var txt
p.append($('<div>') p.append($('<div>')
.addClass('dir cur') .addClass('dir cur')
// XXX BUG: for some reason this element keeps the selection
// but looses focus in IE...
.click(function(){ .click(function(){
that.startFilter() that.toggleFilter('on')
//that.update(path.concat($(this).text())) //that.update(path.concat($(this).text()))
// XXX HACK: prevents the field from blurring when clicked... // XXX HACK: prevents the field from blurring when clicked...
// ...need to find a better way...
that._hold_blur = true that._hold_blur = true
setTimeout(function(){ delete that._hold_blur }, 20) setTimeout(function(){ delete that._hold_blur }, 20)
// XXX HACK: this will work around double triggering of the focus
// event after a click happens...
that._focus_hold = true
}) })
// XXX for some reason this gets triggered when clicking ano // XXX for some reason this gets triggered when clicking ano
// is not triggered when entering via '/' // is not triggered when entering via '/'
@ -484,7 +487,7 @@ var BrowserPrototype = {
// XXX HACK: prevents the field from bluring when clicked... // XXX HACK: prevents the field from bluring when clicked...
// ...need to find a better way... // ...need to find a better way...
if(!that._hold_blur){ if(!that._hold_blur){
that.stopFilter() that.toggleFilter('off')
} }
}) })
/* XXX does the right thing (replaces the later .focus(..) /* XXX does the right thing (replaces the later .focus(..)
@ -494,7 +497,16 @@ var BrowserPrototype = {
}) })
*/ */
// only update if text changed... // only update if text changed...
// XXX for some reason this gets triggered when clicking ano
// is not triggered when entering via '/'
.focus(function(){ .focus(function(){
// XXX HACK: this will work around double triggering of the focus
// event after a click happens...
if(that._focus_hold){
delete that._focus_hold
return
}
txt = $(this).text() txt = $(this).text()
}) })
.keyup(function(){ .keyup(function(){
@ -702,7 +714,7 @@ var BrowserPrototype = {
// //
// NOTE: see .filter(..) for docs on actual filtering. // NOTE: see .filter(..) for docs on actual filtering.
// NOTE: this does not affect any UI modes, for list filtering mode // NOTE: this does not affect any UI modes, for list filtering mode
// see: .startFilter(..) and friends... // see: .toggleFilter(..)...
filterList: function(pattern){ filterList: function(pattern){
var that = this var that = this
var browser = this.dom var browser = this.dom
@ -820,44 +832,52 @@ var BrowserPrototype = {
// NOTE: the action as a side effect exits the filter (causes blur // NOTE: the action as a side effect exits the filter (causes blur
// on filter field)... // on filter field)...
// NOTE: this uses .filter(..) for actual filtering... // NOTE: this uses .filter(..) for actual filtering...
// // NOTE: on state change this will return this...
// XXX should this be a toggler??? toggleFilter: CSSClassToggler(
startFilter: function(){ function(){ return this.dom },
if(this.options.filter){ 'filtering',
var range = document.createRange() // do not enter filter mode if filtering is disabled...
var selection = window.getSelection() function(action){ return action != 'on' || this.options.filter },
function(action){
// on...
if(action == 'on'){
var range = document.createRange()
var selection = window.getSelection()
var that = this var that = this
this.dom.addClass('filtering') var e = this.dom.find('.path .dir.cur')
var e = this.dom.find('.path .dir.cur') //.text('')
//.text('') .attr('contenteditable', true)
.attr('contenteditable', true)
.focus()
// place the cursor... // place the cursor...
//range.setStart(e[0], 0) //range.setStart(e[0], 0)
//range.collapse(true) //range.collapse(true)
range.selectNodeContents(e[0]) range.selectNodeContents(e[0])
selection.removeAllRanges() selection.removeAllRanges()
selection.addRange(range) selection.addRange(range)
}
return this // off...
}, } else {
stopFilter: function(){ this.filterList('*')
this.filterList('*') this.dom
this.dom.removeClass('filtering') .find('.path .dir.cur')
this.dom.find('.path .dir.cur') .text('')
.text('') .removeAttr('contenteditable')
.removeAttr('contenteditable')
// NOTE: we might select an item outside of the current visible // NOTE: we might select an item outside of the current visible
// area, thus re-selecting it after we remove the filter // area, thus re-selecting it after we remove the filter
// will place it correctly. // will place it correctly.
this.select(this.select('!')) this.select(this.select('!'))
return this this.focus()
.focus() }
},
// XXX is this correct???
return this
}),
// shorthands mostly for use in actions and for chaining...
startFilter: function(){ return this.toggleFilter('on') },
stopFilter: function(){ return this.toggleFilter('off') },
// Toggle filter view mode... // Toggle filter view mode...
toggleFilterViewMode: function(){ toggleFilterViewMode: function(){
@ -959,7 +979,7 @@ var BrowserPrototype = {
return $() return $()
} }
filtering = filtering == null ? this.filtering : filtering filtering = filtering == null ? this.toggleFilter('?') == 'on' : filtering
// empty list/string selects none... // empty list/string selects none...
elem = elem != null && elem.length == 0 ? 'none' : elem elem = elem != null && elem.length == 0 ? 'none' : elem

View File

@ -60,7 +60,7 @@
// list is not normalized... // list is not normalized...
// NOTE: the toggler can be passed a non-jquery object, but then only an // NOTE: the toggler can be passed a non-jquery object, but then only an
// explicit state is supported as the second argument, the reason // explicit state is supported as the second argument, the reason
// being that we can not determain the current state without a propper // being that we can not determine the current state without a proper
// .hasClass(..) test... // .hasClass(..) test...
// //
// //
@ -112,7 +112,7 @@ function Toggler(elem, state_accessor, states, callback_a, callback_b){
// normalize states... // normalize states...
states = typeof(states) == typeof('str') ? ['none', states] : states states = typeof(states) == typeof('str') ? ['none', states] : states
// normalize the callbacks... // normalize the callbacks...
if(callback_b == null){ if(callback_b === undefined){
var callback_pre = null var callback_pre = null
var callback_post = callback_a var callback_post = callback_a
} else { } else {
@ -208,7 +208,10 @@ function Toggler(elem, state_accessor, states, callback_a, callback_b){
// post callback... // post callback...
if(callback_post != null){ if(callback_post != null){
callback_post.apply(this, [action, e].concat(args)) var res = callback_post.apply(this, [action, e].concat(args))
if(res !== undefined){
action = res
}
} }
return action return action