Add wikipedia box

This commit is contained in:
pietervdvn 2021-10-02 22:31:16 +02:00
parent 1edf829cad
commit 8b4442c8cc
20 changed files with 401 additions and 149 deletions

View file

@ -3,6 +3,7 @@ import ImageProvider, {ProvidedImage} from "./ImageProvider";
import BaseUIElement from "../../UI/BaseUIElement";
import Svg from "../../Svg";
import {WikimediaImageProvider} from "./WikimediaImageProvider";
import Wikidata from "../Web/Wikidata";
export class WikidataImageProvider extends ImageProvider {
@ -22,31 +23,18 @@ export class WikidataImageProvider extends ImageProvider {
}
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
const wikidataUrl = "https://www.wikidata.org/wiki/"
if (value.startsWith(wikidataUrl)) {
value = value.substring(wikidataUrl.length)
}
if(value.startsWith("http")){
// Probably some random link in the image field - we skip it
return undefined
}
if (!value.startsWith("Q")) {
value = "Q" + value
}
const url = "https://www.wikidata.org/wiki/Special:EntityData/" + value + ".json";
const response = await Utils.downloadJson(url)
const entity = response.entities[value];
const commons = entity.sitelinks.commonswiki;
const entity = await Wikidata.LoadWikidataEntry(value)
const allImages : Promise<ProvidedImage>[] = []
// P18 is the claim 'depicted in this image'
const image = entity.claims.P18?.[0]?.mainsnak?.datavalue?.value;
const allImages = []
if (image !== undefined) {
// We found a 'File://'
const promises = await WikimediaImageProvider.singleton.ExtractUrls(key, image)
for (const img of Array.from(entity.claims.get("P18") ?? [])) {
const promises = await WikimediaImageProvider.singleton.ExtractUrls(undefined, img)
allImages.push(...promises)
}
const commons =entity.wikisites.get("commons")
if (commons !== undefined) {
const promises = await WikimediaImageProvider.singleton.ExtractUrls(commons, image)
const promises = await WikimediaImageProvider.singleton.ExtractUrls(undefined , commons)
allImages.push(...promises)
}
return allImages

View file

@ -44,7 +44,6 @@ export class WikimediaImageProvider extends ImageProvider {
if (continueParameter !== undefined) {
url = `${url}&cmcontinue=${continueParameter}`;
}
console.debug("Loading a wikimedia category: ", url)
const response = await Utils.downloadJson(url)
const members = response.query?.categorymembers ?? [];
const imageOverview: string[] = members.map(member => member.title);
@ -135,8 +134,7 @@ export class WikimediaImageProvider extends ImageProvider {
}
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
if(key !== this.commons_key && !value.startsWith(WikimediaImageProvider.commonsPrefix)){
if(key !== undefined && key !== this.commons_key && !value.startsWith(WikimediaImageProvider.commonsPrefix)){
return []
}

89
Logic/Web/Wikidata.ts Normal file
View file

@ -0,0 +1,89 @@
import {Utils} from "../../Utils";
export interface WikidataResponse {
id: string,
labels: Map<string, string>,
descriptions: Map<string, string>,
claims: Map<string, Set<string>>,
wikisites: Map<string, string>
commons: string
}
/**
* Utility functions around wikidata
*/
export default class Wikidata {
private static ParseResponse(entity: any): WikidataResponse {
const labels = new Map<string, string>()
for (const labelName in entity.labels) {
// The labelname is the language code
labels.set(labelName, entity.labels[labelName].value)
}
const descr = new Map<string, string>()
for (const labelName in entity.descriptions) {
// The labelname is the language code
descr.set(labelName, entity.descriptions[labelName].value)
}
const sitelinks = new Map<string, string>();
for (const labelName in entity.sitelinks) {
// labelName is `${language}wiki`
const language = labelName.substring(0, labelName.length - 4)
const title = entity.sitelinks[labelName].title
sitelinks.set(language, title)
}
const commons = sitelinks.get("commons")
sitelinks.delete("commons")
const claims = new Map<string, Set<string>>();
for (const claimId of entity.claims) {
const claimsList: any[] = entity.claims[claimId]
const values = new Set<string>()
for (const claim of claimsList) {
const value = claim.mainsnak.datavalue.value;
values.add(value)
}
claims.set(claimId, values);
}
return {
claims: claims,
descriptions: descr,
id: entity.id,
labels: labels,
wikisites: sitelinks,
commons: commons
}
}
/**
* Loads a wikidata page
* @returns the entity of the given value
*/
public static async LoadWikidataEntry(value: string | number): Promise<WikidataResponse> {
const wikidataUrl = "https://www.wikidata.org/wiki/"
if (typeof value === "number") {
value = "Q" + value
}
if (value.startsWith(wikidataUrl)) {
value = value.substring(wikidataUrl.length)
}
if (value.startsWith("http")) {
// Probably some random link in the image field - we skip it
return undefined
}
if (!value.startsWith("Q")) {
value = "Q" + value
}
const url = "https://www.wikidata.org/wiki/Special:EntityData/" + value + ".json";
const response = await Utils.downloadJson(url)
return Wikidata.ParseResponse(response.entities[value]);
}
}

View file

@ -2,7 +2,8 @@
* Some usefull utility functions around the wikipedia API
*/
import {Utils} from "../../Utils";
import WikipediaBox from "../../UI/WikipediaBox";
import {UIEventSource} from "../UIEventSource";
import Wikidata from "./Wikidata";
export default class Wikipedia {
@ -14,22 +15,36 @@ export default class Wikipedia {
private static readonly classesToRemove = [
"shortdescription",
"sidebar",
"infobox",
"infobox","infobox_v2",
"noprint",
"ambox",
"mw-editsection",
"mw-selflink",
"hatnote" // Often redirects
]
public static async GetArticle(options: {
private static readonly _cache = new Map<string, UIEventSource<{ success: string } | { error: any }>>()
public static GetArticle(options: {
pageName: string,
language?: "en" | string,
section?: number,
language?: "en" | string}): UIEventSource<{ success: string } | { error: any }>{
const key = (options.language ?? "en")+":"+options.pageName
const cached = Wikipedia._cache.get(key)
if(cached !== undefined){
return cached
}
const v = UIEventSource.FromPromiseWithErr(Wikipedia.GetArticleAsync(options))
Wikipedia._cache.set(key, v)
return v;
}
public static async GetArticleAsync(options: {
pageName: string,
language?: "en" | string
}): Promise<string> {
let section = ""
if (options.section !== undefined) {
section = "&section=" + options.section
}
const url = `https://${options.language ?? "en"}.wikipedia.org/w/api.php?action=parse${section}&format=json&origin=*&prop=text&page=` + options.pageName
const language = options.language ?? "en"
const url = `https://${language}.wikipedia.org/w/api.php?action=parse&format=json&origin=*&prop=text&page=` + options.pageName
const response = await Utils.downloadJson(url)
const html = response["parse"]["text"]["*"];
@ -43,7 +58,19 @@ export default class Wikipedia {
toRemoveElement.parentElement?.removeChild(toRemoveElement)
}
}
return content.innerHTML;
const links = Array.from(content.getElementsByTagName("a"))
console.log("Links are", links)
// Rewrite relative links to absolute links + open them in a new tab
links.filter(link => link.getAttribute("href")?.startsWith("/") ?? false).
forEach(link => {
link.target = '_blank'
// note: link.getAttribute("href") gets the textual value, link.href is the rewritten version which'll contain the host for relative paths
link.href = `https://${language}.wikipedia.org${link.getAttribute("href")}`;
})
return content.innerHTML
}
}

View file

@ -9,9 +9,9 @@ export default class Loading extends Combine {
const t = Translations.T(msg ) ?? Translations.t.general.loading.Clone();
t.SetClass("pl-2")
super([
Svg.loading_svg().SetClass("animate-spin").SetStyle("width: 1.5rem; height: 1.5rem; margin-bottom: 4px;"),
Svg.loading_svg().SetClass("animate-spin").SetStyle("width: 1.5rem; height: 1.5rem;"),
t
])
this.SetClass("flex m-1")
this.SetClass("flex p-1")
}
}

View file

@ -225,7 +225,6 @@ export default class ShowDataLayer {
popup.setContent(`<div style='height: 65vh' id='${id}'>Popup for ${feature.properties.id} ${feature.geometry.type}</div>`)
leafletLayer.on("popupopen", () => {
console.trace(`Opening the popup for ${feature.properties.id} ${feature.geometry.type}`)
if (infobox === undefined) {
const tags = State.state.allElements.getEventSourceById(feature.properties.id);
infobox = new FeatureInfoBox(tags, layer);
@ -239,7 +238,9 @@ export default class ShowDataLayer {
}
infobox.AttachTo(id)
infobox.Activate();
if (State.state?.selectedElement?.data?.properties?.id !== feature.properties.id) {
State.state.selectedElement.setData(feature)
}
});

View file

@ -26,6 +26,7 @@ import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSou
import ShowDataMultiLayer from "./ShowDataLayer/ShowDataMultiLayer";
import Minimap from "./Base/Minimap";
import AllImageProviders from "../Logic/ImageProviders/AllImageProviders";
import WikipediaBox from "./WikipediaBox";
export interface SpecialVisualization {
funcName: string,
@ -84,6 +85,20 @@ export default class SpecialVisualizations {
return new ImageUploadFlow(tags, args[0])
}
},
{
funcName: "wikipedia",
docs: "A box showing the corresponding wikipedia article - based on the wikidata tag",
args: [
{
name: "keyToShowWikipediaFor",
doc: "Use the wikidata entry from this key to show the wikipedia article for",
defaultValue: "wikidata"
}
],
example: "`{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height",
constr: (_, tagsSource, args) =>
new WikipediaBox( tagsSource.map(tags => tags[args[0]]))
},
{
funcName: "minimap",
docs: "A small map showing the selected feature. Note that no styling is applied, wrap this in a div",
@ -156,7 +171,7 @@ export default class SpecialVisualizations {
new ShowDataMultiLayer(
{
leafletMap: minimap["leafletMap"],
enablePopups : false,
enablePopups: false,
zoomToFeatures: true,
layers: State.state.filteredLayers,
features: new StaticFeatureSource(featuresToShow, true)
@ -411,8 +426,8 @@ There are also some technicalities in your theme to keep in mind:
}
return kv
})
const rewrittenTags : UIEventSource<Tag[]> = tagSource.map(tags => {
const newTags : Tag [] = []
const rewrittenTags: UIEventSource<Tag[]> = tagSource.map(tags => {
const newTags: Tag [] = []
for (const [key, value] of tgsSpec) {
if (value.startsWith('$')) {
const origKey = value.substring(1)
@ -446,9 +461,9 @@ There are also some technicalities in your theme to keep in mind:
[
new Title(viz.funcName, 3),
viz.docs,
new Table(["name", "default", "description"],
viz.args.length > 0 ? new Table(["name", "default", "description"],
viz.args.map(arg => [arg.name, arg.defaultValue ?? "undefined", arg.doc])
),
) : undefined,
new Title("Example usage", 4),
new FixedUiElement(
viz.example ?? "`{" + viz.funcName + "(" + viz.args.map(arg => arg.defaultValue).join(",") + ")}`"

View file

@ -8,46 +8,109 @@ import BaseUIElement from "./BaseUIElement";
import Title from "./Base/Title";
import Translations from "./i18n/Translations";
import Svg from "../Svg";
import Wikidata from "../Logic/Web/Wikidata";
import Locale from "./i18n/Locale";
export default class WikipediaBox extends Combine{
export default class WikipediaBox extends Combine {
constructor(options: {
pagename: string,
language: string
}) {
const htmlContent = UIEventSource.FromPromiseWithErr(Wikipedia.GetArticle({
pageName: options.pagename,
language: options.language,
removeInfoBoxes: true
}))
const contents : UIEventSource<string | BaseUIElement> = htmlContent.map(htmlContent => {
if(htmlContent === undefined){
// Still loading
return new Loading("Loading wikipedia page").SetClass("p-4")
}
if(htmlContent["success"] !== undefined){
return new FixedUiElement(htmlContent["success"]).SetClass("wikipedia-article")
}
if(htmlContent["error"]){
return new FixedUiElement(htmlContent["error"]).SetClass("alert p-4")
private static async ExtractWikiPages(wikidata): Promise<Map<string, string>> {
return (await Wikidata.LoadWikidataEntry(wikidata)).wikisites
}
return undefined
private static _cache = new Map()
constructor(wikidataId: string | UIEventSource<string>) {
const wp = Translations.t.general.wikipedia;
if(typeof wikidataId === "string"){
wikidataId = new UIEventSource(wikidataId)
}
const knownPages = new UIEventSource<{success:Map<string, string>}|{error:any}>(undefined)
wikidataId.addCallbackAndRunD(wikidataId => {
WikipediaBox.ExtractWikiPages(wikidataId).then(pages => {
knownPages.setData({success:pages})
}).catch(err=> {
knownPages.setData({error: err})
})
})
const scrollable = new Combine([new VariableUiElement(contents).SetClass("block pl-6 pt-2")])
.SetClass("block overflow-auto normal-background rounded-lg")
const cachedPages = new Map<string, BaseUIElement>()
const contents = new VariableUiElement(
knownPages.map(pages => {
if (pages === undefined) {
return new Loading(wp.loading.Clone())
}
if (pages["error"] !== undefined) {
return wp.failed.Clone().SetClass("alert p-4")
}
const dict: Map<string, string> = pages["success"]
const preferredLanguage = [Locale.language.data, "en", Array.from(dict.keys())[0]]
let language
let pagetitle;
let i = 0
do {
language = preferredLanguage[i]
pagetitle = dict.get(language)
i++;
if(i >= preferredLanguage.length){
return wp.noWikipediaPage.Clone()
}
} while (pagetitle === undefined)
if(cachedPages.has(language)){
return cachedPages.get(language)
}
const page = WikipediaBox.createContents(pagetitle, language);
cachedPages.set(language, page)
return page
}, [Locale.language])
).SetClass("overflow-auto normal-background rounded-lg")
super([
new Combine([Svg.wikipedia_svg().SetStyle("width: 1.5rem").SetClass("mr-3"),
new Title(Translations.t.general.wikipedia.wikipediaboxTitle, 2)]).SetClass("flex"),
scrollable])
new Combine([Svg.wikipedia_ui().SetStyle("width: 1.5rem").SetClass("mr-3"),
new Title(Translations.t.general.wikipedia.wikipediaboxTitle.Clone(), 2)]).SetClass("flex"),
contents])
this
.SetClass("block rounded-xl subtle-background m-1 p-2 flex flex-col")
}
/**
* Returns the actual content in a scrollable way
* @param pagename
* @param language
* @private
*/
private static createContents(pagename: string, language: string): BaseUIElement {
const htmlContent = Wikipedia.GetArticle({
pageName: pagename,
language: language
})
const wp = Translations.t.general.wikipedia
const contents: UIEventSource<string | BaseUIElement> = htmlContent.map(htmlContent => {
if (htmlContent === undefined) {
// Still loading
return new Loading(wp.loading.Clone())
}
if (htmlContent["success"] !== undefined) {
return new FixedUiElement(htmlContent["success"]).SetClass("wikipedia-article")
}
if (htmlContent["error"]) {
return wp.failed.Clone().SetClass("alert p-4")
}
return undefined
})
return new Combine([new VariableUiElement(contents).SetClass("block pl-6 pt-2")])
.SetClass("block")
}
}

View file

@ -392,7 +392,8 @@
}
],
"id": "Surface area"
}
},
"wikipedia"
],
"wayHandling": 2,
"icon": {

View file

@ -122,7 +122,8 @@
},
"id": "Payment methods"
},
"wheelchair-access"
"wheelchair-access",
"wikipedia"
],
"wayHandling": 1,
"icon": {

View file

@ -5,12 +5,17 @@
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"
fill="none"
viewBox="0 0 25 25"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 24.022156 24.021992"
version="1.1"
id="svg6">
id="svg9"
sodipodi:docname="loading.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
width="24.022156"
height="24.021992">
<metadata
id="metadata12">
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
@ -21,18 +26,53 @@
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1043"
id="namedview11"
showgrid="false"
inkscape:zoom="19.666667"
inkscape:cx="-1.7824593"
inkscape:cy="7.7694192"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg9" />
<defs
id="defs10" />
<circle
class="opacity-25"
cx="12.529661"
cy="12.529661"
r="10.441384"
id="circle2"
style="stroke:#000000;stroke-width:4.17655373;stroke-opacity:0.33976835" />
id="defs4">
<style
id="style2">.cls-1{fill:#000;}</style>
</defs>
<path
style="fill:currentColor;stroke-width:1.04413843"
class="opacity-75"
d="M 4.1765537,12.529661 A 8.3531073,8.3531073 0 0 1 12.529661,4.1765537 V 0 C 5.6101557,0 0,5.6101557 0,12.529661 Z m 2.0882768,5.524536 A 8.3134301,8.3134301 0 0 1 4.1765537,12.529661 H 0 c 0,3.176269 1.1850971,6.081062 3.1324153,8.288371 z"
id="path4" />
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:3.26200151;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.26635515"
id="path821"
sodipodi:type="arc"
sodipodi:cx="12.010992"
sodipodi:cy="12.010992"
sodipodi:rx="10.379992"
sodipodi:ry="10.379992"
sodipodi:start="0"
sodipodi:end="6.2828013"
sodipodi:open="true"
d="M 22.390984,12.010992 A 10.379992,10.379992 0 0 1 12.011989,22.390984 10.379992,10.379992 0 0 1 1.6310007,12.012985 10.379992,10.379992 0 0 1 12.008003,1.6310009 10.379992,10.379992 0 0 1 22.390983,12.007006" />
<path
d="m 22.390984,12.010992 a 10.379992,10.379992 0 0 1 -3.26001,7.55315 10.379992,10.379992 0 0 1 -7.732307,2.808765"
sodipodi:open="true"
sodipodi:end="1.6298215"
sodipodi:start="0"
sodipodi:ry="10.379992"
sodipodi:rx="10.379992"
sodipodi:cy="12.010992"
sodipodi:cx="12.010992"
sodipodi:type="arc"
id="path838"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:3.26200151;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -2,6 +2,9 @@
"images": {
"render": "{image_carousel()}{image_upload()}"
},
"wikipedia": {
"render": "{wikipedia():max-height:25rem}"
},
"reviews": {
"render": "{reviews()}"
},

View file

@ -812,10 +812,6 @@ video {
margin: 0px;
}
.m-4 {
margin: 1rem;
}
.m-2 {
margin: 0.5rem;
}
@ -824,8 +820,8 @@ video {
margin: 0.75rem;
}
.m-6 {
margin: 1.5rem;
.m-4 {
margin: 1rem;
}
.my-2 {
@ -852,8 +848,8 @@ video {
margin-left: 0.75rem;
}
.ml-2 {
margin-left: 0.5rem;
.mr-3 {
margin-right: 0.75rem;
}
.mb-2 {
@ -892,6 +888,10 @@ video {
margin-top: 0px;
}
.ml-2 {
margin-left: 0.5rem;
}
.mt-4 {
margin-top: 1rem;
}
@ -912,18 +912,10 @@ video {
margin-bottom: 0.25rem;
}
.mr-3 {
margin-right: 0.75rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.ml-4 {
margin-left: 1rem;
}
.box-border {
box-sizing: border-box;
}
@ -1794,8 +1786,6 @@ svg, img {
box-sizing: content-box;
width: 100%;
height: 100%;
display: unset;
vertical-align: unset;
}
.mapcontrol svg path {

View file

@ -1,7 +1,7 @@
/* This stylesheet reimplements a few classes from wikipedia to show their articles prettily */
.wikipedia-article {
font-family: sans-serif;
font-family: sans-serif !important;
}
.wikipedia-article .tright {
@ -9,6 +9,12 @@
clear: right;
}
.wikipedia-article svg, img {
width: unset;
height: unset;
display: unset;
}
.wikipedia-article .thumb {
background: var(--subtle-detail-color);
margin: 1rem;
@ -17,15 +23,17 @@
border-radius: 0.5rem;
}
.wikipedia-article a {
color: #0645ad;
background: none;
.wikipedia-article a:hover a:focus {
text-decoration: underline !important;
}
.wikipedia-article a:hover a:focus {
text-decoration: underline;
.wikipedia-article a {
color: #0645ad !important;
background: none !important;
text-decoration: none;
}
.wikipedia-article p {
margin-bottom: 0.5rem;
}

View file

@ -91,8 +91,6 @@ svg, img {
box-sizing: content-box;
width: 100%;
height: 100%;
display: unset;
vertical-align: unset;
}
.mapcontrol svg path {

View file

@ -14,6 +14,7 @@
<link href="vendor/MarkerCluster.css" rel="stylesheet"/>
<link href="vendor/MarkerCluster.Default.css" rel="stylesheet"/>
<link href="./css/index-tailwind-output.css" rel="stylesheet" />
<link href="./css/wikipedia.css" rel="stylesheet" />
<meta content="website" property="og:type">
<!-- THEME-SPECIFIC -->

View file

@ -218,7 +218,10 @@
"error_loading": "Could not load the histogram"
},
"wikipedia": {
"wikipediaboxTitle": "Wikipedia"
"wikipediaboxTitle": "Wikipedia",
"failed":"Loading the wikipedia entry failed",
"loading": "Loading Wikipedia...",
"noWikipediaPage": "This wikidata item has no corresponding wikipedia page yet."
}
},
"favourite": {

View file

@ -743,6 +743,22 @@
"description": "On this map, publicly accessible drinking water spots are shown and can be easily added",
"title": "Drinking Water"
},
"etymology": {
"description": "On this map, you can see what an object is named after. The streets, buildings, ... come from OpenStreetMap which got linked with Wikidata. The information comes from Wpikipedia.",
"layers": {
"0": {
"description": "All objects which have an etymology known",
"name": "Has etymolgy",
"tagRenderings": {
"simple etymology": {
"render": "Named after {name:etymology}"
}
}
}
},
"shortDescription": "What is the origin of a toponym?",
"title": "Open Etymology Map"
},
"facadegardens": {
"description": "<a href='https://nl.wikipedia.org/wiki/Geveltuin' target=_blank>Facade gardens</a>, green facades and trees in the city not only bring peace and quiet, but also a more beautiful city, greater biodiversity, a cooling effect and better air quality. <br/> Klimaan VZW and Mechelen Klimaatneutraal want to map existing and new facade gardens as an example for people who want to build their own garden or for city walkers who love nature.<br/>More info about the project at <a href='https://klimaan.be/' target=_blank>klimaan.be</a>.",
"layers": {

View file

@ -624,6 +624,22 @@
"description": "Op deze kaart staan publiek toegankelijke drinkwaterpunten en kan je makkelijk een nieuw drinkwaterpunt toevoegen",
"title": "Drinkwaterpunten"
},
"etymology": {
"description": "Op deze kaart zie je waar een plaats naar is vernoemd. De straten, gebouwen, ... komen uit OpenStreetMap, waar een link naar Wikidata werd gelegd. De informatie komt uit wikipedia.",
"layers": {
"0": {
"description": "Alle lagen met een gelinkt etymology",
"name": "Heeft etymology info",
"tagRenderings": {
"simple etymology": {
"render": "Vernoemd naar {name:etymology}"
}
}
}
},
"shortDescription": "Wat is de oorsprong van een plaatsnaam?",
"title": "Open Etymology-kaart"
},
"facadegardens": {
"description": "Ontharde voortuintjes, groene gevels en bomen ín de stad brengen naast rust ook een mooiere stad, een grotere biodiversiteit, een verkoelend effect en een betere luchtkwaliteit. <br/> Klimaan VZW en 'Mechelen Klimaatneutraal' willen met het project Klim(t)aan je Gevel bestaande en nieuwe geveltuintjes in kaart brengen als voorbeeld voor mensen zelf een tuintje willen aanleggen of voor stadwandelaars die houden van de natuur. <br/>Meer info over het project op <a href='https://klimaan.be/' target=_blank>klimaan.be</a>.",
"layers": {

16
test.ts
View file

@ -1,14 +1,8 @@
import Wikipedia from "./Logic/Web/Wikipedia";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import Wikidata from "./Logic/Web/Wikidata";
import WikipediaBox from "./UI/WikipediaBox";
import Loading from "./UI/Base/Loading";
import Locale from "./UI/i18n/Locale";
import LanguagePicker from "./UI/LanguagePicker";
new WikipediaBox({
pagename: "Poertoren",
language: "nl"
})
.SetStyle("max-height: 20rem;")
new WikipediaBox("Q177").SetStyle("max-height: 25rem")
.AttachTo("maindiv")
LanguagePicker.CreateLanguagePicker(["en","nl","fr","de"]).AttachTo("extradiv")