reworked sort...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2019-11-04 04:27:10 +03:00
parent e498ce3471
commit e64ff7513a
3 changed files with 106 additions and 74 deletions

View File

@ -538,14 +538,16 @@ PACK_FULL = $(BUILD_DIR)/$(APP_NAME)/ $(BUILD_DIR)/$(APP_NAME)/$(NODE_DIR)
# build date... # build date...
# NOTE: this depends on lots of stuff so as to be updated in case any of # NOTE: this depends on lots of stuff so as to be updated in case any of
# the dependencies are touched... # the dependencies are touched...
# XXX add nw version option...
$(BUILD_INFO): $(CSS_FILES) $(NODE_DIR) $(PROJECT_FILES) \ $(BUILD_INFO): $(CSS_FILES) $(NODE_DIR) $(PROJECT_FILES) \
$(JS_FILES) $(CSS_FILES) $(HTML_FILES) $(JS_FILES) $(CSS_FILES) $(HTML_FILES)
$(MD) "$(@D)" $(MD) "$(@D)"
@echo "Build info:" @echo "Build info:"
@echo "$(APP_NAME)" | tee $(BUILD_INFO) @echo "$(APP_NAME)" | tee $(BUILD_INFO)
@echo "$(VERSION)" | tee -a $(BUILD_INFO) @echo "version: $(VERSION)" | tee -a $(BUILD_INFO)
@echo "$(DATE)" | tee -a $(BUILD_INFO) @echo "date: $(DATE)" | tee -a $(BUILD_INFO)
@echo "$(COMMIT)" | tee -a $(BUILD_INFO) @echo "commit: $(COMMIT)" | tee -a $(BUILD_INFO)
@echo "electron: $(ELECTRON_VERSION)" | tee -a $(BUILD_INFO)
%.css: %.less %.css: %.less
@ -686,12 +688,12 @@ $(BUILD_DIR)/$(APP_NAME)-%.in-place.zip: $(TARGET_DIR)/$(ELECTRON_DIST) \
cp "$<" "$@.tmp" cp "$<" "$@.tmp"
# # setup app icon... # # setup app icon...
# # XXX # # XXX
# remove default_app.asar... # remove default_app.asar and misc stuff...
$(call zipDelFrom,"$(BUILD_DIR)",$@.tmp,"$(ASAR_PATH)/default_app.asar") $(call zipDelFrom,"$(BUILD_DIR)",$@.tmp,"$(ASAR_PATH)/default_app.asar")
$(call zipDelFrom,"$(BUILD_DIR)",$@.tmp,"version")
# rename electron stuff... # rename electron stuff...
zipnote "$@.tmp" \ zipnote "$@.tmp" \
| sed 's/\(^@ LICENSE\)$$/\1\n@=LICENSE.electron/' \ | sed 's/\(^@ LICENSE\)$$/\1\n@=LICENSE.electron/' \
| sed 's/\(^@ version\)$$/\1\n@=version.electron/' \
| zipnote -w "$@.tmp" | zipnote -w "$@.tmp"
# add app.asar and friends... # add app.asar and friends...
$(MD) "$(BUILD_DIR)/$(ASAR_PATH)" $(MD) "$(BUILD_DIR)/$(ASAR_PATH)"

View File

