2020-10-09 20:10:21 +02:00
import { UIEventSource } from "../Logic/UIEventSource" ;
2020-10-12 01:25:27 +02:00
import { VariableUiElement } from "./Base/VariableUIElement" ;
import LiveQueryHandler from "../Logic/Web/LiveQueryHandler" ;
2020-10-14 12:15:09 +02:00
import { ImageCarousel } from "./Image/ImageCarousel" ;
import Combine from "./Base/Combine" ;
import { FixedUiElement } from "./Base/FixedUiElement" ;
import { ImageUploadFlow } from "./Image/ImageUploadFlow" ;
2021-01-03 13:50:18 +01:00
2021-01-04 04:06:21 +01:00
import ShareButton from "./BigComponents/ShareButton" ;
2020-11-22 03:50:09 +01:00
import Svg from "../Svg" ;
2020-12-08 23:44:34 +01:00
import ReviewElement from "./Reviews/ReviewElement" ;
import MangroveReviews from "../Logic/Web/MangroveReviews" ;
import Translations from "./i18n/Translations" ;
import ReviewForm from "./Reviews/ReviewForm" ;
2021-01-02 16:04:16 +01:00
import OpeningHoursVisualization from "./OpeningHours/OhVisualization" ;
2020-10-14 12:15:09 +02:00
2021-01-03 13:50:18 +01:00
import State from "../State" ;
2021-01-29 03:23:53 +01:00
import { ImageSearcher } from "../Logic/Actors/ImageSearcher" ;
2021-06-11 22:51:45 +02:00
import BaseUIElement from "./BaseUIElement" ;
2021-06-15 01:24:04 +02:00
import LayerConfig from "../Customizations/JSON/LayerConfig" ;
2021-01-03 13:50:18 +01:00
2020-10-09 20:10:21 +02:00
export default class SpecialVisualizations {
2021-06-15 01:24:04 +02:00
2020-10-09 20:10:21 +02:00
2020-10-11 22:37:55 +02:00
public static specialVisualizations : {
funcName : string ,
2021-06-11 22:51:45 +02:00
constr : ( ( state : State , tagSource : UIEventSource < any > , argument : string [ ] ) = > BaseUIElement ) ,
2020-10-11 22:37:55 +02:00
docs : string ,
2020-10-17 02:37:53 +02:00
example? : string ,
2020-10-12 01:25:27 +02:00
args : { name : string , defaultValue? : string , doc : string } [ ]
2020-10-11 22:37:55 +02:00
} [ ] =
2020-10-09 20:10:21 +02:00
2020-11-17 16:29:51 +01:00
[ {
funcName : "all_tags" ,
docs : "Prints all key-value pairs of the object - used for debugging" ,
args : [ ] ,
2021-03-13 19:07:38 +01:00
constr : ( ( state : State , tags : UIEventSource < any > ) = > {
2020-11-17 16:29:51 +01:00
return new VariableUiElement ( tags . map ( tags = > {
const parts = [ ] ;
for ( const key in tags ) {
2021-06-15 01:24:04 +02:00
if ( ! tags . hasOwnProperty ( key ) ) {
2021-06-11 22:51:45 +02:00
continue ;
}
2020-11-17 16:29:51 +01:00
parts . push ( key + "=" + tags [ key ] ) ;
}
return parts . join ( "<br/>" )
} ) ) . SetStyle ( "border: 1px solid black; border-radius: 1em;padding:1em;display:block;" )
} )
} ,
2020-12-08 23:44:34 +01:00
2020-10-14 12:15:09 +02:00
{
funcName : "image_carousel" ,
docs : "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)" ,
args : [ {
2020-10-17 02:37:53 +02:00
name : "image key/prefix" ,
defaultValue : "image" ,
doc : "The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc... "
} ,
{
name : "smart search" ,
defaultValue : "true" ,
doc : "Also include images given via 'Wikidata', 'wikimedia_commons' and 'mapillary"
} ] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tags , args ) = > {
2021-01-29 03:23:53 +01:00
const imagePrefix = args [ 0 ] ;
const loadSpecial = args [ 1 ] . toLowerCase ( ) === "true" ;
2021-03-26 03:24:58 +01:00
const searcher : UIEventSource < { key : string , url : string } [ ] > = ImageSearcher . construct ( tags , imagePrefix , loadSpecial ) ;
2021-01-29 03:23:53 +01:00
return new ImageCarousel ( searcher , tags ) ;
2020-10-11 22:37:55 +02:00
}
2020-10-14 12:15:09 +02:00
} ,
{
funcName : "image_upload" ,
docs : "Creates a button where a user can upload an image to IMGUR" ,
args : [ {
2020-10-17 02:37:53 +02:00
name : "image-key" ,
2020-10-14 12:15:09 +02:00
doc : "Image tag to add the URL to (or image-tag:0, image-tag:1 when multiple images are added)" ,
2020-10-17 02:37:53 +02:00
defaultValue : "image"
2020-10-14 12:15:09 +02:00
} ] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tags , args ) = > {
2020-10-17 02:37:53 +02:00
return new ImageUploadFlow ( tags , args [ 0 ] )
2020-10-14 12:15:09 +02:00
}
} ,
2020-12-08 23:44:34 +01:00
{
funcName : "reviews" ,
2021-03-13 19:07:38 +01:00
docs : "Adds an overview of the mangrove-reviews of this object. Mangrove.Reviews needs - in order to identify the reviewed object - a coordinate and a name. By default, the name of the object is given, but this can be overwritten" ,
example : "<b>{reviews()}<b> for a vanilla review, <b>{reviews(name, play_forest)}</b> to review a play forest. If a name is known, the name will be used as identifier, otherwise 'play_forest' is used" ,
2020-12-31 22:41:52 +01:00
args : [ {
2021-03-13 19:07:38 +01:00
name : "subjectKey" ,
defaultValue : "name" ,
doc : "The key to use to determine the subject. If specified, the subject will be <b>tags[subjectKey]</b>"
} , {
name : "fallback" ,
doc : "The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value"
2020-12-31 22:41:52 +01:00
} ] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tags , args ) = > {
2020-12-08 23:44:34 +01:00
const tgs = tags . data ;
2021-03-13 19:07:38 +01:00
const key = args [ 0 ] ? ? "name"
let subject = tgs [ key ] ? ? args [ 1 ] ;
if ( subject === undefined || subject === "" ) {
2020-12-08 23:44:34 +01:00
return Translations . t . reviews . name_required ;
}
2020-12-31 21:13:16 +01:00
const mangrove = MangroveReviews . Get ( Number ( tgs . _lon ) , Number ( tgs . _lat ) ,
encodeURIComponent ( subject ) ,
2021-01-03 13:50:18 +01:00
state . mangroveIdentity ,
state . osmConnection . _dryRun
2020-12-08 23:44:34 +01:00
) ;
2021-06-14 19:21:33 +02:00
const form = new ReviewForm ( ( r , whenDone ) = > mangrove . AddReview ( r , whenDone ) , state . osmConnection ) ;
2020-12-08 23:44:34 +01:00
return new ReviewElement ( mangrove . GetSubjectUri ( ) , mangrove . GetReviews ( ) , form ) ;
}
} ,
2020-10-14 12:15:09 +02:00
{
funcName : "opening_hours_table" ,
docs : "Creates an opening-hours table. Usage: {opening_hours_table(opening_hours)} to create a table of the tag 'opening_hours'." ,
args : [ {
name : "key" ,
defaultValue : "opening_hours" ,
2020-10-17 02:37:53 +02:00
doc : "The tagkey from which the table is constructed."
2020-10-14 12:15:09 +02:00
} ] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tagSource : UIEventSource < any > , args ) = > {
2020-10-14 12:15:09 +02:00
let keyname = args [ 0 ] ;
if ( keyname === undefined || keyname === "" ) {
keyname = keyname ? ? "opening_hours"
}
return new OpeningHoursVisualization ( tagSource , keyname )
}
} ,
2020-10-11 22:37:55 +02:00
2020-10-12 01:25:27 +02:00
{
funcName : "live" ,
docs : "Downloads a JSON from the given URL, e.g. '{live(example.org/data.json, shorthand:x.y.z, other:a.b.c, shorthand)}' will download the given file, will create an object {shorthand: json[x][y][z], other: json[a][b][c] out of it and will return 'other' or 'json[a][b][c]. This is made to use in combination with tags, e.g. {live({url}, {url:format}, needed_value)}" ,
2020-10-17 02:37:53 +02:00
example : "{live({url},{url:format},hour)} {live(https://data.mobility.brussels/bike/api/counts/?request=live&featureID=CB2105,hour:data.hour_cnt;day:data.day_cnt;year:data.year_cnt,hour)}" ,
2020-10-12 01:25:27 +02:00
args : [ {
name : "Url" , doc : "The URL to load"
} , {
name : "Shorthands" ,
doc : "A list of shorthands, of the format 'shorthandname:path.path.path'. Seperated by ;"
} , {
name : "path" , doc : "The path (or shorthand) that should be returned"
} ] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tagSource : UIEventSource < any > , args ) = > {
2020-10-12 01:25:27 +02:00
const url = args [ 0 ] ;
const shorthands = args [ 1 ] ;
const neededValue = args [ 2 ] ;
const source = LiveQueryHandler . FetchLiveData ( url , shorthands . split ( ";" ) ) ;
return new VariableUiElement ( source . map ( data = > data [ neededValue ] ? ? "Loading..." ) ) ;
}
2020-10-19 12:08:42 +02:00
} ,
2020-11-21 16:44:48 +01:00
{
funcName : "share_link" ,
docs : "Creates a link that (attempts to) open the native 'share'-screen" ,
example : "{share_link()} to share the current page, {share_link(<some_url>)} to share the given url" ,
args : [
{
name : "url" ,
2021-03-13 19:07:38 +01:00
doc : "The url to share (default: current URL)" ,
2020-11-21 16:44:48 +01:00
}
] ,
2021-03-13 19:07:38 +01:00
constr : ( state : State , tagSource : UIEventSource < any > , args ) = > {
2020-11-24 12:52:01 +01:00
if ( window . navigator . share ) {
2021-06-15 01:24:04 +02:00
const generateShareData = ( ) = > {
const title = state ? . layoutToUse ? . data ? . title ? . txt ? ? "MapComplete" ;
let matchingLayer : LayerConfig = undefined ;
for ( const layer of ( state ? . layoutToUse ? . data ? . layers ? ? [ ] ) ) {
if ( layer . source . osmTags . matchesProperties ( tagSource ? . data ) ) {
matchingLayer = layer
}
}
let name = matchingLayer ? . title ? . GetRenderValue ( tagSource . data ) ? . txt ? ? tagSource . data ? . name ? ? "POI" ;
if ( name ) {
name = ` ${ name } ( ${ title } ) `
} else {
name = title ;
}
let url = args [ 0 ] ? ? ""
if ( url === "" ) {
url = window . location . href
}
return {
title : name ,
url : url ,
text : state?.layoutToUse?.data?.shortDescription?.txt ? ? "MapComplete"
}
2020-11-23 12:54:10 +01:00
}
2021-06-15 01:24:04 +02:00
return new ShareButton ( Svg . share_ui ( ) , generateShareData )
2020-11-21 16:44:48 +01:00
} else {
2020-11-23 02:55:18 +01:00
return new FixedUiElement ( "" )
2020-11-21 16:44:48 +01:00
}
2020-11-17 16:29:51 +01:00
2020-11-21 16:44:48 +01:00
}
}
2020-10-12 01:25:27 +02:00
2020-10-11 22:37:55 +02:00
]
2021-06-11 22:51:45 +02:00
static HelpMessage : BaseUIElement = SpecialVisualizations . GenHelpMessage ( ) ;
2020-10-17 02:37:53 +02:00
private static GenHelpMessage() {
const helpTexts =
SpecialVisualizations . specialVisualizations . map ( viz = > new Combine (
[
` <h3> ${ viz . funcName } </h3> ` ,
viz . docs ,
"<ol>" ,
. . . viz . args . map ( arg = > new Combine ( [
"<li>" ,
"<b>" + arg . name + "</b>: " ,
arg . doc ,
arg . defaultValue === undefined ? "" : ( " Default: <span class='literal-code'>" + arg . defaultValue + "</span>" ) ,
"</li>"
] ) ) ,
"</ol>" ,
"<b>Example usage: </b>" ,
new FixedUiElement (
viz . example ? ? "{" + viz . funcName + "(" + viz . args . map ( arg = > arg . defaultValue ) . join ( "," ) + ")}"
) . SetClass ( "literal-code" ) ,
]
) ) ;
return new Combine ( [
2021-03-13 19:07:38 +01:00
"<h3>Special tag renderings</h3>" ,
2020-10-17 02:37:53 +02:00
"In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's." ,
2021-03-13 19:07:38 +01:00
"General usage is <b>{func_name()}</b> or <b>{func_name(arg, someotherarg)}</b>. Note that you <i>do not</i> need to use quotes around your arguments, the comma is enough to seperate them. This also implies you cannot use a comma in your args" ,
2020-10-17 02:37:53 +02:00
. . . helpTexts
]
) ;
}
2020-10-09 20:10:21 +02:00
}