From 4b1d24ea8664b579a521bfeb150b270cb92072ff Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 11 Apr 2019 00:58:23 +0200 Subject: [PATCH] Make Layers more reliable and generally more aware of textnodes. Closes #1949 --- src/canvas/view/CanvasView.js | 22 ++++++++++------------ src/commands/view/SelectComponent.js | 5 +++-- src/commands/view/ShowOffset.js | 4 +++- src/navigator/view/ItemView.js | 10 ++++++---- src/navigator/view/ItemsView.js | 4 ---- src/style_manager/view/SectorsView.js | 3 ++- src/utils/mixins.js | 17 ++++++++++++++++- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/canvas/view/CanvasView.js b/src/canvas/view/CanvasView.js index c73265578..576b15901 100644 --- a/src/canvas/view/CanvasView.js +++ b/src/canvas/view/CanvasView.js @@ -1,5 +1,12 @@ import Backbone from 'backbone'; -import { on, off, getElement, getKeyChar, isTextNode } from 'utils/mixins'; +import { + on, + off, + getElement, + getKeyChar, + isTextNode, + getElRect +} from 'utils/mixins'; const FrameView = require('./FrameView'); const $ = Backbone.$; let timerZoom; @@ -99,7 +106,7 @@ module.exports = Backbone.View.extend({ * @return {Boolean} */ isElInViewport(el) { - const rect = getElement(el).getBoundingClientRect(); + const rect = getElRect(getElement(el)); const frameRect = this.getFrameOffset(); const rTop = rect.top; const rLeft = rect.left; @@ -294,16 +301,7 @@ module.exports = Backbone.View.extend({ * @return {Object} */ offset(el) { - let rectText; - - if (isTextNode(el)) { - const range = document.createRange(); - range.selectNode(el); - rectText = range.getBoundingClientRect(); - range.detach(); - } - - var rect = rectText || el.getBoundingClientRect(); + var rect = getElRect(el); var docBody = el.ownerDocument.body; return { top: rect.top + docBody.scrollTop, diff --git a/src/commands/view/SelectComponent.js b/src/commands/view/SelectComponent.js index a472c75bf..a7a5a1831 100644 --- a/src/commands/view/SelectComponent.js +++ b/src/commands/view/SelectComponent.js @@ -1,5 +1,5 @@ import { bindAll, isElement, isUndefined } from 'underscore'; -import { on, off, getUnitFromValue } from 'utils/mixins'; +import { on, off, getUnitFromValue, isTextNode } from 'utils/mixins'; const ToolbarView = require('dom_components/view/ToolbarView'); const Toolbar = require('dom_components/model/Toolbar'); @@ -357,7 +357,8 @@ module.exports = { const pfx = config.stylePrefix || ''; const attrName = `data-${pfx}handler`; const resizeClass = `${pfx}resizing`; - const model = !isElement(elem) ? elem : em.getSelected(); + const model = + !isElement(elem) && !isTextNode(elem) ? elem : em.getSelected(); const resizable = model.get('resizable'); const el = isElement(elem) ? elem : model.getEl(); let options = {}; diff --git a/src/commands/view/ShowOffset.js b/src/commands/view/ShowOffset.js index e8bf7d580..ac3dde4eb 100644 --- a/src/commands/view/ShowOffset.js +++ b/src/commands/view/ShowOffset.js @@ -1,4 +1,5 @@ import Backbone from 'backbone'; +import { isTextNode } from 'utils/mixins'; const $ = Backbone.$; module.exports = { @@ -12,9 +13,11 @@ module.exports = { var state = opt.state || ''; var config = editor.getConfig(); const zoom = this.em.getZoomDecimal(); + const el = opt.el || ''; if ( !config.showOffsets || + isTextNode(el) || (!config.showOffsetsSelected && state == 'Fixed') ) { editor.stopCommand(this.id, opts); @@ -22,7 +25,6 @@ module.exports = { } var canvas = editor.Canvas; - var el = opt.el || ''; var pos = opt.elPos || canvas.getElementPos(el); var style = window.getComputedStyle(el); var ppfx = this.ppfx; diff --git a/src/navigator/view/ItemView.js b/src/navigator/view/ItemView.js index de4b0b3d0..547a0cdb8 100644 --- a/src/navigator/view/ItemView.js +++ b/src/navigator/view/ItemView.js @@ -68,12 +68,13 @@ export default Backbone.View.extend({ const ppfx = this.ppfx; const model = this.model; const components = model.get('components'); + const type = model.get('type') || 'default'; model.set('open', false); this.listenTo(components, 'remove add reset', this.checkChildren); this.listenTo(model, 'change:status', this.updateStatus); this.listenTo(model, 'change:open', this.updateOpening); this.listenTo(model, 'change:style:display', this.updateVisibility); - this.className = `${pfx}layer no-select ${ppfx}two-color`; + this.className = `${pfx}layer ${pfx}layer__${type} no-select ${ppfx}two-color`; this.inputNameCls = `${ppfx}layer-name`; this.clsTitleC = `${pfx}layer-title-c`; this.clsTitle = `${pfx}layer-title`; @@ -342,9 +343,9 @@ export default Backbone.View.extend({ }, render() { - const model = this.model; - var pfx = this.pfx; - var vis = this.isVisible(); + const { model, config, pfx, ppfx } = this; + const hidden = config.hideTextnode && model.is('textnode'); + const vis = this.isVisible(); const el = this.$el.empty(); const level = this.level + 1; @@ -373,6 +374,7 @@ export default Backbone.View.extend({ } !vis && (this.className += ` ${pfx}hide`); + hidden && (this.className += ` ${ppfx}hidden`); el.attr('class', this.className); this.updateOpening(); this.updateStatus(); diff --git a/src/navigator/view/ItemsView.js b/src/navigator/view/ItemsView.js index 7af500215..64ad1524c 100644 --- a/src/navigator/view/ItemsView.js +++ b/src/navigator/view/ItemsView.js @@ -75,10 +75,6 @@ module.exports = require('backbone').View.extend({ var fragment = fragmentEl || null; var viewObject = ItemView; - if (!this.isCountable(model, this.config.hideTextnode)) { - return; - } - var view = new viewObject({ level, model, diff --git a/src/style_manager/view/SectorsView.js b/src/style_manager/view/SectorsView.js index af8022bea..e242889ec 100644 --- a/src/style_manager/view/SectorsView.js +++ b/src/style_manager/view/SectorsView.js @@ -1,5 +1,6 @@ import Backbone from 'backbone'; import { extend, isString } from 'underscore'; +import { isTextNode } from 'utils/mixins'; const SectorView = require('./SectorView'); @@ -54,7 +55,7 @@ module.exports = Backbone.View.extend({ pt.helper = null; // Create computed style container - if (el) { + if (el && !isTextNode(el)) { const stateStr = state ? `:${state}` : null; pt.computed = window.getComputedStyle(el, stateStr); } diff --git a/src/utils/mixins.js b/src/utils/mixins.js index be406353c..7b09f9028 100644 --- a/src/utils/mixins.js +++ b/src/utils/mixins.js @@ -103,7 +103,7 @@ const hasDnd = em => { * @return {HTMLElement} */ const getElement = el => { - if (isElement(el)) { + if (isElement(el) || isTextNode(el)) { return el; } else if (el && el.getEl) { return el.getEl(); @@ -128,6 +128,20 @@ const getModel = (el, $) => { return model; }; +const getElRect = el => { + if (!el) return; + let rectText; + + if (isTextNode(el)) { + const range = document.createRange(); + range.selectNode(el); + rectText = range.getBoundingClientRect(); + range.detach(); + } + + return rectText || el.getBoundingClientRect(); +}; + /** * Get cross-device pointer event * @param {Event} ev @@ -153,6 +167,7 @@ export { upFirst, matches, getModel, + getElRect, camelCase, isTextNode, getKeyCode,