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:
		
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | /.idea | ||||||
|  | /vendor | ||||||
|  | /node_modules | ||||||
|  | package-lock.json | ||||||
|  | composer.phar | ||||||
|  | composer.lock | ||||||
|  | phpunit.xml | ||||||
|  | .phpunit.result.cache | ||||||
|  | .DS_Store | ||||||
|  | Thumbs.db | ||||||
							
								
								
									
										29
									
								
								composer.json
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								composer.json
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | { | ||||||
|  |     "name": "lassehaslev/nova-map-fields", | ||||||
|  |     "description": "A Laravel Nova field.", | ||||||
|  |     "keywords": [ | ||||||
|  |         "laravel", | ||||||
|  |         "nova" | ||||||
|  |     ], | ||||||
|  |     "license": "MIT", | ||||||
|  |     "require": { | ||||||
|  |         "php": ">=7.1.0" | ||||||
|  |     }, | ||||||
|  |     "autoload": { | ||||||
|  |         "psr-4": { | ||||||
|  |             "Lassehaslev\\NovaMapFields\\": "src/" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "extra": { | ||||||
|  |         "laravel": { | ||||||
|  |             "providers": [ | ||||||
|  |                 "Lassehaslev\\NovaMapFields\\FieldServiceProvider" | ||||||
|  |             ] | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "config": { | ||||||
|  |         "sort-packages": true | ||||||
|  |     }, | ||||||
|  |     "minimum-stability": "dev", | ||||||
|  |     "prefer-stable": true | ||||||
|  | } | ||||||
							
								
								
									
										0
									
								
								dist/css/field.css
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										0
									
								
								dist/css/field.css
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/layers-2x.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/layers-2x.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/layers.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/layers.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 696 B | 
							
								
								
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/marker-icon.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/images/vendor/leaflet/dist/marker-icon.png
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										25553
									
								
								dist/js/field.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										25553
									
								
								dist/js/field.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								dist/mix-manifest.json
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								dist/mix-manifest.json
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  |     "/js/field.js": "/js/field.js", | ||||||
|  |     "/css/field.css": "/css/field.css" | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								package.json
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								package.json
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |     "private": true, | ||||||
|  |     "scripts": { | ||||||
|  |         "dev": "npm run development", | ||||||
|  |         "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", | ||||||
|  |         "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", | ||||||
|  |         "watch-poll": "npm run watch -- --watch-poll", | ||||||
|  |         "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", | ||||||
|  |         "prod": "npm run production", | ||||||
|  |         "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" | ||||||
|  |     }, | ||||||
|  |     "devDependencies": { | ||||||
|  |         "cross-env": "^5.0.0", | ||||||
|  |         "laravel-mix": "^1.0", | ||||||
|  |         "laravel-nova": "^1.0" | ||||||
|  |     }, | ||||||
|  |     "dependencies": { | ||||||
|  |         "vue": "^2.5.0", | ||||||
|  |         "vue2-leaflet": "^1.0.2" | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										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> | ||||||
							
								
								
									
										12
									
								
								resources/js/field.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								resources/js/field.js
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | Nova.booting((Vue, router) => { | ||||||
|  |     Vue.component('index-nova-map-fields', require('./components/IndexField')); | ||||||
|  |     Vue.component('detail-nova-map-fields', require('./components/DetailField')); | ||||||
|  |     Vue.component('form-nova-map-fields', require('./components/FormField')); | ||||||
|  |  | ||||||
|  |     Vue.component('field-map', require('./components/FieldMap')); | ||||||
|  |     Vue.component('field-marker', require('./components/fields/Marker')); | ||||||
|  |     Vue.component('field-polyline', require('./components/fields/Polyline')); | ||||||
|  |  | ||||||
|  |     // Config leaflet images to load images from CDN | ||||||
|  |     L.Icon.Default.imagePath = 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.4/images/'; | ||||||
|  | }) | ||||||
							
								
								
									
										1
									
								
								resources/sass/field.scss
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								resources/sass/field.scss
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | // Nova Tool CSS | ||||||
							
								
								
									
										28
									
								
								src/FieldServiceProvider.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								src/FieldServiceProvider.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Lassehaslev\NovaMapFields; | ||||||
|  |  | ||||||
|  | use Laravel\Nova\Nova; | ||||||
|  | use Laravel\Nova\Events\ServingNova; | ||||||
|  | use Illuminate\Support\ServiceProvider; | ||||||
|  |  | ||||||
|  | class FieldServiceProvider extends ServiceProvider | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Bootstrap any application services. | ||||||
|  |      */ | ||||||
|  |     public function boot() | ||||||
|  |     { | ||||||
|  |         Nova::serving(function (ServingNova $event) { | ||||||
|  |             Nova::script('nova-map-fields', __DIR__.'/../dist/js/field.js'); | ||||||
|  |             Nova::style('nova-map-fields', __DIR__.'/../dist/css/field.css'); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Register any application services. | ||||||
|  |      */ | ||||||
|  |     public function register() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								src/MapField.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										109
									
								
								src/MapField.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Lassehaslev\NovaMapFields; | ||||||
|  |  | ||||||
|  | use Laravel\Nova\Fields\Field; | ||||||
|  | use Illuminate\Support\Str; | ||||||
|  |  | ||||||
|  | abstract class MapField extends Field | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * The field's component. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $component = 'nova-map-fields'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Hide from index field. | ||||||
|  |      * | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public $showOnIndex = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new field. | ||||||
|  |      * And set default properties. | ||||||
|  |      * | ||||||
|  |      * @param string      $name | ||||||
|  |      * @param string|null $attribute | ||||||
|  |      * @param mixed|null  $resolveCallback | ||||||
|  |      */ | ||||||
|  |     public function __construct($name, $attribute = null, $resolveCallback = null) | ||||||
|  |     { | ||||||
|  |         $this->setHeight('250px'); | ||||||
|  |         $this->setCenter(0, 0); | ||||||
|  |         $this->setZoom(13); | ||||||
|  |  | ||||||
|  |         $this->withMapMeta('type', $this->getMapFieldType()); | ||||||
|  |  | ||||||
|  |         parent::__construct($name, $attribute = null, $resolveCallback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the height for the map. | ||||||
|  |      * | ||||||
|  |      * @param mixed $height | ||||||
|  |      * | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setHeight($height) | ||||||
|  |     { | ||||||
|  |         return $this->withMapMeta('height', $height); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the zoom for the map. | ||||||
|  |      * | ||||||
|  |      * @param mixed $level | ||||||
|  |      * | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setZoom($level) | ||||||
|  |     { | ||||||
|  |         return $this->withMapMeta('zoom', $level); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the position for the map. | ||||||
|  |      * | ||||||
|  |      * @param mixed $latitude | ||||||
|  |      * @param mixed $longitude | ||||||
|  |      * | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setCenter($latitude, $longitude) | ||||||
|  |     { | ||||||
|  |         return $this->withMapMeta('center', [ | ||||||
|  |             'latitude' => $latitude, | ||||||
|  |             'longitude' => $longitude, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add meta data for the map. | ||||||
|  |      * | ||||||
|  |      * @param mixed $key | ||||||
|  |      * @param mixed $value | ||||||
|  |      */ | ||||||
|  |     protected function withMapMeta($key, $value) | ||||||
|  |     { | ||||||
|  |         $existingMapMeta = $this->meta['map'] ?? []; | ||||||
|  |  | ||||||
|  |         return $this->withMeta([ | ||||||
|  |             'map' => array_merge($existingMapMeta, [ | ||||||
|  |                 $key => $value, | ||||||
|  |             ]), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get component name. | ||||||
|  |      * | ||||||
|  |      * @return string | ||||||
|  |      */ | ||||||
|  |     public function getMapFieldType() | ||||||
|  |     { | ||||||
|  |         return Str::kebab(class_basename($this)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										85
									
								
								src/Marker.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										85
									
								
								src/Marker.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Lassehaslev\NovaMapFields; | ||||||
|  |  | ||||||
|  | use Laravel\Nova\Http\Requests\NovaRequest; | ||||||
|  |  | ||||||
|  | class Marker extends MapField | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Create a new field. | ||||||
|  |      * And set default properties. | ||||||
|  |      * | ||||||
|  |      * @param string      $name | ||||||
|  |      * @param string|null $attribute | ||||||
|  |      * @param mixed|null  $resolveCallback | ||||||
|  |      */ | ||||||
|  |     public function __construct($name, $attribute = null, $resolveCallback = null) | ||||||
|  |     { | ||||||
|  |         $this->help('Drag the marker to change the point.'); | ||||||
|  |  | ||||||
|  |         parent::__construct($name, $attribute = null, $resolveCallback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the latutude field. | ||||||
|  |      * | ||||||
|  |      * @param mixed $fieldName | ||||||
|  |      * | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setLatitude($fieldName) | ||||||
|  |     { | ||||||
|  |         return $this->withMeta([ | ||||||
|  |             'latitudeField' => $fieldName, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the longitude field. | ||||||
|  |      * | ||||||
|  |      * @param mixed $fieldName | ||||||
|  |      * | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setLongitude($fieldName) | ||||||
|  |     { | ||||||
|  |         return $this->withMeta([ | ||||||
|  |             'longitudeField' => $fieldName, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Resolve the attribute before sending to frontend. | ||||||
|  |      * | ||||||
|  |      * @param mixed      $resource | ||||||
|  |      * @param mixed|null $attribute | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function resolveAttribute($resource, $attribute = null) | ||||||
|  |     { | ||||||
|  |         return [ | ||||||
|  |             'lat' => $resource->{$this->meta['latitudeField']}, | ||||||
|  |             'lng' => $resource->{$this->meta['longitudeField']}, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Hydrate the given attribute on the model based on the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param \Laravel\Nova\Http\Requests\NovaRequest $request | ||||||
|  |      * @param string                                  $requestAttribute | ||||||
|  |      * @param object                                  $model | ||||||
|  |      * @param string                                  $attribute | ||||||
|  |      */ | ||||||
|  |     protected function fillAttributeFromRequest(NovaRequest $request, $requestAttribute, $model, $attribute) | ||||||
|  |     { | ||||||
|  |         if ($request->exists($requestAttribute)) { | ||||||
|  |             $latLng = json_decode($request[$requestAttribute]); | ||||||
|  |  | ||||||
|  |             $model->{$this->meta['latitudeField']} = $latLng->lat; | ||||||
|  |             $model->{$this->meta['longitudeField']} = $latLng->lng; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								src/Polyline.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								src/Polyline.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Lassehaslev\NovaMapFields; | ||||||
|  |  | ||||||
|  | class Polyline extends MapField | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Create a new field. | ||||||
|  |      * And set default properties. | ||||||
|  |      * | ||||||
|  |      * @param string      $name | ||||||
|  |      * @param string|null $attribute | ||||||
|  |      * @param mixed|null  $resolveCallback | ||||||
|  |      */ | ||||||
|  |     public function __construct($name, $attribute = null, $resolveCallback = null) | ||||||
|  |     { | ||||||
|  |         $this->help('Click on the map to create a new point. Drag a marker to change the point. When the map is selected, you can press [backspace] to remove markers.'); | ||||||
|  |  | ||||||
|  |         parent::__construct($name, $attribute = null, $resolveCallback); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Resolve the attribute before sending to frontend. | ||||||
|  |      * | ||||||
|  |      * @param mixed      $resource | ||||||
|  |      * @param mixed|null $attribute | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function resolveAttribute($resource, $attribute = null) | ||||||
|  |     { | ||||||
|  |         return json_decode($resource->{$attribute}); | ||||||
|  |  | ||||||
|  |         return [ | ||||||
|  |             'lat' => $resource->{$this->meta['latitudeField']}, | ||||||
|  |             'lng' => $resource->{$this->meta['longitudeField']}, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								webpack.mix.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								webpack.mix.js
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | let mix = require('laravel-mix') | ||||||
|  |  | ||||||
|  | mix.setPublicPath('dist') | ||||||
|  |    .js('resources/js/field.js', 'js') | ||||||
|  |    .sass('resources/sass/field.scss', 'css') | ||||||
		Reference in New Issue
	
	Block a user