Browse Source

Merge branch 'xQwexx-canvas-module' into dev

pull/4378/head
Artur Arseniev 4 years ago
parent
commit
b145f58792
  1. 102
      src/abstract/DomainViews.ts
  2. 2
      src/abstract/Model.ts
  3. 4
      src/abstract/Module.ts
  4. 20
      src/abstract/View.ts
  5. 179
      src/canvas/index.ts
  6. 32
      src/canvas/model/Canvas.ts
  7. 43
      src/canvas/model/Frame.ts
  8. 5
      src/canvas/model/Frames.ts
  9. 208
      src/canvas/view/CanvasView.ts
  10. 131
      src/canvas/view/FrameView.ts
  11. 66
      src/canvas/view/FrameWrapView.ts
  12. 21
      src/canvas/view/FramesView.js
  13. 28
      src/canvas/view/FramesView.ts
  14. 2
      src/dom_components/view/ComponentView.js
  15. 19
      src/editor/index.ts
  16. 4
      src/editor/model/Editor.ts
  17. 2
      src/navigator/view/ItemView.ts
  18. 2
      src/navigator/view/ItemsView.ts
  19. 7
      src/pages/model/Page.ts
  20. 2
      src/utils/dom.js
  21. 8
      src/utils/mixins.ts

102
src/abstract/DomainViews.ts

@ -0,0 +1,102 @@
import { includes } from 'underscore';
import Backbone from 'backbone';
import View from './View';
import Model from './Model';
/*interface DomainView<TView, TModel>{
constructor(model: TModel): TView
}*/
type TModel<TCollection> = TCollection extends Backbone.Collection<infer TModel>? TModel: Model;
export default abstract class DomainViews<TCollection extends Backbone.Collection<Model>, TItemView extends View> extends View<TModel<TCollection>> {
// Defines the View per type
itemsView = '';
protected itemType = 'type';
reuseView = false;
viewCollection: TItemView[] = [];
constructor(opts: any = {}, autoAdd = false) {
super(opts);
autoAdd && this.listenTo(this.collection, 'add', this.addTo);
}
/**
* Add new model to the collection
* @param {Model} model
* @private
* */
private addTo(model: TModel<TCollection>) {
this.add(model);
}
private itemViewNotFound(type: string) {
/*const { em, ns } = this;
const warn = `${ns ? `[${ns}]: ` : ''}'${type}' type not found`;
em?.logWarning(warn);*/
}
protected abstract renderView(model: TModel<TCollection>, itemType: string): TItemView;
/**
* Render new model inside the view
* @param {Model} model
* @param {Object} fragment Fragment collection
* @private
* */
private add(model: TModel<TCollection>, fragment?: DocumentFragment) {
const { reuseView, viewCollection, itemsView = {} } = this;
var frag = fragment || null;
var typeField = model.get(this.itemType);
let view;
//@ts-ignore
if (model.view && reuseView) {
//@ts-ignore
view = model.view;
} else {
view = this.renderView(model, typeField);
}
viewCollection.push(view);
const rendered = view.render().el;
if (frag) frag.appendChild(rendered);
else this.$el.append(rendered);
}
render() {
var frag = document.createDocumentFragment();
this.clearItems();
this.$el.empty();
if (this.collection.length)
this.collection.each((model) => {
this.add(model, frag);
}, this);
this.$el.append(frag);
this.onRender();
return this;
}
onRender() {}
onRemoveBefore(items: TItemView[], opts: any) {}
onRemove(items: TItemView[], opts: any) {}
remove(opts: any = {}) {
const { viewCollection } = this;
this.onRemoveBefore(viewCollection, opts);
this.clearItems();
Backbone.View.prototype.remove.apply(this, opts);
this.onRemove(viewCollection, opts);
return this;
}
clearItems() {
const items = this.viewCollection || [];
// TODO Traits do not update the target anymore
// items.forEach(item => item.remove());
// this.items = [];
}
}

2
src/abstract/Model.ts

@ -26,7 +26,7 @@ export default class Model<
return this._module.config; return this._module.config;
} }
protected get em() { public get em() {
return this._module.em; return this._module.em;
} }
} }

4
src/abstract/Module.ts

@ -47,9 +47,7 @@ export default abstract class Module<T extends ModuleConfig = ModuleConfig>
this._em = em; this._em = em;
this._name = moduleName; this._name = moduleName;
const name = this.name.charAt(0).toLowerCase() + this.name.slice(1); const name = this.name.charAt(0).toLowerCase() + this.name.slice(1);
const cfgParent = !isUndefined(em.config[name]) const cfgParent = !isUndefined(em.config[name]) ? em.config[name] : em.config[this.name];
? em.config[name]
: em.config[this.name];
const cfg = cfgParent === true ? {} : cfgParent || {}; const cfg = cfgParent === true ? {} : cfgParent || {};
cfg.pStylePrefix = em.config.pStylePrefix || ''; cfg.pStylePrefix = em.config.pStylePrefix || '';

20
src/abstract/View.ts

@ -1,19 +1,29 @@
import Backbone from 'backbone'; import Backbone from "backbone";
import Model from './Model'; import Model from "./Model";
import Module, { IBaseModule } from "./Module";
export default class View< export default class View<
TModel extends Model = Model, TModel extends Model = Model,
TElement extends Element = HTMLElement TElement extends Element = HTMLElement
> extends Backbone.View<TModel, TElement> { > extends Backbone.View<TModel, TElement> {
protected get pfx() { protected get pfx() {
return (this.model.module.em.config as any).stylePrefix || ''; return this.ppfx + this.config.stylePrefix || "";
} }
protected get ppfx() { protected get ppfx() {
return this.pfx + this.model.module.config.stylePrefix || ''; return (this.em.config as any).stylePrefix || "";
}
protected get module(): TModel extends Model<infer M>? M: unknown {
//console.log((this.collection.first as any).module)
return this.model?.module ?? (this.collection as any).module;
} }
protected get em() { protected get em() {
return this.model.module.em; return this.module.em;
}
protected get config(): TModel extends Model<infer M> ? (M extends IBaseModule<infer C> ? C : unknown) : unknown{
return this.module.config as any
} }
} }

179
src/canvas/index.js → src/canvas/index.ts

