- tsconfig.json with files

- component LocationsMap to typescript
- delete bounding box button
- check unique email adresses of creators and contributors
This commit is contained in:
Arno Kaimbacher 2019-11-29 17:33:08 +01:00
parent 9d056b0b9f
commit 2cdfbdb004
12 changed files with 360 additions and 297 deletions

View file

@ -0,0 +1,226 @@
// import "leaflet";
import * as L from "leaflet";
import "leaflet-draw";
import { Component, Inject, Vue, Prop, Watch } from "vue-property-decorator";
import VueToast from "vue-toast-notification";
import "vue-toast-notification/dist/index.css";
Vue.use(VueToast);
// import ToastedPlugin from 'vue-toasted';
// Vue.use(ToastedPlugin);
@Component({})
export default class LocationsMap extends Vue {
@Inject("$validator") readonly $validator;
@Prop({ type: Object })
geolocation;
map = null;
drawnItems = null;
locationErrors: Array<any> = [];
options = {
theme: "bubble",
position: "top-right",
duration: 3000
};
created() {
// this.$validator.extend("boundingBox", {
// getMessage: field => "At least one " + field + " needs to be checked.",
// validate: (value, [testProp]) => {
// const options = this.dataset.checkedLicenses;
// return value || options.some(option => option[testProp]);
// }
// });
}
zoomTo() {
var _this = this;
_this.locationErrors.length = 0;
this.drawnItems.clearLayers();
//var xmin = document.getElementById("xmin").value;
var xmin = (<HTMLInputElement>document.getElementById("xmin")).value;
// var ymin = document.getElementById("ymin").value;
var ymin = (<HTMLInputElement>document.getElementById("ymin")).value;
//var xmax = document.getElementById("xmax").value;
var xmax = (<HTMLInputElement>document.getElementById("xmax")).value;
//var ymax = document.getElementById("ymax").value;
var ymax = (<HTMLInputElement>document.getElementById("ymax")).value;
var bounds = [[ymin, xmin], [ymax, xmax]];
try {
var boundingBox = L.rectangle(bounds, { color: "#005F6A", weight: 1 });
// this.geolocation.xmin = xmin;
// this.geolocation.ymin = ymin;
// this.geolocation.xmax = xmax;
// this.geolocation.ymax = ymax;
_this.drawnItems.addLayer(boundingBox);
_this.map.fitBounds(bounds);
this.$toast.success("valid bounding box", this.options);
} catch (e) {
// _this.errors.push(e);
this.$toast.error(e, this.options);
}
}
mounted() {
const map = L.map("map");
this.map = map;
map.scrollWheelZoom.disable();
// Construct a bounding box for this map that the user cannot
var southWest = L.latLng(46.5, 9.9),
northEast = L.latLng(48.9, 16.9),
bounds = L.latLngBounds(southWest, northEast);
// zoom the map to that bounding box
// map.fitBounds(bounds);
var southWest1 = L.latLng(46.35877, 8.782379); //lowerCorner
var northEast1 = L.latLng(49.037872, 17.189532); //upperCorner
var layerBounds = L.latLngBounds(southWest1, northEast1);
// var attribution = "www.basemap.at";
// var basemap_0 = L.tileLayer(
// "https://{s}.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png",
// {
// attribution: attribution,
// subdomains: ["maps", "maps1", "maps2", "maps3"],
// continuousWorld: false,
// detectRetina: false,
// bounds: layerBounds
// }
// );
//basemap_0.addTo(map);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a target="_blank" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(this.map);
map.fitBounds(bounds);
this.map = map;
// this.addPlaces(this.places)
// Initialise the FeatureGroup to store editable layers
var drawnItems = (this.drawnItems = new L.FeatureGroup());
map.addLayer(drawnItems);
var drawPluginOptions = {
position: "topright",
draw: {
polygon: false,
// disable toolbar item by setting it to false
polyline: false,
circle: false,
circlemarker: false,
rectangle: {
shapeOptions: {
clickable: true,
color: "#005F6A"
}
},
marker: false
},
// edit: {
// featureGroup: drawnItems, //REQUIRED!!
// remove: false
// }
};
// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);
var customControl = L.Control.extend({
options: {
position: "topleft",
faIcon: 'fa-trash'
// faIcon: 'fa-check-circle'
},
//constructor:
initialize: function(options) {
//util.mixin(this.options, options);
L.Util.setOptions(this, options);
// properties
this.geolocation = options.geolocation;
},
onAdd: function(map) {
this._map = map;
this._container = L.DomUtil.create(
"div",
"leaflet-bar leaflet-control leaflet-control-custom"
);
this._container.style.backgroundColor = "white";
this._container.style.width = "30px";
this._container.style.height = "30px";
this._buildButton();
// container.onclick = function() {
// console.log("buttonClicked");
// };
return this._container;
},
_buildButton: function(){
this._link = L.DomUtil.create('a','simplebutton-action',this._container);
this._link.href = "#";
if(this.options.id) {
this._link.id = this.options.id;
}
if(this.options.text) {
this._link.innerHTML = this.options.text;
}else{
L.DomUtil.create('i','fa ' + this.options.faIcon, this._link);
}
L.DomEvent.on(this._link, 'click', function(ev) {
drawnItems.clearLayers();
this.options.geolocation.xmin = "";
this.options.geolocation.ymin = "";
this.options.geolocation.xmax = "";
this.options.geolocation.ymax = "";
this._map.fitBounds(bounds);
},
this);
}
});
map.addControl(new customControl({ geolocation: this.geolocation }));
map.on(
L.Draw.Event.CREATED,
function(event) {
drawnItems.clearLayers();
var type = event.layerType;
var layer = event.layer;
// if (type === "rectancle") {
// layer.bindPopup("A popup!" + layer.getBounds().toBBoxString());
var bounds = layer.getBounds();
this.geolocation.xmin = bounds.getSouthWest().lng;
this.geolocation.ymin = bounds.getSouthWest().lat;
// console.log(this.geolocation.xmin);
this.geolocation.xmax = bounds.getNorthEast().lng;
this.geolocation.ymax = bounds.getNorthEast().lat;
// }
drawnItems.addLayer(layer);
},
this
);
map.on(
L.Draw.Event.EDITED,
function(event) {
var layers = event.layers.getLayers();
var layer = layers[0];
var bounds = layer.getBounds();
this.geolocation.xmin = bounds.getSouthWest().lng;
this.geolocation.ymin = bounds.getSouthWest().lat;
// console.log(this.geolocation.xmin);
this.geolocation.xmax = bounds.getNorthEast().lng;
this.geolocation.ymax = bounds.getNorthEast().lat;
},
this
);
}
}

