Browse Source

Performance improvements.

pull/327/head
Sebastian Stehle 8 years ago
parent
commit
f95c0cc722
  1. 2
      src/Squidex/app/features/content/pages/content/content-field.component.html
  2. 13
      src/Squidex/app/features/content/pages/content/content-field.component.ts
  3. 5
      src/Squidex/app/features/content/pages/content/content-history.component.html
  4. 4
      src/Squidex/app/features/content/pages/content/content-history.component.ts
  5. 8
      src/Squidex/app/features/content/pages/contents/contents-page.component.html
  6. 14
      src/Squidex/app/features/content/pages/contents/contents-page.component.ts
  7. 2
      src/Squidex/app/features/content/shared/assets-editor.component.ts
  8. 5
      src/Squidex/app/features/content/shared/content-item.component.ts
  9. 10
      src/Squidex/app/features/content/shared/references-editor.component.ts
  10. 2
      src/Squidex/app/framework/angular/forms/date-time-editor.component.ts
  11. 31
      src/Squidex/app/framework/angular/http/loading.interceptor.ts
  12. 20
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts
  13. 5
      src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.ts
  14. 5
      src/Squidex/app/framework/angular/modals/root-view.component.ts
  15. 9
      src/Squidex/app/framework/angular/panel.component.ts
  16. 5
      src/Squidex/app/framework/angular/shortcut.component.ts
  17. 5
      src/Squidex/app/framework/angular/title.component.ts
  18. 5
      src/Squidex/app/framework/angular/user-report.component.ts
  19. 1
      src/Squidex/app/framework/declarations.ts
  20. 1
      src/Squidex/app/framework/internal.ts
  21. 11
      src/Squidex/app/framework/module.ts
  22. 114
      src/Squidex/app/framework/services/loading.service.spec.ts
  23. 68
      src/Squidex/app/framework/services/loading.service.ts
  24. 4
      src/Squidex/app/shared/components/asset.component.html
  25. 8
      src/Squidex/app/shared/components/asset.component.scss
  26. 4
      src/Squidex/app/shared/components/asset.component.ts
  27. 37
      src/Squidex/app/shared/components/geolocation-editor.component.ts
  28. 3
      src/Squidex/app/shared/components/help.component.ts
  29. 2
      src/Squidex/app/shared/components/history-list.component.html
  30. 2
      src/Squidex/app/shared/components/pipes.ts
  31. 8
      src/Squidex/app/shell/pages/internal/internal-area.component.html
  32. 4
      src/Squidex/app/shell/pages/internal/internal-area.component.scss
  33. 8
      src/Squidex/app/shell/pages/internal/internal-area.component.ts
  34. 14
      src/Squidex/app/theme/_common.scss
  35. 4
      src/Squidex/app/theme/icomoon/demo-files/demo.css
  36. 776
      src/Squidex/app/theme/icomoon/demo.html
  37. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.eot
  38. 1
      src/Squidex/app/theme/icomoon/fonts/icomoon.svg
  39. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.ttf
  40. BIN
      src/Squidex/app/theme/icomoon/fonts/icomoon.woff
  41. 3056
      src/Squidex/app/theme/icomoon/selection.json
  42. 124
      src/Squidex/app/theme/icomoon/style.css
  43. BIN
      src/Squidex/wwwroot/images/loader-white.gif

2
src/Squidex/app/features/content/pages/content/content-field.component.html

@ -1,4 +1,4 @@
<div class="table-items-row" [class.invalid]="fieldForm.invalid">
<div class="table-items-row" [class.invalid]="isInvalid | async">
<ng-container *ngIf="field.isLocalizable && languages.length > 1">
<div class="languages-buttons" #buttonLanguages>
<sqx-language-selector size="sm"

13
src/Squidex/app/features/content/pages/content/content-field.component.ts

