mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 03:10:07 +00:00 
			
		
		
		
	more refactoring, rearanged sort-related functions and re-written image/gid distance related code...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									d2a065b09a
								
							
						
					
					
						commit
						1bc2fb64f8
					
				
							
								
								
									
										463
									
								
								ui/data.js
									
									
									
									
									
								
							
							
						
						
									
										463
									
								
								ui/data.js
									
									
									
									
									
								
							| @ -172,119 +172,6 @@ function concatZip(){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| function makeDistanceCmp(start, get){ |  | ||||||
| 	if(get == null){ |  | ||||||
| 		return function(a, b){ |  | ||||||
| 			return Math.abs(start - a) - Math.abs(start - b) |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		start = get(start) |  | ||||||
| 		return function(a, b){ |  | ||||||
| 			return Math.abs(start - get(a)) - Math.abs(start - get(b)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Make a cmp function to compare two gids by distance from gid.
 |  | ||||||
| function makeImageGIDDistanceCmp(gid, get, order){ |  | ||||||
| 	order = order == null ? DATA.order : order |  | ||||||
| 	return makeDistanceCmp(gid, get == null ?  |  | ||||||
| 			function(a){ |  | ||||||
| 				return order.indexOf(a)  |  | ||||||
| 			} |  | ||||||
| 			: function(a){ |  | ||||||
| 				return order.indexOf(get(a)) |  | ||||||
| 			}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // NOTE: essentially this is a 2D distance comparison from gid...
 |  | ||||||
| //
 |  | ||||||
| // XXX make this faster...
 |  | ||||||
| // XXX this is fun, but do we actually need this?
 |  | ||||||
| function makeImageRibbonDistanceCmp(gid, get, data, images){ |  | ||||||
| 	data = data == null ? DATA : data |  | ||||||
| 	images = images == null ? IMAGES : images |  | ||||||
| 
 |  | ||||||
| 	// make a cmp index...
 |  | ||||||
| 	var ribbons = $.map(DATA.ribbons, function(r, i){  |  | ||||||
| 		// sort each ribbon by distance from closest gid...
 |  | ||||||
| 		//return [r.slice().sort(makeImageGIDDistanceCmp(getGIDBefore(gid, i)))] 
 |  | ||||||
| 		return [r.slice().sort(makeImageGIDDistanceCmp(gid))]  |  | ||||||
| 	}) |  | ||||||
| 	var gids = $.map(ribbons, function(e){ return [e[0]] }) |  | ||||||
| 	var ri = gids.indexOf(gid) |  | ||||||
| 
 |  | ||||||
| 	function _getRibbon(gid){ |  | ||||||
| 		for(var i=0; i < ribbons.length; i++){ |  | ||||||
| 			if(ribbons[i].indexOf(gid) >= 0){ |  | ||||||
| 				return ribbons[i] |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	function _getDistance(a){ |  | ||||||
| 		var r = _getRibbon(a) |  | ||||||
| 		var x = r.indexOf(a) |  | ||||||
| 		var y = Math.abs(gids.indexOf(r[0]) - ri) |  | ||||||
| 
 |  | ||||||
| 		// NOTE: this is cheating...
 |  | ||||||
| 		//return x + y
 |  | ||||||
| 		// calculate real distance...
 |  | ||||||
| 		return Math.sqrt(x*x + y*y) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if(get == null){ |  | ||||||
| 		return function(a, b){ |  | ||||||
| 			return _getDistance(a) - _getDistance(b) |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		return function(a, b){ |  | ||||||
| 			return _getDistance(get(a)) - _getDistance(get(b)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function cmp(a, b, get){ |  | ||||||
| 	if(get == null){ |  | ||||||
| 		return a - b |  | ||||||
| 	} |  | ||||||
| 	return get(a) - get(b) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // NOTE: this expects gids...
 |  | ||||||
| function imageDateCmp(a, b, get, data){ |  | ||||||
| 	data = data == null ? IMAGES : data |  | ||||||
| 	if(get != null){ |  | ||||||
| 		a = get(a) |  | ||||||
| 		b = get(b) |  | ||||||
| 	} |  | ||||||
| 	return data[b].ctime - data[a].ctime |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // NOTE: this expects gids...
 |  | ||||||
| function imageNameCmp(a, b, get, data){ |  | ||||||
| 	data = data == null ? IMAGES : data |  | ||||||
| 	if(get != null){ |  | ||||||
| 		a = get(a) |  | ||||||
| 		b = get(b) |  | ||||||
| 	} |  | ||||||
| 	a = data[a].path.split('/').pop() |  | ||||||
| 	b = data[b].path.split('/').pop() |  | ||||||
| 	if(a == b){ |  | ||||||
| 		return 0 |  | ||||||
| 	} else if(a < b){ |  | ||||||
| 		return -1 |  | ||||||
| 	} else { |  | ||||||
| 		return +1 |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Get the first sequence of numbers in the file name...
 | // Get the first sequence of numbers in the file name...
 | ||||||
| function getImageNameSeq(gid, data){ | function getImageNameSeq(gid, data){ | ||||||
| 	data = data == null ? IMAGES : data | 	data = data == null ? IMAGES : data | ||||||
| @ -293,6 +180,7 @@ function getImageNameSeq(gid, data){ | |||||||
| 	return r == null ? n : parseInt(r[1]) | 	return r == null ? n : parseInt(r[1]) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| // Get the first sequence of numbers in the file name but only if it is
 | // Get the first sequence of numbers in the file name but only if it is
 | ||||||
| // at the filename start...
 | // at the filename start...
 | ||||||
| function getImageNameLeadingSeq(gid, data){ | function getImageNameLeadingSeq(gid, data){ | ||||||
| @ -303,62 +191,69 @@ function getImageNameLeadingSeq(gid, data){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Compare images by sequence number (in filename) or by filename
 | function getGIDDistance(a, b, get, data){ | ||||||
| //
 | 	data = data == null ? DATA : data | ||||||
| // Examples:
 | 	var order = data.order | ||||||
| // 	"1 file name", "012-file", "file 123 name", "DSC_1234"
 |  | ||||||
| //
 |  | ||||||
| // NOTE: if there are more than one sequence numbers in a filename then
 |  | ||||||
| // 		only the first is considered.
 |  | ||||||
| // NOTE: images with sequence number always precede images with plain 
 |  | ||||||
| // 		filenames...
 |  | ||||||
| function imageSeqOrNameCmp(a, b, get, data, get_seq){ |  | ||||||
| 	data = data == null ? IMAGES : data |  | ||||||
| 	get_seq = get_seq == null ? getImageNameSeq : get_seq |  | ||||||
| 	if(get != null){ | 	if(get != null){ | ||||||
| 		a = get(a) | 		a = get(a) | ||||||
| 		b = get(b) | 		b = get(b) | ||||||
| 	} | 	} | ||||||
|  | 	a = order.indexOf(a) | ||||||
|  | 	b = order.indexOf(b) | ||||||
|  | 	return Math.abs(a - b) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	var aa = get_seq(a, data) |  | ||||||
| 	var bb = get_seq(b, data) |  | ||||||
| 
 | 
 | ||||||
| 	// special case: seq, name
 | // NOTE: this is a constructor to cache the generated index as it is 
 | ||||||
| 	if(typeof(aa) == typeof(123) && typeof(bb) == typeof('str')){ return -1 } | // 		quite slow to construct, but needs to be current...
 | ||||||
| 	// special case: name, seq
 | function makeGIDRibbonDistanceGetter(gid, data){ | ||||||
| 	if(typeof(aa) == typeof('str') && typeof(bb) == typeof(123)){ return +1 } | 	data = data == null ? DATA : data | ||||||
| 
 | 
 | ||||||
| 	// get the names if there are no sequence numbers...
 | 	// make a cmp index...
 | ||||||
| 	// NOTE: at this point both a and b are either numbers or NaN's...
 | 	var ribbons = $.map(DATA.ribbons, function(r, i){  | ||||||
| 	a = isNaN(aa) ? data[a].path.split('/').pop() : aa | 		// sort each ribbon by distance from closest gid...
 | ||||||
| 	b = isNaN(bb) ? data[b].path.split('/').pop() : bb | 		//return [r.slice().sort(makeGIDDistanceCmp(getGIDBefore(gid, i)))] 
 | ||||||
|  | 		return [r.slice().sort(makeGIDDistanceCmp(gid))]  | ||||||
|  | 	}) | ||||||
|  | 	var gids = $.map(ribbons, function(e){ return [e[0]] }) | ||||||
|  | 	var ri = gids.indexOf(gid) | ||||||
| 
 | 
 | ||||||
| 	// do the actual comparison
 | 	// the basic calculator...
 | ||||||
| 	if(a == b){ | 	return function(gid){ | ||||||
| 		return 0 | 		var r = ribbons[getGIDRibbonIndex(gid, {ribbons: ribbons})] | ||||||
| 	} else if(a < b){ | 		var x = r.indexOf(gid) | ||||||
| 		return -1 | 		var y = Math.abs(gids.indexOf(r[0]) - ri) | ||||||
| 	} else { | 
 | ||||||
| 		return +1 | 		// calculate real distance...
 | ||||||
|  | 		return Math.sqrt(x*x + y*y) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Sort images XP-style
 | 
 | ||||||
|  | // Get distance between two gids taking into account ribbons...
 | ||||||
| //
 | //
 | ||||||
| // This will consider sequence numbers if they are at the start of the 
 | // This is essentially a 2D distance between two gids in data.
 | ||||||
| // filename.
 |  | ||||||
| //
 | //
 | ||||||
| // Examples:
 | // NOTE: to get lots of distances from a specific image use 
 | ||||||
| // 	"1 file name", "012-file"
 | // 		makeGIDDistanceCmp(...) for faster results...
 | ||||||
| //
 | function getGIDRibbonDistance(a, b, data){ | ||||||
| // NOTE: images with sequence number always precede images with plain 
 | 	return makeDistanceFromGIDGetter(a, data)(b) | ||||||
| // 		filenames...
 |  | ||||||
| function imageXPStyleFileNameCmp(a, b, get, data){ |  | ||||||
| 	return imageSeqOrNameCmp(a, b, get, data, getImageNameLeadingSeq) |  | ||||||
| }  | }  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | function cmp(a, b, get){ | ||||||
|  | 	if(get == null){ | ||||||
|  | 		return a - b | ||||||
|  | 	} | ||||||
|  | 	return get(a) - get(b) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Generic ordering via DATA.order
 | ||||||
|  | //
 | ||||||
| // NOTE: this expects gids...
 | // NOTE: this expects gids...
 | ||||||
|  | // NOTE: this is not in sort.js because it is a generic base sort method
 | ||||||
| function imageOrderCmp(a, b, get, data){ | function imageOrderCmp(a, b, get, data){ | ||||||
| 	data = data == null ? DATA : data | 	data = data == null ? DATA : data | ||||||
| 	if(get != null){ | 	if(get != null){ | ||||||
| @ -482,128 +377,22 @@ Array.prototype.binSearch = function(target, cmp, get){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Orientation translation...
 |  | ||||||
| function orientationExif2ImageGrid(orientation){ |  | ||||||
| 	return { |  | ||||||
| 		orientation: { |  | ||||||
| 			0: 0, |  | ||||||
| 			1: 0, |  | ||||||
| 			2: 0, |  | ||||||
| 			3: 180, |  | ||||||
| 			4: 0, |  | ||||||
| 			5: 90, |  | ||||||
| 			6: 90, |  | ||||||
| 			7: 90,  |  | ||||||
| 			8: 270, |  | ||||||
| 		}[orientation], |  | ||||||
| 		flipped: { |  | ||||||
| 			0: null, |  | ||||||
| 			1: null, |  | ||||||
| 			2: ['horizontal'], |  | ||||||
| 			3: null, |  | ||||||
| 			4: ['vertical'], |  | ||||||
| 			5: ['vertical'], |  | ||||||
| 			6: null, |  | ||||||
| 			7: ['horizontal'], |  | ||||||
| 			8: null, |  | ||||||
| 		}[orientation] |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Base URL interface...
 |  | ||||||
| //
 |  | ||||||
| // NOTE: changing a base URL will trigger a baseURLChanged event...
 |  | ||||||
| function setBaseURL(url){ |  | ||||||
| 	var old_url = BASE_URL |  | ||||||
| 	url = url.replace(/\/*$/, '/') |  | ||||||
| 	BASE_URL = url |  | ||||||
| 	$('.viewer').trigger('baseURLChanged', [old_url, url]) |  | ||||||
| 	return url |  | ||||||
| } |  | ||||||
| function getBaseURL(){ |  | ||||||
| 	return BASE_URL |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Normalize the path...
 |  | ||||||
| //
 |  | ||||||
| // This will:
 |  | ||||||
| // 	- convert windows absolute paths 'X:\...' -> 'file:///X:/...'
 |  | ||||||
| // 	- if mode is 'absolute':
 |  | ||||||
| // 		- return absolute paths as-is
 |  | ||||||
| // 		- base relative paths on base/BASE_URL, returning an absolute 
 |  | ||||||
| // 			path
 |  | ||||||
| // 	- if mode is relative:
 |  | ||||||
| // 		- if absolute path is based on base/BASE_URL make a relative 
 |  | ||||||
| // 			to base path out of it buy cutting the base out.
 |  | ||||||
| // 		- return absolute paths as-is
 |  | ||||||
| // 		- return relative paths as-is
 |  | ||||||
| //
 |  | ||||||
| // NOTE: mode can be either 'absolute' (default) or 'relative'...
 |  | ||||||
| function normalizePath(url, base, mode){ |  | ||||||
| 	base = base == null ? getBaseURL() : base |  | ||||||
| 	//mode = /^\./.test(base) && mode == null ? 'relative' : null
 |  | ||||||
| 	mode = mode == null ? 'absolute' : mode |  | ||||||
| 
 |  | ||||||
| 	res = '' |  | ||||||
| 
 |  | ||||||
| 	// windows path...
 |  | ||||||
| 	//	- replace all '\\' with '/'...
 |  | ||||||
| 	url = url.replace(/\\/g, '/') |  | ||||||
| 	//	- replace 'X:/...' with 'file:///X:/...' 
 |  | ||||||
| 	if(/^[A-Z]:\//.test(url)){ |  | ||||||
| 		url = 'file:///' + url |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// we got absolute path...
 |  | ||||||
| 	if(/^(file|http|https):\/\/.*$/.test(url)){ |  | ||||||
| 		// check if we start with base, and remove it if so...
 |  | ||||||
| 		if(mode == 'relative' && url.substring(0, base.length) == base){ |  | ||||||
| 			url = url.substring(base.length - 1) |  | ||||||
| 			res = url[0] == '/' ? url.substring(1) : url |  | ||||||
| 
 |  | ||||||
| 		// if it's a different path, return as-is
 |  | ||||||
| 		} else if(mode == 'absolute'){ |  | ||||||
| 			res = url |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 	// make an absolute path...
 |  | ||||||
| 	} else if(mode == 'absolute') { |  | ||||||
| 		// if base ends and url starts with '.' avoid making it a '..'
 |  | ||||||
| 		if(base[base.length-1] == '.' && url[0] == '.'){ |  | ||||||
| 			res = base + url.substring(1) |  | ||||||
| 		// avoid creating '//'...
 |  | ||||||
| 		} else if(base[base.length-1] != '/' && url[0] != '/'){ |  | ||||||
| 			res = base + '/' + url |  | ||||||
| 		} else { |  | ||||||
| 			res = base + url |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// get the actual path...
 |  | ||||||
| 	res = res.replace('${CACHE_DIR}', CACHE_DIR) |  | ||||||
| 
 |  | ||||||
| 	// XXX legacy support...
 |  | ||||||
| 	res = res.replace('.ImageGridCache', CACHE_DIR) |  | ||||||
| 
 |  | ||||||
| 	return res |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // like getRibbonIndex but get the index only via DATA...
 | // like getRibbonIndex but get the index only via DATA...
 | ||||||
| function getDataRibbonIndex(gid, data){ | function getGIDRibbonIndex(gid, data){ | ||||||
| 	gid = gid == null ? getImageGID() : gid | 	gid = gid == null ? getImageGID() : gid | ||||||
| 	data = data == null ? DATA : data | 	data = data == null ? DATA : data | ||||||
| 
 | 
 | ||||||
| 	for(var i=0; i < data.ribbons.length; i++){ | 	var ribbons = data.ribbons | ||||||
| 		if(data.ribbons[i].indexOf(gid) >= 0){ | 
 | ||||||
|  | 	for(var i=0; i < ribbons.length; i++){ | ||||||
|  | 		if(ribbons[i].indexOf(gid) >= 0){ | ||||||
| 			return i | 			return i | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return -1 | 	return -1 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| // Same as getImageBefore(...), but uses gids and searches in DATA...
 | // Same as getImageBefore(...), but uses gids and searches in DATA...
 | ||||||
| //
 | //
 | ||||||
| // NOTE: this uses it's own predicate...
 | // NOTE: this uses it's own predicate...
 | ||||||
| @ -612,7 +401,7 @@ function getGIDBefore(gid, ribbon, search, data){ | |||||||
| 	data = data == null ? DATA : data | 	data = data == null ? DATA : data | ||||||
| 	// XXX get a ribbon without getting into DOM...
 | 	// XXX get a ribbon without getting into DOM...
 | ||||||
| 	// 		...dependency leek...
 | 	// 		...dependency leek...
 | ||||||
| 	ribbon = ribbon == null ? getDataRibbonIndex(gid, data) : ribbon | 	ribbon = ribbon == null ? getGIDRibbonIndex(gid, data) : ribbon | ||||||
| 	search = search == null ? binSearch : search | 	search = search == null ? binSearch : search | ||||||
| 	//search = search == null ? match2(linSearch, binSearch) : search
 | 	//search = search == null ? match2(linSearch, binSearch) : search
 | ||||||
| 	ribbon = data.ribbons[ribbon] | 	ribbon = data.ribbons[ribbon] | ||||||
| @ -698,6 +487,86 @@ function getImageGIDs(from, count, ribbon, inclusive){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // Base URL interface...
 | ||||||
|  | //
 | ||||||
|  | // NOTE: changing a base URL will trigger a baseURLChanged event...
 | ||||||
|  | function getBaseURL(){ | ||||||
|  | 	return BASE_URL | ||||||
|  | } | ||||||
|  | function setBaseURL(url){ | ||||||
|  | 	var old_url = BASE_URL | ||||||
|  | 	url = url.replace(/\/*$/, '/') | ||||||
|  | 	BASE_URL = url | ||||||
|  | 	$('.viewer').trigger('baseURLChanged', [old_url, url]) | ||||||
|  | 	return url | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Normalize the path...
 | ||||||
|  | //
 | ||||||
|  | // This will:
 | ||||||
|  | // 	- convert windows absolute paths 'X:\...' -> 'file:///X:/...'
 | ||||||
|  | // 	- if mode is 'absolute':
 | ||||||
|  | // 		- return absolute paths as-is
 | ||||||
|  | // 		- base relative paths on base/BASE_URL, returning an absolute 
 | ||||||
|  | // 			path
 | ||||||
|  | // 	- if mode is relative:
 | ||||||
|  | // 		- if absolute path is based on base/BASE_URL make a relative 
 | ||||||
|  | // 			to base path out of it buy cutting the base out.
 | ||||||
|  | // 		- return absolute paths as-is
 | ||||||
|  | // 		- return relative paths as-is
 | ||||||
|  | //
 | ||||||
|  | // NOTE: mode can be either 'absolute' (default) or 'relative'...
 | ||||||
|  | function normalizePath(url, base, mode){ | ||||||
|  | 	base = base == null ? getBaseURL() : base | ||||||
|  | 	//mode = /^\./.test(base) && mode == null ? 'relative' : null
 | ||||||
|  | 	mode = mode == null ? 'absolute' : mode | ||||||
|  | 
 | ||||||
|  | 	res = '' | ||||||
|  | 
 | ||||||
|  | 	// windows path...
 | ||||||
|  | 	//	- replace all '\\' with '/'...
 | ||||||
|  | 	url = url.replace(/\\/g, '/') | ||||||
|  | 	//	- replace 'X:/...' with 'file:///X:/...' 
 | ||||||
|  | 	if(/^[A-Z]:\//.test(url)){ | ||||||
|  | 		url = 'file:///' + url | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// we got absolute path...
 | ||||||
|  | 	if(/^(file|http|https):\/\/.*$/.test(url)){ | ||||||
|  | 		// check if we start with base, and remove it if so...
 | ||||||
|  | 		if(mode == 'relative' && url.substring(0, base.length) == base){ | ||||||
|  | 			url = url.substring(base.length - 1) | ||||||
|  | 			res = url[0] == '/' ? url.substring(1) : url | ||||||
|  | 
 | ||||||
|  | 		// if it's a different path, return as-is
 | ||||||
|  | 		} else if(mode == 'absolute'){ | ||||||
|  | 			res = url | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	// make an absolute path...
 | ||||||
|  | 	} else if(mode == 'absolute') { | ||||||
|  | 		// if base ends and url starts with '.' avoid making it a '..'
 | ||||||
|  | 		if(base[base.length-1] == '.' && url[0] == '.'){ | ||||||
|  | 			res = base + url.substring(1) | ||||||
|  | 		// avoid creating '//'...
 | ||||||
|  | 		} else if(base[base.length-1] != '/' && url[0] != '/'){ | ||||||
|  | 			res = base + '/' + url | ||||||
|  | 		} else { | ||||||
|  | 			res = base + url | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// get the actual path...
 | ||||||
|  | 	res = res.replace('${CACHE_DIR}', CACHE_DIR) | ||||||
|  | 
 | ||||||
|  | 	// XXX legacy support...
 | ||||||
|  | 	res = res.replace('.ImageGridCache', CACHE_DIR) | ||||||
|  | 
 | ||||||
|  | 	return res | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| // Select best preview by size...
 | // Select best preview by size...
 | ||||||
| //
 | //
 | ||||||
| // NOTE: this will use the original if everything else is smaller...
 | // NOTE: this will use the original if everything else is smaller...
 | ||||||
| @ -725,27 +594,32 @@ function getBestPreview(gid, size){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Resort the ribbons by DATA.order and re-render...
 | // Orientation translation...
 | ||||||
| //
 | function orientationExif2ImageGrid(orientation){ | ||||||
| // NOTE: due to how the format is structured, to sort the images one 
 | 	return { | ||||||
| // 		only needs to sort DATA.order and call this.
 | 		orientation: { | ||||||
| function updateRibbonOrder(no_reload_viewer){ | 			0: 0, | ||||||
| 	for(var i=0; i < DATA.ribbons.length; i++){ | 			1: 0, | ||||||
| 		DATA.ribbons[i].sort(imageOrderCmp) | 			2: 0, | ||||||
|  | 			3: 180, | ||||||
|  | 			4: 0, | ||||||
|  | 			5: 90, | ||||||
|  | 			6: 90, | ||||||
|  | 			7: 90,  | ||||||
|  | 			8: 270, | ||||||
|  | 		}[orientation], | ||||||
|  | 		flipped: { | ||||||
|  | 			0: null, | ||||||
|  | 			1: null, | ||||||
|  | 			2: ['horizontal'], | ||||||
|  | 			3: null, | ||||||
|  | 			4: ['vertical'], | ||||||
|  | 			5: ['vertical'], | ||||||
|  | 			6: null, | ||||||
|  | 			7: ['horizontal'], | ||||||
|  | 			8: null, | ||||||
|  | 		}[orientation] | ||||||
| 	} | 	} | ||||||
| 	if(!no_reload_viewer){ |  | ||||||
| 		reloadViewer() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // get list of gids sorted by proximity to current gid
 |  | ||||||
| //
 |  | ||||||
| // NOTE: the distance used is the actual 2D distance...
 |  | ||||||
| function getClosestGIDs(gid){ |  | ||||||
| 	gid = gid == null ? getImageGID() : gid |  | ||||||
| 	//return DATA.order.slice().sort(makeImageGIDDistanceCmp(gid))
 |  | ||||||
| 	return DATA.order.slice().sort(makeImageRibbonDistanceCmp(gid)) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -1276,9 +1150,9 @@ function updateImages(size, cmp){ | |||||||
| 		// sorted run...
 | 		// sorted run...
 | ||||||
| 		if(UPDATE_SORT_ENABLED && cmp != false){ | 		if(UPDATE_SORT_ENABLED && cmp != false){ | ||||||
| 			cmp = cmp == null ?  | 			cmp = cmp == null ?  | ||||||
| 					makeImageGIDDistanceCmp(getImageGID(), getImageGID)  | 					makeGIDDistanceCmp(getImageGID(), getImageGID)  | ||||||
| 					// XXX this is more correct but is slow...
 | 					// XXX this is more correct but is slow...
 | ||||||
| 					//makeImageRibbonDistanceCmp(getImageGID(), getImageGID) 
 | 					//makeGIDRibbonDistanceCmp(getImageGID(), getImageGID) 
 | ||||||
| 				: cmp | 				: cmp | ||||||
| 			deferred.resolve($('.image') | 			deferred.resolve($('.image') | ||||||
| 				// sort images by distance from current, so as to update what 
 | 				// sort images by distance from current, so as to update what 
 | ||||||
| @ -1588,6 +1462,21 @@ function getPrevLocation(){ | |||||||
| * Actions... | * Actions... | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | // Sort the ribbons by DATA.order and re-render...
 | ||||||
|  | //
 | ||||||
|  | // NOTE: due to how the format is structured, to sort the images one 
 | ||||||
|  | // 		only needs to sort DATA.order and call this.
 | ||||||
|  | function updateRibbonOrder(no_reload_viewer){ | ||||||
|  | 	for(var i=0; i < DATA.ribbons.length; i++){ | ||||||
|  | 		DATA.ribbons[i].sort(imageOrderCmp) | ||||||
|  | 	} | ||||||
|  | 	if(!no_reload_viewer){ | ||||||
|  | 		reloadViewer() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /******************************************************* Extension ***/ | /******************************************************* Extension ***/ | ||||||
| 
 | 
 | ||||||
| // Open image in an external editor/viewer
 | // Open image in an external editor/viewer
 | ||||||
|  | |||||||
							
								
								
									
										154
									
								
								ui/sort.js
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								ui/sort.js
									
									
									
									
									
								
							| @ -12,7 +12,159 @@ var OVERFLOW_GAP = PROXIMITY * 5 | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /********************************************************* Sorting ***/ | /********************************************************************** | ||||||
|  | * Helpers | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | // create a generic distance comparison function
 | ||||||
|  | //
 | ||||||
|  | // NOTE: both distances are measured from a fixed point (start)...
 | ||||||
|  | function makeDistanceCmp(start, get){ | ||||||
|  | 	if(get == null){ | ||||||
|  | 		return function(a, b){ | ||||||
|  | 			return Math.abs(start - a) - Math.abs(start - b) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		start = get(start) | ||||||
|  | 		return function(a, b){ | ||||||
|  | 			return Math.abs(start - get(a)) - Math.abs(start - get(b)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Make a cmp function to compare two gids by distance from gid.
 | ||||||
|  | //
 | ||||||
|  | // NOTE: this calculates the distance in a flat sequence...
 | ||||||
|  | function makeGIDDistanceCmp(gid, get, data){ | ||||||
|  | 	return function(a, b){ | ||||||
|  | 		return getGIDDistance(gid, a, get, data) - getGIDDistance(gid, b, get, data) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // 2D distance from a specified gid comparison...
 | ||||||
|  | //
 | ||||||
|  | // XXX make this faster...
 | ||||||
|  | // XXX this is fun, but do we actually need this?
 | ||||||
|  | function makeGIDRibbonDistanceCmp(gid, get, data){ | ||||||
|  | 	data = data == null ? DATA : data | ||||||
|  | 
 | ||||||
|  | 	var _getDistance = makeGIDRibbonDistanceGetter(gid) | ||||||
|  | 
 | ||||||
|  | 	if(get == null){ | ||||||
|  | 		return function(a, b){ | ||||||
|  | 			return _getDistance(a) - _getDistance(b) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		return function(a, b){ | ||||||
|  | 			return _getDistance(get(a)) - _getDistance(get(b)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // NOTE: this expects gids...
 | ||||||
|  | function imageDateCmp(a, b, get, data){ | ||||||
|  | 	data = data == null ? IMAGES : data | ||||||
|  | 	if(get != null){ | ||||||
|  | 		a = get(a) | ||||||
|  | 		b = get(b) | ||||||
|  | 	} | ||||||
|  | 	return data[b].ctime - data[a].ctime | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // NOTE: this expects gids...
 | ||||||
|  | function imageNameCmp(a, b, get, data){ | ||||||
|  | 	data = data == null ? IMAGES : data | ||||||
|  | 	if(get != null){ | ||||||
|  | 		a = get(a) | ||||||
|  | 		b = get(b) | ||||||
|  | 	} | ||||||
|  | 	a = data[a].path.split('/').pop() | ||||||
|  | 	b = data[b].path.split('/').pop() | ||||||
|  | 	if(a == b){ | ||||||
|  | 		return 0 | ||||||
|  | 	} else if(a < b){ | ||||||
|  | 		return -1 | ||||||
|  | 	} else { | ||||||
|  | 		return +1 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Compare images by sequence number (in filename) or by filename
 | ||||||
|  | //
 | ||||||
|  | // Examples:
 | ||||||
|  | // 	"1 file name", "012-file", "file 123 name", "DSC_1234"
 | ||||||
|  | //
 | ||||||
|  | // NOTE: if there are more than one sequence numbers in a filename then
 | ||||||
|  | // 		only the first is considered.
 | ||||||
|  | // NOTE: images with sequence number always precede images with plain 
 | ||||||
|  | // 		filenames...
 | ||||||
|  | function imageSeqOrNameCmp(a, b, get, data, get_seq){ | ||||||
|  | 	data = data == null ? IMAGES : data | ||||||
|  | 	get_seq = get_seq == null ? getImageNameSeq : get_seq | ||||||
|  | 	if(get != null){ | ||||||
|  | 		a = get(a) | ||||||
|  | 		b = get(b) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var aa = get_seq(a, data) | ||||||
|  | 	var bb = get_seq(b, data) | ||||||
|  | 
 | ||||||
|  | 	// special case: seq, name
 | ||||||
|  | 	if(typeof(aa) == typeof(123) && typeof(bb) == typeof('str')){ return -1 } | ||||||
|  | 	// special case: name, seq
 | ||||||
|  | 	if(typeof(aa) == typeof('str') && typeof(bb) == typeof(123)){ return +1 } | ||||||
|  | 
 | ||||||
|  | 	// get the names if there are no sequence numbers...
 | ||||||
|  | 	// NOTE: at this point both a and b are either numbers or NaN's...
 | ||||||
|  | 	a = isNaN(aa) ? data[a].path.split('/').pop() : aa | ||||||
|  | 	b = isNaN(bb) ? data[b].path.split('/').pop() : bb | ||||||
|  | 
 | ||||||
|  | 	// do the actual comparison
 | ||||||
|  | 	if(a == b){ | ||||||
|  | 		return 0 | ||||||
|  | 	} else if(a < b){ | ||||||
|  | 		return -1 | ||||||
|  | 	} else { | ||||||
|  | 		return +1 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Compate images by name XP-style
 | ||||||
|  | //
 | ||||||
|  | // This will consider sequence numbers if they are at the start of the 
 | ||||||
|  | // filename.
 | ||||||
|  | // 
 | ||||||
|  | // Examples:
 | ||||||
|  | // 	"1 file name", "012-file"
 | ||||||
|  | //
 | ||||||
|  | // NOTE: images with sequence number always precede images with plain 
 | ||||||
|  | // 		filenames...
 | ||||||
|  | function imageXPStyleFileNameCmp(a, b, get, data){ | ||||||
|  | 	return imageSeqOrNameCmp(a, b, get, data, getImageNameLeadingSeq) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Get list of gids sorted by proximity to current gid
 | ||||||
|  | //
 | ||||||
|  | // NOTE: the distance used is the actual 2D distance...
 | ||||||
|  | function getClosestGIDs(gid){ | ||||||
|  | 	gid = gid == null ? getImageGID() : gid | ||||||
|  | 	//return DATA.order.slice().sort(makeGIDDistanceCmp(gid))
 | ||||||
|  | 	return DATA.order.slice().sort(makeGIDRibbonDistanceCmp(gid)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /********************************************************************** | ||||||
|  | * Actions | ||||||
|  | */ | ||||||
| 
 | 
 | ||||||
| function reverseImageOrder(){ | function reverseImageOrder(){ | ||||||
| 	DATA.order.reverse() | 	DATA.order.reverse() | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user