Add standalone bicycle library theme, search now opens the popup of the found object
This commit is contained in:
parent
a35b80afbb
commit
c359d43b15
15 changed files with 260 additions and 43 deletions
|
@ -20,6 +20,7 @@ import * as surveillance_cameras from "../assets/themes/surveillance_cameras/sur
|
||||||
import * as trees from "../assets/themes/trees/trees.json"
|
import * as trees from "../assets/themes/trees/trees.json"
|
||||||
import * as personal from "../assets/themes/personalLayout/personalLayout.json"
|
import * as personal from "../assets/themes/personalLayout/personalLayout.json"
|
||||||
import * as playgrounds from "../assets/themes/playgrounds/playgrounds.json"
|
import * as playgrounds from "../assets/themes/playgrounds/playgrounds.json"
|
||||||
|
import * as bicycle_lib from "../assets/themes/bicycle_library/bicycle_library.json"
|
||||||
import LayerConfig from "./JSON/LayerConfig";
|
import LayerConfig from "./JSON/LayerConfig";
|
||||||
import LayoutConfig from "./JSON/LayoutConfig";
|
import LayoutConfig from "./JSON/LayoutConfig";
|
||||||
import SharedLayers from "./SharedLayers";
|
import SharedLayers from "./SharedLayers";
|
||||||
|
@ -57,6 +58,7 @@ export class AllKnownLayouts {
|
||||||
new LayoutConfig(drinking_water),
|
new LayoutConfig(drinking_water),
|
||||||
new LayoutConfig(nature),
|
new LayoutConfig(nature),
|
||||||
new LayoutConfig(cyclestreets),
|
new LayoutConfig(cyclestreets),
|
||||||
|
new LayoutConfig(bicycle_lib),
|
||||||
new LayoutConfig(maps),
|
new LayoutConfig(maps),
|
||||||
new LayoutConfig(fritures),
|
new LayoutConfig(fritures),
|
||||||
new LayoutConfig(benches),
|
new LayoutConfig(benches),
|
||||||
|
|
|
@ -40,6 +40,7 @@ import FeatureSwitched from "./UI/Base/FeatureSwitched";
|
||||||
import FeatureDuplicatorPerLayer from "./Logic/FeatureSource/FeatureDuplicatorPerLayer";
|
import FeatureDuplicatorPerLayer from "./Logic/FeatureSource/FeatureDuplicatorPerLayer";
|
||||||
import LayerConfig from "./Customizations/JSON/LayerConfig";
|
import LayerConfig from "./Customizations/JSON/LayerConfig";
|
||||||
import ShowDataLayer from "./UI/ShowDataLayer";
|
import ShowDataLayer from "./UI/ShowDataLayer";
|
||||||
|
import Hash from "./Logic/Web/Hash";
|
||||||
|
|
||||||
export class InitUiElements {
|
export class InitUiElements {
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@ export class InitUiElements {
|
||||||
|
|
||||||
if (feature === undefined) {
|
if (feature === undefined) {
|
||||||
State.state.fullScreenMessage.setData(undefined);
|
State.state.fullScreenMessage.setData(undefined);
|
||||||
|
Hash.hash.setData(undefined);
|
||||||
}
|
}
|
||||||
if (feature?.properties === undefined) {
|
if (feature?.properties === undefined) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,7 +5,8 @@ export class Geocoding {
|
||||||
private static readonly host = "https://nominatim.openstreetmap.org/search?";
|
private static readonly host = "https://nominatim.openstreetmap.org/search?";
|
||||||
|
|
||||||
static Search(query: string,
|
static Search(query: string,
|
||||||
handleResult: ((places: { display_name: string, lat: number, lon: number, boundingbox: number[] }[]) => void),
|
handleResult: ((places: { display_name: string, lat: number, lon: number, boundingbox: number[],
|
||||||
|
osm_type: string, osm_id: string}[]) => void),
|
||||||
onFail: (() => void)) {
|
onFail: (() => void)) {
|
||||||
const b = State.state.leafletMap.data.getBounds();
|
const b = State.state.leafletMap.data.getBounds();
|
||||||
console.log(b);
|
console.log(b);
|
||||||
|
|
|
@ -454,19 +454,19 @@ export class TagUtils {
|
||||||
|
|
||||||
static MatchesMultiAnswer(tag: TagsFilter, tags: any): boolean {
|
static MatchesMultiAnswer(tag: TagsFilter, tags: any): boolean {
|
||||||
const splitted = TagUtils.SplitKeys([tag]);
|
const splitted = TagUtils.SplitKeys([tag]);
|
||||||
console.log("Matching multianswer", tag, tags)
|
|
||||||
for (const splitKey in splitted) {
|
for (const splitKey in splitted) {
|
||||||
const neededValues = splitted[splitKey];
|
const neededValues = splitted[splitKey];
|
||||||
|
if(tags[splitKey] === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const actualValue = tags[splitKey].split(";");
|
const actualValue = tags[splitKey].split(";");
|
||||||
for (const neededValue of neededValues) {
|
for (const neededValue of neededValues) {
|
||||||
console.log("needed", neededValue, "have: ", actualValue, actualValue.indexOf(neededValue) )
|
|
||||||
if (actualValue.indexOf(neededValue) < 0) {
|
if (actualValue.indexOf(neededValue) < 0) {
|
||||||
console.log("NOT FOUND")
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("OK")
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,17 @@ import {UIEventSource} from "../UIEventSource";
|
||||||
|
|
||||||
export default class Hash {
|
export default class Hash {
|
||||||
|
|
||||||
public static Get() : UIEventSource<string>{
|
public static hash : UIEventSource<string> = Hash.Get();
|
||||||
|
|
||||||
|
private static Get() : UIEventSource<string>{
|
||||||
const hash = new UIEventSource<string>(window.location.hash.substr(1));
|
const hash = new UIEventSource<string>(window.location.hash.substr(1));
|
||||||
hash.addCallback(h => {
|
hash.addCallback(h => {
|
||||||
|
if(h === undefined || h === ""){
|
||||||
|
window.location.hash = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
h = h.replace(/\//g, "_");
|
h = h.replace(/\//g, "_");
|
||||||
return window.location.hash = "#" + h;
|
window.location.hash = "#" + h;
|
||||||
});
|
});
|
||||||
window.onhashchange = () => {
|
window.onhashchange = () => {
|
||||||
hash.setData(window.location.hash.substr(1))
|
hash.setData(window.location.hash.substr(1))
|
||||||
|
|
|
@ -62,7 +62,7 @@ export class QueryParameters {
|
||||||
|
|
||||||
parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(QueryParameters.knownSources[key].data))
|
parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(QueryParameters.knownSources[key].data))
|
||||||
}
|
}
|
||||||
history.replaceState(null, "", "?" + parts.join("&") + "#" + Hash.Get().data);
|
history.replaceState(null, "", "?" + parts.join("&") + "#" + Hash.hash.data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Utils } from "../Utils";
|
import { Utils } from "../Utils";
|
||||||
|
|
||||||
export default class Constants {
|
export default class Constants {
|
||||||
public static vNumber = "0.3.0c";
|
public static vNumber = "0.3.1 ";
|
||||||
|
|
||||||
// The user journey states thresholds when a new feature gets unlocked
|
// The user journey states thresholds when a new feature gets unlocked
|
||||||
public static userJourney = {
|
public static userJourney = {
|
||||||
|
|
2
State.ts
2
State.ts
|
@ -201,7 +201,7 @@ export default class State {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const h = Hash.Get();
|
const h = Hash.hash;
|
||||||
this.selectedElement.addCallback(selected => {
|
this.selectedElement.addCallback(selected => {
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
h.setData("");
|
h.setData("");
|
||||||
|
|
|
@ -8,6 +8,7 @@ import State from "../../State";
|
||||||
import {TextField} from "../Input/TextField";
|
import {TextField} from "../Input/TextField";
|
||||||
import {Geocoding} from "../../Logic/Osm/Geocoding";
|
import {Geocoding} from "../../Logic/Osm/Geocoding";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
|
import Hash from "../../Logic/Web/Hash";
|
||||||
|
|
||||||
export default class SearchAndGo extends UIElement {
|
export default class SearchAndGo extends UIElement {
|
||||||
|
|
||||||
|
@ -61,11 +62,14 @@ export default class SearchAndGo extends UIElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bb = result[0].boundingbox;
|
const poi = result[0];
|
||||||
|
const bb = poi.boundingbox;
|
||||||
const bounds: [[number, number], [number, number]] = [
|
const bounds: [[number, number], [number, number]] = [
|
||||||
[bb[0], bb[2]],
|
[bb[0], bb[2]],
|
||||||
[bb[1], bb[3]]
|
[bb[1], bb[3]]
|
||||||
]
|
]
|
||||||
|
State.state.selectedElement. setData(undefined);
|
||||||
|
Hash.hash.setData(poi.osm_type+"_"+poi.osm_id);
|
||||||
State.state.leafletMap.data.fitBounds(bounds);
|
State.state.leafletMap.data.fitBounds(bounds);
|
||||||
self._placeholder.setData(Translations.t.general.search.search);
|
self._placeholder.setData(Translations.t.general.search.search);
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {OH} from "./OpeningHours";
|
||||||
import {InputElement} from "../Input/InputElement";
|
import {InputElement} from "../Input/InputElement";
|
||||||
import PublicHolidayInput from "./PublicHolidayInput";
|
import PublicHolidayInput from "./PublicHolidayInput";
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
|
import {Utils} from "../../Utils";
|
||||||
|
|
||||||
|
|
||||||
export default class OpeningHoursInput extends InputElement<string> {
|
export default class OpeningHoursInput extends InputElement<string> {
|
||||||
|
@ -63,15 +64,13 @@ export default class OpeningHoursInput extends InputElement<string> {
|
||||||
this._phSelector = new PublicHolidayInput(ph);
|
this._phSelector = new PublicHolidayInput(ph);
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
let rules = OH.ToString(rulesFromOhPicker.data);
|
const regular = OH.ToString(rulesFromOhPicker.data);
|
||||||
if (leftoverRules.data.length != 0) {
|
const rules : string[] = [
|
||||||
rules += ";" + leftoverRules.data.join(";")
|
regular,
|
||||||
}
|
...leftoverRules.data,
|
||||||
const phData = ph.data;
|
ph.data
|
||||||
if (phData !== undefined && phData !== "") {
|
]
|
||||||
rules += ";" + phData;
|
value.setData(Utils.NoEmpty(rules).join(";"));
|
||||||
}
|
|
||||||
value.setData(rules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rulesFromOhPicker.addCallback(update);
|
rulesFromOhPicker.addCallback(update);
|
||||||
|
|
|
@ -68,6 +68,12 @@ export default class ShowDataLayer {
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Hash.hash.addCallback(id => {
|
||||||
|
const action = self._onSelectedTrigger[id];
|
||||||
|
if(action){
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +145,9 @@ export default class ShowDataLayer {
|
||||||
leafletLayer.openPopup();
|
leafletLayer.openPopup();
|
||||||
uiElement.Activate();
|
uiElement.Activate();
|
||||||
}
|
}
|
||||||
|
this._onSelectedTrigger[feature.properties.id.replace("/","_")] = this._onSelectedTrigger[id];
|
||||||
|
|
||||||
|
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data) {
|
||||||
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
|
|
||||||
// This element is in the URL, so this is a share link
|
// This element is in the URL, so this is a share link
|
||||||
// We already open it
|
// We already open it
|
||||||
uiElement.Activate();
|
uiElement.Activate();
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
|
@ -8,6 +8,7 @@
|
||||||
"phone": {
|
"phone": {
|
||||||
"question": {
|
"question": {
|
||||||
"en": "What is the phone number of {name}?",
|
"en": "What is the phone number of {name}?",
|
||||||
|
"nl": "Wat is het telefoonnummer van {name}?",
|
||||||
"de": "Was ist die Telefonnummer von {name}?"
|
"de": "Was ist die Telefonnummer von {name}?"
|
||||||
},
|
},
|
||||||
"render": "<a href='tel:{phone}'>{phone}</a>",
|
"render": "<a href='tel:{phone}'>{phone}</a>",
|
||||||
|
|
27
assets/themes/bicycle_library/bicycle_library.json
Normal file
27
assets/themes/bicycle_library/bicycle_library.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "bicyclelib",
|
||||||
|
"maintainer": "MapComplete",
|
||||||
|
"version": "2020-08-29",
|
||||||
|
"language": [
|
||||||
|
"en",
|
||||||
|
"nl",
|
||||||
|
],
|
||||||
|
"title": {
|
||||||
|
"en": "Bicycle libraries",
|
||||||
|
"nl": "Fietsbibliotheken",
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"nl": "Een fietsbibliotheek is een plaats waar men een fiets kan lenen, vaak voor een klein bedrag per jaar. Een typisch voorbeeld zijn kinderfietsbibliotheken, waar men een fiets op maat van het kind kan lenen. Is het kind de fiets ontgroeid, dan kan het te kleine fietsje omgeruild worden voor een grotere.",
|
||||||
|
"en": "A bicycle library is a place where bicycles can be lent, often for a small yearly fee. A notable use case are bicycle libraries for kids, which allows them to change for a bigger bike when they've outgrown their current bike"
|
||||||
|
},
|
||||||
|
"icon": "./assets/themes/bicycle_library/logo.svg",
|
||||||
|
"socialImage": null,
|
||||||
|
"startLat": 0,
|
||||||
|
"startLon": 0,
|
||||||
|
"startZoom": 1,
|
||||||
|
"widenFactor": 0.05,
|
||||||
|
"roamingRenderings": [],
|
||||||
|
"layers": [
|
||||||
|
"bicycle_library"
|
||||||
|
]
|
||||||
|
}
|
166
assets/themes/bicycle_library/logo.svg
Normal file
166
assets/themes/bicycle_library/logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in a new issue