diff options
author | Matěj Cepl <mcepl@cepl.eu> | 2023-01-22 10:39:31 +0100 |
---|---|---|
committer | Matěj Cepl <mcepl@cepl.eu> | 2023-01-22 10:39:31 +0100 |
commit | 9e8931a65545595fea87132e77e70005556997d1 (patch) | |
tree | a619a1bdb3acf65a0e898a6e398ac7d9b6553e56 | |
parent | 10516625853177b2b1ed01d054aca63ced9042d0 (diff) | |
download | hesla-9e8931a65545595fea87132e77e70005556997d1.tar.gz |
Basics of rewrite to TypeScript
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | activePage.ts | 119 | ||||
-rw-r--r-- | config.ts | 6 | ||||
-rw-r--r-- | hesla.ts | 168 | ||||
-rw-r--r-- | require.d.ts | 330 | ||||
-rw-r--r-- | touchEvent.d.ts | 83 |
6 files changed, 712 insertions, 2 deletions
@@ -4,8 +4,12 @@ FILES=hesla.js hesla.js.map require.js config.js config.js.map \ index_de.html index.html screen.css site.webmanifest favicon.ico \ google9815148f4ac1407f.html config.es hesla.es activePage.es -%.js: %.es - $(BABEL) --source-maps true -o $@ $< +# %.js: %.es +# $(BABEL) --source-maps true -o $@ $< + +%.js: %.ts + # or -m amd + tsc --sourceMap --allowJs true --checkJs false --module es2015 --target ES5 $< all: index.html index_de.html config.js activePage.js hesla.js diff --git a/activePage.ts b/activePage.ts new file mode 100644 index 0000000..a1adf01 --- /dev/null +++ b/activePage.ts @@ -0,0 +1,119 @@ +/// <reference path='touchEvent.d.ts' /> + +export class ActivePage { + // The idea behind this property that it could basically anything, but + // whoever inherits this class must override next(), prev(), and display() methods, + // if necessary; just in the end, its value probably corresponds to the IDs of the + // individual elements in the page. + public cur_section = 0; + private swipe_pos_x = 0; + private swipe_pos_y = 0; + + constructor(appName: string) { + // Swipe event handlers + document.body.addEventListener("dblclick", + () => { + this.display(); + }, false); + + document.body.addEventListener("mousedown", + (evt: MouseEvent) => { + this.swipe_pos_x = evt.screenX; + this.swipe_pos_y = evt.screenY; + console.log("mousedown; pos = " + this.swipe_pos_x + + " / " + this.swipe_pos_y); + }, false); + + document.body.addEventListener("mouseup", + (evt: MouseEvent) => { + console.log("mouseup; end_pos = " + evt.screenX + + " / " + evt.screenY); + this.handle_move(this.swipe_pos_x - evt.screenX, + this.swipe_pos_y - evt.screenY); + }, false); + + document.body.addEventListener("touchstart", + (evt: TouchEvent) => { + this.swipe_pos_x = evt.changedTouches[0].screenX; + this.swipe_pos_y = evt.changedTouches[0].screenY; + console.log("touchstart; pos = " + this.swipe_pos_x + + " / " + this.swipe_pos_y); + }, false); + + document.body.addEventListener("touchend", + (evt: TouchEvent) => { + var end_pos = evt.changedTouches[evt.changedTouches.length - 1]; + // We want't opposite direction to Mouse gestures here + // so the difference should be opposite + this.handle_move(end_pos.screenX - this.swipe_pos_x, + end_pos.screenY - this.swipe_pos_y); + }, false); + + document.body.addEventListener("touchcancel", + () => { + this.swipe_pos_x = 0; + this.swipe_pos_y = 0; + }, false); + + // applicationCache.addEventListener("updateready", + // () => { location.reload(); } + // ); + + this.display(); + } + + /** + * Display current item + * + * @param new_date String with ISO formatted date (optional) + * or Number with the relative distance of the day from the date + * currently displayed. + * + * Displays the Losungen for the given date (or today if not defined) + */ + display() { + var visibleElems = document.getElementsByClassName("visible"); + Array.prototype.forEach.call(visibleElems, function(e) { + e.classList.remove("visible"); + }); + } + + /** + * react to the discovered distance of swipe + * + * @param distX Number distance in points in direction X + * @param distY Number distance in points in direction Y + * + * There is a preference for the horizontal swipe; if that doesn't + * happen (i.e., the distance travelled horizontally is less than + * negligible), then the vertical swipe (in either direction) means + * jump to today. + */ + handle_move(distX: number, distY: number) { + var negligible = 100; + console.log('distX = ' + distX); + console.log('distY = ' + distY); + + if (distX < -negligible) { + console.log("swipe left"); + this.next(); + } + else if (distX > negligible) { + console.log("swipe right"); + this.prev(); + } + } + + next() { + console.log("Next!"); + this.cur_section += 1; + this.display(); + } + + prev() { + console.log("Previous!"); + this.cur_section -= 1; + this.display(); + } + +} diff --git a/config.ts b/config.ts new file mode 100644 index 0000000..c316066 --- /dev/null +++ b/config.ts @@ -0,0 +1,6 @@ +/// <reference path="require.d.ts" /> +import * as hes from "hesla"; + +require([], () => { + var thisHesla = new hes.Hesla(); +}); diff --git a/hesla.ts b/hesla.ts new file mode 100644 index 0000000..c9eeac3 --- /dev/null +++ b/hesla.ts @@ -0,0 +1,168 @@ +/// <reference path='touchEvent.d.ts' /> + +import {ActivePage} from "activePage"; + +class ISODate extends Date { + constructor(dateStr?:string) { + super(dateStr); + } + + public toISODateString() { + function pad(n) { + return n < 10 ? '0' + n : n; + } + + return this.getFullYear() + '-' + pad(this.getMonth() + 1) + + '-' + pad(this.getDate()); + } +} + +export class Hesla extends ActivePage { + public cur_section = null; + + constructor(appName?:string) { + super(appName); + this.cur_section = null; + document.getElementById("czech_nav").addEventListener("click", + (evt) => { + localStorage.setItem("language", "cs"); + this.lang_reload(); + }, false); + + document.getElementById("german_nav").addEventListener("click", + (evt) => { + localStorage.setItem("language", "de"); + this.lang_reload(); + }, false); + + // requires IE 10, Opera 12.10, Safari 7, + // FIXME Android browser requires 4.4 and has only + // webkitHidden and the event is webkitvisibilitychange + if (typeof document.hidden !== "undefined") { + document.addEventListener("visibilitychange", + (evt) => { + if (! document.hidden) { + this.today(); + } + }, false); + } + } + + /** + * react to the discovered distance of swipe + * + * @param distX Number distance in points in direction X + * @param distY Number distance in points in direction Y + * + * There is a preference for the horizontal swipe; if that doesn't + * happen (i.e., the distance travelled horizontally is less than + * negligible), then the vertical swipe (in either direction) means + * jump to today. + */ + handle_move(distX, distY) { + var negligible = 100; + console.log('distX = ' + distX); + console.log('distY = ' + distY); + + if (distX < -negligible) { + console.log("swipe left"); + this.next(); + } + else if (distX > negligible) { + console.log("swipe right"); + this.prev(); + } + } + + // cur_watchword is actually just a virtual property, which is not stored anywhere and its + // accessor methods change the value of the cur_section property instead. + get cur_watchword() { + console.log(`this.cur_section = ${this.cur_section}`); + if (!this.cur_section) { + this.cur_section = new ISODate(); + } + + return this.cur_section; + } + + set cur_watchword(value) { + // Remove 'visible' style from the currently displayed psalm, if + // there is any + + this.cur_section = value; + + // set the parameter directly to avoid call to getter. + console.log('Displaying ' + this.cur_section); + this.display(); + } + + /** + * Display losungen for given day + * + * Displays the Losungen for the given date (or today if not defined) + */ + display() { + super.display(); + + console.log("cur_watchword = " + this.cur_watchword.toISODateString()); + document.getElementById(this.cur_watchword.toISODateString()). + classList.add("visible"); + + window.scroll(0, 0); + } + + today() { + console.log("jump to today!"); + this.cur_watchword = new ISODate(); + this.display(); + } + + shiftDate(shift) { + var cur_date = this.cur_watchword; + cur_date.setDate(cur_date.getDate() + shift); + this.cur_watchword = cur_date; + } + + next() { + console.log("Next day!"); + this.shiftDate(+1); + } + + prev() { + console.log("Previous day!"); + this.shiftDate(-1); + } + + // Switch langauge + /** + * Handler for the switch language event + * + * Switches the displayed langauge page according to the state stored + * in the localStorage.langauge variable which contains ISO code for + * the chosen language ('de' and 'cs' currently). + */ + lang_reload() { + var new_basename = "index.html", new_url = window.location.href, + old_basename = window.location.pathname.split("/").slice(-1)[0]; + console.log('old_basename = ' + old_basename); + + if (localStorage.getItem("language") && + (localStorage.getItem("language") === "de")) { + new_basename = "index_de.html"; + } + + console.log('new_basename = ' + new_basename); + if ((old_basename !== new_basename) || (window.location.pathname.length === 0)) { + new_url = window.location.href.replace(/(index[-\w]*\.html)?$/, + new_basename); + } + + if (window.location.href !== new_url) { + window.location.assign(new_url); + } + } +} + +var thisHesla = new Hesla(); +thisHesla.lang_reload(); +thisHesla.display(); diff --git a/require.d.ts b/require.d.ts new file mode 100644 index 0000000..5ac6d30 --- /dev/null +++ b/require.d.ts @@ -0,0 +1,330 @@ +// Type definitions for RequireJS 2.1.8 +// Project: http://requirejs.org/ +// Definitions by: Josh Baldwin <https://github.com/jbaldwin/> +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/* +require-2.1.8.d.ts may be freely distributed under the MIT license. + +Copyright (c) 2013 Josh Baldwin https://github.com/jbaldwin/require.d.ts + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +*/ + +interface RequireError extends Error { + + /** + * The error ID that maps to an ID on a web page. + **/ + requireType: string; + + /** + * Required modules. + **/ + requireModules: string[]; + + /** + * The original error, if there is one (might be null). + **/ + originalError: Error; +} + +interface RequireShim { + + /** + * List of dependencies. + **/ + deps?: string[]; + + /** + * Name the module will be exported as. + **/ + exports?: string; + + /** + * Initialize function with all dependcies passed in, + * if the function returns a value then that value is used + * as the module export value instead of the object + * found via the 'exports' string. + * @param dependencies + * @return + **/ + init?: (...dependencies: any[]) => any; +} + +interface RequireConfig { + + // The root path to use for all module lookups. + baseUrl?: string; + + // Path mappings for module names not found directly under + // baseUrl. + paths?: { [key: string]: any; }; + + // Dictionary of Shim's. + // does not cover case of key->string[] + shim?: { [key: string]: RequireShim; }; + + /** + * For the given module prefix, instead of loading the + * module with the given ID, substitude a different + * module ID. + * + * @example + * requirejs.config({ + * map: { + * 'some/newmodule': { + * 'foo': 'foo1.2' + * }, + * 'some/oldmodule': { + * 'foo': 'foo1.0' + * } + * } + * }); + **/ + map?: { + [id: string]: { + [id: string]: string; + }; + }; + + /** + * AMD configurations, use module.config() to access in + * define() functions + **/ + config?: { [id: string]: {}; }; + + /** + * Configures loading modules from CommonJS packages. + **/ + packages?: {}; + + /** + * The number of seconds to wait before giving up on loading + * a script. The default is 7 seconds. + **/ + waitSeconds?: number; + + /** + * A name to give to a loading context. This allows require.js + * to load multiple versions of modules in a page, as long as + * each top-level require call specifies a unique context string. + **/ + context?: string; + + /** + * An array of dependencies to load. + **/ + deps?: string[]; + + /** + * A function to pass to require that should be require after + * deps have been loaded. + * @param modules + **/ + callback?: (...modules: any[]) => void; + + /** + * If set to true, an error will be thrown if a script loads + * that does not call define() or have shim exports string + * value that can be checked. + **/ + enforceDefine?: boolean; + + /** + * If set to true, document.createElementNS() will be used + * to create script elements. + **/ + xhtml?: boolean; + + /** + * Extra query string arguments appended to URLs that RequireJS + * uses to fetch resources. Most useful to cachce bust when + * the browser or server is not configured correcty. + * + * @example + * urlArgs: "bust= + (new Date()).getTime() + **/ + urlArgs?: string; + + /** + * Specify the value for the type="" attribute used for script + * tags inserted into the document by RequireJS. Default is + * "text/javascript". To use Firefox's JavasScript 1.8 + * features, use "text/javascript;version=1.8". + **/ + scriptType?: string; + +} + +// todo: not sure what to do with this guy +interface RequireModule { + + /** + * + **/ + config(): {}; + +} + +/** +* +**/ +interface RequireMap { + + /** + * + **/ + prefix: string; + + /** + * + **/ + name: string; + + /** + * + **/ + parentMap: RequireMap; + + /** + * + **/ + url: string; + + /** + * + **/ + originalName: string; + + /** + * + **/ + fullName: string; +} + +interface Require { + + /** + * Configure require.js + **/ + config(config: RequireConfig): Require; + + /** + * CommonJS require call + * @param module Module to load + * @return The loaded module + */ + (module: string): any; + + /** + * Start the main app logic. + * Callback is optional. + * Can alternatively use deps and callback. + * @param modules Required modules to load. + **/ + (modules: string[]): void; + + /** + * @see Require() + * @param ready Called when required modules are ready. + **/ + (modules: string[], ready: Function): void; + + /** + * @see http://requirejs.org/docs/api.html#errbacks + * @param ready Called when required modules are ready. + **/ + (modules: string[], ready: Function, errback: Function): void; + + /** + * Generate URLs from require module + * @param module Module to URL + * @return URL string + **/ + toUrl(module: string): string; + + /** + * On Error override + * @param err + **/ + onError(err: RequireError, errback?: (err: RequireError) => void): void; + + /** + * Undefine a module + * @param module Module to undefine. + **/ + undef(module: string): void; + + /** + * Semi-private function, overload in special instance of undef() + **/ + onResourceLoad(context: Object, map: RequireMap, depArray: RequireMap[]): void; +} + +interface RequireDefine { + + /** + * Define Simple Name/Value Pairs + * @param config Dictionary of Named/Value pairs for the config. + **/ + (config: { [key: string]: any; }): void; + + /** + * Define function. + * @param func: The function module. + **/ + (func: () => any): void; + + /** + * Define function with dependencies. + * @param deps List of dependencies module IDs. + * @param ready Callback function when the dependencies are loaded. + * callback param deps module dependencies + * callback return module definition + **/ + (deps: string[], ready: Function): void; + + /** + * Define module with simplified CommonJS wrapper. + * @param ready + * callback require requirejs instance + * callback exports exports object + * callback module module + * callback return module definition + **/ + (ready: (require: Require, exports: { [key: string]: any; }, module: RequireModule) => any): void; + + /** + * Define a module with a name and dependencies. + * @param name The name of the module. + * @param deps List of dependencies module IDs. + * @param ready Callback function when the dependencies are loaded. + * callback deps module dependencies + * callback return module definition + **/ + (name: string, deps: string[], ready: Function): void; +} + +// Ambient declarations for 'require' and 'define' +declare var requirejs: Require; +declare var require: Require; +declare var define: RequireDefine; diff --git a/touchEvent.d.ts b/touchEvent.d.ts new file mode 100644 index 0000000..552e142 --- /dev/null +++ b/touchEvent.d.ts @@ -0,0 +1,83 @@ +interface TouchEvent extends UIEvent { + touches: TouchList; + targetTouches: TouchList; + changedTouches: TouchList; + altKey: boolean; + metaKey: boolean; + ctrlKey: boolean; + shiftKey: boolean; + rotation: number; + scale: number; + + // for iOS + initTouchEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, viewArg: Window, detailArg: number, screenXArg: number, screenYArg: number, clientXArg: number, clientYArg: number, ctrlKeyArg: boolean, altKeyArg: boolean, shiftKeyArg: boolean, metaKeyArg: boolean, touchesArg: TouchList, targetTouchesArg: TouchList, changedTouchesArg: TouchList, scale: number, rotation: number): void + + // for Android + initTouchEvent(touchesArg: TouchList, targetTouchesArg: TouchList, changedTouchesArg: TouchList, typeArg: string, Aview: Window, screenXArg: number, screenYArg: number, clientXArg: number, clientYArg: number, ctrlKeyArg: boolean, altKeyArg: boolean, shiftKeyArg: boolean, metaKeyArg: boolean); +} + +declare var TouchEvent: { + prototype: TouchEvent; + new (): TouchEvent; +} + +interface TouchList { + length: number; + [index: number]: Touch; + item: (index: number) => Touch; +} + +interface Touch { + identifier: number; + target: EventTarget; + screenX: number; + screenY: number; + clientX: number; + clientY: number; + pageX: number; + pageY: number; +} + +interface Window { + ontouchstart: (ev: TouchEvent) => any; + ontouchmove: (ev: TouchEvent) => any; + ontouchend: (ev: TouchEvent) => any; + ontouchcancel: (ev: TouchEvent) => any; + addEventListener(type: "touchstart", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchmove", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchend", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchcancel", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +} + +interface Document { + ontouchstart: (ev: TouchEvent) => any; + ontouchmove: (ev: TouchEvent) => any; + ontouchend: (ev: TouchEvent) => any; + ontouchcancel: (ev: TouchEvent) => any; + addEventListener(type: "touchstart", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchmove", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchend", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchcancel", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +} + +interface HTMLElement { + ontouchstart: (ev: TouchEvent) => any; + ontouchmove: (ev: TouchEvent) => any; + ontouchend: (ev: TouchEvent) => any; + ontouchcancel: (ev: TouchEvent) => any; + addEventListener(type: "touchstart", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchmove", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchend", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + addEventListener(type: "touchcancel", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +} + +declare var ontouchstart: (ev: TouchEvent) => any; +declare var ontouchmove: (ev: TouchEvent) => any; +declare var ontouchend: (ev: TouchEvent) => any; +declare var ontouchcancel: (ev: TouchEvent) => any; + +declare function addEventListener(type: "touchstart", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +declare function addEventListener(type: "touchmove", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +declare function addEventListener(type: "touchend", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; +declare function addEventListener(type: "touchcancel", listener: (ev: TouchEvent) => any, useCapture?: boolean): void; + |