mirror of
https://github.com/KevinMidboe/nova-map-fields.git
synced 2025-10-29 17:50:27 +00:00
First commit.
This commit is contained in:
15
resources/js/components/DetailField.vue
Executable file
15
resources/js/components/DetailField.vue
Executable file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<panel-item :field="field">
|
||||
<template slot="value">
|
||||
<component :is="'field-' + field.map.type" :field="field" v-model="field.value"></component>
|
||||
</template>
|
||||
</panel-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resource', 'resourceName', 'resourceId', 'field'],
|
||||
}
|
||||
</script>
|
||||
59
resources/js/components/FieldMap.vue
Executable file
59
resources/js/components/FieldMap.vue
Executable file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div :style="{'height': field.map.height}">
|
||||
<l-map
|
||||
style="z-index:0"
|
||||
:zoom="field.map.zoom"
|
||||
:center="center"
|
||||
:bounds="bounds"
|
||||
@click="onMapClick"
|
||||
>
|
||||
<l-tile-layer
|
||||
:url="url"
|
||||
:attribution="attribution"/>
|
||||
<slot></slot>
|
||||
</l-map>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {LMap, LTileLayer} from 'vue2-leaflet'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
requred: true,
|
||||
},
|
||||
center: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
bounds: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
attribution: '© <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors',
|
||||
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onMapClick(evt) {
|
||||
this.$emit('click', evt);
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
LMap,
|
||||
LTileLayer,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "../../../node_modules/leaflet/dist/leaflet.css"
|
||||
</style>
|
||||
40
resources/js/components/FormField.vue
Executable file
40
resources/js/components/FormField.vue
Executable file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<default-field :field="field" :errors="errors">
|
||||
<template slot="field">
|
||||
<component v-if="value" :is="'field-' + field.map.type" :field="field" :edit="true" v-model="value"></component>
|
||||
</template>
|
||||
</default-field>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FormField, HandlesValidationErrors } from 'laravel-nova'
|
||||
|
||||
export default {
|
||||
mixins: [FormField, HandlesValidationErrors],
|
||||
|
||||
props: ['resourceName', 'resourceId', 'field'],
|
||||
|
||||
methods: {
|
||||
/*
|
||||
* Set the initial, internal value for the field.
|
||||
*/
|
||||
setInitialValue() {
|
||||
this.value = this.field.value || {}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fill the given FormData object with the field's internal value.
|
||||
*/
|
||||
fill(formData) {
|
||||
formData.append(this.field.attribute, JSON.stringify(this.value));
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the field's internal value.
|
||||
*/
|
||||
handleChange(value) {
|
||||
this.value = value
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
9
resources/js/components/IndexField.vue
Executable file
9
resources/js/components/IndexField.vue
Executable file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<span>{{ field.value }}</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['resourceName', 'field'],
|
||||
}
|
||||
</script>
|
||||
80
resources/js/components/fields/Marker.vue
Executable file
80
resources/js/components/fields/Marker.vue
Executable file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<field-map :center="position" :field="field">
|
||||
<l-marker :lat-lng="position" :draggable="edit" @dragend="onDragEnd"/>
|
||||
</field-map>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {LMarker} from 'vue2-leaflet'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
position() {
|
||||
return L.latLng(this.value.lat || this.field.map.center.latitude, this.value.lng || this.field.map.center.longitude);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.registerWatchers();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onDragEnd(evt) {
|
||||
let latLng = evt.target.getLatLng();
|
||||
|
||||
this.$emit('input', {
|
||||
lat: latLng.lat,
|
||||
lng: latLng.lng,
|
||||
});
|
||||
},
|
||||
|
||||
registerWatchers() {
|
||||
this.getGlobalFieldComponents().forEach(component => {
|
||||
if ([this.field.latitudeField, this.field.longitudeField].includes(component.field.attribute)) {
|
||||
component.$watch('value', (value) => {
|
||||
this.value[component.field.attribute] = value;
|
||||
}, {immediate: true})
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
getGlobalFieldComponents(components = null) {
|
||||
if (! components) {
|
||||
components = this.$root.$children;
|
||||
}
|
||||
|
||||
let returnArray = [];
|
||||
|
||||
components.forEach(component => {
|
||||
if (component.field) {
|
||||
return returnArray.push(component);
|
||||
}
|
||||
|
||||
returnArray = returnArray.concat(this.getGlobalFieldComponents(component.$children));
|
||||
});
|
||||
|
||||
return returnArray;
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
LMarker,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
87
resources/js/components/fields/Polyline.vue
Executable file
87
resources/js/components/fields/Polyline.vue
Executable file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div @keydown.backspace="removeLastMarker">
|
||||
<field-map :bounds="bounds" :center="center" :field="field" @click="createMarker">
|
||||
<l-marker v-for="marker in markers" :lat-lng="marker" :draggable="edit" @dragend="triggerChange" />
|
||||
<l-polyline :lat-lngs="value" :visible="true" />
|
||||
</field-map>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {LMarker, LPolyline} from 'vue2-leaflet'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
startBounds: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
markers() {
|
||||
if (!this.value[0]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.value;
|
||||
},
|
||||
|
||||
center() {
|
||||
if (!this.markers.length) {
|
||||
return {
|
||||
lat: this.field.map.center.latitude,
|
||||
lng: this.field.map.center.longitude,
|
||||
};
|
||||
}
|
||||
|
||||
return this.bounds.getCenter();
|
||||
},
|
||||
|
||||
bounds() {
|
||||
if (this.startBounds !== undefined) {
|
||||
return this.startBounds;
|
||||
}
|
||||
|
||||
if (!this.markers.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.startBounds = new L.LatLngBounds(this.markers);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
triggerChange() {
|
||||
this.$emit('input', this.markers);
|
||||
},
|
||||
removeLastMarker() {
|
||||
this.markers.splice(-1,1);
|
||||
this.triggerChange();
|
||||
},
|
||||
createMarker(evt) {
|
||||
this.markers.push(evt.latlng);
|
||||
this.triggerChange();
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
LMarker,
|
||||
LPolyline,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user