@ -5,8 +5,9 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import {
AppLanguageDto,
@ -16,11 +17,13 @@ import {
RootFieldDto,
Types
} from '@app/shared';
import { map, startWith } from 'rxjs/operators';
@Component({
selector: 'sqx-content-field',
styleUrls: ['./content-field.component.scss'],
templateUrl: './content-field.component.html'
templateUrl: './content-field.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ContentFieldComponent implements OnChanges {
@Input()
@ -43,6 +46,8 @@ export class ContentFieldComponent implements OnChanges {
public selectedFormControl: AbstractControl;
public isInvalid: Observable<boolean>;
public ngOnChanges(changes: SimpleChanges) {
if (this.field.isLocalizable) {
this.selectedFormControl = this.fieldForm.controls[this.language.iso2Code];
@ -55,6 +60,10 @@ export class ContentFieldComponent implements OnChanges {
this.selectedFormControl['_clearChangeFns']();
}
}
if (changes['fieldForm']) {
this.isInvalid = this.fieldForm.statusChanges.pipe(startWith(this.fieldForm.invalid), map(x => this.fieldForm.invalid));
}
}
}

5
src/Squidex/app/features/content/pages/content/content-history.component.html

@ -4,13 +4,14 @@
</ng-container>
<ng-container content>
<div *ngFor="let event of events | async" class="event row no-gutters">
<div *ngFor="let event of events | async; trackBy: trackByEvent" class="event row no-gutters">
<div class="col col-auto">
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:null" [attr.src]="event.actor | sqxUserPictureRef" />
</div>
<div class="col pl-2">
<div class="event-message">
<span class="event-actor user-ref">{{event.actor | sqxUserNameRef:null}}</span> <span [innerHTML]="format(event.message) | async"></span>
<span class="event-actor user-ref mr-1">{{event.actor | sqxUserNameRef:null}}</span>
<span [innerHTML]="format(event.message) | async"></span>
</div>
<div class="event-created">{{event.created | sqxFromNow}}</div>

4
src/Squidex/app/features/content/pages/content/content-history.component.ts

@ -71,4 +71,8 @@ export class ContentHistoryComponent {
public format(message: string): Observable<string> {
return formatHistoryMessage(message, this.users);
}
public trackByEvent(index: number, event: HistoryEventDto) {
return event.eventId;
}
}

8
src/Squidex/app/features/content/pages/contents/contents-page.component.html

@ -73,19 +73,19 @@
<div class="selection" *ngIf="selectionCount > 0">
{{selectionCount}} items selected:&nbsp;&nbsp;
<button class="btn btn-secondary" (click)="publishSelected()" *ngIf="canPublish">
<button class="btn btn-secondary mr-1" (click)="publishSelected()" *ngIf="canPublish">
Publish
</button>
<button class="btn btn-secondary" (click)="unpublishSelected()" *ngIf="canUnpublish">
<button class="btn btn-secondary mr-1" (click)="unpublishSelected()" *ngIf="canUnpublish">
Unpublish
</button>
<button class="btn btn-secondary" (click)="archiveSelected()" *ngIf="(contentsState.isArchive | async) === false">
<button class="btn btn-secondary mr-1" (click)="archiveSelected()" *ngIf="(contentsState.isArchive | async) === false">
Archive
</button>
<button class="btn btn-secondary" (click)="restoreSelected()" *ngIf="contentsState.isArchive | async">
<button class="btn btn-secondary mr-1" (click)="restoreSelected()" *ngIf="contentsState.isArchive | async">
Restore
</button>

14
src/Squidex/app/features/content/pages/contents/contents-page.component.ts

@ -149,7 +149,7 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
}
public isSelectedQuery(query: string) {
return query === this.contentsState.snapshot.contentsQuery || (!query && !this.contentsState.contentsQuery);
return query === this.contentsState.snapshot.contentsQuery || (!query && !this.contentsState.snapshot.contentsQuery);
}
private changeContentItems(contents: ContentDto[], action: string) {
@ -208,6 +208,12 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
this.updateSelectionSummary();
}
private resetSelection() {
this.selectedItems = {};
this.updateSelectionSummary();
}
public selectAll(isSelected: boolean) {
this.selectedItems = {};
@ -224,12 +230,6 @@ export class ContentsPageComponent implements OnDestroy, OnInit {
return content.id;
}
private resetSelection() {
this.selectedItems = {};
this.updateSelectionSummary();
}
private updateSelectionSummary() {
this.isAllSelected = this.contentsState.snapshot.contents.length > 0;

2
src/Squidex/app/features/content/shared/assets-editor.component.ts

@ -132,7 +132,7 @@ export class AssetsEditorComponent implements ControlValueAccessor {
this.callTouched();
this.callChange(ids);
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}
public sort(assets: AssetDto[]) {

5
src/Squidex/app/features/content/shared/content-item.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import {
AppLanguageDto,
@ -29,7 +29,8 @@ import {
templateUrl: './content-item.component.html',
animations: [
fadeAnimation
]
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ContentItemComponent implements OnChanges {
@Output()

10
src/Squidex/app/features/content/shared/references-editor.component.ts

@ -74,11 +74,11 @@ export class ReferencesEditorComponent implements ControlValueAccessor, OnInit {
.subscribe(dto => {
this.schema = dto;
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}, () => {
this.isInvalidSchema = true;
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
});
}
@ -95,11 +95,11 @@ export class ReferencesEditorComponent implements ControlValueAccessor, OnInit {
this.updateValue();
}
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}, () => {
this.contentItems = ImmutableArray.empty();
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
});
}
} else {
@ -157,6 +157,6 @@ export class ReferencesEditorComponent implements ControlValueAccessor, OnInit {
this.callTouched();
this.callChange(ids);
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}
}

2
src/Squidex/app/framework/angular/forms/date-time-editor.component.ts

@ -144,7 +144,7 @@ export class DateTimeEditorComponent implements ControlValueAccessor, OnDestroy,
this.touched();
if (false) {
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}
}
});

31
src/Squidex/app/framework/angular/http/loading.interceptor.ts

@ -0,0 +1,31 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable} from '@angular/core';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoadingService, MathHelper } from './../../internal';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(
private readonly loadingService: LoadingService
) {
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const id = MathHelper.guid();
this.loadingService.startLoading(id);
return next.handle(req).pipe(finalize(() => {
this.loadingService.completeLoading(id);
}));
}
}

