Add Wikipedia page box

This commit is contained in:
pietervdvn 2021-10-02 17:57:54 +02:00
parent df34239256
commit 9df263c362
12 changed files with 3605 additions and 3457 deletions

View file

@ -62,9 +62,29 @@ export class UIEventSource<T> {
return source; return source;
} }
/**
* Converts a promise into a UIVentsource, sets the UIEVentSource when the result is calculated.
* If the promise fails, the value will stay undefined
* @param promise
* @constructor
*/
public static FromPromise<T>(promise : Promise<T>): UIEventSource<T>{ public static FromPromise<T>(promise : Promise<T>): UIEventSource<T>{
const src = new UIEventSource<T>(undefined) const src = new UIEventSource<T>(undefined)
promise?.then(d => src.setData(d)) promise?.then(d => src.setData(d))
promise?.catch(err => console.warn("Promise failed:", err))
return src
}
/**
* Converts a promise into a UIVentsource, sets the UIEVentSource when the result is calculated.
* If the promise fails, the value will stay undefined
* @param promise
* @constructor
*/
public static FromPromiseWithErr<T>(promise : Promise<T>): UIEventSource<{success: T} | {error: any}>{
const src = new UIEventSource<{success: T}|{error: any}>(undefined)
promise?.then(d => src.setData({success:d}))
promise?.catch(err => src.setData({error: err}))
return src return src
} }

View file

@ -0,0 +1,49 @@
/**
* Some usefull utility functions around the wikipedia API
*/
import {Utils} from "../../Utils";
import WikipediaBox from "../../UI/WikipediaBox";
export default class Wikipedia {
/**
* When getting a wikipedia page data result, some elements (e.g. navigation, infoboxes, ...) should be removed if 'removeInfoBoxes' is set.
* We do this based on the classes. This set contains a blacklist of the classes to remove
* @private
*/
private static readonly classesToRemove = [
"shortdescription",
"sidebar",
"infobox",
"mw-editsection",
"hatnote" // Often redirects
]
public static async GetArticle(options: {
pageName: string,
language?: "en" | string,
section?: number,
}): 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 response = await Utils.downloadJson(url)
const html = response["parse"]["text"]["*"];
const div = document.createElement("div")
div.innerHTML = html
const content = Array.from(div.children)[0]
for (const forbiddenClass of Wikipedia.classesToRemove) {
const toRemove = content.getElementsByClassName(forbiddenClass)
for (const toRemoveElement of Array.from(toRemove)) {
toRemoveElement.parentElement?.removeChild(toRemoveElement)
}
}
return content.innerHTML;
}
}

View file

@ -1,7 +1,17 @@
import {FixedUiElement} from "./FixedUiElement"; import {FixedUiElement} from "./FixedUiElement";
import {Translation} from "../i18n/Translation";
import Combine from "./Combine";
import Svg from "../../Svg";
import Translations from "../i18n/Translations";
export default class Loading extends FixedUiElement { export default class Loading extends Combine {
constructor() { constructor(msg?: Translation | string) {
super("Loading..."); // TODO to be improved 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;"),
t
])
this.SetClass("flex m-1")
} }
} }

53
UI/WikipediaBox.ts Normal file
View file

@ -0,0 +1,53 @@
import {UIEventSource} from "../Logic/UIEventSource";
import {VariableUiElement} from "./Base/VariableUIElement";
import Wikipedia from "../Logic/Web/Wikipedia";
import Loading from "./Base/Loading";
import {FixedUiElement} from "./Base/FixedUiElement";
import Combine from "./Base/Combine";
import BaseUIElement from "./BaseUIElement";
import Title from "./Base/Title";
import Translations from "./i18n/Translations";
import Svg from "../Svg";
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")
}
return undefined
})
const scrollable = new Combine([new VariableUiElement(contents).SetClass("block pl-6 pt-2")])
.SetClass("block 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])
this
.SetClass("block rounded-xl subtle-background m-1 p-2 flex flex-col")
}
}

View file

