Skip to content

Commit b60bf5f

Browse files
Fix drag and drop on NativeDnD set to false (#6346)
1 parent a85d414 commit b60bf5f

File tree

5 files changed

+112
-50
lines changed

5 files changed

+112
-50
lines changed

docs/api/datasource.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ If the `records` property is not an instance of `DataRecords`, it will be conver
4646

4747
### Parameters
4848

49-
* `props` **DataSourceProps** Properties to initialize the data source.
49+
* `props` **DataSourceProps\<DRProps>** Properties to initialize the data source.
5050
* `opts` **DataSourceOptions** Options to initialize the data source.
5151

5252
## records
5353

5454
Retrieves the collection of records associated with this data source.
5555

56-
Returns **DataRecords** The collection of data records.
56+
Returns **DataRecords\<DRProps>** The collection of data records.
5757

5858
## em
5959

@@ -67,7 +67,7 @@ Adds a new record to the data source.
6767

6868
### Parameters
6969

70-
* `record` **DataRecordProps** The properties of the record to add.
70+
* `record` **DRProps** The properties of the record to add.
7171
* `opts` **AddOptions?** Options to apply when adding the record.
7272

7373
Returns **DataRecord** The added data record.
@@ -80,14 +80,14 @@ Retrieves a record from the data source by its ID.
8080

8181
* `id` **([string][6] | [number][7])** The ID of the record to retrieve.
8282

83-
Returns **(DataRecord | [undefined][8])** The data record, or `undefined` if no record is found with the given ID.
83+
Returns **(DataRecord\<DRProps> | [undefined][8])** The data record, or `undefined` if no record is found with the given ID.
8484

8585
## getRecords
8686

8787
Retrieves all records from the data source.
8888
Each record is processed with the `getRecord` method to apply any read transformers.
8989

90-
Returns **[Array][9]<(DataRecord | [undefined][8])>** An array of data records.
90+
Returns **[Array][9]<(DataRecord\<DRProps> | [undefined][8])>** An array of data records.
9191

9292
## removeRecord
9393

@@ -98,15 +98,15 @@ Removes a record from the data source by its ID.
9898
* `id` **([string][6] | [number][7])** The ID of the record to remove.
9999
* `opts` **RemoveOptions?** Options to apply when removing the record.
100100

101-
Returns **(DataRecord | [undefined][8])** The removed data record, or `undefined` if no record is found with the given ID.
101+
Returns **(DataRecord\<DRProps> | [undefined][8])** The removed data record, or `undefined` if no record is found with the given ID.
102102

103103
## setRecords
104104

105105
Replaces the existing records in the data source with a new set of records.
106106

107107
### Parameters
108108

109-
* `records` **[Array][9]\<DataRecordProps>** An array of data record properties to set.
109+
* `records` **[Array][9]\<DRProps>** An array of data record properties to set.
110110

111111
Returns **[Array][9]\<DataRecord>** An array of the added data records.
112112

packages/core/src/block_manager/view/BlockView.ts

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { on, off } from '../../utils/dom';
55
import { hasDnd } from '../../utils/mixins';
66
import { BlockManagerConfig } from '../config/config';
77
import Block from '../model/Block';
8+
import ComponentSorter from '../../utils/sorter/ComponentSorter';
9+
import CanvasNewComponentNode from '../../utils/sorter/CanvasNewComponentNode';
810

911
export interface BlockViewConfig {
1012
em?: EditorModel;
1113
pStylePrefix?: string;
1214
appendOnClick?: BlockManagerConfig['appendOnClick'];
13-
getSorter?: any;
15+
getSorter?: () => ComponentSorter<CanvasNewComponentNode>;
1416
}
1517

1618
export default class BlockView extends View<Block> {
@@ -52,24 +54,30 @@ export default class BlockView extends View<Block> {
5254
} else if (isFunction(onClick)) {
5355
return onClick(model, em?.getEditor(), { event: ev });
5456
}
55-
const sorter = config.getSorter();
57+
const sorter = config.getSorter?.();
58+
if (!sorter) return;
5659
const content = model.get('content')!;
60+
let dropModel = this.getTempDropModel(content);
61+
const el = dropModel.view?.el;
62+
const sources = el ? [{ element: el, dragSource: { content } }] : [];
5763
const selected = em.getSelected();
58-
sorter.setDropContent(content);
59-
let target, valid, insertAt;
64+
let target,
65+
valid,
66+
insertAt,
67+
index = 0;
6068

6169
// If there is a selected component, try first to append
6270
// the block inside, otherwise, try to place it as a next sibling
6371
if (selected) {
64-
valid = sorter.validTarget(selected.getEl(), content);
72+
valid = sorter.validTarget(selected.getEl(), sources, index);
6573

66-
if (valid.valid) {
74+
if (valid) {
6775
target = selected;
6876
} else {
6977
const parent = selected.parent();
7078
if (parent) {
71-
valid = sorter.validTarget(parent.getEl(), content);
72-
if (valid.valid) {
79+
valid = sorter.validTarget(parent.getEl(), sources, index);
80+
if (valid) {
7381
target = parent;
7482
insertAt = parent.components().indexOf(selected) + 1;
7583
}
@@ -80,8 +88,8 @@ export default class BlockView extends View<Block> {
8088
// If no target found yet, try to append the block to the wrapper
8189
if (!target) {
8290
const wrapper = em.getWrapper()!;
83-
valid = sorter.validTarget(wrapper.getEl(), content);
84-
if (valid.valid) target = wrapper;
91+
valid = sorter.validTarget(wrapper.getEl(), sources, index);
92+
if (valid) target = wrapper;
8593
}
8694

8795
const result = target && target.append(content, { at: insertAt })[0];
@@ -100,9 +108,11 @@ export default class BlockView extends View<Block> {
100108
em.refreshCanvas();
101109
const sorter = config.getSorter();
102110
sorter.__currentBlock = model;
103-
sorter.setDragHelper(this.el, e);
104-
sorter.setDropContent(this.model.get('content'));
105-
sorter.startSort([this.el]);
111+
const content = this.model.get('content');
112+
let dropModel = this.getTempDropModel(content);
113+
const el = dropModel.view?.el;
114+
const sources = el ? [{ element: el, dragSource: { content } }] : [];
115+
sorter.startSort(sources);
106116
on(document, 'mouseup', this.endDrag);
107117
}
108118

@@ -124,9 +134,29 @@ export default class BlockView extends View<Block> {
124134
*/
125135
endDrag() {
126136
off(document, 'mouseup', this.endDrag);
127-
const sorter = this.config.getSorter();
137+
const sorter = this.config.getSorter?.();
138+
if (sorter) {
139+
sorter.endDrag();
140+
}
141+
}
128142

129-
sorter.cancelDrag();
143+
/**
144+
* Generates a temporary model of the content being dragged for use with the sorter.
145+
* @returns The temporary model representing the dragged content.
146+
*/
147+
private getTempDropModel(content?: any) {
148+
const comps = this.em.Components.getComponents();
149+
const opts = {
150+
avoidChildren: 1,
151+
avoidStore: 1,
152+
avoidUpdateStyle: 1,
153+
};
154+
const tempModel = comps.add(content, { ...opts, temporary: true });
155+
let dropModel = comps.remove(tempModel, { ...opts, temporary: true } as any);
156+
// @ts-ignore
157+
dropModel = dropModel instanceof Array ? dropModel[0] : dropModel;
158+
dropModel.view?.$el.data('model', dropModel);
159+
return dropModel;
130160
}
131161

132162
render() {

packages/core/src/block_manager/view/BlocksView.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Block from '../model/Block';
77
import Categories from '../../abstract/ModuleCategories';
88
import BlockView from './BlockView';
99
import CategoryView from '../../abstract/ModuleCategoryView';
10+
import CanvasNewComponentNode from '../../utils/sorter/CanvasNewComponentNode';
11+
import { DragDirection } from '../../utils/sorter/types';
1012

1113
export interface BlocksViewConfig {
1214
em: EditorModel;
@@ -71,23 +73,30 @@ export default class BlocksView extends View {
7173
if (!this.sorter) {
7274
const utils = em.Utils;
7375
const canvas = em.Canvas;
74-
75-
this.sorter = new utils.Sorter({
76-
// @ts-ignore
77-
container: canvas.getBody(),
78-
placer: canvas.getPlacerEl(),
79-
containerSel: '*',
80-
itemSel: '*',
81-
pfx: this.ppfx,
82-
onStart: this.onDrag,
83-
onEndMove: this.onDrop,
84-
onMove: this.onMove,
85-
document: canvas.getFrameEl().contentDocument,
86-
direction: 'a',
87-
wmargin: 1,
88-
nested: 1,
76+
this.sorter = new utils.ComponentSorter({
8977
em,
90-
canvasRelative: 1,
78+
treeClass: CanvasNewComponentNode,
79+
containerContext: {
80+
container: canvas.getBody(),
81+
containerSel: '*',
82+
itemSel: '*',
83+
pfx: this.ppfx,
84+
placeholderElement: canvas.getPlacerEl()!,
85+
document: canvas.getBody().ownerDocument,
86+
},
87+
dragBehavior: {
88+
dragDirection: DragDirection.BothDirections,
89+
nested: true,
90+
},
91+
positionOptions: {
92+
windowMargin: 1,
93+
canvasRelative: true,
94+
},
95+
eventHandlers: {
96+
legacyOnStartSort: this.onDrag,
97+
legacyOnEndMove: this.onDrop,
98+
legacyOnMoveClb: this.onMove,
99+
},
91100
});
92101
}
93102

packages/core/src/utils/sorter/ComponentSorter.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
SorterEventHandlers,
1313
DragSource,
1414
} from './types';
15+
import Block from '../../block_manager/model/Block';
1516

1617
const targetSpotType = CanvasSpotBuiltInTypes.Target;
1718

@@ -22,6 +23,8 @@ const spotTarget = {
2223

2324
export default class ComponentSorter<NodeType extends BaseComponentNode> extends Sorter<Component, NodeType> {
2425
targetIsText: boolean = false;
26+
// For event triggering
27+
__currentBlock?: Block;
2528
constructor({
2629
em,
2730
treeClass,

packages/core/src/utils/sorter/Sorter.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
7171
* @param {HTMLElement[]} sources[]
7272
* */
7373
startSort(sources: { element?: HTMLElement; dragSource?: DragSource<T> }[]) {
74-
const validSources = sources.filter((source) => !!source.dragSource || this.findValidSourceElement(source.element));
75-
76-
const sourcesWithModel: { model: T; content?: any }[] = validSources.map((source) => {
77-
return {
78-
model: $(source.element)?.data('model'),
79-
content: source.dragSource,
80-
};
81-
});
82-
const sortedSources = sourcesWithModel.sort((a, b) => {
83-
return sortDom(a.model, b.model);
84-
});
85-
const sourceNodes = sortedSources.map((source) => new this.treeClass(source.model, source.content));
74+
const { sourceNodes, sourcesWithModel } = this.getSourceNodes(sources);
8675
this.sourceNodes = sourceNodes;
8776
this.dropLocationDeterminer.startSort(sourceNodes);
8877
this.bindDragEventHandlers();
@@ -104,6 +93,37 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
10493
this.em.trigger('sorter:drag:start', sources[0], sourcesWithModel[0]);
10594
}
10695

96+
validTarget(
97+
targetEl: HTMLElement | undefined,
98+
sources: { element?: HTMLElement; dragSource?: DragSource<T> }[],
99+
index: number,
100+
): boolean {
101+
if (!targetEl) return false;
102+
const targetModel = $(targetEl).data('model');
103+
if (!targetModel) return false;
104+
105+
const targetNode = new this.treeClass(targetModel);
106+
const { sourceNodes } = this.getSourceNodes(sources);
107+
const canMove = sourceNodes.some((node) => targetNode.canMove(node, index));
108+
return canMove;
109+
}
110+
111+
private getSourceNodes(sources: { element?: HTMLElement; dragSource?: DragSource<T> }[]) {
112+
const validSources = sources.filter((source) => !!source.dragSource || this.findValidSourceElement(source.element));
113+
114+
const sourcesWithModel: { model: T; content?: any }[] = validSources.map((source) => {
115+
return {
116+
model: $(source.element)?.data('model'),
117+
content: source.dragSource,
118+
};
119+
});
120+
const sortedSources = sourcesWithModel.sort((a, b) => {
121+
return sortDom(a.model, b.model);
122+
});
123+
const sourceNodes = sortedSources.map((source) => new this.treeClass(source.model, source.content));
124+
return { sourceNodes, sourcesWithModel };
125+
}
126+
107127
/**
108128
* This method is should be called when the user scrolls within the container.
109129
*/

0 commit comments

Comments
 (0)