Rewrite it in TypeScript; I have no idea if that works. It's still a work-in-progress.
This commit is contained in:
parent
079bda7fb0
commit
5420f9c817
14 changed files with 3420 additions and 47 deletions
|
@ -11,5 +11,6 @@ insert_final_newline = true
|
||||||
|
|
||||||
[*.yml]
|
[*.yml]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
2239
package-lock.json
generated
2239
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,9 @@
|
||||||
"jquery.cookie": "1.4.1"
|
"jquery.cookie": "1.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jquery": "3.3.29",
|
||||||
|
"@types/jqueryui": "1.12.7",
|
||||||
|
"chai": "4.2.0",
|
||||||
"grunt": "1.0.4",
|
"grunt": "1.0.4",
|
||||||
"grunt-cli": "1.3.2",
|
"grunt-cli": "1.3.2",
|
||||||
"grunt-contrib-clean": "2.0.0",
|
"grunt-contrib-clean": "2.0.0",
|
||||||
|
@ -42,9 +45,10 @@
|
||||||
"grunt-version": "1.3.0",
|
"grunt-version": "1.3.0",
|
||||||
"jshint-stylish": "2.2.1",
|
"jshint-stylish": "2.2.1",
|
||||||
"load-grunt-tasks": "4.0.0",
|
"load-grunt-tasks": "4.0.0",
|
||||||
|
"mocha": "6.1.4",
|
||||||
"phantomjs-prebuilt": "2.1.16",
|
"phantomjs-prebuilt": "2.1.16",
|
||||||
"time-grunt": "2.0.0",
|
"time-grunt": "2.0.0",
|
||||||
"mocha": "6.1.4",
|
"webpack": "4.30.0",
|
||||||
"chai": "4.2.0"
|
"webpack-cli": "3.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
87
src/domain/globals.ts
Normal file
87
src/domain/globals.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Layout} from "./layout";
|
||||||
|
import {Theme} from "./theme";
|
||||||
|
|
||||||
|
export class Globals {
|
||||||
|
private static layouts: Layout[] = [];
|
||||||
|
private static themes: Theme[] = [];
|
||||||
|
|
||||||
|
static registerTheme(name: string, styleClass: string): void {
|
||||||
|
if (Globals.themes.some(value => value.name === name)) {
|
||||||
|
console.log(`Theme with name '${name}' already registered; ignoring register request for styleClass '${styleClass}'.`)
|
||||||
|
} else {
|
||||||
|
Globals.themes.push({
|
||||||
|
name,
|
||||||
|
styleClass
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static hasThemes(): boolean {
|
||||||
|
return Globals.themes.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static hasMultipleThemes(): boolean {
|
||||||
|
return Globals.themes.length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getFirstTheme(): Theme {
|
||||||
|
return Globals.getTheme(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTheme(index: number): Theme {
|
||||||
|
return Globals.themes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static getThemes(): Theme[] {
|
||||||
|
return Globals.themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static registerLayout(langCode: string, layout: Layout): void {
|
||||||
|
const available = Globals.layouts.some(element => {
|
||||||
|
if (langCode === element.code) {
|
||||||
|
console.error(
|
||||||
|
`Error: Language code '${langCode}' cannot be registered for layout '${layout.prettyName}'
|
||||||
|
because it is already registered for layout '${element.prettyName}'!`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (available) {
|
||||||
|
layout.code = langCode;
|
||||||
|
Globals.layouts.push(layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static hasLayouts(): boolean {
|
||||||
|
return Globals.layouts.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static hasMultipleLayouts(): boolean {
|
||||||
|
return Globals.layouts.length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getFirstLayout(): Layout {
|
||||||
|
return Globals.layouts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static getLayouts(): Layout[] {
|
||||||
|
return Globals.layouts;
|
||||||
|
}
|
||||||
|
}
|
50
src/domain/layout.ts
Normal file
50
src/domain/layout.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Letter} from "./letter";
|
||||||
|
|
||||||
|
export interface Layout {
|
||||||
|
version: number;
|
||||||
|
code: string;
|
||||||
|
prettyName: string;
|
||||||
|
letters: string[];
|
||||||
|
permanent: WordDefinition | WordDefinition[];
|
||||||
|
hours: TimeDefinition;
|
||||||
|
minutes: TimeDefinition;
|
||||||
|
seconds?: TimeDefinition;
|
||||||
|
getHour?: (Date) => number;
|
||||||
|
getDotMinute?: (Date) => number;
|
||||||
|
getCoarseMinute?: (Date) => number;
|
||||||
|
getSeconds?: (Date) => number;
|
||||||
|
parsed?: Letter[][];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WordDefinition {
|
||||||
|
[line: number]: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimeDefinition {
|
||||||
|
[values: string]: WordDefinition | WordDefinition[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EMPTY_LAYOUT: Layout = {
|
||||||
|
version: 2,
|
||||||
|
code: null,
|
||||||
|
prettyName: null,
|
||||||
|
letters: [],
|
||||||
|
permanent: [],
|
||||||
|
minutes: null,
|
||||||
|
hours: null
|
||||||
|
};
|
43
src/domain/letter.ts
Normal file
43
src/domain/letter.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ein Buchstabe. Hilfsklasse für den Renderer und Inhalt der Layout-Arrays.
|
||||||
|
* @param value Der Buchstabe, der Dargestellt werden soll.
|
||||||
|
* @param style Die CSS-Styleklassen des Buchstabens.
|
||||||
|
*/
|
||||||
|
export class Letter {
|
||||||
|
private readonly value: string;
|
||||||
|
private style: string = '';
|
||||||
|
|
||||||
|
constructor(value: string, style?: string) {
|
||||||
|
this.value = value;
|
||||||
|
if (!!style) {
|
||||||
|
this.style = style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addStyle(style: string): void {
|
||||||
|
if (this.style === '') {
|
||||||
|
this.style = style;
|
||||||
|
} else {
|
||||||
|
this.style += ` ${style}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `<span class="item letter ${this.style}">${this.value}</span>`;
|
||||||
|
};
|
||||||
|
}
|
19
src/domain/theme.ts
Normal file
19
src/domain/theme.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Theme {
|
||||||
|
styleClass: string;
|
||||||
|
name: string;
|
||||||
|
}
|
11
src/index.d.ts
vendored
Normal file
11
src/index.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
declare namespace Fritteli {
|
||||||
|
interface Fritteli {
|
||||||
|
uhr: {
|
||||||
|
register: (options?: { checkboxSelector: JQuery | string }) => JQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JQueryStatic {
|
||||||
|
fritteli: Fritteli.Fritteli;
|
||||||
|
}
|
71
src/index.ts
Normal file
71
src/index.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Globals} from "./domain/globals";
|
||||||
|
import {autodetectThemes} from "./theme-autodetector";
|
||||||
|
import {Uehrli} from "./uehrli";
|
||||||
|
import {WidgetPrototype} from "./widget/widget-prototype";
|
||||||
|
|
||||||
|
// First things first: discover included themes and register them
|
||||||
|
autodetectThemes();
|
||||||
|
|
||||||
|
$.widget("fritteli.uhr", {
|
||||||
|
"options": {
|
||||||
|
width: '100%',
|
||||||
|
status: 'on',
|
||||||
|
language: 'de_CH',
|
||||||
|
theme: Globals.getFirstTheme().styleClass,
|
||||||
|
force: false,
|
||||||
|
controls: true,
|
||||||
|
cookiePath: undefined,
|
||||||
|
autoresize: true,
|
||||||
|
mode: 'normal'
|
||||||
|
},
|
||||||
|
"start": function () {
|
||||||
|
this.__fritteli_uhr_instance.start();
|
||||||
|
},
|
||||||
|
"stop": function () {
|
||||||
|
this.__fritteli_uhr_instance.stop();
|
||||||
|
},
|
||||||
|
"toggle": function () {
|
||||||
|
this.__fritteli_uhr_instance.toggle();
|
||||||
|
},
|
||||||
|
"language": function (key: string) {
|
||||||
|
this.__fritteli_uhr_instance.setLanguage(key);
|
||||||
|
},
|
||||||
|
"theme": function (styleClass: string) {
|
||||||
|
this.__fritteli_uhr_instance.setTheme(styleClass);
|
||||||
|
},
|
||||||
|
"time": function (time: Date) {
|
||||||
|
this.__fritteli_uhr_instance.setTime(time);
|
||||||
|
},
|
||||||
|
"mode": function (mode: string) {
|
||||||
|
this.__fritteli_uhr_instance.setMode(mode);
|
||||||
|
},
|
||||||
|
"width": function (width: string) {
|
||||||
|
this.__fritteli_uhr_instance.setWidth(width);
|
||||||
|
},
|
||||||
|
// constructor method
|
||||||
|
"_create": function () {
|
||||||
|
this.__fritteli_uhr_instance = new Uehrli(this);
|
||||||
|
},
|
||||||
|
// destructor method
|
||||||
|
"_destroy": function () {
|
||||||
|
this.__fritteli_uhr_instance.destroy();
|
||||||
|
},
|
||||||
|
"__fritteli_uhr_instance": null
|
||||||
|
} as WidgetPrototype);
|
||||||
|
|
||||||
|
$.fritteli.uhr.register = Globals.registerLayout;
|
322
src/renderer.ts
Normal file
322
src/renderer.ts
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Layout, TimeDefinition, WordDefinition} from "./domain/layout";
|
||||||
|
import {Letter} from "./domain/letter";
|
||||||
|
|
||||||
|
class UhrRendererV2Delegate {
|
||||||
|
private static readonly vorne0: WordDefinition = {
|
||||||
|
3: [2, 3, 4],
|
||||||
|
4: [1, 5],
|
||||||
|
5: [1, 4, 5],
|
||||||
|
6: [1, 3, 5],
|
||||||
|
7: [1, 2, 5],
|
||||||
|
8: [1, 5],
|
||||||
|
9: [2, 3, 4]
|
||||||
|
};
|
||||||
|
private static readonly hinten0: WordDefinition = {
|
||||||
|
3: [8, 9, 10],
|
||||||
|
4: [7, 11],
|
||||||
|
5: [7, 10, 11],
|
||||||
|
6: [7, 9, 11],
|
||||||
|
7: [7, 8, 11],
|
||||||
|
8: [7, 11],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly vorne1: WordDefinition = {
|
||||||
|
3: [3],
|
||||||
|
4: [2, 3],
|
||||||
|
5: [3],
|
||||||
|
6: [3],
|
||||||
|
7: [3],
|
||||||
|
8: [3],
|
||||||
|
9: [2, 3, 4]
|
||||||
|
};
|
||||||
|
private static readonly hinten1: WordDefinition = {
|
||||||
|
3: [9],
|
||||||
|
4: [8, 9],
|
||||||
|
5: [9],
|
||||||
|
6: [9],
|
||||||
|
7: [9],
|
||||||
|
8: [9],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly vorne2: WordDefinition = {
|
||||||
|
3: [2, 3, 4],
|
||||||
|
4: [1, 5],
|
||||||
|
5: [5],
|
||||||
|
6: [4],
|
||||||
|
7: [3],
|
||||||
|
8: [2],
|
||||||
|
9: [1, 2, 3, 4, 5]
|
||||||
|
};
|
||||||
|
private static readonly hinten2: WordDefinition = {
|
||||||
|
3: [8, 9, 10],
|
||||||
|
4: [7, 11],
|
||||||
|
5: [11],
|
||||||
|
6: [10],
|
||||||
|
7: [9],
|
||||||
|
8: [8],
|
||||||
|
9: [7, 8, 9, 10, 11]
|
||||||
|
};
|
||||||
|
private static readonly vorne3: WordDefinition = {
|
||||||
|
3: [1, 2, 3, 4, 5],
|
||||||
|
4: [4],
|
||||||
|
5: [3],
|
||||||
|
6: [4],
|
||||||
|
7: [5],
|
||||||
|
8: [1, 5],
|
||||||
|
9: [2, 3, 4]
|
||||||
|
};
|
||||||
|
private static readonly hinten3: WordDefinition = {
|
||||||
|
3: [7, 8, 9, 10, 11],
|
||||||
|
4: [10],
|
||||||
|
5: [9],
|
||||||
|
6: [10],
|
||||||
|
7: [11],
|
||||||
|
8: [7, 11],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly vorne4: WordDefinition = {
|
||||||
|
3: [4],
|
||||||
|
4: [3, 4],
|
||||||
|
5: [2, 4],
|
||||||
|
6: [1, 4],
|
||||||
|
7: [1, 2, 3, 4, 5],
|
||||||
|
8: [4],
|
||||||
|
9: [4]
|
||||||
|
};
|
||||||
|
private static readonly hinten4: WordDefinition = {
|
||||||
|
3: [10],
|
||||||
|
4: [9, 10],
|
||||||
|
5: [8, 10],
|
||||||
|
6: [7, 10],
|
||||||
|
7: [7, 8, 9, 10, 11],
|
||||||
|
8: [10],
|
||||||
|
9: [10]
|
||||||
|
};
|
||||||
|
private static readonly vorne5: WordDefinition = {
|
||||||
|
3: [1, 2, 3, 4, 5],
|
||||||
|
4: [1],
|
||||||
|
5: [1, 2, 3, 4],
|
||||||
|
6: [5],
|
||||||
|
7: [5],
|
||||||
|
8: [1, 5],
|
||||||
|
9: [2, 3, 4]
|
||||||
|
};
|
||||||
|
private static readonly hinten5: WordDefinition = {
|
||||||
|
3: [7, 8, 9, 10, 11],
|
||||||
|
4: [7],
|
||||||
|
5: [7, 8, 9, 10],
|
||||||
|
6: [11],
|
||||||
|
7: [11],
|
||||||
|
8: [7, 11],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly hinten6: WordDefinition = {
|
||||||
|
3: [9, 10],
|
||||||
|
4: [8],
|
||||||
|
5: [7],
|
||||||
|
6: [7, 8, 9, 10],
|
||||||
|
7: [7, 11],
|
||||||
|
8: [7, 11],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly hinten7: WordDefinition = {
|
||||||
|
3: [7, 8, 9, 10, 11],
|
||||||
|
4: [11],
|
||||||
|
5: [10],
|
||||||
|
6: [9],
|
||||||
|
7: [8],
|
||||||
|
8: [8],
|
||||||
|
9: [8]
|
||||||
|
};
|
||||||
|
private static readonly hinten8: WordDefinition = {
|
||||||
|
3: [8, 9, 10],
|
||||||
|
4: [7, 11],
|
||||||
|
5: [7, 11],
|
||||||
|
6: [8, 9, 10],
|
||||||
|
7: [7, 11],
|
||||||
|
8: [7, 11],
|
||||||
|
9: [8, 9, 10]
|
||||||
|
};
|
||||||
|
private static readonly hinten9: WordDefinition = {
|
||||||
|
3: [8, 9, 10],
|
||||||
|
4: [7, 11],
|
||||||
|
5: [7, 11],
|
||||||
|
6: [8, 9, 10, 11],
|
||||||
|
7: [11],
|
||||||
|
8: [10],
|
||||||
|
9: [8, 9]
|
||||||
|
};
|
||||||
|
private static readonly seconds: TimeDefinition = {
|
||||||
|
"0": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten0],
|
||||||
|
"1": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten1],
|
||||||
|
"2": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten2],
|
||||||
|
"3": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten3],
|
||||||
|
"4": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten4],
|
||||||
|
"5": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten5],
|
||||||
|
"6": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten6],
|
||||||
|
"7": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten7],
|
||||||
|
"8": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten8],
|
||||||
|
"9": [UhrRendererV2Delegate.vorne0, UhrRendererV2Delegate.hinten9],
|
||||||
|
"10": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten0],
|
||||||
|
"11": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten1],
|
||||||
|
"12": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten2],
|
||||||
|
"13": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten3],
|
||||||
|
"14": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten4],
|
||||||
|
"15": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten5],
|
||||||
|
"16": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten6],
|
||||||
|
"17": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten7],
|
||||||
|
"18": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten8],
|
||||||
|
"19": [UhrRendererV2Delegate.vorne1, UhrRendererV2Delegate.hinten9],
|
||||||
|
"20": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten0],
|
||||||
|
"21": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten1],
|
||||||
|
"22": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten2],
|
||||||
|
"23": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten3],
|
||||||
|
"24": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten4],
|
||||||
|
"25": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten5],
|
||||||
|
"26": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten6],
|
||||||
|
"27": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten7],
|
||||||
|
"28": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten8],
|
||||||
|
"29": [UhrRendererV2Delegate.vorne2, UhrRendererV2Delegate.hinten9],
|
||||||
|
"30": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten0],
|
||||||
|
"31": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten1],
|
||||||
|
"32": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten2],
|
||||||
|
"33": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten3],
|
||||||
|
"34": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten4],
|
||||||
|
"35": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten5],
|
||||||
|
"36": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten6],
|
||||||
|
"37": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten7],
|
||||||
|
"38": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten8],
|
||||||
|
"39": [UhrRendererV2Delegate.vorne3, UhrRendererV2Delegate.hinten9],
|
||||||
|
"40": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten0],
|
||||||
|
"41": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten1],
|
||||||
|
"42": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten2],
|
||||||
|
"43": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten3],
|
||||||
|
"44": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten4],
|
||||||
|
"45": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten5],
|
||||||
|
"46": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten6],
|
||||||
|
"47": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten7],
|
||||||
|
"48": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten8],
|
||||||
|
"49": [UhrRendererV2Delegate.vorne4, UhrRendererV2Delegate.hinten9],
|
||||||
|
"50": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten0],
|
||||||
|
"51": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten1],
|
||||||
|
"52": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten2],
|
||||||
|
"53": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten3],
|
||||||
|
"54": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten4],
|
||||||
|
"55": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten5],
|
||||||
|
"56": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten6],
|
||||||
|
"57": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten7],
|
||||||
|
"58": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten8],
|
||||||
|
"59": [UhrRendererV2Delegate.vorne5, UhrRendererV2Delegate.hinten9]
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(private layout: Layout) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(): Letter[][] {
|
||||||
|
const letters: Letter[][] = [];
|
||||||
|
this.layout.letters.forEach(lineString => {
|
||||||
|
const line: Letter[] = [];
|
||||||
|
for (let c = 0; c < lineString.length; c++) {
|
||||||
|
line.push(new Letter(lineString[c]));
|
||||||
|
}
|
||||||
|
letters.push(line);
|
||||||
|
});
|
||||||
|
this.parseArrayOrObject(letters, 'on', this.layout.permanent);
|
||||||
|
if (typeof this.layout.seconds !== 'undefined' && this.layout.seconds !== null) {
|
||||||
|
this.parseTimeDefinition(letters, 'second', this.layout.seconds);
|
||||||
|
} else {
|
||||||
|
this.parseTimeDefinition(letters, 'second', UhrRendererV2Delegate.seconds);
|
||||||
|
}
|
||||||
|
this.parseTimeDefinition(letters, 'minute', this.layout.minutes);
|
||||||
|
this.parseTimeDefinition(letters, 'hour', this.layout.hours);
|
||||||
|
return letters;
|
||||||
|
};
|
||||||
|
|
||||||
|
private parseObject(letters: Letter[][], styleClass: string, object: WordDefinition): void {
|
||||||
|
if (typeof object !== 'undefined' && object !== null) {
|
||||||
|
Object.keys(object)
|
||||||
|
.map(key => Number(key))
|
||||||
|
.forEach(
|
||||||
|
y => object[y].forEach(
|
||||||
|
x => letters[y - 1][x - 1].addStyle(styleClass)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseArrayOrObject(letters: Letter[][], styleClass: string, input: WordDefinition | WordDefinition[]): void {
|
||||||
|
if (typeof input !== 'undefined' && input !== null) {
|
||||||
|
if (Array.isArray(input)) {
|
||||||
|
input.forEach(item => this.parseObject(letters, styleClass, item));
|
||||||
|
} else {
|
||||||
|
this.parseObject(letters, styleClass, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseTimeDefinition(letters: Letter[][], styleClass: string, definition: TimeDefinition): void {
|
||||||
|
if (typeof definition !== 'undefined' && definition !== null) {
|
||||||
|
Object.keys(definition).forEach(listString => {
|
||||||
|
const timeValues: string[] = listString.split(',');
|
||||||
|
const highlightLetters: WordDefinition | WordDefinition[] = definition[listString];
|
||||||
|
timeValues.forEach(timeValue => this.parseArrayOrObject(letters, styleClass + timeValue, highlightLetters));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hilfsklasse zum Rendern der Uhr.
|
||||||
|
* @param layout Layout-Objekt, das gerendert werden soll.
|
||||||
|
* @param renderarea Das jQuery-gewrappte HTML-Element, auf dem gerendert werden soll.
|
||||||
|
*/
|
||||||
|
export class UhrRenderer {
|
||||||
|
constructor(private layout: Layout, private renderarea: any/*FIXME any: jQuery-wrapped HTML element*/) {
|
||||||
|
}
|
||||||
|
|
||||||
|
render(beforeshow?: () => void): void {
|
||||||
|
if (this.layout.parsed === undefined) {
|
||||||
|
if (this.layout.version === 2) {
|
||||||
|
const delegate: UhrRendererV2Delegate = new UhrRendererV2Delegate(this.layout);
|
||||||
|
const parsedLayout: Letter[][] = delegate.parse();
|
||||||
|
Object.defineProperty(this.layout, "parsed", {
|
||||||
|
"value": parsedLayout,
|
||||||
|
"writable": false,
|
||||||
|
"configurable": false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn(`Unknown layout version: '${this.layout.version}', expecting '2'`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const letters: Letter[][] = this.layout.parsed;
|
||||||
|
this.renderarea.fadeOut('fast', () => {
|
||||||
|
this.renderarea.empty();
|
||||||
|
letters.forEach((line, index, array) => {
|
||||||
|
line.forEach(letter => this.renderarea.append(letter.toString()));
|
||||||
|
if (index < array.length - 1) {
|
||||||
|
this.renderarea.append('<br/>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (typeof beforeshow === 'function') {
|
||||||
|
beforeshow();
|
||||||
|
}
|
||||||
|
this.renderarea.fadeIn('fast');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
36
src/theme-autodetector.ts
Normal file
36
src/theme-autodetector.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as $ from 'jquery';
|
||||||
|
import {Globals} from "./domain/globals";
|
||||||
|
|
||||||
|
export function autodetectThemes() {
|
||||||
|
$('link[rel=stylesheet]').each((index, item) => {
|
||||||
|
const styleSheet = $(item);
|
||||||
|
const styleClass: string = styleSheet.attr('data-class');
|
||||||
|
if (styleClass !== undefined) {
|
||||||
|
let name: string = styleSheet.attr('data-name');
|
||||||
|
if (name === undefined) {
|
||||||
|
name = styleClass;
|
||||||
|
}
|
||||||
|
Globals.registerTheme(name, styleClass);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// fall-back if no theme was included
|
||||||
|
if (!Globals.hasThemes()) {
|
||||||
|
Globals.registerTheme('', '');
|
||||||
|
}
|
||||||
|
}
|
430
src/uehrli.ts
Normal file
430
src/uehrli.ts
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {WidgetPrototype} from "./widget/widget-prototype";
|
||||||
|
import {Globals} from "./domain/globals";
|
||||||
|
import {UhrRenderer} from "./renderer";
|
||||||
|
import {EMPTY_LAYOUT, Layout} from "./domain/layout";
|
||||||
|
|
||||||
|
export class Uehrli {
|
||||||
|
|
||||||
|
private timer: number = null;
|
||||||
|
private currentMinute: number = null;
|
||||||
|
|
||||||
|
constructor(private widgetInstance: WidgetPrototype) {
|
||||||
|
const userTime = this.widgetInstance.options.time;
|
||||||
|
if (this.widgetInstance.options.time === undefined) {
|
||||||
|
this.widgetInstance.options.time = new Date();
|
||||||
|
}
|
||||||
|
this.parseHash();
|
||||||
|
this.setupHTML();
|
||||||
|
this.wireFunctionality();
|
||||||
|
if (userTime !== undefined) {
|
||||||
|
this.setTime(userTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
if (!!this.timer) {
|
||||||
|
window.clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
this.widgetInstance.element
|
||||||
|
.removeAttr('style')
|
||||||
|
.removeAttr('class')
|
||||||
|
.empty();
|
||||||
|
$(`#uhr-configlink${this.widgetInstance.uuid}`).remove();
|
||||||
|
$(`#uhr-controlpanel${this.widgetInstance.uuid}`).remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
start(): void {
|
||||||
|
if (!this.isOn()) {
|
||||||
|
this.timer = window.setInterval(() => {
|
||||||
|
this.widgetInstance.options.time = new Date();
|
||||||
|
this.update();
|
||||||
|
}, 1000);
|
||||||
|
this.update();
|
||||||
|
this.setCookie('uhr-status', 'on');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(): void {
|
||||||
|
if (this.isOn()) {
|
||||||
|
window.clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
this.update();
|
||||||
|
this.setCookie('uhr-status', 'off');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(): void {
|
||||||
|
if (this.isOn()) {
|
||||||
|
this.stop();
|
||||||
|
} else {
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLanguage(key: string): void {
|
||||||
|
if (key !== this.widgetInstance.options.language) {
|
||||||
|
this.widgetInstance.options.language = key;
|
||||||
|
const renderer = new UhrRenderer(this.getCurrentLayout(), this.widgetInstance.element.find('.letterarea'));
|
||||||
|
renderer.render(() => {
|
||||||
|
this.currentMinute = -1;
|
||||||
|
this.update();
|
||||||
|
});
|
||||||
|
this.setCookie('uhr-language', key);
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTheme(styleClass: string): void {
|
||||||
|
if (styleClass !== this.widgetInstance.options.theme) {
|
||||||
|
this.widgetInstance.element.removeClass(this.widgetInstance.options.theme).addClass(styleClass);
|
||||||
|
$(`#uhr-onoffswitch${this.widgetInstance.uuid}`).removeClass(this.widgetInstance.options.theme).addClass(styleClass);
|
||||||
|
this.widgetInstance.options.theme = styleClass;
|
||||||
|
this.setCookie('uhr-theme', styleClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTime(time: Date): void {
|
||||||
|
this.currentMinute = null;
|
||||||
|
if (time === null) {
|
||||||
|
this.widgetInstance.options.time = new Date();
|
||||||
|
} else {
|
||||||
|
if (this.timer !== null) {
|
||||||
|
window.clearInterval(this.timer);
|
||||||
|
}
|
||||||
|
this.widgetInstance.options.time = time;
|
||||||
|
}
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
setMode(mode: string): void {
|
||||||
|
this.widgetInstance.options.mode = mode;
|
||||||
|
this.currentMinute = null;
|
||||||
|
this.update();
|
||||||
|
this.setCookie('uhr-mode', mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWidth(width: string): void {
|
||||||
|
const e = this.widgetInstance.element;
|
||||||
|
e.css('width', width);
|
||||||
|
const realWidth = e.width();
|
||||||
|
e.width(realWidth);
|
||||||
|
e.height(realWidth);
|
||||||
|
e.css('font-size', (realWidth / 40) + 'px');
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupHTML(): void {
|
||||||
|
const e: JQuery<HTMLElement> = this.widgetInstance.element;
|
||||||
|
// Base clock area
|
||||||
|
e.addClass('uhr')
|
||||||
|
.empty()
|
||||||
|
.append('<span class="item dot dot1"></span>')
|
||||||
|
.append('<span class="item dot dot2"></span>')
|
||||||
|
.append('<span class="item dot dot3"></span>')
|
||||||
|
.append('<span class="item dot dot4"></span>')
|
||||||
|
.append('<div class="letterarea"></div>')
|
||||||
|
.append('<div class="reflection"></div>');
|
||||||
|
|
||||||
|
this.setWidth(this.widgetInstance.options.width);
|
||||||
|
|
||||||
|
if (this.widgetInstance.options.controls) {
|
||||||
|
const controlpanel = $(`<div class="uhr-controlpanel" id="uhr-controlpanel${this.widgetInstance.uuid}"></div>`);
|
||||||
|
const content = $('<div class="content"></div>');
|
||||||
|
controlpanel.append(content);
|
||||||
|
// on/off switch
|
||||||
|
const toggleSwitch = $(`<div class="onoffswitch" id="uhr-onoffswitch${this.widgetInstance.uuid}"></div>`);
|
||||||
|
toggleSwitch.append(`<input type="checkbox" class="onoffswitch-checkbox" id="uhr-onoffswitch-checkbox${this.widgetInstance.uuid}" checked="checked" />`);
|
||||||
|
toggleSwitch.append(`<label class="onoffswitch-label" for="uhr-onoffswitch-checkbox${this.widgetInstance.uuid}"><div class="onoffswitch-inner"></div><div class="onoffswitch-switch"></div></label>`);
|
||||||
|
content.append(toggleSwitch);
|
||||||
|
|
||||||
|
// time mode switch
|
||||||
|
const modeSwitch = $(`<div class="onoffswitch" id="uhr-modeswitch${this.widgetInstance.uuid}"></div>`);
|
||||||
|
modeSwitch.append(`<input type="checkbox" class="onoffswitch-checkbox" id="uhr-modeswitch-checkbox${this.widgetInstance.uuid}" checked="checked" />`);
|
||||||
|
modeSwitch.append(`<label class="onoffswitch-label" for="uhr-modeswitch-checkbox${this.widgetInstance.uuid}"><div class="modeswitch-inner"></div><div class="onoffswitch-switch"></div></label>`);
|
||||||
|
content.append(modeSwitch);
|
||||||
|
// language chooser
|
||||||
|
if (Globals.hasMultipleLayouts()) {
|
||||||
|
const languageChooser = $(`<select id="uhr-languagechooser${this.widgetInstance.uuid}"></select>`);
|
||||||
|
Globals.getLayouts().forEach(layout => {
|
||||||
|
languageChooser.append(`<option value="${layout.code}">${layout.prettyName}</option>`);
|
||||||
|
});
|
||||||
|
content.append(languageChooser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// theme chooser
|
||||||
|
if (Globals.hasMultipleThemes()) {
|
||||||
|
const themeChooser = $(`<select id="uhr-themechooser${this.widgetInstance.uuid}"></select>`);
|
||||||
|
Globals.getThemes().forEach(theme => {
|
||||||
|
themeChooser.append(`<option value="${theme.styleClass}">${theme.name}</option>`);
|
||||||
|
});
|
||||||
|
content.append(themeChooser);
|
||||||
|
}
|
||||||
|
const closebutton = $(`<a class="uhr-closecontrolpanel" id="uhr-closecontrolpanel${this.widgetInstance.uuid}"></a>`);
|
||||||
|
//FIXME deprecated?!
|
||||||
|
closebutton.on('click', function () {
|
||||||
|
$(`#uhr-controlpanel${this.uuid}`).hide('fast');
|
||||||
|
}.bind(this.widgetInstance));
|
||||||
|
content.append(closebutton);
|
||||||
|
e.after(controlpanel);
|
||||||
|
controlpanel.hide();
|
||||||
|
const configlink = $(`<a class="uhr-configlink" id="uhr-configlink${this.widgetInstance.uuid}"></a>`);
|
||||||
|
// FIXME deprecated!?
|
||||||
|
configlink.on('click', function () {
|
||||||
|
this.toggleConfigScreen();
|
||||||
|
}.bind(this));
|
||||||
|
e.after(configlink);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private wireFunctionality(): void {
|
||||||
|
// on/off switch
|
||||||
|
const toggleSwitch = $(`#uhr-onoffswitch-checkbox${this.widgetInstance.uuid}`);
|
||||||
|
// FIXME deprecated!?
|
||||||
|
toggleSwitch.on('click', () => this.toggle());
|
||||||
|
let status = this.getCookie('uhr-status');
|
||||||
|
if (status === undefined || this.widgetInstance.options.force) {
|
||||||
|
status = this.widgetInstance.options.status;
|
||||||
|
}
|
||||||
|
toggleSwitch.prop('checked', status === 'on');
|
||||||
|
if (status === 'on') {
|
||||||
|
this.start();
|
||||||
|
} else {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// time mode switch
|
||||||
|
const modeSwitch = $(`#uhr-modeswitch-checkbox${this.widgetInstance.uuid}`);
|
||||||
|
// FIXME deprecated!?
|
||||||
|
modeSwitch.on('click', () => {
|
||||||
|
if (this.widgetInstance.options.mode === 'seconds') {
|
||||||
|
this.setMode('normal');
|
||||||
|
} else {
|
||||||
|
this.setMode('seconds');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mode = this.getCookie('uhr-mode');
|
||||||
|
if (mode === undefined || this.widgetInstance.options.force) {
|
||||||
|
mode = this.widgetInstance.options.mode;
|
||||||
|
}
|
||||||
|
modeSwitch.prop('checked', mode !== 'seconds');
|
||||||
|
if (mode === 'seconds') {
|
||||||
|
this.setMode('seconds');
|
||||||
|
} else {
|
||||||
|
this.setMode('normal');
|
||||||
|
}
|
||||||
|
|
||||||
|
// language chooser
|
||||||
|
const languageChooser = $(`#uhr-languagechooser${this.widgetInstance.uuid}`);
|
||||||
|
// FIXME deprecated!?
|
||||||
|
languageChooser.on('change', () => {
|
||||||
|
const languageKey = $(`#uhr-languagechooser${this.widgetInstance.uuid}`).val() as string;
|
||||||
|
this.setLanguage(languageKey);
|
||||||
|
});
|
||||||
|
let selectedLayout = this.getCookie('uhr-language');
|
||||||
|
if (selectedLayout === undefined || this.widgetInstance.options.force) {
|
||||||
|
selectedLayout = this.widgetInstance.options.language;
|
||||||
|
}
|
||||||
|
let found = Globals.getLayouts().some(item => selectedLayout === item.code);
|
||||||
|
if (!found) {
|
||||||
|
let fallbackLanguage;
|
||||||
|
if (Globals.hasLayouts()) {
|
||||||
|
fallbackLanguage = Globals.getFirstLayout().code;
|
||||||
|
} else {
|
||||||
|
fallbackLanguage = '';
|
||||||
|
}
|
||||||
|
console.warn(`Language '${selectedLayout}' not found! Using fallback '${fallbackLanguage}'.`);
|
||||||
|
selectedLayout = fallbackLanguage;
|
||||||
|
}
|
||||||
|
languageChooser.val(selectedLayout);
|
||||||
|
this.widgetInstance.options.language = "";
|
||||||
|
this.setLanguage(selectedLayout);
|
||||||
|
|
||||||
|
// theme chooser
|
||||||
|
const themeChooser = $(`#uhr-themechooser${this.widgetInstance.uuid}`);
|
||||||
|
// FIXME deprecated!?
|
||||||
|
themeChooser.on('change', () => {
|
||||||
|
const themeKey = $(`#uhr-themechooser${this.widgetInstance.uuid}`).val() as string;
|
||||||
|
this.setTheme(themeKey);
|
||||||
|
});
|
||||||
|
let selectedTheme = this.getCookie('uhr-theme');
|
||||||
|
if (selectedTheme === undefined || this.widgetInstance.options.force) {
|
||||||
|
selectedTheme = this.widgetInstance.options.theme;
|
||||||
|
}
|
||||||
|
found = Globals.getThemes().some(item => selectedTheme === item.styleClass);
|
||||||
|
if (!found) {
|
||||||
|
const fallbackTheme = Globals.getFirstTheme().styleClass;
|
||||||
|
console.warn(`Theme '${selectedTheme}' not found! Using fallback '${fallbackTheme}'.`);
|
||||||
|
selectedTheme = fallbackTheme;
|
||||||
|
}
|
||||||
|
themeChooser.val(selectedTheme);
|
||||||
|
this.widgetInstance.options.theme = "";
|
||||||
|
this.setTheme(selectedTheme);
|
||||||
|
if (this.widgetInstance.options.autoresize) {
|
||||||
|
// FIXME deprecated!?
|
||||||
|
$(window).on('resize', () => {
|
||||||
|
const $e = this.widgetInstance.element;
|
||||||
|
const $parent = $e.parent();
|
||||||
|
const $window = $(window);
|
||||||
|
const parentWidth = $parent.width();
|
||||||
|
const parentHeight = $parent.height();
|
||||||
|
const windowWidth = $window.width();
|
||||||
|
const windowHeight = $window.height();
|
||||||
|
const size = `${Math.min(parentWidth, parentHeight, windowWidth, windowHeight)}px`;
|
||||||
|
this.setWidth(size);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isOn(): boolean {
|
||||||
|
return this.timer !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCookie(cookieName: string): string {
|
||||||
|
return $.cookie(cookieName + this.widgetInstance.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setCookie(cookieName: string, cookieValue: string): void {
|
||||||
|
let options;
|
||||||
|
if (this.widgetInstance.options.cookiePath !== undefined) {
|
||||||
|
options = {expires: 365, path: this.widgetInstance.options.cookiePath};
|
||||||
|
} else {
|
||||||
|
options = {expires: 365};
|
||||||
|
}
|
||||||
|
$.cookie(cookieName + this.widgetInstance.uuid, cookieValue, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(): void {
|
||||||
|
if (this.isOn()) {
|
||||||
|
const time = this.widgetInstance.options.time;
|
||||||
|
if (!this.getCurrentLayout().hasOwnProperty('seconds') && this.widgetInstance.options.mode !== 'seconds') {
|
||||||
|
if (time.getMinutes() === this.currentMinute) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentMinute = time.getMinutes();
|
||||||
|
}
|
||||||
|
this.show(time);
|
||||||
|
} else {
|
||||||
|
this.clear();
|
||||||
|
this.currentMinute = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private show(time: Date): void {
|
||||||
|
const second = this.getSecond(time);
|
||||||
|
const dotMinute = this.getDotMinute(time);
|
||||||
|
const hour = this.getHour(time);
|
||||||
|
const coarseMinute = this.getCoarseMinute(time);
|
||||||
|
this.clear();
|
||||||
|
if (this.widgetInstance.options.mode === 'seconds') {
|
||||||
|
this.highlight(`second${second}`);
|
||||||
|
} else {
|
||||||
|
this.highlight('on');
|
||||||
|
for (let i = 1; i <= dotMinute; i++) {
|
||||||
|
this.highlight(`dot${i}`);
|
||||||
|
}
|
||||||
|
this.highlight(`minute${coarseMinute}`);
|
||||||
|
this.highlight(`hour${hour}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private clear(): void {
|
||||||
|
this.widgetInstance.element.find('.item').removeClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
private highlight(itemClass: string): void {
|
||||||
|
this.widgetInstance.element.find(`.item.${itemClass}`).addClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSecond(time: Date): number {
|
||||||
|
if (typeof this.getCurrentLayout().getSeconds === 'function') {
|
||||||
|
return this.getCurrentLayout().getSeconds(time);
|
||||||
|
}
|
||||||
|
return time.getSeconds();
|
||||||
|
};
|
||||||
|
|
||||||
|
private getDotMinute(date: Date): number {
|
||||||
|
if (typeof this.getCurrentLayout().getDotMinute === 'function') {
|
||||||
|
return this.getCurrentLayout().getDotMinute(date);
|
||||||
|
}
|
||||||
|
return date.getMinutes() % 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
private getCoarseMinute(date: Date): number {
|
||||||
|
if (typeof this.getCurrentLayout().getCoarseMinute === 'function') {
|
||||||
|
return this.getCurrentLayout().getCoarseMinute(date);
|
||||||
|
}
|
||||||
|
return date.getMinutes();
|
||||||
|
};
|
||||||
|
|
||||||
|
private getHour(date: Date): number {
|
||||||
|
if (typeof this.getCurrentLayout().getHour === 'function') {
|
||||||
|
return this.getCurrentLayout().getHour(date);
|
||||||
|
}
|
||||||
|
const hour = date.getHours();
|
||||||
|
if (date.getMinutes() >= 25) {
|
||||||
|
return (hour + 1) % 24;
|
||||||
|
}
|
||||||
|
return hour;
|
||||||
|
};
|
||||||
|
|
||||||
|
private parseHash(): void {
|
||||||
|
let hash: string = window.location.hash;
|
||||||
|
if (hash !== undefined && hash.charAt(0) === '#') {
|
||||||
|
hash = hash.substring(1);
|
||||||
|
hash = decodeURIComponent(hash);
|
||||||
|
const params: string[] = hash.split('&');
|
||||||
|
params.forEach(element => {
|
||||||
|
const pair: string[] = element.split('=');
|
||||||
|
const key = pair[0];
|
||||||
|
const value = pair[1];
|
||||||
|
switch (key) {
|
||||||
|
case 'l':
|
||||||
|
case 'language':
|
||||||
|
this.widgetInstance.options.language = value;
|
||||||
|
this.widgetInstance.options.force = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'theme':
|
||||||
|
this.widgetInstance.options.theme = value;
|
||||||
|
this.widgetInstance.options.force = true;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
case 'mode':
|
||||||
|
this.widgetInstance.options.mode = value;
|
||||||
|
this.widgetInstance.options.force = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
case 'status':
|
||||||
|
this.widgetInstance.options.status = value;
|
||||||
|
this.widgetInstance.options.force = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCurrentLayout(): Layout {
|
||||||
|
const matchingLanguages: Layout[] = Globals.getLayouts().filter(element => element.code === this.widgetInstance.options.language, this);
|
||||||
|
if (matchingLanguages.length > 0) {
|
||||||
|
return matchingLanguages[0];
|
||||||
|
}
|
||||||
|
// fallback: return empty object
|
||||||
|
return EMPTY_LAYOUT;
|
||||||
|
};
|
||||||
|
}
|
27
src/widget/options.ts
Normal file
27
src/widget/options.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Options {
|
||||||
|
width: string;
|
||||||
|
status: string;
|
||||||
|
language: string;
|
||||||
|
theme: string;
|
||||||
|
force: boolean;
|
||||||
|
controls: boolean;
|
||||||
|
cookiePath?: string;
|
||||||
|
autoresize: boolean;
|
||||||
|
mode: string;
|
||||||
|
time?: Date;
|
||||||
|
}
|
33
src/widget/widget-prototype.ts
Normal file
33
src/widget/widget-prototype.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import WidgetCommonProperties = JQueryUI.WidgetCommonProperties;
|
||||||
|
import {Uehrli} from "../uehrli";
|
||||||
|
import {Options} from "./options";
|
||||||
|
|
||||||
|
export interface WidgetPrototype extends WidgetCommonProperties {
|
||||||
|
options: Options;
|
||||||
|
start: () => void;
|
||||||
|
stop: () => void;
|
||||||
|
toggle: () => void;
|
||||||
|
language: (key: string) => void;
|
||||||
|
theme: (id: string) => void;
|
||||||
|
time: (time: Date) => void;
|
||||||
|
mode: (mode: string) => void;
|
||||||
|
width: (width: string) => void;
|
||||||
|
_create: () => void;
|
||||||
|
_destroy: () => void;
|
||||||
|
__fritteli_uhr_instance: Uehrli;
|
||||||
|
}
|
Loading…
Reference in a new issue