From adce8d067c46bd1dd15da116fb64fe62dd745179 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Wed, 8 Jun 2022 18:51:22 +0200 Subject: [PATCH] Counts for tags in index --- app/svganim/strokes.py | 18 +++++++++++---- app/templates/index.html | 47 +++++++++++++++++++++++----------------- app/webserver.py | 7 +++--- app/www/annotations.js | 10 +++++---- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/app/svganim/strokes.py b/app/svganim/strokes.py index 50796bf..e624853 100644 --- a/app/svganim/strokes.py +++ b/app/svganim/strokes.py @@ -14,7 +14,7 @@ import tempfile import io import logging from anytree import NodeMixin, RenderTree, iterators -from anytree.exporter import JsonExporter +from anytree.exporter import JsonExporter, DictExporter from anytree.importer import JsonImporter, DictImporter logger = logging.getLogger('svganim.strokes') @@ -538,10 +538,15 @@ class AnnotationIndex: self.shelve['_annotations'][annotation.id] = annotation if annotation.tag not in self.shelve['_tags']: self.shelve['_tags'][annotation.tag] = [annotation] + logger.error(f"Use of non-existing tag {annotation.tag}") else: self.shelve['_tags'][annotation.tag].append( annotation ) + tag = self.root_tag.find_by_id(annotation.tag) + if tag is not None: + tag.annotation_count += 1 + @property def drawings(self) -> dict[str, Drawing]: @@ -715,7 +720,7 @@ def strokes2D(strokes): return d class Tag(NodeMixin): - def __init__(self, id, name = None, description = "", color = None, parent=None, children=None): + def __init__(self, id, name = None, description = "", color = None, parent=None, children=None, annotation_count=None): self.id = id self.name = self.id if name is None else name self.color = color @@ -724,6 +729,8 @@ class Tag(NodeMixin): if children: self.children = children + self.annotation_count = 0 #always zero! + if self.id == 'root' and not self.is_root: logger.error("Root node shouldn't have a parent assigned") @@ -747,8 +754,11 @@ class Tag(NodeMixin): return t return None - def toJson(self) -> str: - return JsonExporter(indent=2).export(self) + def toJson(self, with_counts=False) -> str: + ignore_counts=lambda attrs: [(k, v) for k, v in attrs if k != "annotation_count"] + attrFilter = None if with_counts else ignore_counts + + return JsonExporter(DictExporter(attriter=attrFilter), indent=2).export(self) def loadTagFromJson(string) -> Tag: tree: Tag = JsonImporter(DictImporter(Tag)).import_(string) diff --git a/app/templates/index.html b/app/templates/index.html index 429bf93..af69133 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -44,17 +44,23 @@ visibility: visible; ; } */ - #tags li.selected > ul>li.add-tag { + #tags li.selected>ul>li.add-tag { display: block; } - #tags > li > ul >li.add-tag { + #tags>li>ul>li.add-tag { display: block; ; } - - + #annotations .annotations-actions { + margin-bottom: 10px; + color: darkgray; + font-size: 80%; + border-bottom: solid 3px #444; + } + + #tags .add-tag { display: none; @@ -73,33 +79,37 @@ vertical-align: middle; margin-right: 10px; } - #tags li:hover > div > input.rm-tag{ + + #tags li:hover>div>input.rm-tag { display: inline-block; } - #tags li div{ - position:relative + + #tags li div { + position: relative } - #tags input.rm-tag:hover{ + + #tags input.rm-tag:hover { color: red; transform: rotate(20deg); } - #tags input.rm-tag{ + + #tags input.rm-tag { /* display: none; */ - position:absolute; - right:0; - top:0; - padding:0; + position: absolute; + right: 0; + top: 0; + padding: 0; background: none; border: none; color: white; - cursor:pointer; + cursor: pointer; } #tags .selected>div { background: lightblue } - + summary h2 { display: inline-block; cursor: pointer; @@ -117,7 +127,7 @@ display: block;; } */ - + #annotation_manager { display: grid; @@ -143,9 +153,7 @@ } - #annotations li { - - } + #annotations li {} #annotations img { /* width: 400px; */ @@ -179,7 +187,6 @@ #annotations .svganim_player:hover .controls { visibility: visible !important; } - diff --git a/app/webserver.py b/app/webserver.py index 243e0d4..99ca601 100644 --- a/app/webserver.py +++ b/app/webserver.py @@ -558,9 +558,10 @@ class TagsHandler(tornado.web.RequestHandler): def get(self): self.set_header("Content-Type", "application/json") - with open('www/tags.json', 'r') as fp: - # TODO: enrich with counts - self.write(fp.read()) + self.write(self.index.root_tag.toJson(with_counts=True)) + # with open('www/tags.json', 'r') as fp: + # # TODO: enrich with counts + # self.write(fp.read()) def put(self): # data = json.loads(self.request.body) diff --git a/app/www/annotations.js b/app/www/annotations.js index a3f1e7a..0ab6c04 100644 --- a/app/www/annotations.js +++ b/app/www/annotations.js @@ -8,12 +8,13 @@ class AnnotationManager { this.selectedAnnotations = []; this.selectedTag = null; - this.loadTags(tagsUrl); + this.tagsUrl = tagsUrl; + this.loadTags(); } - loadTags(tagFile) { + loadTags() { // tags config - const request = new Request(tagFile); + const request = new Request(this.tagsUrl); return fetch(request) .then(response => response.json()) .then(rootTag => { @@ -31,7 +32,7 @@ class AnnotationManager { const tagSubEl = document.createElement('ul'); const tagEl = document.createElement('div'); - tagEl.innerText = tag.get_name(); + tagEl.innerText = `${tag.get_name()} (${tag.annotation_count ?? 0})`; tagEl.addEventListener('click', (ev) => { this.selectTag(tag); }) @@ -318,6 +319,7 @@ class AnnotationManager { })); this.loadAnnotationsForTag(this.selectedTag) + this.loadTags() //updates the counts } async saveTags() {