Skip to content

Commit

Permalink
Refactor sorter (#6149)
Browse files Browse the repository at this point in the history
* Add canMove and getChildren to Sorter

* Make the canvas use Components.canMove function

* Fix StyleManager issue

* Make Sorter dependent on an abstract datastructure

* Remove unneeded properties

* Add drag direction enum

* extract method

* Add default values for the sorter

* reverse avoidSelectOnEnd

* Group related options for the Sorter

* Fix types, and fix canvas sorter

* Add method to clear source element freeze

* Add DropLocationDeterminer class

* Refactor some methods in the sorter

* Refactor endMove method

* Refactor rollback method

* Add DropLocationDeterminer, refactor methods in Sorter class

* Break the sorter into multiple classes

* Fix placeholder class jsdocs

* Fix bug while dropping items near the border

* Refactor DropLocationDeterminer

* Add helping methods to the ComponentSorter

* Remove unwanted fields in DropLocationDeterminer

* Add componentSorter Class

* Refactor DropLocationDeterminer Class

* Rename file

* Fix style manager class

* Move files into a new folder

* Move types to a new file

* Add back the tree class paramater instead of abstract classes

* Fix dropping on the same collection issue

* refactor isInFlow

* Change methods to be accessor methods

* Make component sorter dependant on an abstract node

* Fix bug with dropping into an element with no children

* Fix component layers drag and drop

* Remove the ensure placeholder logic from the StyleManagerSorter

* Refactor event handler types

* export interface SorterEventHandlers

* change to ensurePlaceholderElement method

* Make images droppable

* Add support for dragging and dropping textable components

* Remove container argument from startSort

* Trigger events on starting and ending the dragging

* Add triggering old events and callback functions

* Fix drop issue with the style manager

* Add cancelling the dragging

* Hide placeholder if no target

* Refactor droplocationdeteminer and improve performance

* Fix some bugs

* Fix some callbacks

* trigger 'sorter:drag:validation'

* Disable editable text after dropping

* Remove unused functions

* Fix placeholder direction

* Refactor restnode state

* Run formatter

* Remove unused code and redundent comments

* Fix stack test

* Avoid triggering the drop event twice

* Fix styles being removed when dragging components

* change 'sorter:drag:start' event triggering

* Fix legacyOnMove not being triggered

* Some refactor

* Fix selection after cancelling

* Fix triggering update event without moving any component

* fix the sort of dragged components

* make style manager droppable even if the mouse is outside the continer

* Fix selecting blocks after being dropped

* Fix placeholder for empty containers

* Fix blocks drag cancel issue

* Fix style manager cancel

* Fix autoscroll not stopping issue

* Fix comment components drag

* Fix issue with hidden elements

* Fix selection after dropping

* Format

* Fix position on scroll

* remove console.log

* Change target calculation with scroll

* Fix blocks not activating issue

* Fix block drop in wrapper issue

* Fix dropping multiple components in the same position

* Preserve target canvas spot

* Avoid updating non-text related component on drag/drop

* skip sorter tests

---------

Co-authored-by: Artur Arseniev <[email protected]>
  • Loading branch information
mohamedsalem401 and artf authored Sep 30, 2024
1 parent 7300f8c commit 2124bdc
Show file tree
Hide file tree
Showing 26 changed files with 2,278 additions and 1,462 deletions.
9 changes: 2 additions & 7 deletions packages/core/src/block_manager/view/BlockView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default class BlockView extends View<Block> {
sorter.__currentBlock = model;
sorter.setDragHelper(this.el, e);
sorter.setDropContent(this.model.get('content'));
sorter.startSort(this.el);
sorter.startSort([this.el]);
on(document, 'mouseup', this.endDrag);
}

Expand All @@ -126,12 +126,7 @@ export default class BlockView extends View<Block> {
off(document, 'mouseup', this.endDrag);
const sorter = this.config.getSorter();

// After dropping the block in the canvas the mouseup event is not yet
// triggerd on 'this.doc' and so clicking outside, the sorter, tries to move
// things (throws false positives). As this method just need to drop away
// the block helper I use the trick of 'moved = 0' to void those errors.
sorter.moved = 0;
sorter.endMove();
sorter.cancelDrag();
}

render() {
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ export const getOnComponentDrag = (em: Editor) => (data: any) => em.trigger(even
export const getOnComponentDragEnd =
(em: Editor, targets: Component[], opts: { altMode?: boolean } = {}) =>
(a: any, b: any, data: any) => {
targets.forEach((trg) => trg.set('status', trg.get('selectable') ? 'selected' : ''));
em.setSelected(targets);
targets[0].emitUpdate();
setTimeout(() => {
targets.forEach((trg) => trg.set('status', trg.get('selectable') ? 'selected' : ''));
em.setSelected(targets);
targets[0].emitUpdate();
});
em.trigger(`${eventDrag}:end`, data);

// Defer selectComponent in order to prevent canvas "freeze" #2692
Expand Down
16 changes: 7 additions & 9 deletions packages/core/src/commands/view/MoveComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default extend({}, SelectPosition, SelectComponent, {
this.cacheEl = null;
this.startSelectPosition(e.target, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMove.bind(this);
this.sorter.eventHandlers.legacyOnEndMove = this.onEndMove.bind(this);
this.stopSelectComponent();
this.$wrapper.off('mousedown', this.initSorter);
on(this.getContentWindow(), 'keydown', this.rollback);
Expand All @@ -68,7 +68,7 @@ export default extend({}, SelectPosition, SelectComponent, {
var el = model.view.el;
this.startSelectPosition(el, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this);
this.sorter.eventHandlers.legacyOnEndMove = this.onEndMoveFromModel.bind(this);

/*
this.sorter.setDragHelper(el);
Expand All @@ -95,11 +95,10 @@ export default extend({}, SelectPosition, SelectComponent, {
const frameView = this.em.getCurrentFrame();
const el = lastModel.getEl(frameView?.model)!;
const doc = el.ownerDocument;
this.startSelectPosition(el, doc, { onStart: this.onStart });
this.sorter.draggable = lastModel.get('draggable');
this.sorter.toMove = models;
this.sorter.onMoveClb = this.onDrag;
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this);
const elements = models.map((model) => model?.view?.el);
this.startSelectPosition(elements, doc, { onStart: this.onStart });
this.sorter.eventHandlers.legacyOnMoveClb = this.onDrag;
this.sorter.eventHandlers.legacyOnEndMove = this.onEndMoveFromModel.bind(this);
this.stopSelectComponent();
on(this.getContentWindow(), 'keydown', this.rollback);
},
Expand Down Expand Up @@ -134,8 +133,7 @@ export default extend({}, SelectPosition, SelectComponent, {
rollback(e: any, force: boolean) {
var key = e.which || e.keyCode;
if (key == 27 || force) {
this.sorter.moved = false;
this.sorter.endMove();
this.sorter.cancelDrag();
}
return;
},
Expand Down
56 changes: 35 additions & 21 deletions packages/core/src/commands/view/SelectPosition.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
import { $ } from '../../common';
import CanvasComponentNode from '../../utils/sorter/CanvasComponentNode';
import { DragDirection } from '../../utils/sorter/types';
import { CommandObject } from './CommandAbstract';

export default {
/**
* Start select position event
* @param {HTMLElement} trg
* @param {HTMLElement[]} sourceElements
* @private
* */
startSelectPosition(trg: HTMLElement, doc: Document, opts: any = {}) {
startSelectPosition(sourceElements: HTMLElement[], doc: Document, opts: any = {}) {
this.isPointed = false;
const utils = this.em.Utils;
const container = trg.ownerDocument.body;
const container = sourceElements[0].ownerDocument.body;

if (utils && !this.sorter)
this.sorter = new utils.Sorter({
// @ts-ignore
container,
placer: this.canvas.getPlacerEl(),
containerSel: '*',
itemSel: '*',
pfx: this.ppfx,
direction: 'a',
document: doc,
wmargin: 1,
nested: 1,
this.sorter = new utils.ComponentSorter({
em: this.em,
canvasRelative: 1,
scale: () => this.em.getZoomDecimal(),
treeClass: CanvasComponentNode,
containerContext: {
container,
containerSel: '*',
itemSel: '*',
pfx: this.ppfx,
document: doc,
placeholderElement: this.canvas.getPlacerEl()!,
},
positionOptions: {
windowMargin: 1,
canvasRelative: true,
},
dragBehavior: {
dragDirection: DragDirection.BothDirections,
nested: true,
},
});

if (opts.onStart) this.sorter.onStart = opts.onStart;
trg && this.sorter.startSort(trg, { container });
if (opts.onStart) this.sorter.eventHandlers.legacyOnStartSort = opts.onStart;
this.em.on(
'frame:scroll',
((...agrs: any[]) => {
const canvasScroll = this.canvas.getCanvasView().frame === agrs[0].frame;
if (canvasScroll) this.sorter.recalculateTargetOnScroll();
}).bind(this),
);
sourceElements &&
sourceElements.length > 0 &&
this.sorter.startSort(sourceElements.map((element) => ({ element })));
},

/**
Expand All @@ -54,8 +69,7 @@ export default {
this.posTargetCollection = null;
this.posIndex = this.posMethod == 'after' && this.cDim.length !== 0 ? this.posIndex + 1 : this.posIndex; //Normalize
if (this.sorter) {
this.sorter.moved = 0;
this.sorter.endMove();
this.sorter.cancelDrag();
}
if (this.cDim) {
this.posIsLastEl = this.cDim.length !== 0 && this.posMethod == 'after' && this.posIndex == this.cDim.length;
Expand Down
17 changes: 11 additions & 6 deletions packages/core/src/navigator/view/ItemView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { isEnterKey, isEscKey } from '../../utils/dom';
import LayerManager from '../index';
import ItemsView from './ItemsView';
import { getOnComponentDrag, getOnComponentDragEnd, getOnComponentDragStart } from '../../commands';
import Sorter from '../../utils/sorter/Sorter';
import LayersComponentNode from '../../utils/sorter/LayersComponentNode';

export type ItemViewProps = ViewOptions & {
ItemView: ItemView;
Expand Down Expand Up @@ -99,7 +101,7 @@ export default class ItemView extends View {
opt: ItemViewProps;
module: LayerManager;
config: any;
sorter: any;
sorter: Sorter<Component, LayersComponentNode>;
/** @ts-ignore */
model!: Component;
parentView: ItemView;
Expand Down Expand Up @@ -323,11 +325,14 @@ export default class ItemView extends View {

if (sorter) {
const toMove = model.delegate?.move?.(model) || model;
sorter.onStart = getOnComponentDragStart(em);
sorter.onMoveClb = getOnComponentDrag(em);
sorter.onEndMove = getOnComponentDragEnd(em, [toMove]);
const itemEl = (toMove as any).viewLayer?.el || ev.target;
sorter.startSort(itemEl);
sorter.eventHandlers = {
legacyOnStartSort: getOnComponentDragStart(em),
legacyOnMoveClb: getOnComponentDrag(em),
legacyOnEndMove: getOnComponentDragEnd(em, [toMove]),
...sorter.eventHandlers,
};
const element = (toMove as any).viewLayer?.el || ev.target;
sorter.startSort([{ element }]);
}
}

Expand Down
51 changes: 40 additions & 11 deletions packages/core/src/navigator/view/ItemsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import EditorModel from '../../editor/model/Editor';
import ItemView from './ItemView';
import Components from '../../dom_components/model/Components';
import LayerManager from '..';
import { DragDirection } from '../../utils/sorter/types';
import LayersComponentNode from '../../utils/sorter/LayersComponentNode';
import ComponentSorter from '../../utils/sorter/ComponentSorter';

export default class ItemsView extends View {
items: ItemView[];
opt: any;
opt: {
sorter: ComponentSorter<LayersComponentNode>;
[k: string]: any;
};
config: any;
parentView: ItemView;
module: LayerManager;
Expand All @@ -34,17 +40,23 @@ export default class ItemsView extends View {

if (config.sortable && !this.opt.sorter) {
const utils = em.Utils;
this.opt.sorter = new utils.Sorter({
// @ts-ignore
container: config.sortContainer || this.el,
containerSel: `.${this.className}`,
itemSel: `.${pfx}layer`,
ignoreViewChildren: 1,
avoidSelectOnEnd: 1,
nested: 1,
ppfx,
pfx,
const container = config.sortContainer || this.el;
const placeholderElement = this.createPlaceholder(pfx);
this.opt.sorter = new utils.ComponentSorter({
em,
treeClass: LayersComponentNode,
containerContext: {
container: container,
containerSel: `.${this.className}`,
itemSel: `.${pfx}layer`,
pfx: config.pStylePrefix,
document: document,
placeholderElement: placeholderElement,
},
dragBehavior: {
dragDirection: DragDirection.Vertical,
nested: true,
},
});
}

Expand All @@ -53,6 +65,23 @@ export default class ItemsView extends View {
opt.parent && this.$el.data('model', opt.parent);
}

/**
* Create placeholder
* @return {HTMLElement}
*/
private createPlaceholder(pfx: string) {
const el = document.createElement('div');
const ins = document.createElement('div');
this.el.parentNode;
el.className = pfx + 'placeholder';
el.style.display = 'none';
el.style.pointerEvents = 'none';
ins.className = pfx + 'placeholder-int';
el.appendChild(ins);

return el;
}

removeChildren(removed: Component) {
const view = removed.viewLayer;
if (!view) return;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/style_manager/model/Layers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Collection } from '../../common';
import LayersView from '../view/LayersView';
import Layer from './Layer';

export default class Layers extends Collection<Layer> {
prop: any;
view?: LayersView;

initialize(p: any, opts: { prop?: any } = {}) {
this.prop = opts.prop;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/style_manager/view/LayerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class LayerView extends View<Layer> {
}

initSorter() {
this.sorter?.startSort(this.el);
this.sorter?.startSort([{ element: this.el }]);
}

removeItem(ev: Event) {
Expand Down
49 changes: 38 additions & 11 deletions packages/core/src/style_manager/view/LayersView.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { View } from '../../common';
import EditorModel from '../../editor/model/Editor';
import StyleManagerSorter from '../../utils/sorter/StyleManagerSorter';
import { DragDirection } from '../../utils/sorter/types';
import Layer from '../model/Layer';
import Layers from '../model/Layers';
import LayerView from './LayerView';
import PropertyStackView from './PropertyStackView';

Expand All @@ -10,7 +13,7 @@ export default class LayersView extends View<Layer> {
config: any;
propertyView: PropertyStackView;
items: LayerView[];
sorter: any;
sorter?: StyleManagerSorter;

constructor(o: any) {
super(o);
Expand All @@ -27,20 +30,28 @@ export default class LayersView extends View<Layer> {
this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset', this.reset);
this.items = [];
const placeholderElement = this.createPlaceholder(config.pStylePrefix);
this.$el.append(placeholderElement);

// For the Sorter
const utils = em?.Utils;
this.sorter = utils
? new utils.Sorter({
// @ts-ignore
container: this.el,
ignoreViewChildren: 1,
containerSel: `.${pfx}layers`,
itemSel: `.${pfx}layer`,
pfx: config.pStylePrefix,
? new utils.StyleManagerSorter({
em,
containerContext: {
container: this.el,
containerSel: `.${pfx}layers`,
itemSel: `.${pfx}layer`,
pfx: config.pStylePrefix,
document: document,
placeholderElement: placeholderElement,
},
dragBehavior: {
dragDirection: DragDirection.Vertical,
nested: false,
},
})
: '';
: undefined;
// @ts-ignore
coll.view = this;
this.$el.data('model', coll);
Expand Down Expand Up @@ -107,14 +118,30 @@ export default class LayersView extends View<Layer> {
}

render() {
const { $el, sorter } = this;
const { $el } = this;
const frag = document.createDocumentFragment();
$el.empty();
this.collection.forEach((m) => this.addToCollection(m, frag));
$el.append(frag);
$el.attr('class', this.className!);
if (sorter) sorter.plh = null;

return this;
}

/**
* Create placeholder
* @return {HTMLElement}
*/
private createPlaceholder(pfx: string) {
const el = document.createElement('div');
const ins = document.createElement('div');
this.el.parentNode;
el.className = pfx + 'placeholder';
el.style.display = 'none';
el.style.pointerEvents = 'none';
ins.className = pfx + 'placeholder-int';
el.appendChild(ins);

return el;
}
}
Loading

0 comments on commit 2124bdc

Please sign in to comment.