Support for lexemes, decent etymology layer and theme with rudimentary icon

This commit is contained in:
pietervdvn 2021-10-09 22:40:52 +02:00
parent 9726d85ad7
commit 9faac532b5
18 changed files with 611 additions and 270 deletions

1
.gitignore vendored
View file

@ -16,3 +16,4 @@ missing_translations.txt
*.swp
.DS_Store
Svg.ts
data/

View file

@ -2,27 +2,33 @@ import {Utils} from "../../Utils";
import {UIEventSource} from "../UIEventSource";
export interface WikidataResponse {
export class WikidataResponse {
public readonly id: string
public readonly labels: Map<string, string>
public readonly descriptions: Map<string, string>
public readonly claims: Map<string, Set<string>>
public readonly wikisites: Map<string, string>
public readonly commons: string
id: string,
labels: Map<string, string>,
descriptions: Map<string, string>,
claims: Map<string, Set<string>>,
wikisites: Map<string, string>
commons: string
}
constructor(
id: string,
labels: Map<string, string>,
descriptions: Map<string, string>,
claims: Map<string, Set<string>>,
wikisites: Map<string, string>,
commons: string
) {
export interface WikidataSearchoptions {
lang?: "en" | string,
maxCount?: 20 | number
}
this.id = id
this.labels = labels
this.descriptions = descriptions
this.claims = claims
this.wikisites = wikisites
this.commons = commons
/**
* Utility functions around wikidata
*/
export default class Wikidata {
}
private static ParseResponse(entity: any): WikidataResponse {
public static fromJson(entity: any): WikidataResponse {
const labels = new Map<string, string>()
for (const labelName in entity.labels) {
// The labelname is the language code
@ -45,40 +51,104 @@ export default class Wikidata {
const commons = sitelinks.get("commons")
sitelinks.delete("commons")
const claims = WikidataResponse.extractClaims(entity.claims);
return new WikidataResponse(
entity.id,
labels,
descr,
claims,
sitelinks,
commons
)
}
static extractClaims(claimsJson: any): Map<string, Set<string>> {
const claims = new Map<string, Set<string>>();
for (const claimId in entity.claims) {
for (const claimId in claimsJson) {
const claimsList: any[] = entity.claims[claimId]
const claimsList: any[] = claimsJson[claimId]
const values = new Set<string>()
for (const claim of claimsList) {
let value = claim.mainsnak?.datavalue?.value;
if (value === undefined) {
continue;
}
if(value.id !== undefined){
if (value.id !== undefined) {
value = value.id
}
values.add(value)
}
claims.set(claimId, values);
}
return claims
}
}
return {
claims: claims,
descriptions: descr,
id: entity.id,
labels: labels,
wikisites: sitelinks,
commons: commons
export class WikidataLexeme {
id: string
lemma: Map<string, string>
senses: Map<string, string>
claims: Map<string, Set<string>>
constructor(json) {
this.id = json.id
this.claims = WikidataResponse.extractClaims(json.claims)
this.lemma = new Map<string, string>()
for (const language in json.lemmas) {
this.lemma.set(language, json.lemmas[language].value)
}
this.senses = new Map<string, string>()
for (const sense of json.senses) {
const glosses = sense.glosses
for (const language in glosses) {
let previousSenses = this.senses.get(language)
if(previousSenses === undefined){
previousSenses = ""
}else{
previousSenses = previousSenses+"; "
}
this.senses.set(language, previousSenses + glosses[language].value ?? "")
}
}
}
private static readonly _cache = new Map<number, UIEventSource<{success: WikidataResponse} | {error: any}>>()
public static LoadWikidataEntry(value: string | number): UIEventSource<{success: WikidataResponse} | {error: any}> {
asWikidataResponse() {
return new WikidataResponse(
this.id,
this.lemma,
this.senses,
this.claims,
new Map(),
undefined
);
}
}
export interface WikidataSearchoptions {
lang?: "en" | string,
maxCount?: 20 | number
}
/**
* Utility functions around wikidata
*/
export default class Wikidata {
private static readonly _identifierPrefixes = ["Q", "L"].map(str => str.toLowerCase())
private static readonly _prefixesToRemove = ["https://www.wikidata.org/wiki/Lexeme:", "https://www.wikidata.org/wiki/", "Lexeme:"].map(str => str.toLowerCase())
private static readonly _cache = new Map<string, UIEventSource<{ success: WikidataResponse } | { error: any }>>()
public static LoadWikidataEntry(value: string | number): UIEventSource<{ success: WikidataResponse } | { error: any }> {
const key = this.ExtractKey(value)
const cached = Wikidata._cache.get(key)
if(cached !== undefined){
if (cached !== undefined) {
return cached
}
const src = UIEventSource.FromPromiseWithErr(Wikidata.LoadWikidataEntryAsync(key))
@ -87,101 +157,120 @@ export default class Wikidata {
}
public static async search(
search: string,
options?:WikidataSearchoptions,
page = 1
): Promise<{
search: string,
options?: WikidataSearchoptions,
page = 1
): Promise<{
id: string,
label: string,
description: string
}[]> {
const maxCount = options?.maxCount ?? 20
let pageCount = Math.min(maxCount,50)
const start = page * pageCount - pageCount;
const lang = (options?.lang ?? "en")
const url =
"https://www.wikidata.org/w/api.php?action=wbsearchentities&search=" +
search +
"&language=" +
lang +
"&limit="+pageCount+"&continue=" +
start +
"&format=json&uselang=" +
lang +
"&type=item&origin=*"+
"&props=" ;// props= removes some unused values in the result
const response = await Utils.downloadJson(url)
const maxCount = options?.maxCount ?? 20
let pageCount = Math.min(maxCount, 50)
const start = page * pageCount - pageCount;
const lang = (options?.lang ?? "en")
const url =
"https://www.wikidata.org/w/api.php?action=wbsearchentities&search=" +
search +
"&language=" +
lang +
"&limit=" + pageCount + "&continue=" +
start +
"&format=json&uselang=" +
lang +
"&type=item&origin=*" +
"&props=";// props= removes some unused values in the result
const response = await Utils.downloadJson(url)
const result : any[] = response.search
if(result.length < pageCount){
// No next page
return result;
}
if(result.length < maxCount){
const newOptions = {...options}
newOptions.maxCount = maxCount - result.length
result.push(...await Wikidata.search(search,
newOptions,
page + 1
))
}
const result: any[] = response.search
if (result.length < pageCount) {
// No next page
return result;
}
if (result.length < maxCount) {
const newOptions = {...options}
newOptions.maxCount = maxCount - result.length
result.push(...await Wikidata.search(search,
newOptions,
page + 1
))
}
return result;
}
public static async searchAndFetch(
search: string,
options?:WikidataSearchoptions
) : Promise<WikidataResponse[]>
{
search: string,
options?: WikidataSearchoptions
): Promise<WikidataResponse[]> {
const maxCount = options.maxCount
// We provide some padding to filter away invalid values
options.maxCount = Math.ceil((options.maxCount ?? 20) * 1.5)
const searchResults = await Wikidata.search(search, options)
const maybeResponses = await Promise.all(searchResults.map(async r => {
try{
return await Wikidata.LoadWikidataEntry(r.id).AsPromise()
}catch(e){
console.error(e)
return undefined;
}
const maybeResponses = await Promise.all(searchResults.map(async r => {
try {
return await Wikidata.LoadWikidataEntry(r.id).AsPromise()
} catch (e) {
console.error(e)
return undefined;
}
}))
const responses = maybeResponses
.map(r => <WikidataResponse> r["success"])
.map(r => <WikidataResponse>r["success"])
.filter(wd => {
if(wd === undefined){
return false;
}
if(wd.claims.get("P31" /*Instance of*/)?.has("Q4167410"/* Wikimedia Disambiguation page*/)){
return false;
}
return true;
})
if (wd === undefined) {
return false;
}
if (wd.claims.get("P31" /*Instance of*/)?.has("Q4167410"/* Wikimedia Disambiguation page*/)) {
return false;
}
return true;
})
responses.splice(maxCount, responses.length - maxCount)
return responses
}
private static ExtractKey(value: string | number) : number{
public static ExtractKey(value: string | number): string {
if (typeof value === "number") {
return value
return "Q" + value
}
const wikidataUrl = "https://www.wikidata.org/wiki/"
if (value.startsWith(wikidataUrl)) {
value = value.substring(wikidataUrl.length)
if (value === undefined) {
console.error("ExtractKey: value is undefined")
return undefined;
}
if (value.startsWith("http")) {
value = value.trim().toLowerCase()
for (const prefix of Wikidata._prefixesToRemove) {
if (value.startsWith(prefix)) {
value = value.substring(prefix.length)
}
}
if (value.startsWith("http") && value === "") {
// Probably some random link in the image field - we skip it
return undefined
}
if (value.startsWith("Q")) {
value = value.substring(1)
for (const identifierPrefix of Wikidata._identifierPrefixes) {
if (value.startsWith(identifierPrefix)) {
const trimmed = value.substring(identifierPrefix.length);
if(trimmed === ""){
return undefined
}
const n = Number(trimmed)
if (isNaN(n)) {
return undefined
}
return value.toUpperCase();
}
}
const n = Number(value)
if(isNaN(n)){
return undefined
if (value !== "" && !isNaN(Number(value))) {
return "Q" + value
}
return n;
return undefined;
}
@ -191,14 +280,20 @@ export default class Wikidata {
*/
public static async LoadWikidataEntryAsync(value: string | number): Promise<WikidataResponse> {
const id = Wikidata.ExtractKey(value)
if(id === undefined){
if (id === undefined) {
console.warn("Could not extract a wikidata entry from", value)
return undefined;
throw "Could not extract a wikidata entry from " + value
}
const url = "https://www.wikidata.org/wiki/Special:EntityData/Q" + id + ".json";
const response = await Utils.downloadJson(url)
return Wikidata.ParseResponse(response.entities["Q" + id])
const url = "https://www.wikidata.org/wiki/Special:EntityData/" + id + ".json";
const response = (await Utils.downloadJson(url)).entities[id]
if (id.startsWith("L")) {
// This is a lexeme:
return new WikidataLexeme(response).asWikidataResponse()
}
return WikidataResponse.fromJson(response)
}
}

View file

@ -17,6 +17,7 @@ import {GeoOperations} from "../../Logic/GeoOperations";
import {Unit} from "../../Models/Unit";
import {FixedInputElement} from "./FixedInputElement";
import WikidataSearchBox from "../Wikipedia/WikidataSearchBox";
import Wikidata from "../../Logic/Web/Wikidata";
interface TextFieldDef {
name: string,
@ -153,20 +154,23 @@ export default class ValidatedTextField {
if (str === undefined) {
return false;
}
return (str.length > 1 && (str.startsWith("q") || str.startsWith("Q")) || str.startsWith("https://www.wikidata.org/wiki/Q"))
if(str.length <= 2){
return false;
}
return !str.split(";").some(str => Wikidata.ExtractKey(str) === undefined)
},
(str) => {
if (str === undefined) {
return undefined;
}
const wd = "https://www.wikidata.org/wiki/";
if (str.startsWith(wd)) {
str = str.substr(wd.length)
let out = str.split(";").map(str => Wikidata.ExtractKey(str)).join("; ")
if(str.endsWith(";")){
out = out + ";"
}
return str.toUpperCase();
return out;
},
(currentValue, inputHelperOptions) => {
const args = inputHelperOptions.args
const args = inputHelperOptions.args ?? []
const searchKey = args[0] ?? "name"
let searchFor = <string>inputHelperOptions.feature?.properties[searchKey]?.toLowerCase()
@ -175,7 +179,6 @@ export default class ValidatedTextField {
if (searchFor !== undefined && options !== undefined) {
const prefixes = <string[]>options["removePrefixes"]
const postfixes = <string[]>options["removePostfixes"]
for (const postfix of postfixes ?? []) {
if (searchFor.endsWith(postfix)) {
searchFor = searchFor.substring(0, searchFor.length - postfix.length)

View file

@ -136,7 +136,7 @@ export default class TagRenderingQuestion extends Combine {
options.cancelButton,
saveButton,
bottomTags])
this.SetClass("question")
this.SetClass("question disable-links")
}

View file

@ -51,8 +51,9 @@ export default class WikidataPreviewBox extends VariableUiElement {
wikidata.id,
Svg.wikidata_ui().SetStyle("width: 2.5rem").SetClass("block")
]).SetClass("flex"),
"https://wikidata.org/wiki/"+wikidata.id ,true)
"https://wikidata.org/wiki/"+wikidata.id ,true).SetClass("must-link")
console.log(wikidata)
let info = new Combine( [
new Combine([Translation.fromMap(wikidata.labels).SetClass("font-bold"),
link]).SetClass("flex justify-between"),

View file

@ -6,12 +6,10 @@ import {UIEventSource} from "../../Logic/UIEventSource";
import Wikidata, {WikidataResponse} from "../../Logic/Web/Wikidata";
import Locale from "../i18n/Locale";
import {VariableUiElement} from "../Base/VariableUIElement";
import {FixedUiElement} from "../Base/FixedUiElement";
import WikidataPreviewBox from "./WikidataPreviewBox";
import Title from "../Base/Title";
import WikipediaBox from "./WikipediaBox";
import Svg from "../../Svg";
import Link from "../Base/Link";
export default class WikidataSearchBox extends InputElement<string> {
@ -104,7 +102,7 @@ export default class WikidataSearchBox extends InputElement<string> {
if (wid === undefined) {
return undefined
}
return new WikipediaBox([wid]);
return new WikipediaBox(wid.split(";"));
})).SetStyle("max-height:12.5rem"),
full
]).ConstructElement();

View file

@ -22,7 +22,7 @@ export default class WikipediaBox extends Combine {
const mainContents = []
const pages = wikidataIds.map(wdId => WikipediaBox.createLinkedContent(wdId))
const pages = wikidataIds.map(wdId => WikipediaBox.createLinkedContent(wdId.trim()))
if (wikidataIds.length == 1) {
const page = pages[0]
mainContents.push(
@ -88,6 +88,9 @@ export default class WikipediaBox extends Combine {
}
const wikidata = <WikidataResponse>maybewikidata["success"]
if(wikidata === undefined){
return "failed"
}
if (wikidata.wikisites.size === 0) {
return ["no page", wikidata]
}
@ -157,7 +160,7 @@ export default class WikipediaBox extends Combine {
}
return undefined
}))
.SetClass("flex items-center")
.SetClass("flex items-center enable-links")
return {
contents: contents,

View file

@ -0,0 +1,138 @@
{
"id": "etymology",
"#": "A layer showing all objects having etymology info (either via `name:etymology:wikidata` or `name:etymology`. The intention is that this layer is reused for a certain category to also _ask_ for information",
"name": {
"en": "Has etymolgy",
"nl": "Heeft etymology info"
},
"minzoom": 12,
"source": {
"osmTags": {
"or": [
"name:etymology:wikidata~*",
"name:etymology~*"
]
}
},
"title": {
"render": {
"*": "{name}"
}
},
"description": {
"en": "All objects which have an etymology known",
"nl": "Alle lagen met een gelinkt etymology"
},
"tagRenderings": [
{
"id": "wikipedia-etymology",
"question": {
"en": "What is the Wikidata-item that this object is named after?",
"nl": "Wat is het Wikidata-item van hetgeen dit object is naar vernoemd?"
},
"freeform": {
"key": "name:etymology:wikidata",
"type": "wikidata",
"helperArgs": [
"name",
{
"removePostfixes": [
"steenweg",
"heirbaan",
"baan",
"straat",
"street",
"weg",
"dreef",
"laan",
"boulevard",
"pad",
"path",
"plein",
"square",
"plaza",
"wegel",
"kerk",
"church",
"kaai"
]
}
]
},
"render": {
"en": "<h3>Wikipedia article of the name giver</h3>{wikipedia(name:etymology:wikidata):max-height:20rem}",
"nl": "<h3>Wikipedia artikel van de naamgever</h3>{wikipedia(name:etymology:wikidata):max-height:20rem}"
}
},
{
"id": "zoeken op inventaris onroerend erfgoed",
"render": {
"nl": "<a href='https://inventaris.onroerenderfgoed.be/erfgoedobjecten?tekst={name}' target='_blank'>Zoeken op inventaris onroerend erfgoed</a>",
"en": "<a href='https://inventaris.onroerenderfgoed.be/erfgoedobjecten?tekst={name}' target='_blank'>Search on inventaris onroerend erfgoed</a>"
},
"conditions": "_country=be"
},
{
"id": "simple etymology",
"question": {
"en": "What is this object named after?<br/><span class='subtle'>This might be written on the street name sign</span>",
"nl": "Naar wat is dit object vernoemd?<br/><span class='subtle'>Dit staat mogelijks vermeld op het straatnaambordje</subtle>"
},
"render": {
"en": "Named after {name:etymology}",
"nl": "Vernoemd naar {name:etymology}"
},
"freeform": {
"key": "name:etymology"
},
"condition": {
"or": [
"name:etymology~*",
"name:etymology:wikidata="
]
}
},
{
"id": "street-name-sign-image",
"render": {
"en": "{image_carousel(image:streetsign)}<br/>{image_upload(image:streetsign, Add image of a street name sign)}",
"nl": "{image_carousel(image:streetsign)}<br/>{image_upload(image:streetsign, Voeg afbeelding van straatnaambordje toe)}"
}
},
"wikipedia"
],
"icon": {
"render": "pin:#05d7fcaa;./assets/layers/etymology/logo.svg",
"mappings": [
{
"if": {
"and": [
"name:etymology=",
"name:etymology:wikidata="
]
},
"then": "pin:#fcca05aa;./assets/layers/etymology/logo.svg"
}
]
},
"width": {
"render": "8"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#05d7fcaa",
"mappings": [
{
"if": {
"and": [
"name:etymology=",
"name:etymology:wikidata="
]
},
"then": "#fcca05aa"
}
]
}
}

View file

@ -0,0 +1,10 @@
[
{
"path": "logo.svg",
"license": "CC0",
"authors": [
"Pieter Vander Vennet"
],
"sources": []
}
]

View file

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="31.41128mm"
height="21.6535mm"
viewBox="0 0 31.41128 21.6535"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="logo.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="100.68267"
inkscape:cy="-27.941339"
inkscape:document-units="mm"
inkscape:current-layer="flowRoot10"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1003"
inkscape:window-x="862"
inkscape:window-y="1080"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-18.484101,-182.07744)">
<g
aria-label="ετυμο
λογία "
transform="matrix(0.21233122,0,0,0.21233122,6.7520733,38.096318)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
id="flowRoot10">
<path
d="m 86.101172,696.96673 v 4.12 h -3.28 q -3.08,0 -4.4,0.68 -1.32,0.68 -1.32,2 0,1.08 1.2,1.76 1.2,0.68 4.04,0.68 2.44,0 4.56,-0.52 2.12,-0.52 3.48,-1.16 v 4.76 q -1.48,0.68 -3.64,1.12 -2.16,0.4 -4.84,0.4 -5.64,0 -8.16,-1.76 -2.52,-1.76 -2.52,-4.68 0,-2.4 1.44,-3.6 1.48,-1.2 3.88,-1.64 v -0.2 q -2.08,-0.48 -3.12,-1.76 -1.04,-1.32 -1.04,-3.28 0,-2.08 1.28,-3.32 1.28,-1.28 3.44,-1.84 2.16,-0.56 4.8,-0.56 2.28,0 4.56,0.44 2.28,0.44 3.96,1.2 l -1.84,4.32 q -1.44,-0.6 -3,-1.08 -1.52,-0.48 -3.52,-0.48 -4.36,0 -4.36,2.04 0,1.28 1.28,1.84 1.32,0.52 4.12,0.52 z"
style="font-weight:bold"
id="path28" />
<path
d="m 111.90111,688.56673 v 4.48 h -7.76 v 10.52 q 0,1.24 0.72,1.88 0.72,0.6 1.88,0.6 1,0 1.92,-0.2 0.92,-0.2 1.84,-0.48 v 4.44 q -0.88,0.4 -2.24,0.68 -1.32,0.32 -2.88,0.32 -2.04,0 -3.68,-0.64 -1.6,-0.64 -2.560002,-2.2 -0.96,-1.6 -0.96,-4.4 v -10.52 h -5.48 v -2.48 l 3.44,-2 z"
style="font-weight:bold"
id="path30" />
<path
d="m 126.26104,710.76673 q -3.92,0 -6.12,-1.36 -2.16,-1.4 -3.04,-3.72 -0.88,-2.36 -0.88,-5.24 v -11.88 h 5.96 v 12.08 q 0,2.84 1.04,4.12 1.04,1.24 3.24,1.24 2.36,0 3.52,-1.72 1.16,-1.72 1.16,-5.88 0,-2.6 -0.4,-4.88 -0.36,-2.32 -1,-4.96 h 6 q 0.68,2.6 1,4.92 0.36,2.28 0.36,5.08 0,6.28 -2.76,9.24 -2.72,2.96 -8.08,2.96 z"
style="font-weight:bold"
id="path32" />
<path
d="m 162.50098,688.56673 v 21.84 h -4.52 l -0.84,-2.92 h -0.28 q -0.8,1.64 -2,2.48 -1.16,0.84 -2.88,0.84 -2.44,0 -3.76,-1.76 h -0.12 q 0.08,0.4 0.12,1.28 0.04,0.84 0.04,1.76 0.04,0.96 0.04,1.68 v 6.24 h -5.96 v -31.44 h 5.96 v 12.76 q 0,4.72 3.56,4.72 2.68,0 3.68,-1.84 1,-1.88 1,-5.36 v -10.28 z"
style="font-weight:bold"
id="path34" />
<path
d="m 188.58097,699.44673 q 0,5.44 -2.88,8.4 -2.84,2.96 -7.76,2.96 -3.04,0 -5.44,-1.32 -2.36,-1.32 -3.72,-3.84 -1.36,-2.56 -1.36,-6.2 0,-5.44 2.84,-8.36 2.84,-2.92 7.8,-2.92 3.08,0 5.44,1.32 2.36,1.32 3.72,3.84 1.36,2.48 1.36,6.12 z m -15.08,0 q 0,3.24 1.04,4.92 1.08,1.64 3.48,1.64 2.36,0 3.4,-1.64 1.08,-1.68 1.08,-4.92 0,-3.24 -1.08,-4.84 -1.04,-1.64 -3.44,-1.64 -2.36,0 -3.44,1.64 -1.04,1.6 -1.04,4.84 z"
style="font-weight:bold"
id="path36" />
<path
d="m 69.861172,760.40673 9.24,-20.64 -0.68,-1.8 q -0.84,-2.08 -1.8,-2.64 -0.96,-0.56 -2.56,-0.56 -0.52,0 -1.08,0.08 -0.52,0.08 -0.92,0.16 v -4.92 q 0.56,-0.12 1.52,-0.2 1,-0.12 1.72,-0.12 2.56,0 4.16,0.84 1.64,0.8 2.68,2.36 1.04,1.56 1.84,3.8 l 5.48,15.08 q 0.92,2.48 1.68,3.24 0.76,0.72 1.6,0.72 0.56,0 1.36,-0.2 v 4.6 q -0.48,0.24 -1.6,0.4 -1.08,0.2 -1.84,0.2 -2.44,0 -3.72,-1.2 -1.24,-1.24 -1.96,-3.24 l -1.88,-5.32 q -0.44,-1.28 -0.84,-2.48 -0.4,-1.24 -0.6,-2.12 h -0.12 q -0.28,1.04 -0.68,2.28 -0.4,1.24 -0.8,2.2 l -4.04,9.48 z"
style="font-weight:bold"
id="path38" />
<path
d="m 116.86115,749.44673 q 0,5.44 -2.88,8.4 -2.84,2.96 -7.76,2.96 -3.04,0 -5.44,-1.32 -2.359996,-1.32 -3.719996,-3.84 -1.36,-2.56 -1.36,-6.2 0,-5.44 2.84,-8.36 2.839996,-2.92 7.799996,-2.92 3.08,0 5.44,1.32 2.36,1.32 3.72,3.84 1.36,2.48 1.36,6.12 z m -15.08,0 q 0,3.24 1.04,4.92 1.08,1.64 3.48,1.64 2.36,0 3.4,-1.64 1.08,-1.68 1.08,-4.92 0,-3.24 -1.08,-4.84 -1.04,-1.64 -3.44,-1.64 -2.36,0 -3.44,1.64 -1.04,1.6 -1.04,4.84 z"
style="font-weight:bold"
id="path40" />
<path
d="m 140.58111,738.56673 -8.08,21.48 q -0.6,1.6 -1.04,3.4 -0.44,1.8 -0.68,3.48 -0.2,1.72 -0.2,3.08 h -6.32 q 0,-1.12 0.24,-2.8 0.28,-1.68 0.72,-3.56 0.44,-1.84 1,-3.48 l -8.32,-21.6 h 6.2 l 3.2,9.64 q 0.36,1.04 0.76,2.52 0.44,1.44 0.76,2.8 0.32,1.32 0.44,2.04 h 0.12 q 0.08,-0.6 0.32,-1.76 0.28,-1.2 0.64,-2.6 0.4,-1.44 0.84,-2.72 l 3.2,-9.92 z"
style="font-weight:bold"
id="path42" />
<path
d="m 149.66107,738.56673 v 15 q 0,1.24 0.72,1.88 0.72,0.6 1.88,0.6 1,0 1.92,-0.2 0.92,-0.2 1.84,-0.48 v 4.44 q -0.88,0.4 -2.24,0.68 -1.32,0.32 -2.88,0.32 -2.04,0 -3.68,-0.64 -1.6,-0.64 -2.56,-2.2 -0.96,-1.6 -0.96,-4.4 v -15 z m -4.84,-2.4 v -0.6 q 0.32,-0.96 0.6,-2.2 0.32,-1.24 0.6,-2.52 0.28,-1.28 0.4,-2.28 h 5.52 v 0.48 q -0.64,1.56 -1.56,3.4 -0.92,1.84 -2.08,3.72 z"
style="font-weight:bold"
id="path44" />
<path
d="m 167.22105,760.80673 q -3.84,0 -6.2,-2.84 -2.36,-2.88 -2.36,-8.4 0,-5.6 2.44,-8.48 2.44,-2.88 6.56,-2.88 2.32,0 3.8,0.84 1.48,0.8 2.48,2.44 h 0.28 q 0.2,-0.68 0.52,-1.48 0.32,-0.84 0.8,-1.44 h 4.92 q -0.44,1.28 -0.92,3.72 -0.48,2.44 -0.48,5.12 v 6.08 q 0,1.36 0.48,1.84 0.52,0.48 1.16,0.48 0.28,0 0.64,-0.08 0.36,-0.08 0.52,-0.12 v 4.68 q -0.28,0.16 -1.16,0.32 -0.84,0.2 -1.52,0.2 -2,0 -3.24,-0.72 -1.24,-0.72 -1.92,-2.56 h -0.4 q -0.88,1.36 -2.4,2.32 -1.52,0.96 -4,0.96 z m 1.8,-4.76 q 2.48,0 3.44,-1.48 1,-1.52 1.04,-4.8 v -0.24 q 0,-3.2 -1,-4.88 -0.96,-1.68 -3.56,-1.68 -2.12,0 -3.16,1.72 -1.04,1.68 -1.04,4.92 0,6.44 4.28,6.44 z"
style="font-weight:bold"
id="path46" />
</g>
<g
style="font-style:normal;font-weight:normal;font-size:8.49324894px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.21233122"
id="text20" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View file

@ -45,7 +45,23 @@
},
"wikipedialink": {
"render": "<a href='https://wikipedia.org/wiki/{wikipedia}' target='_blank'><img src='./assets/wikipedia.svg' alt='WP'/></a>",
"condition": "wikipedia~*"
"freeform": {
"key": "wikidata",
"type": "wikidata"
},
"question": {
"en": "What is the corresponding item on Wikipedia?",
"nl": "Welk Wikipedia-artikel beschrijft dit object?"
},
"mappings": [
{
"if": "wikidata=",
"then": {
"en": "Not linked with Wikipedia",
"nl": "Nog geen Wikipedia-artikel bekend"
}
}
]
},
"email": {
"render": "<a href='mailto:{email}' target='_blank'>{email}</a>",

View file

@ -17,7 +17,7 @@
"nl"
],
"maintainer": "",
"icon": "./assets/svg/bug.svg",
"icon": "./assets/layers/etymology/logo.svg",
"version": "0",
"startLat": 0,
"startLon": 0,
@ -25,138 +25,26 @@
"widenFactor": 2,
"socialImage": "",
"layers": [
"etymology",
{
"id": "has_etymology",
"name": {
"en": "Has etymolgy",
"nl": "Heeft etymology info"
},
"minzoom": 12,
"source": {
"osmTags": {
"or": [
"name:etymology:wikidata~*",
"name:etymology~*"
]
}
},
"title": {
"render": {
"*": "{name}"
}
},
"description": {
"en": "All objects which have an etymology known",
"nl": "Alle lagen met een gelinkt etymology"
},
"tagRenderings": [
{
"id": "etymology_wikidata_image",
"render": {
"*": "{image_carousel(name:etymology:wikidata)}"
}
"builtin": "etymology",
"override": {
"id": "streets_without_etymology",
"name": {
"en": "Streets without etymology information",
"nl": "Straten zonder etymologische informatie"
},
{
"id": "simple etymology",
"render": {
"en": "Named after {name:etymology}",
"nl": "Vernoemd naar {name:etymology}"
},
"freeform": {
"key": "name:etymology"
}
},
{
"id": "wikipedia-etymology",
"render": {
"*": "{wikipedia(name:etymology:wikidata):max-height:30rem}"
}
},
{
"id": "wikidata-embed",
"render": {
"*": "<iframe src='https://m.wikidata.org/wiki/{name:etymology:wikidata}' style='width: 100%; height: 25rem'></iframe>"
},
"condition": "name:etymology:wikidata~*"
},
"wikipedia",
{
"id": "street-name-sign-image",
"render": {
"en": "{image_carousel(image:streetsign)}<br/>{image_upload(image:streetsign, Add image of a street name sign)}",
"nl": "{image_carousel(image:streetsign)}<br/>{image_upload(image:streetsign, Voeg afbeelding van straatnaambordje toe)}"
"minzoom": 18,
"source": {
"osmTags": {
"and": [
"name~*",
"highway~*",
"highway!=bus_stop"
]
}
}
],
"icon": {
"render": "./assets/svg/bug.svg"
},
"width": {
"render": "8"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#00f"
},
"presets": []
},
{
"id": "has_a_name",
"name": {
"en": "Has etymolgy",
"nl": "Heeft etymology info"
},
"minzoom": 12,
"source": {
"osmTags": {
"or": [
"name:etymology:wikidata~*",
"name:etymology~*"
]
}
},
"title": {
"render": {
"*": "{name}"
}
},
"description": {
"en": "All objects which have an etymology known",
"nl": "Alle lagen met een gelinkt etymology"
},
"tagRenderings": [
{
"id": "simple etymology",
"render": {
"en": "Named after {name:etymology}",
"nl": "Vernoemd naar {name:etymology}"
},
"freeform": {
"key": "name:etymology"
}
},
{
"id": "wikipedia-etymology",
"render": {
"*": "{wikipedia(name:etymology:wikidata):max-height:20rem}"
}
}
],
"icon": {
"render": "./assets/svg/bug.svg"
},
"width": {
"render": "8"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#00f"
},
"presets": []
}
}
],
"hideFromOverview": true

View file

@ -1958,6 +1958,27 @@ li::marker {
max-width: 2em !important;
}
.block-ruby {
display: block ruby;
}
.disable-links a {
pointer-events: none;
text-decoration: none !important;
color: var(--subtle-detail-color-contrast) !important;
}
.enable-links a {
pointer-events: unset;
text-decoration: underline !important;
color: unset !important;
}
.disable-links a.must-link, .disable-links .must-link a {
/* Hide links if they are disabled */
display: none;
}
/**************** GENERIC ****************/
.alert {
@ -2237,10 +2258,6 @@ li::marker {
}
@media (min-width: 640px) {
.sm\:m-1 {
margin: 0.25rem;
}
.sm\:mx-auto {
margin-left: auto;
margin-right: auto;

View file

@ -20,12 +20,6 @@
height: 100%;
}
.question a {
pointer-events: none;
text-decoration: none;
color: var(--subtle-detail-color-contrast)
}
.question-text {
font-size: larger;
font-weight: bold;

View file

@ -33,6 +33,12 @@
text-decoration: none;
}
.disable-links .wikipedia-article a {
color: black !important;
background: none !important;
text-decoration: none;
}
.wikipedia-article p {
margin-bottom: 0.5rem;

View file

@ -243,6 +243,27 @@ li::marker {
}
.block-ruby {
display: block ruby;
}
.disable-links a {
pointer-events: none;
text-decoration: none !important;
color: var(--subtle-detail-color-contrast) !important;
}
.enable-links a {
pointer-events: unset;
text-decoration: underline !important;
color: unset !important;
}
.disable-links a.must-link, .disable-links .must-link a {
/* Hide links if they are disabled */
display: none;
}
/**************** GENERIC ****************/

View file

@ -1,6 +1,3 @@
import WikidataPreviewBox from "./UI/Wikipedia/WikidataPreviewBox";
import {UIEventSource} from "./Logic/UIEventSource";
import Wikidata from "./Logic/Web/Wikidata";
import WikidataSearchBox from "./UI/Wikipedia/WikidataSearchBox";
import WikipediaBox from "./UI/Wikipedia/WikipediaBox";
new WikidataSearchBox({searchText: new UIEventSource("Brugge")}).AttachTo("maindiv")
new WikipediaBox(["L614072"]).AttachTo("maindiv")

View file

@ -1881,6 +1881,52 @@ export default class WikidataSpecTest extends T {
)
const wikidata = await Wikidata.LoadWikidataEntryAsync("2747456")
}],
["Extract key from a lexeme", () => {
Utils.injectJsonDownloadForTests(
"https://www.wikidata.org/wiki/Special:EntityData/L614072.json" ,
{
"entities": {
"L614072": {
"pageid": 104085278,
"ns": 146,
"title": "Lexeme:L614072",
"lastrevid": 1509989280,
"modified": "2021-10-09T18:43:52Z",
"type": "lexeme",
"id": "L614072",
"lemmas": {"nl": {"language": "nl", "value": "Groen"}},
"lexicalCategory": "Q34698",
"language": "Q7411",
"claims": {},
"forms": [],
"senses": [{
"id": "L614072-S1",
"glosses": {"nl": {"language": "nl", "value": "Nieuw"}},
"claims": {}
}, {
"id": "L614072-S2",
"glosses": {"nl": {"language": "nl", "value": "Jong"}},
"claims": {}
}, {
"id": "L614072-S3",
"glosses": {"nl": {"language": "nl", "value": "Pril"}},
"claims": {}
}]
}
}
}
)
const key = Wikidata.ExtractKey("https://www.wikidata.org/wiki/Lexeme:L614072")
T.equals("L614072", key)
}],
["Download a lexeme", async () => {
const response = await Wikidata.LoadWikidataEntryAsync("https://www.wikidata.org/wiki/Lexeme:L614072")
T.isTrue(response !== undefined, "Response is undefined")
}]
]);