mirror of https://github.com/Squidex/squidex.git
34 changed files with 455 additions and 242 deletions
@ -0,0 +1,16 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Domain.Apps.Core.Schemas |
|||
{ |
|||
public enum TagsFieldEditor |
|||
{ |
|||
Tags, |
|||
Checkboxes, |
|||
Dropdown |
|||
} |
|||
} |
|||
@ -1,3 +1,58 @@ |
|||
<div [formGroup]="editForm"> |
|||
<span>Nothing to setup</span> |
|||
<div> |
|||
<div class="form-group row"> |
|||
<label class="col-3 col-form-label" for="{{field.fieldId}}_editorUrl">Editor Url</label> |
|||
|
|||
<div class="col-6"> |
|||
<input type="text" class="form-control" id="{{field.fieldId}}_editorUrl" formControlName="editorUrl" /> |
|||
|
|||
<small class="form-text text-muted"> |
|||
Url to your plugin if you use a custom editor. |
|||
</small> |
|||
</div> |
|||
</div> |
|||
<div class="form-group row"> |
|||
<label class="col-3 col-form-label" for="{{field.fieldId}}_fieldPlaceholder">Placeholder</label> |
|||
|
|||
<div class="col-6"> |
|||
<input type="text" class="form-control" id="{{field.fieldId}}_fieldPlaceholder" maxlength="100" formControlName="placeholder" /> |
|||
|
|||
<small class="form-text text-muted"> |
|||
Define the placeholder for the input control. |
|||
</small> |
|||
</div> |
|||
</div> |
|||
<div class="form-group row"> |
|||
<label class="col-3 col-form-label">Editor</label> |
|||
|
|||
<div class="col-9"> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls['editor'].value === 'Tags'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="Tags" /> |
|||
|
|||
<i class="icon-control-Input"></i> |
|||
|
|||
<span class="radio-label">Tags</span> |
|||
</label> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls['editor'].value === 'Dropdown'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="Dropdown" /> |
|||
|
|||
<i class="icon-control-Dropdown"></i> |
|||
|
|||
<span class="radio-label" clas>Dropdown</span> |
|||
</label> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls['editor'].value === 'Checkboxes'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="Checkboxes" /> |
|||
|
|||
<i class="icon-control-Checkboxes"></i> |
|||
|
|||
<span class="radio-label">Checkboxes</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
<div class="form-group row"> |
|||
<label class="col-3 col-form-label">Allowed Values</label> |
|||
|
|||
<div class="col-6"> |
|||
<sqx-tag-editor formControlName="allowedValues"></sqx-tag-editor> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,9 @@ |
|||
<span class="form-check" *ngFor="let value of values"> |
|||
<input type="checkbox" class="form-check-input" id="{{control}}{{value}}" |
|||
(blur)="blur()" |
|||
(change)="check($event.target.checked, value)" |
|||
[checked]="isChecked(value)" |
|||
[disabled]="isDisabled"> |
|||
|
|||
<label class="form-check-label" for="{{control}}{{value}}">{{value}}</label> |
|||
</span> |
|||
@ -0,0 +1,12 @@ |
|||
@import '_mixins'; |
|||
@import '_vars'; |
|||
|
|||
.form-check { |
|||
display: inline-block; |
|||
margin-left: 0; |
|||
margin-right: 1rem; |
|||
} |
|||
|
|||
.form-check-input { |
|||
margin-top: .4rem; |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core'; |
|||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; |
|||
|
|||
import { Types } from '@app/framework/internal'; |
|||
import { MathHelper } from '@app/shared'; |
|||
|
|||
export const SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR: any = { |
|||
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CheckboxGroupComponent), multi: true |
|||
}; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-checkbox-group', |
|||
styleUrls: ['./checkbox-group.component.scss'], |
|||
templateUrl: './checkbox-group.component.html', |
|||
providers: [SQX_CHECKBOX_GROUP_CONTROL_VALUE_ACCESSOR], |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class CheckboxGroupComponent implements ControlValueAccessor { |
|||
private callChange = (v: any) => { /* NOOP */ }; |
|||
private callTouched = () => { /* NOOP */ }; |
|||
private checkedValues: string[] = []; |
|||
|
|||
@Input() |
|||
public values: string[] = []; |
|||
|
|||
public isDisabled = false; |
|||
|
|||
public control = MathHelper.guid(); |
|||
|
|||
constructor( |
|||
private readonly changeDetector: ChangeDetectorRef |
|||
) { |
|||
} |
|||
|
|||
public writeValue(obj: any) { |
|||
this.checkedValues = Types.isArrayOfString(obj) ? obj.filter(x => this.values.indexOf(x) >= 0) : []; |
|||
|
|||
this.changeDetector.markForCheck(); |
|||
} |
|||
|
|||
public setDisabledState(isDisabled: boolean): void { |
|||
this.isDisabled = isDisabled; |
|||
|
|||
this.changeDetector.markForCheck(); |
|||
} |
|||
|
|||
public registerOnChange(fn: any) { |
|||
this.callChange = fn; |
|||
} |
|||
|
|||
public registerOnTouched(fn: any) { |
|||
this.callTouched = fn; |
|||
} |
|||
|
|||
public blur() { |
|||
this.callTouched(); |
|||
} |
|||
|
|||
public check(isChecked: boolean, value: string) { |
|||
if (isChecked) { |
|||
this.checkedValues = [value, ...this.checkedValues]; |
|||
} else { |
|||
this.checkedValues = this.checkedValues.filter(x => x !== value); |
|||
} |
|||
|
|||
this.callChange(this.checkedValues); |
|||
} |
|||
|
|||
public isChecked(value: string) { |
|||
return this.checkedValues.indexOf(value) >= 0; |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
<span> |
|||
<div class="selection"> |
|||
<input type="text" class="form-control" [disabled]="isDisabled" (click)="open()" readonly (keydown)="onKeyDown($event)" #input |
|||
autocomplete="off" |
|||
autocorrect="off" |
|||
autocapitalize="off"> |
|||
|
|||
<div class="control-dropdown-item" *ngIf="selectedItem"> |
|||
<ng-container *ngIf="!selectionTemplate">{{selectedItem}}</ng-container> |
|||
|
|||
<ng-template *ngIf="selectionTemplate" [sqxTemplateWrapper]="selectionTemplate" [item]="selectedItem"></ng-template> |
|||
</div> |
|||
|
|||
<i class="icon-caret-down"></i> |
|||
</div> |
|||
|
|||
<div class="items-container"> |
|||
<div class="control-dropdown" #container *sqxModalView="dropdown" [sqxModalTarget]="input" position="bottomLeft"> |
|||
<div *ngFor="let item of items; let i = index;" class="control-dropdown-item control-dropdown-item-selectable" [class.active]="i === selectedIndex" (mousedown)="selectIndexAndClose(i)" [sqxScrollActive]="i === selectedIndex" [container]="container"> |
|||
<ng-container *ngIf="!itemTemplate">{{item}}</ng-container> |
|||
|
|||
<ng-template *ngIf="itemTemplate" [sqxTemplateWrapper]="itemTemplate" [item]="item" [index]="i"></ng-template> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</span> |
|||
@ -1,38 +0,0 @@ |
|||
@import '_mixins'; |
|||
@import '_vars'; |
|||
|
|||
$color-input-disabled: #eef1f4; |
|||
|
|||
.form-control { |
|||
& { |
|||
width: 100%; |
|||
} |
|||
|
|||
&[readonly] { |
|||
background: $color-input-background; |
|||
} |
|||
|
|||
&:disabled { |
|||
background: $color-input-disabled; |
|||
} |
|||
} |
|||
|
|||
.selection { |
|||
& { |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.control-dropdown-item { |
|||
@include absolute(0, 1rem, 0, 0); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.icon-caret-down { |
|||
@include absolute(30%, .4rem, auto, auto); |
|||
cursor: pointer; |
|||
font-size: .9rem; |
|||
font-weight: normal; |
|||
pointer-events: none; |
|||
} |
|||
} |
|||
@ -1,149 +0,0 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, forwardRef, Input, QueryList, TemplateRef } from '@angular/core'; |
|||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; |
|||
|
|||
const KEY_ENTER = 13; |
|||
const KEY_ESCAPE = 27; |
|||
const KEY_UP = 38; |
|||
const KEY_DOWN = 40; |
|||
|
|||
import { ModalModel } from '@app/framework/internal'; |
|||
|
|||
export const SQX_DROPDOWN_CONTROL_VALUE_ACCESSOR: any = { |
|||
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DropdownComponent), multi: true |
|||
}; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-dropdown', |
|||
styleUrls: ['./dropdown.component.scss'], |
|||
templateUrl: './dropdown.component.html', |
|||
providers: [SQX_DROPDOWN_CONTROL_VALUE_ACCESSOR], |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class DropdownComponent implements AfterContentInit, ControlValueAccessor { |
|||
private callChange = (v: any) => { /* NOOP */ }; |
|||
private callTouched = () => { /* NOOP */ }; |
|||
|
|||
@Input() |
|||
public items: any[] = []; |
|||
|
|||
@ContentChildren(TemplateRef) |
|||
public templates: QueryList<any>; |
|||
|
|||
public dropdown = new ModalModel(); |
|||
|
|||
public selectedItem: any; |
|||
public selectedIndex = -1; |
|||
public selectionTemplate: TemplateRef<any>; |
|||
|
|||
public itemTemplate: TemplateRef<any>; |
|||
|
|||
public isDisabled = false; |
|||
|
|||
constructor( |
|||
private readonly changeDetector: ChangeDetectorRef |
|||
) { |
|||
} |
|||
|
|||
public ngAfterContentInit() { |
|||
if (this.templates.length === 1) { |
|||
this.itemTemplate = this.selectionTemplate = this.templates.first; |
|||
} else { |
|||
this.templates.forEach(template => { |
|||
if (template.name === 'selection') { |
|||
this.selectionTemplate = template; |
|||
} else { |
|||
this.itemTemplate = template; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public writeValue(obj: any) { |
|||
this.selectIndex(this.items && obj ? this.items.indexOf(obj) : 0); |
|||
|
|||
this.changeDetector.markForCheck(); |
|||
} |
|||
|
|||
public setDisabledState(isDisabled: boolean): void { |
|||
this.isDisabled = isDisabled; |
|||
|
|||
this.changeDetector.markForCheck(); |
|||
} |
|||
|
|||
public registerOnChange(fn: any) { |
|||
this.callChange = fn; |
|||
} |
|||
|
|||
public registerOnTouched(fn: any) { |
|||
this.callTouched = fn; |
|||
} |
|||
|
|||
public onKeyDown(event: KeyboardEvent) { |
|||
switch (event.keyCode) { |
|||
case KEY_UP: |
|||
this.up(); |
|||
return false; |
|||
case KEY_DOWN: |
|||
this.down(); |
|||
return false; |
|||
case KEY_ESCAPE: |
|||
case KEY_ENTER: |
|||
if (this.dropdown.isOpen) { |
|||
this.close(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public open() { |
|||
this.dropdown.show(); |
|||
this.callTouched(); |
|||
} |
|||
|
|||
public selectIndexAndClose(selectedIndex: number) { |
|||
this.selectIndex(selectedIndex); |
|||
this.close(); |
|||
} |
|||
|
|||
private close() { |
|||
this.dropdown.hide(); |
|||
} |
|||
|
|||
private up() { |
|||
this.selectIndex(this.selectedIndex - 1); |
|||
} |
|||
|
|||
private down() { |
|||
this.selectIndex(this.selectedIndex + 1); |
|||
} |
|||
|
|||
private selectIndex(selectedIndex: number) { |
|||
if (selectedIndex < 0) { |
|||
selectedIndex = 0; |
|||
} |
|||
|
|||
const items = this.items || []; |
|||
|
|||
if (selectedIndex >= items.length) { |
|||
selectedIndex = items.length - 1; |
|||
} |
|||
|
|||
const value = items[selectedIndex]; |
|||
|
|||
if (value !== this.selectedItem) { |
|||
this.selectedIndex = selectedIndex; |
|||
this.selectedItem = value; |
|||
|
|||
this.callChange(value); |
|||
} |
|||
} |
|||
} |
|||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 81 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue