aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@cepl.eu>2023-01-22 10:39:31 +0100
committerMatěj Cepl <mcepl@cepl.eu>2023-01-22 10:39:31 +0100
commit9e8931a65545595fea87132e77e70005556997d1 (patch)
treea619a1bdb3acf65a0e898a6e398ac7d9b6553e56
parent10516625853177b2b1ed01d054aca63ced9042d0 (diff)
downloadhesla-9e8931a65545595fea87132e77e70005556997d1.tar.gz
Basics of rewrite to TypeScript
-rw-r--r--Makefile8
-rw-r--r--activePage.ts119
-rw-r--r--config.ts6
-rw-r--r--hesla.ts168
-rw-r--r--require.d.ts330
-rw-r--r--touchEvent.d.ts83
6 files changed, 712 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index c174cb7..538b991 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
+