mirror of https://github.com/Squidex/squidex.git
33 changed files with 438 additions and 39 deletions
@ -0,0 +1,15 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label for="field-editor" class="col col-3 col-form-label">Editor</label> |
|||
|
|||
<div class="col col-9"> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls.editor.value === 'Map'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="Map" /> |
|||
|
|||
<i class="icon-control-Map"></i> |
|||
|
|||
<span class="radio-label">Map</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
@ -0,0 +1,2 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
@ -0,0 +1,31 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input, OnInit } from '@angular/core'; |
|||
import { FormGroup, FormControl, Validators } from '@angular/forms'; |
|||
|
|||
import { GeolocationFieldPropertiesDto } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-geolocation-ui', |
|||
styleUrls: ['geolocation-ui.component.scss'], |
|||
templateUrl: 'geolocation-ui.component.html' |
|||
}) |
|||
export class GeolocationUIComponent implements OnInit { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: GeolocationFieldPropertiesDto; |
|||
|
|||
public ngOnInit() { |
|||
this.editForm.addControl('editor', |
|||
new FormControl(this.properties.editor, [ |
|||
Validators.required |
|||
])); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label class="col col-3 col-form-checkbox-label" for="field-required">Required</label> |
|||
|
|||
<div class="col col-6"> |
|||
<input type="checkbox" class="form-check-input" id="field-required" formControlName="isRequired" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,10 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.form-check-input { |
|||
margin: 0; |
|||
} |
|||
|
|||
.form-group { |
|||
margin-top: .5rem; |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input } from '@angular/core'; |
|||
import { FormGroup } from '@angular/forms'; |
|||
|
|||
import { GeolocationFieldPropertiesDto } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-geolocation-validation', |
|||
styleUrls: ['geolocation-validation.component.scss'], |
|||
templateUrl: 'geolocation-validation.component.html' |
|||
}) |
|||
export class GeolocationValidationComponent { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: GeolocationFieldPropertiesDto; |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<div> |
|||
<div class="editor" #editor></div> |
|||
|
|||
<div> |
|||
<form class="form-inline" [formGroup]="geolocationForm" (submit)="updateValueByInput()"> |
|||
<div class="form-group latitude-group"> |
|||
<input type="number" class="form-control" formControlName="latitude" step="any" #dateInput /> |
|||
</div> |
|||
<div class="form-group longitude-group"> |
|||
<input type="number" class="form-control" formControlName="longitude" step="any" /> |
|||
</div> |
|||
<div class="form-group" [class.hidden]="!hasValue"> |
|||
<button type="reset" class="btn btn-link clear" (click)="reset()">Clear</button> |
|||
</div> |
|||
|
|||
<button type="submit" class="hidden"></button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,14 @@ |
|||
@import '_mixins'; |
|||
@import '_vars'; |
|||
|
|||
.editor { |
|||
height: 30rem; |
|||
} |
|||
|
|||
.form-inline { |
|||
margin-top: .5rem; |
|||
} |
|||
|
|||
.latitude-group { |
|||
margin-right: .25rem; |
|||
} |
|||
@ -0,0 +1,160 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { AfterViewInit, Component, ElementRef, forwardRef, ViewChild } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; |
|||
|
|||
import { ResourceLoaderService } from './../services/resource-loader.service'; |
|||
import { ValidatorsEx } from './validators'; |
|||
|
|||
const NOOP = () => { /* NOOP */ }; |
|||
|
|||
declare var L: any; |
|||
|
|||
export const SQX_GEOLOCATION_EDITOR_CONTROL_VALUE_ACCESSOR: any = { |
|||
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => GeolocationEditorComponent), multi: true |
|||
}; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-geolocation-editor', |
|||
styleUrls: ['./geolocation-editor.component.scss'], |
|||
templateUrl: './geolocation-editor.component.html', |
|||
providers: [SQX_GEOLOCATION_EDITOR_CONTROL_VALUE_ACCESSOR] |
|||
}) |
|||
export class GeolocationEditorComponent implements ControlValueAccessor, AfterViewInit { |
|||
private changeCallback: (value: any) => void = NOOP; |
|||
private touchedCallback: () => void = NOOP; |
|||
private marker: any; |
|||
private map: any; |
|||
private value: any; |
|||
|
|||
public get hasValue() { |
|||
return !!this.value; |
|||
} |
|||
|
|||
public geolocationForm = |
|||
this.formBuilder.group({ |
|||
latitude: ['', |
|||
[ |
|||
ValidatorsEx.between(-90, 90) |
|||
]], |
|||
longitude: ['', |
|||
[ |
|||
ValidatorsEx.between(-180, 180) |
|||
]] |
|||
}); |
|||
|
|||
public isDisabled = false; |
|||
|
|||
@ViewChild('editor') |
|||
public editor: ElementRef; |
|||
|
|||
constructor( |
|||
private readonly resourceLoader: ResourceLoaderService, |
|||
private readonly formBuilder: FormBuilder |
|||
) { |
|||
} |
|||
|
|||
public writeValue(value: any) { |
|||
this.value = value; |
|||
|
|||
if (this.marker) { |
|||
this.updateMarker(true, false); |
|||
} |
|||
} |
|||
|
|||
public setDisabledState(isDisabled: boolean): void { |
|||
this.isDisabled = isDisabled; |
|||
} |
|||
|
|||
public registerOnChange(fn: any) { |
|||
this.changeCallback = fn; |
|||
} |
|||
|
|||
public registerOnTouched(fn: any) { |
|||
this.touchedCallback = fn; |
|||
} |
|||
|
|||
public updateValueByInput() { |
|||
if (this.geolocationForm.controls['latitude'].value !== null && |
|||
this.geolocationForm.controls['longitude'].value !== null && |
|||
this.geolocationForm.valid) { |
|||
this.value = this.geolocationForm.value; |
|||
} else { |
|||
this.value = null; |
|||
} |
|||
|
|||
this.updateMarker(true, true); |
|||
} |
|||
|
|||
public ngAfterViewInit() { |
|||
this.resourceLoader.loadStyle('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.css'); |
|||
this.resourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.3/leaflet.js').then(() => { |
|||
this.map = L.map(this.editor.nativeElement).fitWorld(); |
|||
|
|||
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { |
|||
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' |
|||
}).addTo(this.map); |
|||
|
|||
this.map.on('click', (event: any) => { |
|||
this.value = { latitude: event.latlng.lat, longitude: event.latlng.lng }; |
|||
|
|||
this.updateMarker(false, true); |
|||
}); |
|||
|
|||
this.updateMarker(true, false); |
|||
}); |
|||
} |
|||
|
|||
public reset() { |
|||
this.value = null; |
|||
|
|||
this.updateMarker(true, true); |
|||
} |
|||
|
|||
private updateMarker(zoom: boolean, fireEvent: boolean) { |
|||
if (this.value) { |
|||
if (!this.marker) { |
|||
this.marker = L.marker([0, 90], { draggable: true }).addTo(this.map); |
|||
|
|||
this.marker.on('drag', (event: any) => { |
|||
this.value = { latitude: event.latlng.lat, longitude: event.latlng.lng }; |
|||
}); |
|||
|
|||
this.marker.on('dragend', (event: any) => { |
|||
this.updateMarker(false, true); |
|||
}); |
|||
} |
|||
|
|||
const latLng = L.latLng(this.value.latitude, this.value.longitude); |
|||
|
|||
if (zoom) { |
|||
this.map.setView(latLng, 8); |
|||
} else { |
|||
this.map.panTo(latLng); |
|||
} |
|||
|
|||
this.marker.setLatLng(latLng); |
|||
|
|||
this.geolocationForm.setValue(this.value, { emitEvent: false, onlySelf: false }); |
|||
} else { |
|||
if (this.marker) { |
|||
this.marker.removeFrom(this.map); |
|||
this.marker = null; |
|||
} |
|||
|
|||
this.map.fitWorld(); |
|||
|
|||
this.geolocationForm.reset(undefined, { emitEvent: false, onlySelf: false }); |
|||
} |
|||
|
|||
if (fireEvent) { |
|||
this.changeCallback(this.value); |
|||
this.touchedCallback(); |
|||
} |
|||
} |
|||
} |
|||
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue