Browse Source

CDK Drag

pull/425/head
Sebastian Stehle 6 years ago
parent
commit
0798fb98e7
  1. 19
      src/Squidex/app-config/webpack.config.js
  2. 2
      src/Squidex/app/app.module.ts
  3. 2
      src/Squidex/app/features/content/module.ts
  4. 12
      src/Squidex/app/features/content/shared/array-editor.component.html
  5. 16
      src/Squidex/app/features/content/shared/array-editor.component.ts
  6. 4
      src/Squidex/app/features/content/shared/array-item.component.html
  7. 11
      src/Squidex/app/features/content/shared/assets-editor.component.html
  8. 8
      src/Squidex/app/features/content/shared/assets-editor.component.ts
  9. 2
      src/Squidex/app/features/content/shared/reference-item.component.ts
  10. 10
      src/Squidex/app/features/content/shared/references-editor.component.html
  11. 8
      src/Squidex/app/features/content/shared/references-editor.component.ts
  12. 2
      src/Squidex/app/features/schemas/module.ts
  13. 21
      src/Squidex/app/features/schemas/pages/schema/field.component.html
  14. 7
      src/Squidex/app/features/schemas/pages/schema/field.component.scss
  15. 16
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  16. 8
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts
  17. 12
      src/Squidex/app/features/settings/pages/languages/language.component.html
  18. 8
      src/Squidex/app/features/settings/pages/languages/language.component.ts
  19. 16
      src/Squidex/app/framework/angular/drag-helper.ts
  20. 1
      src/Squidex/app/framework/internal.ts
  21. 2
      src/Squidex/app/shared/components/geolocation-editor.component.ts
  22. 27
      src/Squidex/app/shared/components/schema-category.component.html
  23. 50
      src/Squidex/app/shared/components/schema-category.component.scss
  24. 16
      src/Squidex/app/shared/components/schema-category.component.ts
  25. 5
      src/Squidex/app/shared/module.ts
  26. 32
      src/Squidex/app/theme/_common.scss
  27. 85
      src/Squidex/package-lock.json
  28. 9
      src/Squidex/package.json

19
src/Squidex/app-config/webpack.config.js

