From b23e9777b71d7f44f3ebc711156030cb9e5e68ef Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Mon, 5 Oct 2020 03:58:03 +0300 Subject: [PATCH] migrated some code to ig-types... Signed-off-by: Alex A. Naanou --- Viewer/cfg/requirejs.js | 5 + Viewer/features/filesystem.js | 132 +--------- Viewer/lib/util.js | 449 +--------------------------------- Viewer/package-lock.json | 17 +- Viewer/package.json | 3 +- 5 files changed, 32 insertions(+), 574 deletions(-) diff --git a/Viewer/cfg/requirejs.js b/Viewer/cfg/requirejs.js index 185ea37d..37d3a90c 100644 --- a/Viewer/cfg/requirejs.js +++ b/Viewer/cfg/requirejs.js @@ -26,6 +26,7 @@ var requirejs_cfg = { //'ext-lib/preact': './node_modules/preact/dist/preact.dev', 'lib/object': 'node_modules/ig-object/object', + 'lib/types': 'node_modules/ig-types/', 'lib/actions': 'node_modules/ig-actions/actions', 'lib/features': 'node_modules/ig-features/features', //'lib/keyboard': './node_modules/ig-keyboard/keyboard', @@ -39,6 +40,7 @@ var requirejs_cfg = { // ...these enable the npm modules reference each other in // a cross-platform manner.... 'ig-object': 'lib/object', + 'ig-types': 'lib/types', 'ig-actions': 'lib/actions', 'ig-features': 'lib/features', @@ -47,6 +49,9 @@ var requirejs_cfg = { 'generic-walk': 'lib/walk', }, }, + packages: [ + 'lib/types', + ], } diff --git a/Viewer/features/filesystem.js b/Viewer/features/filesystem.js index d59ec051..50e9054a 100755 --- a/Viewer/features/filesystem.js +++ b/Viewer/features/filesystem.js @@ -34,6 +34,8 @@ var overlay = require('lib/widget/overlay') var browse = require('lib/widget/browse') var browseWalk = require('lib/widget/browse-walk') +var containers = require('lib/types/containers') + /*********************************************************************/ @@ -2562,50 +2564,6 @@ module.FileSystemWriter = core.ImageGridFeatures.Feature({ //--------------------------------------------------------------------- // Writer UI... -var object = require('lib/object') - -// XXX move this to browse2 and use it as an option/basis for list... -// XXX BUG: UniqueKeyMap([['a', 123], ...]) breaks... -var UniqueKeyMap = object.Constructor('UniqueKeyMap', Map, { - // Format: - // Map([ - // [ , ], - // ... - // ]) - // - // XXX make this a non-enumerable prop... - __names: null, - - __name_pattern__: '$NAME ($COUNT)', - - // XXX problem: non unique elems will override each other in .__names... - set: function(key, elem){ - // elem already in index -> rename... - // XXX should we have the restriction of requiring unique elements??? - if(this.__names.has(elem)){ - return this.rename(this.__names.get(elem), key) } - this.__names[elem] = key - var n = key - var i = 0 - while(this.has(n)){ - i++ - n = this.__name_pattern__ - .replace(/\$NAME/, key) - .replace(/\$COUNT/, i) } - return object.parentCall(UniqueKeyMap.prototype, 'set', this, n, elem) }, - delete: function(key){ - delete this.__names[this.get(key)] - return object.parentCall(UniqueKeyMap.prototype, 'delete', this, key) }, - rename: function(from, to){ - var e = this.get(from) - this.delete(from) - return this.set(to, e) }, - - __init__: function(){ - this.__names = new Map() }, -}) - - // XXX add writer UI feature... // - save as.. (browser) // - save if not base path present (browser) @@ -3177,90 +3135,10 @@ var FileSystemWriterUIActions = actions.Actions({ var that = this var logger = this.logger && this.logger.push('exportPresets') - // XXX need a way for index to support unique names and to do it - // in a stable manner: - // - getName(..) must generate the same title for - // the same item, i.e. 'abc' -> 'abc (3)' -> 'abc (3)' ... - // ...this may be done like this: - // - index format (buildIndex(..)): - // { - // : [ <index>, ... ], - // ... - // } - // - title format (used by getPreset(..)): - // "<title>" -> index = 0 - // "<title> (<index>)" -> index = <index> - // - cache name with index in a Map(..) with preset as key - // - // Format: - // Map([ - // [<preset>, { - // base: <base-name>, - // index: <index>, - // name: "<base-name> (<index>)", - // }], - // ... - // ]) - var getName = function(elem, index){ - // add to index... - if(index){ - var data = index.get(elem) || {} - index.has(elem) - || index.set(elem, data) } - - // generate base name... - // NOTE: we always do this unconditionally so as not to - // mess with keeping things in sync... - var date = preset.date - && Date.fromTimeStamp(preset.date).toShortDate() - date = date ? - date + ' - ' - : '' - var clean = preset['clean-target'] ? - '' - : ' (merge)' - var base = data.base = - date - + (preset.name - || ( preset.mode == 'Images only' ? - // XXX might be a good idea to move name patterns to .config - `${ preset.mode }: ` - +`"${ preset['preview-name-pattern'] }" → "${ preset.path }"${ clean }` - : `${ preset.mode }: → "${ preset.path }"${ clean }`)) - // generate a unique name... - var name = base - var i = 0 - while(name in index.names){ - data.index = ++i - // XXX might be a good idea to move name patterns to .config - name = `${ base } (${ i })` } - data.name = name - index.names[name] = elem - return name } - var getElem = function(title, index){ - return index.names[title] } - var delElem = function(title, index){ - var e = index.names[title] - delete index.names[title] - index.delete(e) - return index } - var renameElem = function(from, to, index){ - var e = getElem(from, index) - if(to.trim() == ''){ - delete e.name - } else { - e.name = to.trim() } - delete index.names[from] - getName(e, index) - return index } - var buildCache = function(list){ - //var index = new Map() - //var index.names = {} - // populate the index... - list - .forEach(function(e){ getName(e, index) }) - return index } + // XXX use this as index... + // XXX use this in browse2... + var index = containers.UniqueKeyMap() diff --git a/Viewer/lib/util.js b/Viewer/lib/util.js index 2a628d76..1e2e7dd0 100755 --- a/Viewer/lib/util.js +++ b/Viewer/lib/util.js @@ -7,436 +7,8 @@ (function(require){ var module={} // make module AMD/node compatible... /*********************************************************************/ -require('object-run') - - -//--------------------------------------------------------------------- -// Object... - -// Get all the accessible keys... -// -// This is different to Object.keys(..) in that this will return keys -// from all the prototypes in the inheritance chain while .keys(..) will -// only return the keys defined in the current object only. -Object.deepKeys = function(obj){ - var res = [] - while(obj != null){ - res = res.concat(Object.keys(obj)) - obj = obj.__proto__ - } - return res.unique() } - - -// Make a full key set copy of an object... -// -// NOTE: this will not deep-copy the values... -Object.flatCopy = function(obj){ - var res = {} - Object.deepKeys(obj).forEach(function(key){ - res[key] = obj[key] - }) - return res } - - - -//--------------------------------------------------------------------- -// Array... - -// Array.prototype.flat polyfill... -// -// NOTE: .flat(..) is not yet supported in IE/Edge... -Array.prototype.flat - || (Array.prototype.flat = function(depth){ - depth = typeof(depth) == typeof(123) ? depth : 1 - return this.reduce(function(res, e){ - return res.concat(e instanceof Array && depth > 0 ? - e.flat(depth-1) - : [e]) }, []) }) - - -// Array.prototype.includes polyfill... -// -Array.prototype.includes - || (Array.prototype.includes = function(value){ - return this.indexOf(value) >= 0 }) - - -// first/last element access short-hands... -// -// .first() -// .last() -// -> elem -// -// .first(value) -// .last(value) -// -> array -// -// NOTE: setting a value will overwrite an existing first/last value. -// NOTE: for an empty array both .first(..)/.last(..) will return undefined -// when getting a value and set the 0'th value when setting... -Array.prototype.first - || (Array.prototype.first = function(value){ - return arguments.length > 0 ? - ((this[0] = value), this) - : this[0]}) -Array.prototype.last - || (Array.prototype.last = function(value){ - return arguments.length > 0 ? - ((this[this.length - 1 || 0] = value), this) - : this[this.length - 1]}) - - -/*/ XXX not yet sure should these be funcs or props... -'first' in Array.prototype - || Object.defineProperty(Array.prototype, 'first', { - enumerable: false, - get : function () { - return this[0] }, - set : function(value){ - this[0] = value - return this }, }) - -'last' in Array.prototype - || Object.defineProperty(Array.prototype, 'last', { - enumerable: false, - get : function () { - return this[this.length - 1] }, - set : function(value){ - this[this.length - 1 || 0] = value - return this }, }) -//*/ - - -// Compact a sparse array... -// -// NOTE: this will not compact in-place. -Array.prototype.compact = function(){ - return this.filter(function(){ return true }) } - - -// like .length but for sparse arrays will return the element count... -'len' in Array.prototype - || Object.defineProperty(Array.prototype, 'len', { - get : function () { - return Object.keys(this).length - }, - set : function(val){}, - }) - - -// Convert an array to object... -// -// Format: -// { -// <item>: <index>, -// ... -// } -// -// NOTE: items should be strings, other types will get converted to -// strings and thus may mess things up. -// NOTE: this will forget repeating items... -// NOTE: normalize will slow things down... -Array.prototype.toKeys = function(normalize){ - return normalize ? - this.reduce(function(r, e, i){ - r[normalize(e)] = i - return r }, {}) - : this.reduce(function(r, e, i){ - r[e] = i - return r }, {}) } - - -// Convert an array to a map... -// -// This is similar to Array.prototype.toKeys(..) but does not restrict -// value type to string. -// -// Format: -// Map([ -// [<item>, <index>], -// ... -// ]) -// -// NOTE: this will forget repeating items... -// NOTE: normalize will slow things down... -Array.prototype.toMap = function(normalize){ - return normalize ? - this - .reduce(function(m, e, i){ - m.set(normalize(e), i) - return m }, new Map()) - : this - .reduce(function(m, e, i){ - m.set(e, i) - return m }, new Map()) } - - -// Return an array with duplicate elements removed... -// -// NOTE: order is preserved... -Array.prototype.unique = function(normalize){ - return normalize ? - [...new Map(this.map(function(e){ return [normalize(e), e] })).values()] - : [...new Set(this)] } -Array.prototype.tailUnique = function(normalize){ - return this - .slice() - .reverse() - .unique(normalize) - .reverse() } - -// Compare two arrays... -// -Array.prototype.cmp = function(other){ - if(this === other){ - return true } - if(this.length != other.length){ - return false } - for(var i=0; i<this.length; i++){ - if(this[i] != other[i]){ - return false } } - return true } - - -// Compare two Arrays as sets... -// -// This will ignore order -// -// XXX should we use Set(..) here??? -Array.prototype.setCmp = function(other){ - return this === other - || this - .unique() - .sort() - .cmp(other - .unique() - .sort()) } - - -Array.prototype.sortAs = function(other){ - return this.sort(function(a, b){ - var i = other.indexOf(a) - var j = other.indexOf(b) - return i < 0 && j < 0 ? 0 - : i < 0 ? 1 - : j < 0 ? -1 - : i - j }) } - - - -// Equivalent to .map(..) / .filter(..) / .reduce(..) / .forEach(..) that -// process the contents in chunks asynchronously... -// -// .mapChunks(func) -// .mapChunks(chunk_size, func) -// .mapChunks([item_handler, chunk_handler]) -// .mapChunks(chunk_size, [item_handler, chunk_handler]) -// -> promise(list) -// -// .filterChunks(func) -// .filterChunks(chunk_size, func) -// .filterChunks([item_handler, chunk_handler]) -// .filterChunks(chunk_size, [item_handler, chunk_handler]) -// -> promise(list) -// -// .reduceChunks(func, res) -// .reduceChunks(chunk_size, func, res) -// .reduceChunks([item_handler, chunk_handler], res) -// .reduceChunks(chunk_size, [item_handler, chunk_handler], res) -// -> promise(res) -// -// -// chunk_handler(chunk, result, offset) -// -// -// chunk_size can be: -// 20 - chunk size -// '20' - chunk size -// '20C' - number of chunks -// -// -// The main goal of this is to not block the runtime while processing a -// very long array by interrupting the processing with a timeout... -// -var makeChunkIter = function(iter, wrapper){ - wrapper = wrapper - || function(res, func, array, e){ - return func.call(this, e[1], e[0], array) } - return function(size, func, ...rest){ - var that = this - var args = [...arguments] - size = (args[0] instanceof Function - || args[0] instanceof Array) ? - (this.CHUNK_SIZE || 50) - : args.shift() - size = typeof(size) == typeof('str') ? - // number of chunks... - (size.trim().endsWith('c') || size.trim().endsWith('C') ? - Math.round(this.length / (parseInt(size) || 1)) || 1 - : parseInt(size)) - : size - var postChunk - func = args.shift() - ;[func, postChunk] = func instanceof Array ? func : [func] - rest = args - var res = [] - var _wrapper = wrapper.bind(this, res, func, this) - - return new Promise(function(resolve, reject){ - var next = function(chunks){ - setTimeout(function(){ - var chunk, val - res.push( - val = (chunk = chunks.shift())[iter](_wrapper, ...rest)) - postChunk - && postChunk.call(that, - chunk.map(function([i, v]){ return v }), - val, - chunk[0][0]) - // stop condition... - chunks.length == 0 ? - resolve(res.flat(2)) - : next(chunks) }, 0) } - next(that - // split the array into chunks... - .reduce(function(res, e, i){ - var c = res.slice(-1)[0] - c.length >= size ? - // initial element in chunk... - res.push([[i, e]]) - // rest... - : c.push([i, e]) - return res }, [[]])) }) } } - -Array.prototype.CHUNK_SIZE = 50 -Array.prototype.mapChunks = makeChunkIter('map') -Array.prototype.filterChunks = makeChunkIter('map', - function(res, func, array, e){ - return !!func.call(this, e[1], e[0], array) ? [e[1]] : [] }) -Array.prototype.reduceChunks = makeChunkIter('reduce', - function(total, func, array, res, e){ - return func.call(this, - total.length > 0 ? - total.pop() - : res, - e[1], e[0], array) }) - - - -//--------------------------------------------------------------------- -// Set... - -// Set set operation shorthands... -Set.prototype.unite = function(other){ - return new Set([...this, ...other]) } -Set.prototype.intersect = function(other){ - var test = other.has ? 'has' : 'includes' - return new Set([...this] - .filter(function(e){ return other[test](e) })) } -Set.prototype.subtract = function(other){ - other = new Set(other) - return new Set([...this] - .filter(function(e){ return !other.has(e) })) } - - - -//--------------------------------------------------------------------- -// RegExp... - -// Quote a string and convert to RegExp to match self literally. -var quoteRegExp = -RegExp.quoteRegExp = -module.quoteRegExp = -function(str){ - return str.replace(/([\.\\\/\(\)\[\]\$\*\+\-\{\}\@\^\&\?\<\>])/g, '\\$1') } - - - -//--------------------------------------------------------------------- -// String... - -String.prototype.capitalize = function(){ - return this == '' ? - this - : this[0].toUpperCase() + this.slice(1) } - - - -//--------------------------------------------------------------------- -// Date... - -// NOTE: repatching a date should not lead to any side effects as this -// does not add any state... -var patchDate = -module.patchDate = function(date){ - date = date || Date - - date.prototype.toShortDate = function(show_ms){ - return '' - + this.getFullYear() - +'-'+ ('0'+(this.getMonth()+1)).slice(-2) - +'-'+ ('0'+this.getDate()).slice(-2) - +' '+ ('0'+this.getHours()).slice(-2) - +':'+ ('0'+this.getMinutes()).slice(-2) - +':'+ ('0'+this.getSeconds()).slice(-2) - + (show_ms ? - ':'+(('000'+this.getMilliseconds()).slice(-3)) - : '') } - date.prototype.getTimeStamp = function(show_ms){ - return '' - + this.getFullYear() - + ('0'+(this.getMonth()+1)).slice(-2) - + ('0'+this.getDate()).slice(-2) - + ('0'+this.getHours()).slice(-2) - + ('0'+this.getMinutes()).slice(-2) - + ('0'+this.getSeconds()).slice(-2) - + (show_ms ? - ('000'+this.getMilliseconds()).slice(-3) - : '') } - date.prototype.setTimeStamp = function(ts){ - ts = ts.replace(/[^0-9]*/g, '') - this.setFullYear(ts.slice(0, 4)) - this.setMonth(ts.slice(4, 6)*1-1) - this.setDate(ts.slice(6, 8)) - this.setHours(ts.slice(8, 10)) - this.setMinutes(ts.slice(10, 12)) - this.setSeconds(ts.slice(12, 14)) - this.setMilliseconds(ts.slice(14, 17) || 0) - return this } - date.timeStamp = function(...args){ - return (new this()).getTimeStamp(...args) } - date.fromTimeStamp = function(ts){ - return (new this()).setTimeStamp(ts) } - // convert string time period to milliseconds... - date.str2ms = function(str, dfl){ - dfl = dfl || 'ms' - - if(typeof(str) == typeof(123)){ - var val = str - str = dfl - - } else { - var val = parseFloat(str) - str = str.trim() - - // check if a unit is given... - str = str == val ? dfl : str - } - - var c = /(m(illi)?(-)?s(ec(ond(s)?)?)?)$/i.test(str) ? 1 - : /s(ec(ond(s)?)?)?$/i.test(str) ? 1000 - : /m(in(ute(s)?)?)?$/i.test(str) ? 1000*60 - : /h(our(s)?)?$/i.test(str) ? 1000*60*60 - : /d(ay(s)?)?$/i.test(str) ? 1000*60*60*24 - : null - - return c ? val * c : NaN - } - - return date -} -// patch the root date... -patchDate() +var types = require('lib/types') +module.patchDate = types.patchDate @@ -449,12 +21,8 @@ module.chainCmp = function(cmp_chain){ for(var i=0; i < cmp_chain.length; i++){ res = cmp_chain[i](a, b, get, data) if(res != 0){ - return res - } - } - return res - } -} + return res } } + return res } } // XXX do we need to quote anything else??? @@ -463,8 +31,7 @@ module.path2url = function(path){ // test if we have a schema, and if yes return as-is... if(/^(data|http|https|file|[\w-]*):[\\\/]{2}/.test(path)){ - return path - } + return path } // skip encoding windows drives... path = path .split(/[\\\/]/g) @@ -479,8 +46,7 @@ function(path){ // NOTE: keep '%' the first... .replace(/%/g, '%25') .replace(/#/g, '%23') - .replace(/&/g, '%26')) -} + .replace(/&/g, '%26')) } // NOTE: we are not using node's path module as we need this to work in @@ -501,8 +67,7 @@ function(path){ // take care of .. .replace(/\/[^\/]+\/\.\.\//g, '/') .replace(/\/[^\/]+\/\.\.$/, '') - : path -} + : path } diff --git a/Viewer/package-lock.json b/Viewer/package-lock.json index a66f3e72..18ba335b 100755 --- a/Viewer/package-lock.json +++ b/Viewer/package-lock.json @@ -1,6 +1,6 @@ { "name": "ImageGrid.Viewer.g4", - "version": "4.0.0a", + "version": "4.0.0-a", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1111,6 +1111,15 @@ "resolved": "https://registry.npmjs.org/ig-object/-/ig-object-5.2.8.tgz", "integrity": "sha512-EzT4CP6d6lI8bnknNgT3W8mUQhSVXflO0yPbKD4dKsFcINiC6npjoEBz+8m3VQmWJhc+36pXD4JLwNxUEgzi+Q==" }, + "ig-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ig-types/-/ig-types-2.0.0.tgz", + "integrity": "sha512-CUxqit6W4vjf3fnxVq1KGITRhI6//PiJcaha0CbHZqKutAvPXPjYOzlPdx9HL00LvmU7iNnOcyzWLrCnYd3Myw==", + "requires": { + "ig-object": "^5.2.8", + "object-run": "^1.0.1" + } + }, "image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -1411,9 +1420,9 @@ "integrity": "sha1-jrbgqZ+HrTT/8YJzMRBJadjFBP4=" }, "moment": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz", - "integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw==" + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz", + "integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA==" }, "ms": { "version": "2.1.2", diff --git a/Viewer/package.json b/Viewer/package.json index d67af787..ee086461 100755 --- a/Viewer/package.json +++ b/Viewer/package.json @@ -31,7 +31,8 @@ "ig-argv": "^2.15.0", "ig-features": "^3.4.2", "ig-object": "^5.2.8", - "moment": "^2.28.0", + "ig-types": "^2.0.0", + "moment": "^2.29.0", "object-run": "^1.0.1", "requirejs": "^2.3.6", "requirejs-plugins": "^1.0.2",