'use strict'; /* 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 . */ (function ($) { var uhrGlobals = { "id": 0, "languages": [], "themes": [], registerLanguage: function registerLanguage(code, language) { var alreadyExists = uhrGlobals.languages.some(function (element) { if (code === element.code) { console.error("Error: Language code '" + code + "' cannot be registered for language '" + language.language + "' because it is already registered for language '" + element.language + "'!"); return true; } return false; }); if (!alreadyExists) { language.code = code; uhrGlobals.languages.push(language); } } }; // auto-detect themes $('link[rel=stylesheet]').each(function (index, item) { var styleSheet = $(item); var styleClass = styleSheet.attr('data-class'); if (styleClass !== undefined) { var name = styleSheet.attr('data-name'); if (name === undefined) { name = styleClass; } uhrGlobals.themes.push({'styleClass': styleClass, 'name': name}); } }); // fall-back if no theme was included if (uhrGlobals.themes.length === 0) { uhrGlobals.themes.push({}); } // public interface methods (exported later) var setCookie; var isOn; var update; var start = function start() { if (!isOn.bind(this)()) { this.timer = window.setInterval(function () { this.options.time = new Date(); update.bind(this)(); }.bind(this), 1000); update.bind(this)(); setCookie.bind(this)('uhr-status', 'on'); } }; var stop = function stop() { if (isOn.bind(this)()) { window.clearInterval(this.timer); this.timer = null; update.bind(this)(); setCookie.bind(this)('uhr-status', 'off'); } }; var toggle = function toggle() { if (isOn.bind(this)()) { this.stop(); } else { this.start(); } }; var language; /** * 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. */ function Letter(value, style) { var myValue = value; var myStyle = style || ''; this.addStyle = function (style) { if (myStyle === '') { myStyle = style; } else { myStyle += ' ' + style; } }; this.toString = function () { return '' + myValue + ''; }; } function UhrRendererV2Delegate(layout) { var vorne0 = { 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] }; var hinten0 = { 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] }; var vorne1 = { 3: [3], 4: [2, 3], 5: [3], 6: [3], 7: [3], 8: [3], 9: [2, 3, 4] }; var hinten1 = { 3: [9], 4: [8, 9], 5: [9], 6: [9], 7: [9], 8: [9], 9: [8, 9, 10] }; var vorne2 = { 3: [2, 3, 4], 4: [1, 5], 5: [5], 6: [4], 7: [3], 8: [2], 9: [1, 2, 3, 4, 5] }; var hinten2 = { 3: [8, 9, 10], 4: [7, 11], 5: [11], 6: [10], 7: [9], 8: [8], 9: [7, 8, 9, 10, 11] }; var vorne3 = { 3: [1, 2, 3, 4, 5], 4: [4], 5: [3], 6: [4], 7: [5], 8: [1, 5], 9: [2, 3, 4] }; var hinten3 = { 3: [7, 8, 9, 10, 11], 4: [10], 5: [9], 6: [10], 7: [11], 8: [7, 11], 9: [8, 9, 10] }; var vorne4 = { 3: [4], 4: [3, 4], 5: [2, 4], 6: [1, 4], 7: [1, 2, 3, 4, 5], 8: [4], 9: [4] }; var hinten4 = { 3: [10], 4: [9, 10], 5: [8, 10], 6: [7, 10], 7: [7, 8, 9, 10, 11], 8: [10], 9: [10] }; var vorne5 = { 3: [1, 2, 3, 4, 5], 4: [1], 5: [1, 2, 3, 4], 6: [5], 7: [5], 8: [1, 5], 9: [2, 3, 4] }; var hinten5 = { 3: [7, 8, 9, 10, 11], 4: [7], 5: [7, 8, 9, 10], 6: [11], 7: [11], 8: [7, 11], 9: [8, 9, 10] }; var hinten6 = { 3: [9, 10], 4: [8], 5: [7], 6: [7, 8, 9, 10], 7: [7, 11], 8: [7, 11], 9: [8, 9, 10] }; var hinten7 = { 3: [7, 8, 9, 10, 11], 4: [11], 5: [10], 6: [9], 7: [8], 8: [8], 9: [8] }; var hinten8 = { 3: [8, 9, 10], 4: [7, 11], 5: [7, 11], 6: [8, 9, 10], 7: [7, 11], 8: [7, 11], 9: [8, 9, 10] }; var hinten9 = { 3: [8, 9, 10], 4: [7, 11], 5: [7, 11], 6: [8, 9, 10, 11], 7: [11], 8: [10], 9: [8, 9] }; var seconds = { "0": [vorne0, hinten0], "1": [vorne0, hinten1], "2": [vorne0, hinten2], "3": [vorne0, hinten3], "4": [vorne0, hinten4], "5": [vorne0, hinten5], "6": [vorne0, hinten6], "7": [vorne0, hinten7], "8": [vorne0, hinten8], "9": [vorne0, hinten9], "10": [vorne1, hinten0], "11": [vorne1, hinten1], "12": [vorne1, hinten2], "13": [vorne1, hinten3], "14": [vorne1, hinten4], "15": [vorne1, hinten5], "16": [vorne1, hinten6], "17": [vorne1, hinten7], "18": [vorne1, hinten8], "19": [vorne1, hinten9], "20": [vorne2, hinten0], "21": [vorne2, hinten1], "22": [vorne2, hinten2], "23": [vorne2, hinten3], "24": [vorne2, hinten4], "25": [vorne2, hinten5], "26": [vorne2, hinten6], "27": [vorne2, hinten7], "28": [vorne2, hinten8], "29": [vorne2, hinten9], "30": [vorne3, hinten0], "31": [vorne3, hinten1], "32": [vorne3, hinten2], "33": [vorne3, hinten3], "34": [vorne3, hinten4], "35": [vorne3, hinten5], "36": [vorne3, hinten6], "37": [vorne3, hinten7], "38": [vorne3, hinten8], "39": [vorne3, hinten9], "40": [vorne4, hinten0], "41": [vorne4, hinten1], "42": [vorne4, hinten2], "43": [vorne4, hinten3], "44": [vorne4, hinten4], "45": [vorne4, hinten5], "46": [vorne4, hinten6], "47": [vorne4, hinten7], "48": [vorne4, hinten8], "49": [vorne4, hinten9], "50": [vorne5, hinten0], "51": [vorne5, hinten1], "52": [vorne5, hinten2], "53": [vorne5, hinten3], "54": [vorne5, hinten4], "55": [vorne5, hinten5], "56": [vorne5, hinten6], "57": [vorne5, hinten7], "58": [vorne5, hinten8], "59": [vorne5, hinten9] }; function parseObject(letters, styleClass, object) { if (typeof object !== 'undefined' && object !== null) { Object.keys(object).forEach(function (y) { var highlightLetters = object[y]; highlightLetters.forEach(function (x) { letters[y - 1][x - 1].addStyle(styleClass); }); }); } } function parseArrayOrObject(letters, styleClass, input) { if (typeof input !== 'undefined' && input !== null) { if (Array.isArray(input)) { input.forEach(function (item) { parseObject(letters, styleClass, item); }); } else { parseObject(letters, styleClass, input); } } } function parseTimeDefinition(letters, styleClass, definition) { if (typeof definition !== 'undefined' && definition !== null) { Object.keys(definition).forEach(function (listString) { var array = listString.split(','); var highlightLetters = definition[listString]; array.forEach(function (item) { parseArrayOrObject(letters, styleClass + item, highlightLetters); }); }); } } this.parse = function parse() { var letters = []; layout.letters.forEach(function (string) { var line = []; for (var c = 0; c < string.length; c++) { var character = new Letter(string[c]); line.push(character); } letters.push(line); }); parseArrayOrObject(letters, 'on', layout.permanent); if (typeof layout.seconds !== 'undefined' && layout.seconds !== null) { parseTimeDefinition(letters, 'second', layout.seconds); } else { parseTimeDefinition(letters, 'second', seconds); } parseTimeDefinition(letters, 'minute', layout.minutes); parseTimeDefinition(letters, 'hour', layout.hours); return letters; }; } /** * 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. */ function UhrRenderer(layout, renderarea) { this.render = function render(beforeshow) { if (layout.parsed === undefined) { switch (layout.version) { case 2: var delegate = new UhrRendererV2Delegate(layout); var parsedLayout = delegate.parse(); Object.defineProperty(layout, "parsed", { "value": parsedLayout, "writable": false, "configurable": false }); break; default: console.warn("Unknown layout version: '" + layout.version + "'"); return; } } var letters = layout.parsed; renderarea.fadeOut('fast', function () { renderarea.empty(); letters.forEach(function (line, index, array) { line.forEach(function (letter) { renderarea.append(letter.toString()); }); if (index < array.length - 1) { renderarea.append('
'); } }); if (typeof beforeshow === 'function') { beforeshow(); } renderarea.fadeIn('fast'); }); }; } var setLanguage = function setLanguage(languageKey) { if (languageKey !== this.options.language) { this.options.language = languageKey; var renderer = new UhrRenderer(language.bind(this)(), this.element.find('.letterarea')); renderer.render.bind(this)(function () { this.currentMinute = -1; update.bind(this)(); }.bind(this)); setCookie.bind(this)('uhr-language', languageKey); update.bind(this)(); } }; var setTheme = function setTheme(theme) { if (theme !== this.options.theme) { this.element.removeClass(this.options.theme).addClass(theme); $('#uhr-onoffswitch' + this.id).removeClass(this.options.theme).addClass(theme); this.options.theme = theme; setCookie.bind(this)('uhr-theme', theme); } }; var setTime = function setTime(time) { this.currentMinute = -1; if (time === null) { this.options.time = new Date(); } else { if (this.timer !== null) { window.clearInterval(this.timer); } this.options.time = time; } update.bind(this)(); }; var setMode = function (mode) { this.options.mode = mode; this.currentMinute = -1; update.bind(this)(); setCookie.bind(this)('uhr-mode', mode); }; var setWidth = function setWidth(width) { var e = this.element; e.css('width', width); var realWidth = e.width(); e.width(realWidth); e.height(realWidth); e.css('font-size', (realWidth / 40) + 'px'); }; // private interface methods var setupHTML; var wireFunctionality; var create = function create() { this.id = uhrGlobals.id++; this.timer = null; this.currentMinute = -1; var userTime = this.options.time; var hash, params; if (this.options.time === undefined) { this.options.time = new Date(); } // parse the URL params hash = window.location.hash; if (hash !== undefined && typeof hash === 'string' && hash.charAt(0) === '#') { hash = hash.substring(1); hash = decodeURIComponent(hash); params = hash.split('&'); params.forEach(function (element) { var pair = element.split('='); var key = pair[0]; var value = pair[1]; switch (key) { case 'l': case 'language': this.options.language = value; this.options.force = true; break; case 't': case 'theme': this.options.theme = value; this.options.force = true; break; case 'm': case 'mode': this.options.mode = value; this.options.force = true; break; case 's': case 'status': this.options.status = value; this.options.force = true; break; } }.bind(this)); } // end parse the URL params setupHTML.bind(this)(); wireFunctionality.bind(this)(); if (userTime !== undefined) { this.time(userTime); } }; // private helper methods (not exported) var toggleConfigScreen = function toggleConfigScreen() { $('#uhr-controlpanel' + this.id).toggle('fast'); }; // set up setupHTML = function setupHTML() { var e = this.element; // Base clock area e.addClass('uhr'); e.empty(); e.append(''); e.append(''); e.append(''); e.append(''); e.append('
'); e.append('
'); setWidth.bind(this)(this.options.width); if (this.options.controls) { var controlpanel = $('
'); var content = $('
'); controlpanel.append(content); // on/off switch var toggleSwitch = $('
'); toggleSwitch.append(''); toggleSwitch.append(''); content.append(toggleSwitch); // time mode switch var modeSwitch = $('
'); modeSwitch.append(''); modeSwitch.append(''); content.append(modeSwitch); // language chooser if (uhrGlobals.languages.length > 1) { var languageChooser = $(''); uhrGlobals.languages.forEach(function (item) { languageChooser.append(''); }); content.append(languageChooser); } // theme chooser if (uhrGlobals.themes.length > 1) { var themeChooser = $(''); uhrGlobals.themes.forEach(function (item) { themeChooser.append(''); }); content.append(themeChooser); } var closebutton = $(''); closebutton.on('click', function () { $('#uhr-controlpanel' + this.id).hide('fast'); }.bind(this)); content.append(closebutton); e.after(controlpanel); controlpanel.hide(); var configlink = $(''); configlink.on('click', function () { toggleConfigScreen.bind(this)(); }.bind(this)); e.after(configlink); } }; wireFunctionality = function wireFunctionality() { // on/off switch var toggleSwitch = $('#uhr-onoffswitch-checkbox' + this.id); toggleSwitch.on('click', function () { this.toggle(); }.bind(this)); var status = $.cookie('uhr-status' + this.id); if (status === undefined || this.options.force) { status = this.options.status; } toggleSwitch.prop('checked', status === 'on'); if (status === 'on') { this.start(); } else { this.stop(); } // time mode switch var modeSwitch = $('#uhr-modeswitch-checkbox' + this.id); modeSwitch.on('click', function () { if (this.options.mode === 'seconds') { setMode.bind(this)('normal'); } else { setMode.bind(this)('seconds'); } }.bind(this)); var mode = $.cookie('uhr-mode' + this.id); if (mode === undefined || this.options.force) { mode = this.options.mode; } modeSwitch.prop('checked', mode !== 'seconds'); if (mode === 'seconds') { setMode.bind(this)('seconds'); } else { setMode.bind(this)('normal'); } // language chooser var languageChooser = $('#uhr-languagechooser' + this.id); languageChooser.on('change', function () { var languageKey = $('#uhr-languagechooser' + this.id).val(); this.language(languageKey); }.bind(this)); var selectedLanguage = $.cookie('uhr-language' + this.id); if (selectedLanguage === undefined || this.options.force) { selectedLanguage = this.options.language; } var found = uhrGlobals.languages.some(function (item) { return selectedLanguage === item.code; }); if (!found) { var fallbackLanguage; if (uhrGlobals.languages.length > 0) { fallbackLanguage = uhrGlobals.languages[0].code; } else { fallbackLanguage = ''; } console.warn("Language '" + selectedLanguage + "' not found! Using fallback '" + fallbackLanguage + "'"); selectedLanguage = fallbackLanguage; } languageChooser.val(selectedLanguage); this.options.language = ""; this.language(selectedLanguage); // theme chooser var themeChooser = $('#uhr-themechooser' + this.id); themeChooser.on('change', function () { var themeKey = $('#uhr-themechooser' + this.id).val(); this.theme(themeKey); }.bind(this)); var selectedTheme = $.cookie('uhr-theme' + this.id); if (selectedTheme === undefined || this.options.force) { selectedTheme = this.options.theme; } found = uhrGlobals.themes.some(function (item) { return selectedTheme === item.styleClass; }); if (!found) { var fallbackTheme = uhrGlobals.themes[0].styleClass; console.warn("Theme '" + selectedTheme + "' not found! Using fallback '" + fallbackTheme + "'"); selectedTheme = fallbackTheme; } themeChooser.val(selectedTheme); this.options.theme = ""; this.theme(selectedTheme); if (this.options.autoresize) { $(window).on('resize', function () { var $e = this.element; var $parent = $e.parent(); var $window = $(window); var parentWidth = $parent.width(); var parentHeight = $parent.height(); var windowWidth = $window.width(); var windowHeight = $window.height(); var size = Math.min(parentWidth, parentHeight, windowWidth, windowHeight) + 'px'; setWidth.bind(this)(size); }.bind(this)); } }; var destroy = function destroy() { this.timer = null; $(this.element) .removeAttr('style') .removeAttr('class') .empty(); $('#uhr-configlink' + this.id).remove(); $('#uhr-controlpanel' + this.id).remove(); }; setCookie = function setCookie(cookieName, cookieValue) { var options = {}; if (this.options.cookiePath !== undefined) { options = {expires: 365, path: this.options.cookiePath}; } else { options = {expires: 365}; } $.cookie(cookieName + this.id, cookieValue, options); }; // business logic isOn = function isOn() { return this.timer !== null; }; var show; var clear; update = function update() { if (isOn.bind(this)()) { var time = this.options.time; if (!language.bind(this)().hasOwnProperty('seconds') && this.options.mode !== 'seconds') { if (time.getMinutes() === this.currentMinute) { return; } this.currentMinute = time.getMinutes(); } show.bind(this)(time); } else { clear.bind(this)(); this.currentMinute = -1; } }; var highlight; var getSecond; var getDotMinute; var getCoarseMinute; var getHour; show = function show(time) { var second = getSecond.bind(this)(time); var dotMinute = getDotMinute.bind(this)(time); var hour = getHour.bind(this)(time); var coarseMinute = getCoarseMinute.bind(this)(time); clear.bind(this)(); if (this.options.mode === 'seconds') { highlight.bind(this)('second' + second); } else { highlight.bind(this)('on'); for (var i = 1; i <= dotMinute; i++) { highlight.bind(this)('dot' + i); } highlight.bind(this)('minute' + coarseMinute); highlight.bind(this)('hour' + hour); } }; highlight = function highlight(itemClass) { this.element.find('.item.' + itemClass).addClass('active'); }; clear = function clear() { this.element.find('.item').removeClass('active'); }; getSecond = function getSecond(date) { if (typeof language.bind(this)().getSeconds === 'function') { return language.bind(this)().getSeconds(date); } return date.getSeconds(); }; getDotMinute = function getDotMinute(date) { if (typeof language.bind(this)().getDotMinute === 'function') { return language.bind(this)().getDotMinute(date); } var minutes = date.getMinutes(); return minutes % 5; }; getCoarseMinute = function getCoarseMinute(date) { if (typeof language.bind(this)().getCoarseMinute === 'function') { return language.bind(this)().getCoarseMinute(date); } return date.getMinutes(); }; getHour = function getHour(date) { if (typeof language.bind(this)().getHour === 'function') { return language.bind(this)().getHour(date); } var hour = date.getHours(); if (date.getMinutes() >= 25) { return (hour + 1) % 24; } return hour; }; language = function language() { var matchingLanguages = uhrGlobals.languages.filter(function (element) { return (element.code === this.options.language); }, this); if (matchingLanguages.length > 0) { return matchingLanguages[0]; } // fallback: return empty object return {}; }; $.widget("fritteli.uhr", { "options": { width: '100%', status: 'on', language: 'de_CH', theme: uhrGlobals.themes[0].styleClass, force: false, controls: true, cookiePath: undefined, autoresize: true, mode: 'normal' }, "start": start, "stop": stop, "toggle": toggle, "language": setLanguage, "theme": setTheme, "time": setTime, "mode": setMode, "width": setWidth, // constructor method "_create": create, // destructor method "_destroy": destroy }); $.fritteli.uhr.register = uhrGlobals.registerLanguage; })(jQuery);