@ -25,7 +25,9 @@ const plugins = {
// https://github.com/NMFR/optimize-css-assets-webpack-plugin // https://github.com/NMFR/optimize-css-assets-webpack-plugin
OptimizeCSSAssetsPlugin: require("optimize-css-assets-webpack-plugin"), OptimizeCSSAssetsPlugin: require("optimize-css-assets-webpack-plugin"),
// https://github.com/jrparish/tslint-webpack-plugin // https://github.com/jrparish/tslint-webpack-plugin
TsLintPlugin: require('tslint-webpack-plugin') TsLintPlugin: require('tslint-webpack-plugin'),
// https://www.npmjs.com/package/@angular-devkit/build-optimizer
BuildOptimizer: require('@angular-devkit/build-optimizer')
}; };
module.exports = function (env) { module.exports = function (env) {
@ -335,6 +337,21 @@ module.exports = function (env) {
}) })
} }
// Optimization plugin for production build.
if (isProduction) {
config.module.rules.push({
test: /\.js$/,
use: [{
loader: '@angular-devkit/build-optimizer/webpack-loader?sourceMap=false',
options: {
sourceMap: false
}
}]
});
config.plugins.push(new plugins.BuildOptimizer.BuildOptimizerWebpackPlugin());
}
if (isProduction) { if (isProduction) {
config.module.rules.push({ config.module.rules.push({
test: /\.scss$/, test: /\.scss$/,

2
src/Squidex/app/app.module.ts

@ -12,7 +12,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { DndModule } from 'ng2-dnd';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -75,7 +74,6 @@ export function configCurrency() {
imports: [ imports: [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
DndModule.forRoot(),
HttpClientModule, HttpClientModule,
FormsModule, FormsModule,
CommonModule, CommonModule,

2
src/Squidex/app/features/content/module.ts

@ -7,7 +7,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { DndModule } from 'ng2-dnd';
import { import {
CanDeactivateGuard, CanDeactivateGuard,
@ -102,7 +101,6 @@ const routes: Routes = [
@NgModule({ @NgModule({
imports: [ imports: [
DndModule,
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule, SqxSharedModule,
RouterModule.forChild(routes) RouterModule.forChild(routes)

12
src/Squidex/app/features/content/shared/array-editor.component.html

@ -1,7 +1,12 @@
<div class="array-container" *ngIf="arrayControl.controls.length > 0" <div class="array-container" *ngIf="arrayControl.controls.length > 0"
[sqxSortModel]="arrayControl.controls" cdkDropList
(sqxSort)="sort($event)"> [cdkDropListDisabled]="false"
<div class="item" *ngFor="let itemForm of arrayControl.controls; let i = index"> [cdkDropListData]="arrayControl.controls"
(cdkDropListDropped)="sort($event)">
<div *ngFor="let itemForm of arrayControl.controls; let i = index"
class="table-drag item"
cdkDrag
cdkDragLockAxis="y">
<sqx-array-item <sqx-array-item
[form]="form" [form]="form"
[formContext]="formContext" [formContext]="formContext"
@ -18,6 +23,7 @@
(move)="move(itemForm, $event)" (move)="move(itemForm, $event)"
(remove)="itemRemove(i)" (remove)="itemRemove(i)"
(toggle)="hide($event)"> (toggle)="hide($event)">
<i cdkDragHandle class="icon-drag2"></i>
</sqx-array-item> </sqx-array-item>
</div> </div>
</div> </div>

16
src/Squidex/app/features/content/shared/array-editor.component.ts

@ -5,6 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
import { AbstractControl, FormArray, FormGroup } from '@angular/forms'; import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
@ -12,6 +13,7 @@ import {
AppLanguageDto, AppLanguageDto,
EditContentForm, EditContentForm,
RootFieldDto, RootFieldDto,
sorted,
StatefulComponent StatefulComponent
} from '@app/shared'; } from '@app/shared';
@ -62,10 +64,8 @@ export class ArrayEditorComponent extends StatefulComponent<State> {
this.form.arrayItemInsert(this.field, this.language, value); this.form.arrayItemInsert(this.field, this.language, value);
} }
public sort(controls: ReadonlyArray<AbstractControl>) { public sort(event: CdkDragDrop<ReadonlyArray<AbstractControl>>) {
for (let i = 0; i < controls.length; i++) { this.sortInternal(sorted(event));
this.arrayControl.setControl(i, controls[i]);
}
} }
public move(control: AbstractControl, index: number) { public move(control: AbstractControl, index: number) {
@ -74,6 +74,12 @@ export class ArrayEditorComponent extends StatefulComponent<State> {
controls.splice(controls.indexOf(control), 1); controls.splice(controls.indexOf(control), 1);
controls.splice(index, 0, control); controls.splice(index, 0, control);
this.sort(controls); this.sortInternal(controls);
}
private sortInternal(controls: ReadonlyArray<AbstractControl>) {
for (let i = 0; i < controls.length; i++) {
this.arrayControl.setControl(i, controls[i]);
}
} }
} }

4
src/Squidex/app/features/content/shared/array-item.component.html

@ -1,7 +1,9 @@
<div class="card item" [class.invalid]="isInvalid | async"> <div class="card item" [class.invalid]="isInvalid | async">
<div class="card-header drag-handle"> <div class="card-header drag-handle">
<span class="pull-left"> <span class="pull-left">
<i class="icon-drag2 mr-1"></i> <span class="mr-1">
<ng-content></ng-content>
</span>
<span class="header-text text-decent">Item #{{index + 1}}</span> <span class="header-text text-decent">Item #{{index + 1}}</span>

11
src/Squidex/app/features/content/shared/assets-editor.component.html

@ -42,9 +42,14 @@
</sqx-asset> </sqx-asset>
<div <div
[sqxSortModel]="snapshot.assets" cdkDropList
(sqxSort)="sortAssets($event)"> [cdkDropListDisabled]="snapshot.isDisabled"
<div *ngFor="let asset of snapshot.assets; trackBy: trackByAsset"> [cdkDropListData]="snapshot.assets"
(cdkDropListDropped)="sortAssets($event)">
<div *ngFor="let asset of snapshot.assets; trackBy: trackByAsset"
class="table-drag"
cdkDrag
cdkDragLockAxis="y">
<sqx-asset [asset]="asset" removeMode="true" <sqx-asset [asset]="asset" removeMode="true"
[isListView]="true" [isListView]="true"
[isCompact]="isCompact" [isCompact]="isCompact"

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

@ -5,6 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { NG_VALUE_ACCESSOR } from '@angular/forms';
@ -15,6 +16,7 @@ import {
DialogModel, DialogModel,
LocalStoreService, LocalStoreService,
MessageBus, MessageBus,
sorted,
StatefulControlComponent, StatefulControlComponent,
Types Types
} from '@app/shared'; } from '@app/shared';
@ -133,9 +135,9 @@ export class AssetsEditorComponent extends StatefulControlComponent<State, strin
} }
} }
public sortAssets(assets: ReadonlyArray<AssetDto>) { public sortAssets(event: CdkDragDrop<ReadonlyArray<AssetDto>>) {
if (assets) { if (event) {
this.setAssets(assets); this.setAssets(sorted(event));
this.updateValue(); this.updateValue();
} }

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

@ -21,7 +21,7 @@ import {
template: ` template: `
<tr> <tr>
<td class="cell-select"> <td class="cell-select">
<i class="icon-drag2 drag-handle"></i> <ng-content></ng-content>
</td> </td>
<td class="cell-user" *ngIf="!isCompact"> <td class="cell-user" *ngIf="!isCompact">

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

@ -7,14 +7,20 @@
</div> </div>
<table class="table table-items table-fixed" [class.disabled]="snapshot.isDisabled" *ngIf="snapshot.contentItems && snapshot.contentItems.length > 0" <table class="table table-items table-fixed" [class.disabled]="snapshot.isDisabled" *ngIf="snapshot.contentItems && snapshot.contentItems.length > 0"
[sqxSortModel]="snapshot.contentItems" cdkDropList
(sqxSort)="sort($event)"> [cdkDropListData]="snapshot.contentItems"
[cdkDropListDisabled]="snapshot.isDisabled"
(cdkDropListDropped)="sort($event)">
<tbody *ngFor="let content of snapshot.contentItems; trackBy: trackByContent" <tbody *ngFor="let content of snapshot.contentItems; trackBy: trackByContent"
[sqxReferenceItem]="content" [sqxReferenceItem]="content"
class="table-drag"
cdkDrag
cdkDragLockAxis="y"
[language]="language" [language]="language"
[isCompact]="isCompact" [isCompact]="isCompact"
[columnCount]="snapshot.columnCount" [columnCount]="snapshot.columnCount"
(delete)="remove(content)"> (delete)="remove(content)">
<i cdkDragHandle class="icon-drag2 drag-handle"></i>
</tbody> </tbody>
</table> </table>
</ng-container> </ng-container>

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

@ -5,6 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { NG_VALUE_ACCESSOR } from '@angular/forms';
@ -14,6 +15,7 @@ import {
ContentDto, ContentDto,
ContentsService, ContentsService,
DialogModel, DialogModel,
sorted,
StatefulControlComponent, StatefulControlComponent,
Types Types
} from '@app/shared'; } from '@app/shared';
@ -113,9 +115,9 @@ export class ReferencesEditorComponent extends StatefulControlComponent<State, s
} }
} }
public sort(contents: ReadonlyArray<ContentDto>) { public sort(event: CdkDragDrop<ReadonlyArray<ContentDto>>) {
if (contents) { if (event) {
this.setContentItems(contents); this.setContentItems(sorted(event));
this.updateValue(); this.updateValue();
} }

2
src/Squidex/app/features/schemas/module.ts

@ -7,7 +7,6 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { DndModule } from 'ng2-dnd';
import { import {
HelpComponent, HelpComponent,
@ -75,7 +74,6 @@ const routes: Routes = [
imports: [ imports: [
SqxFrameworkModule, SqxFrameworkModule,
SqxSharedModule, SqxSharedModule,
DndModule,
RouterModule.forChild(routes) RouterModule.forChild(routes)
], ],
providers: [ providers: [

21
src/Squidex/app/features/schemas/pages/schema/field.component.html

@ -1,6 +1,8 @@
<div class="table-items-row table-items-row-expandable field"> <div class="table-items-row table-items-row-expandable field">
<div class="table-items-row-summary"> <div class="table-items-row-summary">
<i class="icon-drag2 drag-handle"></i> <span class="drag-container">
<ng-content></ng-content>
</span>
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
@ -95,13 +97,20 @@
<span class="nested-field-line-v"></span> <span class="nested-field-line-v"></span>
<div <div
[sqxSortDisabled]="!isEditable" cdkDropList
[sqxSortModel]="nested" [cdkDropListDisabled]="!isEditable"
(sqxSort)="sortFields($event)"> [cdkDropListData]="nested"
<div class="nested-field" *ngFor="let nested of nested; trackBy: trackByFieldFn"> (cdkDropListDropped)="sortFields($event)">
<div *ngFor="let nested of nested; trackBy: trackByFieldFn"
class="nested-field table-drag"
cdkDrag
cdkDragLockAxis="y">
<span class="nested-field-line-h"></span> <span class="nested-field-line-h"></span>
<sqx-field [field]="nested" [schema]="schema" [parent]="field" [patterns]="patterns"></sqx-field> <sqx-field [field]="nested" [schema]="schema" [parent]="field" [patterns]="patterns">
<i cdkDragHandle class="icon-drag2 drag-handle"></i>
</sqx-field>
</div> </div>
</div> </div>

7
src/Squidex/app/features/schemas/pages/schema/field.component.scss

@ -22,8 +22,9 @@ $padding: 1rem;
padding-left: 3rem; padding-left: 3rem;
} }
.drag-handle { .drag-container {
@include absolute(1.75rem, auto, auto, .75rem); @include absolute(1.75rem, auto, auto, .75rem);
line-height: 1px;
} }
.col { .col {
@ -37,6 +38,10 @@ $padding: 1rem;
} }
} }
.field {
position: relative;
}
.nested-fields { .nested-fields {
padding: $padding; padding: $padding;
padding-left: 2 * $padding; padding-left: 2 * $padding;

16
src/Squidex/app/features/schemas/pages/schema/schema-page.component.html

@ -76,11 +76,17 @@
<ng-container *ngIf="patternsState.patterns | async; let patterns"> <ng-container *ngIf="patternsState.patterns | async; let patterns">
<div class="schemas" <div class="schemas"
[sqxSortDisabled]="!schema.canOrderFields" cdkDropList
[sqxSortModel]="schema.fields" [cdkDropListDisabled]="!schema.canOrderFields"
(sqxSort)="sortFields($event)"> [cdkDropListData]="schema.fields"
<div *ngFor="let field of schema.fields; trackBy: trackByFieldFn"> (cdkDropListDropped)="sortFields($event)">
<sqx-field [field]="field" [schema]="schema" [patterns]="patterns"></sqx-field> <div *ngFor="let field of schema.fields; trackBy: trackByFieldFn"
class="table-drag"
cdkDrag
cdkDragLockAxis="y">
<sqx-field [field]="field" [schema]="schema" [patterns]="patterns">
<i cdkDragHandle class="icon-drag2 drag-handle"></i>
</sqx-field>
</div> </div>
</div> </div>

8
src/Squidex/app/features/schemas/pages/schema/schema-page.component.ts

@ -7,6 +7,7 @@
// tslint:disable:no-shadowed-variable // tslint:disable:no-shadowed-variable
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
@ -20,7 +21,8 @@ import {
PatternsState, PatternsState,
ResourceOwner, ResourceOwner,
SchemaDetailsDto, SchemaDetailsDto,
SchemasState SchemasState,
sorted
} from '@app/shared'; } from '@app/shared';
import { import {
@ -79,8 +81,8 @@ export class SchemaPageComponent extends ResourceOwner implements OnInit {
this.schemasState.unpublish(this.schema).subscribe(); this.schemasState.unpublish(this.schema).subscribe();
} }
public sortFields(fields: ReadonlyArray<FieldDto>) { public sortFields(event: CdkDragDrop<ReadonlyArray<FieldDto>>) {
this.schemasState.orderFields(this.schema, fields).subscribe(); this.schemasState.orderFields(this.schema, sorted(event)).subscribe();
} }
public trackByField(index: number, field: FieldDto) { public trackByField(index: number, field: FieldDto) {

12
src/Squidex/app/features/settings/pages/languages/language.component.html

@ -40,13 +40,17 @@
<div class="col-9"> <div class="col-9">
<div class="fallback-languages" <div class="fallback-languages"
[sqxSortModel]="fallbackLanguages" cdkDropList
[sqxSortDisabled]="!isEditable" [cdkDropListData]="fallbackLanguages"
[cdkDropListDisabled]="!isEditable"
(cdkDropListDropped)="sort($event)"
*ngIf="fallbackLanguages.length > 0"> *ngIf="fallbackLanguages.length > 0">
<div class="fallback-language" *ngFor="let language of fallbackLanguages"> <div class="fallback-language table-drag" *ngFor="let language of fallbackLanguages"
cdkDrag
cdkDragLockAxis="y">
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col-auto" *ngIf="isEditable"> <div class="col-auto" *ngIf="isEditable">
<i class="icon-drag2 drag-handle mr-1"></i> <i cdkDragHandle class="icon-drag2 drag-handle mr-1"></i>
</div> </div>
<div class="col"> <div class="col">
{{language.englishName}} {{language.englishName}}

8
src/Squidex/app/features/settings/pages/languages/language.component.ts

@ -5,6 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { Component, Input, OnChanges } from '@angular/core'; import { Component, Input, OnChanges } from '@angular/core';
import { FormBuilder } from '@angular/forms'; import { FormBuilder } from '@angular/forms';
@ -12,7 +13,8 @@ import {
AppLanguageDto, AppLanguageDto,
EditLanguageForm, EditLanguageForm,
fadeAnimation, fadeAnimation,
LanguagesState LanguagesState,
sorted
} from '@app/shared'; } from '@app/shared';
@Component({ @Component({
@ -63,6 +65,10 @@ export class LanguageComponent implements OnChanges {
this.languagesState.remove(this.language); this.languagesState.remove(this.language);
} }
public sort(event: CdkDragDrop<ReadonlyArray<AppLanguageDto>>) {
this.fallbackLanguages = sorted(event);
}
public save() { public save() {
if (!this.isEditable) { if (!this.isEditable) {
return; return;

16
src/Squidex/app/framework/angular/drag-helper.ts

@ -0,0 +1,16 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
export function sorted<T>(event: CdkDragDrop<ReadonlyArray<T>>): ReadonlyArray<T> {
const items = <T[]>event.container.data;
moveItemInArray(items, event.previousIndex, event.currentIndex);
return items;
}

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

@ -5,6 +5,7 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
export * from './angular/drag-helper';
export * from './angular/routers/router-utils'; export * from './angular/routers/router-utils';
export * from './angular/animations'; export * from './angular/animations';

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

@ -335,11 +335,11 @@ export class GeolocationEditorComponent extends StatefulControlComponent<Snapsho
if (this.value) { if (this.value) {
if (!this.marker) { if (!this.marker) {
this.marker = new google.maps.Marker({ this.marker = new google.maps.Marker({
map: this.map,
position: { position: {
lat: 0, lat: 0,
lng: 0 lng: 0
}, },
map: this.map,
draggable: true draggable: true
}); });

27
src/Squidex/app/shared/components/schema-category.component.html

@ -1,5 +1,8 @@
<div *ngIf="!forContent || snapshot.filtered.length > 0" dnd-droppable class="droppable category" [allowDrop]="allowDrop" (onDropSuccess)="changeCategory($event.dragData)"> <div *ngIf="!forContent || snapshot.filtered.length > 0" class="droppable category"
<div class="drop-indicator"></div> cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="schemaCategory.name"
(cdkDropListDropped)="changeCategory($event)">
<div class="header clearfix"> <div class="header clearfix">
<button type="button" class="btn btn-sm btn-text-secondary" (click)="toggle()"> <button type="button" class="btn btn-sm btn-text-secondary" (click)="toggle()">
@ -13,10 +16,18 @@
</button> </button>
</div> </div>
<ul class="nav nav-panel nav-dark nav-dark-bordered flex-column" *ngIf="snapshot.isOpen" @fade> <div class="nav nav-panel nav-dark nav-dark-bordered flex-column" @fade>
<ng-container *ngIf="!forContent; else simpleMode"> <ng-container *ngIf="!forContent; else simpleMode">
<li *ngFor="let schema of snapshot.filtered; trackBy: trackBySchema" class="nav-item" dnd-draggable [dragEnabled]="schema.canUpdateCategory" [dragData]="schema"> <div *ngFor="let schema of snapshot.filtered; trackBy: trackBySchema" class="nav-item"
<a class="nav-link" [routerLink]="schemaRoute(schema)" routerLinkActive="active"> routerLinkActive="active"
cdkDropList
cdkDrag
cdkDragLockAxis="y"
[cdkDragData]="schema">
<i cdkDragHandle class="icon-drag2 drag-handle"></i>
<a class="nav-link" [routerLink]="schemaRoute(schema)">
<div class="row"> <div class="row">
<div class="col-4"> <div class="col-4">
<span class="schema-name schema-name-accent">{{schema.displayName}}</span> <span class="schema-name schema-name-accent">{{schema.displayName}}</span>
@ -33,7 +44,7 @@
</div> </div>
</div> </div>
</a> </a>
</li> </div>
</ng-container> </ng-container>
<ng-template #simpleMode> <ng-template #simpleMode>
@ -43,5 +54,7 @@
</a> </a>
</li> </li>
</ng-template> </ng-template>
</ul> </div>
<div class="drop-indicator"></div>
</div> </div>

50
src/Squidex/app/shared/components/schema-category.component.scss

@ -21,17 +21,12 @@ h3 {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.dnd-drag-start {
border: 0;
}
.droppable { .droppable {
& { & {
position: relative; position: relative;
} }
&.dnd-drag-over, &.cdk-drop-list-dragging {
&.dnd-drag-enter {
& { & {
border: 0; border: 0;
} }
@ -43,9 +38,9 @@ h3 {
.drop-indicator { .drop-indicator {
@include absolute($drag-margin, $drag-margin, $drag-margin, $drag-margin); @include absolute($drag-margin, $drag-margin, $drag-margin, $drag-margin);
display: none;
border: 2px dashed $color-dark-black; border: 2px dashed $color-dark-black;
background: none; background: none;
display: none;
pointer-events: none; pointer-events: none;
} }
} }
@ -57,6 +52,47 @@ h3 {
.nav-link { .nav-link {
padding-top: .75rem; padding-top: .75rem;
padding-bottom: .75rem; padding-bottom: .75rem;
border: 0;
}
.nav-item {
& {
border-bottom: 1px solid $color-dark2-separator;
}
&:last-child {
border: 0;
}
&.active {
background: $color-dark2-active-background;
}
&.cdk-drag {
padding-left: 2rem;
padding-right: 0;
position: relative;
}
.drag-handle {
@include absolute(1rem, auto, auto, 1rem);
}
}
.cdk-drag-preview {
background: $color-dark2-background !important;
a {
color: $color-dark1-foreground !important;
}
}
.cdk-drag-placeholder {
display: none;
}
.cdk-drag-animating {
@include transition(none);
} }
.schema { .schema {

16
src/Squidex/app/shared/components/schema-category.component.ts

@ -5,18 +5,16 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { import {
fadeAnimation, fadeAnimation,
isSameCategory,
LocalStoreService, LocalStoreService,
SchemaCategory, SchemaCategory,
SchemaDetailsDto,
SchemaDto, SchemaDto,
SchemasState, SchemasState,
StatefulComponent, StatefulComponent
Types
} from '@app/shared/internal'; } from '@app/shared/internal';
interface State { interface State {
@ -47,10 +45,6 @@ export class SchemaCategoryComponent extends StatefulComponent<State> implements
@Input() @Input()
public forContent: boolean; public forContent: boolean;
public allowDrop = (schema: any) => {
return (Types.is(schema, SchemaDto) || Types.is(schema, SchemaDetailsDto)) && !isSameCategory(this.schemaCategory.name, schema);
}
constructor(changeDetector: ChangeDetectorRef, constructor(changeDetector: ChangeDetectorRef,
private readonly localStore: LocalStoreService, private readonly localStore: LocalStoreService,
private readonly schemasState: SchemasState private readonly schemasState: SchemasState
@ -98,8 +92,10 @@ export class SchemaCategoryComponent extends StatefulComponent<State> implements
} }
} }
public changeCategory(schema: SchemaDto) { public changeCategory(drag: CdkDragDrop<any>) {
this.schemasState.changeCategory(schema, this.schemaCategory.name); if (drag.previousContainer !== drag.container) {
this.schemasState.changeCategory(drag.item.data, this.schemaCategory.name);
}
} }
public emitRemove() { public emitRemove() {

5
src/Squidex/app/shared/module.ts

@ -5,10 +5,10 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { DragDropModule } from '@angular/cdk/drag-drop';
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { ModuleWithProviders, NgModule } from '@angular/core'; import { ModuleWithProviders, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { DndModule } from 'ng2-dnd';
import { SqxFrameworkModule } from '@app/framework'; import { SqxFrameworkModule } from '@app/framework';
@ -109,7 +109,7 @@ import { SchemaTagConverter } from './state/schema-tag-converter';
@NgModule({ @NgModule({
imports: [ imports: [
DndModule, DragDropModule,
RouterModule, RouterModule,
SqxFrameworkModule SqxFrameworkModule
], ],
@ -162,6 +162,7 @@ import { SchemaTagConverter } from './state/schema-tag-converter';
AssetUploaderComponent, AssetUploaderComponent,
CommentComponent, CommentComponent,
CommentsComponent, CommentsComponent,
DragDropModule,
FileIconPipe, FileIconPipe,
GeolocationEditorComponent, GeolocationEditorComponent,
HelpComponent, HelpComponent,

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

@ -47,6 +47,38 @@ body {
} }
} }
.cdk-drag-preview {
@include opacity(.7);
&.table-drag {
background: $color-dark-foreground;
border: 2px dashed darken($color-border, 5%);
display: table;
* {
display: none;
}
}
}
.cdk-drag-placeholder {
@include opacity(0);
}
.cdk-drag-animating {
@include transition(transform 250ms cubic-bezier(0, 0, .2, 1));
}
.cdk-drop-list-dragging {
* {
@include transition(transform 250ms cubic-bezier(0, 0, .2, 1));
}
.cdk-drag-placeholder {
@include transition(none);
}
}
.icon-bold { .icon-bold {
font-weight: bold; font-weight: bold;
} }

85
src/Squidex/package-lock.json

@ -4,6 +4,71 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@angular-devkit/build-optimizer": {
"version": "0.803.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.8.tgz",
"integrity": "sha512-UiMxl1wI3acqIoRkC0WA0qpab+ni6SlCaB4UIwfD1H/FdzU80P04AIUuJS7StxjbwVkVtA05kcfgmqzP8yBMVg==",
"dev": true,
"requires": {
"loader-utils": "1.2.3",
"source-map": "0.7.3",
"tslib": "1.10.0",
"typescript": "3.5.3",
"webpack-sources": "1.4.3"
},
"dependencies": {
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
"integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
"dev": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^2.0.0",
"json5": "^1.0.1"
}
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
}
}
},
"@angular-devkit/core": { "@angular-devkit/core": {
"version": "8.3.8", "version": "8.3.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.8.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.8.tgz",
@ -84,6 +149,15 @@
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@angular/cdk": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz",
"integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^1.7.1"
}
},
"@angular/common": { "@angular/common": {
"version": "8.2.9", "version": "8.2.9",
"resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.9.tgz", "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.9.tgz",
@ -9329,11 +9403,6 @@
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
"dev": true "dev": true
}, },
"ng2-dnd": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/ng2-dnd/-/ng2-dnd-5.0.2.tgz",
"integrity": "sha512-5mWWBePwvEPsNd/HkdbD543Q9mPyJofL6zkNydl8/Ah3qrrvZT2DaEPbknY08OgkXpI2qUGksc01OzzVlRQ9dQ=="
},
"ngx-color-picker": { "ngx-color-picker": {
"version": "8.2.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-8.2.0.tgz", "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-8.2.0.tgz",
@ -10068,6 +10137,12 @@
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true "dev": true
}, },
"parse5": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
"integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
"optional": true
},
"parseqs": { "parseqs": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",

9
src/Squidex/package.json

@ -16,6 +16,7 @@
}, },
"dependencies": { "dependencies": {
"@angular/animations": "8.2.9", "@angular/animations": "8.2.9",
"@angular/cdk": "^8.2.3",
"@angular/common": "8.2.9", "@angular/common": "8.2.9",
"@angular/core": "8.2.9", "@angular/core": "8.2.9",
"@angular/forms": "8.2.9", "@angular/forms": "8.2.9",
@ -31,10 +32,9 @@
"graphiql": "0.13.2", "graphiql": "0.13.2",
"graphql": "14.4.2", "graphql": "14.4.2",
"marked": "0.7.0", "marked": "0.7.0",
"mersenne-twister": "^1.1.0", "mersenne-twister": "1.1.0",
"moment": "2.24.0", "moment": "2.24.0",
"mousetrap": "1.6.3", "mousetrap": "1.6.3",
"ng2-dnd": "5.0.2",
"ngx-color-picker": "8.2.0", "ngx-color-picker": "8.2.0",
"oidc-client": "1.9.1", "oidc-client": "1.9.1",
"pikaday": "1.8.0", "pikaday": "1.8.0",
@ -43,18 +43,19 @@
"react-dom": "16.10.2", "react-dom": "16.10.2",
"rxjs": "6.5.3", "rxjs": "6.5.3",
"slugify": "1.3.5", "slugify": "1.3.5",
"sortablejs": "1.10.1", "sortablejs": "^1.10.1",
"tslib": "1.10.0", "tslib": "1.10.0",
"zone.js": "0.10.2" "zone.js": "0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-optimizer": "0.803.8",
"@angular/compiler": "8.2.9", "@angular/compiler": "8.2.9",
"@angular/compiler-cli": "8.2.9", "@angular/compiler-cli": "8.2.9",
"@ngtools/webpack": "8.3.8", "@ngtools/webpack": "8.3.8",
"@types/core-js": "2.5.2", "@types/core-js": "2.5.2",
"@types/jasmine": "3.4.2", "@types/jasmine": "3.4.2",
"@types/marked": "0.6.5", "@types/marked": "0.6.5",
"@types/mersenne-twister": "^1.1.2", "@types/mersenne-twister": "1.1.2",
"@types/mousetrap": "1.6", "@types/mousetrap": "1.6",
"@types/node": "12.7.11", "@types/node": "12.7.11",
"@types/react": "16.9.5", "@types/react": "16.9.5",

Loading…
Cancel
Save