kopia lustrzana https://github.com/FacilMap/facilmap
Convert facilmap-client to TypeScript
rodzic
df1fd8cfcc
commit
61c731788b
|
@ -3,4 +3,4 @@
|
|||
node_modules
|
||||
bower_components
|
||||
frontend/build
|
||||
client/build
|
||||
client/dist
|
|
@ -438,7 +438,7 @@ Get a fake line object for a line with the given type. This can be used so that
|
|||
that line already has the right style.
|
||||
|
||||
* `data` (`{typeId: <typeId>}`): An object containing the type ID
|
||||
* _returns_ (Promise<[line](#line-1)): A fake line object with the styles of this type
|
||||
* _returns_ (Promise<[line](#line-1)>): A fake line object with the styles of this type
|
||||
|
||||
### `addLine(data)`
|
||||
|
||||
|
@ -626,7 +626,7 @@ their `idx` property.
|
|||
* `id` (number): The ID of this history entry
|
||||
* `time` (Date): The time when the modification was done
|
||||
* `type` (string): The type of object that was modified, one of `Marker`, `Line`, `View`, `Type`, `Pad`
|
||||
* `action` (string): The action that was done, one of `create`, `update, `delete`
|
||||
* `action` (string): The action that was done, one of `create`, `update`, `delete`
|
||||
* `objectId` (number): The ID of the object that was modified (null if the object was the map itself)
|
||||
* `objectBefore` (object): The object before the modification (null if `action` is `create`)
|
||||
* `objectAfter` (object): The object after the modification (null if `action` is `delete`)
|
||||
|
@ -644,7 +644,7 @@ their `idx` property.
|
|||
* `name` (string): The name of the field. This is at the same time the key in the `data` properties of markers and lines
|
||||
* `oldName` (string): When renaming a field (using [`editType(data)`](#edittypedata)), specify the former name here
|
||||
* `type` (string): The type of field, one of `textarea`, `dropdown`, `checkbox`, `input`
|
||||
* `controlColour`, `controlSize`, `controlSymbol`, `controlWidth` (boolean): If this field is a dropdown, whether
|
||||
* `controlColour`, `controlSize`, `controlSymbol`, `controlShape`, `controlWidth` (boolean): If this field is a dropdown, whether
|
||||
the different options set a specific property on the object
|
||||
* `default` (string/boolean): The default value of this field
|
||||
* `options` ([object]): If this field is a dropdown, an array of objects with the following properties:
|
||||
|
|
399
client/client.js
399
client/client.js
|
@ -1,399 +0,0 @@
|
|||
const io = require("socket.io-client");
|
||||
const Promise = require("es6-promise").Promise;
|
||||
|
||||
class Socket {
|
||||
constructor(server, padId) {
|
||||
this._init(server, padId);
|
||||
}
|
||||
|
||||
_init(server, padId) {
|
||||
// Needs to be in a separate method so that we can merge this class with a scope object in the frontend.
|
||||
|
||||
this.server = server;
|
||||
this.padId = padId;
|
||||
|
||||
this.socket = io.connect(server, { 'force new connection': true });
|
||||
|
||||
this.padData = null;
|
||||
this.readonly = null;
|
||||
this.writable = null;
|
||||
this.deleted = false;
|
||||
this.markers = { };
|
||||
this.lines = { };
|
||||
this.views = { };
|
||||
this.types = { };
|
||||
this.history = { };
|
||||
this.route = null;
|
||||
|
||||
this._listeners = [ ];
|
||||
|
||||
for(let i in this._handlers) {
|
||||
this.on(i, this._handlers[i].bind(this));
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this._simulateEvent("loadStart");
|
||||
}, 0);
|
||||
this.once("connect", () => {
|
||||
this._simulateEvent("loadEnd");
|
||||
});
|
||||
}
|
||||
|
||||
on(eventName, fn) {
|
||||
if(typeof this._listeners[eventName] != "object") {
|
||||
this._listeners[eventName] = [ ];
|
||||
this.socket.on(eventName, this._simulateEvent.bind(this, eventName));
|
||||
}
|
||||
|
||||
this._listeners[eventName].push(fn);
|
||||
}
|
||||
|
||||
once(eventName, fn) {
|
||||
let handler = (data) => {
|
||||
this.removeListener(eventName, handler);
|
||||
fn(data);
|
||||
};
|
||||
this.on(eventName, handler);
|
||||
}
|
||||
|
||||
removeListener(eventName, fn) {
|
||||
if(typeof this._listeners[eventName] == "object") {
|
||||
this._listeners[eventName] = this._listeners[eventName].filter((listener) => (listener !== fn));
|
||||
}
|
||||
}
|
||||
|
||||
_emit(eventName, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._simulateEvent("loadStart");
|
||||
|
||||
this.socket.emit(eventName, data, (err, data) => {
|
||||
this._simulateEvent("loadEnd");
|
||||
|
||||
if(err)
|
||||
reject(err);
|
||||
else
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setPadId(padId) {
|
||||
if(this.padId != null)
|
||||
throw new Error("Pad ID already set.");
|
||||
|
||||
return this._setPadId(padId);
|
||||
}
|
||||
|
||||
updateBbox(bbox) {
|
||||
this.bbox = bbox;
|
||||
return this._emit("updateBbox", bbox).then((obj) => {
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
createPad(data) {
|
||||
return this._emit("createPad", data).then((obj) => {
|
||||
this.readonly = false;
|
||||
this.writable = 2;
|
||||
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
editPad(data) {
|
||||
return this._emit("editPad", data);
|
||||
}
|
||||
|
||||
deletePad() {
|
||||
return this._emit("deletePad");
|
||||
}
|
||||
|
||||
listenToHistory() {
|
||||
return this._emit("listenToHistory").then((obj) => {
|
||||
this._listeningToHistory = true;
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
stopListeningToHistory() {
|
||||
this._listeningToHistory = false;
|
||||
return this._emit("stopListeningToHistory");
|
||||
}
|
||||
|
||||
revertHistoryEntry(data) {
|
||||
return this._emit("revertHistoryEntry", data).then((obj) => {
|
||||
this.history = { };
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
async getMarker(data) {
|
||||
let marker = await this._emit("getMarker", data);
|
||||
this.markers[marker.id] = marker;
|
||||
return marker;
|
||||
}
|
||||
|
||||
addMarker(data) {
|
||||
return this._emit("addMarker", data);
|
||||
}
|
||||
|
||||
editMarker(data) {
|
||||
return this._emit("editMarker", data);
|
||||
}
|
||||
|
||||
deleteMarker(data) {
|
||||
return this._emit("deleteMarker", data);
|
||||
}
|
||||
|
||||
getLineTemplate(data) {
|
||||
return this._emit("getLineTemplate", data);
|
||||
}
|
||||
|
||||
addLine(data) {
|
||||
return this._emit("addLine", data);
|
||||
}
|
||||
|
||||
editLine(data) {
|
||||
return this._emit("editLine", data);
|
||||
}
|
||||
|
||||
deleteLine(data) {
|
||||
return this._emit("deleteLine", data);
|
||||
}
|
||||
|
||||
exportLine(data) {
|
||||
return this._emit("exportLine", data);
|
||||
}
|
||||
|
||||
find(data) {
|
||||
return this._emit("find", data);
|
||||
}
|
||||
|
||||
findOnMap(data) {
|
||||
return this._emit("findOnMap", data);
|
||||
}
|
||||
|
||||
getRoute(data) {
|
||||
return this._emit("getRoute", data);
|
||||
}
|
||||
|
||||
setRoute(data) {
|
||||
return this._emit("setRoute", data).then((route) => {
|
||||
if(route) { // If unset, a newer submitted route has returned in the meantime
|
||||
this.route = route;
|
||||
this.route.trackPoints = this._mergeTrackPoints({}, route.trackPoints);
|
||||
}
|
||||
|
||||
return this.route;
|
||||
});
|
||||
}
|
||||
|
||||
clearRoute() {
|
||||
this.route = null;
|
||||
return this._emit("clearRoute");
|
||||
}
|
||||
|
||||
lineToRoute(data) {
|
||||
return this._emit("lineToRoute", data).then((route) => {
|
||||
this.route = route;
|
||||
this.route.trackPoints = this._mergeTrackPoints({}, route.trackPoints);
|
||||
|
||||
return this.route;
|
||||
});
|
||||
}
|
||||
|
||||
exportRoute(data) {
|
||||
return this._emit("exportRoute", data);
|
||||
}
|
||||
|
||||
addType(data) {
|
||||
return this._emit("addType", data);
|
||||
}
|
||||
|
||||
editType(data) {
|
||||
return this._emit("editType", data);
|
||||
}
|
||||
|
||||
deleteType(data) {
|
||||
return this._emit("deleteType", data);
|
||||
}
|
||||
|
||||
addView(data) {
|
||||
return this._emit("addView", data);
|
||||
}
|
||||
|
||||
editView(data) {
|
||||
return this._emit("editView", data);
|
||||
}
|
||||
|
||||
deleteView(data) {
|
||||
return this._emit("deleteView", data);
|
||||
}
|
||||
|
||||
geoip() {
|
||||
return this._emit("geoip");
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.socket.removeAllListeners();
|
||||
this.socket.disconnect();
|
||||
}
|
||||
|
||||
_setPadId(padId) {
|
||||
this.padId = padId;
|
||||
return this._emit("setPadId", padId).then((obj) => {
|
||||
this.disconnected = false;
|
||||
|
||||
this._receiveMultiple(obj);
|
||||
}).catch((err) => {
|
||||
this.serverError = err;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
_receiveMultiple(obj) {
|
||||
for(let i in obj || { })
|
||||
obj[i].forEach((it) => { this._simulateEvent(i, it); });
|
||||
}
|
||||
|
||||
_simulateEvent(eventName, data) {
|
||||
if(typeof this._listeners[eventName] == "object") {
|
||||
this._listeners[eventName].forEach(function(listener) {
|
||||
listener(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_mergeTrackPoints(existingTrackPoints, newTrackPoints) {
|
||||
let ret = existingTrackPoints ? Object.assign({}, existingTrackPoints) : {};
|
||||
|
||||
for(let i=0; i<newTrackPoints.length; i++) {
|
||||
ret[newTrackPoints[i].idx] = newTrackPoints[i];
|
||||
}
|
||||
|
||||
ret.length = 0;
|
||||
for(let i in ret) {
|
||||
if(i != "length" && i >= ret.length)
|
||||
ret.length = 1*i+1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Socket.prototype._handlers = {
|
||||
padData(data) {
|
||||
this.padData = data;
|
||||
|
||||
if(data.writable != null) {
|
||||
this.readonly = (data.writable == 0);
|
||||
this.writable = data.writable;
|
||||
}
|
||||
|
||||
let id = this.writable == 2 ? data.adminId : this.writable == 1 ? data.writeId : data.id;
|
||||
if(id != null)
|
||||
this.padId = id;
|
||||
},
|
||||
|
||||
deletePad() {
|
||||
this.readonly = true;
|
||||
this.writable = 0;
|
||||
this.deleted = true;
|
||||
},
|
||||
|
||||
marker(data) {
|
||||
if(this.markers[data.id] == null)
|
||||
this.markers[data.id] = { };
|
||||
|
||||
this.markers[data.id] = data;
|
||||
},
|
||||
|
||||
deleteMarker(data) {
|
||||
delete this.markers[data.id];
|
||||
},
|
||||
|
||||
line(data) {
|
||||
if(this.lines[data.id])
|
||||
data.trackPoints = this.lines[data.id].trackPoints;
|
||||
else
|
||||
this.lines[data.id] = { };
|
||||
|
||||
this.lines[data.id] = data;
|
||||
},
|
||||
|
||||
deleteLine(data) {
|
||||
delete this.lines[data.id];
|
||||
},
|
||||
|
||||
linePoints(data) {
|
||||
let line = this.lines[data.id];
|
||||
if(line == null)
|
||||
return console.error("Received line points for non-existing line "+data.id+".");
|
||||
|
||||
line.trackPoints = this._mergeTrackPoints(data.reset ? {} : line.trackPoints, data.trackPoints);
|
||||
},
|
||||
|
||||
routePoints(data) {
|
||||
if(!this.route) {
|
||||
console.error("Received route points for non-existing route.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.route.trackPoints = this._mergeTrackPoints(this.route.trackPoints, data);
|
||||
},
|
||||
|
||||
view(data) {
|
||||
if(this.views[data.id] == null)
|
||||
this.views[data.id] = { };
|
||||
|
||||
this.views[data.id] = data;
|
||||
},
|
||||
|
||||
deleteView(data) {
|
||||
delete this.views[data.id];
|
||||
if(this.padData.defaultViewId == data.id)
|
||||
this.padData.defaultViewId = null;
|
||||
},
|
||||
|
||||
type(data) {
|
||||
if(this.types[data.id] == null)
|
||||
this.types[data.id] = { };
|
||||
|
||||
this.types[data.id] = data;
|
||||
},
|
||||
|
||||
deleteType(data) {
|
||||
delete this.types[data.id];
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
this.disconnected = true;
|
||||
this.markers = { };
|
||||
this.lines = { };
|
||||
this.views = { };
|
||||
this.history = { };
|
||||
},
|
||||
|
||||
connect() {
|
||||
if(this.padId)
|
||||
this._setPadId(this.padId);
|
||||
else
|
||||
this.disconnected = false; // Otherwise it gets set when padData arrives
|
||||
|
||||
if(this.bbox)
|
||||
this.updateBbox(this.bbox);
|
||||
|
||||
if(this._listeningToHistory) // TODO: Execute after setPadId() returns
|
||||
this.listenToHistory().catch(function(err) { console.error("Error listening to history", err); });
|
||||
|
||||
if(this.route)
|
||||
this.setRoute(this.route);
|
||||
},
|
||||
|
||||
history(data) {
|
||||
this.history[data.id] = data;
|
||||
// TODO: Limit to 50 entries
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Socket;
|
Plik diff jest za duży
Load Diff
|
@ -14,27 +14,30 @@
|
|||
},
|
||||
"license": "AGPL-3.0",
|
||||
"author": "Candid Dauth <cdauth@cdauth.eu>",
|
||||
"main": "./client.js",
|
||||
"main": "./dist/client.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FacilMap/facilmap2.git"
|
||||
},
|
||||
"scripts": {
|
||||
"deps": "npm install",
|
||||
"build": "webpack",
|
||||
"clean": "rimraf ./build"
|
||||
"watch": "webpack --watch",
|
||||
"clean": "rimraf dist",
|
||||
"dev-server": "webpack-dev-server --mode development"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/geojson": "^7946.0.7",
|
||||
"es6-promise": "^4.2.5",
|
||||
"facilmap-types": "2.7.0",
|
||||
"socket.io-client": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"babel-loader": "^8.1.0",
|
||||
"expose-loader": "^0.7.5",
|
||||
"@types/socket.io-client": "^1.4.32",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-loader": "^6.2.1",
|
||||
"typescript": "^3.8.3",
|
||||
"webpack": "^4.42.1",
|
||||
"webpack-bundle-analyzer": "^3.6.1",
|
||||
"webpack-cli": "^3.3.11"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,460 @@
|
|||
import io from "socket.io-client";
|
||||
import { Promise as PromiseShim } from "es6-promise";
|
||||
import {
|
||||
Bbox, EventData, EventDataParams, EventHandler, EventName, FindOnMapQuery, FindQuery, HistoryEntry, ID, Line, LineCreate,
|
||||
LineExportRequest, LineTemplateRequest, LineUpdate, Marker, MarkerCreate, MarkerUpdate, MultipleEvents, ObjectWithId,
|
||||
PadData, PadDataCreate, PadDataUpdate, PadId, RequestData, RequestName, ResponseData, Route, RouteCreate, RouteExportRequest,
|
||||
TrackPoint, Type, TypeCreate, TypeUpdate, View, ViewCreate, ViewUpdate, Writable
|
||||
} from "facilmap-types";
|
||||
|
||||
declare module "facilmap-types/src/events" {
|
||||
interface EventMap {
|
||||
connect: void,
|
||||
connect_error: Error;
|
||||
connect_timeout: void;
|
||||
reconnect: number;
|
||||
reconnect_attempt: number;
|
||||
reconnecting: number;
|
||||
reconnect_error: Error;
|
||||
reconnect_failed: void;
|
||||
disconnect: void,
|
||||
loadStart: void,
|
||||
loadEnd: void
|
||||
}
|
||||
}
|
||||
|
||||
export interface TrackPoints {
|
||||
[idx: number]: TrackPoint;
|
||||
length: number
|
||||
}
|
||||
|
||||
export interface LineWithTrackPoints extends Line {
|
||||
trackPoints: TrackPoints;
|
||||
}
|
||||
|
||||
export interface RouteWithTrackPoints extends Omit<Route, "trackPoints"> {
|
||||
trackPoints: TrackPoints;
|
||||
}
|
||||
|
||||
export default class Socket {
|
||||
disconnected!: boolean;
|
||||
server!: string;
|
||||
padId!: string;
|
||||
bbox!: Bbox | null;
|
||||
socket!: SocketIOClient.Socket;
|
||||
padData!: PadData | null;
|
||||
readonly!: boolean | null;
|
||||
writable!: Writable | null;
|
||||
deleted!: boolean;
|
||||
markers!: Record<ID, Marker>;
|
||||
lines!: Record<ID, LineWithTrackPoints>;
|
||||
views!: Record<ID, View>;
|
||||
types!: Record<ID, Type>;
|
||||
history!: Record<ID, HistoryEntry>;
|
||||
route!: RouteWithTrackPoints | null;
|
||||
serverError!: Error | null;
|
||||
|
||||
_listeners!: {
|
||||
[E in EventName]?: Array<EventHandler<E>>
|
||||
};
|
||||
_listeningToHistory!: boolean;
|
||||
|
||||
constructor(server: string, padId: string) {
|
||||
this._init(server, padId);
|
||||
}
|
||||
|
||||
_init(server: string, padId: string) {
|
||||
// Needs to be in a separate method so that we can merge this class with a scope object in the frontend.
|
||||
|
||||
this.server = server;
|
||||
this.padId = padId;
|
||||
this.bbox = null;
|
||||
this.serverError = null;
|
||||
|
||||
this.disconnected = true;
|
||||
this.socket = io.connect(server, { forceNew: true });
|
||||
|
||||
this.padData = null;
|
||||
this.readonly = null;
|
||||
this.writable = null;
|
||||
this.deleted = false;
|
||||
this.markers = { };
|
||||
this.lines = { };
|
||||
this.views = { };
|
||||
this.types = { };
|
||||
this.history = { };
|
||||
this.route = null;
|
||||
|
||||
this._listeners = { };
|
||||
this._listeningToHistory = false;
|
||||
|
||||
for(let i of Object.keys(this._handlers) as EventName[]) {
|
||||
this.on(i, this._handlers[i] as EventHandler<typeof i>);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this._simulateEvent("loadStart");
|
||||
}, 0);
|
||||
this.once("connect", () => {
|
||||
this._simulateEvent("loadEnd");
|
||||
});
|
||||
}
|
||||
|
||||
on<E extends EventName>(eventName: E, fn: EventHandler<E>) {
|
||||
let listeners = this._listeners[eventName] as Array<EventHandler<E>> | undefined;
|
||||
if(!listeners) {
|
||||
listeners = this._listeners[eventName] = [ ];
|
||||
this.socket.on(eventName, (data: EventData<E>) => { this._simulateEvent(eventName as any, data); });
|
||||
}
|
||||
|
||||
listeners.push(fn);
|
||||
}
|
||||
|
||||
once<E extends EventName>(eventName: E, fn: EventHandler<E>) {
|
||||
let handler: EventHandler<E> = (data) => {
|
||||
this.removeListener(eventName, handler);
|
||||
fn(data);
|
||||
};
|
||||
this.on(eventName, handler);
|
||||
}
|
||||
|
||||
removeListener<E extends EventName>(eventName: E, fn: EventHandler<E>) {
|
||||
const listeners = this._listeners[eventName] as Array<EventHandler<E>> | undefined;
|
||||
if(listeners) {
|
||||
this._listeners[eventName] = listeners.filter((listener) => (listener !== fn)) as any;
|
||||
}
|
||||
}
|
||||
|
||||
_emit<R extends RequestName>(eventName: R, ...[data]: RequestData<R> extends void ? [ ] : [ RequestData<R> ]): PromiseShim<ResponseData<R>> {
|
||||
return new PromiseShim((resolve, reject) => {
|
||||
this._simulateEvent("loadStart");
|
||||
|
||||
this.socket.emit(eventName, data, (err: Error, data: ResponseData<R>) => {
|
||||
this._simulateEvent("loadEnd");
|
||||
|
||||
if(err)
|
||||
reject(err);
|
||||
else
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_handlers: {
|
||||
[E in EventName]?: EventHandler<E>
|
||||
} = {
|
||||
padData: (data) => {
|
||||
this.padData = data;
|
||||
|
||||
if(data.writable != null) {
|
||||
this.readonly = (data.writable == 0);
|
||||
this.writable = data.writable;
|
||||
}
|
||||
|
||||
let id = this.writable == 2 ? data.adminId : this.writable == 1 ? data.writeId : data.id;
|
||||
if(id != null)
|
||||
this.padId = id;
|
||||
},
|
||||
|
||||
deletePad: () => {
|
||||
this.readonly = true;
|
||||
this.writable = 0;
|
||||
this.deleted = true;
|
||||
},
|
||||
|
||||
marker: (data) => {
|
||||
this.markers[data.id] = data;
|
||||
},
|
||||
|
||||
deleteMarker: (data) => {
|
||||
delete this.markers[data.id];
|
||||
},
|
||||
|
||||
line: (data) => {
|
||||
this.lines[data.id] = {
|
||||
...data,
|
||||
trackPoints: this.lines[data.id]?.trackPoints || { }
|
||||
};
|
||||
},
|
||||
|
||||
deleteLine: (data) => {
|
||||
delete this.lines[data.id];
|
||||
},
|
||||
|
||||
linePoints: (data) => {
|
||||
let line = this.lines[data.id];
|
||||
if(line == null)
|
||||
return console.error("Received line points for non-existing line "+data.id+".");
|
||||
|
||||
line.trackPoints = this._mergeTrackPoints(data.reset ? {} : line.trackPoints, data.trackPoints);
|
||||
},
|
||||
|
||||
routePoints: (data) => {
|
||||
if(!this.route) {
|
||||
console.error("Received route points for non-existing route.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.route.trackPoints = this._mergeTrackPoints(this.route.trackPoints, data);
|
||||
},
|
||||
|
||||
view: (data) => {
|
||||
this.views[data.id] = data;
|
||||
},
|
||||
|
||||
deleteView: (data) => {
|
||||
delete this.views[data.id];
|
||||
if (this.padData) {
|
||||
if(this.padData.defaultViewId == data.id)
|
||||
this.padData.defaultViewId = null;
|
||||
}
|
||||
},
|
||||
|
||||
type: (data) => {
|
||||
this.types[data.id] = data;
|
||||
},
|
||||
|
||||
deleteType: (data) => {
|
||||
delete this.types[data.id];
|
||||
},
|
||||
|
||||
disconnect: () => {
|
||||
this.disconnected = true;
|
||||
this.markers = { };
|
||||
this.lines = { };
|
||||
this.views = { };
|
||||
this.history = { };
|
||||
},
|
||||
|
||||
connect: () => {
|
||||
if(this.padId)
|
||||
this._setPadId(this.padId);
|
||||
else
|
||||
this.disconnected = false; // Otherwise it gets set when padData arrives
|
||||
|
||||
if(this.bbox)
|
||||
this.updateBbox(this.bbox);
|
||||
|
||||
if(this._listeningToHistory) // TODO: Execute after setPadId() returns
|
||||
this.listenToHistory().catch(function(err) { console.error("Error listening to history", err); });
|
||||
|
||||
if(this.route)
|
||||
this.setRoute(this.route);
|
||||
},
|
||||
|
||||
history: (data) => {
|
||||
this.history[data.id] = data;
|
||||
// TODO: Limit to 50 entries
|
||||
}
|
||||
};
|
||||
|
||||
setPadId(padId: PadId) {
|
||||
if(this.padId != null)
|
||||
throw new Error("Pad ID already set.");
|
||||
|
||||
return this._setPadId(padId);
|
||||
}
|
||||
|
||||
updateBbox(bbox: Bbox) {
|
||||
this.bbox = bbox;
|
||||
return this._emit("updateBbox", bbox).then((obj) => {
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
createPad(data: PadDataCreate) {
|
||||
return this._emit("createPad", data).then((obj) => {
|
||||
this.readonly = false;
|
||||
this.writable = 2;
|
||||
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
editPad(data: PadDataUpdate) {
|
||||
return this._emit("editPad", data);
|
||||
}
|
||||
|
||||
deletePad() {
|
||||
return this._emit("deletePad");
|
||||
}
|
||||
|
||||
listenToHistory() {
|
||||
return this._emit("listenToHistory").then((obj) => {
|
||||
this._listeningToHistory = true;
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
stopListeningToHistory() {
|
||||
this._listeningToHistory = false;
|
||||
return this._emit("stopListeningToHistory");
|
||||
}
|
||||
|
||||
revertHistoryEntry(data: ObjectWithId) {
|
||||
return this._emit("revertHistoryEntry", data).then((obj) => {
|
||||
this.history = { };
|
||||
this._receiveMultiple(obj);
|
||||
});
|
||||
}
|
||||
|
||||
async getMarker(data: ObjectWithId) {
|
||||
let marker = await this._emit("getMarker", data);
|
||||
this.markers[marker.id] = marker;
|
||||
return marker;
|
||||
}
|
||||
|
||||
addMarker(data: MarkerCreate) {
|
||||
return this._emit("addMarker", data);
|
||||
}
|
||||
|
||||
editMarker(data: MarkerUpdate) {
|
||||
return this._emit("editMarker", data);
|
||||
}
|
||||
|
||||
deleteMarker(data: ObjectWithId) {
|
||||
return this._emit("deleteMarker", data);
|
||||
}
|
||||
|
||||
getLineTemplate(data: LineTemplateRequest) {
|
||||
return this._emit("getLineTemplate", data);
|
||||
}
|
||||
|
||||
addLine(data: LineCreate) {
|
||||
return this._emit("addLine", data);
|
||||
}
|
||||
|
||||
editLine(data: LineUpdate) {
|
||||
return this._emit("editLine", data);
|
||||
}
|
||||
|
||||
deleteLine(data: ObjectWithId) {
|
||||
return this._emit("deleteLine", data);
|
||||
}
|
||||
|
||||
exportLine(data: LineExportRequest) {
|
||||
return this._emit("exportLine", data);
|
||||
}
|
||||
|
||||
find(data: FindQuery) {
|
||||
return this._emit("find", data);
|
||||
}
|
||||
|
||||
findOnMap(data: FindOnMapQuery) {
|
||||
return this._emit("findOnMap", data);
|
||||
}
|
||||
|
||||
getRoute(data: RouteCreate) {
|
||||
return this._emit("getRoute", data);
|
||||
}
|
||||
|
||||
setRoute(data: RouteCreate) {
|
||||
return this._emit("setRoute", data).then((route) => {
|
||||
if(route) { // If unset, a newer submitted route has returned in the meantime
|
||||
this.route = {
|
||||
...route,
|
||||
trackPoints: this._mergeTrackPoints({}, route.trackPoints)
|
||||
};
|
||||
}
|
||||
|
||||
return this.route;
|
||||
});
|
||||
}
|
||||
|
||||
clearRoute() {
|
||||
this.route = null;
|
||||
return this._emit("clearRoute");
|
||||
}
|
||||
|
||||
lineToRoute(data: ObjectWithId) {
|
||||
return this._emit("lineToRoute", data).then((route) => {
|
||||
this.route = {
|
||||
...route,
|
||||
trackPoints: this._mergeTrackPoints({}, route.trackPoints)
|
||||
};
|
||||
|
||||
return this.route;
|
||||
});
|
||||
}
|
||||
|
||||
exportRoute(data: RouteExportRequest) {
|
||||
return this._emit("exportRoute", data);
|
||||
}
|
||||
|
||||
addType(data: TypeCreate) {
|
||||
return this._emit("addType", data);
|
||||
}
|
||||
|
||||
editType(data: TypeUpdate) {
|
||||
return this._emit("editType", data);
|
||||
}
|
||||
|
||||
deleteType(data: ObjectWithId) {
|
||||
return this._emit("deleteType", data);
|
||||
}
|
||||
|
||||
addView(data: ViewCreate) {
|
||||
return this._emit("addView", data);
|
||||
}
|
||||
|
||||
editView(data: ViewUpdate) {
|
||||
return this._emit("editView", data);
|
||||
}
|
||||
|
||||
deleteView(data: ObjectWithId) {
|
||||
return this._emit("deleteView", data);
|
||||
}
|
||||
|
||||
geoip() {
|
||||
return this._emit("geoip");
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.socket.removeAllListeners();
|
||||
this.socket.disconnect();
|
||||
}
|
||||
|
||||
_setPadId(padId: string) {
|
||||
this.padId = padId;
|
||||
return this._emit("setPadId", padId).then((obj) => {
|
||||
this.disconnected = false;
|
||||
|
||||
this._receiveMultiple(obj);
|
||||
}).catch((err) => {
|
||||
this.serverError = err;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
_receiveMultiple(obj?: MultipleEvents) {
|
||||
if (obj) {
|
||||
for(const i of Object.keys(obj) as EventName[])
|
||||
(obj[i] as Array<EventData<typeof i>>).forEach((it) => { this._simulateEvent(i, it); });
|
||||
}
|
||||
}
|
||||
|
||||
_simulateEvent<E extends EventName>(eventName: E, ...[data]: EventDataParams<E>) {
|
||||
const listeners = this._listeners[eventName] as Array<EventHandler<E>> | undefined;
|
||||
if(listeners) {
|
||||
listeners.forEach(function(listener: EventHandler<E>) {
|
||||
listener(data as EventData<E>);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_mergeTrackPoints(existingTrackPoints: Record<number, TrackPoint> | null, newTrackPoints: TrackPoint[]) {
|
||||
let ret = { ...(existingTrackPoints || { }) } as TrackPoints;
|
||||
|
||||
for(let i=0; i<newTrackPoints.length; i++) {
|
||||
ret[newTrackPoints[i].idx] = newTrackPoints[i];
|
||||
}
|
||||
|
||||
ret.length = 0;
|
||||
for(let i in ret) {
|
||||
if(i != "length")
|
||||
ret.length = Math.max(ret.length, parseInt(i) + 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es3",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
}
|
|
@ -1,24 +1,40 @@
|
|||
const webpack = require("webpack");
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
||||
module.exports = {
|
||||
entry: `expose-loader?FacilMap.Client!${__dirname}/client.js`,
|
||||
output: {
|
||||
filename: "client.js",
|
||||
path: __dirname + "/build/"
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [ "@babel/preset-env" ]
|
||||
}
|
||||
module.exports = (env, argv) => {
|
||||
const isDev = argv.mode == "development";
|
||||
|
||||
return {
|
||||
entry: `${__dirname}/src/client.ts`,
|
||||
output: {
|
||||
filename: "client.js",
|
||||
path: __dirname + "/dist/",
|
||||
library: "FacilMap.Client",
|
||||
libraryTarget: "umd"
|
||||
},
|
||||
resolve: {
|
||||
extensions: [ ".js", ".ts" ]
|
||||
},
|
||||
mode: isDev ? "development" : "production",
|
||||
devtool: isDev ? "cheap-eval-source-map" : "source-map",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
resource: { and: [ /\.ts/, [
|
||||
__dirname + "/src/"
|
||||
] ] },
|
||||
loader: 'ts-loader'
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [ 'style-loader', 'css-loader' ]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
mode: "production",
|
||||
devtool: "source-map"
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
//new BundleAnalyzerPlugin()
|
||||
],
|
||||
devServer: {
|
||||
publicPath: "/dist"
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -96,8 +96,5 @@
|
|||
"webpack-bundle-analyzer": "^3.7.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-hot-middleware": "^2.24.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/leaflet": "1.6.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "facilmap-types",
|
||||
"version": "2.7.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/geojson": {
|
||||
"version": "7946.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
|
||||
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ=="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "facilmap-types",
|
||||
"version": "2.7.0",
|
||||
"description": "Typescript typings for the FacilMap communication between client and server.",
|
||||
"homepage": "https://github.com/FacilMap/facilmap2",
|
||||
"bugs": {
|
||||
"url": "https://github.com/FacilMap/facilmap2/issues"
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"author": "Candid Dauth <cdauth@cdauth.eu>",
|
||||
"main": "./src/index.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FacilMap/facilmap2.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/geojson": "^7946.0.7"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
export type Latitude = number;
|
||||
export type Longitude = number;
|
||||
export type ZoomLevel = number;
|
||||
export type Colour = string;
|
||||
export type Symbol = string;
|
||||
export type Shape = "" | "drop" | "circle";
|
||||
export type ID = number;
|
||||
export type RouteMode = string;
|
||||
export type Layer = string;
|
||||
export type ExportFormat = "gpx-trk" | "gpx-rte";
|
||||
|
||||
export interface Point {
|
||||
lat: Latitude;
|
||||
lon: Longitude;
|
||||
}
|
||||
|
||||
export interface Bbox {
|
||||
top: Latitude;
|
||||
bottom: Latitude;
|
||||
left: Longitude;
|
||||
right: Longitude;
|
||||
}
|
||||
|
||||
export interface BboxWithZoom extends Bbox {
|
||||
zoom: ZoomLevel;
|
||||
}
|
||||
|
||||
export type ObjectWithId = {
|
||||
id: ID;
|
||||
}
|
||||
|
||||
export type AllOptionalExceptId<T extends ObjectWithId> = Pick<T, "id"> & Partial<Omit<T, "id">>;
|
|
@ -0,0 +1,43 @@
|
|||
import { ID, ObjectWithId } from "./base";
|
||||
import { Type } from "./type";
|
||||
import { HistoryEntry } from "./historyEntry";
|
||||
import { View } from "./view";
|
||||
import { Line, TrackPoint } from "./line";
|
||||
import { Marker } from "./marker";
|
||||
import { PadData } from "./padData";
|
||||
|
||||
export interface LinePointsEvent {
|
||||
id: ID;
|
||||
reset: boolean;
|
||||
trackPoints: TrackPoint[];
|
||||
}
|
||||
|
||||
export interface EventMap {
|
||||
padData: PadData;
|
||||
deletePad: void;
|
||||
marker: Marker;
|
||||
deleteMarker: ObjectWithId;
|
||||
line: Line;
|
||||
deleteLine: ObjectWithId;
|
||||
linePoints: LinePointsEvent;
|
||||
routePoints: TrackPoint[];
|
||||
view: View;
|
||||
deleteView: ObjectWithId;
|
||||
type: Type;
|
||||
deleteType: ObjectWithId;
|
||||
history: HistoryEntry;
|
||||
}
|
||||
|
||||
export type EventName = keyof EventMap;
|
||||
export type EventData<E extends EventName> = EventMap[E];
|
||||
export type EventHandler<E extends EventName> = EventData<E> extends void ? () => void : (data: EventData<E>) => void;
|
||||
|
||||
export type EventDataParams<E extends EventName> = Array<EventData<E>> & (EventData<E> extends void ? {
|
||||
0?: undefined
|
||||
} : {
|
||||
0: EventData<E>
|
||||
});
|
||||
|
||||
export type MultipleEvents = {
|
||||
[E in EventName]?: Array<EventData<E>> | undefined
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
import { ID } from "./base";
|
||||
import { Marker } from "./marker";
|
||||
import { Line } from "./line";
|
||||
import { View } from "./view";
|
||||
import { PadData } from "./padData";
|
||||
import { Type } from "./type";
|
||||
|
||||
type HistoryEntryType = "Marker" | "Line" | "View" | "Type" | "Pad";
|
||||
type HistoryEntryAction = "create" | "update" | "delete";
|
||||
|
||||
type HistoryEntryObject<T extends HistoryEntryType> =
|
||||
T extends "Marker" ? Marker :
|
||||
T extends "Line" ? Line :
|
||||
T extends "View" ? View :
|
||||
T extends "Type" ? Type :
|
||||
PadData;
|
||||
|
||||
type HistoryEntryBefore<T extends HistoryEntryType, A extends HistoryEntryAction> = A extends "create" ? null : HistoryEntryObject<T>;
|
||||
type HistoryEntryAfter<T extends HistoryEntryType, A extends HistoryEntryAction> = A extends "delete" ? null : HistoryEntryObject<T>;
|
||||
|
||||
interface HistoryEntryBase<T extends HistoryEntryType, A extends HistoryEntryAction> {
|
||||
id: ID;
|
||||
time: Date;
|
||||
objectId: ID;
|
||||
action: A;
|
||||
objectBefore: HistoryEntryBefore<T, A>;
|
||||
objectAfter: HistoryEntryAfter<T, A>;
|
||||
}
|
||||
|
||||
type HistoryEntryBase2<T extends HistoryEntryType> =
|
||||
HistoryEntryBase<T, "create">
|
||||
| HistoryEntryBase<T, "update">
|
||||
| HistoryEntryBase<T, "delete">
|
||||
|
||||
|
||||
export type HistoryEntry =
|
||||
HistoryEntryBase2<"Marker">
|
||||
| HistoryEntryBase2<"Line">
|
||||
| HistoryEntryBase2<"View">
|
||||
| HistoryEntryBase2<"Type">
|
||||
| HistoryEntryBase2<"Pad">;
|
|
@ -0,0 +1,11 @@
|
|||
export * from './base';
|
||||
export * from './events';
|
||||
export * from './historyEntry';
|
||||
export * from './line';
|
||||
export * from './marker';
|
||||
export * from './padData';
|
||||
export * from './route';
|
||||
export * from './searchResult';
|
||||
export * from './socket';
|
||||
export * from './type';
|
||||
export * from './view';
|
|
@ -0,0 +1,33 @@
|
|||
import { AllOptionalExceptId, Bbox, Colour, ID, Point, RouteMode, ZoomLevel } from "./base";
|
||||
|
||||
interface LineBase {
|
||||
id: ID;
|
||||
routePoints: Point[];
|
||||
mode: RouteMode;
|
||||
colour: Colour;
|
||||
width: number;
|
||||
name: string;
|
||||
typeId: ID;
|
||||
data: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface Line extends LineBase, Bbox {
|
||||
distance: number;
|
||||
ascent: number;
|
||||
descent: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface TrackPoint extends Point {
|
||||
idx: number;
|
||||
zoom: ZoomLevel;
|
||||
ele?: number;
|
||||
}
|
||||
|
||||
interface TrackLineCreate extends LineBase {
|
||||
mode: "track";
|
||||
trackPoints: TrackPoint[];
|
||||
}
|
||||
|
||||
export type LineCreate = LineBase | TrackLineCreate;
|
||||
export type LineUpdate = AllOptionalExceptId<LineCreate>;
|
|
@ -0,0 +1,16 @@
|
|||
import { AllOptionalExceptId, Colour, ID, Point, Shape, Symbol } from "./base";
|
||||
|
||||
export interface Marker extends Point {
|
||||
id: ID;
|
||||
name: string;
|
||||
colour: Colour;
|
||||
size: number;
|
||||
symbol: Symbol;
|
||||
shape: Shape;
|
||||
elevation: number;
|
||||
typeId: ID;
|
||||
data: Record<string, string>;
|
||||
}
|
||||
|
||||
export type MarkerCreate = Marker;
|
||||
export type MarkerUpdate = AllOptionalExceptId<MarkerCreate>;
|
|
@ -0,0 +1,31 @@
|
|||
import { View } from "./view";
|
||||
import { ID } from "./base";
|
||||
|
||||
export type PadId = string;
|
||||
|
||||
export interface PadDataBase {
|
||||
id: PadId;
|
||||
writeId: PadId;
|
||||
adminId: PadId;
|
||||
name: string;
|
||||
searchEngines: boolean;
|
||||
description: string;
|
||||
clusterMarkers: boolean;
|
||||
legend1: string;
|
||||
legend2: string;
|
||||
defaultViewId: ID | null;
|
||||
}
|
||||
|
||||
export enum Writable {
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
ADMIN = 2
|
||||
}
|
||||
|
||||
export type PadData = Omit<PadDataBase, "writeId" | "adminId"> & Partial<Pick<PadDataBase, "writeId" | "adminId">> & {
|
||||
writable: Writable;
|
||||
defaultView?: View;
|
||||
}
|
||||
|
||||
export type PadDataCreate = PadDataBase;
|
||||
export type PadDataUpdate = Partial<PadDataCreate>;
|
|
@ -0,0 +1,18 @@
|
|||
import { Point, RouteMode } from "./base";
|
||||
import { TrackPoint } from "./line";
|
||||
|
||||
interface RouteBase {
|
||||
routePoints: Point[];
|
||||
mode: RouteMode;
|
||||
}
|
||||
|
||||
export interface RouteCreate extends RouteBase {
|
||||
}
|
||||
|
||||
export interface Route extends RouteBase {
|
||||
trackPoints: TrackPoint[],
|
||||
distance: number;
|
||||
time?: number;
|
||||
ascent?: number;
|
||||
descent?: number;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { Bbox, Point, ZoomLevel } from "./base";
|
||||
import { GeoJSON } from "geojson";
|
||||
|
||||
export type SearchResultType = string;
|
||||
|
||||
export interface SearchResult extends Point {
|
||||
short_name: string;
|
||||
display_name: string;
|
||||
address: string;
|
||||
boundingbox: Bbox | null;
|
||||
zoom: ZoomLevel | null;
|
||||
extratags: Record<string, string>;
|
||||
geojson: GeoJSON | null;
|
||||
icon: Symbol;
|
||||
type: SearchResultType;
|
||||
id: string;
|
||||
ele?: number;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
import { Bbox, ExportFormat, ID, ObjectWithId } from "./base";
|
||||
import { PadData, PadDataCreate, PadDataUpdate } from "./padData";
|
||||
import { Marker, MarkerCreate, MarkerUpdate } from "./marker";
|
||||
import { Line, LineCreate, LineUpdate } from "./line";
|
||||
import { Route, RouteCreate } from "./route";
|
||||
import { Type, TypeCreate, TypeUpdate } from "./type";
|
||||
import { View, ViewCreate, ViewUpdate } from "./view";
|
||||
import { MultipleEvents } from "./events";
|
||||
import { SearchResult } from "./searchResult";
|
||||
|
||||
export interface LineTemplateRequest {
|
||||
typeId: ID
|
||||
}
|
||||
|
||||
export interface LineExportRequest {
|
||||
id: ID;
|
||||
format: ExportFormat
|
||||
}
|
||||
|
||||
export interface RouteExportRequest {
|
||||
format: ExportFormat
|
||||
}
|
||||
|
||||
export interface FindQuery {
|
||||
query: string;
|
||||
loadUrls?: boolean;
|
||||
elevation?: boolean;
|
||||
}
|
||||
|
||||
export interface FindOnMapQuery {
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface RequestDataMap {
|
||||
updateBbox: Bbox;
|
||||
createPad: PadDataCreate;
|
||||
editPad: PadDataUpdate;
|
||||
listenToHistory: void;
|
||||
stopListeningToHistory: void;
|
||||
revertHistoryEntry: ObjectWithId;
|
||||
getMarker: ObjectWithId;
|
||||
addMarker: MarkerCreate;
|
||||
editMarker: MarkerUpdate;
|
||||
deleteMarker: ObjectWithId;
|
||||
getLineTemplate: LineTemplateRequest;
|
||||
addLine: LineCreate;
|
||||
editLine: LineUpdate;
|
||||
deleteLine: ObjectWithId;
|
||||
exportLine: LineExportRequest;
|
||||
find: FindQuery;
|
||||
findOnMap: FindOnMapQuery;
|
||||
getRoute: RouteCreate;
|
||||
setRoute: RouteCreate;
|
||||
clearRoute: void;
|
||||
lineToRoute: ObjectWithId;
|
||||
exportRoute: RouteExportRequest;
|
||||
addType: TypeCreate;
|
||||
editType: TypeUpdate;
|
||||
deleteType: ObjectWithId;
|
||||
addView: ViewCreate;
|
||||
editView: ViewUpdate;
|
||||
deleteView: ObjectWithId;
|
||||
geoip: void;
|
||||
setPadId: string;
|
||||
}
|
||||
|
||||
export interface ResponseDataMap {
|
||||
updateBbox: MultipleEvents;
|
||||
createPad: MultipleEvents;
|
||||
editPad: PadData;
|
||||
listenToHistory: MultipleEvents;
|
||||
stopListeningToHistory: void;
|
||||
revertHistoryEntry: MultipleEvents;
|
||||
getMarker: Marker;
|
||||
addMarker: Marker;
|
||||
editMarker: Marker;
|
||||
deleteMarker: Marker;
|
||||
getLineTemplate: Line;
|
||||
addLine: Line;
|
||||
editLine: Line;
|
||||
deleteLine: Line;
|
||||
exportLine: string;
|
||||
find: string | SearchResult[];
|
||||
findOnMap: Array<Pick<Marker, "id" | "name" | "typeId" | "lat" | "lon"> | Pick<Line, "id" | "name" | "typeId" | "left" | "top" | "right" | "bottom">>;
|
||||
getRoute: Route;
|
||||
setRoute: Route;
|
||||
clearRoute: void;
|
||||
lineToRoute: Route;
|
||||
exportRoute: string;
|
||||
addType: Type;
|
||||
editType: Type;
|
||||
deleteType: Type;
|
||||
addView: View;
|
||||
editView: View;
|
||||
deleteView: View;
|
||||
geoip: Bbox | null;
|
||||
setPadId: MultipleEvents;
|
||||
}
|
||||
|
||||
export type RequestName = keyof RequestDataMap;
|
||||
export type RequestData<E extends RequestName> = RequestDataMap[E];
|
||||
export type ResponseData<E extends RequestName> = ResponseDataMap[E];
|
|
@ -0,0 +1,62 @@
|
|||
import { AllOptionalExceptId, Colour, ID, RouteMode, Shape } from "./base";
|
||||
|
||||
type ObjectType = "marker" | "line";
|
||||
type FieldType = "textarea" | "dropdown" | "checkbox" | "input";
|
||||
type FieldValue<F extends FieldType> = F extends "checkbox" ? boolean : string;
|
||||
type OptionValue<F extends FieldType> = F extends "checkbox" ? "1" | "0" : string;
|
||||
|
||||
type FieldBase<F extends FieldType, O extends ObjectType, isUpdate extends boolean> = {
|
||||
name: string;
|
||||
type: F;
|
||||
controlColour: boolean;
|
||||
default: FieldValue<F>;
|
||||
} & (O extends "marker" ? {
|
||||
controlSize: boolean;
|
||||
controlSymbol: boolean;
|
||||
controlShape: boolean;
|
||||
} : {
|
||||
controlWidth: boolean;
|
||||
}) & (F extends "dropdown" | "checkbox" ? {
|
||||
options: Array<FieldOption<F, O, isUpdate>>
|
||||
} : { }) & (isUpdate extends true ? {
|
||||
oldName: string;
|
||||
} : { });
|
||||
|
||||
type FieldOption<F extends FieldType, O extends ObjectType, isUpdate extends boolean> = {
|
||||
value: OptionValue<F>;
|
||||
colour?: Colour;
|
||||
} & (O extends "marker" ? {
|
||||
size: number;
|
||||
symbol: Symbol;
|
||||
shape: Shape;
|
||||
} : {
|
||||
width: number;
|
||||
}) & (isUpdate extends true ? {
|
||||
oldValue?: OptionValue<F>
|
||||
} : { });
|
||||
|
||||
type Field<O extends ObjectType, isUpdate extends boolean> =
|
||||
FieldBase<"textarea", O, isUpdate>
|
||||
| FieldBase<"dropdown", O, isUpdate>
|
||||
| FieldBase<"checkbox", O, isUpdate>
|
||||
| FieldBase<"input", O, isUpdate>;
|
||||
|
||||
type TypeBase<O extends ObjectType, isUpdate extends boolean> = {
|
||||
id: ID;
|
||||
name: string;
|
||||
defaultColour: Colour | null;
|
||||
fields: Array<Field<O, isUpdate>>
|
||||
} & (isUpdate extends false ? {
|
||||
type: O
|
||||
} : {}) & (O extends "marker" ? {
|
||||
defaultSize?: number;
|
||||
defaultSymbol?: Symbol;
|
||||
defaultShape?: Shape;
|
||||
} : {
|
||||
defaultWidth: number;
|
||||
defaultMode: RouteMode;
|
||||
});
|
||||
|
||||
export type Type = TypeBase<"marker", false> | TypeBase<"line", false>;
|
||||
export type TypeCreate = Type;
|
||||
export type TypeUpdate = AllOptionalExceptId<TypeBase<"marker", true> | TypeBase<"line", true>>;
|
|
@ -0,0 +1,12 @@
|
|||
import { AllOptionalExceptId, Bbox, ID, Layer } from "./base";
|
||||
|
||||
export interface View extends Bbox {
|
||||
id: ID;
|
||||
name: string;
|
||||
baseLayer: Layer;
|
||||
layers: Layer[];
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
export type ViewCreate = View;
|
||||
export type ViewUpdate = AllOptionalExceptId<View>;
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es3",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue