First alpha

This commit is contained in:
Fabian
2019-01-27 21:29:33 +01:00
commit 313f5aee97
41 changed files with 10856 additions and 0 deletions

55
src/helper/base64.ts Executable file
View File

@ -0,0 +1,55 @@
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Use a lookup table to find the index.
var lookup = new Uint8Array(256);
for (var i = 0; i < chars.length; i++) {
lookup[chars.charCodeAt(i)] = i;
}
export function encode(arraybuffer: ArrayBuffer | Uint8Array) {
var bytes = new Uint8Array(arraybuffer),
i, len = bytes.length, base64 = "";
for (i = 0; i < len; i += 3) {
base64 += chars[bytes[i] >> 2];
base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
base64 += chars[bytes[i + 2] & 63];
}
if ((len % 3) === 2) {
base64 = base64.substring(0, base64.length - 1) + "=";
} else if (len % 3 === 1) {
base64 = base64.substring(0, base64.length - 2) + "==";
}
return base64;
};
export function decode(base64: string) {
var bufferLength = base64.length * 0.75,
len = base64.length, i, p = 0,
encoded1, encoded2, encoded3, encoded4;
if (base64[base64.length - 1] === "=") {
bufferLength--;
if (base64[base64.length - 2] === "=") {
bufferLength--;
}
}
var arraybuffer = new ArrayBuffer(bufferLength),
bytes = new Uint8Array(arraybuffer);
for (i = 0; i < len; i += 4) {
encoded1 = lookup[base64.charCodeAt(i)];
encoded2 = lookup[base64.charCodeAt(i + 1)];
encoded3 = lookup[base64.charCodeAt(i + 2)];
encoded4 = lookup[base64.charCodeAt(i + 3)];
bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
}
return bytes;
}

104
src/helper/indexeddb.ts Executable file
View File

@ -0,0 +1,104 @@
import Lock from "./lock";
import { DB, openDb, Transaction } from "idb";
export default class IDB {
initLock = new Lock();
db: DB;
constructor(database: string, private stores: string[]) {
let lock = this.initLock.getLock();
lock.then(async l => {
let v = localStorage.getItem(database + "_version");
let version = 0;
if (v) version = Number(v)
let lastStoresS = localStorage.getItem(database + "_stores");
if (!lastStoresS) lastStoresS = "";
let lastStores = lastStoresS.split(",").filter(e => e !== "");
if (!stores.every(e => lastStores.indexOf(e) >= 0) || !lastStores.every(e => stores.indexOf(e) >= 0)) version++;
localStorage.setItem(database + "_version", version.toString());
localStorage.setItem(database + "_stores", stores.join(","));
this.db = await openDb(database, version, db => {
console.log("IndexedDB need update")
stores.forEach(store => {
if (!db.objectStoreNames.contains(store))
db.createObjectStore(store);
})
})
console.log("Got DATABASE", this.db)
l.release();
})
}
transaction(...stores: string[] | { name: string }[]) {
if (stores.length < 1) stores = this.stores;
let s: string[];
if (typeof stores[0] === "string")
s = <any>stores
else
s = (<any>stores).map(e => e.name)
return this.db.transaction(s, "readwrite")
}
getStore<T = any>(name: string) {
return {
name: name,
transaction: () => {
return this.db.transaction(name, "readwrite")
},
get: async (key: string, transaction?: Transaction): Promise<T> => {
(await this.initLock.getLock()).release()
return (transaction || this.db.transaction(name))
.objectStore(name).get(key);
},
getAll: async (transaction?: Transaction): Promise<T[]> => {
(await this.initLock.getLock()).release()
return (transaction || this.db.transaction(name))
.objectStore(name).getAll();
},
set: async (key: string, val: T, transaction?: Transaction) => {
(await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).put(val, key);
return tx.complete;
},
delete: async (key: string, transaction?: Transaction) => {
(await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).delete(key);
return tx.complete;
},
clear: async (transaction?: Transaction) => {
(await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name, "readwrite"));
tx.objectStore(name).clear();
return tx.complete;
},
keys: async (transaction?: Transaction): Promise<string[]> => {
(await this.initLock.getLock()).release()
const tx = (transaction || this.db.transaction(name));
const keys: string[] = [];
const store = tx.objectStore(name);
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
// openKeyCursor isn't supported by Safari, so we fall back
(store.iterateKeyCursor || store.iterateCursor).call(store, (cursor: any) => {
if (!cursor) return;
keys.push(cursor.key);
cursor.continue();
});
return tx.complete.then(() => keys);
}
}
}
}

36
src/helper/lock.ts Executable file
View File

@ -0,0 +1,36 @@
export type Release = { release: () => void };
export default class Lock {
private _locked: boolean = false;
get locked() {
return this._locked;
}
private toCome: (() => void)[] = [];
constructor() {
this.release = this.release.bind(this);
}
async getLock(): Promise<Release> {
if (!this._locked) return { release: this.lock() };
else {
return new Promise<Release>((resolve) => {
this.toCome.push(() => {
resolve({ release: this.lock() });
})
})
}
}
private lock() {
this._locked = true;
return this.release;
}
private async release() {
if (this.toCome.length > 0) {
this.toCome.shift()();
} else {
this._locked = false;
}
}
}

46
src/helper/observable.ts Executable file
View File

@ -0,0 +1,46 @@
export type ObserverCallback<T> = (data: T[]) => void;
export default class Observable<T = any> {
private subscriber: { callback: ObserverCallback<T>, one: boolean }[] = [];
private events: T[] = [];
private timeout = undefined;
constructor(private collect: boolean = true, private collect_intervall: number = 100) { }
getPublicApi() {
return {
subscribe: (callback: ObserverCallback<T>, one: boolean = false) => {
let oldcb = this.subscriber.find(e => e.callback === callback);
if (oldcb)
oldcb.one = one
else
this.subscriber.push({ callback, one })
},
unsubscribe: (callback: ObserverCallback<T>) => {
let idx = this.subscriber.findIndex(e => e.callback === callback);
if (idx >= 0) {
this.subscriber.splice(idx, 1);
}
}
}
}
send(data: T) {
if (!this.collect)
this.subscriber.forEach(e => e.callback([data]));
else {
this.events.push(data);
if (!this.timeout) {
this.timeout = setTimeout(() => {
this.subscriber.forEach(cb => {
if (cb.one)
this.events.forEach(e => cb.callback([e]));
else
cb.callback(this.events)
});
this.timeout = 0;
}, this.collect_intervall);
}
}
}
}

77
src/helper/swipe.tsx Executable file
View File

@ -0,0 +1,77 @@
import { Component, h, cloneElement } from 'preact';
export default class SwipeRecognizer extends Component<{ onSwipe?: (direction: string) => void }, { swipe: string }> {
private tolerance = 100;
private gesture = { x: [], y: [], match: '' };
componentDidMount() {
this.base.addEventListener('touchstart', this.capture);
this.base.addEventListener('touchmove', this.capture);
this.base.addEventListener('touchend', this.compute)
}
componentWillUnmount() {
this.base.removeEventListener('touchstart', this.capture);
this.base.removeEventListener('touchmove', this.capture);
this.base.removeEventListener('touchend', this.compute);
}
private capture = (event: TouchEvent) => {
// event.preventDefault()
this.gesture.x.push(event.touches[0].clientX)
this.gesture.y.push(event.touches[0].clientY)
};
private compute = (event: TouchEvent) => {
// event.preventDefault();
let xStart = this.gesture.x[0];
let yStart = this.gesture.y[0];
let xEnd = this.gesture.x.pop();
let yEnd = this.gesture.y.pop();
let xTravel = xEnd - xStart;
let yTravel = yEnd - yStart;
console.log(xTravel, yTravel);
let xTravel_b = xTravel < 0 ? xTravel * (-1) : xTravel;
let yTravel_b = yTravel < 0 ? yTravel * (-1) : yTravel;
console.log(xTravel_b, yTravel_b);
if (xTravel_b > yTravel_b) {
if (xTravel_b > this.tolerance) {
if (xTravel > 0) {
this.gesture.match = "right";
} else {
this.gesture.match = "left";
}
}
} else {
if (yTravel_b > this.tolerance) {
if (yTravel > 0) {
this.gesture.match = "down";
} else {
this.gesture.match = "up";
}
}
}
console.log(this.gesture.match);
if (this.gesture.match !== '') {
this.onSwipe(this.gesture.match);
}
this.gesture.x = []
this.gesture.y = []
this.gesture.match = '';
};
onSwipe = (direction: string) => {
if (this.props.onSwipe) {
this.props.onSwipe(direction);
}
this.setState({ swipe: direction });
};
render({ children }, state) {
return cloneElement(children[0], state);
}
}