diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs index 6eef2043f..0299cee87 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs @@ -122,7 +122,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// 404 => Schema, field or app not found. /// [HttpPut] - [Route("apps/{app}/schemas/{name}/fields/{parentId:long}/ordering/")] + [Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/ordering/")] [ProducesResponseType(typeof(ErrorDto), 400)] [ApiCosts(1)] public async Task PutNestedFieldOrdering(string app, string name, long parentId, [FromBody] ReorderFieldsDto request) diff --git a/src/Squidex/app/app.module.ts b/src/Squidex/app/app.module.ts index 9b7142c4a..b65f53064 100644 --- a/src/Squidex/app/app.module.ts +++ b/src/Squidex/app/app.module.ts @@ -12,8 +12,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterModule } from '@angular/router'; -import { DragulaModule } from 'ng2-dragula'; - +import { DndModule } from 'ng2-dnd'; import { AppComponent } from './app.component'; diff --git a/src/Squidex/app/features/api/module.ts b/src/Squidex/app/features/api/module.ts index 7f7614cdc..f4701b425 100644 --- a/src/Squidex/app/features/api/module.ts +++ b/src/Squidex/app/features/api/module.ts @@ -7,7 +7,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { DndModule } from 'ng2-dnd'; import { SqxFrameworkModule, @@ -37,7 +36,6 @@ const routes: Routes = [ @NgModule({ imports: [ - DndModule, SqxFrameworkModule, SqxSharedModule, RouterModule.forChild(routes) diff --git a/src/Squidex/app/features/content/module.ts b/src/Squidex/app/features/content/module.ts index e7064c595..c3d18210a 100644 --- a/src/Squidex/app/features/content/module.ts +++ b/src/Squidex/app/features/content/module.ts @@ -7,7 +7,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { DndModule } from 'ng2-dnd'; import { CanDeactivateGuard, @@ -82,7 +81,6 @@ const routes: Routes = [ imports: [ SqxFrameworkModule, SqxSharedModule, - DndModule, RouterModule.forChild(routes) ], declarations: [ diff --git a/src/Squidex/app/features/content/shared/references-editor.component.html b/src/Squidex/app/features/content/shared/references-editor.component.html index caa531af3..be514e0df 100644 --- a/src/Squidex/app/features/content/shared/references-editor.component.html +++ b/src/Squidex/app/features/content/shared/references-editor.component.html @@ -7,9 +7,9 @@ - - - + + -
+
@@ -102,26 +102,30 @@
- + + -
- - - -
- -
- - - -
+
+
+ + + +
+
- - - +
+ + + +
+ + + + +
\ No newline at end of file diff --git a/src/Squidex/app/features/schemas/pages/schema/field.component.scss b/src/Squidex/app/features/schemas/pages/schema/field.component.scss index b23caa70b..2a79f7ffa 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field.component.scss +++ b/src/Squidex/app/features/schemas/pages/schema/field.component.scss @@ -87,8 +87,4 @@ $padding: 1rem; min-width: 4rem; max-width: 6rem; } -} - -.dnd-sortable-drag { - border: 0; } \ No newline at end of file diff --git a/src/Squidex/app/features/schemas/pages/schema/field.component.ts b/src/Squidex/app/features/schemas/pages/schema/field.component.ts index 22f789bed..c9c244ee0 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/field.component.ts @@ -41,6 +41,9 @@ export class FieldComponent implements OnInit { @Input() public parent: RootFieldDto; + @Input() + public handleClass: string; + @Input() public patterns: ImmutableArray; diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html index d791146b5..1a47ac598 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.html @@ -59,17 +59,15 @@
-
-
-
- -
+ +
+
-
+ diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss index e4adeb7bb..fcbc34891 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss +++ b/src/Squidex/app/features/schemas/pages/schema/schema-page.component.scss @@ -58,8 +58,4 @@ &-text { font-size: .9rem; } -} - -.dnd-sortable-drag { - border: 0; } \ No newline at end of file diff --git a/src/Squidex/app/features/settings/module.ts b/src/Squidex/app/features/settings/module.ts index 5672f29ac..f43871ef9 100644 --- a/src/Squidex/app/features/settings/module.ts +++ b/src/Squidex/app/features/settings/module.ts @@ -7,7 +7,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { DndModule } from 'ng2-dnd'; import { HelpComponent, @@ -156,7 +155,6 @@ const routes: Routes = [ @NgModule({ imports: [ - DndModule, SqxFrameworkModule, SqxSharedModule, RouterModule.forChild(routes) diff --git a/src/Squidex/app/features/settings/pages/languages/language.component.html b/src/Squidex/app/features/settings/pages/languages/language.component.html index 6a1c88efb..fb6a2f7a8 100644 --- a/src/Squidex/app/features/settings/pages/languages/language.component.html +++ b/src/Squidex/app/features/settings/pages/languages/language.component.html @@ -38,8 +38,8 @@
-
-
+
+
{{language.englishName}} diff --git a/src/Squidex/app/framework/angular/sorted.directive.ts b/src/Squidex/app/framework/angular/sorted.directive.ts index 9a2f573af..5a82887d1 100644 --- a/src/Squidex/app/framework/angular/sorted.directive.ts +++ b/src/Squidex/app/framework/angular/sorted.directive.ts @@ -6,56 +6,90 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { Directive, EventEmitter, Output } from '@angular/core'; +import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, Renderer2 } from '@angular/core'; -import { - DragDropSortableService, - SortableComponent, - SortableContainer -} from 'ng2-dnd'; +import * as dragula from 'dragula'; @Directive({ - selector: '[sqxSorted]' + selector: '[sqxSortModel]' }) -export class SortedDirective { - private oldArray: any[]; +export class SortedDirective implements OnDestroy, OnInit { + private drake: dragula.Drake; + + @Input('sqxSortModel') + public sortModel: any[]; + + @Input() + public handleClass: string | null = null; @Output('sqxSorted') - public sorted = new EventEmitter>(); + public sorted = new EventEmitter(); constructor( - sortableComponent: SortableComponent, - sortableContainer: SortableContainer, - sortableDragDropService: DragDropSortableService + private readonly elementRef: ElementRef, + private readonly renderer: Renderer2 ) { - const oldDragStartCallback = sortableComponent._onDragStartCallback.bind(sortableComponent); + } - if (Array.isArray(sortableContainer.sortableData)) { - sortableComponent._onDragStartCallback = () => { - oldDragStartCallback(); + public ngOnDestroy() { + this.drake.destroy(); + } - this.oldArray = [...sortableContainer.sortableData]; - }; + public ngOnInit() { + const handleClass = this.handleClass; - const oldDropCallback = sortableComponent._onDropCallback.bind(sortableComponent); + this.drake = dragula([this.elementRef.nativeElement], { + ignoreInputTextSelection: true, - sortableComponent._onDropCallback = (event: Event) => { - oldDropCallback(event); + moves: (element, container, handle: HTMLElement) => { + if (!handleClass) { + return true; + } - if (sortableDragDropService.isDragged) { - const newArray: any[] = sortableContainer.sortableData; - const oldArray = this.oldArray; + let current: HTMLElement | null = handle; - if (newArray && oldArray && newArray.length === oldArray.length) { - for (let i = 0; i < oldArray.length; i++) { - if (oldArray[i] !== newArray[i]) { - this.sorted.emit(newArray); - break; - } - } + while (current && current !== container) { + if (current.classList.contains(handleClass)) { + return true; } + + current = current.parentNode; } - }; - } + + return false; + } + }); + + let dragIndex: number; + let dropIndex: number; + + this.drake.on('dragend', (element: any, container: any) => { + this.renderer.removeClass(element, 'sorting'); + }); + + this.drake.on('drag', (element: any, container: any) => { + this.renderer.addClass(element, 'sorting'); + + dragIndex = this.domIndexOf(container, element); + }); + + this.drake.on('drop', (element: any, container: any) => { + dropIndex = this.domIndexOf(container, element); + + if (this.sortModel && dragIndex !== dropIndex) { + const newModel = [...this.sortModel]; + + const item = this.sortModel[dragIndex]; + + newModel.splice(dragIndex, 1); + newModel.splice(dropIndex, 0, item); + + this.sorted.emit(newModel); + } + }); + } + + private domIndexOf(parent: any, child: any): any { + return Array.prototype.indexOf.call(parent.children, child); } -} +} \ No newline at end of file diff --git a/src/Squidex/app/theme/_common.scss b/src/Squidex/app/theme/_common.scss index a271702fb..185624ead 100644 --- a/src/Squidex/app/theme/_common.scss +++ b/src/Squidex/app/theme/_common.scss @@ -113,7 +113,9 @@ body { // Drop area for drag and drop features. // .drop-container { - position: relative; + & { + position: relative; + } .drop-area { & { @@ -147,6 +149,13 @@ body { } } +.sorting { + &, + & > * { + @include opacity(.5); + } +} + // // Animations // diff --git a/src/Squidex/app/theme/theme.scss b/src/Squidex/app/theme/theme.scss index c91f6a74d..3dca4d75d 100644 --- a/src/Squidex/app/theme/theme.scss +++ b/src/Squidex/app/theme/theme.scss @@ -6,8 +6,8 @@ // Pikaday @import '~pikaday/css/pikaday.css'; -// Drag and Drop -@import '~ng2-dnd/bundles/style.css'; +// Dragula +@import '~dragula/dist/dragula.css'; // Bootstrap Overrides @import '_bootstrap.scss'; diff --git a/src/Squidex/package-lock.json b/src/Squidex/package-lock.json index e25471e46..b89285982 100644 --- a/src/Squidex/package-lock.json +++ b/src/Squidex/package-lock.json @@ -121,6 +121,12 @@ "integrity": "sha1-mL1OSb1cXo2l2F36pYnfwmm3sGc=", "dev": true }, + "@types/dragula": { + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/@types/dragula/-/dragula-2.1.33.tgz", + "integrity": "sha512-cb5BNoOXPZ4Bohe+TC7/bbNxbFOL9T+32xjlU2h7gJfCg+9qV/5uX1mVm7dfyFutVdxAQDjZemGz2m9Dav8rMA==", + "dev": true + }, "@types/graphql": { "version": "0.11.7", "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.7.tgz", diff --git a/src/Squidex/package.json b/src/Squidex/package.json index be2f9f8a4..d3eea2053 100644 --- a/src/Squidex/package.json +++ b/src/Squidex/package.json @@ -29,11 +29,11 @@ "babel-polyfill": "6.26.0", "bootstrap": "4.0.0", "core-js": "2.5.3", + "dragula": "^3.7.2", "graphiql": "0.11.11", "moment": "2.20.1", "mousetrap": "1.6.1", "ng2-dnd": "5.0.2", - "ng2-dragula": "^1.5.0", "oidc-client": "1.4.1", "pikaday": "1.7.0", "progressbar.js": "1.0.1", @@ -48,6 +48,7 @@ "@angular/compiler-cli": "5.2.1", "@ngtools/webpack": "1.9.5", "@types/core-js": "0.9.45", + "@types/dragula": "^2.1.33", "@types/jasmine": "2.5.45", "@types/mousetrap": "1.6", "@types/node": "8.5.2",