mirror of https://github.com/Squidex/squidex.git
30 changed files with 639 additions and 85 deletions
@ -0,0 +1,106 @@ |
|||
<div class="table-items-row"> |
|||
<div class="field-summary"> |
|||
<div class="row"> |
|||
<div class="col-xs-8"> |
|||
{{field.name}} |
|||
</div> |
|||
<div class="col-xs-4"> |
|||
<div class="float-xs-right"> |
|||
<button type="button" class="btn btn-secondary field-edit-button" [class.active]="isEditing" (click)="toggleEditing()"> |
|||
<i class="icon-settings"></i> |
|||
</button> |
|||
<button type="button" class="btn btn-simple"> |
|||
<i class="icon-dots"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="field-details" *ngIf="isEditing"> |
|||
<form [formGroup]="editForm" (submit)="save()"> |
|||
<div class="field-details-tabs clearfix"> |
|||
<ul class="nav nav-inline nav-field-tabs"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" (click)="selectTab(0)" [class.active]="selectedTab === 0">Common</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" (click)="selectTab(1)" [class.active]="selectedTab === 1">Validation</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" (click)="selectTab(2)" [class.active]="selectedTab === 2">User Interface</a> |
|||
</li> |
|||
</ul> |
|||
|
|||
<div class="float-xs-right"> |
|||
<button type="reset" class="btn btn-link" (click)="cancel()">Cancel</button> |
|||
<button type="submit" class="btn btn-primary">Save</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="field-details-tab" *ngIf="selectedTab == 0"> |
|||
<div class="form-group row"> |
|||
<label for="field-label" class="col-xs-3 col-form-label">Label</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<div class="errors-box" *ngIf="editForm.get('label').invalid && editForm.get('label').touched" [@fade]> |
|||
<div class="errors"> |
|||
<span *ngIf="editForm.get('label').hasError('maxlength')"> |
|||
Label can not have more than 100 characters. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<input type="text" class="form-control" id="field-label" maxlength="100" formControlName="label" /> |
|||
|
|||
<span class="form-hint"> |
|||
Define the display name for the field for documentation and user interfaces. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label for="field-hints" class="col-xs-3 col-form-label">Hints</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<div class="errors-box" *ngIf="editForm.get('hints').invalid && editForm.get('hints').touched" [@fade]> |
|||
<div class="errors"> |
|||
<span *ngIf="editForm.get('hints').hasError('maxlength')"> |
|||
Hints can not have more than 100 characters. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<input type="text" class="form-control" id="field-hints" maxlength="100" formControlName="hints" /> |
|||
|
|||
<span class="form-hint"> |
|||
Define some hints for the user and editor for the field for documentation and user interfaces. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="field-details-tab" *ngIf="selectedTab == 1"> |
|||
<div [ngSwitch]="field.properties.fieldType"> |
|||
<div *ngSwitchCase="'number'"> |
|||
asdsad |
|||
</div> |
|||
<div *ngSwitchCase="'string'"> |
|||
<sqx-string-validation [editForm]="editForm" [properties]="field.properties"></sqx-string-validation> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="field-details-tab" *ngIf="selectedTab == 2"> |
|||
<div [ngSwitch]="field.properties.fieldType"> |
|||
<div *ngSwitchCase="'number'"> |
|||
asdsad |
|||
</div> |
|||
<div *ngSwitchCase="'string'"> |
|||
<sqx-string-ui [editForm]="editForm" [properties]="field.properties"></sqx-string-ui> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,78 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
$field-header: #e7ebef; |
|||
|
|||
.table-items-row { |
|||
padding: 0; |
|||
} |
|||
|
|||
.field { |
|||
&-summary { |
|||
padding: 15px 20px; |
|||
line-height: 40px; |
|||
} |
|||
|
|||
&-edit-button { |
|||
& { |
|||
color: $color-theme-blue; |
|||
} |
|||
|
|||
&:hover { |
|||
color: $color-theme-blue-dark; |
|||
} |
|||
|
|||
&.active { |
|||
background: $color-theme-blue; |
|||
border: 0; |
|||
color: $color-accent-dark; |
|||
} |
|||
} |
|||
|
|||
&-details { |
|||
& { |
|||
position: relative; |
|||
} |
|||
|
|||
&::before { |
|||
@include caret-top; |
|||
@include absolute(-10px, 90px, auto, auto); |
|||
border-color: transparent transparent $color-border; |
|||
border-width: 10px; |
|||
} |
|||
|
|||
&-tab { |
|||
padding: 15px 20px 20px; |
|||
} |
|||
|
|||
&-tabs { |
|||
background: $color-border; |
|||
position: relative; |
|||
padding: 15px 20px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.nav-field-tabs { |
|||
& { |
|||
@include absolute(auto, auto, 0, 20px); |
|||
} |
|||
|
|||
& .nav-link { |
|||
& { |
|||
color: $color-text; |
|||
cursor: pointer; |
|||
padding: 18px 10px; |
|||
border-bottom: 4px solid transparent; |
|||
} |
|||
|
|||
&.active { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
&.active, |
|||
&:hover { |
|||
border-color: $color-theme-blue; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,109 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { Observable} from 'rxjs'; |
|||
import { |
|||
createProperties, |
|||
fadeAnimation, |
|||
FieldDto, |
|||
FieldPropertiesDto |
|||
} from 'shared'; |
|||
|
|||
const ESCAPE_KEY = 27; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-field', |
|||
styleUrls: ['./field.component.scss'], |
|||
templateUrl: './field.component.html', |
|||
animations: [ |
|||
fadeAnimation |
|||
] |
|||
}) |
|||
export class FieldComponent implements OnInit { |
|||
private oldValue: any; |
|||
|
|||
@Input() |
|||
public field: FieldDto; |
|||
|
|||
@Output() |
|||
public saved = new EventEmitter<FieldDto>(); |
|||
|
|||
public isEditing: boolean = false; |
|||
public selectedTab = 0; |
|||
|
|||
public editForm: FormGroup = |
|||
this.formBuilder.group({ |
|||
label: ['', |
|||
[ |
|||
Validators.maxLength(100) |
|||
]], |
|||
hints: ['', |
|||
[ |
|||
Validators.maxLength(100) |
|||
]], |
|||
isRequired: [false] |
|||
}); |
|||
|
|||
constructor( |
|||
private readonly formBuilder: FormBuilder |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.resetForm(this.field.properties); |
|||
} |
|||
|
|||
public save() { |
|||
this.editForm.markAsTouched(); |
|||
|
|||
if (this.editForm.valid) { |
|||
const properties = createProperties(this.field.properties['fieldType'], this.editForm.value); |
|||
|
|||
const field = |
|||
new FieldDto( |
|||
this.field.name, |
|||
this.field.isHidden, |
|||
this.field.isHidden, |
|||
properties); |
|||
|
|||
this.saved.emit(field); |
|||
} |
|||
} |
|||
|
|||
public cancel() { |
|||
this.resetForm(this.oldValue); |
|||
} |
|||
|
|||
public toggleEditing() { |
|||
this.isEditing = true; |
|||
} |
|||
|
|||
public selectTab(tab: number) { |
|||
this.selectedTab = tab; |
|||
} |
|||
|
|||
private resetForm(properties: any) { |
|||
this.editForm.reset(); |
|||
|
|||
for (let property in properties) { |
|||
if (properties.hasOwnProperty(property)) { |
|||
const controlName = property + ''; |
|||
|
|||
if (this.editForm.contains(controlName)) { |
|||
this.editForm.get(controlName).setValue(properties[property]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
this.oldValue = Object.assign({}, this.editForm.value); |
|||
|
|||
this.isEditing = false; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,21 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label for="field-input-placeholder" class="col-xs-3 col-form-label">Placeholder</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<div class="errors-box" *ngIf="editForm.get('placeholder').invalid && editForm.get('placeholder').touched" [@fade]> |
|||
<div class="errors"> |
|||
<span *ngIf="editForm.get('placeholder').hasError('maxlength')"> |
|||
Placeholder can not have more than 100 characters. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<input type="text" class="form-control" id="field-input-placeholder" maxlength="100" formControlName="placeholder" /> |
|||
|
|||
<span class="form-hint"> |
|||
Define the placeholder for the input control. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,2 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
@ -0,0 +1,34 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input, OnInit } from '@angular/core'; |
|||
import { FormControl, FormGroup, Validators } from '@angular/forms'; |
|||
|
|||
import { fadeAnimation, StringFieldPropertiesDto } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-string-ui', |
|||
styleUrls: ['string-ui.component.scss'], |
|||
templateUrl: 'string-ui.component.html', |
|||
animations: [ |
|||
fadeAnimation |
|||
] |
|||
}) |
|||
export class StringUIComponent implements OnInit { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: StringFieldPropertiesDto; |
|||
|
|||
public ngOnInit() { |
|||
this.editForm.addControl('placeholder', |
|||
new FormControl('', [ |
|||
Validators.maxLength(100) |
|||
])); |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label for="field-required" class="col-xs-3">Required</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<input type="checkbox" class="form-check-input" id="field-required" formControlName="isRequired" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col-xs-3 col-form-label">Length</label> |
|||
|
|||
<div class="col-xs-3 minlength-col"> |
|||
<input type="number" class="form-control" id="field-min-length" formControlName="minLength" placeholder="Min Length" /> |
|||
|
|||
<label class="col-form-label minlength-label">-</label> |
|||
</div> |
|||
<div class="col-xs-3"> |
|||
<input type="number" class="form-control" id="field-max-length" formControlName="maxLength" placeholder="Max Length" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col-xs-3 col-form-label" for="field-pattern">Pattern</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<input type="text" class="form-control" id="field-pattern" formControlName="pattern" placeholder="Regex Pattern" /> |
|||
</div> |
|||
</div> |
|||
<div class="form-group row" [class.hide]="hidePatternMessage | async"> |
|||
<label class="col-xs-3 col-form-label" for="field-pattern-message">Pattern Message</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<input type="text" class="form-control" id="field-pattern-message" formControlName="patternMessage" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row" [class.hide]="(hideDefaultValue | async)"> |
|||
<label class="col-xs-3 col-form-label" for="field-default-value">Default Value</label> |
|||
|
|||
<div class="col-xs-6"> |
|||
<input type="text" class="form-control" id="field-default-value" formControlName="defaultValue" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,16 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.minlength { |
|||
&-col { |
|||
position: relative; |
|||
} |
|||
|
|||
&-label { |
|||
@include absolute(0, -4px, auto, auto); |
|||
} |
|||
} |
|||
|
|||
.form-check-input { |
|||
margin: 0; |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input, OnInit } from '@angular/core'; |
|||
import { FormControl, FormGroup } from '@angular/forms'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { StringFieldPropertiesDto } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-string-validation', |
|||
styleUrls: ['string-validation.component.scss'], |
|||
templateUrl: 'string-validation.component.html' |
|||
}) |
|||
export class StringValidationComponent implements OnInit { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: StringFieldPropertiesDto; |
|||
|
|||
public hidePatternMessage: Observable<boolean>; |
|||
public hideDefaultValue: Observable<boolean>; |
|||
|
|||
public ngOnInit() { |
|||
this.editForm.addControl('maxLength', |
|||
new FormControl()); |
|||
this.editForm.addControl('minLength', |
|||
new FormControl()); |
|||
this.editForm.addControl('pattern', |
|||
new FormControl()); |
|||
this.editForm.addControl('patternMessage', |
|||
new FormControl()); |
|||
this.editForm.addControl('defaultValue', |
|||
new FormControl()); |
|||
|
|||
this.hideDefaultValue = |
|||
Observable.of(false) |
|||
.merge(this.editForm.get('isRequired').valueChanges) |
|||
.map(x => !!x); |
|||
|
|||
this.hidePatternMessage = |
|||
Observable.of(false) |
|||
.merge(this.editForm.get('pattern').valueChanges) |
|||
.map(x => !x || x.trim().length === 0); |
|||
} |
|||
} |
|||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue