diff --git a/src/canvas/config/config.js b/src/canvas/config/config.js index 1cd99480a..3c8c2a3b6 100644 --- a/src/canvas/config/config.js +++ b/src/canvas/config/config.js @@ -24,5 +24,12 @@ module.exports = { * return component.getName(); * } */ - customBadgeLabel: '' + customBadgeLabel: '', + + /** + * When some textable component is selected and focused (eg. input or text component) the editor + * stops some commands (eg. disables the copy/paste of components with CTRL+C/V to allow the copy/paste of the text). + * This option allows to customize, by a selector, which element should not be considered textable + */ + notTextable: ['button', 'input[type=checkbox]', 'input[type=radio]'] }; diff --git a/src/canvas/index.js b/src/canvas/index.js index d81f8f603..432bb80e3 100644 --- a/src/canvas/index.js +++ b/src/canvas/index.js @@ -409,11 +409,11 @@ module.exports = () => { * @private */ isInputFocused() { - let contentDocument = this.getFrameEl().contentDocument; - return ( - contentDocument.activeElement && - contentDocument.activeElement.tagName !== 'BODY' - ); + const doc = this.getDocument(); + const toIgnore = ['body', ...this.getConfig().notTextable]; + const focused = doc && doc.activeElement; + + return focused && !toIgnore.some(item => focused.matches(item)); }, /** diff --git a/src/commands/view/ComponentDelete.js b/src/commands/view/ComponentDelete.js index b00f60d11..2fc73c033 100644 --- a/src/commands/view/ComponentDelete.js +++ b/src/commands/view/ComponentDelete.js @@ -2,7 +2,7 @@ import { isArray } from 'underscore'; module.exports = { run(ed, sender, opts = {}) { - if (ed.getModel().isEditing()) return; + if (ed.getModel().isEditing() || ed.Canvas.isInputFocused()) return; let components = opts.component || ed.getSelectedAll(); components = isArray(components) ? [...components] : [components]; diff --git a/src/commands/view/ComponentEnter.js b/src/commands/view/ComponentEnter.js index 675efc4a4..3f1a9bc3b 100644 --- a/src/commands/view/ComponentEnter.js +++ b/src/commands/view/ComponentEnter.js @@ -1,6 +1,11 @@ module.exports = { run(ed) { - if (!ed.Canvas.hasFocus() || ed.getModel().isEditing()) return; + if ( + !ed.Canvas.hasFocus() || + ed.getModel().isEditing() || + ed.Canvas.isInputFocused() + ) + return; const toSelect = []; ed.getSelectedAll().forEach(component => { diff --git a/src/commands/view/ComponentExit.js b/src/commands/view/ComponentExit.js index 517d1d4d4..0dff37e03 100644 --- a/src/commands/view/ComponentExit.js +++ b/src/commands/view/ComponentExit.js @@ -1,6 +1,11 @@ module.exports = { run(ed) { - if (!ed.Canvas.hasFocus() || ed.getModel().isEditing()) return; + if ( + !ed.Canvas.hasFocus() || + ed.getModel().isEditing() || + ed.Canvas.isInputFocused() + ) + return; const toSelect = []; ed.getSelectedAll().forEach(component => { diff --git a/src/commands/view/ComponentNext.js b/src/commands/view/ComponentNext.js index 0a18824fe..c0af4744d 100644 --- a/src/commands/view/ComponentNext.js +++ b/src/commands/view/ComponentNext.js @@ -1,6 +1,11 @@ module.exports = { run(ed) { - if (!ed.Canvas.hasFocus() || ed.getModel().isEditing()) return; + if ( + !ed.Canvas.hasFocus() || + ed.getModel().isEditing() || + ed.Canvas.isInputFocused() + ) + return; const toSelect = []; ed.getSelectedAll().forEach(component => { diff --git a/src/commands/view/ComponentPrev.js b/src/commands/view/ComponentPrev.js index 09202d427..0fe40ebcb 100644 --- a/src/commands/view/ComponentPrev.js +++ b/src/commands/view/ComponentPrev.js @@ -1,6 +1,11 @@ module.exports = { run(ed) { - if (!ed.Canvas.hasFocus() || ed.getModel().isEditing()) return; + if ( + !ed.Canvas.hasFocus() || + ed.getModel().isEditing() || + ed.Canvas.isInputFocused() + ) + return; const toSelect = []; ed.getSelectedAll().forEach(component => { diff --git a/src/commands/view/CopyComponent.js b/src/commands/view/CopyComponent.js index 53f09822b..c26cd1ecb 100644 --- a/src/commands/view/CopyComponent.js +++ b/src/commands/view/CopyComponent.js @@ -3,7 +3,7 @@ module.exports = { const em = ed.getModel(); const models = [...ed.getSelectedAll()]; - if (models.length && !em.isEditing()) { + if (models.length && !em.isEditing() && !ed.Canvas.isInputFocused()) { em.set('clipboard', models); } } diff --git a/src/commands/view/PasteComponent.js b/src/commands/view/PasteComponent.js index 5c7c13bd3..3a127099d 100644 --- a/src/commands/view/PasteComponent.js +++ b/src/commands/view/PasteComponent.js @@ -6,7 +6,7 @@ module.exports = { const clp = em.get('clipboard'); const selected = ed.getSelected(); - if (clp && selected && !em.isEditing()) { + if (clp && selected && !em.isEditing() && !ed.Canvas.isInputFocused()) { ed.getSelectedAll().forEach(comp => { if (!comp) return; const coll = comp.collection; diff --git a/src/panels/view/PanelView.js b/src/panels/view/PanelView.js index f6e9f14dd..a98222168 100644 --- a/src/panels/view/PanelView.js +++ b/src/panels/view/PanelView.js @@ -13,6 +13,7 @@ module.exports = Backbone.View.extend({ this.id = this.pfx + model.get('id'); this.listenTo(model, 'change:appendContent', this.appendContent); this.listenTo(model, 'change:content', this.updateContent); + this.listenTo(model, 'change:visible', this.toggleVisible); model.view = this; }, @@ -30,6 +31,14 @@ module.exports = Backbone.View.extend({ this.$el.html(this.model.get('content')); }, + toggleVisible() { + if (!this.model.get('visible')) { + this.$el.addClass(`${this.ppfx}hidden`); + return; + } + this.$el.removeClass(`${this.ppfx}hidden`); + }, + attributes() { return this.model.get('attributes'); }, diff --git a/test/specs/panels/view/PanelView.js b/test/specs/panels/view/PanelView.js index 544d45022..cbd15dfa1 100644 --- a/test/specs/panels/view/PanelView.js +++ b/test/specs/panels/view/PanelView.js @@ -39,6 +39,19 @@ module.exports = { expect(view.$el.html()).toEqual('test2'); }); + test('Hide panel', () => { + expect(view.$el.hasClass('hidden')).toBeFalsy(); + model.set('visible', false); + expect(view.$el.hasClass('hidden')).toBeTruthy(); + }); + + test('Show panel', () => { + model.set('visible', false); + expect(view.$el.hasClass('hidden')).toBeTruthy(); + model.set('visible', true); + expect(view.$el.hasClass('hidden')).toBeFalsy(); + }); + describe('Init with options', () => { beforeEach(() => { model = new Panel({