From 4407b9fb3ee058ba6f08c377b8602bebf0119d78 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 8 Jul 2016 23:22:15 +0200 Subject: [PATCH] Add rte toolbar --- src/canvas/view/CanvasView.js | 48 +++++++ src/dom_components/view/ComponentTextView.js | 16 +-- src/editor/model/Editor.js | 4 +- src/rich_text_editor/main.js | 130 ++++++++----------- styles/css/main.css | 1 + styles/scss/main.scss | 1 + 6 files changed, 113 insertions(+), 87 deletions(-) diff --git a/src/canvas/view/CanvasView.js b/src/canvas/view/CanvasView.js index 63a71b4b5..fe086ff53 100644 --- a/src/canvas/view/CanvasView.js +++ b/src/canvas/view/CanvasView.js @@ -13,6 +13,17 @@ function(Backbone, FrameView) { this.frame = new FrameView({ model: this.model.get('frame')}); }, + /** + * Update tools position + * @private + */ + onFrameScroll: function(){ + var u = 'px'; + var body = this.frame.el.contentDocument.body; + this.toolsEl.style.top = '-' + body.scrollTop + u; + this.toolsEl.style.left = '-' + body.scrollLeft + u; + }, + /** * Render inside frame's body * @private @@ -33,9 +44,46 @@ function(Backbone, FrameView) { if(protCss) body.append(''); this.config.em.trigger('loaded'); + this.frame.el.contentWindow.onscroll = this.onFrameScroll.bind(this); } }, + /** + * Get the offset of the element + * @param {HTMLElement} el + * @return {Object} + */ + offset: function(el){ + var rect = el.getBoundingClientRect(); + var docBody = el.ownerDocument.body; + return { + top: rect.top + docBody.scrollTop, + left: rect.left + docBody.scrollLeft + }; + }, + + /** + * Returns element's data info + * @param {HTMLElement} el + * @return {Object} + * @private + */ + getElementPos: function(el){ + if(!this.frmOff) + this.frmOff = this.offset(this.frame.el); + if(!this.cvsOff) + this.cvsOff = this.offset(this.el); + var eo = this.offset(el); + var top = eo.top + this.frmOff.top - this.cvsOff.top; + var left = eo.left + this.frmOff.left - this.cvsOff.left; + return { + top: top, + left: left, + height: el.offsetHeight, + width: el.offsetWidth + }; + }, + render: function() { this.wrapper = this.model.get('wrapper'); diff --git a/src/dom_components/view/ComponentTextView.js b/src/dom_components/view/ComponentTextView.js index 2e52342dc..782225f99 100644 --- a/src/dom_components/view/ComponentTextView.js +++ b/src/dom_components/view/ComponentTextView.js @@ -15,26 +15,24 @@ define(['backbone', './ComponentView'], }, /** - * Enable this component to be editable, - * load also the mini toolbar for quick editing + * Enable the component to be editable * @param {Event} e * @private * */ enableEditing: function(e){ if(this.rte) - this.rte.bind(this); + this.rte.attach(this); this.toggleEvents(1); }, /** * Disable this component to be editable - * @param Event + * @param {Event} * @private * */ disableEditing: function(e){ - if(this.rte){ - this.rte.unbind(this); - } + if(this.rte) + this.rte.detach(this); this.toggleEvents(); this.updateContents(); }, @@ -52,7 +50,7 @@ define(['backbone', './ComponentView'], * Update contents of the element * @private **/ - updateContents : function(){ + updateContents: function(){ this.model.set('content', this.el.innerHTML); }, @@ -63,7 +61,7 @@ define(['backbone', './ComponentView'], toggleEvents: function(enable) { var method = enable ? 'on' : 'off'; // The ownerDocument is from the frame - var elDocs = [this.el.ownerDocument, document]; + var elDocs = [this.el.ownerDocument, document, this.rte]; $(elDocs)[method]('mousedown', this.disableEditing); // Avoid closing edit mode on component click this.$el[method]('mousedown', this.disablePropagation); diff --git a/src/editor/model/Editor.js b/src/editor/model/Editor.js index 4cb87c7b1..c5e917840 100644 --- a/src/editor/model/Editor.js +++ b/src/editor/model/Editor.js @@ -272,7 +272,9 @@ define([ initRichTextEditor: function() { var cfg = this.config.rte, rteStylePfx = cfg.stylePrefix || 'rte-'; - cfg.stylePrefix = this.config.stylePrefix + rteStylePfx; + cfg.pStylePrefix = this.config.stylePrefix; + cfg.stylePrefix = cfg.pStylePrefix + rteStylePfx; + cfg.em = this; this.rte = new RichTextEditor(cfg); this.set('RichTextEditor', this.rte); }, diff --git a/src/rich_text_editor/main.js b/src/rich_text_editor/main.js index ea469bcc1..63dce4335 100644 --- a/src/rich_text_editor/main.js +++ b/src/rich_text_editor/main.js @@ -1,64 +1,44 @@ define(function(require) { - /** - * @class RichTextEditor - * @param {Object} Configurations - * - * @return {Object} - * */ - function RichTextEditor(config) - { - var c = config || {}, - defaults = require('./config/config'), - rte = require('./view/TextEditorView'), - CommandButtons = require('./model/CommandButtons'), - CommandButtonsView = require('./view/CommandButtonsView'); + + return function(config) { + var c = config || {}, + defaults = require('./config/config'), + rte = require('./view/TextEditorView'), + CommandButtons = require('./model/CommandButtons'), + CommandButtonsView = require('./view/CommandButtonsView'); for (var name in defaults) { if (!(name in c)) c[name] = defaults[name]; } - this.tlbPfx = c.stylePrefix; - this.commands = new CommandButtons(c.commands); - var obj = { - collection : this.commands, - config : c, - }; - - this.toolbar = new CommandButtonsView(obj); - this.$toolbar = this.toolbar.render().$el; - } + var tlbPfx = c.stylePrefix; + var toolbar = new CommandButtonsView({ + collection: new CommandButtons(c.commands), + config: c, + }); - RichTextEditor.prototype = { - - /** - * Render toolbar - * @return {HTMLElement} - */ - render: function(){ - return this.toolbar.render().el; - }, - - /** - * Return toolbar element - * @return {HTMLElement} - */ - getToolbarEl: function() { - return this.$toolbar; - }, + return { /** * Bind rich text editor to element * @param {View} view * */ - bind: function(view){ + attach: function(view){ view.$el.wysiwyg({hotKeys: {}}).focus(); - this.updatePosition(view.$el); + if(c.em){ + var u = 'px'; + var cvsView = c.em.get('Canvas').CanvasView; + var dims = cvsView.getElementPos(view.el); + var toolEl = toolbar.el; + var toolS = toolbar.el.style; + toolS.top = (dims.top - toolbar.$el.outerHeight()) + u; + toolS.left = dims.left + u; + } this.bindToolbar(view).show(); - //Avoid closing edit mode clicking on toolbar - this.$toolbar.on('mousedown', this.disableProp); + toolbar.$el.on('mousedown', this.disableProp); }, /** @@ -66,63 +46,42 @@ define(function(require) { * @param {Object} view * * */ - unbind: function(view){ + detach: function(view){ view.$el.wysiwyg('destroy'); this.hide(); - this.$toolbar.off('mousedown', this.disableProp); + toolbar.$el.off('mousedown', this.disableProp); }, /** * Bind toolbar to element - * @param {Object} view - * - * @return this + * @param {Object} view + * @return {this} * */ bindToolbar: function(view){ - var id = this.tlbPfx + view.model.cid, - dId = this.tlbPfx + 'inited'; + var id = tlbPfx + view.model.cid, + dId = tlbPfx + 'inited'; if(!view.$el.data(dId)){ view.$el.data(dId, 1); view.$el.attr('id',id); } - this.toolbar.updateTarget('#' + id); + toolbar.updateTarget('#' + id); return this; }, - /** - * Update toolbar position - * @param {Object} $el Element - * - */ - updatePosition: function($el){ - var cOffset = this.$container.offset(), - cTop = cOffset ? cOffset.top : 0, - cLeft = cOffset ? cOffset.left : 0, - eOffset = $el.offset(), - rTop = eOffset.top - cTop + this.$container.scrollTop(), - rLeft = eOffset.left - cLeft + this.$container.scrollLeft(); - if(!this.tlbH) - this.tlbH = this.$toolbar.outerHeight(); - this.$toolbar.css({ - top : (rTop - this.tlbH - 5), - left : rLeft - }); - }, - /** * Show toolbar * * */ - show : function(){ - this.$toolbar.show(); + show: function(){ + toolbar.el.style.display = 'block'; }, /** * Hide toolbar * * */ - hide : function(){ - this.$toolbar.hide(); + hide: function(){ + toolbar.el.style.display = 'none'; }, /** @@ -132,7 +91,24 @@ define(function(require) { disableProp: function(e){ e.stopPropagation(); }, + + /** + * Return toolbar element + * @return {HTMLElement} + */ + getToolbarEl: function() { + return toolbar.el; + }, + + /** + * Render toolbar + * @return {HTMLElement} + */ + render: function(){ + return toolbar.render().el; + } + + }; }; - return RichTextEditor; }); \ No newline at end of file diff --git a/styles/css/main.css b/styles/css/main.css index 02ea78d6c..1d9356f78 100644 --- a/styles/css/main.css +++ b/styles/css/main.css @@ -3534,6 +3534,7 @@ ol.example li.placeholder:before { position: absolute; border-radius: 3px; overflow: hidden; + display: none; z-index: 5; } #wte-rte-toolbar .wte-rte-btn { color: #eee; diff --git a/styles/scss/main.scss b/styles/scss/main.scss index e04bd13f5..70935265a 100644 --- a/styles/scss/main.scss +++ b/styles/scss/main.scss @@ -1148,6 +1148,7 @@ $uploadPadding: 150px 10px; position: absolute; border-radius: 3px; overflow: hidden; + display: none; z-index: 5; .#{$rte-prefix}btn {