diff --git a/index.html b/index.html index 06c795195..323643296 100755 --- a/index.html +++ b/index.html @@ -9,18 +9,6 @@
diff --git a/src/canvas/main.js b/src/canvas/main.js index b048c5e96..d74bd6f9a 100644 --- a/src/canvas/main.js +++ b/src/canvas/main.js @@ -179,6 +179,39 @@ define(function(require) { }; }, + /** + * This method comes handy when you need to attach something like toolbars + * to elements inside the canvas, dealing with all relative position, + * offsets, etc. and returning as result the object with positions which are + * viewable by the user (when the canvas is scrolled the top edge of the element + * is not viewable by the user anymore so the new top edge is the one of the canvas) + * + * The target should be visible before being passed here as invisible elements + * return empty string as width + * @param {HTMLElement} target The target in this case could be the toolbar + * @param {HTMLElement} element The element on which I'd attach the toolbar + * @param {Boolean} toRight Set to true if you want the toolbar attached to the right + * @return {Object} + */ + getTargetToElementDim: function (target, element, toRight) { + var canvasPos = CanvasView.getPosition(); + var pos = CanvasView.getElementPos(element); + + var elTop = pos.top - target.offsetHeight; + var elLeft = pos.left; + elLeft += toRight ? pos.width : 0; + elLeft = toRight ? (elLeft - target.offsetWidth) : elLeft; + + var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft; + var topPos = elTop < canvasPos.top ? canvasPos.top : elTop; + topPos = topPos > (pos.top + pos.height) ? (pos.top + pos.height) : topPos; + + return { + top: topPos, + left: leftPos + }; + }, + /** * Returns wrapper element * @return {HTMLElement} diff --git a/src/canvas/view/CanvasView.js b/src/canvas/view/CanvasView.js index a074eff5b..6a5a04325 100644 --- a/src/canvas/view/CanvasView.js +++ b/src/canvas/view/CanvasView.js @@ -27,6 +27,7 @@ function(Backbone, FrameView) { var body = this.frame.el.contentDocument.body; this.toolsEl.style.top = '-' + body.scrollTop + u; this.toolsEl.style.left = '-' + body.scrollLeft + u; + this.em.trigger('canvasScroll'); }, /** @@ -42,12 +43,16 @@ function(Backbone, FrameView) { var conf = this.config.em.get('Config'); body.append(wrap.render()).append(cssc.render()); var protCss = conf.protectedCss; - var frameCss = '.' + ppfx + 'dashed *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' + + var frameCss = '.' + ppfx + 'dashed :not([contenteditable]) > *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' + '.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' + '.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+ '.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' + '.' + ppfx + 'no-pointer{pointer-events: none}' + - '.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}'; + '.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}' + + '* ::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1)}' + + '* ::-webkit-scrollbar-thumb {background: rgba(255, 255, 255, 0.2)}' + + '* ::-webkit-scrollbar {width: 10px}' + + (conf.canvasCss || ''); if(protCss) body.append(''); this.config.em.trigger('loaded'); diff --git a/src/commands/main.js b/src/commands/main.js index f6b0a9bb9..e338f5905 100644 --- a/src/commands/main.js +++ b/src/commands/main.js @@ -101,7 +101,56 @@ define(function(require) { defaultCommands['open-assets'] = require('./view/OpenAssets'); defaultCommands.fullscreen = require('./view/Fullscreen'); defaultCommands.preview = require('./view/Preview'); - //this.defaultCommands['resize-comp'] = require('./view/ResizeComponent'); + + defaultCommands['tlb-delete'] = { + run: function(ed){ + var sel = ed.getSelected(); + + if(!sel || !sel.get('removable')) { + console.warn('The element is not removable'); + return; + } + + sel.destroy(); + ed.Canvas.getToolbarEl().style.display = 'none'; + }, + }; + + defaultCommands['tlb-clone'] = { + run: function(ed){ + var sel = ed.getSelected(); + + if(!sel || !sel.get('copyable')) { + console.warn('The element is not clonable'); + return; + } + + var collection = sel.collection; + var index = collection.indexOf(sel); + collection.add(sel.clone(), {at: index + 1}); + }, + }; + + defaultCommands['tlb-move'] = { + run: function(ed){ + var sel = ed.getSelected(); + var toolbarEl = ed.Canvas.getToolbarEl(); + var toolbarDisplay = toolbarEl.style.display; + var cmdMove = ed.Commands.get('move-comp'); + + cmdMove.onEndMoveFromModel = function() { + ed.editor.runDefault(); + ed.editor.set('selectedComponent', sel); + //toolbarEl.style.display = toolbarDisplay; + //ed.trigger('canvasScroll'); <- Need first this on SelectComponent + }; + + ed.editor.stopDefault(); + cmdMove.initSorterFromModel(sel); + sel.set('status', 'selected'); + toolbarEl.style.display = 'none'; + }, + }; if(c.em) c.model = c.em.get('Canvas'); diff --git a/src/commands/view/SelectComponent.js b/src/commands/view/SelectComponent.js index c1ecc9047..b5f6d0e17 100644 --- a/src/commands/view/SelectComponent.js +++ b/src/commands/view/SelectComponent.js @@ -253,6 +253,7 @@ define(function(require) { * @param {Object} model */ updateToolbar: function(model) { + // if no model get the selectedOne var toolbar = model.get('toolbar'); var ppfx = this.ppfx; var showToolbar = this.config.em.get('Config').showToolbar; @@ -300,8 +301,9 @@ define(function(require) { var topPos = elTop < canvasPos.top ? canvasPos.top : elTop; // This will stop the toolbar when the end of the element is reached topPos = topPos > (pos.top + pos.height) ? (pos.top + pos.height) : topPos; - toolbarStyle.left = elLeft + unit; + toolbarStyle.top = topPos + unit; + toolbarStyle.left = leftPos + unit; }, /** diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index d6f8bbe4e..626d1bd9b 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -58,6 +58,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0) this.set('void', true); + this.opt = opt; this.sm = opt ? opt.sm || {} : {}; this.config = o || {}; this.defaultC = this.config.components || []; @@ -143,7 +144,8 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana } attr.status = ''; attr.view = ''; - return new this.constructor(attr, {sm: this.sm}); + + return new this.constructor(attr, this.opt); }, /** diff --git a/src/editor/config/config.js b/src/editor/config/config.js index b4fc4db7e..31678175a 100644 --- a/src/editor/config/config.js +++ b/src/editor/config/config.js @@ -20,14 +20,18 @@ define(function () { // Width for the editor container width: '100%', - // The css that could only be seen (for instance, inside the code viewer) - protectedCss: '*{box-sizing: border-box;}body{margin:0;height:100%}#wrapper{min-height:100%; overflow:auto}', + // CSS that could only be seen (for instance, inside the code viewer) + protectedCss: '*{box-sizing: border-box;}body{margin:0;height:100%;background:#fff}#wrapper{min-height:100%; overflow:auto}', + + // CSS for the iframe which containing the canvas, useful if you need to custom something inside + // (eg. the style of the selected component) + canvasCss: '', // Default command defaultCommand: 'select-comp', // Show a toolbar when the component is selected - showToolbar: 0, + showToolbar: 1, // Allow script tag importing allowScripts: 0, diff --git a/src/editor/main.js b/src/editor/main.js index a1e9f18d4..c9e913768 100644 --- a/src/editor/main.js +++ b/src/editor/main.js @@ -27,8 +27,9 @@ * var editor = grapesjs.init({...}); * ``` * Available events - * #run:{commandName} - * #stop:{commandName} + * #canvasScroll: - Triggered when the canvas is scrolled + * #run:{commandName} - Triggered when some command is called to run (eg. editor.runCommand('preview')) + * #stop:{commandName} - Triggered when some command is called to stop (eg. editor.stopCommand('preview')) * #load - When the editor is loaded * * @module Editor diff --git a/src/editor/view/EditorView.js b/src/editor/view/EditorView.js index da28909f0..bf1fdc93a 100644 --- a/src/editor/view/EditorView.js +++ b/src/editor/view/EditorView.js @@ -14,26 +14,26 @@ function(Backbone){ }, this); }, - render: function(){ + render: function() { var conf = this.conf; + var contEl = $(conf.el || ('body ' + conf.container)); this.$el.empty(); - this.$cont = $(conf.el || ('body ' + conf.container)); if(conf.width) - this.$cont.css('width', conf.width); + contEl.css('width', conf.width); if(conf.height) - this.$cont.css('height', conf.height); + contEl.css('height', conf.height); // Canvas this.$el.append(this.model.get('Canvas').render()); // Panels this.$el.append(this.pn.render()); - this.$el.attr('class', this.className); - this.$cont.html(this.$el); + contEl.addClass(conf.stylePrefix + 'editor-cont'); + contEl.html(this.$el); return this; } diff --git a/src/rich_text_editor/main.js b/src/rich_text_editor/main.js index 91906db86..b65adcb02 100644 --- a/src/rich_text_editor/main.js +++ b/src/rich_text_editor/main.js @@ -115,16 +115,12 @@ define(function(require) { * @private */ udpatePosition: function(){ - if(!this.lastEl || !c.em) - return; - var u = 'px'; - var eOffset = c.em.get('canvasOffset'); - var cvsView = c.em.get('Canvas').getCanvasView(); - var dims = cvsView.getElementPos(this.lastEl); - var toolS = toolbar.el.style; - var toolH = toolbar.$el.outerHeight(); - toolS.top = (dims.top - toolH) + u; - toolS.left = (dims.left + eOffset.left) + u; + var u = 'px'; + var canvas = c.em.get('Canvas'); + var pos = canvas.getTargetToElementDim(toolbar.el, this.lastEl, 1); + var toolbarStyle = toolbar.el.style; + toolbarStyle.top = pos.top + u; + toolbarStyle.left = pos.left + u; }, /** @@ -136,12 +132,19 @@ define(function(require) { view.$el.wysiwyg({}).focus(); this.lastEl = view.el; + this.show(); + if(c.em){ this.udpatePosition(); + c.em.off('change:canvasOffset', this.udpatePosition, this); c.em.on('change:canvasOffset', this.udpatePosition, this); + + // Update position on scrolling + c.em.off('canvasScroll', this.udpatePosition, this); + c.em.on('canvasScroll', this.udpatePosition, this); } - this.show(); + //Avoid closing edit mode clicking on toolbar toolbar.$el.on('mousedown', this.disableProp); }, @@ -202,4 +205,4 @@ define(function(require) { }; }; -}); \ No newline at end of file +}); diff --git a/styles/css/main.css b/styles/css/main.css index 1d382b6bc..e4bf30809 100644 --- a/styles/css/main.css +++ b/styles/css/main.css @@ -2661,6 +2661,15 @@ $fontColorActive: #4f8ef7; padding: 5px; cursor: pointer; } +.gjs-editor-cont ::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); } + +.gjs-editor-cont ::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); } + +.gjs-editor-cont ::-webkit-scrollbar { + width: 8px; } + /********************* MAIN ************************/ .clear { clear: both; } @@ -2758,7 +2767,6 @@ div.gjs-select { z-index: 1; /* This simulate body behaviour */ } .gjs-cv-canvas > iframe { - background-color: #fff; height: 100%; outline: medium none; width: 100%; @@ -3970,7 +3978,7 @@ ol.example li.placeholder:before { position: absolute; border-radius: 3px; overflow: hidden; - z-index: 5; } + z-index: 10; } #gjs-rte-toolbar .gjs-rte-btn { display: inline-block; padding: 5px; diff --git a/styles/scss/main.scss b/styles/scss/main.scss index 5924a5b94..c0922a9f3 100644 --- a/styles/scss/main.scss +++ b/styles/scss/main.scss @@ -162,6 +162,18 @@ $fontV: 20;//random(1000) cursor: pointer; } +.#{$app-prefix}editor-cont ::-webkit-scrollbar-track { + background: $mainDklColor; +} + +.#{$app-prefix}editor-cont ::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.2); +} + +.#{$app-prefix}editor-cont ::-webkit-scrollbar { + width: 8px; +} + /********************* MAIN ************************/ .clear{ clear:both } @@ -274,7 +286,6 @@ div.#{$app-prefix}select { z-index:1; > iframe { - background-color: #fff; height: 100%; outline: medium none; width: 100%; @@ -1430,7 +1441,7 @@ $uploadPadding: 150px 10px; position: absolute; border-radius: 3px; overflow: hidden; - z-index: 5; + z-index: 10; .#{$rte-prefix}btn { @extend .#{$app-prefix}color-main;