@ -80,6 +80,11 @@ module.SortActions = actions.Actions({
'Name (natural number order)': 'Name (natural number order)':
'name-leading-sequence name path', 'name-leading-sequence name path',
'Ribbon order':
'sort-via-ribbons keep-position',
'Reverse ribbon order':
'sort-via-ribbons-reverse keep-position',
// aliases... // aliases...
'example-sort-alias': 'example-sort-alias':
'Date "File date" Name', 'Date "File date" Name',
@ -144,20 +149,28 @@ module.SortActions = actions.Actions({
// remove quotes... // remove quotes...
.replace(/^(["'])([^'"]*)(\1)$/, '$2') .replace(/^(["'])([^'"]*)(\1)$/, '$2')
var m = that.config['sort-methods'][name] var m = that.config['sort-methods'][name]
|| (that.__sort_methods__ && that.__sort_methods__[name]) || (that.__sort_methods__
&& that.__sort_methods__[name])
|| SortActions.__sort_methods__[name] || SortActions.__sort_methods__[name]
return typeof(m) == typeof('str') ? splitMethods(m) : m return typeof(m) == typeof('str') ?
} splitMethods(m)
: m }
// return a single method... // return a single method...
if(!(methods instanceof Array)){ if(!(methods instanceof Array)){
return actions.ASIS(get(methods) || null) return actions.ASIS(
get(methods)
|| that.getSortMethods(splitMethods(methods))
|| null)
} }
// return multiple methods... // return multiple methods...
var res = {} var res = {}
methods methods
.forEach(function(m){ res[m] = get(m) }) .forEach(function(m){
res[m] = m == 'reverse' ?
(res[m] || []).concat([m])
: get(m) })
return res return res
}], }],
// XXX should this count 'reverese' arity??? // XXX should this count 'reverese' arity???
@ -174,15 +187,22 @@ module.SortActions = actions.Actions({
`, `,
function(method, seen){ function(method, seen){
var that = this var that = this
var reverse = false
seen = seen || [] seen = seen || []
if(seen.indexOf(method) >= 0){ if(seen.indexOf(method) >= 0){
throw new Error('Sort method loop detected.') throw new Error('Sort method loop detected.') }
}
var methods = that.config['sort-methods'] || [] var methods = that.config['sort-methods'] || []
return (method instanceof Array ? return (method instanceof Array ?
method method
: that.getSortMethods(method)) : that.getSortMethods(method)
.run(function(){
return Object.entries(this)
.map(function([key, value]){
return value == null ?
key
: value })
.flat() }))
.map(function(method){ .map(function(method){
var a = SortActions.__sort_methods__[method] var a = SortActions.__sort_methods__[method]
|| (that.__sort_methods__ && that.__sort_methods__[method]) || (that.__sort_methods__ && that.__sort_methods__[method])
@ -195,6 +215,13 @@ module.SortActions = actions.Actions({
: a instanceof Array ? : a instanceof Array ?
a a
: method }) : method })
// count reverse arity...
.filter(function(e){
reverse = e == 'reverse' ? !reverse : reverse
return e != 'reverse' })
.concat(reverse ?
'reverse'
: [])
.flat() }], .flat() }],
// Custom sort methods... // Custom sort methods...
@ -316,21 +343,50 @@ module.SortActions = actions.Actions({
return (index[a] || 0) - (index[b] || 0) } return (index[a] || 0) - (index[b] || 0) }
}, },
// Keep image order in each ribbon the same but sort ribbons (i.e.
// images within ribbons) in ribbon order...
//
// e.g. all images in ribbon N are after images of ribbon <N
// and before images in ribbons >N
'sort-via-ribbons': function(reverse){
var that = this
var index = new Map(
this.data.ribbon_order
.run(function(){
return reverse ?
this.slice().reverse()
: this })
.map(function(gid){
return that.data.ribbons[gid] })
.flat()
.compact()
.map(function(e, i){
return [e, i] }))
return function(a, b){
a = index.get(a)
b = index.get(b)
return (a === undefined || b === undefined) ?
0
: a - b } },
'sort-via-ribbons-reverse': function(){
return SortActions.__sort_methods__['sort-via-ribbons'].call(this, true) },
// This is specifically designed to terminate sort methods to prevent // This is specifically designed to terminate sort methods to prevent
// images that are not relevant to the previous order to stay in place // images that are not relevant to the previous order to stay in place
// //
// If this is explicitly included then 'reverse' order is ignored.
//
// XXX need to test how will this affect a set of images where part // XXX need to test how will this affect a set of images where part
// of the set is sortable an part is not... // of the set is sortable an part is not...
// XXX legacy: this is added to every sort automatically... // XXX legacy: this is added to every sort automatically...
// ...do we still need this here??? // ...do we still need this here???
'keep-position': function(){ 'keep-position': function(){
var order = new Map(
this.data.order
.map(function(e, i){
return [e, i] }))
return function(a, b){ return function(a, b){
a = this.data.order.indexOf(a) return order.get(a) - order.get(b) } },
b = this.data.order.indexOf(b)
return a - b
}
},
}, },
// XXX would be nice to be able to sort a list of gids or a section // XXX would be nice to be able to sort a list of gids or a section
// of images... // of images...
@ -398,25 +454,24 @@ module.SortActions = actions.Actions({
// special case: 'update' // special case: 'update'
method = method == 'update' ? [] : method method = method == 'update' ? [] : method
// defaults... // defaults...
method = method method = method
|| ((this.config['default-sort'] || 'image-date') || ((this.config['default-sort'] || 'image-date')
+ (this.config['default-sort-order'] == 'reverse' ? ' reverse' : '')) + (this.config['default-sort-order'] == 'reverse' ? ' reverse' : ''))
// set sort method in data... // set sort method in data...
this.data.sort_method = typeof(method) == typeof('str') ? method : method.join(' ') this.data.sort_method = typeof(method) == typeof('str') ?
method
: method.join(' ')
method = this.expandSortMethod(method) method = this.expandSortMethod(method + (reverse ? ' reverse' : ''))
// get the reverse arity... // get the reverse arity...
var i = method.indexOf('reverse') reverse = method[method.length - 1] == 'reverse'
while(i >=0){ reverse
reverse = !reverse && method.pop()
reverse = reverse
method.splice(i, 1) && !method.includes('keep-position')
i = method.indexOf('reverse')
}
// can't sort if we know nothing about .images // can't sort if we know nothing about .images
if(method && method.length > 0 && (!this.images || this.images.length == 0)){ if(method && method.length > 0 && (!this.images || this.images.length == 0)){
@ -428,6 +483,8 @@ module.SortActions = actions.Actions({
// remove duplicate methods... // remove duplicate methods...
// XXX should we keep the last occurrence or the first occurrence??? // XXX should we keep the last occurrence or the first occurrence???
.unique() .unique()
.concat(['keep-position'])
.tailUnique()
.map(function(m){ .map(function(m){
return (SortActions.__sort_methods__[m] return (SortActions.__sort_methods__[m]
|| (that.__sort_methods__ && that.__sort_methods__[m]) || (that.__sort_methods__ && that.__sort_methods__[m])
@ -461,15 +518,7 @@ module.SortActions = actions.Actions({
} else { } else {
return +1 return +1
} }
}}).call(that) }}).call(that) })
})
// terminator: keep current position...
.concat([function(a, b){
a = that.data.order.indexOf(a)
b = that.data.order.indexOf(b)
return a - b
}])
// prepare the cmp function... // prepare the cmp function...
var cmp = method.length == 1 ? var cmp = method.length == 1 ?
@ -537,46 +586,22 @@ module.SortActions = actions.Actions({
// XXX need to refactor the toggler a bit to make the // XXX need to refactor the toggler a bit to make the
// signature simpler... (???) // signature simpler... (???)
function(mode, _, reverse){ function(mode, _, reverse){
reverse = reverse == 'reverse' || reverse reverse = reverse || ''
reverse = reverse === true ? 'reverse' : reverse
var cache = this.data.sort_cache = this.data.sort_cache || {} var cache = this.data.sort_cache = this.data.sort_cache || {}
var method = this.data.sort_method var method = this.data.sort_method
// cache sort order... // cache sort order...
if(method == 'Manual'){ method == 'Manual'
this.saveOrder(method) && this.saveOrder(method)
} else if(method && !(method in cache)){ var sort = `"${mode}" `+ reverse
this.cacheOrder()
}
var sort = `"${mode}"`+ (reverse ? ' reverse' : '')
// cached order...
// XXX use load cache action...
if(mode in cache
|| sort in cache){
var order = (cache[mode] || cache[sort]).slice()
// invalid cache -> sort...
if(order.length != this.data.order.length){
// drop the cached order...
delete cache[ mode in cache ? mode : sort ]
this.sortImages(sort)
// load cache...
} else {
this.data.order = order
this.sortImages('update' + (reverse ? ' reverse' : ''))
this.data.sort_method = mode
}
// saved sort order... // saved sort order...
} else if(this.data.sort_order ;(this.data.sort_order
&& mode in this.data.sort_order){ && mode in this.data.sort_order) ?
this.loadOrder(mode, reverse) this.loadOrder(mode, reverse == 'reverse')
: this.sortImages(sort)
} else {
this.sortImages(sort)
}
})], })],
// XXX add drop/load actions... // XXX add drop/load actions...
@ -810,6 +835,7 @@ var SortUIActions = actions.Actions({
// XXX should we be able to edit modes??? // XXX should we be able to edit modes???
// XXX should this be a toggler??? // XXX should this be a toggler???
// XXX add "New from current order..."
sortDialog: ['Edit|Sort/Sort images...', sortDialog: ['Edit|Sort/Sort images...',
widgets.makeUIDialog(function(){ widgets.makeUIDialog(function(){
var that = this var that = this

View File

@ -144,13 +144,17 @@ Array.prototype.toMap = function(normalize){
// //
// NOTE: we are not using an Object as an index here as an Array can // NOTE: we are not using an Object as an index here as an Array can
// contain any type of item while Object keys can only be strings... // contain any type of item while Object keys can only be strings...
// NOTE: for an array containing only strings use a much faster .uniqueStrings(..)
// NOTE: this may not work on IE... // NOTE: this may not work on IE...
Array.prototype.unique = function(normalize){ Array.prototype.unique = function(normalize){
return normalize ? return normalize ?
[...new Map(this.map(function(e){ return [normalize(e), e] })).values()] [...new Map(this.map(function(e){ return [normalize(e), e] })).values()]
: [...(new Set(this))] } : [...new Set(this)] }
Array.prototype.tailUnique = function(normalize){
return this
.slice()
.reverse()
.unique(normalize)
.reverse() }
// Compare two arrays... // Compare two arrays...
// //