ES6: Port Tagger to ES6
Change-Id: I67d35ec3cf24f62d3c23a0384488a1a59fe888bb
diff --git a/Changes b/Changes
index cf7dd84..70299f7 100644
--- a/Changes
+++ b/Changes
@@ -1,4 +1,5 @@
- - Migration of pageInfo to ES6 (hebasta)
+ - Migration pageInfo to ES6 (hebasta)
+ - Migration tagger to ES6 (hebasta)
0.66 2026-09-02
- Fix link to NEGRA corpus (diewald)
diff --git a/dev/js/src-lib/palette.js b/dev/js/src-lib/palette.js
new file mode 100644
index 0000000..140a5a8
--- /dev/null
+++ b/dev/js/src-lib/palette.js
@@ -0,0 +1,80 @@
+import KorAP from './util/util.js';
+ /*
+ * Created with http://tools.medialab.sciences-po.fr/iwanthue/
+ * and H: 0-360, C: 0.4-2.1, L: 0.7-1.5, 64 colors
+ */
+ const palette = [
+ '9C8AC7',
+ '6DED31',
+ 'DF7F23',
+ '5AECD1',
+ 'F54597',
+ 'D4D275',
+ 'E6A8A1',
+ '67E682',
+ '719A93',
+ 'E67AE6',
+ 'E8F03F',
+ 'F45042',
+ '6D9C25',
+ 'D0C3D9',
+ 'E37076',
+ '509A58',
+ 'BE9962',
+ 'D88AB6',
+ '71ABCE',
+ '62DCEB',
+ 'D4B73C',
+ 'A0E5B0',
+ '5BBB26',
+ 'A7E230',
+ '7E8EEA',
+ 'D1856B',
+ '59E9A9',
+ 'F24A61',
+ 'A6D455',
+ 'AEE38B',
+ '4DA385',
+ '999C46',
+ 'AFDDDE',
+ 'BA85E0',
+ 'B68C31',
+ '8AA46C',
+ 'D9874C',
+ 'A18EA8',
+ 'E56BAC',
+ 'ECA72F',
+ '3AE152',
+ '5B9EDF',
+ 'E9672F',
+ '43B046',
+ 'E96D59',
+ 'D6B3E6',
+ 'E6BB6A',
+ '92C5A9',
+ 'BE7C85',
+ '9C9B1E',
+ 'CCD896',
+ '84E861',
+ 'DA7093',
+ 'DDEA6F',
+ 'BCC92E',
+ '59C9BD',
+ '52A8B0',
+ '51BC7C',
+ '7EB051',
+ 'F0D036',
+ 'D970C5',
+ 'E95F7D',
+ 'EF9798',
+ 'ED5490'
+ ];
+
+ KorAP.Palette = {
+ getC : function (index) {
+ return '#' + palette[index % 64];
+ }
+ };
+
+
+export default KorAP.Palette;
diff --git a/dev/js/src-lib/tagger/demo/index.html b/dev/js/src-lib/tagger/demo/index.html
new file mode 100644
index 0000000..544ceb6
--- /dev/null
+++ b/dev/js/src-lib/tagger/demo/index.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Tagger demo</title>
+ <meta charset="utf-8" />
+ <link type="text/css" rel="stylesheet" href="/css/kalamar-latest.css" />
+ <style type="text/css" rel="stylesheet">
+.info {
+ background-color: #ddd;
+ color: black;
+ padding: 1em;
+ font-family: mono;
+}
+body {
+ margin: 0;
+ background-color: #ddd;
+}
+span.close::after {
+ content: 'x'
+}
+
+ </style>
+ </head>
+ <body>
+ <main>
+ <h1>Tagger demo</h1>
+ <script type="module" src="./taggerdemo.js"></script>
+ <div class="tagger" id="tagger"></div>
+ </main>
+ </body>
+</html>
+
diff --git a/dev/js/src-lib/tagger/demo/taggerdemo.js b/dev/js/src-lib/tagger/demo/taggerdemo.js
new file mode 100644
index 0000000..d509905
--- /dev/null
+++ b/dev/js/src-lib/tagger/demo/taggerdemo.js
@@ -0,0 +1,4 @@
+import Tagger from '../tagger.js';
+
+const gTagger = new Tagger(document.getElementById('tagger'));
+
diff --git a/dev/js/src-lib/tagger/package.json b/dev/js/src-lib/tagger/package.json
new file mode 100644
index 0000000..4eb4bdc
--- /dev/null
+++ b/dev/js/src-lib/tagger/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "Kalamar-tagger",
+ "version": "0.0.1",
+ "description": "Tagger for Kalmar",
+ "main": "tagger.js",
+ "scripts": {
+ "dev": "vite --open /demo/index.html"
+ },
+ "author": "",
+ "license": "ISC"
+}
diff --git a/dev/js/src-lib/tagger/tagger.js b/dev/js/src-lib/tagger/tagger.js
new file mode 100644
index 0000000..6f34bdc
--- /dev/null
+++ b/dev/js/src-lib/tagger/tagger.js
@@ -0,0 +1,38 @@
+import p from '../palette.js';
+import '../util/util.js';
+
+class Tagger {
+
+ constructor(elem) {
+ this._nr = 0;
+ this._elem = elem;
+ elem.addE('div');
+
+ const newCat = elem.addE('input');
+ newCat.setAttribute('type', 'text');
+ newCat.addEventListener('keypress', function (e) {
+ const key = e.key || e.keyCode || e.which;
+ if (key === 'Enter' || key === 13) {
+ this.addTag(newCat.value);
+ newCat.value = '';
+ };
+ }.bind(this));
+
+ this._cat = [];
+ }
+
+
+
+ addTag(name) {
+ this._cat.push(name);
+ this._nr++;
+
+ const cat = document.createElement('span');
+ cat.addT(name);
+ cat.addE('span').setAttribute('class','close');
+ cat.style.backgroundColor = p.getC(this._nr);
+ this._elem.firstChild.appendChild(cat);
+ }
+ }
+
+export default Tagger;
diff --git a/dev/js/src-lib/tagger/test/taggerSpec.js b/dev/js/src-lib/tagger/test/taggerSpec.js
new file mode 100644
index 0000000..bf025e0
--- /dev/null
+++ b/dev/js/src-lib/tagger/test/taggerSpec.js
@@ -0,0 +1,144 @@
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
+import Tagger from '../tagger.js';
+import '../../palette.js';
+
+describe('Tagger', () => {
+ let container;
+ let tagger;
+
+ beforeEach(() => {
+ // Create a container element for the tagger
+ container = document.createElement('div');
+ document.body.appendChild(container);
+
+ // Initialize the tagger
+ tagger = new Tagger(container);
+ });
+
+ afterEach(() => {
+ // Clean up
+ document.body.removeChild(container);
+ });
+
+ it('should initialize with correct default values', () => {
+ expect(tagger._nr).toBe(0);
+ expect(tagger._elem).toBe(container);
+ expect(Array.isArray(tagger._cat)).toBe(true);
+ expect(tagger._cat.length).toBe(0);
+ });
+
+ it('should create a div element on initialization', () => {
+ expect(container.children.length).toBeGreaterThan(0);
+ expect(container.firstChild.tagName).toBe('DIV');
+ });
+
+ it('should create an input element on initialization', () => {
+ const input = container.querySelector('input');
+ expect(input).not.toBeNull();
+ expect(input.getAttribute('type')).toBe('text');
+ });
+
+ it('should add a tag with addTag method', () => {
+ const tagName = 'TestTag';
+ tagger.addTag(tagName);
+
+ expect(tagger._cat[0]).toBe(tagName);
+ expect(tagger._nr).toBe(1);
+ });
+
+ it('should increment counter for each tag added', () => {
+ tagger.addTag('Tag1');
+ tagger.addTag('Tag2');
+ tagger.addTag('Tag3');
+
+ expect(tagger._nr).toBe(3);
+ expect(tagger._cat.length).toBe(3);
+ });
+
+ it('should create span elements for added tags', () => {
+ tagger.addTag('TestTag');
+
+ const tagElement = container.firstChild.querySelector('span');
+ expect(tagElement).not.toBeNull();
+ expect(tagElement.textContent).toContain('TestTag');
+ });
+
+ it('should add a close button to each tag', () => {
+ tagger.addTag('TestTag');
+
+ const tagElement = container.firstChild.querySelector('span');
+ const closeButton = tagElement.querySelector('span.close');
+ expect(closeButton).not.toBeNull();
+ });
+
+ it('should assign colors to tags based on palette', () => {
+ tagger.addTag('ColoredTag');
+
+ const tagElement = container.firstChild.querySelector('span');
+ const backgroundColor = tagElement.style.backgroundColor;
+
+ expect(backgroundColor).toBeTruthy();
+ });
+
+ it('should trigger addTag on Enter key press', () => {
+ const input = container.querySelector('input');
+ const tagName = 'KeyPressTag';
+ input.value = tagName;
+
+ const event = new KeyboardEvent('keypress', {
+ keyCode: 13,
+ key: 'Enter',
+ bubbles: true
+ });
+
+ input.dispatchEvent(event);
+
+ expect(tagger._cat[0]).toBe(tagName);
+ expect(input.value).toBe('');
+ expect(tagger._nr).toBe(1);
+ });
+
+ it('should not trigger addTag on non-Enter keys', () => {
+ const input = container.querySelector('input');
+ input.value = 'ShouldNotBeAdded';
+
+ const event = new KeyboardEvent('keypress', {
+ keyCode: 65,
+ key: 'a',
+ bubbles: true
+ });
+
+ input.dispatchEvent(event);
+
+ expect(tagger._cat.length).toBe(0);
+ expect(tagger._nr).toBe(0);
+ expect(input.value).toBe('ShouldNotBeAdded');
+ });
+
+ it('should handle multiple tags with different names', () => {
+ tagger.addTag('JavaScript');
+ tagger.addTag('Testing');
+ tagger.addTag('Vitest');
+
+ expect(tagger._nr).toBe(3);
+ expect(tagger._cat.length).toBe(3);
+ expect(tagger._cat[0]).toBe('JavaScript');
+ expect(tagger._cat[1]).toBe('Testing');
+ expect(tagger._cat[2]).toBe('Vitest');
+ });
+
+ it('should allow empty tag names', () => {
+ tagger.addTag('');
+
+ expect(tagger._cat[0]).toBe('');
+ expect(tagger._nr).toBe(1);
+ });
+
+ it('should handle special characters in tag names', () => {
+ const specialTag = '<script>alert("test")</script>';
+ tagger.addTag(specialTag);
+
+ expect(tagger._cat[0]).toBe(specialTag);
+ expect(tagger._nr).toBe(1);
+ });
+});
diff --git a/dev/js/src-lib/tagger/vite.config.js b/dev/js/src-lib/tagger/vite.config.js
new file mode 100644
index 0000000..1edc2f0
--- /dev/null
+++ b/dev/js/src-lib/tagger/vite.config.js
@@ -0,0 +1,29 @@
+import { defineConfig } from 'vite';
+import path from 'path';
+
+const scssDir = path.resolve(__dirname, '../../../scss'); // Path to your SCSS directory
+const fontDir = path.resolve(__dirname, '../../../font');
+
+export default defineConfig({
+
+ server: {
+ fs: {
+ allow: [
+ scssDir,
+ fontDir,
+ __dirname
+ ]
+ },
+ port: 3000
+ },
+
+
+ css: {
+ preprocessorOptions: {
+ scss: {
+ loadPaths: [scssDir]
+ }
+ }
+ }
+});
+