Performance improvements, add clock
This commit is contained in:
parent
c2b1f6643b
commit
efd7631837
21 changed files with 2947 additions and 105 deletions
|
@ -181,7 +181,7 @@ export class InitUiElements {
|
||||||
|
|
||||||
// This layer is the layer that gives the questions
|
// This layer is the layer that gives the questions
|
||||||
const featureBox = new FeatureInfoBox(
|
const featureBox = new FeatureInfoBox(
|
||||||
State.state.allElements.getElement(data.id),
|
State.state.allElements.getEventSourceById(data.id),
|
||||||
layer
|
layer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,14 @@ export class ElementStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getElement(elementId): UIEventSource<any> {
|
getEventSourceById(elementId): UIEventSource<any> {
|
||||||
if (elementId in this._elements) {
|
if (elementId in this._elements) {
|
||||||
return this._elements[elementId];
|
return this._elements[elementId];
|
||||||
}
|
}
|
||||||
console.log("Can not find eventsource with id ", elementId);
|
console.error("Can not find eventsource with id ", elementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getEventSourceFor(feature): UIEventSource<any> {
|
||||||
|
return this.getEventSourceById(feature.properties.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ import {UIElement} from "../UI/UIElement";
|
||||||
import State from "../State";
|
import State from "../State";
|
||||||
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
import LayerConfig from "../Customizations/JSON/LayerConfig";
|
||||||
import Hash from "./Web/Hash";
|
import Hash from "./Web/Hash";
|
||||||
|
import LazyElement from "../UI/Base/LazyElement";
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* A filtered layer is a layer which offers a 'set-data' function
|
* A filtered layer is a layer which offers a 'set-data' function
|
||||||
|
@ -78,7 +79,7 @@ export class FilteredLayer {
|
||||||
const tags = TagUtils.proprtiesToKV(feature.properties);
|
const tags = TagUtils.proprtiesToKV(feature.properties);
|
||||||
const matches = this.filters.matches(tags);
|
const matches = this.filters.matches(tags);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
selfFeatures.push(feature);
|
selfFeatures.push(feature);
|
||||||
}
|
}
|
||||||
if (!matches || this.layerDef.passAllFeatures) {
|
if (!matches || this.layerDef.passAllFeatures) {
|
||||||
leftoverFeatures.push(feature);
|
leftoverFeatures.push(feature);
|
||||||
|
@ -130,14 +131,13 @@ export class FilteredLayer {
|
||||||
let self = this;
|
let self = this;
|
||||||
this._geolayer = L.geoJSON(data, {
|
this._geolayer = L.geoJSON(data, {
|
||||||
style: feature => {
|
style: feature => {
|
||||||
const tagsSource = State.state.allElements.getElement(feature.properties.id);
|
const tagsSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
return self.layerDef.GenerateLeafletStyle(tagsSource, self._showOnPopup !== undefined);
|
return self.layerDef.GenerateLeafletStyle(tagsSource, self._showOnPopup !== undefined);
|
||||||
},
|
},
|
||||||
pointToLayer: function (feature, latLng) {
|
pointToLayer: function (feature, latLng) {
|
||||||
// Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
|
// Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
|
||||||
// Click handling is done in the next step
|
// Click handling is done in the next step
|
||||||
|
const tagSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
const tagSource = State.state.allElements.getElement(feature.properties.id);
|
|
||||||
|
|
||||||
const style = self.layerDef.GenerateLeafletStyle(tagSource, self._showOnPopup !== undefined);
|
const style = self.layerDef.GenerateLeafletStyle(tagSource, self._showOnPopup !== undefined);
|
||||||
let marker;
|
let marker;
|
||||||
|
@ -169,10 +169,9 @@ export class FilteredLayer {
|
||||||
closeOnEscapeKey: true,
|
closeOnEscapeKey: true,
|
||||||
}, layer);
|
}, layer);
|
||||||
|
|
||||||
let uiElement: UIElement;
|
|
||||||
|
|
||||||
const eventSource = State.state.allElements.addOrGetElement(feature);
|
const eventSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
uiElement = self._showOnPopup(eventSource, feature);
|
let uiElement: LazyElement = new LazyElement(() => self._showOnPopup(eventSource, feature));
|
||||||
popup.setContent(uiElement.Render());
|
popup.setContent(uiElement.Render());
|
||||||
layer.bindPopup(popup);
|
layer.bindPopup(popup);
|
||||||
// We first render the UIelement (which'll still need an update later on...)
|
// We first render the UIelement (which'll still need an update later on...)
|
||||||
|
@ -181,11 +180,16 @@ export class FilteredLayer {
|
||||||
|
|
||||||
layer.on("click", (e) => {
|
layer.on("click", (e) => {
|
||||||
// We set the element as selected...
|
// We set the element as selected...
|
||||||
|
uiElement.Activate();
|
||||||
State.state.selectedElement.setData(feature);
|
State.state.selectedElement.setData(feature);
|
||||||
uiElement.Update();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
|
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
|
||||||
|
// This element is in the URL, so this is a share link
|
||||||
|
// We already open it
|
||||||
|
uiElement.Activate();
|
||||||
|
popup.setContent(uiElement.Render());
|
||||||
|
|
||||||
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
||||||
popup.setLatLng({lat: center[1], lng: center[0]});
|
popup.setLatLng({lat: center[1], lng: center[0]});
|
||||||
popup.openOn(State.state.bm.map);
|
popup.openOn(State.state.bm.map);
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import {GeoOperations} from "./GeoOperations";
|
import {GeoOperations} from "./GeoOperations";
|
||||||
import CodeGrid from "./Web/CodeGrid";
|
|
||||||
import State from "../State";
|
import State from "../State";
|
||||||
import opening_hours from "opening_hours";
|
import opening_hours from "opening_hours";
|
||||||
import {And, Or, Tag} from "./Tags";
|
import {And, Or, Tag} from "./Tags";
|
||||||
import {Utils} from "../Utils";
|
import {Utils} from "../Utils";
|
||||||
import CountryCoder from "latlon2country/lib/countryCoder";
|
import CountryCoder from "latlon2country"
|
||||||
|
|
||||||
|
|
||||||
class SimpleMetaTagger {
|
class SimpleMetaTagger {
|
||||||
private _f: (feature: any, index: number) => void;
|
private _f: (feature: any, index: number) => void;
|
||||||
|
@ -62,57 +60,60 @@ export default class MetaTagging {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
private static country = new SimpleMetaTagger(
|
private static country = new SimpleMetaTagger(
|
||||||
["_country"], "",
|
["_country"], "The country code of the property (with latlon2country)",
|
||||||
((feature, index) => {
|
(feature, index) => {
|
||||||
|
|
||||||
const coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
|
const coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
|
||||||
const centerPoint = GeoOperations.centerpoint(feature);
|
|
||||||
|
let centerPoint: any = GeoOperations.centerpoint(feature);
|
||||||
const lat = centerPoint.geometry.coordinates[1];
|
const lat = centerPoint.geometry.coordinates[1];
|
||||||
const lon = centerPoint.geometry.coordinates[0]
|
const lon = centerPoint.geometry.coordinates[0]
|
||||||
// But the codegrid SHOULD be a number!
|
coder.GetCountryCodeFor(lon, lat, (countries) => {
|
||||||
coder.CountryCodeFor(lon, lat, (countries) => {
|
feature.properties["_country"] = countries[0].trim().toLowerCase();
|
||||||
feature.properties["_country"] = countries[0];
|
const tagsSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
console.log("Country is ",countries.join(";"))
|
tagsSource.ping();
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
)
|
)
|
||||||
private static isOpen = new SimpleMetaTagger(
|
private static isOpen = new SimpleMetaTagger(
|
||||||
["_isOpen", "_isOpen:description"],
|
["_isOpen", "_isOpen:description"],
|
||||||
"If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
|
"If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
|
||||||
(feature => {
|
(feature => {
|
||||||
const tagsSource = State.state.allElements.addOrGetElement(feature);
|
|
||||||
tagsSource.addCallback(tags => {
|
|
||||||
|
|
||||||
if (tags["opening_hours"] !== undefined && tags["_country"] !== undefined) {
|
const tagsSource = State.state.allElements.getEventSourceFor(feature);
|
||||||
|
tagsSource.addCallbackAndRun(tags => {
|
||||||
if (tags._isOpen !== undefined) {
|
if (tags.opening_hours === undefined || tags._country === undefined) {
|
||||||
// Already defined
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oh = new opening_hours(tags["opening_hours"], {
|
|
||||||
lat: tags._lat,
|
|
||||||
lon: tags._lon,
|
|
||||||
address: {
|
|
||||||
country_code: tags._country.toLowerCase()
|
|
||||||
}
|
|
||||||
}, {tag_key: "opening_hours"});
|
|
||||||
|
|
||||||
const updateTags = () => {
|
|
||||||
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
|
||||||
const comment = oh.getComment();
|
|
||||||
if (comment) {
|
|
||||||
tags["_isOpen:description"] = comment;
|
|
||||||
}
|
|
||||||
const nextChange = oh.getNextChange() as Date;
|
|
||||||
if (nextChange !== undefined) {
|
|
||||||
window.setTimeout(
|
|
||||||
updateTags,
|
|
||||||
(nextChange.getTime() - (new Date()).getTime())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateTags();
|
|
||||||
}
|
}
|
||||||
|
const oh = new opening_hours(tags["opening_hours"], {
|
||||||
|
lat: tags._lat,
|
||||||
|
lon: tags._lon,
|
||||||
|
address: {
|
||||||
|
country_code: tags._country.toLowerCase()
|
||||||
|
}
|
||||||
|
}, {tag_key: "opening_hours"});
|
||||||
|
// AUtomatically triggered on the next change
|
||||||
|
const updateTags = () => {
|
||||||
|
const oldValueIsOpen = tags["_isOpen"];
|
||||||
|
tags["_isOpen"] = oh.getState() ? "yes" : "no";
|
||||||
|
const comment = oh.getComment();
|
||||||
|
if (comment) {
|
||||||
|
tags["_isOpen:description"] = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldValueIsOpen !== tags._isOpen) {
|
||||||
|
tagsSource.ping();
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextChange = oh.getNextChange() as Date;
|
||||||
|
if (nextChange !== undefined) {
|
||||||
|
window.setTimeout(
|
||||||
|
updateTags,
|
||||||
|
(nextChange.getTime() - (new Date()).getTime())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateTags();
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class Changes {
|
||||||
if (changes.length == 0) {
|
if (changes.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const eventSource = tags ?? State.state?.allElements.getElement(elementId);
|
const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId);
|
||||||
const elementTags = eventSource.data;
|
const elementTags = eventSource.data;
|
||||||
const pending : {elementId:string, key: string, value: string}[] = [];
|
const pending : {elementId:string, key: string, value: string}[] = [];
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
|
|
|
@ -181,7 +181,7 @@ export class ChangesetHandler {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
console.log("Rewriting id: ", oldId, "-->", newId);
|
console.log("Rewriting id: ", oldId, "-->", newId);
|
||||||
const element = allElements.getElement("node/" + oldId);
|
const element = allElements.getEventSourceById("node/" + oldId);
|
||||||
element.data.id = "node/" + newId;
|
element.data.id = "node/" + newId;
|
||||||
allElements.addElementById("node/" + newId, element);
|
allElements.addElementById("node/" + newId, element);
|
||||||
element.ping();
|
element.ping();
|
||||||
|
|
|
@ -99,12 +99,15 @@ export class UpdateFromOverpass {
|
||||||
|
|
||||||
let newIds = 1;
|
let newIds = 1;
|
||||||
for (const feature of geojson.features) {
|
for (const feature of geojson.features) {
|
||||||
if(feature.properties.id === undefined){
|
if (feature.properties.id === undefined) {
|
||||||
feature.properties.id = "ext/"+newIds;
|
feature.properties.id = "ext/" + newIds;
|
||||||
newIds++;
|
newIds++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geojson.features.forEach(feature => {
|
||||||
|
State.state.allElements.addElement(feature);
|
||||||
|
})
|
||||||
MetaTagging.addMetatags(geojson.features);
|
MetaTagging.addMetatags(geojson.features);
|
||||||
|
|
||||||
function renderLayers(layers: FilteredLayer[]) {
|
function renderLayers(layers: FilteredLayer[]) {
|
||||||
|
@ -125,6 +128,7 @@ export class UpdateFromOverpass {
|
||||||
}, 50)
|
}, 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
renderLayers(State.state.filteredLayers.data);
|
renderLayers(State.state.filteredLayers.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,3 +263,5 @@ Bench icons from StreetComplete: https://github.com/westnordost/StreetComplete/t
|
||||||
|
|
||||||
|
|
||||||
Urinal icon: https://thenounproject.com/term/urinal/1307984/
|
Urinal icon: https://thenounproject.com/term/urinal/1307984/
|
||||||
|
|
||||||
|
24/7 icon: https://www.vecteezy.com/vector-art/1394992-24-7-service-and-support-icon-set
|
12
Svg.ts
12
Svg.ts
File diff suppressed because one or more lines are too long
30
UI/Base/LazyElement.ts
Normal file
30
UI/Base/LazyElement.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import {UIElement} from "../UIElement";
|
||||||
|
|
||||||
|
export default class LazyElement extends UIElement {
|
||||||
|
|
||||||
|
|
||||||
|
private _content: UIElement = undefined;
|
||||||
|
|
||||||
|
public Activate: () => void;
|
||||||
|
|
||||||
|
constructor(content: (() => UIElement)) {
|
||||||
|
super();
|
||||||
|
this.dumbMode = false;
|
||||||
|
const self = this;
|
||||||
|
this.Activate = () => {
|
||||||
|
if (this._content === undefined) {
|
||||||
|
self._content = content();
|
||||||
|
}
|
||||||
|
self.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InnerRender(): string {
|
||||||
|
if (this._content === undefined) {
|
||||||
|
return "Rendering...";
|
||||||
|
}
|
||||||
|
return this._content.InnerRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ export class TextField extends InputElement<string> {
|
||||||
private readonly _htmlType: string;
|
private readonly _htmlType: string;
|
||||||
private readonly _textAreaRows: number;
|
private readonly _textAreaRows: number;
|
||||||
|
|
||||||
private readonly _isValid: (string, country) => boolean;
|
private readonly _isValid: (string,country) => boolean;
|
||||||
private _label: UIElement;
|
private _label: UIElement;
|
||||||
|
|
||||||
constructor(options?: {
|
constructor(options?: {
|
||||||
|
@ -22,7 +22,7 @@ export class TextField extends InputElement<string> {
|
||||||
htmlType?: string,
|
htmlType?: string,
|
||||||
label?: UIElement,
|
label?: UIElement,
|
||||||
textAreaRows?: number,
|
textAreaRows?: number,
|
||||||
isValid?: ((s: string, country?: string) => boolean)
|
isValid?: ((s: string, country?: () => string) => boolean)
|
||||||
}) {
|
}) {
|
||||||
super(undefined);
|
super(undefined);
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
|
@ -14,8 +14,8 @@ import DirectionInput from "./DirectionInput";
|
||||||
interface TextFieldDef {
|
interface TextFieldDef {
|
||||||
name: string,
|
name: string,
|
||||||
explanation: string,
|
explanation: string,
|
||||||
isValid: ((s: string, country?: string) => boolean),
|
isValid: ((s: string, country?:() => string) => boolean),
|
||||||
reformat?: ((s: string, country?: string) => string),
|
reformat?: ((s: string, country?: () => string) => string),
|
||||||
inputHelper?: (value: UIEventSource<string>, options?: {
|
inputHelper?: (value: UIEventSource<string>, options?: {
|
||||||
location: [number, number]
|
location: [number, number]
|
||||||
}) => InputElement<string>,
|
}) => InputElement<string>,
|
||||||
|
@ -26,8 +26,8 @@ export default class ValidatedTextField {
|
||||||
|
|
||||||
private static tp(name: string,
|
private static tp(name: string,
|
||||||
explanation: string,
|
explanation: string,
|
||||||
isValid?: ((s: string, country?: string) => boolean),
|
isValid?: ((s: string, country?: () => string) => boolean),
|
||||||
reformat?: ((s: string, country?: string) => string),
|
reformat?: ((s: string, country?: () => string) => string),
|
||||||
inputHelper?: (value: UIEventSource<string>, options?:{
|
inputHelper?: (value: UIEventSource<string>, options?:{
|
||||||
location: [number, number]
|
location: [number, number]
|
||||||
}) => InputElement<string>): TextFieldDef {
|
}) => InputElement<string>): TextFieldDef {
|
||||||
|
@ -154,13 +154,14 @@ export default class ValidatedTextField {
|
||||||
ValidatedTextField.tp(
|
ValidatedTextField.tp(
|
||||||
"phone",
|
"phone",
|
||||||
"A phone number",
|
"A phone number",
|
||||||
(str, country: any) => {
|
(str, country: () => string) => {
|
||||||
if (str === undefined) {
|
if (str === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return parsePhoneNumberFromString(str, country?.toUpperCase())?.isValid() ?? false
|
console.log("Validating phone number",str,"in country",country())
|
||||||
|
return parsePhoneNumberFromString(str, (country())?.toUpperCase() as any)?.isValid() ?? false
|
||||||
},
|
},
|
||||||
(str, country: any) => parsePhoneNumberFromString(str, country?.toUpperCase()).formatInternational()
|
(str, country: () => string) => parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational()
|
||||||
),
|
),
|
||||||
ValidatedTextField.tp(
|
ValidatedTextField.tp(
|
||||||
"opening_hours",
|
"opening_hours",
|
||||||
|
@ -200,8 +201,8 @@ export default class ValidatedTextField {
|
||||||
value?: UIEventSource<string>,
|
value?: UIEventSource<string>,
|
||||||
textArea?: boolean,
|
textArea?: boolean,
|
||||||
textAreaRows?: number,
|
textAreaRows?: number,
|
||||||
isValid?: ((s: string, country: string) => boolean),
|
isValid?: ((s: string, country: () => string) => boolean),
|
||||||
country?: string,
|
country?: () => string,
|
||||||
location?: [number /*lat*/, number /*lon*/]
|
location?: [number /*lat*/, number /*lon*/]
|
||||||
}): InputElement<string> {
|
}): InputElement<string> {
|
||||||
options = options ?? {};
|
options = options ?? {};
|
||||||
|
@ -304,7 +305,7 @@ export default class ValidatedTextField {
|
||||||
textArea?: boolean,
|
textArea?: boolean,
|
||||||
textAreaRows?: number,
|
textAreaRows?: number,
|
||||||
isValid?: ((string: string) => boolean),
|
isValid?: ((string: string) => boolean),
|
||||||
country?: string
|
country?: () => string
|
||||||
}): InputElement<T> {
|
}): InputElement<T> {
|
||||||
let textField: InputElement<string>;
|
let textField: InputElement<string>;
|
||||||
if (options?.type) {
|
if (options?.type) {
|
||||||
|
|
|
@ -151,7 +151,7 @@ export default class OpeningHoursVisualization extends UIElement {
|
||||||
|
|
||||||
const tags = this._source.data;
|
const tags = this._source.data;
|
||||||
if (tags._country === undefined) {
|
if (tags._country === undefined) {
|
||||||
return "Loading...";
|
return "Loading country information...";
|
||||||
}
|
}
|
||||||
let oh = null;
|
let oh = null;
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ export default class OpeningHoursVisualization extends UIElement {
|
||||||
}, {tag_key: this._key});
|
}, {tag_key: this._key});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return "Error: could not visualize these opening hours"
|
return `Error: could not visualize these opening hours<br/><spann class='subtle'>${e}</spann>`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!oh.getState() && !oh.getUnknown()) {
|
if (!oh.getState() && !oh.getUnknown()) {
|
||||||
|
|
|
@ -251,7 +251,7 @@ export default class TagRenderingQuestion extends UIElement {
|
||||||
|
|
||||||
const textField = ValidatedTextField.InputForType(this._configuration.freeform.type, {
|
const textField = ValidatedTextField.InputForType(this._configuration.freeform.type, {
|
||||||
isValid: (str) => (str.length <= 255),
|
isValid: (str) => (str.length <= 255),
|
||||||
country: this._tags.data._country,
|
country: () => this._tags.data._country,
|
||||||
location: [this._tags.data._lat, this._tags.data._lon]
|
location: [this._tags.data._lat, this._tags.data._lon]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
9
Utils.ts
9
Utils.ts
|
@ -169,5 +169,14 @@ export class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static MatchKeys(object: any, prototype: any, context?: string){
|
||||||
|
|
||||||
|
for (const objectKey in object) {
|
||||||
|
if(prototype[objectKey] === undefined){
|
||||||
|
console.error("Key ", objectKey, "might be not supported (in context",context,")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
22
assets/svg/clock.svg
Normal file
22
assets/svg/clock.svg
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
style="fill:none">
|
||||||
|
<circle
|
||||||
|
cx="50"
|
||||||
|
cy="50"
|
||||||
|
r="45.0"
|
||||||
|
id="circle4"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="path823"
|
||||||
|
d="M 46,55.932203 H 66.550847"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="path825"
|
||||||
|
d="m 46,55.533898 v -27.805085 0"
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 805 B |
42
assets/svg/closed.svg
Normal file
42
assets/svg/closed.svg
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
id="svg3"
|
||||||
|
width="100"
|
||||||
|
height="100"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
version="1.1"
|
||||||
|
style="fill:none">
|
||||||
|
<metadata
|
||||||
|
id="metadata9">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs7" />
|
||||||
|
<circle
|
||||||
|
cx="50"
|
||||||
|
cy="50"
|
||||||
|
r="45.408772"
|
||||||
|
id="circle4"
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#180000;stroke-width:7.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="path823"
|
||||||
|
d="M 46,55.932203 H 66.550847"
|
||||||
|
style="fill:none;stroke:#180000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="path825"
|
||||||
|
d="m 46,55.533898 v -27.805085 0"
|
||||||
|
style="fill:none;stroke:#180000;stroke-width:7.38227367;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -73,6 +73,16 @@
|
||||||
},
|
},
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
"images",
|
"images",
|
||||||
|
{
|
||||||
|
"question": {
|
||||||
|
"en": "What is the name of this shop?",
|
||||||
|
"fr": "Qu'est-ce que le nom de ce magasin?"
|
||||||
|
},
|
||||||
|
"render": "This shop is called <i>{name}</i>",
|
||||||
|
"freeform": {
|
||||||
|
"key": "name"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"render": {
|
"render": {
|
||||||
"en": "This shop sells {shop}",
|
"en": "This shop sells {shop}",
|
||||||
|
@ -226,6 +236,28 @@
|
||||||
"icon": {
|
"icon": {
|
||||||
"render": "./assets/themes/shops/shop.svg"
|
"render": "./assets/themes/shops/shop.svg"
|
||||||
},
|
},
|
||||||
|
"iconOverlays": [
|
||||||
|
{
|
||||||
|
"if": "_isOpen=yes",
|
||||||
|
"then": "clock:#0f0",
|
||||||
|
"badge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "_isOpen=no",
|
||||||
|
"then": "circle:#f00;clock:#fff",
|
||||||
|
"badge": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"and": [
|
||||||
|
"_isOpen=",
|
||||||
|
"opening_hours~*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"then": "clock:#ff0",
|
||||||
|
"badge": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"width": {
|
"width": {
|
||||||
"render": "8"
|
"render": "8"
|
||||||
},
|
},
|
||||||
|
|
2714
package-lock.json
generated
2714
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -20,9 +20,9 @@
|
||||||
"generate:translations": "ts-node scripts/generateTranslations.ts",
|
"generate:translations": "ts-node scripts/generateTranslations.ts",
|
||||||
"generate:layouts": "ts-node scripts/createLayouts.ts",
|
"generate:layouts": "ts-node scripts/createLayouts.ts",
|
||||||
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
|
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
|
||||||
"generate": "npm run generate:images && npm run generate:translations && npm run generate:layouts && npm run generate:editor-layer-index",
|
"generate": "npm run generate:images && npm run generate:translations",
|
||||||
"build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
|
"build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
|
||||||
"prepare-deploy": "npm run generate && npm run build && rm -rf .cache",
|
"prepare-deploy": "npm run generate:editor-layer-index && npm run generate:layouts && npm run generate && npm run build && rm -rf .cache",
|
||||||
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
|
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
|
||||||
"deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
|
"deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
|
||||||
"clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(index\\|land\\|test\\|preferences\\|customGenerator\\).html\" | xargs rm) && (find *.webmanifest | xargs rm)"
|
"clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(index\\|land\\|test\\|preferences\\|customGenerator\\).html\" | xargs rm) && (find *.webmanifest | xargs rm)"
|
||||||
|
@ -35,13 +35,12 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/leaflet-providers": "^1.2.0",
|
"@types/leaflet-providers": "^1.2.0",
|
||||||
"codegrid-js": "git://github.com/hlaw/codegrid-js.git",
|
|
||||||
"country-language": "^0.1.7",
|
"country-language": "^0.1.7",
|
||||||
"email-validator": "^2.0.4",
|
"email-validator": "^2.0.4",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"i18next-client": "^1.11.4",
|
"i18next-client": "^1.11.4",
|
||||||
"jquery": "latest",
|
"jquery": "latest",
|
||||||
"latlon2country": "^1.0.3",
|
"latlon2country": "^1.0.7",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
"leaflet-providers": "^1.10.2",
|
"leaflet-providers": "^1.10.2",
|
||||||
"libphonenumber": "0.0.10",
|
"libphonenumber": "0.0.10",
|
||||||
|
|
14
test.ts
14
test.ts
|
@ -1,17 +1,5 @@
|
||||||
//*
|
/*
|
||||||
|
|
||||||
import CountryCoder from "latlon2country/lib/countryCoder";
|
|
||||||
|
|
||||||
f
|
|
||||||
unction pr(countries) {
|
|
||||||
console.log(">>>>>", countries.join(";"))
|
|
||||||
}
|
|
||||||
|
|
||||||
coder.CountryCodeFor(3.2, 51.2, pr)
|
|
||||||
coder.CountryCodeFor(4.2, 51.2, pr);
|
|
||||||
coder.CountryCodeFor(4.92119, 51.43995, pr)
|
|
||||||
coder.CountryCodeFor(4.93189, 51.43552, pr)
|
|
||||||
coder.CountryCodeFor(34.2581, 44.7536, pr)
|
|
||||||
/*/
|
/*/
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue