2021-06-14 23:08:07 +01:00
|
|
|
<template>
|
|
|
|
<div>
|
2021-06-17 18:12:07 +01:00
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
<div class="modal fade" ref="error_modal" tabindex="-1">
|
|
|
|
<div class="modal-dialog modal-dialog-scrollable modal-xl">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header bg-danger text-white">
|
|
|
|
<h5 class="modal-title">
|
|
|
|
<span v-if="api_call_error_message">{{ api_call_error_message }}</span>
|
|
|
|
<span v-else>Error from server</span>
|
|
|
|
</h5>
|
|
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
|
|
<div v-if="api_call_error_traceback">
|
|
|
|
<div>error message: {{ api_call_error_message }}</div>
|
|
|
|
<div class="mt-2"><pre>{{ api_call_error_traceback }}</pre></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer bg-danger">
|
|
|
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Close</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<div id="map">
|
|
|
|
</div>
|
2021-06-18 18:28:56 +01:00
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<button ref="btn" id="select-area-btn" type="button" class="btn btn-primary btn-lg" v-if="current_hit" @click.stop="select_area()">
|
2021-07-16 10:47:15 +01:00
|
|
|
Select this area
|
2021-06-14 23:08:07 +01:00
|
|
|
</button>
|
2021-06-16 16:48:45 +01:00
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
<div class="alert alert-primary alert-map" role="alert" v-if="area_too_big">
|
|
|
|
Zoom in to see Wikidata items on the map.
|
|
|
|
</div>
|
|
|
|
|
2021-07-24 11:28:34 +01:00
|
|
|
<div class="alert alert-primary alert-map" role="alert" v-if="loading">
|
2021-07-11 16:18:45 +01:00
|
|
|
Found {{ item_count }} Wikidata items. Updating markers. <span class="spinner-border spinner-border-sm"></span>
|
|
|
|
</div>
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
<div class="alert alert-primary alert-map text-center" role="alert" v-if="!area_too_big && this.too_many_items">
|
2021-07-11 16:18:45 +01:00
|
|
|
Found {{ this.item_count.toLocaleString('en-US') }} Wikidata items.<br/> Zoom in to see them.
|
2021-07-06 16:24:14 +01:00
|
|
|
</div>
|
|
|
|
|
2021-07-19 21:11:01 +01:00
|
|
|
<div id="edit-count" class="p-2" v-if="!upload_state && edits.length">
|
2021-06-18 18:28:56 +01:00
|
|
|
<span>edits: {{ edits.length }}</span>
|
|
|
|
<button class="btn btn-primary btn-sm ms-2" @click="close_item(); view_edits=true">
|
|
|
|
<i class="fa fa-upload"></i> save
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="current_item && wd_item.image_list.length" class="modal fade" id="imageModal" tabindex="-1">
|
|
|
|
<div class="modal-dialog modal-dialog-centered modal-lg">
|
|
|
|
<div class="modal-content">
|
|
|
|
<div class="modal-header">
|
|
|
|
<h5 class="modal-title">Image from Wikidata</h5>
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
|
|
</div>
|
|
|
|
<div class="modal-body">
|
2021-06-16 16:48:45 +01:00
|
|
|
<img class="img-fluid" :src="api_base_url + '/commons/' + wd_item.image_list[0]">
|
2021-06-18 18:28:56 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-16 16:48:45 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<div id="sidebar">
|
2021-06-18 18:28:56 +01:00
|
|
|
<div v-if="view_edits" class="p-2">
|
|
|
|
<div class="h3">
|
|
|
|
Upload to OpenStreetMap
|
2021-06-24 17:40:59 +01:00
|
|
|
<button :disabled="upload_state !== undefined && upload_state != 'done'"
|
|
|
|
type="button"
|
|
|
|
class="btn-close float-end"
|
|
|
|
@click="close_edit_list"></button>
|
2021-06-18 18:28:56 +01:00
|
|
|
</div>
|
|
|
|
|
2021-06-24 17:40:59 +01:00
|
|
|
<div class="card w-100 bg-light mb-2">
|
2021-06-18 18:28:56 +01:00
|
|
|
<div class="card-body">
|
2021-07-16 10:14:05 +01:00
|
|
|
|
|
|
|
<template v-if="upload_state === undefined">
|
|
|
|
<div v-if="mockUpload" class="alert alert-danger">
|
|
|
|
<i class="fa fa-exclamation-triangle"></i>
|
|
|
|
Changes won't be saved to OpenStreetMap. This software uses a mock upload process to allow testing of the user interface, while it is still in development.
|
|
|
|
</div>
|
|
|
|
<div v-else class="alert alert-info">
|
|
|
|
<i class="fa fa-info-circle"></i>
|
|
|
|
Editing is live, changes will be uploaded to OpenStreetMap.
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<p class="card-text">
|
|
|
|
{{ edits.length + (edits.length == 1 ? " edit" : " edits") }} to upload
|
|
|
|
</p>
|
2021-06-24 17:40:59 +01:00
|
|
|
<form @submit.prevent="upload">
|
2021-06-18 18:28:56 +01:00
|
|
|
<div class="mb-3">
|
|
|
|
<label for="changesetComment" class="form-label">Changeset comment</label>
|
2021-06-24 17:40:59 +01:00
|
|
|
<input
|
|
|
|
:disabled="upload_state !== undefined"
|
|
|
|
type="text"
|
|
|
|
class="form-control"
|
|
|
|
id="changesetComment"
|
|
|
|
v-model="changeset_comment">
|
2021-06-18 18:28:56 +01:00
|
|
|
</div>
|
2021-06-24 17:40:59 +01:00
|
|
|
<button
|
|
|
|
:disabled="changeset_comment && upload_state !== undefined"
|
|
|
|
type="submit"
|
|
|
|
class="btn btn-primary">
|
|
|
|
<i class="fa fa-upload"></i> Save to OpenStreetMap
|
|
|
|
</button>
|
2021-06-18 18:28:56 +01:00
|
|
|
</form>
|
2021-06-24 17:40:59 +01:00
|
|
|
|
|
|
|
<div class="progress mt-2">
|
|
|
|
<div :style="{ width: upload_progress + '%' }"
|
|
|
|
class="progress-bar"
|
|
|
|
role="progressbar"></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2021-06-24 17:40:59 +01:00
|
|
|
<div v-if="upload_state == 'auth-fail'" class="alert alert-danger" role="alert">
|
|
|
|
<p>The OpenStreetMap returned an error: "Couldn't authenticate you".</p>
|
|
|
|
<p>To workaround this error you need to logout and login again.</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="upload_state == 'init'" class="alert alert-info" role="alert">
|
2021-07-16 10:27:19 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-06-24 17:40:59 +01:00
|
|
|
Starting upload.
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="upload_state == 'uploading'" class="alert alert-info" role="alert">
|
2021-07-16 10:27:19 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-06-24 17:40:59 +01:00
|
|
|
Uploading changes.
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="upload_state == 'closing'" class="alert alert-info" role="alert">
|
2021-07-16 10:27:19 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-06-24 17:40:59 +01:00
|
|
|
Closing changeset.
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="upload_state == 'done'" class="alert alert-success" role="alert">
|
2021-07-16 10:27:19 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-06-24 17:40:59 +01:00
|
|
|
Changes saved.
|
|
|
|
<a :href="`https://www.openstreetmap.org/changeset/${changeset_id}`"
|
|
|
|
target="_blank">
|
2021-07-11 16:18:45 +01:00
|
|
|
view your changeset <i class="fa fa-external-link"></i>
|
2021-06-24 17:40:59 +01:00
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<div class="card my-2 w-100" v-for="edit in edits_grouped_by_qid">
|
|
|
|
<div class="card-body">
|
|
|
|
<h4 class="card-title">
|
|
|
|
<a :href="qid_url(edit.qid)" target="_blank">
|
|
|
|
{{ edit.wikidata.label }}
|
|
|
|
</a> ({{ edit.qid }})
|
|
|
|
</h4>
|
|
|
|
|
|
|
|
<p class="card-text">
|
|
|
|
|
|
|
|
<span v-if="edit.wikidata.description">
|
|
|
|
<strong>description</strong><br/>
|
|
|
|
{{ edit.wikidata.description }}<br/>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<strong>item type</strong><br/>
|
|
|
|
<span
|
|
|
|
v-bind:key="`isa-${edit.qid}-${isa_qid}`"
|
2021-10-22 11:43:27 +01:00
|
|
|
v-for="isa in edit.wikidata.isa_list">
|
|
|
|
<a :href="qid_url(isa.qid)" target="_blank">{{ isa.label }}</a> ({{isa.qid}})
|
2021-06-18 18:28:56 +01:00
|
|
|
<br/>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span v-if="edit.wikidata.street_address.length">
|
|
|
|
<strong>street address</strong><br/>
|
|
|
|
{{ edit.wikidata.street_address[0] }}<br/>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<strong>OSM matches</strong>
|
|
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<table class="table table-sm table-hover">
|
|
|
|
<tbody>
|
|
|
|
<tr v-for="osm in edit.osm" class="osm-candidate">
|
2021-07-06 16:24:14 +01:00
|
|
|
<td class="text-end">
|
|
|
|
<span class="text-nowrap">{{ osm.distance.toFixed(0) }}m</span><br>
|
2021-06-18 18:28:56 +01:00
|
|
|
<a
|
|
|
|
:href="'https://www.openstreetmap.org/' + osm.identifier"
|
|
|
|
target="_blank"
|
|
|
|
@click.stop><i class="fa fa-map-o"></i></a>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
{{ osm.name || "no name" }}
|
|
|
|
<span v-for="(p, index) in osm.presets">
|
|
|
|
<span v-if="index != 0">, </span>
|
|
|
|
<a
|
|
|
|
:href="'http://wiki.openstreetmap.org/wiki/' + p.tag_or_key"
|
|
|
|
class="osm-wiki-link"
|
|
|
|
target="_blank"
|
|
|
|
@click.stop>{{p.name}} <i class="fa fa-external-link"></i></a>
|
|
|
|
</span>
|
|
|
|
|
2021-06-18 20:37:55 +01:00
|
|
|
<span v-if="osm.address && osm.address != osm.name">
|
2021-06-18 18:28:56 +01:00
|
|
|
<br>street address: {{ osm.address }}
|
|
|
|
</span>
|
2021-06-18 20:37:55 +01:00
|
|
|
<span v-else-if="osm.tags['addr:street'] && osm.address != osm.name">
|
2021-06-18 18:28:56 +01:00
|
|
|
<br>street: {{ osm.tags['addr:street'] }}
|
|
|
|
</span>
|
2021-11-12 11:43:33 +00:00
|
|
|
<span v-else-if="osm.tags['addr:housenumber'] && osm.address != osm.name">
|
|
|
|
<br>house number: {{ osm.tags['addr:housenumber'] }}
|
|
|
|
</span>
|
2021-06-18 18:28:56 +01:00
|
|
|
|
|
|
|
<span v-if="osm.address_list.length">
|
2021-07-22 16:02:52 +01:00
|
|
|
<br>nodes within building: {{ osm.address_list.join("; ") }}
|
2021-06-18 18:28:56 +01:00
|
|
|
</span>
|
|
|
|
|
|
|
|
<span v-if="osm.part_of">
|
2021-07-11 16:18:45 +01:00
|
|
|
<br>part of:
|
|
|
|
<span v-for="(part_of, part_of_index) in osm.part_of">
|
|
|
|
<span v-if="part_of_index != 0">, </span>
|
2021-07-16 10:47:31 +01:00
|
|
|
{{ part_of.tags.name }}
|
2021-07-11 16:18:45 +01:00
|
|
|
</span>
|
2021-06-18 18:28:56 +01:00
|
|
|
</span>
|
|
|
|
|
|
|
|
<br>
|
|
|
|
<span v-if="osm.selected">
|
2021-10-22 11:50:25 +01:00
|
|
|
<span v-if="osm.tags.wikidata !== undefined">
|
|
|
|
update tag: <span class="badge bg-success">wikidata={{ edit.qid }}</span>
|
|
|
|
</span>
|
|
|
|
<span v-else>
|
|
|
|
add tag: <span class="badge bg-success">wikidata={{ edit.qid }}</span>
|
|
|
|
</span>
|
2021-06-18 18:28:56 +01:00
|
|
|
</span>
|
|
|
|
<span v-else>
|
|
|
|
remove tag: <span class="badge bg-danger">wikidata={{ edit.qid }}</span>
|
|
|
|
</span>
|
|
|
|
|
2021-06-24 17:40:59 +01:00
|
|
|
<span v-if="osm.upload_state == 'current'"
|
|
|
|
class="ms-2 badge bg-info">uploading</span>
|
|
|
|
<span v-if="osm.upload_state == 'saved'"
|
|
|
|
class="ms-2 badge bg-success">saved</span>
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
<div v-if="!current_item && !view_edits">
|
2021-06-14 23:08:07 +01:00
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<div v-if="!edits.length" class="card m-2">
|
2021-06-14 23:08:07 +01:00
|
|
|
<div class="card-body">
|
|
|
|
<form id="search-form" class="row row-cols-lg-auto g-3 align-items-center" @submit.prevent="run_search">
|
|
|
|
<div class="col-12">
|
|
|
|
<input class="form-control" id="search-text" v-model.trim="search_text" placeholder="place">
|
|
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
|
|
<button type="submit" id="search-btn" class="btn btn-primary">search</button>
|
2021-07-30 15:02:41 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
</div>
|
|
|
|
</form>
|
2021-07-11 16:18:45 +01:00
|
|
|
<p v-if="recent_search" class="card-text mt-2">Searching for '{{ recent_search }}', found {{ hits.length }} places.</p>
|
2021-06-18 18:24:50 +01:00
|
|
|
<div class="list-group" v-if="hits.length">
|
2021-06-14 23:08:07 +01:00
|
|
|
<a class="list-group-item list-group-item-action"
|
2021-07-11 16:18:45 +01:00
|
|
|
:class="{ active: hit == this.current_hit }"
|
2021-06-14 23:08:07 +01:00
|
|
|
v-bind:key="hit.identifier"
|
|
|
|
v-for="hit in hits"
|
|
|
|
:href="hit_url(hit)"
|
2021-07-11 16:18:45 +01:00
|
|
|
@mouseenter="show_hit_on_map(hit)"
|
2021-06-14 23:08:07 +01:00
|
|
|
@click.prevent="visit(hit)">
|
2024-05-04 09:13:49 +01:00
|
|
|
{{ hit.name }} <span class="badge bg-info">{{ hit.label }}</span>
|
2021-06-14 23:08:07 +01:00
|
|
|
</a>
|
|
|
|
</div>
|
2021-07-16 10:47:15 +01:00
|
|
|
<div class="alert alert-info mt-2" v-if="hits.length">
|
|
|
|
<i class="fa fa-info-circle"></i>
|
|
|
|
<span v-if="hits.length == 1">
|
|
|
|
One search result. Click the result to continue.
|
|
|
|
</span>
|
|
|
|
<span v-else>
|
|
|
|
Click a result to continue.
|
|
|
|
</span>
|
|
|
|
</div>
|
2021-07-30 15:02:41 +01:00
|
|
|
<div class="form-check form-switch">
|
|
|
|
<input class="form-check-input" type="checkbox" id="type-filter" v-model="show_item_type_filter">
|
|
|
|
<label class="form-check-label" for="type-filter">item type filter</label>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="card" v-if="show_item_type_filter">
|
|
|
|
<div class="card-body">
|
|
|
|
<h5 class="card-title">item type filters</h5>
|
|
|
|
<input class="form-control" v-model.trim="item_type_search" placeholder="item type">
|
|
|
|
|
|
|
|
<div class="list-group" v-if="item_type_hits.length">
|
|
|
|
<a class="list-group-item"
|
|
|
|
v-bind:key="isa.qid"
|
|
|
|
v-for="isa in item_type_hits"
|
|
|
|
href="#"
|
2023-05-13 14:01:28 +01:00
|
|
|
@click.prevent="add_item_type_filter(isa)"
|
2021-07-30 15:02:41 +01:00
|
|
|
>
|
|
|
|
{{ isa.label }} ({{ isa.qid }})
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<h6>current item type filters</h6>
|
|
|
|
<div class="list-group" v-if="item_type_filters.length">
|
|
|
|
<a class="list-group-item" v-bind:key="isa.qid" v-for="(isa, index) in item_type_filters" href="#">
|
|
|
|
{{ isa.label }} ({{ isa.qid }})
|
|
|
|
<button type="button"
|
|
|
|
class="btn btn-danger btn-sm"
|
|
|
|
@click="item_type_filters.splice(index, 1)">remove</button>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<div v-else>no item type filters</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-07-11 16:18:45 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="card m-2" v-if="show_instructions">
|
|
|
|
<div class="card-body">
|
|
|
|
<div class="h3 card-title">Link Wikidata and OpenStreetMap</div>
|
2021-07-14 14:57:51 +01:00
|
|
|
<div class="alert alert-danger">
|
|
|
|
<i class="fa fa-exclamation-triangle"></i>
|
2021-08-05 07:43:15 +01:00
|
|
|
This software is beta, it works but is incomplete. <a href="/documentation">See what's broken</a>.
|
|
|
|
<!-- This software is unfinished. Only mock editing happens, nothing is uploaded to the OpenStreetMap database yet. <a href="/documentation" class="alert-link">See what's broken</a> -->
|
2021-07-14 14:57:51 +01:00
|
|
|
</div>
|
2021-08-05 07:43:15 +01:00
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<p class="card-text">This tool will help you link Wikidata items with the matching object on OpenStreetMap (OSM).</p>
|
|
|
|
|
|
|
|
<p v-if="!username" class="card-text">To save changes you need to <a href="/login">login via OpenStreetMap</a>.</p>
|
|
|
|
|
|
|
|
<p class="card-text">Zoom in or search for an area to work on.</p>
|
|
|
|
|
2021-07-14 14:57:51 +01:00
|
|
|
<hr>
|
|
|
|
|
|
|
|
<p>This project was created by Edward Betts
|
|
|
|
[<a href="https://twitter.com/edwardbetts/"><i class="fa fa-twitter"></i></a>].</p>
|
|
|
|
|
|
|
|
<p class="card-text">
|
|
|
|
Discussion of collaboration between Wikidata and OpenStreetMap happens on the
|
|
|
|
<a href="https://t.me/wikimaps" target="_blank" class="text-nowrap">
|
|
|
|
<i class="fa fa-telegram"></i>Wikimaps Telegram channel</a> and the
|
|
|
|
<a href="https://osmus.slack.com/archives/CUP8V1Z61" target="_blank" class="text-nowrap">
|
|
|
|
<i class="fa fa-slack"></i>OpenStreetMap/Wikimedia Slack channel</a>.
|
|
|
|
</p>
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<!--
|
|
|
|
|
|
|
|
<p class="card-text">The map will show at most 400 items, if there are more then you need to zoom in before you can start editing.</p>
|
|
|
|
|
|
|
|
<p class="card-text">Wikidata items appear on the map as red or green markers. Items not linked for OSM appear in red, those that are linked appear in green. The map shows the location of Wikidata tagged OSM objects with a yellow pin.</p>
|
|
|
|
|
|
|
|
<p class="card-text">There are controls to filter what appears on the map. You have the option to hide Wikidata items that are already tagged on OSM. The type filter allows you to adjust what types of Wikidata item are displayed.</p>
|
|
|
|
|
|
|
|
<p class="card-text">Click on a marker to show details of the Wikidata item and find nearby possible OSM matches.</p>
|
|
|
|
-->
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="card m-2" v-if="!view_edits && isa_list.length">
|
|
|
|
<div class="card-body">
|
|
|
|
<div class="h5 card-title">Map key</div>
|
2024-05-04 09:13:49 +01:00
|
|
|
<ul class="list-group">
|
2021-07-11 16:18:45 +01:00
|
|
|
<li class="list-group-item">
|
2024-05-04 09:13:49 +01:00
|
|
|
<i style="background: #a23337; color: white" class="p-1 fa fa-chain-broken"></i>
|
2021-07-11 16:18:45 +01:00
|
|
|
Wikidata item without OSM link
|
|
|
|
</li>
|
|
|
|
<li class="list-group-item">
|
2024-05-04 09:13:49 +01:00
|
|
|
<i style="background: #6dae40; color: white" class="p-1 fa fa-link"></i>
|
2021-07-11 16:18:45 +01:00
|
|
|
Wikidata item with OSM link
|
|
|
|
</li>
|
|
|
|
<li class="list-group-item">
|
|
|
|
<i style="background: #f5bb39; color: white" class="p-1 fa fa-map"></i>
|
|
|
|
Linked OSM object
|
|
|
|
</li>
|
2024-05-04 09:13:49 +01:00
|
|
|
</ul>
|
2021-06-14 23:08:07 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2024-05-04 09:13:49 +01:00
|
|
|
<div class="m-2" v-if="!view_edits && isa_list.length">
|
2021-06-18 18:28:56 +01:00
|
|
|
|
2024-05-04 09:13:49 +01:00
|
|
|
<ul class="nav nav-pills" id="myTab" role="tablist">
|
|
|
|
<li class="nav-item" role="presentation">
|
|
|
|
<button class="nav-link" id="filter-tab" role="tab" @click.stop="tab='filters'" :class="{ active: tab == 'filters' }">Map filters</button>
|
|
|
|
</li>
|
|
|
|
<li class="nav-item" role="presentation">
|
|
|
|
<button class="nav-link" id="item-list-tab" role="tab" @click.stop="tab='items'" :class="{ active: tab == 'items' }">Items</button>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
<div class="tab-content" id="myTabContent">
|
|
|
|
|
|
|
|
<div class="tab-pane active" id="filters" v-if="tab=='filters'">
|
|
|
|
<div class="card my-2">
|
2021-07-11 16:18:45 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<div class="card-body">
|
|
|
|
<div class="h5 card-title">OSM/Wikidata link status</div>
|
|
|
|
<div class="list-group">
|
|
|
|
<label for="linked" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
|
|
<span>
|
|
|
|
<input class="form-check-input me-1" id="linked" type="checkbox" v-model="linked">
|
|
|
|
Wikidata items tagged in OSM
|
|
|
|
</span>
|
|
|
|
<span class="badge bg-primary rounded-pill">{{ tagged_count }}</span>
|
|
|
|
</label><br>
|
|
|
|
<label for="not-linked" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
|
|
<span>
|
|
|
|
<input class="form-check-input me-1" id="not-linked" type="checkbox" v-model="not_linked">
|
|
|
|
Wikidata items not tagged in OSM
|
|
|
|
</span>
|
|
|
|
<span class="badge bg-primary rounded-pill">{{ not_tagged_count }}</span>
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2024-05-04 09:13:49 +01:00
|
|
|
<div class="card my-2" id="isa-card">
|
2021-06-14 23:08:07 +01:00
|
|
|
<div class="card-body">
|
|
|
|
<div class="h5 card-title">item types</div>
|
2021-07-22 16:03:56 +01:00
|
|
|
<div>
|
|
|
|
<button type="button" class="btn btn-primary btn-sm m-1" @click.prevent="isa_tick_all">select all</button>
|
|
|
|
<button type="button" class="btn btn-primary btn-sm m-1" @click.prevent="isa_ticked=[]">clear selection</button>
|
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
<div class="list-group" @mouseout="this.hover_isa=undefined">
|
|
|
|
<label class="list-group-item list-group-item-action d-flex justify-content-between align-items-center" v-for="isa in isa_list" @mouseenter="this.hover_isa=isa">
|
|
|
|
<span>
|
2021-06-18 18:26:07 +01:00
|
|
|
<input class="form-check-input me-1" type="checkbox" :id="'isa-' + isa.qid" :value="isa.qid" v-model="isa_ticked">
|
2021-06-14 23:08:07 +01:00
|
|
|
{{ isa.label }} ({{ isa.qid }})
|
2021-07-22 14:30:18 +01:00
|
|
|
<a href="#" @click.prevent="isa_ticked=[isa.qid]">only</a>
|
2021-06-14 23:08:07 +01:00
|
|
|
</span>
|
|
|
|
<span class="badge bg-primary rounded-pill">{{ isa.count }}</span>
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-05-04 09:13:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tab-pane active" id="items" v-if="tab=='items'">
|
|
|
|
<ul class="list-group">
|
|
|
|
<li v-for="(item, qid) in items" class="list-group-item" @click.stop="open_item(qid)"
|
|
|
|
:class="{active: highlight_item==item}"
|
|
|
|
@mouseover="add_highlight(qid)" @mouseleave="drop_highlight(qid)">
|
|
|
|
<div v-if="item.wikidata">
|
|
|
|
<div>
|
|
|
|
<span class="fw-bold">
|
|
|
|
{{ item.wikidata.label }}
|
|
|
|
</span>
|
|
|
|
({{ qid }})
|
|
|
|
<span class="badge bg-success" v-if="item.osm">Linked</span>
|
|
|
|
<span class="badge bg-danger" v-else>Not linked</span>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{{ item.wikidata.description }}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div class="fw-bold">item type</div>
|
|
|
|
<div v-for="isa in item.wikidata.isa_list">
|
|
|
|
{{ isa.label }} ({{ isa.qid }})
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<span v-else>
|
|
|
|
{{ qid }}
|
|
|
|
</span>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="card m-2" id="detail-card" v-if="current_item">
|
|
|
|
<div class="card-body">
|
|
|
|
<div class="h4 card-title">
|
|
|
|
<span id="detail-header">item detail</span>
|
2021-10-06 18:05:04 +01:00
|
|
|
|
|
|
|
<button class="btn btn-primary btn-sm ms-2" @click="zoom_to_selected_marker()">
|
|
|
|
<i class="fa fa-search-plus"></i> zoom in on item
|
|
|
|
</button>
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<button type="button" class="btn-close float-end" id="close-detail" @click="close_item()"></button>
|
|
|
|
</div>
|
|
|
|
<div id="detail">
|
2021-10-06 18:02:18 +01:00
|
|
|
<div class="row"><div class="col-xl-6">
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<strong>Wikidata item</strong><br>
|
|
|
|
<a :href="qid_url(wd_item.qid)" target="_blank">{{ wd_item.label }}</a> ({{ wd_item.qid }})
|
|
|
|
|
|
|
|
<span v-if="wd_item.description">
|
|
|
|
<br><strong>description</strong><br>{{ wd_item.description }}
|
|
|
|
</span>
|
|
|
|
|
2021-10-06 18:06:42 +01:00
|
|
|
<span v-if="wd_item.aliases !== undefined && wd_item.aliases.length">
|
|
|
|
<br><strong>aliases</strong>
|
|
|
|
<br>{{ wd_item.aliases.join("; ") }}
|
|
|
|
</span>
|
|
|
|
|
2023-05-13 14:01:28 +01:00
|
|
|
<br><strong>item coordinates</strong>
|
|
|
|
<span v-for="marker in wd_item.markers">
|
|
|
|
<br><a target="_blank" :href="marker_osm_url(marker)" @click.stop>
|
|
|
|
{{ marker[0].toFixed(5) }},
|
|
|
|
{{ marker[1].toFixed(5) }}
|
|
|
|
<i class="fa fa-map-o"></i></a>
|
|
|
|
</span>
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
<br><strong>item type</strong>
|
2021-10-22 11:43:27 +01:00
|
|
|
<span v-bind:key="`isa-${wd_item.qid}-${isa.qid}`" v-for="isa in wd_item.isa_list">
|
|
|
|
<br><a :href="qid_url(isa.qid)" target="_blank">{{isa.label}}</a> ({{isa.qid}})
|
|
|
|
<a :href="'/isa/' + isa.qid" target="_blank"><i class="fa fa-pencil-square-o"></i></a>
|
2021-06-14 23:08:07 +01:00
|
|
|
</span>
|
|
|
|
|
2023-05-13 14:01:28 +01:00
|
|
|
<span v-if="wd_item.wikipedia.length > 0">
|
|
|
|
<br>
|
|
|
|
<strong>
|
|
|
|
Wikipedia
|
|
|
|
<i class="fa fa-external-link"></i>
|
|
|
|
</strong>
|
|
|
|
<br>
|
|
|
|
<span v-for="wp in wd_item.wikipedia">
|
|
|
|
<a :href="wikipedia_link(wp.lang, wp.title)" target="_blank">{{wp.lang}}</a>
|
|
|
|
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
|
2021-11-19 15:44:16 +00:00
|
|
|
<span v-if="wd_item.inception.length">
|
|
|
|
<br><strong>inception</strong>
|
|
|
|
<br>{{wd_item.inception.join('; ')}}
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span v-if="wd_item.p1619.length">
|
|
|
|
<br><strong>date of official opening</strong>
|
|
|
|
<br>{{wd_item.p1619.join('; ')}}
|
|
|
|
</span>
|
|
|
|
|
2021-07-02 10:08:53 +01:00
|
|
|
<span v-if="wd_item.closed.length">
|
|
|
|
<br><strong>closed</strong>
|
|
|
|
<br>{{wd_item.closed.join('; ')}}
|
|
|
|
</span>
|
|
|
|
|
2021-11-19 15:44:16 +00:00
|
|
|
<span v-if="wd_item.p576.length">
|
|
|
|
<br><strong>dissolved, abolished or demolished date</strong>
|
|
|
|
<br>{{wd_item.p576.join('; ')}}
|
|
|
|
</span>
|
|
|
|
|
2021-10-06 18:13:34 +01:00
|
|
|
<span v-if="wd_item.heritage_designation.length">
|
|
|
|
<br><strong>heritage designation</strong>
|
2021-10-22 11:43:27 +01:00
|
|
|
<span v-bind:key="`hd-${wd_item.qid}-${hd.qid}`" v-for="hd in wd_item.heritage_designation">
|
|
|
|
<br><a :href="qid_url(hd.qid)" target="_blank">{{hd.label}}</a> ({{hd.qid}})
|
|
|
|
</span>
|
2021-10-06 18:13:34 +01:00
|
|
|
</span>
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
</div>
|
2021-10-06 18:02:18 +01:00
|
|
|
<div class="col-xl-6">
|
2021-06-18 18:28:56 +01:00
|
|
|
|
2021-10-06 18:05:04 +01:00
|
|
|
<div v-if="bounds_before_open" class="alert alert-info">
|
|
|
|
<i class="fa fa-info-circle"></i> Close item to zoom out.
|
|
|
|
</div>
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
<div v-if="current_item.tag_or_key_list && current_item.tag_or_key_list.length">
|
|
|
|
<strong>OSM tags/keys to search for</strong><br/>
|
|
|
|
{{ current_item.tag_or_key_list.length }} tags/keys to consider
|
2021-07-14 14:58:53 +01:00
|
|
|
<a href="#" @click.prevent="show_tag_or_key_list = !show_tag_or_key_list">show/hide</a><br/>
|
2021-06-18 18:28:56 +01:00
|
|
|
<div v-if="show_tag_or_key_list">
|
|
|
|
<div v-for="v in current_item.tag_or_key_list">{{ v }}</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
<span v-if="wd_item.image_list.length">
|
2021-07-11 16:18:45 +01:00
|
|
|
<strong>Image from Wikidata</strong><br/>
|
2021-06-16 16:48:45 +01:00
|
|
|
<a href="#" data-bs-toggle="modal" data-bs-target="#imageModal">
|
|
|
|
<img class="w-100" :src="api_base_url + '/commons/' + wd_item.image_list[0]">
|
|
|
|
</a>
|
|
|
|
<br/>
|
|
|
|
<a href="#" data-bs-toggle="modal" data-bs-target="#imageModal">
|
|
|
|
enlarge image
|
|
|
|
</a>
|
2021-06-14 23:08:07 +01:00
|
|
|
</span>
|
|
|
|
|
2023-05-13 14:01:28 +01:00
|
|
|
<span v-if="wd_item.commons !== undefined">
|
|
|
|
<br><strong>Images on Commons</strong>
|
|
|
|
<br><a
|
|
|
|
:href="`https://commons.wikimedia.org/wiki/${wd_item.commons.replaceAll(' ', '_')}`"
|
|
|
|
target="_blank">
|
|
|
|
{{wd_item.commons}} <i class="fa fa-external-link"></i>
|
|
|
|
</a>
|
|
|
|
</span>
|
|
|
|
|
2024-05-04 09:13:49 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="row">
|
|
|
|
<div class="col-xl-12">
|
|
|
|
<span v-if="Object.keys(wd_item.identifiers).length !== 0">
|
|
|
|
<strong>identifiers</strong>
|
|
|
|
<div v-for="(values, label) in wd_item.identifiers">
|
|
|
|
{{ label }}: {{ values.join("; ") }}
|
|
|
|
</div>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span v-if="wd_item.street_address.length">
|
|
|
|
<strong>street address</strong>
|
|
|
|
<br>{{wd_item.street_address[0]}}
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
</div>
|
|
|
|
|
2021-07-14 14:59:57 +01:00
|
|
|
<div class="form-check form-switch">
|
|
|
|
<input class="form-check-input" type="checkbox" id="debug" v-model="debug">
|
|
|
|
<label class="form-check-label" for="debug">debug</label>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="debug">
|
|
|
|
API calls:
|
|
|
|
<a :href="`${api_base_url}/api/1/count?${bounds_param()}`" target="_blank">count</a> |
|
|
|
|
<a :href="`${api_base_url}/api/1/isa?${bounds_param()}`" target="_blank">item type counts</a> |
|
|
|
|
<a :href="`${api_base_url}/api/1/item/${wd_item.qid}`" target="_blank">item detail</a> |
|
|
|
|
<a :href="`${api_base_url}/api/1/item/${wd_item.qid}/tags`" target="_blank">item tags</a> |
|
2021-07-22 13:51:24 +01:00
|
|
|
<a :href="`${api_base_url}/api/1/item/${wd_item.qid}/candidates`" target="_blank">nearby OSM candidates</a>
|
2021-07-14 14:59:57 +01:00
|
|
|
</div>
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<div v-if="!current_item.nearby" class="alert alert-info">
|
|
|
|
Searching for nearby OSM matches <span class="spinner-border spinner-border-sm"></span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="current_item.nearby && !current_item.nearby.length">
|
|
|
|
<strong>No OSM matches found nearby</strong>
|
2021-10-22 11:52:21 +01:00
|
|
|
|
2023-05-13 14:01:28 +01:00
|
|
|
<div class="mt-2" v-if="current_item.tag_or_key_list && current_item.tag_or_key_list.length">
|
2021-10-22 11:52:21 +01:00
|
|
|
<p>The OSM tags/keys used as the search criteria to find matching
|
|
|
|
OSM objects are listed below, along with the Wikidata item that was
|
|
|
|
the source.</p>
|
|
|
|
<div v-for="v in current_item.tag_or_key_list">
|
|
|
|
<b>{{ v }}</b><br>
|
|
|
|
|
|
|
|
<div v-for="src_list in current_item.tag_src[v]">
|
|
|
|
<a :href="qid_url(wd_item.qid)" target="_blank">{{ wd_item.label }}</a> ({{ wd_item.qid }})<br>
|
|
|
|
<span v-for="(src_obj, i) in src_list">
|
|
|
|
⤷ <a :href="qid_url(src_obj.qid)">{{ src_obj.label }}</a> ({{ src_obj.qid}})<br></span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div v-else>
|
|
|
|
There are no OSM tags/keys associated with this type of item on Wikidata.
|
|
|
|
</div>
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
<div v-if="current_item.nearby && current_item.nearby.length">
|
2021-07-06 16:24:14 +01:00
|
|
|
|
2021-07-14 15:01:07 +01:00
|
|
|
<div v-if="!username" class="alert alert-info">
|
2021-07-16 10:47:15 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-07-14 15:01:07 +01:00
|
|
|
<a href="/login">Login with OpenStreetMap</a> to add Wikidata tags</div>
|
|
|
|
|
|
|
|
<div v-if="edits.length" class="alert alert-info">
|
2021-07-16 10:47:15 +01:00
|
|
|
<i class="fa fa-info-circle"></i>
|
2021-07-14 15:01:07 +01:00
|
|
|
Use the save button in the top right corner of the map to upload changes.
|
|
|
|
</div>
|
2021-07-11 16:18:45 +01:00
|
|
|
|
|
|
|
<strong>Possible OSM matches</strong> (sorted by distance from item)<br>
|
|
|
|
show:
|
|
|
|
<div class="form-check form-switch form-check-inline">
|
2021-07-06 16:24:14 +01:00
|
|
|
<input class="form-check-input" type="checkbox" id="show-tags" v-model="show_tags">
|
2021-07-11 16:18:45 +01:00
|
|
|
<label class="form-check-label" for="show-tags">tags</label>
|
|
|
|
</div>
|
|
|
|
<div class="form-check form-switch form-check-inline">
|
|
|
|
<input class="form-check-input" type="checkbox" id="show-area" v-model="show_area">
|
|
|
|
<label class="form-check-label" for="show-area">area</label>
|
|
|
|
</div>
|
|
|
|
<div class="form-check form-switch form-check-inline">
|
|
|
|
<input class="form-check-input" type="checkbox" id="show-presets" v-model="show_presets">
|
|
|
|
<label class="form-check-label" for="show-presets">type</label>
|
2021-07-06 16:24:14 +01:00
|
|
|
</div>
|
|
|
|
|
2021-06-20 13:45:10 +01:00
|
|
|
<table class="table table-sm table-hover" @mouseleave="this.current_osm = undefined">
|
2021-06-14 23:08:07 +01:00
|
|
|
<tbody>
|
|
|
|
<tr
|
|
|
|
v-for="osm in current_item.nearby"
|
|
|
|
class="osm-candidate"
|
2021-07-11 16:18:45 +01:00
|
|
|
:class="{ 'table-success': osm.selected }"
|
2021-06-18 18:28:56 +01:00
|
|
|
@mouseenter="this.current_osm=osm"
|
|
|
|
@click="select_osm(current_item, osm)">
|
2021-07-06 16:24:14 +01:00
|
|
|
<td class="text-nowrap">
|
|
|
|
<input class="form-check-input" type="checkbox" v-model="osm.selected" v-if="username" />
|
2021-06-14 23:08:07 +01:00
|
|
|
{{ osm.distance.toFixed(0) }}m
|
2021-06-18 18:28:56 +01:00
|
|
|
<a
|
|
|
|
:href="'https://www.openstreetmap.org/' + osm.identifier"
|
|
|
|
target="_blank"
|
|
|
|
@click.stop><i class="fa fa-map-o"></i></a>
|
2021-06-14 23:08:07 +01:00
|
|
|
</td>
|
|
|
|
<td>
|
2021-07-11 16:18:45 +01:00
|
|
|
<span class="badge bg-primary float-end">{{ osm.type }}</span>
|
2021-11-19 15:43:51 +00:00
|
|
|
<span v-if="osm.name">
|
|
|
|
{{ osm.name }}
|
|
|
|
<span class="badge bg-success" v-if="osm.name_match">name match</span>
|
2024-05-03 19:52:54 +01:00
|
|
|
<span class="badge bg-danger" v-if="osm.tags['disused'] == 'yes' || isDisused(osm.tags)">disused</span>
|
2021-11-19 15:43:51 +00:00
|
|
|
</span>
|
2021-07-11 16:18:45 +01:00
|
|
|
<template v-if="show_presets && osm.presets.length">
|
2021-10-22 11:58:34 +01:00
|
|
|
<template v-if="osm.name"><br></template>
|
2021-06-14 23:08:07 +01:00
|
|
|
<span v-for="(p, index) in osm.presets">
|
|
|
|
<span v-if="index != 0">, </span>
|
|
|
|
<a
|
|
|
|
:href="'http://wiki.openstreetmap.org/wiki/' + p.tag_or_key"
|
|
|
|
class="osm-wiki-link"
|
2021-06-17 18:16:32 +01:00
|
|
|
target="_blank"
|
|
|
|
@click.stop>{{p.name}} <i class="fa fa-external-link"></i></a>
|
|
|
|
</span>
|
2021-07-11 16:18:45 +01:00
|
|
|
</template>
|
2021-10-22 11:58:34 +01:00
|
|
|
<template v-if="!osm.name"> <i>no name</i></template>
|
2021-06-17 18:16:32 +01:00
|
|
|
|
2021-06-18 20:37:55 +01:00
|
|
|
<span v-if="osm.address && osm.address != osm.name">
|
2021-06-17 18:16:32 +01:00
|
|
|
<br>street address: {{ osm.address }}
|
|
|
|
</span>
|
2021-06-18 20:37:55 +01:00
|
|
|
<span v-else-if="osm.tags['addr:street'] && osm.address != osm.name">
|
2021-06-17 18:16:32 +01:00
|
|
|
<br>street: {{ osm.tags['addr:street'] }}
|
2021-06-14 23:08:07 +01:00
|
|
|
</span>
|
2021-11-12 11:43:33 +00:00
|
|
|
<span v-else-if="osm.tags['addr:housenumber'] && osm.address != osm.name">
|
|
|
|
<br>house number: {{ osm.tags['addr:housenumber'] }}
|
|
|
|
</span>
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
<span v-if="osm.address_list.length">
|
2021-07-22 16:02:52 +01:00
|
|
|
<br>nodes within building: {{ osm.address_list.join("; ") }}
|
2021-06-14 23:08:07 +01:00
|
|
|
</span>
|
2021-06-16 13:33:18 +01:00
|
|
|
|
|
|
|
<span v-if="osm.part_of">
|
2021-07-11 16:18:45 +01:00
|
|
|
<br>part of:
|
|
|
|
<span v-for="(part_of, part_of_index) in osm.part_of">
|
|
|
|
<span v-if="part_of_index != 0">, </span>
|
2021-10-06 18:14:47 +01:00
|
|
|
|
|
|
|
<a
|
|
|
|
:href="`https://www.openstreetmap.org/${part_of.type}/${part_of.id}`"
|
|
|
|
target="_blank"
|
|
|
|
@click.stop>
|
|
|
|
{{ part_of.tags.name }} <i class="fa fa-map-o"></i></a>
|
2021-07-11 16:18:45 +01:00
|
|
|
</span>
|
2021-10-06 18:14:47 +01:00
|
|
|
|
2021-06-16 13:33:18 +01:00
|
|
|
</span>
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
<span v-if="osm.tags.ele">
|
|
|
|
<br>elevation: {{ osm.tags.ele }} m
|
|
|
|
</span>
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
<span v-if="show_area && osm.area && osm.area > 10 * 10">
|
|
|
|
<br>area: {{ format_area(osm.area) }}
|
2021-07-06 16:24:14 +01:00
|
|
|
</span>
|
|
|
|
|
|
|
|
<span v-if="osm.tags.wikidata">
|
|
|
|
<br>Wikidata tag:
|
|
|
|
<a :href="`https://wikidata.org/wiki/${osm.tags.wikidata}`">{{ osm.tags.wikidata }}</a>
|
2021-07-23 13:41:10 +01:00
|
|
|
<span class="ms-1">
|
|
|
|
<span v-if="osm.tags.wikidata == wd_item.qid" class="badge bg-success">this item</span>
|
|
|
|
<span v-else class="badge bg-info">different item</span>
|
|
|
|
</span>
|
2021-07-06 16:24:14 +01:00
|
|
|
</span>
|
2021-10-22 11:59:11 +01:00
|
|
|
|
|
|
|
<div v-if="osm.tags['brand:wikidata']">
|
|
|
|
Brand Wikidata tag:
|
|
|
|
<a :href="`https://wikidata.org/wiki/${osm.tags['brand:wikidata']}`">{{ osm.tags['brand:wikidata'] }}</a>
|
|
|
|
<span class="ms-1">
|
|
|
|
<span v-if="osm.tags['brand:wikidata'] == wd_item.qid" class="badge bg-success">this item</span>
|
|
|
|
<span v-else class="badge bg-info">different item</span>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="osm.tags['brand:wikidata'] == wd_item.qid" class="alert alert-info mt-1">
|
|
|
|
<i class="fa fa-exclamation-triangle"></i>
|
|
|
|
No need to add a Wikidata tag, already tagged as brand.
|
|
|
|
</div>
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
<div class="card" v-if="show_tags">
|
|
|
|
<div class="card-body tag-card-body">
|
|
|
|
<span class="badge bg-secondary float-end">tags</span>
|
|
|
|
<div class="card-text" v-for="(value, key) of osm.tags">
|
|
|
|
<strong>{{ key }}</strong>:
|
|
|
|
{{ value.replace(/;/g, '; ') }}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-06-14 23:08:07 +01:00
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2024-05-04 09:13:49 +01:00
|
|
|
import 'bootstrap';
|
|
|
|
import { Modal } from 'bootstrap';
|
|
|
|
import 'bootstrap/dist/css/bootstrap.css';
|
2021-06-14 23:08:07 +01:00
|
|
|
import L from "leaflet";
|
2024-05-04 09:13:49 +01:00
|
|
|
import 'leaflet/dist/leaflet.css';
|
2021-06-14 23:08:07 +01:00
|
|
|
import { ExtraMarkers } from "leaflet-extra-markers";
|
2024-05-04 09:13:49 +01:00
|
|
|
import 'leaflet-extra-markers/dist/css/leaflet.extra-markers.min.css';
|
2021-06-14 23:08:07 +01:00
|
|
|
import axios from "redaxios";
|
2024-05-04 09:13:49 +01:00
|
|
|
import { toRaw } from 'vue';
|
|
|
|
|
|
|
|
import 'fork-awesome/css/fork-awesome.css';
|
|
|
|
|
|
|
|
L.Icon.Default.imagePath = "/static/leaflet/images/";
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
var redMarker = ExtraMarkers.icon({
|
2024-05-04 09:13:49 +01:00
|
|
|
icon: "fa-chain-broken",
|
2021-06-14 23:08:07 +01:00
|
|
|
markerColor: "red",
|
|
|
|
shape: "circle",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
|
|
|
var greenMarker = ExtraMarkers.icon({
|
2024-05-04 09:13:49 +01:00
|
|
|
icon: "fa-link",
|
2021-06-20 13:46:33 +01:00
|
|
|
markerColor: "green-light",
|
|
|
|
shape: "circle",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
|
|
|
var greenDarkMarker = ExtraMarkers.icon({
|
2024-05-04 09:13:49 +01:00
|
|
|
icon: "fa-link",
|
2021-06-20 13:46:33 +01:00
|
|
|
markerColor: "green-dark",
|
2021-06-14 23:08:07 +01:00
|
|
|
shape: "circle",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
|
|
|
var blueMarker = ExtraMarkers.icon({
|
|
|
|
icon: "fa-wikidata",
|
|
|
|
markerColor: "blue",
|
|
|
|
shape: "circle",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
|
|
|
var osmYellowMarker = ExtraMarkers.icon({
|
|
|
|
icon: "fa-map",
|
|
|
|
markerColor: "yellow",
|
|
|
|
shape: "square",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
2021-06-20 13:44:35 +01:00
|
|
|
var osmOrangeMarker = ExtraMarkers.icon({
|
|
|
|
icon: "fa-map",
|
|
|
|
markerColor: "orange",
|
|
|
|
shape: "square",
|
|
|
|
prefix: "fa",
|
|
|
|
});
|
|
|
|
|
2021-07-16 10:48:44 +01:00
|
|
|
function beforeUnloadListener(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
return event.returnValue = "";
|
|
|
|
};
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
export default {
|
|
|
|
props: {
|
|
|
|
startLat: Number,
|
|
|
|
startLon: Number,
|
|
|
|
startZoom: Number,
|
2021-07-06 16:24:14 +01:00
|
|
|
startRadius: Number,
|
2023-05-13 14:01:28 +01:00
|
|
|
startItem: String,
|
|
|
|
startItemTypeFilter: Array,
|
2021-06-17 18:12:07 +01:00
|
|
|
username: String,
|
2021-07-11 16:18:45 +01:00
|
|
|
startMode: String,
|
|
|
|
q: String,
|
2021-07-16 08:59:06 +01:00
|
|
|
defaultComment: String,
|
2021-07-16 10:14:05 +01:00
|
|
|
mockUpload: Boolean,
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2021-10-22 11:55:05 +01:00
|
|
|
api_base_url: "https://map.osm.wikidata.link",
|
2024-05-04 09:13:49 +01:00
|
|
|
// api_base_url: "http://localhost:5000",
|
2021-06-14 23:08:07 +01:00
|
|
|
tag_or_key_list: [],
|
|
|
|
search_text: "",
|
|
|
|
load_button_pressed: false,
|
|
|
|
hits: [],
|
|
|
|
center: undefined,
|
|
|
|
zoom: undefined,
|
|
|
|
isa_ticked: [],
|
|
|
|
isa_list: [],
|
|
|
|
isa_lookup: {},
|
|
|
|
items: {},
|
|
|
|
osm_loaded: false,
|
|
|
|
wikidata_loaded: false,
|
|
|
|
osm_loading: false,
|
|
|
|
wikidata_loading: false,
|
|
|
|
current_item: undefined,
|
|
|
|
current_osm: undefined,
|
|
|
|
hover_qid: undefined,
|
|
|
|
isa_labels: {},
|
|
|
|
linked: true,
|
|
|
|
not_linked: true,
|
|
|
|
map: undefined,
|
|
|
|
hover_circles: [],
|
|
|
|
candidate_outline: undefined,
|
|
|
|
check_for_missing_done: false,
|
|
|
|
selected_circles: [],
|
|
|
|
hover_isa: undefined,
|
2021-06-16 14:41:33 +01:00
|
|
|
detail_qid: undefined,
|
2021-06-18 18:28:56 +01:00
|
|
|
show_tag_or_key_list: undefined,
|
|
|
|
edits: [],
|
|
|
|
view_edits: false,
|
2021-07-16 08:59:06 +01:00
|
|
|
changeset_comment: undefined,
|
2021-06-24 17:40:59 +01:00
|
|
|
changeset_id: undefined,
|
|
|
|
upload_state: undefined,
|
|
|
|
upload_progress: 0,
|
2021-07-06 16:24:14 +01:00
|
|
|
show_tags: false,
|
2021-07-11 16:18:45 +01:00
|
|
|
show_area: true,
|
|
|
|
show_presets: true,
|
2021-07-06 16:24:14 +01:00
|
|
|
flag_show_hover_isa: false,
|
|
|
|
debug: false,
|
|
|
|
map_area: undefined,
|
|
|
|
item_count: undefined,
|
2021-07-11 16:18:45 +01:00
|
|
|
mode: undefined,
|
|
|
|
current_hit: undefined,
|
|
|
|
recent_search: undefined,
|
2021-07-30 15:02:41 +01:00
|
|
|
show_item_type_filter: false,
|
|
|
|
item_type_search: undefined,
|
|
|
|
item_type_hits: [],
|
|
|
|
item_type_filters: [],
|
2021-10-06 18:05:04 +01:00
|
|
|
bounds_before_open: undefined,
|
|
|
|
bounds_done: [],
|
|
|
|
zoom_on_open: false,
|
|
|
|
selected_marker: undefined,
|
2021-10-22 11:40:10 +01:00
|
|
|
debug_info: [],
|
|
|
|
map_update_number: 0,
|
|
|
|
api_call_error_message: undefined,
|
|
|
|
api_call_error_traceback: undefined,
|
2024-05-04 09:13:49 +01:00
|
|
|
tab: "filters",
|
|
|
|
highlight_item: undefined,
|
2021-06-14 23:08:07 +01:00
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
2021-07-11 16:18:45 +01:00
|
|
|
show_instructions() {
|
|
|
|
return (this.mode != "search"
|
2021-07-16 10:47:15 +01:00
|
|
|
&& !this.loading
|
2021-07-11 16:18:45 +01:00
|
|
|
&& !this.isa_list.length
|
|
|
|
&& !this.view_edits
|
|
|
|
&& !this.current_item);
|
|
|
|
},
|
2021-07-06 16:24:14 +01:00
|
|
|
area_too_big() {
|
2021-07-30 15:02:41 +01:00
|
|
|
return !this.item_type_filters.length && this.map_area > 1000 * 1000 * 1000;
|
2021-07-06 16:24:14 +01:00
|
|
|
},
|
|
|
|
too_many_items() {
|
2021-08-05 07:31:07 +01:00
|
|
|
return this.item_count > 600;
|
2021-07-06 16:24:14 +01:00
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
loading() {
|
|
|
|
return this.osm_loading || this.wikidata_loading;
|
|
|
|
},
|
2021-07-11 16:18:45 +01:00
|
|
|
current_qid() {
|
|
|
|
return this.current_item ? this.current_item.wikidata.qid : undefined;
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
wd_item() {
|
|
|
|
return this.current_item ? this.current_item.wikidata : undefined;
|
|
|
|
},
|
|
|
|
tagged_count() {
|
|
|
|
var count = 0;
|
|
|
|
for (const qid in this.items) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
if (item.wikidata && item.osm) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
},
|
|
|
|
not_tagged_count() {
|
|
|
|
var count = 0;
|
|
|
|
for (const qid in this.items) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
if (item.wikidata && !item.osm) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
},
|
2021-06-28 10:51:41 +01:00
|
|
|
item_is_selceted(item) {
|
2021-10-22 11:43:27 +01:00
|
|
|
return item.wikidata.isa_list.some(isa => this.isa_ticked.includes(isa.qid));
|
2021-06-28 10:51:41 +01:00
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
selected_items() {
|
|
|
|
var ret = {};
|
|
|
|
for (const qid in this.items) {
|
2021-06-28 10:51:41 +01:00
|
|
|
if (!this.items[qid]) continue;
|
2021-06-14 23:08:07 +01:00
|
|
|
var item = this.items[qid];
|
|
|
|
if (!item.wikidata) continue;
|
|
|
|
|
|
|
|
if (!this.linked && item.osm) continue;
|
|
|
|
if (!this.not_linked && !item.osm) continue;
|
|
|
|
|
2021-10-22 11:43:27 +01:00
|
|
|
if (item.wikidata.isa_list.some(isa => this.isa_ticked.includes(isa.qid))) {
|
2021-06-14 23:08:07 +01:00
|
|
|
ret[qid] = item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2021-06-18 18:28:56 +01:00
|
|
|
},
|
|
|
|
edits_grouped_by_qid() {
|
|
|
|
var qid_order = [];
|
|
|
|
var edit_lookup = {};
|
|
|
|
|
|
|
|
this.edits.forEach((edit) => {
|
|
|
|
var qid = edit.item.qid;
|
|
|
|
|
|
|
|
if (!edit_lookup[qid]) {
|
|
|
|
qid_order.push(qid);
|
|
|
|
edit_lookup[qid] = {
|
|
|
|
'qid': qid,
|
|
|
|
'wikidata': edit.item.wikidata,
|
|
|
|
'osm': [],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
edit_lookup[qid].osm.push(edit.osm);
|
|
|
|
});
|
|
|
|
|
|
|
|
return qid_order.map((qid) => edit_lookup[qid]);
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
watch: {
|
2021-07-16 10:48:44 +01:00
|
|
|
edits(edit_list) {
|
|
|
|
this.update_unload_warning(edit_list);
|
|
|
|
},
|
2021-07-30 15:02:41 +01:00
|
|
|
item_type_search(value) {
|
|
|
|
if (value.length < 3) {
|
|
|
|
this.item_type_hits = [];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var params = { q: value };
|
2021-10-22 11:43:27 +01:00
|
|
|
this.api_call("isa_search", { params: params }).then((response) => {
|
2021-07-30 15:02:41 +01:00
|
|
|
this.item_type_hits = response.data.items;
|
|
|
|
});
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
selected_items(new_items, old_items) {
|
|
|
|
for (const qid of Object.keys(new_items)) {
|
|
|
|
if (!old_items[qid])
|
2021-06-28 10:51:41 +01:00
|
|
|
new_items[qid].group.addTo(this.map);
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const qid of Object.keys(old_items)) {
|
|
|
|
if (!new_items[qid])
|
2021-06-28 10:51:41 +01:00
|
|
|
old_items[qid].group.removeFrom(this.map);
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
current_osm(osm) {
|
|
|
|
if (this.candidate_outline !== undefined) {
|
|
|
|
this.candidate_outline.removeFrom(this.map);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (osm === undefined) return;
|
|
|
|
|
|
|
|
var mapStyle = { fillOpacity: 0, color: "red" };
|
|
|
|
var geojson = L.geoJSON(null, { style: mapStyle });
|
|
|
|
geojson.addData(osm.geojson);
|
|
|
|
geojson.addTo(this.map);
|
|
|
|
|
|
|
|
this.candidate_outline = geojson;
|
|
|
|
},
|
|
|
|
current_item(item, old_item) {
|
|
|
|
if (old_item) {
|
|
|
|
this.selected_circles.forEach((circle) => {
|
|
|
|
circle.removeFrom(this.map);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.selected_circles = [];
|
|
|
|
|
|
|
|
if (!item) return;
|
|
|
|
|
|
|
|
item.markers.forEach((marker) => {
|
|
|
|
var coords = marker.getLatLng();
|
2021-07-06 16:24:14 +01:00
|
|
|
var circle = L.circleMarker(coords, { radius: 20, color: "orange" }).addTo(this.map);
|
2021-06-14 23:08:07 +01:00
|
|
|
this.selected_circles.push(circle);
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
hover_isa(highlight_isa) {
|
2021-07-06 16:24:14 +01:00
|
|
|
// if (!this.flag_show_hover_isa) return;
|
2021-06-14 23:08:07 +01:00
|
|
|
this.drop_hover_circles();
|
|
|
|
|
|
|
|
for(const item of Object.values(this.selected_items)) {
|
2021-07-06 16:24:14 +01:00
|
|
|
// var opacity = 0.9;
|
2021-06-14 23:08:07 +01:00
|
|
|
if (highlight_isa) {
|
2021-10-22 11:43:27 +01:00
|
|
|
var match = item.wikidata.isa_list.some(isa => isa.qid == highlight_isa.qid);
|
2021-07-06 16:24:14 +01:00
|
|
|
// opacity = match ? 1 : 0.2;
|
2021-06-14 23:08:07 +01:00
|
|
|
if (match) {
|
|
|
|
this.add_hover_circles(item);
|
|
|
|
}
|
|
|
|
}
|
2021-07-06 16:24:14 +01:00
|
|
|
// this.set_item_opacity(item, opacity);
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2024-05-03 19:52:54 +01:00
|
|
|
isDisused(tags) {
|
|
|
|
return Object.keys(tags).some(key => key.startsWith('disused:'));
|
|
|
|
},
|
2023-05-13 14:01:28 +01:00
|
|
|
wikipedia_link(lang, title) {
|
|
|
|
var norm_title = title.replaceAll(" ", "_");
|
|
|
|
return `https://${lang}.wikipedia.org/wiki/${norm_title}`;
|
|
|
|
},
|
|
|
|
marker_osm_url(marker) {
|
|
|
|
var lat = marker[0].toFixed(5);
|
|
|
|
var lon = marker[1].toFixed(5);
|
|
|
|
return `https://www.openstreetmap.org/?mlat=${lat}&mlon=${lon}#map=18/${lat}/${lon}`
|
|
|
|
},
|
|
|
|
add_item_type_filter(isa) {
|
|
|
|
if (this.item_type_filters.includes(isa)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.item_type_filters.push(isa);
|
|
|
|
this.update_map_path();
|
|
|
|
},
|
|
|
|
api_call(endpoint, options) {
|
2021-10-22 11:40:10 +01:00
|
|
|
var url = `${this.api_base_url}/api/1/${endpoint}`;
|
2023-05-13 14:01:28 +01:00
|
|
|
return axios.get(url, options).catch(this.show_api_error_modal);
|
|
|
|
},
|
2021-07-16 10:48:44 +01:00
|
|
|
update_unload_warning(edit_list) {
|
|
|
|
if (edit_list.length) {
|
|
|
|
addEventListener("beforeunload", beforeUnloadListener, {capture: true});
|
|
|
|
} else {
|
|
|
|
removeEventListener("beforeunload", beforeUnloadListener, {capture: true});
|
|
|
|
}
|
|
|
|
},
|
2021-07-11 16:18:45 +01:00
|
|
|
format_area(area) {
|
|
|
|
var value, unit, dp;
|
|
|
|
if(area > 1000 * 1000) {
|
|
|
|
value = area / (1000 * 1000);
|
|
|
|
unit = "km²";
|
|
|
|
dp = 1;
|
|
|
|
} else {
|
|
|
|
value = area;
|
|
|
|
unit = "m²";
|
|
|
|
dp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value.toLocaleString("en-US", {maximumFractionDigits: dp}) + " " + unit
|
|
|
|
},
|
2021-07-06 16:24:14 +01:00
|
|
|
bounds_area(bounds) {
|
|
|
|
var width = bounds.getSouthWest().distanceTo(bounds.getSouthEast());
|
|
|
|
var height = bounds.getSouthWest().distanceTo(bounds.getNorthWest());
|
|
|
|
|
|
|
|
return width * height;
|
|
|
|
},
|
|
|
|
bounds_param() {
|
|
|
|
return 'bounds=' + this.map.getBounds().toBBoxString();
|
|
|
|
},
|
2021-10-22 11:40:10 +01:00
|
|
|
show_api_error_modal(error) {
|
|
|
|
var reply = error.data;
|
|
|
|
this.api_call_error_message = reply.error;
|
|
|
|
this.api_call_error_traceback = reply.traceback;
|
2024-05-04 09:13:49 +01:00
|
|
|
var error_modal = new Modal(this.$refs.error_modal);
|
2021-10-22 11:40:10 +01:00
|
|
|
|
|
|
|
this.$refs.error_modal.addEventListener('hidden.bs.modal', function (event) {
|
|
|
|
this.api_call_error_message = undefined;
|
|
|
|
this.api_call_error_traceback = undefined;
|
|
|
|
})
|
|
|
|
|
|
|
|
error_modal.show();
|
|
|
|
},
|
|
|
|
test_api_error() {
|
|
|
|
this.api_call("error");
|
|
|
|
},
|
2021-06-24 17:40:59 +01:00
|
|
|
close_edit_list() {
|
|
|
|
this.view_edits = false;
|
2021-07-16 10:59:07 +01:00
|
|
|
if (this.upload_state != 'done') return;
|
|
|
|
|
|
|
|
this.edits.forEach(edit => {
|
|
|
|
var item = edit.item;
|
|
|
|
var identifier = edit.osm.identifier;
|
|
|
|
edit.outline.removeFrom(this.map);
|
|
|
|
if (edit.osm.selected) {
|
|
|
|
if (item.osm) {
|
|
|
|
if (item.osm[identifier]) return;
|
|
|
|
} else {
|
|
|
|
item.osm = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var keys = ['identifier', 'id', 'type', 'geojson', 'centroid', 'name'];
|
|
|
|
var osm = Object.fromEntries(keys.map(key => [key, edit.osm[key]]));
|
|
|
|
osm['wikidata'] = item.qid;
|
|
|
|
item.osm[identifier] = osm;
|
|
|
|
this.add_osm_to_map(item, osm);
|
2021-07-19 21:11:01 +01:00
|
|
|
|
|
|
|
item.lines ||= [];
|
|
|
|
item.wikidata.markers.forEach((marker_data) => {
|
|
|
|
var path = [osm.centroid, marker_data];
|
|
|
|
var polyline = L.polyline(path, { color: "green" });
|
|
|
|
polyline.addTo(item.group);
|
|
|
|
item.lines.push(polyline);
|
|
|
|
});
|
2021-07-16 10:59:07 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
var updated_items = new Set(this.edits.map(edit => edit.item));
|
|
|
|
this.edits = [];
|
|
|
|
this.upload_progress = 0;
|
|
|
|
this.upload_state = undefined;
|
|
|
|
|
|
|
|
updated_items.forEach(item => {
|
|
|
|
var marker = this.getMarker(item);
|
|
|
|
|
|
|
|
item.wikidata.markers.forEach((marker_data) => {
|
|
|
|
marker_data.marker.setIcon(marker);
|
|
|
|
});
|
|
|
|
});
|
2021-06-24 17:40:59 +01:00
|
|
|
},
|
|
|
|
upload() {
|
|
|
|
console.log('upload triggered');
|
|
|
|
this.upload_state = "init";
|
|
|
|
var edit_list = [];
|
|
|
|
this.edits.forEach((edit) => {
|
2021-10-22 11:50:25 +01:00
|
|
|
var qid = edit.item.qid;
|
|
|
|
var osm = edit.osm;
|
2021-06-24 17:40:59 +01:00
|
|
|
var e = {
|
2021-10-22 11:50:25 +01:00
|
|
|
'qid': qid,
|
|
|
|
'osm': osm.identifier,
|
2021-06-24 17:40:59 +01:00
|
|
|
};
|
2021-10-22 11:50:25 +01:00
|
|
|
if (osm.selected) {
|
|
|
|
if (osm.tags.wikidata !== undefined && osm.tags.wikidata != qid) {
|
|
|
|
e['op'] = 'change';
|
|
|
|
} else {
|
|
|
|
e['op'] = 'add';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
e['op'] = 'remove';
|
|
|
|
}
|
2021-06-24 17:40:59 +01:00
|
|
|
edit_list.push(e);
|
|
|
|
});
|
|
|
|
var post_json = {
|
|
|
|
'comment': this.changeset_comment,
|
|
|
|
'edit_list': edit_list,
|
|
|
|
}
|
|
|
|
console.log('post new session');
|
|
|
|
var edit_session_url = `${this.api_base_url}/api/1/edit`;
|
|
|
|
axios.post(edit_session_url, post_json).then((response) => {
|
|
|
|
var session_id = response.data.session_id;
|
|
|
|
var save_url = `${this.api_base_url}/api/1/save/${session_id}`;
|
|
|
|
console.log('new event source');
|
|
|
|
const es = new EventSource(save_url);
|
|
|
|
es.onerror = function(event) {
|
|
|
|
console.log('event source:', es);
|
|
|
|
console.log('ready state:', es.readyState);
|
|
|
|
}
|
|
|
|
var app = this;
|
|
|
|
es.onmessage = function(event) {
|
|
|
|
const data = JSON.parse(event.data);
|
|
|
|
switch(data.type) {
|
|
|
|
case "auth-fail":
|
|
|
|
app.upload_state = "auth-fail";
|
|
|
|
console.log("auth-fail");
|
|
|
|
es.close();
|
|
|
|
break;
|
|
|
|
case "changeset-error":
|
|
|
|
app.upload_state = "changeset-error";
|
|
|
|
app.upload_error = data.error;
|
|
|
|
console.log("changeset-error", data.error);
|
|
|
|
es.close();
|
|
|
|
break;
|
|
|
|
case "open":
|
|
|
|
app.upload_state = "uploading";
|
|
|
|
app.changeset_id = data.id;
|
|
|
|
break;
|
|
|
|
case "progress":
|
|
|
|
var edit = app.edits[data.num];
|
2021-07-11 16:18:45 +01:00
|
|
|
app.upload_progress = ((data.num + 1) * 100) / app.edits.length;
|
2021-06-24 17:40:59 +01:00
|
|
|
edit.osm.upload_state = "progress";
|
|
|
|
break;
|
|
|
|
case "saved":
|
|
|
|
var edit = app.edits[data.num];
|
|
|
|
edit.osm.upload_state = "saved";
|
|
|
|
break;
|
|
|
|
case "closing":
|
|
|
|
app.upload_state = "closing";
|
|
|
|
break;
|
|
|
|
case "done":
|
|
|
|
app.upload_state = "done";
|
2021-07-16 10:48:44 +01:00
|
|
|
removeEventListener("beforeunload", beforeUnloadListener, {capture: true});
|
2021-06-24 17:40:59 +01:00
|
|
|
es.close();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
console.log('upload state:', app.upload_state);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2021-06-18 18:28:56 +01:00
|
|
|
edit_list_index(item, osm) {
|
|
|
|
var index = -1;
|
|
|
|
for (var i = 0; i < this.edits.length; i++) {
|
|
|
|
var edit = this.edits[i];
|
|
|
|
if (edit.item.qid == item.qid &&
|
|
|
|
edit.osm.identifier == osm.identifier) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
},
|
|
|
|
select_osm(item, osm) {
|
2021-07-11 16:18:45 +01:00
|
|
|
if (!this.username) return;
|
2021-06-18 18:28:56 +01:00
|
|
|
osm.selected = !osm.selected;
|
|
|
|
var index = this.edit_list_index(item, osm);
|
|
|
|
|
|
|
|
if (index == -1) {
|
2021-06-20 13:46:33 +01:00
|
|
|
var mapStyle = { fillOpacity: 0, color: "darkturquoise" };
|
|
|
|
var geojson = L.geoJSON(null, { style: mapStyle });
|
|
|
|
geojson.addData(osm.geojson);
|
|
|
|
geojson.addTo(this.map);
|
|
|
|
|
|
|
|
this.edits.push({'item': item, 'osm': osm, 'outline': geojson});
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
} else {
|
2021-06-20 13:46:33 +01:00
|
|
|
var edit = this.edits[index];
|
|
|
|
edit.outline.removeFrom(this.map);
|
2021-06-18 18:28:56 +01:00
|
|
|
this.edits.splice(index, 1);
|
|
|
|
}
|
2021-06-20 13:46:33 +01:00
|
|
|
|
2021-07-16 10:48:44 +01:00
|
|
|
this.update_unload_warning(this.edits);
|
|
|
|
|
2021-06-20 13:46:33 +01:00
|
|
|
var marker = this.getMarker(item);
|
|
|
|
|
|
|
|
item.wikidata.markers.forEach((marker_data) => {
|
|
|
|
marker_data.marker.setIcon(marker);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
},
|
2021-06-16 14:41:33 +01:00
|
|
|
qid_from_url() {
|
|
|
|
const queryString = window.location.search;
|
|
|
|
const urlParams = new URLSearchParams(queryString);
|
|
|
|
return urlParams.get("item") || undefined;
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
isa_tick_all() {
|
|
|
|
this.isa_ticked = Object.keys(this.isa_labels);
|
|
|
|
},
|
|
|
|
build_map_path() {
|
2023-05-13 14:01:28 +01:00
|
|
|
if (this.current_item) {
|
|
|
|
return `/item/${this.current_qid}`;
|
|
|
|
}
|
2021-06-14 23:08:07 +01:00
|
|
|
var zoom = this.map.getZoom();
|
|
|
|
var c = this.map.getCenter();
|
|
|
|
var lat = c.lat.toFixed(5);
|
|
|
|
var lng = c.lng.toFixed(5);
|
|
|
|
var path = `/map/${zoom}/${lat}/${lng}`;
|
2023-05-13 14:01:28 +01:00
|
|
|
|
|
|
|
if (this.item_type_filters.length) {
|
|
|
|
path += "?isa=" + this.item_type_filters.map((t) => t.qid).join(";");
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
2023-05-13 14:01:28 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
return path;
|
|
|
|
},
|
|
|
|
|
|
|
|
mouse_events(marker, qid) {
|
|
|
|
marker.on("mouseover", () => { this.add_highlight(qid); });
|
|
|
|
marker.on("mouseout", () => { this.drop_highlight(qid); });
|
2021-10-06 18:05:04 +01:00
|
|
|
marker.on("click", () => { this.open_item(qid, marker); });
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
var item = this.items[qid];
|
|
|
|
|
|
|
|
item.markers ||= [];
|
|
|
|
item.markers.push(marker);
|
|
|
|
},
|
|
|
|
|
|
|
|
set_item_opacity(item, opacity) {
|
|
|
|
if (item.outline) {
|
|
|
|
item.outline.setStyle({ opacity: opacity });
|
|
|
|
}
|
|
|
|
if (item.lines) {
|
|
|
|
item.lines.forEach((line) => {
|
|
|
|
line.setStyle({ opacity: opacity });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
item.markers.forEach((marker) => {
|
|
|
|
marker.setOpacity(opacity);
|
|
|
|
})
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
add_hover_circles(item) {
|
|
|
|
item.markers.forEach((marker) => {
|
|
|
|
var coords = marker.getLatLng();
|
2021-07-06 16:24:14 +01:00
|
|
|
var circle = L.circleMarker(coords, { radius: 20 }).addTo(this.map);
|
2021-06-14 23:08:07 +01:00
|
|
|
this.hover_circles.push(circle);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
drop_hover_circles() {
|
|
|
|
this.hover_circles.forEach((circle) => {
|
|
|
|
circle.removeFrom(this.map);
|
|
|
|
});
|
|
|
|
this.hover_circles = [];
|
|
|
|
},
|
|
|
|
add_highlight(qid) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
|
|
|
|
if (item.outline) {
|
|
|
|
item.outline.setStyle({ fillOpacity: 0.2, weight: 6 });
|
|
|
|
}
|
|
|
|
if (item.lines) {
|
|
|
|
item.lines.forEach((line) => {
|
|
|
|
line.setStyle({ weight: 6 });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
this.add_hover_circles(item);
|
2024-05-04 09:13:49 +01:00
|
|
|
this.highlight_item = item;
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
drop_highlight(qid) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
|
|
|
|
if (item.outline) {
|
|
|
|
item.outline.setStyle({ fillOpacity: 0, weight: 3 });
|
|
|
|
}
|
|
|
|
if (item.lines) {
|
|
|
|
item.lines.forEach((line) => {
|
|
|
|
line.setStyle({ weight: 3 });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
this.drop_hover_circles();
|
2024-05-04 09:13:49 +01:00
|
|
|
this.highlight_item = undefined;
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
2021-06-28 10:51:41 +01:00
|
|
|
map_moved() {
|
2021-07-11 16:18:45 +01:00
|
|
|
if (this.mode == "search") return;
|
2021-06-28 10:51:41 +01:00
|
|
|
this.auto_load();
|
|
|
|
this.update_map_path();
|
|
|
|
},
|
2021-07-11 16:18:45 +01:00
|
|
|
current_state() {
|
|
|
|
var c = this.map.getCenter();
|
|
|
|
return {
|
|
|
|
mode: this.mode,
|
|
|
|
zoom: this.map.getZoom(),
|
|
|
|
lat: c.lat.toFixed(5),
|
|
|
|
lon: c.lng.toFixed(5),
|
|
|
|
search_text: this.search_text,
|
|
|
|
detail_qid: this.current_qid,
|
|
|
|
item_count: this.item_count,
|
|
|
|
map_area: this.map_area,
|
|
|
|
hits: toRaw(this.hits),
|
|
|
|
current_hit: toRaw(this.current_hit),
|
|
|
|
current_osm: toRaw(this.current_osm),
|
|
|
|
recent_search: this.recent_search,
|
|
|
|
};
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
update_map_path() {
|
2021-07-11 16:18:45 +01:00
|
|
|
var state = this.current_state();
|
2024-05-04 09:13:49 +01:00
|
|
|
// history.replaceState(state, '', this.build_map_path());
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
2021-10-06 18:05:04 +01:00
|
|
|
open_item(qid, marker) {
|
2021-07-21 20:30:21 +01:00
|
|
|
this.close_edit_list();
|
2021-07-19 21:11:01 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
var item = this.items[qid];
|
2021-11-13 20:21:16 +00:00
|
|
|
if (item === undefined) {
|
|
|
|
this.close_item();
|
|
|
|
return;
|
|
|
|
}
|
2021-10-06 18:05:04 +01:00
|
|
|
if (marker) {
|
|
|
|
this.selected_marker = marker;
|
|
|
|
} else {
|
|
|
|
marker = item.markers[0].marker;
|
|
|
|
this.selected_marker = undefined;
|
|
|
|
}
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
if (this.current_item == item) return; // already open
|
2021-06-14 23:08:07 +01:00
|
|
|
this.current_osm = undefined;
|
|
|
|
this.current_item = item;
|
2021-07-11 16:18:45 +01:00
|
|
|
|
|
|
|
var state = this.current_state();
|
|
|
|
history.pushState(state, '', this.build_map_path());
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
this.hover_isa = undefined;
|
2021-06-14 23:08:07 +01:00
|
|
|
|
|
|
|
if (item.detail_requested !== undefined) return;
|
|
|
|
item.detail_requested = true;
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
this.api_call(`item/${qid}/tags`).then((response) => {
|
2021-06-14 23:08:07 +01:00
|
|
|
var qid = response.data.qid;
|
|
|
|
this.items[qid].tag_or_key_list = response.data.tag_or_key_list;
|
2021-10-22 11:40:10 +01:00
|
|
|
this.items[qid].tag_src = response.data.tag_src;
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
this.api_call(`item/${qid}/candidates`).then((response) => {
|
2021-06-14 23:08:07 +01:00
|
|
|
var qid = response.data.qid;
|
2021-06-18 18:28:56 +01:00
|
|
|
var item = this.items[qid];
|
2021-07-16 10:58:37 +01:00
|
|
|
var osm_identifiers = item.osm ? Object.keys(item.osm) : [];
|
2021-06-18 18:28:56 +01:00
|
|
|
|
|
|
|
item.nearby = response.data.nearby;
|
|
|
|
item.nearby.forEach((osm) => {
|
|
|
|
osm.selected = osm_identifiers.includes(osm.identifier);
|
|
|
|
if (this.edits.length && this.edit_list_index(item, osm) != -1) {
|
|
|
|
osm.selected = !osm.selected;
|
|
|
|
}
|
|
|
|
});
|
2021-10-06 18:05:04 +01:00
|
|
|
|
|
|
|
if (response.data.nearby.length) {
|
|
|
|
if (this.zoom_on_open) {
|
|
|
|
if (!this.bounds_before_open) {
|
|
|
|
this.bounds_before_open = this.map.getBounds();
|
|
|
|
}
|
|
|
|
this.map.flyTo(marker.getLatLng(), 18);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
},
|
2021-10-06 18:05:04 +01:00
|
|
|
zoom_to_selected_marker() {
|
|
|
|
var marker = this.selected_marker || this.current_item.markers[0];
|
|
|
|
if (!this.bounds_before_open) {
|
|
|
|
this.bounds_before_open = this.map.getBounds();
|
|
|
|
}
|
|
|
|
this.map.flyTo(marker.getLatLng(), 18);
|
|
|
|
},
|
2021-06-20 13:46:33 +01:00
|
|
|
item_has_edit(item) {
|
|
|
|
if (this.edits.length == 0) return false;
|
|
|
|
return this.edits.some((edit) => edit.item.qid == item.qid);
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
close_item() {
|
|
|
|
this.current_osm = undefined;
|
|
|
|
this.current_item = undefined;
|
2021-10-06 18:05:04 +01:00
|
|
|
this.selected_marker = undefined;
|
2021-06-14 23:08:07 +01:00
|
|
|
this.update_map_path();
|
2021-10-06 18:05:04 +01:00
|
|
|
if (this.bounds_before_open) {
|
|
|
|
this.map.flyToBounds(this.bounds_before_open);
|
|
|
|
this.bounds_before_open = undefined;
|
|
|
|
}
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
qid_url(qid) {
|
|
|
|
return "https://www.wikidata.org/wiki/" + qid;
|
|
|
|
},
|
|
|
|
getMarker(item) {
|
|
|
|
if (!this.osm_loaded) return blueMarker;
|
2021-06-20 13:46:33 +01:00
|
|
|
if (this.item_has_edit(item)) {
|
|
|
|
return greenDarkMarker;
|
|
|
|
} else {
|
|
|
|
return item.osm ? greenMarker : redMarker;
|
|
|
|
}
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
hit_url(hit) {
|
|
|
|
var lat = parseFloat(hit.lat).toFixed(5);
|
|
|
|
var lon = parseFloat(hit.lon).toFixed(5);
|
|
|
|
return `/map/16/${lat}/${lon}`
|
|
|
|
},
|
2021-07-11 16:18:45 +01:00
|
|
|
fit_bounds_to_hit(hit) {
|
|
|
|
var bounds = [[hit.boundingbox[0], hit.boundingbox[2]],
|
|
|
|
[hit.boundingbox[1], hit.boundingbox[3]]];
|
|
|
|
this.map.fitBounds(bounds);
|
|
|
|
},
|
|
|
|
show_hit_on_map(hit) {
|
|
|
|
this.fit_bounds_to_hit(hit);
|
|
|
|
this.current_hit = hit;
|
|
|
|
this.update_search_state();
|
|
|
|
},
|
|
|
|
select_area() {
|
|
|
|
this.current_hit = undefined;
|
|
|
|
this.mode = "map";
|
|
|
|
this.hits = [];
|
|
|
|
this.search_text = "";
|
|
|
|
this.auto_load();
|
|
|
|
|
|
|
|
var state = this.current_state();
|
|
|
|
history.pushState(state, '', this.build_map_path());
|
|
|
|
},
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
visit(hit) {
|
2021-07-11 16:18:45 +01:00
|
|
|
this.current_hit = undefined;
|
|
|
|
this.hits = [];
|
|
|
|
this.recent_search = undefined;
|
|
|
|
this.search_text = "";
|
|
|
|
this.fit_bounds_to_hit(hit);
|
|
|
|
this.mode = "map";
|
|
|
|
|
|
|
|
var state = this.current_state();
|
|
|
|
history.pushState(state, '', this.build_map_path());
|
2021-06-14 23:08:07 +01:00
|
|
|
|
2021-06-17 18:14:42 +01:00
|
|
|
this.auto_load();
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
process_wikidata_items(load_items) {
|
|
|
|
load_items.forEach(item => {
|
|
|
|
var qid = item.qid;
|
2021-06-18 18:28:56 +01:00
|
|
|
this.items[qid] ||= {'qid': qid};
|
2021-06-14 23:08:07 +01:00
|
|
|
if (this.items[qid].wikidata) return;
|
|
|
|
this.items[qid].wikidata = item;
|
|
|
|
var group = this.items[qid].group ||= L.featureGroup();
|
|
|
|
|
|
|
|
var icon = blueMarker;
|
|
|
|
var label = `${item.label} (${item.qid})`;
|
|
|
|
item.markers.forEach((marker_data) => {
|
|
|
|
var marker = L.marker(marker_data, { opacity: 0.9, icon: icon });
|
|
|
|
marker.addTo(group);
|
|
|
|
this.mouse_events(marker, qid);
|
|
|
|
marker_data.marker = marker;
|
|
|
|
});
|
|
|
|
// group.addTo(this.map);
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2021-06-28 10:51:41 +01:00
|
|
|
clear_isa() {
|
|
|
|
this.isa_list = [];
|
|
|
|
// this.isa_ticked = [];
|
|
|
|
this.isa_labels = {};
|
|
|
|
this.isa_lookup = {};
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
|
2021-06-28 10:51:41 +01:00
|
|
|
clear_items() {
|
2021-06-14 23:08:07 +01:00
|
|
|
for (const qid of Object.keys(this.items)) {
|
|
|
|
this.items[qid].group.removeFrom(this.map);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.items = {};
|
2021-07-06 16:24:14 +01:00
|
|
|
this.clear_isa();
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
2021-07-16 10:58:37 +01:00
|
|
|
add_osm_to_map(item, osm) {
|
|
|
|
var group = item.group ||= L.featureGroup();
|
|
|
|
var icon = osmYellowMarker;
|
|
|
|
var marker = L.marker(osm.centroid, { opacity: 0.9, title: osm.name, icon: icon });
|
|
|
|
osm.marker = marker;
|
|
|
|
marker.addTo(group);
|
|
|
|
this.mouse_events(marker, item.qid);
|
|
|
|
|
|
|
|
if (osm.type != "node" && osm.geojson) {
|
|
|
|
var mapStyle = { fillOpacity: 0 };
|
|
|
|
var geojson = L.geoJSON(null, { style: mapStyle });
|
|
|
|
geojson.addData(osm.geojson);
|
|
|
|
geojson.addTo(group);
|
|
|
|
item.outline = geojson;
|
|
|
|
}
|
|
|
|
},
|
2021-07-06 16:24:14 +01:00
|
|
|
load_wikidata_items(bounds) {
|
2021-10-22 12:06:10 +01:00
|
|
|
bounds ||= this.map.getBounds();
|
|
|
|
var this_update = this.map_update_number += 1;
|
|
|
|
|
|
|
|
for(const b of this.bounds_done) {
|
|
|
|
if (b.contains(bounds)) return; // already done
|
|
|
|
}
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
this.load_button_pressed = true;
|
|
|
|
this.wikidata_loaded = false;
|
|
|
|
this.osm_loaded = false;
|
|
|
|
this.check_for_missing_done = false;
|
|
|
|
|
|
|
|
this.wikidata_loading = true;
|
|
|
|
this.osm_loading = true;
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
var params = { bounds: this.bbox_string(bounds) };
|
2021-06-14 23:08:07 +01:00
|
|
|
|
2021-07-30 15:02:41 +01:00
|
|
|
if (this.item_type_filters.length) {
|
|
|
|
params["isa"] = this.item_type_filters.map(isa => isa.qid).join(",");
|
|
|
|
}
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push(`${this_update}: get items ` + this.bbox_string(bounds));
|
|
|
|
this.api_call("items", { params: params }).then((response) => {
|
|
|
|
if (this.map_update_number > this_update) {
|
|
|
|
this.debug_info.push(`${this_update}: got items, took ${response.data.duration.toFixed(4)} seconds. ignoring, ${this.map_update_number} is newer`)
|
|
|
|
return;
|
|
|
|
}
|
2021-06-28 10:51:41 +01:00
|
|
|
this.clear_isa();
|
2021-06-14 23:08:07 +01:00
|
|
|
this.isa_list = response.data.isa_count;
|
|
|
|
this.isa_list.forEach(isa => {
|
2021-08-05 07:32:06 +01:00
|
|
|
this.isa_ticked.push(isa.qid);
|
|
|
|
/* if (this.detail_qid || this.item_type_filters.length) {
|
2021-07-30 15:02:41 +01:00
|
|
|
this.isa_ticked.push(isa.qid);
|
2021-08-05 07:32:06 +01:00
|
|
|
} */
|
2021-06-14 23:08:07 +01:00
|
|
|
this.isa_labels[isa.qid] = isa.label;
|
|
|
|
this.isa_lookup[isa.qid] = isa;
|
|
|
|
});
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push(`${this_update} got items, took ${response.data.duration.toFixed(4)} seconds`)
|
2021-06-14 23:08:07 +01:00
|
|
|
this.process_wikidata_items(response.data.items);
|
|
|
|
this.wikidata_loaded = true;
|
|
|
|
|
|
|
|
this.check_for_missing();
|
2021-06-18 18:28:56 +01:00
|
|
|
this.hits = [];
|
2021-10-22 11:40:10 +01:00
|
|
|
|
|
|
|
this.wikidata_loading = false;
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push(`${this_update}: get OSM objects ` + this.bbox_string(bounds));
|
|
|
|
this.api_call("osm", { params: params }).then((response) => {
|
|
|
|
var osm_count = response.data.objects.length;
|
|
|
|
|
|
|
|
if (this.map_update_number > this_update) {
|
|
|
|
this.debug_info.push(`${this_update}: got OSM: ${osm_count} objects. took ${response.data.duration.toFixed(4)} seconds, ignoring, ${this.map_update_number} is newer`)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.debug_info.push(`${this_update}: got OSM: ${osm_count} objects. took ${response.data.duration.toFixed(4)} seconds`)
|
2021-06-14 23:08:07 +01:00
|
|
|
response.data.objects.forEach((osm) => {
|
|
|
|
var qid = osm.wikidata;
|
2021-07-16 10:58:37 +01:00
|
|
|
var item = this.items[qid] ||= {'qid': qid};
|
|
|
|
if (item.osm) {
|
|
|
|
if (item.osm[osm.identifier]) return;
|
|
|
|
} else {
|
|
|
|
item.osm = {};
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
2021-07-16 10:58:37 +01:00
|
|
|
item.osm[osm.identifier] = osm;
|
|
|
|
this.add_osm_to_map(item, osm);
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
this.osm_loaded = true;
|
|
|
|
|
|
|
|
this.check_for_missing();
|
2021-06-17 18:14:42 +01:00
|
|
|
this.hits = [];
|
2021-10-22 11:40:10 +01:00
|
|
|
|
|
|
|
this.osm_loading = false;
|
2021-06-17 18:14:42 +01:00
|
|
|
});
|
|
|
|
},
|
2021-10-22 11:40:10 +01:00
|
|
|
bbox_string(bounds) {
|
|
|
|
const dp = 4;
|
|
|
|
return [bounds.getWest().toFixed(dp),
|
|
|
|
bounds.getSouth().toFixed(dp),
|
|
|
|
bounds.getEast().toFixed(dp),
|
|
|
|
bounds.getNorth().toFixed(dp)].join(',');
|
|
|
|
},
|
2021-07-06 16:24:14 +01:00
|
|
|
auto_load(bounds) {
|
|
|
|
bounds ||= this.map.getBounds();
|
|
|
|
this.map_area = this.bounds_area(bounds);
|
|
|
|
if (this.area_too_big) {
|
|
|
|
this.item_count = undefined;
|
|
|
|
if (this.items) this.clear_items();
|
|
|
|
return;
|
|
|
|
}
|
2021-10-22 11:40:10 +01:00
|
|
|
var params = { bounds: this.bbox_string(bounds) };
|
2021-07-30 15:02:41 +01:00
|
|
|
|
|
|
|
if (this.item_type_filters.length) {
|
|
|
|
params["isa"] = this.item_type_filters.map(isa => isa.qid).join(",");
|
|
|
|
console.log(params.isa);
|
|
|
|
}
|
|
|
|
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push("count " + this.bbox_string(bounds));
|
|
|
|
this.api_call("count", { params: params }).then((response) => {
|
2021-07-06 16:24:14 +01:00
|
|
|
this.item_count = response.data.count;
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push(`item count: ${this.item_count}, took ${response.data.duration.toFixed(4)} seconds`)
|
2021-07-06 16:24:14 +01:00
|
|
|
if (!this.too_many_items) this.load_wikidata_items(bounds);
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
},
|
2021-07-11 16:18:45 +01:00
|
|
|
update_search_state() {
|
|
|
|
history.replaceState(this.current_state(), '', "/search?q=" + this.search_text);
|
|
|
|
},
|
|
|
|
search_path() {
|
|
|
|
return "/search?q=" + this.search_text;
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
run_search() {
|
|
|
|
if (!this.search_text) return;
|
2021-07-11 16:18:45 +01:00
|
|
|
this.current_hit = undefined;
|
2021-06-14 23:08:07 +01:00
|
|
|
var params = { q: this.search_text };
|
2021-10-22 11:40:10 +01:00
|
|
|
this.api_call("search", { params: params }).then((response) => {
|
2021-06-14 23:08:07 +01:00
|
|
|
this.hits = response.data.hits;
|
2021-07-11 16:18:45 +01:00
|
|
|
if (!this.hits.length) return;
|
|
|
|
|
|
|
|
this.recent_search = this.search_text;
|
|
|
|
this.item_count = undefined;
|
|
|
|
this.map_area = undefined;
|
|
|
|
this.clear_items();
|
|
|
|
this.mode = "search";
|
|
|
|
|
|
|
|
this.current_hit = this.hits[0];
|
|
|
|
this.fit_bounds_to_hit(this.current_hit);
|
|
|
|
history.pushState(this.current_state(), '', this.search_path());
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
check_for_missing() {
|
|
|
|
if (this.check_for_missing_done) return;
|
|
|
|
if (!this.osm_loaded || !this.wikidata_loaded) return;
|
|
|
|
|
|
|
|
var missing_qids = [];
|
|
|
|
for (const [qid, item] of Object.entries(this.items)) {
|
|
|
|
if (!item.wikidata) missing_qids.push(qid);
|
|
|
|
}
|
|
|
|
|
2021-10-22 12:06:10 +01:00
|
|
|
this.bounds_done.push(this.map.getBounds());
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
if (missing_qids.length == 0) {
|
|
|
|
this.update_wikidata();
|
2021-06-16 14:41:33 +01:00
|
|
|
this.check_for_missing_done = true;
|
|
|
|
this.start_item();
|
2021-06-14 23:08:07 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var c = this.map.getCenter();
|
|
|
|
var params = {
|
|
|
|
qids: missing_qids.join(","),
|
|
|
|
lat: c.lat.toFixed(5),
|
|
|
|
lon: c.lng.toFixed(5),
|
|
|
|
};
|
2021-10-22 11:40:10 +01:00
|
|
|
this.debug_info.push("missing: " + params.qids);
|
|
|
|
this.api_call("missing", { params: params }).then((response) => {
|
|
|
|
var item_count = response.data.items.length;
|
|
|
|
this.debug_info.push(`missing done: ${item_count} items, took ${response.data.duration.toFixed(2)} seconds`);
|
2021-06-14 23:08:07 +01:00
|
|
|
response.data.isa_count.forEach((isa) => {
|
|
|
|
this.isa_labels[isa.qid] = isa.label;
|
|
|
|
if (this.isa_lookup[isa.qid] === undefined) {
|
|
|
|
this.isa_lookup[isa.qid] = isa;
|
|
|
|
this.isa_list.push(isa);
|
2021-08-05 07:32:06 +01:00
|
|
|
this.isa_ticked.push(isa.qid);
|
|
|
|
/* if (this.detail_qid || this.item_type_filters.length) {
|
2021-07-30 15:02:41 +01:00
|
|
|
this.isa_ticked.push(isa.qid);
|
2021-08-05 07:32:06 +01:00
|
|
|
} */
|
2021-06-14 23:08:07 +01:00
|
|
|
} else {
|
|
|
|
this.isa_lookup[isa.qid].count += 1;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.process_wikidata_items(response.data.items);
|
|
|
|
this.update_wikidata();
|
2021-06-16 14:41:33 +01:00
|
|
|
this.check_for_missing_done = true;
|
|
|
|
this.start_item();
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
},
|
2021-06-16 14:41:33 +01:00
|
|
|
start_item() {
|
|
|
|
if (!this.detail_qid) return;
|
2021-10-06 18:05:04 +01:00
|
|
|
this.open_item(this.detail_qid, null);
|
2021-06-16 14:41:33 +01:00
|
|
|
this.detail_qid = undefined;
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
update_wikidata() {
|
|
|
|
for (const qid in this.items) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
if (!item.osm) continue
|
|
|
|
|
|
|
|
var wd_item = item.wikidata;
|
|
|
|
|
2021-07-16 10:58:37 +01:00
|
|
|
Object.values(item.osm).forEach((osm) => {
|
2021-06-14 23:08:07 +01:00
|
|
|
osm.marker.setIcon(wd_item ? osmYellowMarker : osmOrangeMarker);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!wd_item) continue;
|
|
|
|
|
|
|
|
wd_item.markers.forEach((marker_data) => {
|
2021-06-20 13:46:33 +01:00
|
|
|
var marker = this.item_has_edit(item) ? greenDarkMarker : greenMarker;
|
|
|
|
marker_data.marker.setIcon(marker);
|
2021-06-14 23:08:07 +01:00
|
|
|
item.lines ||= [];
|
2021-07-16 10:58:37 +01:00
|
|
|
Object.values(item.osm).forEach((osm) => {
|
2021-06-14 23:08:07 +01:00
|
|
|
var path = [osm.centroid, marker_data];
|
|
|
|
var polyline = L.polyline(path, { color: "green" });
|
2021-07-19 21:11:01 +01:00
|
|
|
polyline.addTo(item.group);
|
|
|
|
item.lines.push(polyline);
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const qid in this.items) {
|
|
|
|
var item = this.items[qid];
|
|
|
|
if (item.osm) continue;
|
|
|
|
item.wikidata.markers.forEach((marker_data) => {
|
2021-06-20 13:46:33 +01:00
|
|
|
var marker = this.item_has_edit(item) ? greenDarkMarker : redMarker;
|
|
|
|
marker_data.marker.setIcon(marker);
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
}
|
2021-07-11 16:18:45 +01:00
|
|
|
},
|
|
|
|
onpopstate(event) {
|
|
|
|
var state = event.state;
|
2021-07-16 10:59:28 +01:00
|
|
|
if (!state) return;
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
this.mode = state.mode;
|
|
|
|
this.zoom = state.zoom;
|
|
|
|
this.search_text = state.search_text;
|
|
|
|
this.center = [state.lat, state.lon];
|
|
|
|
this.detail_qid = state.detail_qid;
|
|
|
|
this.recent_search = state.recent_search;
|
|
|
|
if (!this.detail_qid) this.current_item = undefined;
|
|
|
|
|
|
|
|
this.item_count = state.item_count;
|
|
|
|
this.map_area = state.map_area;
|
|
|
|
this.hits = state.hits;
|
|
|
|
this.current_hit = state.current_hit;
|
|
|
|
|
|
|
|
this.current_osm = state.current_osm;
|
|
|
|
|
|
|
|
this.map.setView(this.center, this.zoom);
|
|
|
|
|
|
|
|
if (this.mode == "search") {
|
|
|
|
this.clear_items();
|
|
|
|
this.fit_bounds_to_hit(this.current_hit);
|
|
|
|
}
|
|
|
|
},
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
created() {
|
|
|
|
var lat = this.startLat ?? 52.19679;
|
|
|
|
var lon = this.startLon ?? 0.15224;
|
|
|
|
this.center = [lat, lon];
|
2021-07-06 16:24:14 +01:00
|
|
|
this.zoom = this.startZoom;
|
2021-07-11 16:18:45 +01:00
|
|
|
this.mode = this.startMode;
|
2021-07-16 08:59:06 +01:00
|
|
|
this.changeset_comment = this.defaultComment || '+wikidata';
|
2023-05-13 14:01:28 +01:00
|
|
|
console.log(this.startItemTypeFilter);
|
|
|
|
if (this.startItemTypeFilter.length) {
|
|
|
|
this.show_item_type_filter = true;
|
|
|
|
}
|
|
|
|
this.item_type_filters = this.startItemTypeFilter;
|
2021-06-14 23:08:07 +01:00
|
|
|
},
|
|
|
|
mounted() {
|
2021-07-11 16:18:45 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
this.$nextTick(function () {
|
|
|
|
var options = {
|
|
|
|
center: this.center,
|
2021-07-06 16:24:14 +01:00
|
|
|
zoom: this.zoom || 16,
|
2021-06-14 23:08:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
var map = L.map("map", options);
|
2023-11-01 20:58:44 +00:00
|
|
|
var osm_url = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
2021-06-14 23:08:07 +01:00
|
|
|
var osm = L.tileLayer(osm_url, {
|
2023-11-02 12:46:47 +00:00
|
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
2021-06-14 23:08:07 +01:00
|
|
|
maxZoom: 19,
|
|
|
|
});
|
|
|
|
osm.addTo(map);
|
|
|
|
|
2024-05-04 09:13:49 +01:00
|
|
|
this.test_api_error();
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
var bounds;
|
|
|
|
if (this.startRadius) {
|
|
|
|
var bounds = L.latLng(this.center).toBounds(this.startRadius * 2000);
|
|
|
|
map.fitBounds(bounds);
|
|
|
|
} else {
|
|
|
|
bounds = map.getBounds();
|
|
|
|
}
|
|
|
|
|
2021-06-28 10:51:41 +01:00
|
|
|
map.on("moveend", this.map_moved);
|
2021-06-14 23:08:07 +01:00
|
|
|
this.map = map;
|
2021-06-16 14:41:33 +01:00
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
if (this.mode == "search") {
|
|
|
|
this.search_text = this.q.trim();
|
|
|
|
this.run_search();
|
2021-06-17 18:14:42 +01:00
|
|
|
} else {
|
2023-05-13 14:01:28 +01:00
|
|
|
this.detail_qid = this.startItem;
|
2021-07-11 16:18:45 +01:00
|
|
|
if (this.detail_qid) {
|
|
|
|
this.load_wikidata_items(bounds);
|
|
|
|
} else {
|
|
|
|
this.auto_load(bounds);
|
2023-05-13 14:01:28 +01:00
|
|
|
this.update_map_path();
|
2021-07-11 16:18:45 +01:00
|
|
|
}
|
2021-06-16 14:41:33 +01:00
|
|
|
}
|
2021-07-11 16:18:45 +01:00
|
|
|
|
|
|
|
window.onpopstate = this.onpopstate;
|
2024-05-04 09:13:49 +01:00
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
2021-07-11 16:18:45 +01:00
|
|
|
#select-area-btn {
|
|
|
|
position: absolute;
|
|
|
|
top: 77px;
|
|
|
|
left: 70%;
|
|
|
|
transform: translate(-50%, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
#map {
|
|
|
|
position: absolute;
|
2021-06-17 18:12:07 +01:00
|
|
|
top: 57px;
|
2021-06-14 23:08:07 +01:00
|
|
|
bottom: 0px;
|
2021-07-11 16:18:45 +01:00
|
|
|
left: 40%;
|
2021-07-16 10:49:15 +01:00
|
|
|
width: 60%;
|
2021-06-17 18:12:07 +01:00
|
|
|
z-index: -1;
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
.alert-map {
|
|
|
|
position: absolute;
|
|
|
|
bottom: 2rem;
|
2021-07-11 16:18:45 +01:00
|
|
|
left: 70%;
|
2021-07-06 16:24:14 +01:00
|
|
|
transform: translate(-50%, 0);
|
|
|
|
}
|
|
|
|
|
2021-06-18 18:28:56 +01:00
|
|
|
#edit-count {
|
|
|
|
position: absolute;
|
|
|
|
top: 77px;
|
|
|
|
right: 80px;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
#search {
|
|
|
|
position: absolute;
|
|
|
|
overflow: auto;
|
2021-06-17 18:12:07 +01:00
|
|
|
top: 77px;
|
2021-06-14 23:08:07 +01:00
|
|
|
left: 20px;
|
|
|
|
bottom: 20px;
|
|
|
|
width: 25%;
|
|
|
|
background: lightgray;
|
|
|
|
}
|
|
|
|
|
|
|
|
.bg-highlight {
|
|
|
|
background: lightgray !important;
|
|
|
|
}
|
|
|
|
|
|
|
|
#sidebar {
|
|
|
|
position: absolute;
|
|
|
|
background: #eee;
|
2021-07-08 13:56:24 +01:00
|
|
|
top: 57px;
|
2021-06-14 23:08:07 +01:00
|
|
|
left: 0px;
|
|
|
|
bottom: 0px;
|
|
|
|
overflow: auto;
|
2021-07-11 16:18:45 +01:00
|
|
|
width: 40%;
|
2021-06-14 23:08:07 +01:00
|
|
|
}
|
|
|
|
|
2021-07-06 16:24:14 +01:00
|
|
|
.tag-card-body {
|
|
|
|
padding: 0.5rem 0.5rem;
|
|
|
|
}
|
|
|
|
|
2021-06-14 23:08:07 +01:00
|
|
|
</style>
|