diff --git a/ui (gen4)/imagegrid/tags.js b/ui (gen4)/imagegrid/tags.js index 1fd05b53..dd6f08d8 100755 --- a/ui (gen4)/imagegrid/tags.js +++ b/ui (gen4)/imagegrid/tags.js @@ -858,7 +858,6 @@ var BaseTagsPrototype = { // Edit API... // - // XXX save un-normalized tags to dict... ??? (a-la flickr) tag: function(tags, value){ var that = this value = value instanceof Array ? value : [value] @@ -1117,7 +1116,7 @@ var BaseTagsPrototype = { patchObj(this.__index || {}) patchObj(this.definitions || {}, true) } - + return this }, @@ -1312,6 +1311,8 @@ var BaseTagsPrototype = { var index = this.__index || {} normalizeSplit(others) .forEach(function(other){ + other.dict + && (that.dict = Object.assign(that.dict || {}, other.dict)) Object.entries(other.__index || {}) .forEach(function(e){ index[e[0]] = new Set([...(index[e[0]] || []), ...e[1]]) }) }) @@ -1681,11 +1682,10 @@ object.makeConstructor('BaseTags', //--------------------------------------------------------------------- // XXX EXPERIMENTAL... -// ...this is a bit too generic, we need to save dict values only -// when tagging or adding tags... -// ...also need to clear the dict when untagging... +// XXX need a .dict cleanup strategy... var TagsWithDictPrototype = { - __proto__: BaseTags, + __proto__: BaseTagsPrototype, + // Tag dictionary... // @@ -1697,17 +1697,22 @@ var TagsWithDictPrototype = { // dict: null, - // XXX need to only do this when adding new tags... - // ...rename to .normalizeSave(..) and use in .tag(..), .toggle(..), ... - normalize: function(...tags){ - var dict = this.dict = this.dict || {} - var res = TagsWithDict.__proto__.normalize.call(this, ...tags) + + // Normalize tags and save their dict values... + // + // NOTE: this is signature-compatible with .normalize(..) with the + // side-effect of saving non-normalized values to .dict + // + normalizeSave: function(...tags){ var sp = this.COMBINED_SEPARATOR + var dict = this.dict = this.dict || {} + var res = this.normalize(...tags) tags = normalizeSplit(tags) .map(function(tag){ return tag.split(sp) }) .flat() + ;(res instanceof Array ? res : [res]) .map(function(tag){ return tag.split(sp) }) @@ -1717,12 +1722,23 @@ var TagsWithDictPrototype = { var value = tags[i].trim() // only add tags if they are not the same as normalized... tag != value - && (dict[tag] = [value] - .concat(dict[tag] || []) + // NOTE: we keep the first value added as main... + && (dict[tag] = (dict[tag] || []) + .concat([value]) .unique()) }) return res }, + + // Translate normalized tag to the dict form... + // + // .translateTag(tag) + // -> str + // + // .translateTag(tag, ..) + // .translateTag([tag, ..]) + // -> [str, ..] + // translateTag: function(...tags){ var that = this var dict = this.dict @@ -1745,6 +1761,58 @@ var TagsWithDictPrototype = { return arguments.length == 1 && typeof(arguments[0]) == typeof('str') ? res[0] : res }, + + // XXX batch remove??? + // XXX + + // Remove orphaned .dict values... + // + // NOTE: an orphan is a dict entry for a tag that is no longer used. + cleanupDict: function(){ + // XXX is this the full list??? + var sp = this.COMBINED_SEPARATOR + var tags = new Set(this.singleTags() + .concat(this.definitionPaths() + .map(function(p){ + return p.split(sp) }) + .flat())) + var dict = this.dict + dict + && Object.keys(dict) + .filter(function(tag){ + return !tags.has(tag) }) + .forEach(function(tag){ + delete dict[tag] }) + return this + }, + + + // Hooks... + tag: function(tags, value){ + this.normalizeSave(tags) + return object.parent(TagsWithDictPrototype.tag, this).call(this, ...arguments) }, + // XXX cleanup .dict... + untag: function(tags, value){ + // XXX cleanup .dict... + return object.parent(TagsWithDictPrototype.untag, this).call(this, ...arguments) }, + // XXX cleanup .dict... + rename: function(from, to, ...tags){ + arguments.length == 2 + && this.normalizeSave(to) + // XXX cleanup dict... + return object.parent(TagsWithDictPrototype.rename, this).call(this, ...arguments) }, + // XXX cleanup .dict... + togglePersistent: function(...tags){ + // XXX remove action... + this.normalizeSave(tags) + // XXX cleanup dict... + return object.parent(TagsWithDictPrototype.togglePersistent, this).call(this, ...arguments) }, + // XXX cleanup .dict... + define: function(tag, value){ + arguments.length > 1 + && value != null + && this.normalizeSave(tag, value) + return object.parent(TagsWithDictPrototype.define, this).call(this, ...arguments) }, } @@ -1868,16 +1936,16 @@ var TagsWithHandlersPrototype = { // tag: function(tags, value){ var that = this - return TagsWithHandlersPrototype.__proto__.tag.call(this, + return object.parent(TagsWithHandlersPrototype.tag, this).call(this, that.handleSpecialTag(tags, 'tag', value), ...[...arguments].slice(1)) }, untag: function(tags, value){ var that = this - return TagsWithHandlersPrototype.__proto__.untag.call(this, + return object.parent(TagsWithHandlersPrototype.untag, this).call(this, that.handleSpecialTag(tags, 'untag', value), ...[...arguments].slice(1)) }, rename: function(tag, to, ...tags){ - return TagsWithHandlersPrototype.__proto__.rename.call(this, + return object.parent(TagsWithHandlersPrototype.rename, this).call(this, tags.length == 0 ? this.handleSpecialTag(tag, to == '' ? 'remove' : 'rename', to) : tag, @@ -1903,19 +1971,9 @@ module.Tags = //BaseTags object.makeConstructor('Tags', BaseTagsClassPrototype, - // XXX HACK??? - // ...this is not a good way to do multiple inheritance/mixins... - Object.assign( - // XXX these must not intersect... - // ...intersecting methods will overwrite each other... - // ...another problem with this approach is that the mixin - // methods explicitly call the base method of the prototype - // which might not be the correct method in the inheritance - // tree (of two or more of the mixins define the same - // method only one definition will get called)... - {__proto__: BaseTagsPrototype}, + object.mixin(BaseTagsPrototype, TagsWithDictPrototype, - TagsWithHandlersPrototype)) + TagsWithHandlers)) diff --git a/ui (gen4)/lib/keyboard.js b/ui (gen4)/lib/keyboard.js index dc49e3a8..815e8983 100755 --- a/ui (gen4)/lib/keyboard.js +++ b/ui (gen4)/lib/keyboard.js @@ -1115,7 +1115,7 @@ var KeyboardWithCSSModesPrototype = { }, __init__: function(keyboard, context){ - object.superMethod(KeyboardWithCSSModes, '__init__').call(this, keyboard) + object.parent(KeyboardWithCSSModesPrototype.__init__, this).call(this, keyboard) if(context instanceof Function){ Object.defineProperty(this, 'context', { diff --git a/ui (gen4)/lib/widget/browse.js b/ui (gen4)/lib/widget/browse.js index c928283c..626e3421 100755 --- a/ui (gen4)/lib/widget/browse.js +++ b/ui (gen4)/lib/widget/browse.js @@ -1880,7 +1880,7 @@ var BrowserPrototype = { // no items selected -- trigger event on main ui... } else { - object.superMethod(Browser, 'trigger').apply(this, arguments) + object.parent(BrowserPrototype.trigger, this).apply(this, arguments) } return this @@ -4030,7 +4030,7 @@ var BrowserPrototype = { __init__: function(parent, options){ var that = this - object.superMethod(Browser, '__init__').call(this, parent, options) + object.parent(BrowserPrototype.__init__, this).call(this, parent, options) var dom = this.dom options = this.options diff --git a/ui (gen4)/lib/widget/overlay.js b/ui (gen4)/lib/widget/overlay.js index e597b506..f2d57186 100755 --- a/ui (gen4)/lib/widget/overlay.js +++ b/ui (gen4)/lib/widget/overlay.js @@ -78,7 +78,7 @@ var OverlayPrototype = { __init__: function(parent, client, options){ var that = this - object.superMethod(Overlay, '__init__').call(this, parent, client, options) + object.parent(OverlayPrototype.__init__, this).call(this, parent, client, options) // Prevent closing the overlay if clicked while blurred... // i.e. diff --git a/ui (gen4)/package-lock.json b/ui (gen4)/package-lock.json index 1bf7d1b0..659cff50 100755 --- a/ui (gen4)/package-lock.json +++ b/ui (gen4)/package-lock.json @@ -345,7 +345,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -1172,9 +1172,9 @@ } }, "ig-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ig-object/-/ig-object-1.0.7.tgz", - "integrity": "sha512-bBlxP0AE9oxjUEtIzgZN302nuUAYycAOeh2F2D/z3OSl4zUc+R0Cb9HMpwOO4gZfc6I4ZV9tr/Ax1lk4KkW/aQ==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ig-object/-/ig-object-1.2.0.tgz", + "integrity": "sha512-+66y36wvev5bdn4bpsK6i6sbePUQ/eLMu+GJ3/lLzGzQSsNWAelOIllKsYpQSObllna3Sl8C2/57I1x/zjm2nQ==" }, "image-size": { "version": "0.5.5", @@ -1417,9 +1417,9 @@ } }, "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==" }, "ms": { "version": "2.0.0", @@ -1656,7 +1656,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1816,7 +1816,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { diff --git a/ui (gen4)/package.json b/ui (gen4)/package.json index a76c11a8..9f25548d 100755 --- a/ui (gen4)/package.json +++ b/ui (gen4)/package.json @@ -28,8 +28,8 @@ "guarantee-events": "^1.0.0", "ig-actions": "^3.22.0", "ig-features": "^3.3.4", - "ig-object": "^1.0.7", - "moment": "^2.22.2", + "ig-object": "^1.2.0", + "moment": "^2.23.0", "openseadragon": "^2.4.0", "requirejs": "^2.3.6", "requirejs-plugins": "^1.0.2",