@ -3,16 +3,12 @@
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
fill="none" fill="none"
viewBox="0 0 24 24" viewBox="0 0 25 25"
version="1.1" version="1.1"
id="svg6" id="svg6">
sodipodi:docname="loading.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata <metadata
id="metadata12"> id="metadata12">
<rdf:RDF> <rdf:RDF>
@ -20,44 +16,23 @@
rdf:about=""> rdf:about="">
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<defs <defs
id="defs10"/> id="defs10" />
<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="1003"
id="namedview8"
showgrid="false"
inkscape:zoom="13.906433"
inkscape:cx="14.114788"
inkscape:cy="9.6469257"
inkscape:window-x="1024"
inkscape:window-y="1080"
inkscape:window-maximized="1"
inkscape:current-layer="svg6"/>
<circle <circle
class="opacity-25" class="opacity-25"
cx="12" cx="12.529661"
cy="12" cy="12.529661"
r="10" r="10.441384"
id="circle2" id="circle2"
stroke-width="4" style="stroke:#000000;stroke-width:4.17655373;stroke-opacity:0.33976835" />
stroke="currentColor"
style="stroke:#000000;stroke-opacity:0.33976835"/>
<path <path
style="fill:currentColor;stroke-width:1.04413843"
class="opacity-75" class="opacity-75"
fill="currentColor" 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"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" id="path4" />
id="path4"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -812,6 +812,10 @@ video {
margin: 0px; margin: 0px;
} }
.m-4 {
margin: 1rem;
}
.m-2 { .m-2 {
margin: 0.5rem; margin: 0.5rem;
} }
@ -820,8 +824,8 @@ video {
margin: 0.75rem; margin: 0.75rem;
} }
.m-4 { .m-6 {
margin: 1rem; margin: 1.5rem;
} }
.my-2 { .my-2 {
@ -844,18 +848,14 @@ video {
margin-right: 1rem; margin-right: 1rem;
} }
.-ml-1 {
margin-left: -0.25rem;
}
.mr-3 {
margin-right: 0.75rem;
}
.ml-3 { .ml-3 {
margin-left: 0.75rem; margin-left: 0.75rem;
} }
.ml-2 {
margin-left: 0.5rem;
}
.mb-2 { .mb-2 {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
@ -892,10 +892,6 @@ video {
margin-top: 0px; margin-top: 0px;
} }
.ml-2 {
margin-left: 0.5rem;
}
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@ -916,10 +912,18 @@ video {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
.mr-3 {
margin-right: 0.75rem;
}
.mb-4 { .mb-4 {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.ml-4 {
margin-left: 1rem;
}
.box-border { .box-border {
box-sizing: border-box; box-sizing: border-box;
} }
@ -968,10 +972,6 @@ video {
height: 100%; height: 100%;
} }
.h-5 {
height: 1.25rem;
}
.h-24 { .h-24 {
height: 6rem; height: 6rem;
} }
@ -988,6 +988,10 @@ video {
height: 3rem; height: 3rem;
} }
.h-5 {
height: 1.25rem;
}
.h-screen { .h-screen {
height: 100vh; height: 100vh;
} }
@ -1032,10 +1036,6 @@ video {
width: 100%; width: 100%;
} }
.w-5 {
width: 1.25rem;
}
.w-10 { .w-10 {
width: 2.5rem; width: 2.5rem;
} }
@ -1394,6 +1394,18 @@ video {
padding: 0px; padding: 0px;
} }
.pl-6 {
padding-left: 1.5rem;
}
.pt-2 {
padding-top: 0.5rem;
}
.pl-2 {
padding-left: 0.5rem;
}
.pt-3 { .pt-3 {
padding-top: 0.75rem; padding-top: 0.75rem;
} }
@ -1422,10 +1434,6 @@ video {
padding-top: 1.5rem; padding-top: 1.5rem;
} }
.pl-2 {
padding-left: 0.5rem;
}
.pl-5 { .pl-5 {
padding-left: 1.25rem; padding-left: 1.25rem;
} }
@ -1787,6 +1795,7 @@ svg, img {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: unset; display: unset;
vertical-align: unset;
} }
.mapcontrol svg path { .mapcontrol svg path {
@ -1876,6 +1885,11 @@ li::marker {
color: var(--subtle-detail-color-contrast); color: var(--subtle-detail-color-contrast);
} }
.normal-background {
background: var(--background-color);
color: var(--foreground-color)
}
.subtle-lighter { .subtle-lighter {
color: var(--subtle-detail-color-light-contrast); color: var(--subtle-detail-color-light-contrast);
} }

32
css/wikipedia.css Normal file
View file

@ -0,0 +1,32 @@
/* This stylesheet reimplements a few classes from wikipedia to show their articles prettily */
.wikipedia-article {
font-family: sans-serif;
}
.wikipedia-article .tright {
float: right;
clear: right;
}
.wikipedia-article .thumb {
background: var(--subtle-detail-color);
margin: 1rem;
padding: 0.5rem;
border: 1px solid var(--subtle-detail-color-light-contrast);
border-radius: 0.5rem;
}
.wikipedia-article a {
color: #0645ad;
background: none;
}
.wikipedia-article a:hover a:focus {
text-decoration: underline;
}
.wikipedia-article p {
margin-bottom: 0.5rem;
}

View file

@ -92,6 +92,7 @@ svg, img {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: unset; display: unset;
vertical-align: unset;
} }
.mapcontrol svg path { .mapcontrol svg path {
@ -179,6 +180,11 @@ li::marker {
color: var(--subtle-detail-color-contrast); color: var(--subtle-detail-color-contrast);
} }
.normal-background {
background: var(--background-color);
color: var(--foreground-color)
}
.subtle-lighter { .subtle-lighter {
color: var(--subtle-detail-color-light-contrast); color: var(--subtle-detail-color-light-contrast);
} }

View file

@ -62,6 +62,7 @@
"readMessages": "You have unread messages. Read these before deleting a point - someone might have feedback" "readMessages": "You have unread messages. Read these before deleting a point - someone might have feedback"
}, },
"general": { "general": {
"loading": "Loading...",
"pdf": { "pdf": {
"generatedWith": "Generated with MapComplete.osm.be", "generatedWith": "Generated with MapComplete.osm.be",
"attr": "Map data © OpenStreetMap Contributors, reusable under ODbL", "attr": "Map data © OpenStreetMap Contributors, reusable under ODbL",
@ -215,6 +216,9 @@
}, },
"histogram": { "histogram": {
"error_loading": "Could not load the histogram" "error_loading": "Could not load the histogram"
},
"wikipedia": {
"wikipediaboxTitle": "Wikipedia"
} }
}, },
"favourite": { "favourite": {

View file

@ -10,6 +10,8 @@
<link href="./css/mobile.css" rel="stylesheet"/> <link href="./css/mobile.css" rel="stylesheet"/>
<link href="./css/openinghourstable.css" rel="stylesheet"/> <link href="./css/openinghourstable.css" rel="stylesheet"/>
<link href="./css/tagrendering.css" rel="stylesheet"/> <link href="./css/tagrendering.css" rel="stylesheet"/>
<link href="./css/index-tailwind-output.css" rel="stylesheet"/>
<link href="./css/wikipedia.css" rel="stylesheet"/>
<link href="css/ReviewElement.css" rel="stylesheet"/> <link href="css/ReviewElement.css" rel="stylesheet"/>
<link href="vendor/MarkerCluster.css" rel="stylesheet"/> <link href="vendor/MarkerCluster.css" rel="stylesheet"/>
<link href="vendor/MarkerCluster.Default.css" rel="stylesheet"/> <link href="vendor/MarkerCluster.Default.css" rel="stylesheet"/>

33
test.ts
View file

@ -1,31 +1,14 @@
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; import Wikipedia from "./Logic/Web/Wikipedia";
import TagRenderingQuestion from "./UI/Popup/TagRenderingQuestion"; import {FixedUiElement} from "./UI/Base/FixedUiElement";
import {UIEventSource} from "./Logic/UIEventSource"; import WikipediaBox from "./UI/WikipediaBox";
import {VariableUiElement} from "./UI/Base/VariableUIElement"; import Loading from "./UI/Base/Loading";
const theme = AllKnownLayouts.allKnownLayouts.get("charging_stations")
const tagRendering = theme.layers[0].tagRenderings.filter(tr => tr.id === "Available_charging_stations (generated)")[0] new WikipediaBox({
const tag = new UIEventSource({ pagename: "Poertoren",
id: "node/42", language: "nl"
amenity:"charging_station",
bicycle:"yes",
car:"no",
"motorcar":"no",
"hgv":"no",
bus:"no"
}) })
window.tags = tag .SetStyle("max-height: 20rem;")
//const q =
new VariableUiElement(tag.map(_ => new TagRenderingQuestion(tag, tagRendering) ))
.SetStyle("width: 100px")
.AttachTo("maindiv") .AttachTo("maindiv")
window.setTimeout(_ => {
tag.data.bicycle="no"
tag.data.car = "yes"
tag.ping()
console.log("Pinged")
}, 2500)