From 7e77f800fd2443206f174005dd41574fe9b0deab Mon Sep 17 00:00:00 2001 From: Frodo161 Date: Sun, 1 Oct 2023 21:20:01 +0200 Subject: [PATCH] Add (sub)category class (+ superclass) to remove hardcoded categories in the (non-view) JavaScript. --- app/assets/javascripts/application.js | 3 ++ .../thyme/annotations/annotation.js | 51 +++---------------- .../javascripts/thyme/annotations/category.js | 24 +++++++++ .../thyme/annotations/category_enum.js | 40 +++++++++++++++ .../thyme/annotations/subcategory.js | 22 ++++++++ .../components/annotation_category_toggle.js | 5 +- app/assets/javascripts/thyme/heatmap.js | 13 ++--- .../javascripts/thyme/thyme_feedback.js | 39 +++++++------- 8 files changed, 124 insertions(+), 73 deletions(-) create mode 100644 app/assets/javascripts/thyme/annotations/category.js create mode 100644 app/assets/javascripts/thyme/annotations/category_enum.js create mode 100644 app/assets/javascripts/thyme/annotations/subcategory.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 0a2bfb4c1..ba1e71e7c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -80,6 +80,9 @@ //= require thyme/components/seek_bar //= require thyme/components/speed_selector //= require thyme/components/volume_bar +//= require thyme/annotations/category_enum +//= require thyme/annotations/category +//= require thyme/annotations/subcategory //= require thyme/annotations/annotation //= require thyme/annotations/annotation_area //= require thyme/annotations/annotation_manager diff --git a/app/assets/javascripts/thyme/annotations/annotation.js b/app/assets/javascripts/thyme/annotations/annotation.js index 2e050705a..3db6a8dae 100644 --- a/app/assets/javascripts/thyme/annotations/annotation.js +++ b/app/assets/javascripts/thyme/annotations/annotation.js @@ -5,19 +5,19 @@ class Annotation { constructor(json) { // We only save attributes that are needed in the thyme related JavaScripts in the asset pipeline! - this.category = json.category; + this.category = Category.getByName(json.category); this.color = json.color; this.comment = json.comment; this.id = json.id; this.seconds = thymeUtility.timestampToSeconds(json.timestamp); - this.subcategory = json.subcategory; + this.subcategory = Subcategory.getByName(json.subcategory); this.belongsToCurrentUser = json.belongs_to_current_user; } /* - * AUXILIARY METHODS + * AUXILIARY METHODS */ /* @@ -80,48 +80,9 @@ class Annotation { Returns a string with the correct translation of the category and subcategory of this annotation. */ categoryLocale() { - let c, s; - switch (this.category) { - case "note": - c = document.getElementById('annotation-locales').dataset.note; - break; - case "content": - c = document.getElementById('annotation-locales').dataset.content; - break; - case "mistake": - c = document.getElementById('annotation-locales').dataset.mistake; - break; - case "presentation": - c = document.getElementById('annotation-locales').dataset.presentation; - } - if (this.subcategory === null) { - return c; - } - switch (this.subcategory) { - case "definition": - s = document.getElementById('annotation-locales').dataset.definition; - break; - case "argument": - s = document.getElementById('annotation-locales').dataset.argument; - break; - case "strategy": - s = document.getElementById('annotation-locales').dataset.strategy; - } - return c + " (" + s + ")"; - } - - /* Returns a fixed color depending only on the category of the annotation. */ - categoryColor() { - switch (this.category) { - case "note": - return "#44ee11"; //green - case "content": - return "#eeee00"; //yellow - case "mistake": - return "#ff0000"; //red - case "presentation": - return "#ff9933"; //orange - } + const c = this.category; + const s = this.subcategory; + return s == null ? c.locale() : c.locale() + " (" + s.locale() + ")"; } /* diff --git a/app/assets/javascripts/thyme/annotations/category.js b/app/assets/javascripts/thyme/annotations/category.js new file mode 100644 index 000000000..b3172c52d --- /dev/null +++ b/app/assets/javascripts/thyme/annotations/category.js @@ -0,0 +1,24 @@ +class Category extends CategoryEnum { + + static _categories = []; + + static NOTE = new Category('note', '#44ee11'); //green + static CONTENT = new Category('content', '#eeee00'); //yellow + static PRESENTATION = new Category('presentation', '#ff9933'); //orange + static MISTAKE = new Category('mistake', '#ff0000'); //red + + constructor(name, color) { + super(name); + this.color = color; + Category._categories.push(this); + } + + static getByName(name) { + return super.getByName(name, Category._categories); + } + + static all() { + return super.all(Category._categories); + } + +} \ No newline at end of file diff --git a/app/assets/javascripts/thyme/annotations/category_enum.js b/app/assets/javascripts/thyme/annotations/category_enum.js new file mode 100644 index 000000000..1149e647c --- /dev/null +++ b/app/assets/javascripts/thyme/annotations/category_enum.js @@ -0,0 +1,40 @@ +class CategoryEnum { + + constructor(name) { + this.name = name; + } + + /* + * Returns the correct locale for the given category. + * This method will only work if the given thyme player + * has a div-tag with the id "annotation-locales" which + * includes the name of the categories as data sets, e.g. + * data-note="<%= t(...) %>". + */ + locale() { + return document.getElementById('annotation-locales').dataset[this.name]; + } + + /* + * Return the object with the given name in the given array. + * + * Override in subclasses. + */ + static getByName(name, array) { + for (let a of array) { + if (a.name === name) { + return a; + } + } + } + + /* + * Returns an array with all objects of this enum. + * + * Override in subclasses. + */ + static all(array) { + return array.slice(); + } + +} \ No newline at end of file diff --git a/app/assets/javascripts/thyme/annotations/subcategory.js b/app/assets/javascripts/thyme/annotations/subcategory.js new file mode 100644 index 000000000..6795630e8 --- /dev/null +++ b/app/assets/javascripts/thyme/annotations/subcategory.js @@ -0,0 +1,22 @@ +class Subcategory extends CategoryEnum { + + static _subcategories = []; // do not manipulate this array outside of this class! + + static DEFINITION = new Subcategory('definition'); + static ARGUMENT = new Subcategory('argument'); + static STRATEGY = new Subcategory('strategy'); + + constructor(name) { + super(name); + Subcategory._subcategories.push(this); + } + + static getByName(name) { + return super.getByName(name, Subcategory._subcategories); + } + + static all() { + return super.all(Subcategory._subcategories); + } + +} \ No newline at end of file diff --git a/app/assets/javascripts/thyme/components/annotation_category_toggle.js b/app/assets/javascripts/thyme/components/annotation_category_toggle.js index 028968425..d676d84e1 100644 --- a/app/assets/javascripts/thyme/components/annotation_category_toggle.js +++ b/app/assets/javascripts/thyme/components/annotation_category_toggle.js @@ -2,7 +2,7 @@ class AnnotationCategoryToggle extends Component { /* element = A reference on the HTML component (via document.getElementByID()). - category = The name of the category this toggle triggers. + category = The category which this toggle triggers. heatmap = The heatmap that will be updated depending on the value of the toggle. */ constructor(element, category, heatmap) { @@ -16,6 +16,9 @@ class AnnotationCategoryToggle extends Component { const category = this.category; const check = document.getElementById(this.element.id + '-check'); const heatmap = this.heatmap; + if (heatmap != null) { + heatmap.addCategory(category); // add category when adding the button + } check.addEventListener('click', function() { thymeAttributes.annotationManager.updateAnnotations(); diff --git a/app/assets/javascripts/thyme/heatmap.js b/app/assets/javascripts/thyme/heatmap.js index b7807e50e..85b6de606 100644 --- a/app/assets/javascripts/thyme/heatmap.js +++ b/app/assets/javascripts/thyme/heatmap.js @@ -8,14 +8,11 @@ class Heatmap { static MAX_HEIGHT = 0.25 // this number adjusts the maximum heights of the heatmap peaks /* - id = The ID of the HTML element to which the heatmap will be appended. - - categories = An array which contains all the categories (i.e. the string representing - the categories) that should be displayed in the heatmap. - */ - constructor(id, categories) { + * id = The ID of the HTML element to which the heatmap will be appended. + */ + constructor(id) { this.heatmap = $('#' + id); - this.categories = categories; + this.categories = []; } @@ -52,7 +49,7 @@ class Heatmap { for (const a of thymeAttributes.annotations) { const valid = this.#validCategory(a.category); if (valid === true) { - colors.push(a.categoryColor()); + colors.push(a.category.color); } const time = a.seconds; const position = Math.round(width * (time / video.duration)); diff --git a/app/assets/javascripts/thyme/thyme_feedback.js b/app/assets/javascripts/thyme/thyme_feedback.js index 4466d0a61..101fd5ef5 100644 --- a/app/assets/javascripts/thyme/thyme_feedback.js +++ b/app/assets/javascripts/thyme/thyme_feedback.js @@ -34,23 +34,24 @@ $(document).on('turbolinks:load', function() { seekBar.add(); // heatmap - const heatmap = new Heatmap('heatmap', ['presentation', 'content', 'note']); + const heatmap = new Heatmap('heatmap'); // below-area - const toggleMistakeAnnotations = new AnnotationCategoryToggle( - 'toggle-mistake-annotations', 'mistake', null); // <- don't draw mistake annotations in the heatmap - const togglePresentationAnnotations = new AnnotationCategoryToggle( - 'toggle-presentation-annotations', 'presentation', heatmap); - const toggleContentAnnotations = new AnnotationCategoryToggle( - 'toggle-content-annotations', 'content', heatmap); - const toggleNoteAnnotations = new AnnotationCategoryToggle( - 'toggle-note-annotations', 'note', heatmap); - toggleMistakeAnnotations.add(); - togglePresentationAnnotations.add(); - toggleContentAnnotations.add(); - toggleNoteAnnotations.add(); - const toggles = [toggleMistakeAnnotations, togglePresentationAnnotations, - toggleContentAnnotations, toggleNoteAnnotations]; + const allCategories = Category.all(); + const annotationCategoryToggles = new Array(allCategories.length); + let category; + + for (let i = 0; i < allCategories.length; i++) { + category = allCategories[i]; + annotationCategoryToggles[i] = new AnnotationCategoryToggle( + 'toggle-' + category.name + '-annotations', category, heatmap + ); + if (category === Category.MISTAKE) { + // exclude mistake annotations from heatmap + annotationCategoryToggles[i].heatmap = null; + } + annotationCategoryToggles[i].add(); + } @@ -58,10 +59,10 @@ $(document).on('turbolinks:load', function() { ANNOTATION FUNCTIONALITY */ function colorFunc(annotation) { - return annotation.categoryColor(); + return annotation.category.color; } function isValid(annotation) { - for (let toggle of toggles) { + for (let toggle of annotationCategoryToggles) { if (annotation.category === toggle.category && toggle.getValue() === true) { return true; } @@ -71,10 +72,10 @@ $(document).on('turbolinks:load', function() { const annotationArea = new AnnotationArea(false, colorFunc, isValid); thymeAttributes.annotationArea = annotationArea; function strokeColorFunc(annotation) { - return annotation.category === 'mistake' ? 'darkred' : 'black'; + return annotation.category === Category.MISTAKE ? 'darkred' : 'black'; } function sizeFunc(annotation) { - return annotation.category === 'mistake' ? true : false; + return annotation.category === Category.MISTAKE ? true : false; } function onClick(annotation) { annotationArea.update(annotation);