View file

@ -1,287 +0,0 @@
<template>
<div style="position:relative">
<!-- <div id="inset">
xmin:
<input
type="text"
name="xmin"
id="xmin"
v-model="geolocation.xmin"
data-vv-scope="step-2"
v-validate="'decimal'"
>
<br>ymin:
<input
type="text"
name="ymin"
id="ymin"
v-model="geolocation.ymin"
data-vv-scope="step-2"
>
xmax:
<input
type="text"
name="xmax"
id="xmax"
v-model="geolocation.xmax"
data-vv-scope="step-2"
>
<br>ymax:
<input
type="text"
name="ymax"
id="ymax"
v-model="geolocation.ymax"
data-vv-scope="step-2"
>
<input type="button" v-on:click="zoomTo" value="zoomTo">
</div>-->
<div id="map"></div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="xmin">xmin:</label>
<input
name="xmin"
type="text"
class="pure-u-23-24"
v-model="geolocation.xmin"
data-vv-scope="step-2"
id="xmin"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="ymin">ymin:</label>
<input
name="ymin"
type="text"
class="pure-u-23-24"
v-model="geolocation.ymin"
data-vv-scope="step-2"
id="ymin"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="xmax">xmax:</label>
<input
name="xmax"
type="text"
class="pure-u-23-24"
v-model="geolocation.xmax"
data-vv-scope="step-2"
id="xmax"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="ymax">ymax:</label>
<input
name="ymax"
type="text"
class="pure-u-23-24"
v-model="geolocation.ymax"
data-vv-scope="step-2"
id="ymax"
v-validate="'decimal'"
/>
</div>
<input type="button" v-on:click="zoomTo" value="validate coordinates" />
</div>
</div>
</template>
<script>
// import "leaflet";
import * as L from "leaflet";
import "leaflet-draw";
//const L = window.L;
export default {
inject: {
$validator: "$validator"
},
props: {
geolocation: {
type: Object
}
},
data() {
return {
map: [],
drawnItems: null,
locationErrors: []
};
},
created() {
this.$validator.extend("boundingBox", {
getMessage: field => "At least one " + field + " needs to be checked.",
validate: (value, [testProp]) => {
const options = this.dataset.checkedLicenses;
return value || options.some(option => option[testProp]);
}
});
},
computed: {},
watch: {},
methods: {
zoomTo() {
var _this = this;
_this.locationErrors.length = 0;
this.drawnItems.clearLayers();
var xmin = document.getElementById("xmin").value;
var ymin = document.getElementById("ymin").value;
var xmax = document.getElementById("xmax").value;
var ymax = document.getElementById("ymax").value;
var bounds = [[ymin, xmin], [ymax, xmax]];
try {
var boundingBox = L.rectangle(bounds, { color: "#005F6A", weight: 1 });
// this.geolocation.xmin = xmin;
// this.geolocation.ymin = ymin;
// this.geolocation.xmax = xmax;
// this.geolocation.ymax = ymax;
_this.drawnItems.addLayer(boundingBox);
_this.map.fitBounds(bounds);
_this.$toast.success("valid bounding box");
} catch (e) {
// _this.errors.push(e);
_this.$toast.error(e);
}
}
},
mounted() {
const map = L.map("map");
this.map = map;
map.scrollWheelZoom.disable();
// Construct a bounding box for this map that the user cannot
var southWest = L.latLng(46.5, 9.9),
northEast = L.latLng(48.9, 16.9),
bounds = L.latLngBounds(southWest, northEast);
// zoom the map to that bounding box
// map.fitBounds(bounds);
var southWest1 = L.latLng(46.35877, 8.782379); //lowerCorner
var northEast1 = L.latLng(49.037872, 17.189532); //upperCorner
var layerBounds = L.latLngBounds(southWest1, northEast1);
// var attribution = "www.basemap.at";
// var basemap_0 = L.tileLayer(
// "https://{s}.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png",
// {
// attribution: attribution,
// subdomains: ["maps", "maps1", "maps2", "maps3"],
// continuousWorld: false,
// detectRetina: false,
// bounds: layerBounds
// }
// );
//basemap_0.addTo(map);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a target="_blank" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(this.map);
map.fitBounds(bounds);
this.map = map;
// this.addPlaces(this.places)
// Initialise the FeatureGroup to store editable layers
var drawnItems = (this.drawnItems = new L.FeatureGroup());
map.addLayer(drawnItems);
var drawPluginOptions = {
position: "topright",
draw: {
polygon: false,
// disable toolbar item by setting it to false
polyline: false,
circle: false,
circlemarker: false,
rectangle: {
shapeOptions: {
clickable: true,
color: "#005F6A"
}
},
marker: false
},
edit: {
featureGroup: drawnItems, //REQUIRED!!
remove: false
}
};
// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);
map.on(
L.Draw.Event.CREATED,
function(event) {
drawnItems.clearLayers();
var type = event.layerType;
var layer = event.layer;
// if (type === "rectancle") {
// layer.bindPopup("A popup!" + layer.getBounds().toBBoxString());
var bounds = layer.getBounds();
this.geolocation.xmin = bounds.getSouthWest().lng;
this.geolocation.ymin = bounds.getSouthWest().lat;
// console.log(this.geolocation.xmin);
this.geolocation.xmax = bounds.getNorthEast().lng;
this.geolocation.ymax = bounds.getNorthEast().lat;
// }
drawnItems.addLayer(layer);
},
this
);
map.on(
L.Draw.Event.EDITED,
function(event) {
var layers = event.layers.getLayers();
var layer = layers[0];
var bounds = layer.getBounds();
this.geolocation.xmin = bounds.getSouthWest().lng;
this.geolocation.ymin = bounds.getSouthWest().lat;
// console.log(this.geolocation.xmin);
this.geolocation.xmax = bounds.getNorthEast().lng;
this.geolocation.ymax = bounds.getNorthEast().lat;
},
this
);
}
};
</script>
// https://github.com/vuejs-templates/webpack/issues/121
// npm install node-sass sass-loader --save-dev
<style lang="scss">
/* Import CSS from Leaflet and plugins.*/
@import "~leaflet/dist/leaflet.css";
@import "~leaflet-draw/dist/leaflet.draw.css";
#map {
width: 100%;
height: 400px;
font-weight: bold;
font-size: 13px;
text-shadow: 0 0 2px #fff;
}
#inset {
position: absolute;
bottom: 0;
left: 0;
border: none;
width: 120px;
z-index: 999;
/*height: 120px;*/
}
</style>