@ -47,49 +47,49 @@
* @module Canvas * @module Canvas
*/ */
import { AddOptions } from 'backbone';
import { isUndefined } from 'underscore'; import { isUndefined } from 'underscore';
import { Module } from '../abstract';
import ComponentView from '../dom_components/view/ComponentView';
import EditorModel from '../editor/model/Editor';
import { getElement, getViewEl } from '../utils/mixins'; import { getElement, getViewEl } from '../utils/mixins';
import defaults from './config/config'; import defaults from './config/config';
import Canvas from './model/Canvas'; import Canvas from './model/Canvas';
import Frame from './model/Frame'; import Frame from './model/Frame';
import CanvasView from './view/CanvasView'; import CanvasView from './view/CanvasView';
import FrameView from './view/FrameView';
export default class CanvasModule { export default class CanvasModule extends Module<typeof defaults> {
/** /**
* Used inside RTE * Used inside RTE
* @private * @private
*/ */
getCanvasView() { getCanvasView(): CanvasView {
return this.canvasView; return this.canvasView as any;
} }
name = 'Canvas'; //name = 'Canvas';
canvas: Canvas;
model: Canvas;
private canvasView?: CanvasView;
c = {};
canvas;
canvasView;
/** /**
* Initialize module. Automatically called with a new instance of the editor * Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations * @param {Object} config Configurations
* @private * @private
*/ */
init(config = {}) { constructor(em: EditorModel) {
this.c = { super(em, "Canvas", defaults)
...defaults,
...config,
module: this,
};
this.em = this.c.em; this.canvas = new Canvas(this);
const { scripts, styles } = this.c;
const ppfx = this.c.pStylePrefix;
if (ppfx) this.c.stylePrefix = ppfx + this.c.stylePrefix;
this.canvas = new Canvas({ scripts, styles }, config);
this.model = this.canvas; this.model = this.canvas;
this.startAutoscroll = this.startAutoscroll.bind(this); this.startAutoscroll = this.startAutoscroll.bind(this);
this.stopAutoscroll = this.stopAutoscroll.bind(this); this.stopAutoscroll = this.stopAutoscroll.bind(this);
return this; return this;
} }
init(){
}
onLoad() { onLoad() {
this.model.init(); this.model.init();
@ -99,25 +99,15 @@ export default class CanvasModule {
return this.canvas; return this.canvas;
} }
/**
* Get the configuration object
* @returns {Object} Configuration object
* @example
* console.log(canvas.getConfig())
*/
getConfig() {
return this.c;
}
/** /**
* Get the canvas element * Get the canvas element
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
getElement() { getElement() {
return this.canvasView.el; return this.getCanvasView().el;
} }
getFrame(index) { getFrame(index?: number) {
return this.getFrames()[index || 0]; return this.getFrames()[index || 0];
} }
@ -127,11 +117,11 @@ export default class CanvasModule {
*/ */
getFrameEl() { getFrameEl() {
const { frame } = this.canvasView || {}; const { frame } = this.canvasView || {};
return frame && frame.el; return frame?.el as HTMLIFrameElement;
} }
getFramesEl() { getFramesEl() {
return this.canvasView.framesArea; return this.canvasView?.framesArea as HTMLElement;
} }
/** /**
@ -139,7 +129,8 @@ export default class CanvasModule {
* @returns {Window} * @returns {Window}
*/ */
getWindow() { getWindow() {
return this.getFrameEl().contentWindow; const { frame } = this.canvasView || {};
return frame?.getWindow() as Window;
} }
/** /**
@ -148,7 +139,7 @@ export default class CanvasModule {
*/ */
getDocument() { getDocument() {
const frame = this.getFrameEl(); const frame = this.getFrameEl();
return frame && frame.contentDocument; return frame?.contentDocument as Document;
} }
/** /**
@ -157,16 +148,12 @@ export default class CanvasModule {
*/ */
getBody() { getBody() {
const doc = this.getDocument(); const doc = this.getDocument();
return doc && doc.body; return doc?.body as HTMLBodyElement;
} }
_getCompFrame(compView) { _getLocalEl(globalEl: any, compView: any, method: keyof FrameView) {
return compView && compView._getFrame();
}
_getLocalEl(globalEl, compView, method) {
let result = globalEl; let result = globalEl;
const frameView = this._getCompFrame(compView); const frameView = compView?._getFrame();
result = frameView ? frameView[method]() : result; result = frameView ? frameView[method]() : result;
return result; return result;
@ -178,7 +165,7 @@ export default class CanvasModule {
* @private * @private
*/ */
getGlobalToolsEl() { getGlobalToolsEl() {
return this.canvasView.toolsGlobEl; return this.canvasView?.toolsGlobEl;
} }
/** /**
@ -186,8 +173,8 @@ export default class CanvasModule {
* @returns {HTMLElement} * @returns {HTMLElement}
* @private * @private
*/ */
getToolsEl(compView) { getToolsEl(compView: any) {
return this._getLocalEl(this.canvasView.toolsEl, compView, 'getToolsEl'); return this._getLocalEl(this.getCanvasView().toolsEl, compView, 'getToolsEl');
} }
/** /**
@ -195,8 +182,8 @@ export default class CanvasModule {
* @returns {HTMLElement} * @returns {HTMLElement}
* @private * @private
*/ */
getHighlighter(compView) { getHighlighter(compView: any) {
return this._getLocalEl(this.canvasView.hlEl, compView, 'getHighlighter'); return this._getLocalEl(this.getCanvasView().hlEl, compView, 'getHighlighter');
} }
/** /**
@ -204,8 +191,8 @@ export default class CanvasModule {
* @returns {HTMLElement} * @returns {HTMLElement}
* @private * @private
*/ */
getBadgeEl(compView) { getBadgeEl(compView: any) {
return this._getLocalEl(this.canvasView.badgeEl, compView, 'getBadgeEl'); return this._getLocalEl(this.getCanvasView().badgeEl, compView, 'getBadgeEl');
} }
/** /**
@ -214,7 +201,7 @@ export default class CanvasModule {
* @private * @private
*/ */
getPlacerEl() { getPlacerEl() {
return this.canvasView.placerEl; return this.getCanvasView().placerEl;
} }
/** /**
@ -223,7 +210,7 @@ export default class CanvasModule {
* @private * @private
*/ */
getGhostEl() { getGhostEl() {
return this.canvasView.ghostEl; return this.getCanvasView().ghostEl;
} }
/** /**
@ -232,7 +219,7 @@ export default class CanvasModule {
* @private * @private
*/ */
getToolbarEl() { getToolbarEl() {
return this.canvasView.toolbarEl; return this.getCanvasView().toolbarEl;
} }
/** /**
@ -241,7 +228,7 @@ export default class CanvasModule {
* @private * @private
*/ */
getResizerEl() { getResizerEl() {
return this.canvasView.resizerEl; return this.getCanvasView().resizerEl;
} }
/** /**
@ -249,8 +236,8 @@ export default class CanvasModule {
* @returns {HTMLElement} * @returns {HTMLElement}
* @private * @private
*/ */
getOffsetViewerEl(compView) { getOffsetViewerEl(compView: any) {
return this._getLocalEl(this.canvasView.offsetEl, compView, 'getOffsetViewerEl'); return this._getLocalEl(this.getCanvasView().offsetEl, compView, 'getOffsetViewerEl');
} }
/** /**
@ -259,15 +246,12 @@ export default class CanvasModule {
* @private * @private
*/ */
getFixedOffsetViewerEl() { getFixedOffsetViewerEl() {
return this.canvasView.fixedOffsetEl; return this.getCanvasView().fixedOffsetEl;
} }
render() { render() {
this.canvasView?.remove(); this.canvasView?.remove();
this.canvasView = new CanvasView({ this.canvasView = new CanvasView(this.canvas);
model: this.canvas,
config: this.c,
});
return this.canvasView.render().el; return this.canvasView.render().el;
} }
@ -291,8 +275,8 @@ export default class CanvasModule {
* @returns {Object} * @returns {Object}
* @private * @private
*/ */
offset(el) { offset(el: HTMLElement) {
return this.canvasView.offset(el); return this.getCanvasView().offset(el);
} }
/** /**
@ -303,8 +287,9 @@ export default class CanvasModule {
* return component.getName(); * return component.getName();
* }); * });
*/ */
setCustomBadgeLabel(f) { setCustomBadgeLabel(f: Function) {
this.c.customBadgeLabel = f; //@ts-ignore
this.config.customBadgeLabel = f;
} }
/** /**
@ -313,8 +298,8 @@ export default class CanvasModule {
* @returns {Object} * @returns {Object}
* @private * @private
*/ */
getElementPos(el, opts) { getElementPos(el: HTMLElement, opts?: any) {
return this.canvasView.getElementPos(el, opts); return this.getCanvasView().getElementPos(el, opts);
} }
/** /**
@ -323,8 +308,8 @@ export default class CanvasModule {
* @returns {Object} * @returns {Object}
* @private * @private
*/ */
getElementOffsets(el) { getElementOffsets(el: HTMLElement) {
return this.canvasView.getElementOffsets(el); return this.getCanvasView().getElementOffsets(el);
} }
/** /**
@ -332,9 +317,9 @@ export default class CanvasModule {
* @returns {Object} * @returns {Object}
*/ */
getRect() { getRect() {
const { top, left } = this.canvasView.getPosition(); const { top = 0, left = 0 } = this.getCanvasView().getPosition() ?? {};
return { return {
...this.canvasView.getCanvasOffset(), ...this.getCanvasView().getCanvasOffset(),
topScroll: top, topScroll: top,
leftScroll: left, leftScroll: left,
}; };
@ -356,11 +341,11 @@ export default class CanvasModule {
* @return {Object} * @return {Object}
* @private * @private
*/ */
getTargetToElementDim(target, element, options = {}) { getTargetToElementDim(target: HTMLElement, element: HTMLElement, options: any = {}) {
var opts = options || {}; var opts = options || {};
var canvasPos = this.canvasView.getPosition(); var canvasPos = this.getCanvasView().getPosition();
if (!canvasPos) return; if (!canvasPos) return;
var pos = opts.elPos || this.canvasView.getElementPos(element); var pos = opts.elPos || this.getCanvasView().getElementPos(element);
var toRight = options.toRight || 0; var toRight = options.toRight || 0;
var targetHeight = opts.targetHeight || target.offsetHeight; var targetHeight = opts.targetHeight || target.offsetHeight;
var targetWidth = opts.targetWidth || target.offsetWidth; var targetWidth = opts.targetWidth || target.offsetWidth;
@ -391,20 +376,20 @@ export default class CanvasModule {
}; };
// In this way I can catch data and also change the position strategy // In this way I can catch data and also change the position strategy
if (eventToTrigger && this.c.em) { if (eventToTrigger && this.em) {
this.c.em.trigger(eventToTrigger, result); this.em.trigger(eventToTrigger, result);
} }
return result; return result;
} }
canvasRectOffset(el, pos, opts = {}) { canvasRectOffset(el: HTMLElement, pos: {top: number, left: number}, opts: any = {}) {
const getFrameElFromDoc = doc => { const getFrameElFromDoc = (doc: Document) => {
const { defaultView } = doc; const { defaultView } = doc;
return defaultView && defaultView.frameElement; return defaultView?.frameElement as HTMLElement;
}; };
const rectOff = (el, top = 1, pos) => { const rectOff = (el: HTMLElement, top = 1, pos: {top: number, left: number}) => {
const zoom = this.em.getZoomDecimal(); const zoom = this.em.getZoomDecimal();
const side = top ? 'top' : 'left'; const side = top ? 'top' : 'left';
const doc = el.ownerDocument; const doc = el.ownerDocument;
@ -426,7 +411,7 @@ export default class CanvasModule {
}; };
} }
getTargetToElementFixed(el, elToMove, opts = {}) { getTargetToElementFixed(el: any, elToMove: any, opts: any = {}) {
const pos = opts.pos || this.getElementPos(el); const pos = opts.pos || this.getElementPos(el);
const cvOff = opts.canvasOff || this.canvasRectOffset(el, pos); const cvOff = opts.canvasOff || this.canvasRectOffset(el, pos);
const toolbarH = elToMove.offsetHeight || 0; const toolbarH = elToMove.offsetHeight || 0;
@ -440,7 +425,8 @@ export default class CanvasModule {
let top = -toolbarH; let top = -toolbarH;
let left = !isUndefined(opts.left) ? opts.left : pos.width - toolbarW; let left = !isUndefined(opts.left) ? opts.left : pos.width - toolbarW;
left = pos.left < -left ? -pos.left : left; left = pos.left < -left ? -pos.left : left;
left = elRight > frCvOff.width ? left - (elRight - frCvOff.width) : left; const frCvWidth = frCvOff?.width ?? 0;
left = elRight > frCvWidth ? left - (elRight - frCvWidth) : left;
// Scroll with the window if the top edge is reached and the // Scroll with the window if the top edge is reached and the
// element is bigger than the canvas // element is bigger than the canvas
@ -477,8 +463,7 @@ export default class CanvasModule {
* @return {Object} * @return {Object}
* @private * @private
*/ */
getMouseRelativePos(e, options) { getMouseRelativePos(e: any, opts: any = {}) {
var opts = options || {};
var addTop = 0; var addTop = 0;
var addLeft = 0; var addLeft = 0;
var subWinOffset = opts.subWinOffset; var subWinOffset = opts.subWinOffset;
@ -506,9 +491,9 @@ export default class CanvasModule {
* @return {Object} * @return {Object}
* @private * @private
*/ */
getMouseRelativeCanvas(ev, opts) { getMouseRelativeCanvas(ev: MouseEvent, opts: any) {
const zoom = this.getZoomDecimal(); const zoom = this.getZoomDecimal();
const { top, left } = this.canvasView.getPosition(opts); const { top = 0, left = 0 } = this.getCanvasView().getPosition(opts) ?? {};
return { return {
y: ev.clientY * zoom + top, y: ev.clientY * zoom + top,
@ -532,7 +517,8 @@ export default class CanvasModule {
isInputFocused() { isInputFocused() {
const doc = this.getDocument(); const doc = this.getDocument();
const frame = this.getFrameEl(); const frame = this.getFrameEl();
const toIgnore = ['body', ...this.getConfig().notTextable]; //console.log(this.config)
const toIgnore = ['body', ...this.config.notTextable];
const docActive = frame && document.activeElement === frame; const docActive = frame && document.activeElement === frame;
const focused = docActive ? doc && doc.activeElement : document.activeElement; const focused = docActive ? doc && doc.activeElement : document.activeElement;
@ -554,7 +540,7 @@ export default class CanvasModule {
* // Force the scroll, even if the element is alredy visible * // Force the scroll, even if the element is alredy visible
* canvas.scrollTo(selected, { force: true }); * canvas.scrollTo(selected, { force: true });
*/ */
scrollTo(el, opts = {}) { scrollTo(el: any, opts = {}) {
const elem = getElement(el); const elem = getElement(el);
const view = elem && getViewEl(elem); const view = elem && getViewEl(elem);
view && view.scrollIntoView(opts); view && view.scrollIntoView(opts);
@ -564,7 +550,7 @@ export default class CanvasModule {
* Start autoscroll * Start autoscroll
* @private * @private
*/ */
startAutoscroll(frame) { startAutoscroll(frame: Frame) {
const fr = (frame && frame.view) || this.em.getCurrentFrame(); const fr = (frame && frame.view) || this.em.getCurrentFrame();
fr && fr.startAutoscroll(); fr && fr.startAutoscroll();
} }
@ -573,7 +559,7 @@ export default class CanvasModule {
* Stop autoscroll * Stop autoscroll
* @private * @private
*/ */
stopAutoscroll(frame) { stopAutoscroll(frame: Frame) {
const fr = (frame && frame.view) || this.em.getCurrentFrame(); const fr = (frame && frame.view) || this.em.getCurrentFrame();
fr && fr.stopAutoscroll(); fr && fr.stopAutoscroll();
} }
@ -585,7 +571,7 @@ export default class CanvasModule {
* @example * @example
* canvas.setZoom(50); // set zoom to 50% * canvas.setZoom(50); // set zoom to 50%
*/ */
setZoom(value) { setZoom(value: string) {
this.canvas.set('zoom', parseFloat(value)); this.canvas.set('zoom', parseFloat(value));
return this; return this;
} }
@ -609,7 +595,7 @@ export default class CanvasModule {
* @example * @example
* canvas.setCoords(100, 100); * canvas.setCoords(100, 100);
*/ */
setCoords(x, y) { setCoords(x: string, y: string) {
this.canvas.set({ x: parseFloat(x), y: parseFloat(y) }); this.canvas.set({ x: parseFloat(x), y: parseFloat(y) });
return this; return this;
} }
@ -622,7 +608,7 @@ export default class CanvasModule {
* const coords = canvas.getCoords(); * const coords = canvas.getCoords();
* // { x: 100, y: 100 } * // { x: 100, y: 100 }
*/ */
getCoords() { getCoords(): {x: number, y: number} {
const { x, y } = this.canvas.attributes; const { x, y } = this.canvas.attributes;
return { x, y }; return { x, y };
} }
@ -636,13 +622,13 @@ export default class CanvasModule {
return zoom ? 1 / zoom : 1; return zoom ? 1 / zoom : 1;
} }
toggleFramesEvents(on) { toggleFramesEvents(on: boolean) {
const { style } = this.getFramesEl(); const { style } = this.getFramesEl();
style.pointerEvents = on ? '' : 'none'; style.pointerEvents = on ? '' : 'none';
} }
getFrames() { getFrames() {
return this.canvas.get('frames').map(item => item); return this.canvas.frames.map(item => item);
} }
/** /**
@ -668,13 +654,14 @@ export default class CanvasModule {
* }); * });
*/ */
addFrame(props = {}, opts = {}) { addFrame(props = {}, opts = {}) {
return this.canvas.frames.add(new Frame({ ...props }, { em: this.em }), opts); return this.canvas.frames.add(new Frame(this, { ...props }), opts);
} }
destroy() { destroy() {
this.canvas.stopListening(); this.canvas.stopListening();
this.canvasView?.remove(); this.canvasView?.remove();
[this.c, this.canvas, this.canvasView].forEach(i => (i = {})); //[this.canvas, this.canvasView].forEach(i => (i = {}));
['em', 'model', 'droppable'].forEach(i => (this[i] = {})); //@ts-ignore
['model', 'droppable'].forEach(i => (this[i] = {}));
} }
} }

32
src/canvas/model/Canvas.ts

@ -1,15 +1,14 @@
import { Model } from '../../common'; import { Model } from "../../abstract";
import Backbone from 'backbone'; import { evPageSelect } from "../../pages";
import { evPageSelect } from '../../pages'; import Frames from "./Frames";
import Frames from './Frames'; import Page from "../../pages/model/Page";
import EditorModel from '../../editor/model/Editor'; import CanvasModule from "..";
import Page from '../../pages/model/Page';
export default class Canvas extends Backbone.Model { export default class Canvas extends Model<CanvasModule> {
defaults() { defaults() {
return { return {
frame: '', frame: '',
frames: new Frames(), frames: [],
rulers: false, rulers: false,
zoom: 100, zoom: 100,
x: 0, x: 0,
@ -20,18 +19,17 @@ export default class Canvas extends Backbone.Model {
styles: [], styles: [],
}; };
} }
em: EditorModel;
config: any;
constructor(props: any, config: any = {}) { constructor(module: CanvasModule) {
super(props); const { em, config } = module;
const { em } = config; const { scripts, styles } = config;
this.config = config; super(module, {scripts, styles});
this.em = em; this.set("frames", new Frames(module))
this.listenTo(this, 'change:zoom', this.onZoomChange); this.listenTo(this, "change:zoom", this.onZoomChange);
this.listenTo(em, 'change:device', this.updateDevice); this.listenTo(em, "change:device", this.updateDevice);
this.listenTo(em, evPageSelect, this._pageUpdated); this.listenTo(em, evPageSelect, this._pageUpdated);
} }
get frames(): Frames { get frames(): Frames {
return this.get('frames'); return this.get('frames');
} }

43
src/canvas/model/Frame.ts

@ -1,7 +1,7 @@
import { result, forEach, isEmpty, isString } from 'underscore'; import { result, forEach, isEmpty, isString } from 'underscore';
import { Model } from '../../common'; import { Model } from "../../abstract";
import CanvasModule from "..";
import ComponentWrapper from '../../dom_components/model/ComponentWrapper'; import ComponentWrapper from '../../dom_components/model/ComponentWrapper';
import EditorModel from '../../editor/model/Editor';
import { isComponent, isObject } from '../../utils/mixins'; import { isComponent, isObject } from '../../utils/mixins';
import FrameView from '../view/FrameView'; import FrameView from '../view/FrameView';
import Frames from './Frames'; import Frames from './Frames';
@ -17,7 +17,7 @@ const keyAutoH = '__ah';
* @property {Number} [y=0] Vertical position of the frame in the canvas. * @property {Number} [y=0] Vertical position of the frame in the canvas.
* *
*/ */
export default class Frame extends Model { export default class Frame extends Model<CanvasModule> {
defaults() { defaults() {
return { return {
x: 0, x: 0,
@ -33,21 +33,16 @@ export default class Frame extends Model {
_undoexc: ['changesCount'], _undoexc: ['changesCount'],
}; };
} }
em: EditorModel;
view?: FrameView; view?: FrameView;
/** constructor(module: CanvasModule, props: any) {
* @hideconstructor super(module, props);
*/ const { em } = this;
constructor(props: any, opts: any) {
super(props);
const { em } = opts;
const { styles, component } = this.attributes; const { styles, component } = this.attributes;
const domc = em.get('DomComponents'); const domc = em.get('DomComponents');
const conf = domc.getConfig(); const conf = domc.getConfig();
const allRules = em.get('CssComposer').getAll(); const allRules = em.get('CssComposer').getAll();
const idMap: any = {}; const idMap: any = {};
this.em = em;
const modOpts = { em, config: conf, frame: this, idMap }; const modOpts = { em, config: conf, frame: this, idMap };
if (!isComponent(component)) { if (!isComponent(component)) {
@ -88,6 +83,10 @@ export default class Frame extends Model {
!props.height && this.set(keyAutoH, 1); !props.height && this.set(keyAutoH, 1);
} }
get head(): {tag: string, attributes: any}[]{
return this.get("head");
}
onRemove() { onRemove() {
this.getComponent().remove({ root: 1 }); this.getComponent().remove({ root: 1 });
} }
@ -118,23 +117,19 @@ export default class Frame extends Model {
} }
getHead() { getHead() {
const head = this.get('head') || []; return [...this.head];
return [...head];
} }
setHead(value: any) { setHead(value: {tag: string, attributes: any}[]) {
return this.set('head', [...value]); return this.set("head", [...value]);
} }
addHeadItem(item: any) { addHeadItem(item: {tag: string, attributes: any}) {
const head = this.getHead(); this.head.push(item);
head.push(item);
this.setHead(head);
} }
getHeadByAttr(attr: string, value: any, tag: string) { getHeadByAttr(attr: string, value: any, tag: string) {
const head = this.getHead(); return this.head.filter(
return head.filter(
(item) => (item) =>
item.attributes && item.attributes &&
item.attributes[attr] == value && item.attributes[attr] == value &&
@ -143,13 +138,11 @@ export default class Frame extends Model {
} }
removeHeadByAttr(attr: string, value: any, tag: string) { removeHeadByAttr(attr: string, value: any, tag: string) {
const head = this.getHead();
const item = this.getHeadByAttr(attr, value, tag); const item = this.getHeadByAttr(attr, value, tag);
const index = head.indexOf(item); const index = this.head.indexOf(item);
if (index >= 0) { if (index >= 0) {
head.splice(index, 1); this.head.splice(index, 1);
this.setHead(head);
} }
} }

5
src/canvas/model/Frames.ts

@ -1,4 +1,5 @@
import { bindAll } from 'underscore'; import { bindAll } from 'underscore';
import CanvasModule from '..';
import { Collection } from '../../common'; import { Collection } from '../../common';
import Page from '../../pages/model/Page'; import Page from '../../pages/model/Page';
import Frame from './Frame'; import Frame from './Frame';
@ -7,9 +8,11 @@ export default class Frames extends Collection<Frame> {
loadedItems = 0; loadedItems = 0;
itemsToLoad = 0; itemsToLoad = 0;
page?: Page; page?: Page;
module: CanvasModule
constructor(models?: Frame[]) { constructor(module: CanvasModule, models: Frame[] = []) {
super(models); super(models);
this.module = module;
bindAll(this, 'itemLoaded'); bindAll(this, 'itemLoaded');
this.on('reset', this.onReset); this.on('reset', this.onReset);
this.on('remove', this.onRemove); this.on('remove', this.onRemove);

208
src/canvas/view/CanvasView.js → src/canvas/view/CanvasView.ts

@ -1,12 +1,24 @@
import { bindAll } from 'underscore'; import { bindAll } from 'underscore';
import { View } from '../../common'; import { View } from '../../abstract';
import { on, off, getElement, getKeyChar, isTextNode, getElRect, getUiClass } from '../../utils/mixins'; import { on, off, getElement, getKeyChar, isTextNode, getElRect, getUiClass } from '../../utils/mixins';
import { createEl } from '../../utils/dom'; import { createEl } from '../../utils/dom';
import FramesView from './FramesView'; import FramesView from './FramesView';
import Canvas from '../model/Canvas';
let timerZoom; import FrameView from './FrameView';
import ComponentView from '../../dom_components/view/ComponentView';
export default class CanvasView extends View { import Component from '../../dom_components/model/Component';
interface MarginPaddingOffsets{
marginTop?: number,
marginRight?: number,
marginBottom?: number,
marginLeft?: number,
paddingTop?: number,
paddingRight?: number,
paddingBottom?: number,
paddingLeft?: number,
}
export default class CanvasView extends View<Canvas> {
events() { events() {
return { return {
wheel: 'onWheel', wheel: 'onWheel',
@ -20,22 +32,42 @@ export default class CanvasView extends View {
<div id="${pfx}tools" class="${pfx}canvas__tools" data-tools></div> <div id="${pfx}tools" class="${pfx}canvas__tools" data-tools></div>
`; `;
} }
/*get className(){
initialize(o) { return this.pfx + 'canvas':
}*/
hlEl?: HTMLElement;
badgeEl?: HTMLElement;
placerEl?: HTMLElement;
ghostEl?: HTMLElement;
toolbarEl?: HTMLElement;
resizerEl?: HTMLElement;
offsetEl?: HTMLElement;
fixedOffsetEl?: HTMLElement;
toolsGlobEl?: HTMLElement;
toolsEl?: HTMLElement;
framesArea?: HTMLElement;
toolsWrapper?: HTMLElement;
ready = false;
frames!: FramesView;
frame?: FrameView;
private timerZoom?: number
private frmOff?: {top: number, left: number, width: number, height: number}
private cvsOff?: {top: number, left: number, width: number, height: number}
constructor(model: Canvas) {
super({model});
bindAll(this, 'clearOff', 'onKeyPress', 'onCanvasMove'); bindAll(this, 'clearOff', 'onKeyPress', 'onCanvasMove');
const { model } = this; this.className = this.pfx + 'canvas';
this.config = o.config || {};
this.em = this.config.em || {};
this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
this.className = this.config.stylePrefix + 'canvas';
const { em } = this; const { em } = this;
this._initFrames(); this._initFrames();
this.listenTo(em, 'change:canvasOffset', this.clearOff); this.listenTo(em, 'change:canvasOffset', this.clearOff);
this.listenTo(em, 'component:selected', this.checkSelected); this.listenTo(em, 'component:selected', this.checkSelected);
this.listenTo(model, 'change:zoom change:x change:y', this.updateFrames); this.listenTo(model, 'change:zoom change:x change:y', this.updateFrames);
this.listenTo(model, 'change:frames', this._onFramesUpdate); this.listenTo(model, 'change:frames', this._onFramesUpdate);
this.toggleListeners(1); this.toggleListeners(true);
} }
_onFramesUpdate() { _onFramesUpdate() {
@ -45,59 +77,62 @@ export default class CanvasView extends View {
_initFrames() { _initFrames() {
const { frames, model, config, em } = this; const { frames, model, config, em } = this;
const collection = model.get('frames'); const collection = model.frames;
em.set('readyCanvas', 0); em.set('readyCanvas', 0);
collection.once('loaded:all', () => em.set('readyCanvas', 1)); collection.once('loaded:all', () => em.set('readyCanvas', 1));
frames && frames.remove(); frames?.remove();
this.frames = new FramesView({ this.frames = new FramesView(
collection, {collection},
config: { {
...config, ...config,
canvasView: this, canvasView: this,
}, },
}); );
} }
checkSelected(component, opts = {}) { checkSelected(component: Component, opts: any = {}) {
const { scroll } = opts; const { scroll } = opts;
const currFrame = this.em.get('currentFrame'); const currFrame = this.em.get('currentFrame');
scroll && scroll && component.views?.forEach(view => {
component.views.forEach(view => {
view._getFrame() === currFrame && view.scrollIntoView(scroll); view._getFrame() === currFrame && view.scrollIntoView(scroll);
}); });
} }
remove() { remove(...args: any) {
this.frames.remove(); this.frames?.remove();
this.frames = {}; //@ts-ignore
View.prototype.remove.apply(this, arguments); this.frames = undefined;
this.toggleListeners(); View.prototype.remove.apply(this, args);
this.toggleListeners(false);
return this
} }
preventDefault(ev) { preventDefault(ev: Event) {
if (ev) { if (ev) {
ev.preventDefault(); ev.preventDefault();
ev._parentEvent && ev._parentEvent.preventDefault(); //@ts-ignore
ev._parentEvent?.preventDefault();
} }
} }
onCanvasMove(ev) { onCanvasMove(ev: Event) {
// const data = { x: ev.clientX, y: ev.clientY }; // const data = { x: ev.clientX, y: ev.clientY };
// const data2 = this.em.get('Canvas').getMouseRelativeCanvas(ev); // const data2 = this.em.get('Canvas').getMouseRelativeCanvas(ev);
// const data3 = this.em.get('Canvas').getMouseRelativePos(ev); // const data3 = this.em.get('Canvas').getMouseRelativePos(ev);
// this.em.trigger('canvas:over', data, data2, data3); // this.em.trigger('canvas:over', data, data2, data3);
} }
toggleListeners(enable) { toggleListeners(enable: boolean) {
const { el } = this; const { el } = this;
const fn = enable ? on : off; const fn = enable ? on : off;
// @ts-ignore
fn(document, 'keypress', this.onKeyPress); fn(document, 'keypress', this.onKeyPress);
fn(window, 'scroll resize', this.clearOff); fn(window, 'scroll resize', this.clearOff);
// fn(el, 'mousemove dragover', this.onCanvasMove); // fn(el, 'mousemove dragover', this.onCanvasMove);
} }
onKeyPress(ev) { onKeyPress(ev: KeyboardEvent) {
const { em } = this; const { em } = this;
const key = getKeyChar(ev); const key = getKeyChar(ev);
@ -107,28 +142,30 @@ export default class CanvasView extends View {
} }
} }
onWheel(ev) { onWheel(ev: KeyboardEvent) {
if ((ev.ctrlKey || ev.metaKey) && this.em.getConfig().multiFrames) { if ((ev.ctrlKey || ev.metaKey) && this.em.getConfig().multiFrames) {
this.preventDefault(ev); this.preventDefault(ev);
const { model } = this; const { model } = this;
//@ts-ignore this is potentially deprecated
const delta = Math.max(-1, Math.min(1, ev.wheelDelta || -ev.detail)); const delta = Math.max(-1, Math.min(1, ev.wheelDelta || -ev.detail));
const zoom = model.get('zoom'); const zoom = model.get('zoom');
model.set('zoom', zoom + delta * 2); model.set('zoom', zoom + delta * 2);
} }
} }
updateFrames(ev) { updateFrames(ev: Event) {
const { em, model } = this; const { em, model } = this;
const { x, y } = model.attributes; const { x, y } = model.attributes;
const zoom = this.getZoom(); const zoom = this.getZoom();
const defOpts = { preserveSelected: 1 }; const defOpts = { preserveSelected: 1 };
const mpl = zoom ? 1 / zoom : 1; const mpl = zoom ? 1 / zoom : 1;
//@ts-ignore
this.framesArea.style.transform = `scale(${zoom}) translate(${x * mpl}px, ${y * mpl}px)`; this.framesArea.style.transform = `scale(${zoom}) translate(${x * mpl}px, ${y * mpl}px)`;
this.clearOff(); this.clearOff();
em.stopDefault(defOpts); em.stopDefault(defOpts);
em.trigger('canvas:update', ev); em.trigger('canvas:update', ev);
timerZoom && clearTimeout(timerZoom); this.timerZoom && clearTimeout(this.timerZoom);
timerZoom = setTimeout(() => em.runDefault(defOpts), 300); this.timerZoom = setTimeout(() => em.runDefault(defOpts), 300) as any;
} }
getZoom() { getZoom() {
@ -140,7 +177,7 @@ export default class CanvasView extends View {
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Boolean} * @return {Boolean}
*/ */
isElInViewport(el) { isElInViewport(el: HTMLElement) {
const elem = getElement(el); const elem = getElement(el);
const rect = getElRect(elem); const rect = getElRect(elem);
const frameRect = this.getFrameOffset(elem); const frameRect = this.getFrameOffset(elem);
@ -152,16 +189,16 @@ export default class CanvasView extends View {
/** /**
* Get the offset of the element * Get the offset of the element
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Object} * @return { {top: number, left: number, width: number, height: number} }
*/ */
offset(el, opts = {}) { offset(el?: HTMLElement, opts: any = {}) {
const rect = getElRect(el); const rect = getElRect(el);
const docBody = el.ownerDocument.body; const docBody = el?.ownerDocument.body;
const { noScroll } = opts; const { noScroll } = opts;
return { return {
top: rect.top + (noScroll ? 0 : docBody.scrollTop), top: rect.top + (noScroll ? 0 : docBody?.scrollTop ?? 0),
left: rect.left + (noScroll ? 0 : docBody.scrollLeft), left: rect.left + (noScroll ? 0 : docBody?.scrollLeft ?? 0),
width: rect.width, width: rect.width,
height: rect.height, height: rect.height,
}; };
@ -172,20 +209,20 @@ export default class CanvasView extends View {
* @private * @private
*/ */
clearOff() { clearOff() {
this.frmOff = null; this.frmOff = undefined;
this.cvsOff = null; this.cvsOff = undefined;
} }
/** /**
* Return frame offset * Return frame offset
* @return {Object} * @return { {top: number, left: number, width: number, height: number} }
* @private * @public
*/ */
getFrameOffset(el) { getFrameOffset(el?: HTMLElement) {
if (!this.frmOff || el) { if (!this.frmOff || el) {
const frame = this.frame.el; const frame = this.frame?.el;
const winEl = el && el.ownerDocument.defaultView; const winEl = el?.ownerDocument.defaultView;
const frEl = winEl ? winEl.frameElement : frame; const frEl = winEl ? winEl.frameElement as HTMLElement : frame;
this.frmOff = this.offset(frEl || frame); this.frmOff = this.offset(frEl || frame);
} }
return this.frmOff; return this.frmOff;
@ -193,8 +230,8 @@ export default class CanvasView extends View {
/** /**
* Return canvas offset * Return canvas offset
* @return {Object} * @return { {top: number, left: number, width: number, height: number} }
* @private * @public
*/ */
getCanvasOffset() { getCanvasOffset() {
if (!this.cvsOff) this.cvsOff = this.offset(this.el); if (!this.cvsOff) this.cvsOff = this.offset(this.el);
@ -204,10 +241,10 @@ export default class CanvasView extends View {
/** /**
* Returns element's rect info * Returns element's rect info
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Object} * @return { {top: number, left: number, width: number, height: number, zoom: number, rect: any} }
* @private * @public
*/ */
getElementPos(el, opts) { getElementPos(el: HTMLElement, opts: any = {}) {
const zoom = this.getZoom(); const zoom = this.getZoom();
const opt = opts || {}; const opt = opts || {};
const frameOffset = this.getFrameOffset(el); const frameOffset = this.getFrameOffset(el);
@ -228,14 +265,14 @@ export default class CanvasView extends View {
/** /**
* Returns element's offsets like margins and paddings * Returns element's offsets like margins and paddings
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Object} * @return { MarginPaddingOffsets }
* @private * @public
*/ */
getElementOffsets(el) { getElementOffsets(el: HTMLElement) {
if (!el || isTextNode(el)) return {}; if (!el || isTextNode(el)) return {};
const result = {}; const result: MarginPaddingOffsets = {} ;
const styles = window.getComputedStyle(el); const styles = window.getComputedStyle(el);
[ const marginPaddingOffsets: (keyof MarginPaddingOffsets)[] =[
'marginTop', 'marginTop',
'marginRight', 'marginRight',
'marginBottom', 'marginBottom',
@ -244,7 +281,8 @@ export default class CanvasView extends View {
'paddingRight', 'paddingRight',
'paddingBottom', 'paddingBottom',
'paddingLeft', 'paddingLeft',
].forEach(offset => { ]
marginPaddingOffsets.forEach(offset => {
result[offset] = parseFloat(styles[offset]) * this.getZoom(); result[offset] = parseFloat(styles[offset]) * this.getZoom();
}); });
@ -253,11 +291,12 @@ export default class CanvasView extends View {
/** /**
* Returns position data of the canvas element * Returns position data of the canvas element
* @return {Object} obj Position object * @return { {top: number, left: number, width: number, height: number} } obj Position object
* @private * @public
*/ */
getPosition(opts = {}) { getPosition(opts: any = {}) {
const doc = this.frame.el.contentDocument;
const doc = this.frame?.el.contentDocument;
if (!doc) return; if (!doc) return;
const bEl = doc.body; const bEl = doc.body;
const zoom = this.getZoom(); const zoom = this.getZoom();
@ -278,7 +317,8 @@ export default class CanvasView extends View {
* @param {View} view Component's View * @param {View} view Component's View
* @private * @private
*/ */
updateScript(view) { //TODO change type after the ComponentView was updated to ts
updateScript(view: any) {
const model = view.model; const model = view.model;
const id = model.getId(); const id = model.getId();
@ -313,25 +353,25 @@ export default class CanvasView extends View {
* Get javascript container * Get javascript container
* @private * @private
*/ */
getJsContainer(view) { getJsContainer(view?: ComponentView) {
const frameView = this.getFrameView(view); const frameView = this.getFrameView(view);
return frameView && frameView.getJsContainer(); return frameView && frameView.getJsContainer();
} }
getFrameView(view) { getFrameView(view?: ComponentView) {
return (view && view._getFrame()) || this.em.get('currentFrame'); return view?._getFrame() || this.em.get('currentFrame');
} }
_renderFrames() { _renderFrames() {
if (!this.ready) return; if (!this.ready) return;
const { model, frames, em, framesArea } = this; const { model, frames, em, framesArea } = this;
const frms = model.get('frames'); const frms = model.frames;
frms.listenToLoad(); frms.listenToLoad();
frames.render(); frames.render();
const mainFrame = frms.at(0); const mainFrame = frms.at(0);
const currFrame = mainFrame && mainFrame.view; const currFrame = mainFrame?.view;
em.setCurrentFrame(currFrame); em.setCurrentFrame(currFrame);
framesArea && framesArea.appendChild(frames.el); framesArea?.appendChild(frames.el);
this.frame = currFrame; this.frame = currFrame;
} }
@ -360,18 +400,18 @@ export default class CanvasView extends View {
</div> </div>
`); `);
const toolsEl = el.querySelector(`#${ppfx}tools`); const toolsEl = el.querySelector(`#${ppfx}tools`);
this.hlEl = el.querySelector(`.${ppfx}highlighter`); this.hlEl = el.querySelector(`.${ppfx}highlighter`) as HTMLElement;
this.badgeEl = el.querySelector(`.${ppfx}badge`); this.badgeEl = el.querySelector(`.${ppfx}badge`) as HTMLElement;
this.placerEl = el.querySelector(`.${ppfx}placeholder`); this.placerEl = el.querySelector(`.${ppfx}placeholder`) as HTMLElement;
this.ghostEl = el.querySelector(`.${ppfx}ghost`); this.ghostEl = el.querySelector(`.${ppfx}ghost`) as HTMLElement;
this.toolbarEl = el.querySelector(`.${ppfx}toolbar`); this.toolbarEl = el.querySelector(`.${ppfx}toolbar`) as HTMLElement;
this.resizerEl = el.querySelector(`.${ppfx}resizer`); this.resizerEl = el.querySelector(`.${ppfx}resizer`) as HTMLElement;
this.offsetEl = el.querySelector(`.${ppfx}offset-v`); this.offsetEl = el.querySelector(`.${ppfx}offset-v`) as HTMLElement;
this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`); this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`) as HTMLElement;
this.toolsGlobEl = el.querySelector(`.${ppfx}tools-gl`); this.toolsGlobEl = el.querySelector(`.${ppfx}tools-gl`) as HTMLElement;
this.toolsEl = toolsEl; this.toolsEl = toolsEl as HTMLElement;
this.el.className = getUiClass(em, this.className); this.el.className = getUiClass(em, this.className);
this.ready = 1; this.ready = true;
this._renderFrames(); this._renderFrames();
return this; return this;

131
src/canvas/view/FrameView.js → src/canvas/view/FrameView.ts

@ -1,31 +1,47 @@
import { bindAll, isString, debounce, isUndefined } from 'underscore'; import { bindAll, isString, debounce, isUndefined } from 'underscore';
import { appendVNodes, append, createEl, createCustomEvent, motionsEv } from '../../utils/dom'; import { appendVNodes, append, createEl, createCustomEvent, motionsEv } from '../../utils/dom';
import { on, off, setViewEl, hasDnd, getPointerEvent } from '../../utils/mixins'; import { on, off, setViewEl, hasDnd, getPointerEvent } from '../../utils/mixins';
import { View } from '../../common'; import { View } from '../../abstract';
import CssRulesView from '../../css_composer/view/CssRulesView'; import CssRulesView from '../../css_composer/view/CssRulesView';
import Droppable from '../../utils/Droppable'; import Droppable from '../../utils/Droppable';
import Frame from '../model/Frame';
import Canvas from '../model/Canvas';
import ComponentWrapper from '../../dom_components/model/ComponentWrapper';
import FrameWrapView from './FrameWrapView';
export default class FrameView extends View { export default class FrameView extends View<Frame, HTMLIFrameElement> {
tagName() {
return 'iframe';
}
attributes() { //@ts-ignore
return { get tagName(){return 'iframe'};
allowfullscreen: 'allowfullscreen', //@ts-ignore
}; get attributes() {return { allowfullscreen: 'allowfullscreen' }};
}
dragging = false;
droppable?: Droppable;
rect?: DOMRect;
initialize(o) { lastClientY?: number;
lastMaxHeight = 0;
private jsContainer?: HTMLElement;
private tools: {[key: string]: HTMLElement} = {};
private wrapper?: any;
private frameWrapView?: FrameWrapView;
constructor(model: Frame, view?: FrameWrapView) {
super({model});
bindAll(this, 'updateClientY', 'stopAutoscroll', 'autoscroll', '_emitUpdate'); bindAll(this, 'updateClientY', 'stopAutoscroll', 'autoscroll', '_emitUpdate');
const { model, el } = this; const { el, em } = this;
this.tools = {}; //el = em.config.el
this.config = { //@ts-ignore
...(o.config || {}), this.module._config = {
...(this.config || {}),
//@ts-ignore
frameView: this, frameView: this,
//canvasView: view?.cv
}; };
this.ppfx = this.config.pStylePrefix || ''; //console.log(this.config)
this.em = this.config.em; this.frameWrapView = view;
this.showGlobalTools = debounce(this.showGlobalTools.bind(this), 50); this.showGlobalTools = debounce(this.showGlobalTools.bind(this), 50);
const cvModel = this.getCanvasModel(); const cvModel = this.getCanvasModel();
this.listenTo(model, 'change:head', this.updateHead); this.listenTo(model, 'change:head', this.updateHead);
@ -40,16 +56,16 @@ export default class FrameView extends View {
updateHead() { updateHead() {
const { model } = this; const { model } = this;
const headEl = this.getHead(); const headEl = this.getHead();
const toRemove = []; const toRemove: any[] = [];
const toAdd = []; const toAdd: any[] = [];
const current = model.get('head'); const current = model.head;
const prev = model.previous('head'); const prev = model.previous('head');
const attrStr = (attr = {}) => const attrStr = (attr: any = {}) =>
Object.keys(attr) Object.keys(attr)
.sort() .sort()
.map(i => `[${i}="${attr[i]}"]`) .map(i => `[${i}="${attr[i]}"]`)
.join(''); .join('');
const find = (items, stack, res) => { const find = (items: any[], stack: any[], res: any[]) => {
items.forEach(item => { items.forEach(item => {
const { tag, attributes } = item; const { tag, attributes } = item;
const has = stack.some(s => s.tag === tag && attrStr(s.attributes) === attrStr(attributes)); const has = stack.some(s => s.tag === tag && attrStr(s.attributes) === attrStr(attributes));
@ -60,7 +76,7 @@ export default class FrameView extends View {
find(prev, current, toRemove); find(prev, current, toRemove);
toRemove.forEach(stl => { toRemove.forEach(stl => {
const el = headEl.querySelector(`${stl.tag}${attrStr(stl.attributes)}`); const el = headEl.querySelector(`${stl.tag}${attrStr(stl.attributes)}`);
el && el.parentNode.removeChild(el); el?.parentNode?.removeChild(el);
}); });
appendVNodes(headEl, toAdd); appendVNodes(headEl, toAdd);
} }
@ -69,28 +85,28 @@ export default class FrameView extends View {
return this.el; return this.el;
} }
getCanvasModel() { getCanvasModel(): Canvas {
return this.em.get('Canvas').getModel(); return this.em.get('Canvas').getModel();
} }
getWindow() { getWindow() {
return this.getEl().contentWindow; return this.getEl().contentWindow as Window;
} }
getDoc() { getDoc() {
return this.getEl().contentDocument; return this.getEl().contentDocument as Document;
} }
getHead() { getHead() {
return this.getDoc().querySelector('head'); return this.getDoc().querySelector('head') as HTMLHeadElement;
} }
getBody() { getBody() {
return this.getDoc().querySelector('body'); return this.getDoc().querySelector('body') as HTMLBodyElement;
} }
getWrapper() { getWrapper() {
return this.getBody().querySelector('[data-gjs-type=wrapper]'); return this.getBody().querySelector('[data-gjs-type=wrapper]') as HTMLElement;
} }
getJsContainer() { getJsContainer() {
@ -102,8 +118,7 @@ export default class FrameView extends View {
} }
getToolsEl() { getToolsEl() {
const { frameWrapView } = this.config; return this.frameWrapView?.elTools as HTMLElement;
return frameWrapView && frameWrapView.elTools;
} }
getGlobalToolsEl() { getGlobalToolsEl() {
@ -151,23 +166,24 @@ export default class FrameView extends View {
}; };
} }
_getTool(name) { _getTool(name: string) {
const { tools } = this; const { tools } = this;
const toolsEl = this.getToolsEl(); const toolsEl = this.getToolsEl();
if (!tools[name]) { if (!tools[name]) {
tools[name] = toolsEl.querySelector(name); tools[name] = toolsEl.querySelector(name) as HTMLElement;
} }
return tools[name]; return tools[name];
} }
remove() { remove(...args: any) {
const wrp = this.wrapper; const wrp = this.wrapper;
this._toggleEffects(); this._toggleEffects(false);
this.tools = {}; this.tools = {};
wrp && wrp.remove(); wrp && wrp.remove();
View.prototype.remove.apply(this, arguments); View.prototype.remove.apply(this, args);
return this;
} }
startAutoscroll() { startAutoscroll() {
@ -176,7 +192,7 @@ export default class FrameView extends View {
// By detaching those from the stack avoid browsers lags // By detaching those from the stack avoid browsers lags
// Noticeable with "fast" drag of blocks // Noticeable with "fast" drag of blocks
setTimeout(() => { setTimeout(() => {
this._toggleAutoscrollFx(1); this._toggleAutoscrollFx(true);
requestAnimationFrame(this.autoscroll); requestAnimationFrame(this.autoscroll);
}, 0); }, 0);
} }
@ -216,7 +232,7 @@ export default class FrameView extends View {
} }
} }
updateClientY(ev) { updateClientY(ev: Event) {
ev.preventDefault(); ev.preventDefault();
this.lastClientY = getPointerEvent(ev).clientY * this.em.getZoomDecimal(); this.lastClientY = getPointerEvent(ev).clientY * this.em.getZoomDecimal();
} }
@ -226,10 +242,10 @@ export default class FrameView extends View {
} }
stopAutoscroll() { stopAutoscroll() {
this.dragging && this._toggleAutoscrollFx(); this.dragging && this._toggleAutoscrollFx(false);
} }
_toggleAutoscrollFx(enable) { _toggleAutoscrollFx(enable: boolean) {
this.dragging = enable; this.dragging = enable;
const win = this.getWindow(); const win = this.getWindow();
const method = enable ? 'on' : 'off'; const method = enable ? 'on' : 'off';
@ -250,7 +266,7 @@ export default class FrameView extends View {
const evLoad = 'frame:load'; const evLoad = 'frame:load';
const evOpts = { el, model, view: this }; const evOpts = { el, model, view: this };
const canvas = this.getCanvasModel(); const canvas = this.getCanvasModel();
const appendScript = scripts => { const appendScript = (scripts: any[]) => {
if (scripts.length > 0) { if (scripts.length > 0) {
const src = scripts.shift(); const src = scripts.shift();
const scriptEl = createEl('script', { const scriptEl = createEl('script', {
@ -258,7 +274,7 @@ export default class FrameView extends View {
...(isString(src) ? { src } : src), ...(isString(src) ? { src } : src),
}); });
scriptEl.onerror = scriptEl.onload = appendScript.bind(null, scripts); scriptEl.onerror = scriptEl.onload = appendScript.bind(null, scripts);
el.contentDocument.head.appendChild(scriptEl); el.contentDocument?.head.appendChild(scriptEl);
} else { } else {
this.renderBody(); this.renderBody();
em && em.trigger(evLoad, evOpts); em && em.trigger(evLoad, evOpts);
@ -278,10 +294,10 @@ export default class FrameView extends View {
}; };
} }
renderStyles(opts = {}) { renderStyles(opts: any = {}) {
const head = this.getHead(); const head = this.getHead();
const canvas = this.getCanvasModel(); const canvas = this.getCanvasModel();
const normalize = stls => const normalize = (stls: any[]) =>
stls.map(href => ({ stls.map(href => ({
tag: 'link', tag: 'link',
attributes: { attributes: {
@ -291,9 +307,9 @@ export default class FrameView extends View {
})); }));
const prevStyles = normalize(opts.prev || canvas.previous('styles')); const prevStyles = normalize(opts.prev || canvas.previous('styles'));
const styles = normalize(canvas.get('styles')); const styles = normalize(canvas.get('styles'));
const toRemove = []; const toRemove: any[] = [];
const toAdd = []; const toAdd: any[] = [];
const find = (items, stack, res) => { const find = (items: any[], stack: any[], res: any[]) => {
items.forEach(item => { items.forEach(item => {
const { href } = item.attributes; const { href } = item.attributes;
const has = stack.some(s => s.attributes.href === href); const has = stack.some(s => s.attributes.href === href);
@ -304,18 +320,18 @@ export default class FrameView extends View {
find(prevStyles, styles, toRemove); find(prevStyles, styles, toRemove);
toRemove.forEach(stl => { toRemove.forEach(stl => {
const el = head.querySelector(`link[href="${stl.attributes.href}"]`); const el = head.querySelector(`link[href="${stl.attributes.href}"]`);
el && el.parentNode.removeChild(el); el?.parentNode?.removeChild(el);
}); });
appendVNodes(head, toAdd); appendVNodes(head, toAdd);
} }
renderBody() { renderBody() {
const { config, model, ppfx } = this; const { config, em, model, ppfx } = this;
const { em } = config;
const doc = this.getDoc(); const doc = this.getDoc();
const body = this.getBody(); const body = this.getBody();
const win = this.getWindow(); const win = this.getWindow();
const conf = em.get('Config'); const conf = em.config;
//@ts-ignore TODO I don't understand why this needed nowhere else is used
win._isEditor = true; win._isEditor = true;
this.renderStyles({ prev: [] }); this.renderStyles({ prev: [] });
@ -395,14 +411,16 @@ export default class FrameView extends View {
model: component, model: component,
config: { config: {
...component.config, ...component.config,
em,
frameView: this, frameView: this,
}, },
}).render(); }).render();
append(body, this.wrapper.el); append(body, this.wrapper?.el);
append( append(
body, body,
new CssRulesView({ new CssRulesView({
collection: model.getStyles(), collection: model.getStyles(),
//@ts-ignore
config: { config: {
...em.get('CssComposer').getConfig(), ...em.get('CssComposer').getConfig(),
frameView: this, frameView: this,
@ -414,7 +432,8 @@ export default class FrameView extends View {
//this.updateOffset(); // TOFIX (check if I need it) //this.updateOffset(); // TOFIX (check if I need it)
// Avoid some default behaviours // Avoid some default behaviours
on(body, 'click', ev => ev && ev.target.tagName == 'A' && ev.preventDefault()); //@ts-ignore
on(body, 'click', ev => ev && ev.target?.tagName == 'A' && ev.preventDefault());
on(body, 'submit', ev => ev && ev.preventDefault()); on(body, 'submit', ev => ev && ev.preventDefault());
// When the iframe is focused the event dispatcher is not the same so // When the iframe is focused the event dispatcher is not the same so
@ -430,12 +449,12 @@ export default class FrameView extends View {
}) })
); );
this._toggleEffects(1); this._toggleEffects(true);
this.droppable = hasDnd(em) && new Droppable(em, this.wrapper.el); this.droppable = hasDnd(em) && new Droppable(em, this.wrapper?.el);
model.trigger('loaded'); model.trigger('loaded');
} }
_toggleEffects(enable) { _toggleEffects(enable: boolean) {
const method = enable ? on : off; const method = enable ? on : off;
const win = this.getWindow(); const win = this.getWindow();
win && method(win, `${motionsEv} resize`, this._emitUpdate); win && method(win, `${motionsEv} resize`, this._emitUpdate);

66
src/canvas/view/FrameWrapView.js → src/canvas/view/FrameWrapView.ts

@ -1,34 +1,37 @@
import { bindAll, isNumber, isNull, debounce } from 'underscore'; import { bindAll, isNumber, isNull, debounce } from 'underscore';
import { View } from '../../common'; import { View } from '../../abstract';
import FrameView from './FrameView'; import FrameView from './FrameView';
import { createEl, removeEl } from '../../utils/dom'; import { createEl, removeEl } from '../../utils/dom';
import Dragger from '../../utils/Dragger'; import Dragger from '../../utils/Dragger';
import CanvasView from './CanvasView';
import Frame from '../model/Frame';
export default class FrameWrapView extends View { export default class FrameWrapView extends View<Frame> {
events() { events() {
return { return {
'click [data-action-remove]': 'remove', 'click [data-action-remove]': 'remove',
'mousedown [data-action-move]': 'startDrag', 'mousedown [data-action-move]': 'startDrag',
}; };
} }
elTools?: HTMLElement;
initialize(opts = {}, conf = {}) { frame: FrameView;
dragger?: Dragger;
cv: CanvasView
classAnim: string
constructor(model: Frame, canvasView: CanvasView) {
super({model});
bindAll(this, 'onScroll', 'frameLoaded', 'updateOffset', 'remove', 'startDrag'); bindAll(this, 'onScroll', 'frameLoaded', 'updateOffset', 'remove', 'startDrag');
const { model } = this; //console.log(model.module)
const config = { const config = {
...(opts.config || conf), ...(model.config),
frameWrapView: this, frameWrapView: this,
}; };
const { canvasView, em } = config;
this.cv = canvasView; this.cv = canvasView;
this.config = config; this.frame = new FrameView(model, this);
this.em = em;
this.canvas = em && em.get('Canvas');
this.ppfx = config.pStylePrefix || '';
this.frame = new FrameView({ model, config });
this.classAnim = `${this.ppfx}frame-wrapper--anim`; this.classAnim = `${this.ppfx}frame-wrapper--anim`;
this.updateOffset = debounce(this.updateOffset.bind(this)); this.updateOffset = debounce(this.updateOffset.bind(this), 0);
this.updateSize = debounce(this.updateSize.bind(this)); this.updateSize = debounce(this.updateSize.bind(this), 0);
this.listenTo(model, 'loaded', this.frameLoaded); this.listenTo(model, 'loaded', this.frameLoaded);
this.listenTo(model, 'change:x change:y', this.updatePos); this.listenTo(model, 'change:x change:y', this.updatePos);
this.listenTo(model, 'change:width change:height', this.updateSize); this.listenTo(model, 'change:width change:height', this.updateSize);
@ -38,10 +41,10 @@ export default class FrameWrapView extends View {
} }
setupDragger() { setupDragger() {
const { canvas, model } = this; const { module, model } = this;
let dragX, dragY, zoom; let dragX: number, dragY: number, zoom: number;
const toggleEffects = on => { const toggleEffects = (on: boolean) => {
canvas.toggleFramesEvents(on); module.toggleFramesEvents(on);
}; };
this.dragger = new Dragger({ this.dragger = new Dragger({
@ -50,10 +53,10 @@ export default class FrameWrapView extends View {
zoom = this.em.getZoomMultiplier(); zoom = this.em.getZoomMultiplier();
dragX = x; dragX = x;
dragY = y; dragY = y;
toggleEffects(); toggleEffects(false);
}, },
onEnd: () => toggleEffects(1), onEnd: () => toggleEffects(true),
setPosition: posOpts => { setPosition: (posOpts: any) => {
model.set({ model.set({
x: dragX + posOpts.x * zoom, x: dragX + posOpts.x * zoom,
y: dragY + posOpts.y * zoom, y: dragY + posOpts.y * zoom,
@ -62,20 +65,21 @@ export default class FrameWrapView extends View {
}); });
} }
startDrag(ev) { startDrag(ev?: Event) {
ev && this.dragger.start(ev); ev && this.dragger?.start(ev);
} }
__clear(opts) { __clear(opts?: any) {
const { frame } = this; const { frame } = this;
frame && frame.remove(opts); frame && frame.remove(opts);
removeEl(this.elTools); removeEl(this.elTools);
} }
remove(opts) { remove(opts?: any) {
this.__clear(opts); this.__clear(opts);
View.prototype.remove.apply(this, arguments); View.prototype.remove.apply(this, opts);
['frame', 'dragger', 'cv', 'em', 'canvas', 'elTools'].forEach(i => (this[i] = 0)); //@ts-ignore
['frame', 'dragger', 'cv', 'elTools'].forEach(i => (this[i] = 0));
return this; return this;
} }
@ -87,11 +91,11 @@ export default class FrameWrapView extends View {
frame.model._emitUpdated(); frame.model._emitUpdated();
} }
updatePos(md) { updatePos(md?: boolean) {
const { model, el } = this; const { model, el } = this;
const { x, y } = model.attributes; const { x, y } = model.attributes;
const { style } = el; const { style } = el;
this.frame.rect = 0; this.frame.rect = undefined;
style.left = isNaN(x) ? x : `${x}px`; style.left = isNaN(x) ? x : `${x}px`;
style.top = isNaN(y) ? y : `${y}px`; style.top = isNaN(y) ? y : `${y}px`;
md && this.updateOffset(); md && this.updateOffset();
@ -108,7 +112,7 @@ export default class FrameWrapView extends View {
updateDim() { updateDim() {
const { em, el, $el, model, classAnim, frame } = this; const { em, el, $el, model, classAnim, frame } = this;
if (!frame) return; if (!frame) return;
frame.rect = 0; frame.rect = undefined;
$el.addClass(classAnim); $el.addClass(classAnim);
const { noChanges, width, height } = this.__handleSize(); const { noChanges, width, height } = this.__handleSize();
@ -219,7 +223,7 @@ export default class FrameWrapView extends View {
` `
); );
this.elTools = elTools; this.elTools = elTools;
const twrp = cv.toolsWrapper; const twrp = cv?.toolsWrapper;
twrp && twrp.appendChild(elTools); // TODO remove on frame remove twrp && twrp.appendChild(elTools); // TODO remove on frame remove
onRender && onRender &&
onRender({ onRender({

21
src/canvas/view/FramesView.js

@ -1,21 +0,0 @@
import DomainViews from '../../domain_abstract/view/DomainViews';
import FrameWrapView from './FrameWrapView';
export default class FramesView extends DomainViews {
constructor(opts = {}, config) {
super(opts, config, true);
this.listenTo(this.collection, 'reset', this.render);
}
onRemoveBefore(items, opts) {
items.forEach(item => item.remove(opts));
}
onRender() {
const { config, $el } = this;
const { em } = config;
em && $el.attr({ class: `${em.getConfig().stylePrefix}frames` });
}
}
FramesView.prototype.itemView = FrameWrapView;

28
src/canvas/view/FramesView.ts

@ -0,0 +1,28 @@
import CanvasModule from '..';
import DomainViews from '../../abstract/DomainViews';
import Frames from '../model/Frames';
import CanvasView from './CanvasView';
import FrameWrapView from './FrameWrapView';
export default class FramesView extends DomainViews<Frames, FrameWrapView> {
canvasView: CanvasView;
private _module: CanvasModule;
constructor(opts = {}, config: any) {
super(opts, true);
//console.log(this.collection)
this.listenTo(this.collection, 'reset', this.render);
this.canvasView = config.canvasView
this._module = config.module;
}
onRemoveBefore(items: FrameWrapView[], opts = {}) {
items.forEach(item => item.remove(opts));
}
onRender() {
const { $el, ppfx } = this;
$el.attr({ class: `${ppfx}frames` });
}
protected renderView(item: any, type: string){return new FrameWrapView(item, this.canvasView)}
}

2
src/dom_components/view/ComponentView.js

@ -458,7 +458,7 @@ export default class ComponentView extends Backbone.View {
} }
_getFrame() { _getFrame() {
return this.config.frameView; return this.config.em?.get('Canvas').config.frameView;
} }
/** /**

19
src/editor/index.ts

@ -54,14 +54,15 @@
* ## Methods * ## Methods
* @module Editor * @module Editor
*/ */
import { EventHandler } from 'backbone'; import { EventHandler } from "backbone";
import { isUndefined } from 'underscore'; import { isUndefined } from "underscore";
import { IBaseModule } from '../abstract/Module'; import { IBaseModule } from "../abstract/Module";
import cash from '../utils/cash-dom'; import CanvasModule from "../canvas";
import html from '../utils/html'; import cash from "../utils/cash-dom";
import defaults from './config/config'; import html from "../utils/html";
import EditorModel from './model/Editor'; import defaults from "./config/config";
import EditorView from './view/EditorView'; import EditorModel from "./model/Editor";
import EditorView from "./view/EditorView";
export default class EditorModule implements IBaseModule<typeof defaults> { export default class EditorModule implements IBaseModule<typeof defaults> {
constructor(config = {}, opts: any = {}) { constructor(config = {}, opts: any = {}) {
@ -112,7 +113,7 @@ export default class EditorModule implements IBaseModule<typeof defaults> {
get Panels(): PanelsModule { get Panels(): PanelsModule {
return this.em.get('Panels'); return this.em.get('Panels');
} }
//@ts-ignore
get Canvas(): CanvasModule { get Canvas(): CanvasModule {
return this.em.get('Canvas'); return this.em.get('Canvas');
} }

4
src/editor/model/Editor.ts

@ -827,8 +827,8 @@ export default class EditorModel extends Model {
return this.get('DomComponents').getWrapper(); return this.get('DomComponents').getWrapper();
} }
setCurrentFrame(frameView: FrameView) { setCurrentFrame(frameView?: FrameView) {
return this.set('currentFrame', frameView); return this.set("currentFrame", frameView);
} }
getCurrentFrame(): FrameView { getCurrentFrame(): FrameView {

2
src/navigator/view/ItemView.ts

@ -1,5 +1,5 @@
import { isString, bindAll } from 'underscore'; import { isString, bindAll } from 'underscore';
import { View } from '../../abstract'; import { View } from '../../common';
import { getModel, isEscKey, isEnterKey } from '../../utils/mixins'; import { getModel, isEscKey, isEnterKey } from '../../utils/mixins';
import ComponentView from '../../dom_components/view/ComponentView'; import ComponentView from '../../dom_components/view/ComponentView';
import Component, { eventDrag } from '../../dom_components/model/Component'; import Component, { eventDrag } from '../../dom_components/model/Component';

2
src/navigator/view/ItemsView.ts

@ -1,4 +1,4 @@
import { View } from '../../abstract'; import { View } from '../../common';
import Component, { eventDrag } from '../../dom_components/model/Component'; import Component, { eventDrag } from '../../dom_components/model/Component';
import ItemView from './ItemView'; import ItemView from './ItemView';

7
src/pages/model/Page.ts

@ -24,7 +24,9 @@ export default class Page extends Model {
['component', 'styles'].map((i) => this.unset(i)); ['component', 'styles'].map((i) => this.unset(i));
} }
const frms: any[] = props.frames || [defFrame]; const frms: any[] = props.frames || [defFrame];
const frames = new Frames(frms?.map((model) => new Frame(model, opts))); const frames = new Frames(em.get("Canvas"),
frms?.map((model) => new Frame(em.get("Canvas"), model))
);
frames.page = this; frames.page = this;
this.set('frames', frames); this.set('frames', frames);
!this.getId() && this.set('id', em?.get('PageManager')._createId()); !this.getId() && this.set('id', em?.get('PageManager')._createId());
@ -33,7 +35,7 @@ export default class Page extends Model {
} }
onRemove() { onRemove() {
this.get('frames').reset(); this.getFrames().reset();
} }
getFrames(): Frames { getFrames(): Frames {
@ -84,7 +86,6 @@ export default class Page extends Model {
* const mainFrame = page.getMainFrame(); * const mainFrame = page.getMainFrame();
*/ */
getMainFrame(): Frame { getMainFrame(): Frame {
//@ts-ignore
return this.getFrames().at(0); return this.getFrames().at(0);
} }

2
src/utils/dom.js

@ -51,7 +51,7 @@ export const appendAtIndex = (parent, child, index) => {
export const append = (parent, child) => appendAtIndex(parent, child); export const append = (parent, child) => appendAtIndex(parent, child);
export const createEl = (tag, attrs = '', child) => { export const createEl = (tag, attrs = {}, child) => {
const el = document.createElement(tag); const el = document.createElement(tag);
attrs && each(attrs, (value, key) => el.setAttribute(key, value)); attrs && each(attrs, (value, key) => el.setAttribute(key, value));

8
src/utils/mixins.ts

@ -87,7 +87,7 @@ const shallowDiff = (objOrig: Record<string, any>, objNew: Record<string, any>)
return result; return result;
}; };
const on = (el: HTMLElement | HTMLElement[], ev: string, fn: () => void, opts?: AddEventListenerOptions) => { const on = (el: HTMLElement|Window|Document | (Window|HTMLElement|Document)[], ev: string, fn: (ev: Event) => void, opts?: AddEventListenerOptions) => {
const evs = ev.split(/\s+/); const evs = ev.split(/\s+/);
el = el instanceof Array ? el : [el]; el = el instanceof Array ? el : [el];
@ -96,7 +96,7 @@ const on = (el: HTMLElement | HTMLElement[], ev: string, fn: () => void, opts?:
} }
}; };
const off = (el: HTMLElement | HTMLElement[], ev: string, fn: () => void, opts?: AddEventListenerOptions) => { const off = (el: HTMLElement|Window|Document | (Window|HTMLElement|Document)[], ev: string, fn: (ev: Event) => void, opts?: AddEventListenerOptions) => {
const evs = ev.split(/\s+/); const evs = ev.split(/\s+/);
el = el instanceof Array ? el : [el]; el = el instanceof Array ? el : [el];
@ -220,7 +220,7 @@ const getModel = (el: any, $?: any) => {
return model; return model;
}; };
const getElRect = (el: HTMLElement) => { const getElRect = (el?: HTMLElement) => {
const def = { const def = {
top: 0, top: 0,
left: 0, left: 0,
@ -243,7 +243,7 @@ const getElRect = (el: HTMLElement) => {
/** /**
* Get cross-device pointer event * Get cross-device pointer event
* @param {Event} ev * @param {Event} ev
* @return {Event} * @return {PointerEvent}
*/ */
const getPointerEvent = (ev: Event) => const getPointerEvent = (ev: Event) =>
// @ts-ignore // @ts-ignore

Loading…
Cancel
Save