20
src/Squidex/app/framework/angular/modals/dialog-renderer.component.ts

@ -5,7 +5,7 @@
* Copyright (c) Sebastian Stehle. All rights r vbeserved
*/
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import {
@ -22,7 +22,8 @@ import {
templateUrl: './dialog-renderer.component.html',
animations: [
fadeAnimation
]
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DialogRendererComponent implements OnDestroy, OnInit {
private dialogSubscription: Subscription;
@ -38,6 +39,7 @@ export class DialogRendererComponent implements OnDestroy, OnInit {
public position = 'bottomright';
constructor(
private readonly changeDetector: ChangeDetectorRef,
private readonly dialogs: DialogService
) {
}
@ -53,6 +55,8 @@ export class DialogRendererComponent implements OnDestroy, OnInit {
this.dialogView.isOpen.subscribe(isOpen => {
if (!isOpen) {
this.cancel();
this.changeDetector.detectChanges();
}
});
@ -65,6 +69,8 @@ export class DialogRendererComponent implements OnDestroy, OnInit {
this.close(notification);
}, notification.displayTime);
}
this.changeDetector.detectChanges();
});
this.dialogsSubscription =
@ -74,6 +80,8 @@ export class DialogRendererComponent implements OnDestroy, OnInit {
this.dialogRequest = request;
this.dialogView.show();
this.changeDetector.detectChanges();
});
}
@ -94,6 +102,12 @@ export class DialogRendererComponent implements OnDestroy, OnInit {
}
public close(notification: Notification) {
this.notifications.splice(this.notifications.indexOf(notification), 1);
const index = this.notifications.indexOf(notification);
if (index >= 0) {
this.notifications.splice(index, 1);
this.changeDetector.detectChanges();
}
}
}