View file

@ -47,12 +47,13 @@
/>
</td>
<td>
<!-- v-validate="'required|email'" -->
<input
name="email"
class="form-control"
placeholder="[EMAIL]"
v-model="item.email"
v-validate="'required|email'"
v-model="item.email"
v-validate="{required: true, email: true, unique: [personlist, index, 'email']}"
v-bind:readonly="item.status==1"
data-vv-scope="step-1"
/>

View file

@ -0,0 +1,108 @@
<template>
<div style="position:relative">
<!-- <div id="inset">
</div>-->
<div id="map"></div>
<!-- <div id="delete">Delete Features</div> -->
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="xmin">xmin:</label>
<input
name="xmin"
type="text"
class="pure-u-23-24"
v-model="geolocation.xmin"
data-vv-scope="step-2"
id="xmin"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="ymin">ymin:</label>
<input
name="ymin"
type="text"
class="pure-u-23-24"
v-model="geolocation.ymin"
data-vv-scope="step-2"
id="ymin"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="xmax">xmax:</label>
<input
name="xmax"
type="text"
class="pure-u-23-24"
v-model="geolocation.xmax"
data-vv-scope="step-2"
id="xmax"
v-validate="'decimal'"
/>
</div>
<div class="pure-u-1 pure-u-md-1-2 pure-div">
<label for="ymax">ymax:</label>
<input
name="ymax"
type="text"
class="pure-u-23-24"
v-model="geolocation.ymax"
data-vv-scope="step-2"
id="ymax"
v-validate="'decimal'"
/>
</div>
<input type="button" v-on:click="zoomTo" value="validate coordinates" />
</div>
</div>
</template>
<script lang="ts">
import LocationsMap from "./LocationsMap";
export default LocationsMap;
</script>
// https://github.com/vuejs-templates/webpack/issues/121
// npm install node-sass sass-loader --save-dev
<style lang="scss">
/* Import CSS from Leaflet and plugins.*/
@import "~leaflet/dist/leaflet.css";
@import "~leaflet-draw/dist/leaflet.draw.css";
#map {
width: 100%;
height: 400px;
font-weight: bold;
font-size: 13px;
text-shadow: 0 0 2px #fff;
}
#delete,
#export {
position: absolute;
top: 50px;
right: 10px;
z-index: 100;
background: white;
color: black;
padding: 6px;
border-radius: 4px;
font-family: "Helvetica Neue";
cursor: pointer;
font-size: 12px;
text-decoration: none;
z-index: 999;
}
#inset {
position: absolute;
bottom: 0;
left: 0;
border: none;
width: 120px;
z-index: 999;
/*height: 120px;*/
}
</style>

