diff --git a/ui/crop.js b/ui/crop.js index 05b332dc..056e875e 100755 --- a/ui/crop.js +++ b/ui/crop.js @@ -325,6 +325,10 @@ function filterImagesDialog(){ +'All filter text fields support\n' +'regular expressions.\n' +'\n' + +'Adding a "!" to any text filter\n' + +'will negate it, selecting unmatching\n' + +'images only.\n' + +'\n' +'Only non-empty fields are used\n' +'for filtering.', cfg, diff --git a/ui/data.js b/ui/data.js index 6296b31d..906b3478 100755 --- a/ui/data.js +++ b/ui/data.js @@ -1474,6 +1474,13 @@ function makePrevFromListAction(get_closest, get_list, restrict_to_ribbon){ // - if image attribute value is a list, the pattern must match at // least one element of the list (OR) // +// A filter can be negated by prepending with '!', this will change the +// matching rules: +// - an attribute is non-existent +// - an attribute does not match the filter +// - if image attribute value is a list, the pattern must not match any +// of the elements (AND) +// // If gids is passed, it will be used as the source, otherwise // getLoadedGIDs(..) will be used to produce a list of gids. // @@ -1491,29 +1498,38 @@ function filterGIDs(filter, gids, data, images){ // normalize filter... for(var k in filter){ if(typeof(filter[k]) == typeof('str')){ - filter[k] = RegExp(filter[k]) + if(filter[k][0] == '!'){ + filter[k] = [ RegExp(filter[k].slice(1)), false ] + } else { + filter[k] = [ RegExp(filter[k]), true ] + } + } else { + filter[k] = [ RegExp(filter[k]), true ] } } var res = gids.filter(function(gid){ var img = images[gid] for(var k in filter){ - // if key does not exist we have no match... - if(!(k in img)){ - return false + var f = filter[k] + var exp = f[1] + f = f[0] + var val = img[k] + + // if key does not exist... + if(val == null){ + return exp ? false : true } - var f = filter[k] - var val = img[k] val = typeof(val) == typeof('str') ? val.trim() : val // value is a list, check items, at least one needs to match... if(val.constructor.name == 'Array' - && val.filter(function(e){ return f.test(e) }).length < 1){ + && val.filter(function(e){ return f.test(e) == exp }).length < 1){ return false // check the whole value... - } else if(!f.test(val)){ + } else if(f.test(val) != exp){ return false } } diff --git a/ui/keybindings.js b/ui/keybindings.js index bc4dfac9..60a2a76d 100755 --- a/ui/keybindings.js +++ b/ui/keybindings.js @@ -369,6 +369,15 @@ var KEYBOARD_CONFIG = { 'ctrl+shift': 'next-screen', }, + // align to base ribbon... + // XXX base ribbon concept is not yet fully defined... + Down: { + 'ctrl+alt': doc('Align sorted section to current ribbon (EXPERIMENTAL)', + function(){ + alignRibbons() + }), + }, + // zooming... '#1': doc('Fit one image', function(){ fitNImages(1) }), '#2': doc('Fit two images', function(){ fitNImages(2) }),