5
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, Renderer2 } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import {
fadeAnimation,
@ -20,7 +20,8 @@ import {
templateUrl: './onboarding-tooltip.component.html',
animations: [
fadeAnimation
]
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnboardingTooltipComponent implements OnDestroy, OnInit {
private showTimer: any;

5
src/Squidex/app/framework/angular/modals/root-view.component.ts

@ -5,12 +5,13 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, ViewChild, ViewContainerRef } from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewChild, ViewContainerRef } from '@angular/core';
@Component({
selector: 'sqx-root-view',
styleUrls: ['./root-view.component.scss'],
templateUrl: './root-view.component.html'
templateUrl: './root-view.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RootViewComponent {
@ViewChild('element', { read: ViewContainerRef })

9
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, Renderer2, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild } from '@angular/core';
import { slideRightAnimation } from './animations';
@ -17,7 +17,8 @@ import { PanelContainerDirective } from './panel-container.directive';
templateUrl: './panel.component.html',
animations: [
slideRightAnimation
]
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
private styleWidth: string;
@ -62,6 +63,7 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
constructor(
private readonly container: PanelContainerDirective,
private readonly changeDetector: ChangeDetectorRef,
private readonly renderer: Renderer2
) {
}
@ -83,8 +85,9 @@ export class PanelComponent implements AfterViewInit, OnDestroy, OnInit {
this.styleWidth = size;
this.renderer.setStyle(this.panel.nativeElement, 'width', size);
this.renderWidth = this.panel.nativeElement.getBoundingClientRect().width;
this.changeDetector.detectChanges();
}
}

5
src/Squidex/app/framework/angular/shortcut.component.ts

@ -5,13 +5,14 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from '@angular/core';
import { ShortcutService } from './../services/shortcut.service';
@Component({
selector: 'sqx-shortcut',
template: ''
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ShortcutComponent implements OnDestroy, OnInit {
@Input()

5
src/Squidex/app/framework/angular/title.component.ts

@ -5,13 +5,14 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, Input, OnChanges } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { TitleService } from './../services/title.service';
@Component({
selector: 'sqx-title',
template: ''
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TitleComponent implements OnChanges {
@Input()

5
src/Squidex/app/framework/angular/user-report.component.ts

@ -5,14 +5,15 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { UserReportConfig } from './../configurations';
import { ResourceLoaderService } from './../services/resource-loader.service';
@Component({
selector: 'sqx-user-report',
template: ''
template: '',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserReportComponent implements OnDestroy, OnInit {
private loadingTimer: any;

1
src/Squidex/app/framework/declarations.ts

@ -27,6 +27,7 @@ export * from './angular/forms/toggle.component';
export * from './angular/forms/transform-input.directive';
export * from './angular/forms/validators';
export * from './angular/http/loading.interceptor';
export * from './angular/http/http-extensions';
export * from './angular/modals/dialog-renderer.component';

1
src/Squidex/app/framework/internal.ts

@ -11,6 +11,7 @@ export * from './angular/animations';
export * from './services/analytics.service';
export * from './services/clipboard.service';
export * from './services/dialog.service';
export * from './services/loading.service';
export * from './services/local-store.service';
export * from './services/message-bus.service';
export * from './services/onboarding.service';

11
src/Squidex/app/framework/module.ts

@ -6,6 +6,7 @@
*/
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@ -44,6 +45,8 @@ import {
KeysPipe,
KNumberPipe,
LightenPipe,
LoadingInterceptor,
LoadingService,
LocalStoreService,
MessageBus,
ModalDialogComponent,
@ -220,11 +223,17 @@ export class SqxFrameworkModule {
ClipboardService,
DialogService,
LocalStoreService,
LoadingService,
MessageBus,
OnboardingService,
ResourceLoaderService,
ShortcutService,
TitleService
TitleService,
{
provide: HTTP_INTERCEPTORS,
useClass: LoadingInterceptor,
multi: true
}
]
};
}

114
src/Squidex/app/framework/services/loading.service.spec.ts

@ -0,0 +1,114 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Event, NavigationError, NavigationStart } from '@angular/router';
import { Subject } from 'rxjs';
import { LoadingService, LoadingServiceFactory } from './loading.service';
describe('LoadingService', () => {
let events = new Subject<Event>();
it('should instantiate from factory', () => {
const loadingService = LoadingServiceFactory(<any>{ events });
expect(loadingService).toBeDefined();
});
it('should instantiate', () => {
const loadingService = new LoadingService(<any>{ events });
expect(loadingService).toBeDefined();
loadingService.ngOnDestroy();
});
it('should set to loaded', () => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
loadingService.startLoading('1');
expect(state).toBeTruthy();
});
it('should set to loaded on navigation start', () => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
events.next(new NavigationStart(0, ''));
expect(state).toBeTruthy();
});
it('should not unset from loaded immediately', () => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
loadingService.startLoading('1');
loadingService.completeLoading('1');
expect(state).toBeTruthy();
});
it('should not unset from loaded delayed', (cb) => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
loadingService.startLoading('1');
loadingService.completeLoading('1');
setTimeout(() => {
expect(state).toBeFalsy();
cb();
}, 400);
});
it('should not unset from loaded delayed on navigation event', (cb) => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
events.next(new NavigationStart(0, ''));
events.next(new NavigationError(0, '', 0));
setTimeout(() => {
expect(state).toBeFalsy();
cb();
}, 400);
});
it('should set back to loaded after several completions', (cb) => {
const loadingService = new LoadingService(<any>{ events });
let state = false;
loadingService.loading.subscribe(v => state = v);
loadingService.startLoading('1');
loadingService.completeLoading('1');
loadingService.completeLoading('1');
loadingService.startLoading('2');
setTimeout(() => {
expect(state).toBeTruthy();
cb();
}, 400);
});
});

68
src/Squidex/app/framework/services/loading.service.ts

@ -0,0 +1,68 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Injectable, OnDestroy } from '@angular/core';
import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { Types } from './../utils/types';
export const LoadingServiceFactory = (router: Router) => {
return new LoadingService(router);
};
@Injectable()
export class LoadingService implements OnDestroy {
private readonly routerSubscription: Subscription;
private readonly loading$ = new BehaviorSubject(0);
private readonly loadingOperations: { [key: string]: boolean } = {};
public get loading(): Observable<boolean> {
return this.loading$.pipe(map(x => x > 0));
}
constructor(router: Router) {
this.routerSubscription =
router.events.subscribe(event => {
if (Types.is(event, NavigationStart)) {
this.startLoading(event.id.toString());
} else if (
Types.is(event, NavigationEnd) ||
Types.is(event, NavigationCancel) ||
Types.is(event, NavigationError)) {
this.completeLoading(event.id.toString());
}
});
}
public ngOnDestroy() {
this.routerSubscription.unsubscribe();
}
public startLoading(key: string) {
if (!this.loadingOperations[key]) {
this.loadingOperations[key] = true;
this.loading$.next(this.loading$.value + 1);
}
}
public completeLoading(key: string) {
if (this.loadingOperations[key]) {
delete this.loadingOperations[key];
setTimeout(() => {
const value = this.loading$.value;
if (value > 0) {
this.loading$.next(value - 1);
}
}, 250);
}
}
}

4
src/Squidex/app/shared/components/asset.component.html

@ -7,7 +7,7 @@
</span>
<div *ngIf="asset.isImage" class="file-image">
<img [sqxImageSource]="asset | sqxAssetPreviewUrl">
<img [sqxImageSource]="asset | sqxAssetPreviewUrl" class="bg">
</div>
<div *ngIf="!asset.isImage" class="file-icon">
<img [attr.src]="asset | sqxFileIcon">
@ -89,7 +89,7 @@
<div class="left-border" [class.selected]="isSelected" ></div>
<div *ngIf="asset && asset.isImage && progress === 0" class="image" @fade>
<img [sqxImageSource]="asset | sqxAssetPreviewUrl">
<img [sqxImageSource]="asset | sqxAssetPreviewUrl" class="bg2">
</div>
<div *ngIf="asset && !asset.isImage && progress === 0" class="image image-padded" @fade>
<img class="icon" [attr.src]="asset | sqxFileIcon">

8
src/Squidex/app/shared/components/asset.component.scss

@ -287,6 +287,14 @@ $list-height: 2.375rem;
cursor: pointer;
}
.bg {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAIAAAC1nk4lAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAACbSURBVGhD7c6hDQAxAMPA33+m7vYlJh7AoFKOBMbfyfyZRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4E3o9kA7YFFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgUUbD4FFGw+BRRsPgQejz7nPYYKl8IqSfgAAAABJRU5ErkJggg==');
}
.bg2 {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAAsSURBVDhPY9iDF/zHC0Y1YwCoKhxgRGqG0jgA1AwcYFQzBoCqwgFGnuY9ewCdSg6FRg4gMAAAAABJRU5ErkJggg==');
}
.tags {
min-height: 26px;
}

