diff --git a/src/Squidex/app/features/content/pages/content/content-field.component.html b/src/Squidex/app/features/content/pages/content/content-field.component.html index 20f661428..12eafe95b 100644 --- a/src/Squidex/app/features/content/pages/content/content-field.component.html +++ b/src/Squidex/app/features/content/pages/content/content-field.component.html @@ -58,7 +58,7 @@ - + diff --git a/src/Squidex/app/features/content/shared/content-item.component.html b/src/Squidex/app/features/content/shared/content-item.component.html index b95d7c688..26f7f064a 100644 --- a/src/Squidex/app/features/content/shared/content-item.component.html +++ b/src/Squidex/app/features/content/shared/content-item.component.html @@ -27,7 +27,7 @@
- +
+ The schema name becomes part of the api url,
e.g {{apiUrl.buildUrl("api/content/")}}{{appsState.appName}}/{{createForm.schemaName | async}}/. diff --git a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html index d33e5fd2a..ab463d7dd 100644 --- a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html +++ b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html @@ -27,7 +27,7 @@
- +
diff --git a/src/Squidex/app/framework/angular/forms/file-drop.directive.ts b/src/Squidex/app/framework/angular/forms/file-drop.directive.ts index 52cc95610..0238b1e04 100644 --- a/src/Squidex/app/framework/angular/forms/file-drop.directive.ts +++ b/src/Squidex/app/framework/angular/forms/file-drop.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Directive, ElementRef, EventEmitter, HostListener, Output, Renderer } from '@angular/core'; +import { Directive, ElementRef, EventEmitter, HostListener, Output, Renderer2 } from '@angular/core'; @Directive({ selector: '[sqxFileDrop]' @@ -18,7 +18,7 @@ export class FileDropDirective { constructor( private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -71,7 +71,7 @@ export class FileDropDirective { this.dragCounter++; if (this.dragCounter === 1) { - this.renderer.setElementClass(this.element.nativeElement, 'drag', true); + this.renderer.addClass(this.element.nativeElement, 'drag'); } } @@ -79,7 +79,7 @@ export class FileDropDirective { this.dragCounter = number || this.dragCounter - 1; if (this.dragCounter === 0) { - this.renderer.setElementClass(this.element.nativeElement, 'drag', false); + this.renderer.removeClass(this.element.nativeElement, 'drag'); } } diff --git a/src/Squidex/app/framework/angular/forms/focus-on-init.directive.spec.ts b/src/Squidex/app/framework/angular/forms/focus-on-init.directive.spec.ts index a5a47d69d..ec13649f4 100644 --- a/src/Squidex/app/framework/angular/forms/focus-on-init.directive.spec.ts +++ b/src/Squidex/app/framework/angular/forms/focus-on-init.directive.spec.ts @@ -5,33 +5,51 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { ElementRef, Renderer } from '@angular/core'; +import { ElementRef } from '@angular/core'; import { FocusOnInitDirective } from './focus-on-init.directive'; describe('FocusOnInitDirective', () => { + let isFocusCalled = false; + let isSelectCalled = false; + + const element: ElementRef = { + nativeElement: { + focus: () => { + isFocusCalled = true; + }, + select: () => { + isSelectCalled = true; + } + } + }; + + beforeEach(() => { + isFocusCalled = false; + isSelectCalled = false; + }); + it('should call focus on element when init', (cb) => { - const calledMethods: string[] = []; - const calledElements: any[] = []; + const directive = new FocusOnInitDirective(element); + directive.select = false; + directive.ngAfterViewInit(); - const renderer = { - invokeElementMethod: (elem: any, method: any) => { - calledElements.push(elem); - calledMethods.push(method); - } - }; + setTimeout(() => { + expect(isFocusCalled).toBeTruthy(); + expect(isSelectCalled).toBeFalsy(); - const element: ElementRef = { - nativeElement: {} - }; + cb(); + }, 200); + }); - const directive = new FocusOnInitDirective(element, renderer as Renderer); + it('should call select on element when init', (cb) => { + const directive = new FocusOnInitDirective(element); directive.select = true; directive.ngAfterViewInit(); setTimeout(() => { - expect(calledMethods).toEqual(['focus', 'select']); - expect(calledElements).toEqual([element.nativeElement, element.nativeElement]); + expect(isFocusCalled).toBeTruthy(); + expect(isSelectCalled).toBeTruthy(); cb(); }, 200); diff --git a/src/Squidex/app/framework/angular/forms/focus-on-init.directive.ts b/src/Squidex/app/framework/angular/forms/focus-on-init.directive.ts index 1a3cbcc3a..954888fb4 100644 --- a/src/Squidex/app/framework/angular/forms/focus-on-init.directive.ts +++ b/src/Squidex/app/framework/angular/forms/focus-on-init.directive.ts @@ -5,7 +5,9 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, Input, Renderer } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, Input } from '@angular/core'; + +import { Types } from '@app/framework/internal'; @Directive({ selector: '[sqxFocusOnInit]' @@ -15,17 +17,20 @@ export class FocusOnInitDirective implements AfterViewInit { public select: boolean; constructor( - private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly element: ElementRef ) { } public ngAfterViewInit() { setTimeout(() => { - this.renderer.invokeElementMethod(this.element.nativeElement, 'focus', []); + if (Types.isFunction(this.element.nativeElement.focus)) { + this.element.nativeElement.focus(); + } if (this.select) { - this.renderer.invokeElementMethod(this.element.nativeElement, 'select', []); + if (Types.isFunction(this.element.nativeElement.select)) { + this.element.nativeElement.select(); + } } }, 100); } diff --git a/src/Squidex/app/framework/angular/forms/iframe-editor.component.ts b/src/Squidex/app/framework/angular/forms/iframe-editor.component.ts index 2074eada1..503c9bd63 100644 --- a/src/Squidex/app/framework/angular/forms/iframe-editor.component.ts +++ b/src/Squidex/app/framework/angular/forms/iframe-editor.component.ts @@ -5,10 +5,12 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, Renderer, ViewChild } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { DomSanitizer } from '@angular/platform-browser'; +import { Types } from '@app/framework/internal'; + export const SQX_IFRAME_EDITOR_CONTROL_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IFrameEditorComponent), multi: true }; @@ -38,7 +40,7 @@ export class IFrameEditorComponent implements ControlValueAccessor, AfterViewIni constructor( private readonly sanitizer: DomSanitizer, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -52,14 +54,14 @@ export class IFrameEditorComponent implements ControlValueAccessor, AfterViewIni public ngOnInit(): void { this.windowMessageListener = - this.renderer.listenGlobal('window', 'message', (event: MessageEvent) => { + this.renderer.listen('window', 'message', (event: MessageEvent) => { if (event.source === this.plugin.contentWindow) { const { type } = event.data; if (type === 'started') { this.isInitialized = true; - if (this.plugin.contentWindow) { + if (this.plugin.contentWindow && Types.isFunction(this.plugin.contentWindow.postMessage)) { this.plugin.contentWindow.postMessage({ type: 'disabled', disabled: this.isDisabled }, '*'); this.plugin.contentWindow.postMessage({ type: 'valueChanged', value: this.value }, '*'); } @@ -93,7 +95,7 @@ export class IFrameEditorComponent implements ControlValueAccessor, AfterViewIni this.value = value; this.valueJson = JSON.stringify(value); - if (this.isInitialized && this.plugin.contentWindow) { + if (this.isInitialized && this.plugin.contentWindow && Types.isFunction(this.plugin.contentWindow.postMessage)) { this.plugin.contentWindow.postMessage({ type: 'valueChanged', value: this.value }, '*'); } } @@ -101,7 +103,7 @@ export class IFrameEditorComponent implements ControlValueAccessor, AfterViewIni public setDisabledState(isDisabled: boolean): void { this.isDisabled = isDisabled; - if (this.isInitialized && this.plugin.contentWindow) { + if (this.isInitialized && this.plugin.contentWindow && Types.isFunction(this.plugin.contentWindow.postMessage)) { this.plugin.contentWindow.postMessage({ type: 'disabled', disabled: this.isDisabled }, '*'); } } diff --git a/src/Squidex/app/framework/angular/forms/indeterminate-value.directive.ts b/src/Squidex/app/framework/angular/forms/indeterminate-value.directive.ts index bbe7d7d7e..61ff1c5b8 100644 --- a/src/Squidex/app/framework/angular/forms/indeterminate-value.directive.ts +++ b/src/Squidex/app/framework/angular/forms/indeterminate-value.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Directive, ElementRef, forwardRef, HostListener, Renderer } from '@angular/core'; +import { Directive, ElementRef, forwardRef, HostListener, Renderer2 } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Types } from '@app/framework/internal'; @@ -23,8 +23,8 @@ export class IndeterminateValueDirective implements ControlValueAccessor { private callTouched = () => { /* NOOP */ }; constructor( - private readonly renderer: Renderer, - private readonly element: ElementRef + private readonly element: ElementRef, + private readonly renderer: Renderer2 ) { } @@ -40,16 +40,16 @@ export class IndeterminateValueDirective implements ControlValueAccessor { public writeValue(value: boolean | number | undefined) { if (!Types.isBoolean(value)) { - this.renderer.setElementProperty(this.element.nativeElement, 'indeterminate', true); - this.renderer.setElementProperty(this.element.nativeElement, 'checked', false); + this.renderer.setProperty(this.element.nativeElement, 'indeterminate', true); + this.renderer.setProperty(this.element.nativeElement, 'checked', false); } else { - this.renderer.setElementProperty(this.element.nativeElement, 'indeterminate', false); - this.renderer.setElementProperty(this.element.nativeElement, 'checked', value); + this.renderer.setProperty(this.element.nativeElement, 'indeterminate', false); + this.renderer.setProperty(this.element.nativeElement, 'checked', value); } } public setDisabledState(isDisabled: boolean): void { - this.renderer.setElementProperty(this.element.nativeElement, 'disabled', isDisabled); + this.renderer.setProperty(this.element.nativeElement, 'disabled', isDisabled); } public registerOnChange(fn: any) { diff --git a/src/Squidex/app/framework/angular/forms/lowercase-input.directive.ts b/src/Squidex/app/framework/angular/forms/lowercase-input.directive.ts deleted file mode 100644 index 982ddc703..000000000 --- a/src/Squidex/app/framework/angular/forms/lowercase-input.directive.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Squidex Headless CMS - * - * @license - * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. - */ - -import { Directive, ElementRef, forwardRef, HostListener, Renderer } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -import { Types } from '@app/framework/internal'; - -export const SQX_LOWERCASE_INPUT_VALUE_ACCESSOR: any = { - provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => LowerCaseInputDirective), multi: true -}; - -@Directive({ - selector: '[sqxLowerCaseInput]', - providers: [SQX_LOWERCASE_INPUT_VALUE_ACCESSOR] -}) -export class LowerCaseInputDirective implements ControlValueAccessor { - private callChange = (v: any) => { /* NOOP */ }; - private callTouched = () => { /* NOOP */ }; - - constructor( - private readonly element: ElementRef, - private readonly renderer: Renderer - ) { - } - - @HostListener('input', ['$event.target.value']) - public onChange(value: any) { - const normalizedValue = this.transform(value); - - this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue); - this.callChange(normalizedValue); - } - - @HostListener('blur') - public onTouched() { - this.callTouched(); - } - - public writeValue(value: string) { - const normalizedValue = this.transform(value); - - this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue); - } - - public setDisabledState(isDisabled: boolean): void { - this.renderer.setElementProperty(this.element.nativeElement, 'disabled', isDisabled); - } - - public registerOnChange(fn: any) { - this.callChange = fn; - } - - public registerOnTouched(fn: any) { - this.callTouched = fn; - } - - private transform(value: any): string { - return Types.isString(value) ? value.toLowerCase() : ''; - } -} \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/forms/progress-bar.component.ts b/src/Squidex/app/framework/angular/forms/progress-bar.component.ts index ac769399b..31d6f3dee 100644 --- a/src/Squidex/app/framework/angular/forms/progress-bar.component.ts +++ b/src/Squidex/app/framework/angular/forms/progress-bar.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, ElementRef, Input, OnChanges, OnInit, Renderer, SimpleChanges } from '@angular/core'; +import { Component, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChanges } from '@angular/core'; const ProgressBar = require('progressbar.js'); @@ -36,7 +36,7 @@ export class ProgressBarComponent implements OnChanges, OnInit { constructor( private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -48,7 +48,7 @@ export class ProgressBarComponent implements OnChanges, OnInit { strokeWidth: this.strokeWidth }; - this.renderer.setElementStyle(this.element.nativeElement, 'display', 'block'); + this.renderer.setStyle(this.element.nativeElement, 'display', 'block'); if (this.mode === 'Circle') { this.progressBar = new ProgressBar.Circle(this.element.nativeElement, options); diff --git a/src/Squidex/app/framework/angular/forms/slider.component.ts b/src/Squidex/app/framework/angular/forms/slider.component.ts index 84d363565..23dc9905b 100644 --- a/src/Squidex/app/framework/angular/forms/slider.component.ts +++ b/src/Squidex/app/framework/angular/forms/slider.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, ElementRef, forwardRef, Input, Renderer, ViewChild } from '@angular/core'; +import { Component, ElementRef, forwardRef, Input, Renderer2, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Types } from '@app/framework/internal'; @@ -47,7 +47,7 @@ export class SliderComponent implements ControlValueAccessor { @Input() public step = 1; - constructor(private readonly renderer: Renderer) { } + constructor(private readonly renderer: Renderer2) { } public writeValue(value: number) { this.lastValue = this.value = Types.isNumber(value) ? value : 0; @@ -87,16 +87,16 @@ export class SliderComponent implements ControlValueAccessor { this.centerStartOffset = event.offsetX - this.thumb.nativeElement.clientWidth * 0.5; this.windowMouseMoveListener = - this.renderer.listenGlobal('window', 'mousemove', (e: MouseEvent) => { + this.renderer.listen('window', 'mousemove', (e: MouseEvent) => { this.onMouseMove(e); }); this.windowMouseUpListener = - this.renderer.listenGlobal('window', 'mouseup', () => { + this.renderer.listen('window', 'mouseup', () => { this.onMouseUp(); }); - this.renderer.setElementClass(this.thumb.nativeElement, 'focused', true); + this.renderer.addClass(this.thumb.nativeElement, 'focused'); this.isDragging = true; @@ -123,7 +123,7 @@ export class SliderComponent implements ControlValueAccessor { setTimeout(() => { this.releaseMouseHandlers(); - this.renderer.setElementClass(this.thumb.nativeElement, 'focused', false); + this.renderer.removeClass(this.thumb.nativeElement, 'focused'); }, 10); this.centerStartOffset = 0; @@ -168,7 +168,7 @@ export class SliderComponent implements ControlValueAccessor { private updateThumbPosition() { const relativeValue = Math.min(1, Math.max(0, (this.value - this.min) / (this.max - this.min))); - this.renderer.setElementStyle(this.thumb.nativeElement, 'left', relativeValue * 100 + '%'); + this.renderer.setStyle(this.thumb.nativeElement, 'left', relativeValue * 100 + '%'); } private releaseMouseHandlers() { diff --git a/src/Squidex/app/framework/angular/forms/slugify-input.directive.ts b/src/Squidex/app/framework/angular/forms/slugify-input.directive.ts deleted file mode 100644 index 0a77d763d..000000000 --- a/src/Squidex/app/framework/angular/forms/slugify-input.directive.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Squidex Headless CMS - * - * @license - * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. - */ - -import { Directive, ElementRef, forwardRef, HostListener, Renderer } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -import slugify from 'slugify'; - -import { Types } from '@app/framework/internal'; - -export const SQX_SLUGIFY_INPUT_VALUE_ACCESSOR: any = { - provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SlugifyInputDirective), multi: true -}; - -@Directive({ - selector: '[sqxSlugifyInput]', - providers: [SQX_SLUGIFY_INPUT_VALUE_ACCESSOR] -}) -export class SlugifyInputDirective implements ControlValueAccessor { - private callChange = (v: any) => { /* NOOP */ }; - private callTouched = () => { /* NOOP */ }; - - constructor( - private readonly element: ElementRef, - private readonly renderer: Renderer - ) { - } - - @HostListener('input', ['$event.target.value']) - public onChange(value: any) { - const normalizedValue = this.transform(value); - - this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue); - this.callChange(normalizedValue); - } - - @HostListener('blur') - public onTouched() { - this.callTouched(); - } - - public writeValue(value: string) { - const normalizedValue = this.transform(value); - - this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue); - } - - public setDisabledState(isDisabled: boolean): void { - this.renderer.setElementProperty(this.element.nativeElement, 'disabled', isDisabled); - } - - public registerOnChange(fn: any) { - this.callChange = fn; - } - - public registerOnTouched(fn: any) { - this.callTouched = fn; - } - - private transform(value: any): string { - return Types.isString(value) ? slugify(value, { lower: true }) : ''; - } -} \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/forms/transform-input.directive.ts b/src/Squidex/app/framework/angular/forms/transform-input.directive.ts new file mode 100644 index 000000000..34683bac4 --- /dev/null +++ b/src/Squidex/app/framework/angular/forms/transform-input.directive.ts @@ -0,0 +1,94 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Directive, ElementRef, forwardRef, HostListener, Input, Renderer2 } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; + +import slugify from 'slugify'; + +type Transform = (value: string) => string; + +export const TransformNoop: Transform = value => value; +export const TransformLowerCase: Transform = value => value.toLowerCase(); +export const TransformSlugify: Transform = value => slugify(value, { lower: true }); +export const TransformSlugifyCased: Transform = value => slugify(value, { lower: false }); +export const TransformUpperCase: Transform = value => value.toUpperCase(); + +import { Types } from '@app/framework/internal'; + +export const SQX_TRANSFORM_INPUT_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TransformInputDirective), multi: true +}; + +@Directive({ + selector: '[sqxTransformInput]', + providers: [SQX_TRANSFORM_INPUT_VALUE_ACCESSOR] +}) +export class TransformInputDirective implements ControlValueAccessor { + private callChange = (v: any) => { /* NOOP */ }; + private callTouched = () => { /* NOOP */ }; + private transformer: Transform; + + @Input('sqxTransformInput') + public set transform(value: Transform | string) { + if (Types.isString(value)) { + if (value === 'LowerCase') { + this.transformer = TransformLowerCase; + } else if (value === 'Slugify') { + this.transform = TransformSlugify; + } else if (value === 'SlugifyCased') { + this.transform = TransformSlugifyCased; + } else if (value === 'UpperCase') { + this.transform = TransformUpperCase; + } + } else { + this.transformer = value || TransformNoop; + } + } + + constructor( + private readonly element: ElementRef, + private readonly renderer: Renderer2 + ) { + } + + @HostListener('input', ['$event.target.value']) + public onChange(value: any) { + const normalizedValue = this.transformValue(value); + + this.renderer.setProperty(this.element.nativeElement, 'value', normalizedValue); + + this.callChange(normalizedValue); + } + + @HostListener('blur') + public onTouched() { + this.callTouched(); + } + + public writeValue(value: string) { + const normalizedValue = this.transformValue(value); + + this.renderer.setProperty(this.element.nativeElement, 'value', normalizedValue); + } + + public setDisabledState(isDisabled: boolean): void { + this.renderer.setProperty(this.element.nativeElement, 'disabled', isDisabled); + } + + public registerOnChange(fn: any) { + this.callChange = fn; + } + + public registerOnTouched(fn: any) { + this.callTouched = fn; + } + + private transformValue(value: any): string { + return Types.isString(value) ? this.transformer(value) : ''; + } +} \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/ignore-scrollbar.directive.ts b/src/Squidex/app/framework/angular/ignore-scrollbar.directive.ts index 65f09de73..2174b14cc 100644 --- a/src/Squidex/app/framework/angular/ignore-scrollbar.directive.ts +++ b/src/Squidex/app/framework/angular/ignore-scrollbar.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, OnDestroy, OnInit, Renderer2 } from '@angular/core'; @Directive({ selector: '[sqxIgnoreScrollbar]' @@ -18,7 +18,7 @@ export class IgnoreScrollbarDirective implements OnDestroy, OnInit, AfterViewIni constructor( private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -61,7 +61,7 @@ export class IgnoreScrollbarDirective implements OnDestroy, OnInit, AfterViewIni if (scrollbarWidth !== this.scollbarWidth) { this.scollbarWidth = scrollbarWidth; - this.renderer.setElementStyle(this.element.nativeElement, 'marginRight', `-${scrollbarWidth}px`); + this.renderer.setStyle(this.element.nativeElement, 'marginRight', `-${scrollbarWidth}px`); } } } \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/image-source.directive.ts b/src/Squidex/app/framework/angular/image-source.directive.ts index 5cacfe5ba..d525fc6cc 100644 --- a/src/Squidex/app/framework/angular/image-source.directive.ts +++ b/src/Squidex/app/framework/angular/image-source.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { MathHelper } from './../utils/math-helper'; @@ -31,7 +31,7 @@ export class ImageSourceDirective implements OnChanges, OnDestroy, OnInit, After constructor( private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -65,12 +65,12 @@ export class ImageSourceDirective implements OnChanges, OnDestroy, OnInit, After @HostListener('load') public onLoad() { - this.renderer.setElementStyle(this.element.nativeElement, 'visibility', 'visible'); + this.renderer.setStyle(this.element.nativeElement, 'visibility', 'visible'); } @HostListener('error') public onError() { - this.renderer.setElementStyle(this.element.nativeElement, 'visibility', 'hidden'); + this.renderer.setStyle(this.element.nativeElement, 'visibility', 'hidden'); this.retryLoadingImage(); } @@ -78,9 +78,9 @@ export class ImageSourceDirective implements OnChanges, OnDestroy, OnInit, After private resize(parent: any) { this.size = this.parent.getBoundingClientRect(); - this.renderer.setElementStyle(this.element.nativeElement, 'display', 'inline-block'); - this.renderer.setElementStyle(this.element.nativeElement, 'width', this.size.width + 'px'); - this.renderer.setElementStyle(this.element.nativeElement, 'height', this.size.height + 'px'); + this.renderer.setStyle(this.element.nativeElement, 'display', 'inline-block'); + this.renderer.setStyle(this.element.nativeElement, 'width', this.size.width + 'px'); + this.renderer.setStyle(this.element.nativeElement, 'height', this.size.height + 'px'); this.setImageSource(); } @@ -100,7 +100,7 @@ export class ImageSourceDirective implements OnChanges, OnDestroy, OnInit, After source += `&q=${this.loadQuery}`; } - this.renderer.setElementAttribute(this.element.nativeElement, 'src', source); + this.renderer.setProperty(this.element.nativeElement, 'src', source); } } diff --git a/src/Squidex/app/framework/angular/modals/modal-target.directive.ts b/src/Squidex/app/framework/angular/modals/modal-target.directive.ts index cef07507f..3858649e1 100644 --- a/src/Squidex/app/framework/angular/modals/modal-target.directive.ts +++ b/src/Squidex/app/framework/angular/modals/modal-target.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, Input, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core'; const POSITION_TOPLEFT = 'topLeft'; const POSITION_TOPRIGHT = 'topRight'; @@ -39,7 +39,7 @@ export class ModalTargetDirective implements AfterViewInit, OnDestroy, OnInit { public autoPosition = true; constructor( - private readonly renderer: Renderer, + private readonly renderer: Renderer2, private readonly element: ElementRef ) { } @@ -80,8 +80,8 @@ export class ModalTargetDirective implements AfterViewInit, OnDestroy, OnInit { public ngAfterViewInit() { const modalRef = this.element.nativeElement; - this.renderer.setElementStyle(modalRef, 'position', 'fixed'); - this.renderer.setElementStyle(modalRef, 'z-index', '1000000'); + this.renderer.setStyle(modalRef, 'position', 'fixed'); + this.renderer.setStyle(modalRef, 'z-index', '1000000'); this.updatePosition(); } @@ -197,14 +197,14 @@ export class ModalTargetDirective implements AfterViewInit, OnDestroy, OnInit { const w = targetRect.width + 2 * this.offset; const h = targetRect.height + 2 * this.offset; - this.renderer.setElementStyle(modalRef, 'width', `${w}px`); - this.renderer.setElementStyle(modalRef, 'height', `${h}px`); + this.renderer.setStyle(modalRef, 'width', `${w}px`); + this.renderer.setStyle(modalRef, 'height', `${h}px`); } - this.renderer.setElementStyle(modalRef, 'top', `${t}px`); - this.renderer.setElementStyle(modalRef, 'left', `${l}px`); - this.renderer.setElementStyle(modalRef, 'right', 'auto'); - this.renderer.setElementStyle(modalRef, 'bottom', 'auto'); - this.renderer.setElementStyle(modalRef, 'margin', '0'); + this.renderer.setStyle(modalRef, 'top', `${t}px`); + this.renderer.setStyle(modalRef, 'left', `${l}px`); + this.renderer.setStyle(modalRef, 'right', 'auto'); + this.renderer.setStyle(modalRef, 'bottom', 'auto'); + this.renderer.setStyle(modalRef, 'margin', '0'); } } \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/modals/modal-view.directive.ts b/src/Squidex/app/framework/angular/modals/modal-view.directive.ts index c9421288e..636c6330e 100644 --- a/src/Squidex/app/framework/angular/modals/modal-view.directive.ts +++ b/src/Squidex/app/framework/angular/modals/modal-view.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Directive, EmbeddedViewRef, Input, OnChanges, OnDestroy, Renderer, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core'; +import { Directive, EmbeddedViewRef, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core'; import { Subscription } from 'rxjs'; import { ModalView } from '@app/framework/internal'; @@ -31,7 +31,7 @@ export class ModalViewDirective implements OnChanges, OnDestroy { constructor( private readonly templateRef: TemplateRef, - private readonly renderer: Renderer, + private readonly renderer: Renderer2, private readonly viewContainer: ViewContainerRef, private readonly rootView: RootViewComponent ) { @@ -78,7 +78,7 @@ export class ModalViewDirective implements OnChanges, OnDestroy { } if (this.renderedView.rootNodes[0].style) { - this.renderer.setElementStyle(this.renderedView.rootNodes[0], 'display', 'block'); + this.renderer.setStyle(this.renderedView.rootNodes[0], 'display', 'block'); } setTimeout(() => { @@ -103,7 +103,7 @@ export class ModalViewDirective implements OnChanges, OnDestroy { } this.documentClickListener = - this.renderer.listenGlobal('document', 'click', (event: MouseEvent) => { + this.renderer.listen('document', 'click', (event: MouseEvent) => { if (!event.target || this.renderedView === null) { return; } diff --git a/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts b/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts index ad9538f75..a7b0cd539 100644 --- a/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts +++ b/src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Component, Input, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { fadeAnimation, @@ -43,7 +43,7 @@ export class OnboardingTooltipComponent implements OnDestroy, OnInit { constructor( private readonly onboardingService: OnboardingService, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } diff --git a/src/Squidex/app/framework/angular/modals/tooltip.component.ts b/src/Squidex/app/framework/angular/modals/tooltip.component.ts index 014ec1d9c..4bc1f20b5 100644 --- a/src/Squidex/app/framework/angular/modals/tooltip.component.ts +++ b/src/Squidex/app/framework/angular/modals/tooltip.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { ModalView } from './../../utils/modal-view'; @@ -30,7 +30,7 @@ export class TooltipComponent implements OnDestroy, OnInit { public modal = new ModalView(false, false); constructor( - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } diff --git a/src/Squidex/app/framework/angular/panel-container.directive.ts b/src/Squidex/app/framework/angular/panel-container.directive.ts index 009a14bfd..4ddd78943 100644 --- a/src/Squidex/app/framework/angular/panel-container.directive.ts +++ b/src/Squidex/app/framework/angular/panel-container.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, HostListener } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, HostListener, Renderer2 } from '@angular/core'; import { PanelComponent } from './panel.component'; @@ -17,7 +17,8 @@ export class PanelContainerDirective implements AfterViewInit { private containerWidth = 0; constructor( - private readonly element: ElementRef + private readonly element: ElementRef, + private readonly renderer: Renderer2 ) { } @@ -84,12 +85,8 @@ export class PanelContainerDirective implements AfterViewInit { currentLayer -= 10; } - const diff = currentPosition - this.containerWidth; + const diff = Math.max(0, currentPosition - this.containerWidth); - if (diff > 0) { - this.element.nativeElement.scrollLeft = diff; - } else { - this.element.nativeElement.scrollLeft = 0; - } + this.renderer.setProperty(this.element.nativeElement, 'scrollLeft', diff); } } \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/panel.component.ts b/src/Squidex/app/framework/angular/panel.component.ts index e76c52732..f0317de6a 100644 --- a/src/Squidex/app/framework/angular/panel.component.ts +++ b/src/Squidex/app/framework/angular/panel.component.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, Renderer, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core'; import { slideRightAnimation } from './animations'; @@ -59,7 +59,7 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit { constructor( private readonly container: PanelContainerDirective, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -79,17 +79,17 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit { if (this.styleWidth !== size) { this.styleWidth = size; - this.renderer.setElementStyle(this.panel.nativeElement, 'width', size); + this.renderer.setStyle(this.panel.nativeElement, 'width', size); this.renderWidth = this.panel.nativeElement.getBoundingClientRect().width; } } public arrange(left: any, layer: any) { - this.renderer.setElementStyle(this.panel.nativeElement, 'top', '0px'); - this.renderer.setElementStyle(this.panel.nativeElement, 'left', left); - this.renderer.setElementStyle(this.panel.nativeElement, 'bottom', '0px'); - this.renderer.setElementStyle(this.panel.nativeElement, 'position', 'absolute'); - this.renderer.setElementStyle(this.panel.nativeElement, 'z-index', layer); + this.renderer.setStyle(this.panel.nativeElement, 'top', '0px'); + this.renderer.setStyle(this.panel.nativeElement, 'left', left); + this.renderer.setStyle(this.panel.nativeElement, 'bottom', '0px'); + this.renderer.setStyle(this.panel.nativeElement, 'position', 'absolute'); + this.renderer.setStyle(this.panel.nativeElement, 'z-index', layer); } } \ No newline at end of file diff --git a/src/Squidex/app/framework/angular/routers/parent-link.directive.ts b/src/Squidex/app/framework/angular/routers/parent-link.directive.ts index 3dfd71d9a..9a093d53f 100644 --- a/src/Squidex/app/framework/angular/routers/parent-link.directive.ts +++ b/src/Squidex/app/framework/angular/routers/parent-link.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer } from '@angular/core'; +import { Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Subscription } from 'rxjs'; @@ -23,7 +23,7 @@ export class ParentLinkDirective implements OnDestroy, OnInit { private readonly router: Router, private readonly route: ActivatedRoute, private readonly element: ElementRef, - private readonly renderer: Renderer + private readonly renderer: Renderer2 ) { } @@ -40,7 +40,7 @@ export class ParentLinkDirective implements OnDestroy, OnInit { this.router.createUrlTree(['.'], { relativeTo: this.route.parent!.parent }).toString() : this.router.createUrlTree(['.'], { relativeTo: this.route.parent }).toString(); - this.renderer.setElementAttribute(this.element.nativeElement, 'href', this.url); + this.renderer.setProperty(this.element.nativeElement, 'href', this.url); }); } diff --git a/src/Squidex/app/framework/angular/scroll-active.directive.ts b/src/Squidex/app/framework/angular/scroll-active.directive.ts index ac0fe898f..f10bbab92 100644 --- a/src/Squidex/app/framework/angular/scroll-active.directive.ts +++ b/src/Squidex/app/framework/angular/scroll-active.directive.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { AfterViewInit, Directive, ElementRef, Input, OnChanges } from '@angular/core'; +import { AfterViewInit, Directive, ElementRef, Input, OnChanges, Renderer2 } from '@angular/core'; @Directive({ selector: '[sqxScrollActive]' @@ -18,7 +18,8 @@ export class ScrollActiveDirective implements AfterViewInit, OnChanges { public container: HTMLElement; constructor( - private readonly element: ElementRef + private readonly element: ElementRef, + private readonly renderer: Renderer2 ) { } @@ -37,7 +38,7 @@ export class ScrollActiveDirective implements AfterViewInit, OnChanges { } private scrollInView(parent: HTMLElement, target: HTMLElement) { - if (!parent.getBoundingClientRect) { + if (!parent.getBoundingClientRect || !target.getBoundingClientRect || !document.body) { return; } @@ -49,13 +50,13 @@ export class ScrollActiveDirective implements AfterViewInit, OnChanges { const scroll = parent.scrollTop; if (offset < 0) { - parent.scrollTop = scroll + offset; + this.renderer.setProperty(parent, 'scrollTop', scroll + offset); } else { const targetHeight = targetRect.height; const parentHeight = parentRect.height; if ((offset + targetHeight) > parentHeight) { - parent.scrollTop = scroll + offset - parentHeight + targetHeight; + this.renderer.setProperty(parent, 'scrollTop', scroll + offset - parentHeight + targetHeight); } } } diff --git a/src/Squidex/app/framework/declarations.ts b/src/Squidex/app/framework/declarations.ts index 659283d6c..56fce1cfc 100644 --- a/src/Squidex/app/framework/declarations.ts +++ b/src/Squidex/app/framework/declarations.ts @@ -18,13 +18,12 @@ export * from './angular/forms/iframe-editor.component'; export * from './angular/forms/indeterminate-value.directive'; export * from './angular/forms/jscript-editor.component'; export * from './angular/forms/json-editor.component'; -export * from './angular/forms/lowercase-input.directive'; export * from './angular/forms/progress-bar.component'; export * from './angular/forms/slider.component'; -export * from './angular/forms/slugify-input.directive'; export * from './angular/forms/stars.component'; export * from './angular/forms/tag-editor.component'; export * from './angular/forms/toggle.component'; +export * from './angular/forms/transform-input.directive'; export * from './angular/forms/validators'; export * from './angular/http/http-extensions-impl'; diff --git a/src/Squidex/app/framework/module.ts b/src/Squidex/app/framework/module.ts index 43480accb..d1c67d92a 100644 --- a/src/Squidex/app/framework/module.ts +++ b/src/Squidex/app/framework/module.ts @@ -42,7 +42,6 @@ import { KeysPipe, KNumberPipe, LocalStoreService, - LowerCaseInputDirective, MessageBus, ModalDialogComponent, ModalTargetDirective, @@ -65,7 +64,6 @@ import { ShortDatePipe, ShortTimePipe, SliderComponent, - SlugifyInputDirective, SortedDirective, StarsComponent, TagEditorComponent, @@ -74,6 +72,7 @@ import { TitleService, ToggleComponent, TooltipComponent, + TransformInputDirective, UserReportComponent } from './declarations'; @@ -111,7 +110,6 @@ import { JsonEditorComponent, KeysPipe, KNumberPipe, - LowerCaseInputDirective, ModalDialogComponent, ModalTargetDirective, ModalViewDirective, @@ -130,7 +128,6 @@ import { ShortDatePipe, ShortTimePipe, SliderComponent, - SlugifyInputDirective, SortedDirective, StarsComponent, TagEditorComponent, @@ -138,6 +135,7 @@ import { TitleComponent, ToggleComponent, TooltipComponent, + TransformInputDirective, UserReportComponent ], exports: [ @@ -170,7 +168,6 @@ import { JsonEditorComponent, KeysPipe, KNumberPipe, - LowerCaseInputDirective, ModalDialogComponent, ModalTargetDirective, ModalViewDirective, @@ -190,7 +187,6 @@ import { ShortDatePipe, ShortTimePipe, SliderComponent, - SlugifyInputDirective, SortedDirective, StarsComponent, TagEditorComponent, @@ -198,6 +194,7 @@ import { TitleComponent, ToggleComponent, TooltipComponent, + TransformInputDirective, UserReportComponent ] }) diff --git a/src/Squidex/app/framework/utils/types.ts b/src/Squidex/app/framework/utils/types.ts index a08609ee3..d94c31a1c 100644 --- a/src/Squidex/app/framework/utils/types.ts +++ b/src/Squidex/app/framework/utils/types.ts @@ -6,51 +6,51 @@ */ export module Types { - export function isString(value: any): boolean { + export function isString(value: any): value is string { return typeof value === 'string' || value instanceof String; } - export function isNumber(value: any): boolean { + export function isNumber(value: any): value is number { return typeof value === 'number' && isFinite(value); } - export function isArray(value: any): boolean { + export function isArray(value: any): value is Array { return Array.isArray(value); } - export function isFunction(value: any): boolean { + export function isFunction(value: any): value is Function { return typeof value === 'function'; } - export function isObject(value: any): boolean { + export function isObject(value: any): value is Object { return value && typeof value === 'object' && value.constructor === Object; } - export function isBoolean(value: any): boolean { + export function isBoolean(value: any): value is boolean { return typeof value === 'boolean'; } - export function isNull(value: any): boolean { + export function isNull(value: any): value is null { return value === null; } - export function isUndefined(value: any): boolean { + export function isUndefined(value: any): value is undefined { return typeof value === 'undefined'; } - export function isRegExp(value: any): boolean { + export function isRegExp(value: any): value is RegExp { return value && typeof value === 'object' && value.constructor === RegExp; } - export function isDate(value: any): boolean { + export function isDate(value: any): value is Date { return value instanceof Date; } - export function isArrayOfNumber(value: any): boolean { + export function isArrayOfNumber(value: any): value is Array { return isArrayOf(value, v => isNumber(v)); } - export function isArrayOfString(value: any): boolean { + export function isArrayOfString(value: any): value is Array { return isArrayOf(value, v => isString(v)); } diff --git a/src/Squidex/app/shared/components/app-form.component.html b/src/Squidex/app/shared/components/app-form.component.html index d4ba4ab14..24782a7d4 100644 --- a/src/Squidex/app/shared/components/app-form.component.html +++ b/src/Squidex/app/shared/components/app-form.component.html @@ -18,7 +18,7 @@ - + The app name becomes part of the api url,
e.g {{apiUrl.buildUrl("api/content/")}}{{createForm.appName | async}}/.