mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 10:20:08 +00:00
moved sort to a separate module + some refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
7a7641c2fc
commit
8276ea7689
@ -12,6 +12,7 @@ define(function(require){ var module = {}
|
|||||||
var core = require('features/core')
|
var core = require('features/core')
|
||||||
|
|
||||||
require('features/base')
|
require('features/base')
|
||||||
|
require('features/sort')
|
||||||
require('features/location')
|
require('features/location')
|
||||||
require('features/history')
|
require('features/history')
|
||||||
require('features/app')
|
require('features/app')
|
||||||
|
|||||||
@ -552,325 +552,6 @@ module.Base = core.ImageGridFeatures.Feature({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
|
||||||
// Sort...
|
|
||||||
|
|
||||||
var SortActions =
|
|
||||||
module.SortActions = actions.Actions({
|
|
||||||
config: {
|
|
||||||
// this can be:
|
|
||||||
// - sort mode name - as set in .config['sort-mode'] key
|
|
||||||
// Example: 'Date'
|
|
||||||
// - explicit sort method - as set in .config['sort-mode'] value
|
|
||||||
// Example: 'metadata.createDate birthtime'
|
|
||||||
'default-sort': 'Date',
|
|
||||||
|
|
||||||
// Format:
|
|
||||||
// The value is a space separated string of methods.
|
|
||||||
// A method is either a sort method defined in .__sort_methods__
|
|
||||||
// or a dot-separated image attribute path.
|
|
||||||
//
|
|
||||||
// NOTE: 'Date' is descending by default
|
|
||||||
// NOTE: .toggleImageSort('?') may also show 'Manual' when
|
|
||||||
// .data.manual_order is present.
|
|
||||||
// NOTE: 'Manual' mode is set after .shiftImageLeft(..)/.shiftImageRight(..)
|
|
||||||
// are called or when restoring a pre-existing .data.manual_order
|
|
||||||
// via .toggleImageSort('Manual')
|
|
||||||
//
|
|
||||||
// XXX need a natural way to reverse these...
|
|
||||||
'sort-methods': {
|
|
||||||
'none': '',
|
|
||||||
// NOTE: this is descending by default...
|
|
||||||
'Date': 'metadata.createDate birthtime reverse',
|
|
||||||
'File date': 'birthtime reverse',
|
|
||||||
'Name (XP-style)': 'name-leading-sequence name path',
|
|
||||||
'File sequence number': 'name-sequence name path',
|
|
||||||
'Name': 'name path',
|
|
||||||
// XXX sequence number with overflow...
|
|
||||||
//'File sequence number with overflow': 'name-leading-sequence name path',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Custom sort methods...
|
|
||||||
//
|
|
||||||
// Format:
|
|
||||||
// {
|
|
||||||
// <method-name>: function(a, b){ ... },
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// NOTE: the cmp function is called in the actions context.
|
|
||||||
//
|
|
||||||
// XXX sequence number with overflow...
|
|
||||||
__sort_methods__: {
|
|
||||||
'name-leading-sequence': function(a, b){
|
|
||||||
a = this.images.getImageNameLeadingSeq(a)
|
|
||||||
a = typeof(a) == typeof('str') ? 0 : a
|
|
||||||
b = this.images.getImageNameLeadingSeq(b)
|
|
||||||
b = typeof(b) == typeof('str') ? 0 : b
|
|
||||||
|
|
||||||
return a - b
|
|
||||||
},
|
|
||||||
'name-sequence': function(a, b){
|
|
||||||
a = this.images.getImageNameSeq(a)
|
|
||||||
a = typeof(a) == typeof('str') ? 0 : a
|
|
||||||
b = this.images.getImageNameSeq(b)
|
|
||||||
b = typeof(b) == typeof('str') ? 0 : b
|
|
||||||
|
|
||||||
return a - b
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Sort using the default sort method
|
|
||||||
// .sortImages()
|
|
||||||
// NOTE: the actual sort method used is set via
|
|
||||||
// .config['default-sort']
|
|
||||||
//
|
|
||||||
// Sort using a specific method(s):
|
|
||||||
// .sortImages(<method>)
|
|
||||||
// .sortImages(<method>, <reverse>)
|
|
||||||
//
|
|
||||||
// .sortImages('<method> ..')
|
|
||||||
// .sortImages('<method> ..', <reverse>)
|
|
||||||
//
|
|
||||||
// .sortImages([<method>, ..])
|
|
||||||
// .sortImages([<method>, ..], <reverse>)
|
|
||||||
// NOTE: <method> can either be one of:
|
|
||||||
// 1) method name (key) from .config['sort-methods']
|
|
||||||
// 2) a space separated string of methods or attribute paths
|
|
||||||
// as in .config['sort-methods']'s values.
|
|
||||||
// for more info se doc for: .config['sort-methods']
|
|
||||||
// NOTE: if it is needed to reverse the method by default just
|
|
||||||
// add 'reverse' to it's string.
|
|
||||||
//
|
|
||||||
// Update current sort order:
|
|
||||||
// .sortImages('update')
|
|
||||||
// NOTE: unless the sort order (.data.order) is changed manually
|
|
||||||
// this will have no effect.
|
|
||||||
// NOTE: this is designed to facilitate manual sorting of
|
|
||||||
// .data.order
|
|
||||||
//
|
|
||||||
// Reverse image order:
|
|
||||||
// .sortImages('reverse')
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// NOTE: reverse is calculated by oddity -- if an odd number indicated
|
|
||||||
// then the result is reversed, otherwise it is not.
|
|
||||||
// e.g. adding:
|
|
||||||
// 'metadata.createDate birthtime' + ' reverse'
|
|
||||||
// will reverse the result's order while:
|
|
||||||
// 'metadata.createDate birthtime reverse' + ' reverese'
|
|
||||||
// will cancel reversal.
|
|
||||||
// NOTE: with empty images this will not do anything.
|
|
||||||
//
|
|
||||||
// XXX cache order???
|
|
||||||
// XXX would be nice to be able to sort a list of gids or a section
|
|
||||||
// of images...
|
|
||||||
// XXX sorting with partial images will throw the images that do not
|
|
||||||
// exist or the ones that do not have the right attrs all over
|
|
||||||
// the place...
|
|
||||||
sortImages: ['- Edit|Sort/Sort images',
|
|
||||||
function(method, reverse){
|
|
||||||
var that = this
|
|
||||||
|
|
||||||
if(method == 'reverse'){
|
|
||||||
method = 'update'
|
|
||||||
reverse = true
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse = reverse == null ? false
|
|
||||||
: reverse == 'reverse'
|
|
||||||
|| reverse
|
|
||||||
|
|
||||||
// special case: 'update'
|
|
||||||
method = method == 'update' ? [] : method
|
|
||||||
|
|
||||||
// defaults...
|
|
||||||
method = method
|
|
||||||
|| this.config['sort-methods'][this.config['default-sort']]
|
|
||||||
|| this.config['default-sort']
|
|
||||||
|| 'birthtime'
|
|
||||||
|
|
||||||
// expand method names...
|
|
||||||
// XXX should this be recursive???
|
|
||||||
method = typeof(method) == typeof('str') ?
|
|
||||||
method
|
|
||||||
.split(/ +/g)
|
|
||||||
.map(function(m){
|
|
||||||
return that.config['sort-methods'][m] || m })
|
|
||||||
.join(' ')
|
|
||||||
: method
|
|
||||||
method = typeof(method) == typeof('str') ? method.split(/ +/g) : method
|
|
||||||
|
|
||||||
// get the reverse arity...
|
|
||||||
var i = method.indexOf('reverse')
|
|
||||||
while(i >=0){
|
|
||||||
reverse = !reverse
|
|
||||||
|
|
||||||
method.splice(i, 1)
|
|
||||||
i = method.indexOf('reverse')
|
|
||||||
}
|
|
||||||
|
|
||||||
// can't sort if we know nothing about .images
|
|
||||||
if(method && method.length > 0 && (!this.images || this.images.length == 0)){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the compare routine...
|
|
||||||
method = method
|
|
||||||
// remove duplicate methods...
|
|
||||||
.unique()
|
|
||||||
.map(function(m){
|
|
||||||
return SortActions.__sort_methods__[m]
|
|
||||||
|| (that.__sort_methods__ && that.__sort_methods__[m])
|
|
||||||
// sort by attr path...
|
|
||||||
|| (function(){
|
|
||||||
var p = m.split(/\./g)
|
|
||||||
var _get = function(obj){
|
|
||||||
if(obj == null){
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
for(var i=0; i<p.length; i++){
|
|
||||||
obj = obj[p[i]]
|
|
||||||
if(obj === undefined){
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
return function(a, b){
|
|
||||||
a = _get(this.images[a])
|
|
||||||
b = _get(this.images[b])
|
|
||||||
|
|
||||||
if(a == b){
|
|
||||||
return 0
|
|
||||||
} else if(a < b){
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return +1
|
|
||||||
}
|
|
||||||
}})()
|
|
||||||
})
|
|
||||||
|
|
||||||
// prepare the cmp function...
|
|
||||||
var cmp = method.length == 1 ?
|
|
||||||
method[0]
|
|
||||||
// chain compare -- return first non equal (0) result...
|
|
||||||
: function(a, b){
|
|
||||||
var res = 0
|
|
||||||
for(var i=0; i < method.length; i++){
|
|
||||||
res = method[i].call(that, a, b)
|
|
||||||
if(res != 0){
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// do the sort (in place)...
|
|
||||||
if(method && method.length > 0 && this.images){
|
|
||||||
this.data.order = this.data.order.slice()
|
|
||||||
reverse ?
|
|
||||||
this.data.order.sort(cmp.bind(this)).reverse()
|
|
||||||
: this.data.order.sort(cmp.bind(this))
|
|
||||||
|
|
||||||
// just reverse...
|
|
||||||
} else if(method.length <= 0 && reverse) {
|
|
||||||
this.data.order.reverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data.updateImagePositions()
|
|
||||||
}],
|
|
||||||
|
|
||||||
// XXX should this be a dialog with ability to edit modes???
|
|
||||||
// - toggle reverse sort
|
|
||||||
// XXX currently this will not toggle past 'none'
|
|
||||||
toggleImageSort: ['- Edit|Sort/Toggle image sort method',
|
|
||||||
toggler.Toggler(null,
|
|
||||||
function(){ return this.data.sort_method || 'none' },
|
|
||||||
function(){
|
|
||||||
return Object.keys(this.config['sort-methods'])
|
|
||||||
.concat((this.data.manual_order
|
|
||||||
|| this.data.sort_method == 'Manual') ? ['Manual'] : [])},
|
|
||||||
// prevent setting 'none' as mode...
|
|
||||||
function(mode){
|
|
||||||
return !!this.images
|
|
||||||
&& (mode != 'none'
|
|
||||||
|| (mode == 'Manual' && this.data.manual_order)) },
|
|
||||||
// XXX need to refactor the toggler a bit to make the
|
|
||||||
// signature simpler...
|
|
||||||
function(mode, _, reverse){
|
|
||||||
reverse = reverse == 'reverse' || reverse
|
|
||||||
|
|
||||||
// save manual order...
|
|
||||||
if(this.data.sort_method == 'Manual'){
|
|
||||||
this.data.manual_order = this.data.order.slice()
|
|
||||||
}
|
|
||||||
|
|
||||||
// special case: manual order...
|
|
||||||
// XXX this does not use .sortImages(..) thus this does not update...
|
|
||||||
if(mode == 'Manual'){
|
|
||||||
this.data.order = this.data.manual_order.slice()
|
|
||||||
this.sortImages('update' + (reverse ? ' reverse' : ''))
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.sortImages(mode + (reverse ? ' reverse' : ''))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.data.sort_method = mode
|
|
||||||
})],
|
|
||||||
|
|
||||||
// Store/load sort data:
|
|
||||||
// .data.sort_method - current sort mode (optional)
|
|
||||||
// .data.manual_order - manual sort order (optional)
|
|
||||||
load: [function(data){
|
|
||||||
return function(){
|
|
||||||
if(data.data && data.data.sort_method){
|
|
||||||
this.data.sort_method = data.data.sort_method
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.data && data.data.manual_order){
|
|
||||||
this.data.manual_order = data.data.manual_order
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
json: [function(){
|
|
||||||
return function(res){
|
|
||||||
if(this.data.sort_method){
|
|
||||||
res.data.sort_method = this.data.sort_method
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.data.manual_order){
|
|
||||||
res.data.manual_order = this.data.manual_order
|
|
||||||
|
|
||||||
} else if(this.toggleImageSort('?') == 'Manual'){
|
|
||||||
res.data.manual_order = this.data.order
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
})
|
|
||||||
|
|
||||||
var Sort =
|
|
||||||
module.Sort = core.ImageGridFeatures.Feature({
|
|
||||||
title: '',
|
|
||||||
|
|
||||||
tag: 'sort',
|
|
||||||
depends: [
|
|
||||||
'base',
|
|
||||||
],
|
|
||||||
|
|
||||||
actions: SortActions,
|
|
||||||
|
|
||||||
handlers: [
|
|
||||||
['shiftImageRight shiftImageLeft',
|
|
||||||
function(){
|
|
||||||
this.data.sort_method = 'Manual'
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Tags...
|
// Tags...
|
||||||
|
|
||||||
@ -1250,6 +931,7 @@ core.ImageGridFeatures.Feature('base-full', [
|
|||||||
'sort',
|
'sort',
|
||||||
'crop',
|
'crop',
|
||||||
'image-group',
|
'image-group',
|
||||||
|
'tasks',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
460
ui (gen4)/features/sort.js
Executable file
460
ui (gen4)/features/sort.js
Executable file
@ -0,0 +1,460 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
define(function(require){ var module = {}
|
||||||
|
|
||||||
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
||||||
|
|
||||||
|
var actions = require('lib/actions')
|
||||||
|
var features = require('lib/features')
|
||||||
|
var toggler = require('lib/toggler')
|
||||||
|
|
||||||
|
var core = require('features/core')
|
||||||
|
|
||||||
|
var overlay = require('lib/widget/overlay')
|
||||||
|
var browse = require('lib/widget/browse')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
var SortActions =
|
||||||
|
module.SortActions = actions.Actions({
|
||||||
|
config: {
|
||||||
|
// Default sort method...
|
||||||
|
//
|
||||||
|
// this can be:
|
||||||
|
// - sort mode name - as set in .config['sort-mode'] key
|
||||||
|
// Example: 'Date'
|
||||||
|
// - explicit sort method - as set in .config['sort-mode'] value
|
||||||
|
// Example: 'metadata.createDate birthtime'
|
||||||
|
'default-sort': 'Date',
|
||||||
|
|
||||||
|
// Default sort order...
|
||||||
|
//
|
||||||
|
// can be: 'default', 'reverse')
|
||||||
|
'default-sort-order': 'default',
|
||||||
|
|
||||||
|
// Sort methods...
|
||||||
|
//
|
||||||
|
// Format:
|
||||||
|
// The value is a space separated string of methods.
|
||||||
|
// A method is either a sort method defined in .__sort_methods__
|
||||||
|
// or a dot-separated image attribute path.
|
||||||
|
//
|
||||||
|
// NOTE: 'Date' is descending by default
|
||||||
|
// NOTE: .toggleImageSort('?') may also show 'Manual' when
|
||||||
|
// .data.manual_order is present.
|
||||||
|
// NOTE: 'Manual' mode is set after .shiftImageLeft(..)/.shiftImageRight(..)
|
||||||
|
// are called or when restoring a pre-existing .data.manual_order
|
||||||
|
// via .toggleImageSort('Manual')
|
||||||
|
//
|
||||||
|
// XXX need a natural way to reverse these...
|
||||||
|
'sort-methods': {
|
||||||
|
'none': '',
|
||||||
|
// NOTE: this is descending by default...
|
||||||
|
'Date': 'metadata.createDate birthtime reverse',
|
||||||
|
'File date': 'birthtime reverse',
|
||||||
|
'Name (XP-style)': 'name-leading-sequence name path',
|
||||||
|
'File sequence number': 'name-sequence name path',
|
||||||
|
'Name': 'name path',
|
||||||
|
// XXX sequence number with overflow...
|
||||||
|
//'File sequence number with overflow': 'name-leading-sequence name path',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleDefaultSortOrder: ['- Edit|Sort/Default sort order',
|
||||||
|
core.makeConfigToggler('default-sort-order', ['default', 'reverse'])],
|
||||||
|
|
||||||
|
// Custom sort methods...
|
||||||
|
//
|
||||||
|
// Format:
|
||||||
|
// {
|
||||||
|
// <method-name>: function(a, b){ ... },
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// NOTE: the cmp function is called in the actions context.
|
||||||
|
//
|
||||||
|
// XXX add sequence number with overflow...
|
||||||
|
__sort_methods__: {
|
||||||
|
'name-leading-sequence': function(a, b){
|
||||||
|
a = this.images.getImageNameLeadingSeq(a)
|
||||||
|
a = typeof(a) == typeof('str') ? 0 : a
|
||||||
|
b = this.images.getImageNameLeadingSeq(b)
|
||||||
|
b = typeof(b) == typeof('str') ? 0 : b
|
||||||
|
|
||||||
|
return a - b
|
||||||
|
},
|
||||||
|
'name-sequence': function(a, b){
|
||||||
|
a = this.images.getImageNameSeq(a)
|
||||||
|
a = typeof(a) == typeof('str') ? 0 : a
|
||||||
|
b = this.images.getImageNameSeq(b)
|
||||||
|
b = typeof(b) == typeof('str') ? 0 : b
|
||||||
|
|
||||||
|
return a - b
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Sort images...
|
||||||
|
//
|
||||||
|
// Sort using the default sort method
|
||||||
|
// .sortImages()
|
||||||
|
// NOTE: the actual sort method used is set via
|
||||||
|
// .config['default-sort'] and .config['default-sort-order']
|
||||||
|
//
|
||||||
|
// Sort using a specific method(s):
|
||||||
|
// .sortImages(<method>)
|
||||||
|
// .sortImages(<method>, <reverse>)
|
||||||
|
//
|
||||||
|
// .sortImages('<method> ..')
|
||||||
|
// .sortImages('<method> ..', <reverse>)
|
||||||
|
//
|
||||||
|
// .sortImages([<method>, ..])
|
||||||
|
// .sortImages([<method>, ..], <reverse>)
|
||||||
|
// NOTE: <method> can either be one of:
|
||||||
|
// 1) method name (key) from .config['sort-methods']
|
||||||
|
// 2) a space separated string of methods or attribute paths
|
||||||
|
// as in .config['sort-methods']'s values.
|
||||||
|
// for more info se doc for: .config['sort-methods']
|
||||||
|
// NOTE: if it is needed to reverse the method by default just
|
||||||
|
// add 'reverse' to it's string.
|
||||||
|
//
|
||||||
|
// Update current sort order:
|
||||||
|
// .sortImages('update')
|
||||||
|
// NOTE: unless the sort order (.data.order) is changed manually
|
||||||
|
// this will have no effect.
|
||||||
|
// NOTE: this is designed to facilitate manual sorting of
|
||||||
|
// .data.order
|
||||||
|
//
|
||||||
|
// Reverse image order:
|
||||||
|
// .sortImages('reverse')
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTE: reverse is calculated by oddity -- if an odd number indicated
|
||||||
|
// then the result is reversed, otherwise it is not.
|
||||||
|
// e.g. adding:
|
||||||
|
// 'metadata.createDate birthtime' + ' reverse'
|
||||||
|
// will reverse the result's order while:
|
||||||
|
// 'metadata.createDate birthtime reverse' + ' reverese'
|
||||||
|
// will cancel reversal.
|
||||||
|
// NOTE: with empty images this will not do anything.
|
||||||
|
//
|
||||||
|
// XXX would be nice to be able to sort a list of gids or a section
|
||||||
|
// of images...
|
||||||
|
// XXX sorting with partial images will throw the images that do not
|
||||||
|
// exist or the ones that do not have the right attrs all over
|
||||||
|
// the place...
|
||||||
|
// ...should we pool the "unknowns" to one side with their
|
||||||
|
// current order??
|
||||||
|
// XXX should this handle manual sort order???
|
||||||
|
sortImages: ['- Edit|Sort/Sort images',
|
||||||
|
function(method, reverse){
|
||||||
|
var that = this
|
||||||
|
|
||||||
|
if(method == 'reverse'){
|
||||||
|
method = 'update'
|
||||||
|
reverse = true
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse = reverse == null ? false
|
||||||
|
: reverse == 'reverse'
|
||||||
|
|| reverse
|
||||||
|
|
||||||
|
// special case: 'update'
|
||||||
|
method = method == 'update' ? [] : method
|
||||||
|
|
||||||
|
// defaults...
|
||||||
|
method = method
|
||||||
|
|| ((this.config['default-sort'] || 'birthtime')
|
||||||
|
+ (this.config['default-sort-order'] == 'reverse' ? ' reverse' : ''))
|
||||||
|
|
||||||
|
// set sort method in data...
|
||||||
|
this.data.sort_method = typeof(method) == typeof('str') ? method : method.join(' ')
|
||||||
|
|
||||||
|
// expand method names...
|
||||||
|
// XXX should this be recursive???
|
||||||
|
method = typeof(method) == typeof('str') ?
|
||||||
|
method
|
||||||
|
.split(/ +/g)
|
||||||
|
.map(function(m){
|
||||||
|
return that.config['sort-methods'][m] || m })
|
||||||
|
.join(' ')
|
||||||
|
: method
|
||||||
|
method = typeof(method) == typeof('str') ? method.split(/ +/g) : method
|
||||||
|
|
||||||
|
// get the reverse arity...
|
||||||
|
var i = method.indexOf('reverse')
|
||||||
|
while(i >=0){
|
||||||
|
reverse = !reverse
|
||||||
|
|
||||||
|
method.splice(i, 1)
|
||||||
|
i = method.indexOf('reverse')
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't sort if we know nothing about .images
|
||||||
|
if(method && method.length > 0 && (!this.images || this.images.length == 0)){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the compare routine...
|
||||||
|
method = method
|
||||||
|
// remove duplicate methods...
|
||||||
|
.unique()
|
||||||
|
.map(function(m){
|
||||||
|
return SortActions.__sort_methods__[m]
|
||||||
|
|| (that.__sort_methods__ && that.__sort_methods__[m])
|
||||||
|
// sort by attr path...
|
||||||
|
|| (function(){
|
||||||
|
var p = m.split(/\./g)
|
||||||
|
var _get = function(obj){
|
||||||
|
if(obj == null){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
for(var i=0; i<p.length; i++){
|
||||||
|
obj = obj[p[i]]
|
||||||
|
if(obj === undefined){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
return function(a, b){
|
||||||
|
a = _get(this.images[a])
|
||||||
|
b = _get(this.images[b])
|
||||||
|
|
||||||
|
if(a == b){
|
||||||
|
return 0
|
||||||
|
} else if(a < b){
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}})()
|
||||||
|
})
|
||||||
|
|
||||||
|
// prepare the cmp function...
|
||||||
|
var cmp = method.length == 1 ?
|
||||||
|
method[0]
|
||||||
|
// chain compare -- return first non equal (0) result...
|
||||||
|
: function(a, b){
|
||||||
|
var res = 0
|
||||||
|
for(var i=0; i < method.length; i++){
|
||||||
|
res = method[i].call(that, a, b)
|
||||||
|
if(res != 0){
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the sort (in place)...
|
||||||
|
if(method && method.length > 0 && this.images){
|
||||||
|
this.data.order = this.data.order.slice()
|
||||||
|
reverse ?
|
||||||
|
this.data.order.sort(cmp.bind(this)).reverse()
|
||||||
|
: this.data.order.sort(cmp.bind(this))
|
||||||
|
|
||||||
|
// just reverse...
|
||||||
|
} else if(method.length <= 0 && reverse) {
|
||||||
|
this.data.order.reverse()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.updateImagePositions()
|
||||||
|
}],
|
||||||
|
|
||||||
|
// Toggle sort modes...
|
||||||
|
//
|
||||||
|
// This is similar to sort images but it will also maintain
|
||||||
|
// .data.manual_order state.
|
||||||
|
//
|
||||||
|
// NOTE: a state can be passed appended with reverse, e.g.
|
||||||
|
// .toggleImageSort('Date') and .toggleImageSort('Date reverse')
|
||||||
|
// both will set the sort method to 'Date' but the later will
|
||||||
|
// also reverse it.
|
||||||
|
//
|
||||||
|
// XXX should we merge manual order handling with .sortImages(..)???
|
||||||
|
// XXX currently this will not toggle past 'none'
|
||||||
|
toggleImageSort: ['- Edit|Sort/Toggle image sort method',
|
||||||
|
toggler.Toggler(null,
|
||||||
|
function(){ return (this.data && this.data.sort_method) || 'none' },
|
||||||
|
function(){
|
||||||
|
return Object.keys(this.config['sort-methods'])
|
||||||
|
.concat((this.data
|
||||||
|
&& (this.data.manual_order
|
||||||
|
|| this.data.sort_method == 'Manual')) ?
|
||||||
|
['Manual']
|
||||||
|
: [])},
|
||||||
|
// prevent setting 'none' as mode...
|
||||||
|
function(mode){
|
||||||
|
return !!this.images
|
||||||
|
&& (mode != 'none'
|
||||||
|
|| (mode == 'Manual' && this.data.manual_order)) },
|
||||||
|
// XXX need to refactor the toggler a bit to make the
|
||||||
|
// signature simpler... (???)
|
||||||
|
function(mode, _, reverse){
|
||||||
|
reverse = reverse == 'reverse' || reverse
|
||||||
|
|
||||||
|
// save manual order...
|
||||||
|
if(this.data.sort_method == 'Manual'){
|
||||||
|
this.data.manual_order = this.data.order.slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case: manual order...
|
||||||
|
if(mode == 'Manual'){
|
||||||
|
this.data.order = this.data.manual_order.slice()
|
||||||
|
this.sortImages('update' + (reverse ? ' reverse' : ''))
|
||||||
|
this.data.sort_method = mode
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.sortImages(mode + (reverse ? ' reverse' : ''))
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
|
||||||
|
// Store/load sort data:
|
||||||
|
// .data.sort_method - current sort mode (optional)
|
||||||
|
// .data.manual_order - manual sort order (optional)
|
||||||
|
load: [function(data){
|
||||||
|
return function(){
|
||||||
|
if(data.data && data.data.sort_method){
|
||||||
|
this.data.sort_method = data.data.sort_method
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.data && data.data.manual_order){
|
||||||
|
this.data.manual_order = data.data.manual_order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
json: [function(){
|
||||||
|
return function(res){
|
||||||
|
if(this.data.sort_method){
|
||||||
|
res.data.sort_method = this.data.sort_method
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.data.manual_order){
|
||||||
|
res.data.manual_order = this.data.manual_order
|
||||||
|
|
||||||
|
} else if(this.toggleImageSort('?') == 'Manual'){
|
||||||
|
res.data.manual_order = this.data.order
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
|
||||||
|
var Sort =
|
||||||
|
module.Sort = core.ImageGridFeatures.Feature({
|
||||||
|
title: '',
|
||||||
|
|
||||||
|
tag: 'sort',
|
||||||
|
depends: [
|
||||||
|
'base',
|
||||||
|
],
|
||||||
|
suggested: [
|
||||||
|
'ui-sort',
|
||||||
|
],
|
||||||
|
|
||||||
|
actions: SortActions,
|
||||||
|
|
||||||
|
handlers: [
|
||||||
|
['shiftImageRight shiftImageLeft',
|
||||||
|
function(){
|
||||||
|
this.data.sort_method = 'Manual'
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
var SortUIActions = actions.Actions({
|
||||||
|
// XXX should we be able to edit modes???
|
||||||
|
sortDialog: ['Edit|Sort/Sort images...',
|
||||||
|
function(){
|
||||||
|
var that = this
|
||||||
|
|
||||||
|
var dfl = this.config['default-sort']
|
||||||
|
|
||||||
|
// XXX might be a good idea to make this generic...
|
||||||
|
var _makeTogglHandler = function(toggler){
|
||||||
|
return function(){
|
||||||
|
var txt = $(this).find('.text').first().text()
|
||||||
|
that[toggler]()
|
||||||
|
o.client.update()
|
||||||
|
.then(function(){ o.client.select(txt) })
|
||||||
|
that.toggleSlideshow('?') == 'on'
|
||||||
|
&& o.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var o = overlay.Overlay(this.ribbons.viewer,
|
||||||
|
browse.makeLister(null, function(path, make){
|
||||||
|
var cur = that.toggleImageSort('?')
|
||||||
|
|
||||||
|
that.toggleImageSort('??').forEach(function(mode){
|
||||||
|
// skip 'none'...
|
||||||
|
if(mode == 'none'){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
make(mode)
|
||||||
|
.on('open', function(){
|
||||||
|
that.toggleImageSort(null, mode,
|
||||||
|
that.config['default-sort-order'] == 'reverse')
|
||||||
|
o.close()
|
||||||
|
})
|
||||||
|
.addClass(mode == cur ? 'highlighted' : '')
|
||||||
|
.addClass(mode == dfl ? 'default' : '')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Commands...
|
||||||
|
make('---')
|
||||||
|
|
||||||
|
make('Reverse images')
|
||||||
|
.on('open', function(){
|
||||||
|
that.reverseImages()
|
||||||
|
o.close()
|
||||||
|
})
|
||||||
|
/*
|
||||||
|
make('Reverse ribbons')
|
||||||
|
.on('open', function(){
|
||||||
|
that.reverseRibbons()
|
||||||
|
o.close()
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Settings...
|
||||||
|
make('---')
|
||||||
|
|
||||||
|
make(['Default order: ', that.config['default-sort-order'] || 'ascending'])
|
||||||
|
.on('open', _makeTogglHandler('toggleDefaultSortOrder'))
|
||||||
|
.addClass('item-value-view')
|
||||||
|
}))
|
||||||
|
|
||||||
|
// select the current order...
|
||||||
|
o.client.select('"' + this.toggleImageSort('?') + '"')
|
||||||
|
|
||||||
|
return o
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
var SortUI =
|
||||||
|
module.SortUI = core.ImageGridFeatures.Feature({
|
||||||
|
title: '',
|
||||||
|
doc: '',
|
||||||
|
|
||||||
|
tag: 'ui-sort',
|
||||||
|
depends: [
|
||||||
|
'ui',
|
||||||
|
],
|
||||||
|
|
||||||
|
actions: SortUIActions,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* vim:set ts=4 sw=4 : */
|
||||||
|
return module })
|
||||||
@ -69,13 +69,12 @@ var core = require('features/core')
|
|||||||
// . | | . - drag enabled (XXX not implemented)
|
// . | | . - drag enabled (XXX not implemented)
|
||||||
// . | | . - next/prev image keeps drag position
|
// . | | . - next/prev image keeps drag position
|
||||||
// . +---------------+ .
|
// . +---------------+ .
|
||||||
// . .
|
// . . - use tiles instead very large images (XXX ???)
|
||||||
// + - - - - - - - - - +
|
// + - - - - - - - - - +
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// NOTE: this in part does the same job as .ribbons.correctImageProportionsForRotation(..)
|
// NOTE: this in part does the same job as .ribbons.correctImageProportionsForRotation(..)
|
||||||
//
|
//
|
||||||
// XXX might be a good idea to use tiles for zoomed in images...
|
|
||||||
// XXX should this be an action???
|
// XXX should this be an action???
|
||||||
function updateImageProportions(){
|
function updateImageProportions(){
|
||||||
var that = this
|
var that = this
|
||||||
|
|||||||
@ -19,9 +19,6 @@ var ribbons = require('ribbons')
|
|||||||
var core = require('features/core')
|
var core = require('features/core')
|
||||||
var base = require('features/base')
|
var base = require('features/base')
|
||||||
|
|
||||||
var overlay = require('lib/widget/overlay')
|
|
||||||
var browse = require('lib/widget/browse')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
@ -336,6 +333,7 @@ module.ViewerActions = actions.Actions({
|
|||||||
// ...navigate by proximity (closest to center) rather than by
|
// ...navigate by proximity (closest to center) rather than by
|
||||||
// order...
|
// order...
|
||||||
// XXX skip off-screen ribbons (???)
|
// XXX skip off-screen ribbons (???)
|
||||||
|
// XXX should the timeout be configurable???
|
||||||
alignByOrder: ['Interface/Align ribbons by image order',
|
alignByOrder: ['Interface/Align ribbons by image order',
|
||||||
function(target, scale, now){
|
function(target, scale, now){
|
||||||
if(target == 'now'){
|
if(target == 'now'){
|
||||||
@ -753,10 +751,6 @@ module.Viewer = core.ImageGridFeatures.Feature({
|
|||||||
'base',
|
'base',
|
||||||
'workspace',
|
'workspace',
|
||||||
],
|
],
|
||||||
suggested: [
|
|
||||||
'ui-sort',
|
|
||||||
// XXX add base ui features here...
|
|
||||||
],
|
|
||||||
|
|
||||||
actions: ViewerActions,
|
actions: ViewerActions,
|
||||||
|
|
||||||
@ -820,93 +814,6 @@ module.Viewer = core.ImageGridFeatures.Feature({
|
|||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
// User interfaces for different base features...
|
// User interfaces for different base features...
|
||||||
|
|
||||||
var SortUIActions = actions.Actions({
|
|
||||||
config: {
|
|
||||||
'default-sort-order': 'default',
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleDefaultSortOrder: ['- Edit|Sort/Default sort order',
|
|
||||||
core.makeConfigToggler('default-sort-order', ['default', 'reverse'])],
|
|
||||||
sortDialog: ['Edit|Sort/Sort images...',
|
|
||||||
function(){
|
|
||||||
var that = this
|
|
||||||
|
|
||||||
// XXX might be a good idea to make this generic...
|
|
||||||
var _makeTogglHandler = function(toggler){
|
|
||||||
return function(){
|
|
||||||
var txt = $(this).find('.text').first().text()
|
|
||||||
that[toggler]()
|
|
||||||
o.client.update()
|
|
||||||
.then(function(){ o.client.select(txt) })
|
|
||||||
that.toggleSlideshow('?') == 'on'
|
|
||||||
&& o.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var o = overlay.Overlay(this.ribbons.viewer,
|
|
||||||
browse.makeLister(null, function(path, make){
|
|
||||||
var cur = that.toggleImageSort('?')
|
|
||||||
|
|
||||||
that.toggleImageSort('??').forEach(function(mode){
|
|
||||||
// skip 'none'...
|
|
||||||
if(mode == 'none'){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
make(mode + (cur == mode ? ' *' : ''))
|
|
||||||
.on('open', function(){
|
|
||||||
that.toggleImageSort(null, mode,
|
|
||||||
that.config['default-sort-order'] == 'reverse')
|
|
||||||
o.close()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Commands...
|
|
||||||
make('---')
|
|
||||||
|
|
||||||
make('Reverse images')
|
|
||||||
.on('open', function(){
|
|
||||||
that.reverseImages()
|
|
||||||
o.close()
|
|
||||||
})
|
|
||||||
/*
|
|
||||||
make('Reverse ribbons')
|
|
||||||
.on('open', function(){
|
|
||||||
that.reverseRibbons()
|
|
||||||
o.close()
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Settings...
|
|
||||||
make('---')
|
|
||||||
|
|
||||||
make(['Default order: ', that.config['default-sort-order'] || 'ascending'])
|
|
||||||
.on('open', _makeTogglHandler('toggleDefaultSortOrder'))
|
|
||||||
.addClass('item-value-view')
|
|
||||||
}))
|
|
||||||
|
|
||||||
// select the current order...
|
|
||||||
o.client.select('"' + this.toggleImageSort('?') + ' *"')
|
|
||||||
|
|
||||||
return o
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
|
|
||||||
var SortUI =
|
|
||||||
module.SortUI = core.ImageGridFeatures.Feature({
|
|
||||||
title: '',
|
|
||||||
doc: '',
|
|
||||||
|
|
||||||
tag: 'ui-sort',
|
|
||||||
depends: [
|
|
||||||
'ui',
|
|
||||||
],
|
|
||||||
|
|
||||||
actions: SortUIActions,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
|
||||||
// XXX tag dialogs...
|
// XXX tag dialogs...
|
||||||
// XXX
|
// XXX
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user