added experimental tag dict...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-12-24 17:44:31 +03:00
parent e6f1f9e416
commit bd97721bbc
2 changed files with 121 additions and 28 deletions

View File

@ -540,6 +540,8 @@ var TagUIActions = actions.Actions({
return browse.makeLister(null, function(path, make){ return browse.makeLister(null, function(path, make){
var tags = that.data.getTags(gids) var tags = that.data.getTags(gids)
var tagset = that.data.tags
var dict = tagset.dict
// tags... // tags...
// XXX make this a group... // XXX make this a group...
@ -590,7 +592,17 @@ var TagUIActions = actions.Actions({
var tagged = tag[3] var tagged = tag[3]
tag = tag[0] tag = tag[0]
return make(tag, { var text = dict ?
tag.split(tagset.PATH_SEPARATOR)
.map(function(s){
return s.split(tagset.SET_SEPARATOR)
.map(function(t){
return (dict[t] || [t])[0] })
.join(':') })
.join('/')
: tag
return make(text, {
cls: tagged ? 'tagged' : '', cls: tagged ? 'tagged' : '',
style: { style: {
opacity: tagged ? '' : '0.3' opacity: tagged ? '' : '0.3'

View File

@ -80,6 +80,9 @@ var normalizeSplit = function(args){
var BaseTagsClassPrototype = { var BaseTagsClassPrototype = {
// NOTE: do not include 'g' flag here, it will make the RE objects
// stateful which will yield very unpredictable results from
// general system.
PATH_SEPARATOR: /[\\\/]+/, PATH_SEPARATOR: /[\\\/]+/,
SET_SEPARATOR: /:+/, SET_SEPARATOR: /:+/,
COMBINED_SEPARATOR: /[:\\\/]+/, COMBINED_SEPARATOR: /[:\\\/]+/,
@ -99,17 +102,19 @@ var BaseTagsClassPrototype = {
// .normalize([tag, ...]) // .normalize([tag, ...])
// -> [ntag, ...] // -> [ntag, ...]
// //
// NOTE: tag set order is not significant. //
// NOTE: path sections take priority over set sections, i.e. a set is
// always contained within a path:
// a:b/c -> a:b / c
// NOTE: tag set order is not significant, thus tag sets are further
// normalized by sorting the elements in alphabetical order.
// NOTE: for mixed tags sets are sorted in-place within paths, // NOTE: for mixed tags sets are sorted in-place within paths,
// e.g. // e.g.
// c:b/a -> b:c/a // c:b/a -> b:c/a
// NOTE: no way of grouping or prioritizing is currently supported
// by design, this is done so as to simplify the system as much
// as possible.
// //
// XXX not sure if we should do:
// c:b/a -> b:c/a - sort sets within pats (current)
// or
// c:b/a -> b/a:c - sort paths within sets
// XXX should we support priority braces, i.e. c:(b/a)
// XXX do we support leading '/' ???
normalize: function(...tags){ normalize: function(...tags){
var that = this var that = this
var tagRemovedChars = (this.config || {})['tagRemovedChars'] var tagRemovedChars = (this.config || {})['tagRemovedChars']
@ -145,6 +150,11 @@ var BaseTagsClassPrototype = {
res.pop() res.pop()
: res : res
}, },
// Split the tag into individual singular tags...
//
// Example:
// 'a:b/c' -> ['a', 'b', 'c']
//
subTags: function(...tags){ subTags: function(...tags){
var that = this var that = this
return this.normalize(normalizeSplit(tags)) return this.normalize(normalizeSplit(tags))
@ -256,9 +266,11 @@ var BaseTagsClassPrototype = {
// ... // ...
var BaseTagsPrototype = { var BaseTagsPrototype = {
config: { config: {
// XXX docs!
tagRemovedChars: '[\\s-_]', tagRemovedChars: '[\\s-_]',
}, },
// NOTE: for notes on structure see notes on the Utils section below...
PATH_SEPARATOR: BaseTagsClassPrototype.PATH_SEPARATOR, PATH_SEPARATOR: BaseTagsClassPrototype.PATH_SEPARATOR,
SET_SEPARATOR: BaseTagsClassPrototype.SET_SEPARATOR, SET_SEPARATOR: BaseTagsClassPrototype.SET_SEPARATOR,
COMBINED_SEPARATOR: BaseTagsClassPrototype.COMBINED_SEPARATOR, COMBINED_SEPARATOR: BaseTagsClassPrototype.COMBINED_SEPARATOR,
@ -274,7 +286,6 @@ var BaseTagsPrototype = {
// //
__index: null, __index: null,
// Persistent tags... // Persistent tags...
// //
// Format: // Format:
@ -306,11 +317,7 @@ var BaseTagsPrototype = {
// All persistent tags... // All persistent tags...
// //
// This will include: // This will combine .persistent and .definitionPaths()
// .persistent
// .definitionPaths()
//
// XXX do we need this???
get persistentAll(){ get persistentAll(){
return (this.__persistent || new Set()) return (this.__persistent || new Set())
.unite(this.definitionPaths()) }, .unite(this.definitionPaths()) },
@ -709,8 +716,7 @@ var BaseTagsPrototype = {
// Direct tag/value check... // Direct tag/value check...
// //
// NOTE: these are not using for loops so as to enable "fast abort", // NOTE: these are not using for loops so as to enable "fast abort",
// not sure who much performance this actually gains though. // not sure how much performance this actually gains though.
// XXX should these take multiple values???
hasTag: function(tag){ hasTag: function(tag){
for(var t of this.tags()){ for(var t of this.tags()){
if(this.match(tag, t)){ if(this.match(tag, t)){
@ -738,13 +744,16 @@ var BaseTagsPrototype = {
// .tags(value, [tag, ..]) // .tags(value, [tag, ..])
// -> bool // -> bool
// //
// NOTE: this will return the list of actual tags used and will not
// generate any new values (like .singleTags(..) and friends do).
// NOTE: this includes all the persistent tags as well as all the
// tags actually used.
// //
// XXX should we rename this to .usedTags(..) and .singleTags(..) to // This will return/search:
// .tags(..) ??? // - actual used tags (in .__index)
// - persistent tags (in .persistent)
//
//
// NOTE: persistent tags are added to the results in two cases: when
// they are explicitly used to tag a value or when we are getting
// all the tags (via .tag() without arguments).
//
tags: function(value, ...tags){ tags: function(value, ...tags){
var that = this var that = this
@ -781,11 +790,13 @@ var BaseTagsPrototype = {
singleTags: function(value, ...tags){ singleTags: function(value, ...tags){
return this.subTags(this.tags(...arguments)).unique() }, return this.subTags(this.tags(...arguments)).unique() },
paths: function(value){ paths: function(value){
var sp = that.PATH_SEPARATOR
return this.tags(value) return this.tags(value)
.filter(function(tag){ return /[\\\/]/.test(tag) }) }, .filter(function(tag){ return sp.test(tag) }) },
sets: function(value){ sets: function(value){
var sp = this.SET_SEPARATOR
return this.tags(value) return this.tags(value)
.filter(function(tag){ return tag.includes(':') }) }, .filter(function(tag){ return sp.test(tag) }) },
// //
// Get all values... // Get all values...
// .values() // .values()
@ -1669,8 +1680,63 @@ object.makeConstructor('BaseTags',
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// XXX EXPERIMENTAL... // XXX EXPERIMENTAL...
// try using this to implement local tags in collections by defining // ...this is a bit too generic, we need to save dict values only
// a '/local/*' handler... // when tagging or adding tags...
var TagsWithDictPrototype = {
__proto__: BaseTags,
// Tag dictionary...
//
// Format:
// {
// <tag>: [<value>, ..],
// ...
// }
//
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)
var sp = this.COMBINED_SEPARATOR
tags = normalizeSplit(tags)
.map(function(tag){
return tag.split(sp) })
.flat()
;(res instanceof Array ? res : [res])
.map(function(tag){
return tag.split(sp) })
.flat()
.forEach(function(tag, i){
tag = tag.trim()
var value = tags[i].trim()
// only add tags if they are not the same as normalized...
tag != value
&& (dict[tag] = [value]
.concat(dict[tag] || [])
.unique()) })
return res
},
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var TagsWithDict =
module.TagsWithDict =
object.makeConstructor('TagsWithDict',
BaseTagsClassPrototype,
TagsWithDictPrototype)
//---------------------------------------------------------------------
// XXX EXPERIMENTAL...
var TagsWithHandlersPrototype = { var TagsWithHandlersPrototype = {
__proto__: BaseTagsPrototype, __proto__: BaseTagsPrototype,
@ -1809,8 +1875,23 @@ object.makeConstructor('TagsWithHandlers',
var Tags = var Tags =
module.Tags = module.Tags =
TagsWithHandlers //TagsWithHandlers
//BaseTags //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},
TagsWithDictPrototype,
TagsWithHandlersPrototype))