View file

@ -32,7 +32,7 @@ import MyAutocomplete from './components/MyAutocomplete.vue';
import messagesEN from './strings/messages/en.js';
import VeeValidate from 'vee-validate';
import Dataset from './components/Dataset';
import LocationsMap from './components/LocationsMap.vue';
import LocationsMap from './components/locations-map.vue';
import VueCountdown from './components/vue-countdown';
import PersonTable from './components/PersonTable.vue';
import modal from './components/ShowModal.vue';
@ -122,10 +122,10 @@ const app = new Vue({
}
});
const isUnique = (value, [objectArray, index]) =>
const isUnique = (value, [objectArray, index, attribute]) =>
new Promise(resolve => {
setTimeout(() => {
if (objectArray.some((item, i) => item.value === value && index !== i)) {
if (objectArray.some((item, i) => item[attribute] === value && index !== i)) {
return resolve({
valid: false,
data: {

8
resources/js/index.d.ts vendored Normal file
View file

@ -0,0 +1,8 @@
import Vue from 'vue';
import VueToast from 'vue-toast-notification';
declare module 'vue/types/vue' {
interface Vue {
$toast: VueToast
}
}

View file

@ -526,7 +526,7 @@
<tbody>
<tr v-for="(item, index) in dataset.keywords">
<td>
<input name="Keyword Value" class="form-control" placeholder="[KEYWORD VALUE]" v-model="item.value" v-validate="{required: true, unique: [dataset.keywords, index]}"
<input name="Keyword Value" class="form-control" placeholder="[KEYWORD VALUE]" v-model="item.value" v-validate="{required: true, unique: [dataset.keywords, index, 'value']}"
data-vv-scope="step-2" />
</td>
<td>