4
src/Squidex/app/shared/components/asset.component.ts

@ -209,7 +209,7 @@ export class AssetComponent implements OnDestroy, OnInit {
private setProgress(progress: number) {
this.progress = progress;
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}
private updateAsset(asset: AssetDto, emitEvent: boolean) {
@ -224,6 +224,6 @@ export class AssetComponent implements OnDestroy, OnInit {
this.renameCancel();
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
}
}

37
src/Squidex/app/shared/components/geolocation-editor.component.ts

@ -272,13 +272,24 @@ export class GeolocationEditorComponent implements ControlValueAccessor, AfterVi
private updateMarker(zoom: boolean, fireEvent: boolean) {
if (!this.isGoogleMaps) {
this.updateMarkerOSM(zoom, fireEvent);
this.updateMarkerOSM(zoom);
} else {
this.updateMarkerGoogle(zoom, fireEvent);
this.updateMarkerGoogle(zoom);
}
if (this.value) {
this.geolocationForm.setValue(this.value, { emitEvent: true, onlySelf: false });
} else {
this.geolocationForm.reset(undefined, { emitEvent: true, onlySelf: false });
}
if (fireEvent) {
this.callChange(this.value);
this.callTouched();
}
}
private updateMarkerOSM(zoom: boolean, fireEvent: boolean) {
private updateMarkerOSM(zoom: boolean) {
if (this.value) {
if (!this.marker) {
this.marker = L.marker([0, 90], { draggable: true }).addTo(this.map);
@ -307,8 +318,6 @@ export class GeolocationEditorComponent implements ControlValueAccessor, AfterVi
}
this.marker.setLatLng(latLng);
this.geolocationForm.setValue(this.value, { emitEvent: false, onlySelf: false });
} else {
if (this.marker) {
this.marker.removeFrom(this.map);
@ -316,17 +325,10 @@ export class GeolocationEditorComponent implements ControlValueAccessor, AfterVi
}
this.map.fitWorld();
this.geolocationForm.reset(undefined, { emitEvent: false, onlySelf: false });
}
if (fireEvent) {
this.callChange(this.value);
this.callTouched();
}
}
private updateMarkerGoogle(zoom: boolean, fireEvent: boolean) {
private updateMarkerGoogle(zoom: boolean) {
if (this.value) {
if (!this.marker) {
this.marker = new google.maps.Marker({
@ -361,8 +363,6 @@ export class GeolocationEditorComponent implements ControlValueAccessor, AfterVi
this.marker.setPosition(latLng);
this.map.setZoom(12);
this.geolocationForm.setValue(this.value, { emitEvent: false, onlySelf: false });
} else {
if (this.marker) {
this.marker.setMap(null);
@ -370,13 +370,6 @@ export class GeolocationEditorComponent implements ControlValueAccessor, AfterVi
}
this.map.setCenter({ lat: 0, lng: 0 });
this.geolocationForm.reset(undefined, { emitEvent: false, onlySelf: false });
}
if (fireEvent) {
this.callChange(this.value);
this.callTouched();
}
}
}

3
src/Squidex/app/shared/components/help.component.ts

@ -17,8 +17,7 @@ import { HelpService } from '@app/shared/internal';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HelpComponent {
public helpSections =
this.helpService.getHelp(this.route.snapshot.data['helpPage']);
public helpSections = this.helpService.getHelp(this.route.snapshot.data['helpPage']);
constructor(
private readonly helpService: HelpService,

2
src/Squidex/app/shared/components/history-list.component.html

@ -1,5 +1,5 @@
<ng-container *ngIf="events">
<div *ngFor="let event of events" class="event row no-gutters">
<div *ngFor="let event of events; trackBy: trackByEvent" class="event row no-gutters">
<div class="col col-auto">
<img class="user-picture" [attr.title]="event.actor | sqxUserNameRef:null" [attr.src]="event.actor | sqxUserPictureRef" />
</div>

2
src/Squidex/app/shared/components/pipes.ts

@ -44,7 +44,7 @@ class UserAsyncPipe implements OnDestroy {
this.subscription = transform(this.users).subscribe(value => {
this.lastValue = value;
this.changeDetector.markForCheck();
this.changeDetector.detectChanges();
});
}

8
src/Squidex/app/shell/pages/internal/internal-area.component.html

@ -1,6 +1,12 @@
<nav class="navbar fixed-top navbar-dark bg-primary bg-faded">
<span class="navbar-brand" routerLink="/app">
<i class="icon-logo"></i>
<ng-container *ngIf="loadingService.loading | async; else noLoading">
<img class="loader" src="/images/loader-white.gif" @fade />
</ng-container>
<ng-template #noLoading>
<i class="icon-logo" @fade></i>
</ng-template>
</span>
<div class="float-left apps-menu">

4
src/Squidex/app/shell/pages/internal/internal-area.component.scss

@ -71,4 +71,8 @@ $support-text-size: 200px;
font-weight: normal;
width: $support-icon-size;
}
}
.loader {
@include absolute(12px, auto, auto, 40px);
}

8
src/Squidex/app/shell/pages/internal/internal-area.component.ts

@ -11,13 +11,18 @@ import { Subscription } from 'rxjs';
import {
DialogService,
fadeAnimation,
LoadingService,
Notification
} from '@app/shared';
@Component({
selector: 'sqx-internal-area',
styleUrls: ['./internal-area.component.scss'],
templateUrl: './internal-area.component.html'
templateUrl: './internal-area.component.html',
animations: [
fadeAnimation
]
})
export class InternalAreaComponent implements OnDestroy, OnInit {
private queryParamsSubscription: Subscription;
@ -25,6 +30,7 @@ export class InternalAreaComponent implements OnDestroy, OnInit {
public notifications: Notification[] = [];
constructor(
public readonly loadingService: LoadingService,
private readonly dialogs: DialogService,
private readonly route: ActivatedRoute
) {

14
src/Squidex/app/theme/_common.scss

@ -163,6 +163,20 @@ body {
@include animation(spin 3s infinite linear);
}
.spin2 {
@include animation(spin2 5s infinite linear);
}
@include keyframes (spin2) {
50% {
@include rotate(180deg);
}
100% {
@include rotate(360deg);
}
}
@include keyframes (spin) {
20% {
@include rotate(0deg);

4
src/Squidex/app/theme/icomoon/demo-files/demo.css

@ -147,10 +147,10 @@ p {
font-size: 16px;
}
.fs1 {
font-size: 20px;
font-size: 32px;
}
.fs2 {
font-size: 32px;
font-size: 20px;
}
.fs3 {
font-size: 32px;

776
src/Squidex/app/theme/icomoon/demo.html

File diff suppressed because it is too large

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.eot

Binary file not shown.

1
src/Squidex/app/theme/icomoon/fonts/icomoon.svg

@ -96,6 +96,7 @@
<glyph unicode="&#xe956;" glyph-name="type-Array" d="M832 682.057h-657.92c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h657.92c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 497.737h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 308.297h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6zM832 118.857h-409.6c-15.36 0-25.6 10.24-25.6 25.6s10.24 25.6 25.6 25.6h409.6c15.36 0 25.6-10.24 25.6-25.6s-10.24-25.6-25.6-25.6z" />
<glyph unicode="&#xe957;" glyph-name="multiple-content" horiz-adv-x="1029" d="M777.143 4.571h-525.714c-89.143 0-160 70.857-160 160v297.143c0 89.143 70.857 160 160 160h525.714c89.143 0 160-70.857 160-160v-297.143c0-89.143-70.857-160-160-160zM251.429 576c-64 0-114.286-50.286-114.286-114.286v-297.143c0-64 50.286-114.286 114.286-114.286h525.714c64 0 114.286 50.286 114.286 114.286v297.143c0 64-50.286 114.286-114.286 114.286h-525.714zM731.429 370.286h-457.143c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h457.143c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM502.857 210.286h-228.571c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h228.571c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM777.143 690.286h-525.714c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h525.714c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857zM685.714 804.571h-342.857c-13.714 0-22.857 9.143-22.857 22.857s9.143 22.857 22.857 22.857h342.857c13.714 0 22.857-9.143 22.857-22.857s-9.143-22.857-22.857-22.857z" />
<glyph unicode="&#xe958;" glyph-name="single-content" horiz-adv-x="1029" d="M251.429 850.277c-87.896 0-160-72.104-160-160v-525.714c0-87.896 72.104-160 160-160h525.714c87.896 0 160 72.104 160 160v525.714c0 87.896-72.104 160-160 160zM251.429 804.562h525.714c62.961 0 114.286-51.325 114.286-114.286v-525.714c0-62.961-51.325-114.286-114.286-114.286h-525.714c-62.961 0-114.286 51.325-114.286 114.286v525.714c0 62.961 51.325 114.286 114.286 114.286zM251.429 644.562c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h525.697c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017zM251.429 507.419c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h297.126c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017zM251.429 370.277c-0.096 0.001-0.21 0.002-0.323 0.002-12.625 0-22.859-10.235-22.859-22.859s10.235-22.859 22.859-22.859c0.114 0 0.227 0.001 0.34 0.002h297.126c0.096-0.001 0.21-0.002 0.323-0.002 12.625 0 22.859 10.235 22.859 22.859s-10.235 22.859-22.859 22.859c-0.114 0-0.227-0.001-0.34-0.002h0.017z" />
<glyph unicode="&#xe959;" glyph-name="spinner2" d="M512-64c-136.76 0-265.334 53.258-362.040 149.96-96.702 96.706-149.96 225.28-149.96 362.040 0 96.838 27.182 191.134 78.606 272.692 50 79.296 120.664 143.372 204.356 185.3l43-85.832c-68.038-34.084-125.492-86.186-166.15-150.67-41.746-66.208-63.812-142.798-63.812-221.49 0-229.382 186.618-416 416-416s416 186.618 416 416c0 78.692-22.066 155.282-63.81 221.49-40.66 64.484-98.114 116.584-166.15 150.67l43 85.832c83.692-41.928 154.358-106.004 204.356-185.3 51.422-81.558 78.604-175.854 78.604-272.692 0-136.76-53.258-265.334-149.96-362.040-96.706-96.702-225.28-149.96-362.040-149.96z" />
<glyph unicode="&#xe95a;" glyph-name="support" d="M726 426.667c0-24-20-42-44-42h-426l-170-172v598c0 24 18 42 42 42h554c24 0 44-18 44-42v-384zM896 682.667c24 0 42-18 42-42v-640l-170 170h-470c-24 0-42 18-42 42v86h554v384h86z" />
<glyph unicode="&#xe95b;" glyph-name="backup" d="M512 810.667c212 0 384-172 384-384s-172-384-384-384c-88 0-170 30-234 80l60 60c50-34 110-54 174-54 166 0 298 132 298 298s-132 298-298 298-298-132-298-298h128l-172-170-170 170h128c0 212 172 384 384 384zM598 426.667c0-46-40-86-86-86s-86 40-86 86 40 86 86 86 86-40 86-86z" />
<glyph unicode="&#xe95c;" glyph-name="twitter" d="M1024 733.6c-37.6-16.8-78.2-28-120.6-33 43.4 26 76.6 67.2 92.4 116.2-40.6-24-85.6-41.6-133.4-51-38.4 40.8-93 66.2-153.4 66.2-116 0-210-94-210-210 0-16.4 1.8-32.4 5.4-47.8-174.6 8.8-329.4 92.4-433 219.6-18-31-28.4-67.2-28.4-105.6 0-72.8 37-137.2 93.4-174.8-34.4 1-66.8 10.6-95.2 26.2 0-0.8 0-1.8 0-2.6 0-101.8 72.4-186.8 168.6-206-17.6-4.8-36.2-7.4-55.4-7.4-13.6 0-26.6 1.4-39.6 3.8 26.8-83.4 104.4-144.2 196.2-146-72-56.4-162.4-90-261-90-17 0-33.6 1-50.2 3 93.2-59.8 203.6-94.4 322.2-94.4 386.4 0 597.8 320.2 597.8 597.8 0 9.2-0.2 18.2-0.6 27.2 41 29.4 76.6 66.4 104.8 108.6z" />

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 79 KiB

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.ttf

Binary file not shown.

BIN
src/Squidex/app/theme/icomoon/fonts/icomoon.woff

Binary file not shown.

3056
src/Squidex/app/theme/icomoon/selection.json

File diff suppressed because one or more lines are too long

124
src/Squidex/app/theme/icomoon/style.css

@ -1,10 +1,10 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?sfm7f7');
src: url('fonts/icomoon.eot?sfm7f7#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?sfm7f7') format('truetype'),
url('fonts/icomoon.woff?sfm7f7') format('woff'),
url('fonts/icomoon.svg?sfm7f7#icomoon') format('svg');
src: url('fonts/icomoon.eot?z1dhmx');
src: url('fonts/icomoon.eot?z1dhmx#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?z1dhmx') format('truetype'),
url('fonts/icomoon.woff?z1dhmx') format('woff'),
url('fonts/icomoon.svg?z1dhmx#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
@ -24,6 +24,63 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-spinner2:before {
content: "\e959";
}
.icon-star-full:before {
content: "\e95d";
}
.icon-star-empty:before {
content: "\e95e";
}
.icon-twitter:before {
content: "\e95c";
}
.icon-hour-glass:before {
content: "\e954";
}
.icon-spinner:before {
content: "\e953";
}
.icon-clock:before {
content: "\e950";
}
.icon-bin2:before {
content: "\e902";
}
.icon-earth:before {
content: "\e9ca";
}
.icon-elapsed:before {
content: "\e943";
}
.icon-google:before {
content: "\e93b";
}
.icon-lock:before {
content: "\e934";
}
.icon-microsoft:before {
content: "\e940";
}
.icon-pause:before {
content: "\e92f";
}
.icon-play:before {
content: "\e930";
}
.icon-reset:before {
content: "\e92e";
}
.icon-settings2:before {
content: "\e92d";
}
.icon-timeout:before {
content: "\e944";
}
.icon-unlocked:before {
content: "\e933";
}
.icon-grid1:before {
content: "\e952";
}
@ -33,6 +90,9 @@
.icon-info:before {
content: "\e93c";
}
.icon-control-Stars:before {
content: "\e93a";
}
.icon-control-Color:before {
content: "\e94d";
}
@ -201,60 +261,6 @@
.icon-user:before {
content: "\e928";
}
.icon-star-full:before {
content: "\e95d";
}
.icon-star-empty:before {
content: "\e95e";
}
.icon-twitter:before {
content: "\e95c";
}
.icon-hour-glass:before {
content: "\e954";
}
.icon-spinner:before {
content: "\e953";
}
.icon-clock:before {
content: "\e950";
}
.icon-bin2:before {
content: "\e902";
}
.icon-earth:before {
content: "\e9ca";
}
.icon-elapsed:before {
content: "\e943";
}
.icon-google:before {
content: "\e93b";
}
.icon-lock:before {
content: "\e934";
}
.icon-microsoft:before {
content: "\e940";
}
.icon-pause:before {
content: "\e92f";
}
.icon-play:before {
content: "\e930";
}
.icon-reset:before {
content: "\e92e";
}
.icon-settings2:before {
content: "\e92d";
}
.icon-timeout:before {
content: "\e944";
}
.icon-unlocked:before {
content: "\e933";
}
.icon-backup:before {
content: "\e95b";
}

BIN
src/Squidex/wwwroot/images/loader-white.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Loading…
Cancel
Save