431 lines
16 KiB
TypeScript
431 lines
16 KiB
TypeScript
/*
|
|
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";
|
|
import * as Cookies from "js-cookie";
|
|
|
|
export class Uhr {
|
|
|
|
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', () => $(`#uhr-controlpanel${this.widgetInstance.uuid}`).hide('fast'));
|
|
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', () => this.toggleConfigScreen());
|
|
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 Cookies.get(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};
|
|
}
|
|
Cookies.set(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 toggleConfigScreen() {
|
|
$(`#uhr-controlpanel${this.widgetInstance.uuid}`).toggle('fast');
|
|
};
|
|
|
|
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;
|
|
};
|
|
}
|