Browse Source

Convert CanvasView to ts

pull/4316/head
Alex Ritter 4 years ago
parent
commit
a5a939a16a
  1. 19
      src/abstract/View.ts
  2. 187
      src/canvas/view/CanvasView.ts
  3. 4
      src/editor/model/Editor.ts
  4. 15
      src/utils/dom.js

19
src/abstract/View.ts

@ -1,19 +1,28 @@
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.model.em.config as any).stylePrefix || "";
} }
protected get ppfx() { protected get ppfx() {
return this.pfx + this.model.module.config.stylePrefix || ''; return this.pfx + this.config.stylePrefix || "";
}
protected get module(): TModel extends Model<infer M>? M: unknown {
return this.model.module as any;
} }
protected get em() { protected get em() {
return this.model.module.em; return this.model.em;
}
protected get config(): TModel extends Model<infer M> ? (M extends IBaseModule<infer C> ? C : unknown) : unknown{
return this.module.config as any
} }
} }

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

@ -1,12 +1,26 @@
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 Frame from '../model/Frame';
import FrameView from './FrameView';
export default class CanvasView extends View { import Components from '../../dom_components/model/Components';
import ComponentView from '../../dom_components/view/ComponentView';
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,23 +34,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(){
constructor(o) { return this.pfx + 'canvas':
super(o); }*/
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.model.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() {
@ -49,7 +82,7 @@ export default class CanvasView extends View {
const collection = model.get('frames'); const collection = model.get('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: {
@ -59,38 +92,40 @@ export default class CanvasView extends View {
}); });
} }
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;
fn(document, 'keypress', this.onKeyPress); fn(document, 'keypress', this.onKeyPress);
@ -98,7 +133,7 @@ export default class CanvasView extends View {
// fn(el, 'mousemove dragover', this.onCanvasMove); // fn(el, 'mousemove dragover', this.onCanvasMove);
} }
onKeyPress(ev) { onKeyPress(ev: Event) {
const { em } = this; const { em } = this;
const key = getKeyChar(ev); const key = getKeyChar(ev);
@ -108,28 +143,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() {
@ -141,7 +178,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);
@ -155,14 +192,14 @@ export default class CanvasView extends View {
* @param {HTMLElement} el * @param {HTMLElement} el
* @return { {top: number, left: number, width: number, height: number} } * @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,
}; };
@ -173,8 +210,8 @@ export default class CanvasView extends View {
* @private * @private
*/ */
clearOff() { clearOff() {
this.frmOff = null; this.frmOff = undefined;
this.cvsOff = null; this.cvsOff = undefined;
} }
/** /**
@ -182,11 +219,11 @@ export default class CanvasView extends View {
* @return { {top: number, left: number, width: number, height: number} } * @return { {top: number, left: number, width: number, height: number} }
* @public * @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;
@ -208,7 +245,7 @@ export default class CanvasView extends View {
* @return { {top: number, left: number, width: number, height: number, zoom: number, rect: any} } * @return { {top: number, left: number, width: number, height: number, zoom: number, rect: any} }
* @public * @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);
@ -229,21 +266,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 {{ marginTop: number, * @return { MarginPaddingOffsets }
* marginRight: number,
* marginBottom: number,
* marginLeft: number,
* paddingTop: number,
* paddingRight: number,
* paddingBottom: number,
* paddingLeft: number,}}
* @public * @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',
@ -252,7 +282,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();
}); });
@ -264,8 +295,9 @@ export default class CanvasView extends View {
* @return { {top: number, left: number, width: number, height: number} } obj Position object * @return { {top: number, left: number, width: number, height: number} } obj Position object
* @public * @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();
@ -286,7 +318,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();
@ -321,25 +354,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;
} }
@ -368,18 +401,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;

4
src/editor/model/Editor.ts

@ -822,8 +822,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 {

15
src/utils/dom.js

@ -5,8 +5,7 @@ const KEY_TAG = 'tag';
const KEY_ATTR = 'attributes'; const KEY_ATTR = 'attributes';
const KEY_CHILD = 'children'; const KEY_CHILD = 'children';
export const motionsEv = export const motionsEv = 'transitionend oTransitionEnd transitionend webkitTransitionEnd';
'transitionend oTransitionEnd transitionend webkitTransitionEnd';
export const isDoc = el => el && el.nodeType === 9; export const isDoc = el => el && el.nodeType === 9;
@ -18,14 +17,10 @@ export const removeEl = el => {
export const find = (el, query) => el.querySelectorAll(query); export const find = (el, query) => el.querySelectorAll(query);
export const attrUp = (el, attrs = {}) => export const attrUp = (el, attrs = {}) =>
el && el && el.setAttribute && each(attrs, (value, key) => el.setAttribute(key, value));
el.setAttribute &&
each(attrs, (value, key) => el.setAttribute(key, value));
export const isVisible = el => { export const isVisible = el => {
return ( return el && !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
el && !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
);
}; };
export const empty = node => { export const empty = node => {
@ -56,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));
@ -90,7 +85,7 @@ export const createCustomEvent = (e, cls) => {
Object.defineProperty(oEvent, prop, { Object.defineProperty(oEvent, prop, {
get() { get() {
return this.keyCodeVal; return this.keyCodeVal;
} },
}); });
}); });
} }

Loading…
Cancel
Save