Browse Source

Merge branch 'cm-toolbar-ft' into dev

pull/36/head
Artur Arseniev 10 years ago
parent
commit
3536f9780b
  1. 2
      bower.json
  2. 2
      dist/css/grapes.min.css
  3. 12
      dist/grapes.min.js
  4. 2
      package.json
  5. 34
      src/canvas/main.js
  6. 38
      src/canvas/view/CanvasView.js
  7. 26
      src/commands/view/MoveComponent.js
  8. 126
      src/commands/view/SelectComponent.js
  9. 35
      src/demo.js
  10. 11
      src/dom_components/model/Component.js
  11. 13
      src/dom_components/model/ComponentImage.js
  12. 6
      src/dom_components/model/Toolbar.js
  13. 13
      src/dom_components/model/ToolbarButton.js
  14. 3
      src/dom_components/view/ComponentView.js
  15. 37
      src/dom_components/view/ToolbarButtonView.js
  16. 15
      src/dom_components/view/ToolbarView.js
  17. 3
      src/editor/config/config.js
  18. 11
      styles/css/main.css
  19. 13
      styles/scss/main.scss

2
bower.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Open source Web Template Editor",
"version": "0.3.37",
"version": "0.3.38",
"author": "Artur Arseniev",
"homepage": "http://grapesjs.com",
"main": [

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

12
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Open source Web Template Editor",
"version": "0.3.37",
"version": "0.3.38",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",

34
src/canvas/main.js

@ -136,6 +136,14 @@ define(function(require) {
return CanvasView.ghostEl;
},
/**
* Returns toolbar element
* @return {HTMLElement}
*/
getToolbarEl: function(){
return CanvasView.toolbarEl;
},
/**
* Render canvas
* */
@ -158,18 +166,18 @@ define(function(require) {
},
/**
* Get the offset of the element
* @param {HTMLElement} el
* @return {Object}
* @private
*/
offset: function(el){
var rect = el.getBoundingClientRect();
return {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
};
},
* Get the offset of the element
* @param {HTMLElement} el
* @return {Object}
* @private
*/
offset: function(el){
var rect = el.getBoundingClientRect();
return {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
};
},
/**
* Returns wrapper element
@ -182,4 +190,4 @@ define(function(require) {
};
};
});
});

38
src/canvas/view/CanvasView.js

@ -36,17 +36,18 @@ function(Backbone, FrameView) {
renderBody: function(){
var wrap = this.model.get('frame').get('wrapper');
if(wrap){
var ppfx = this.ppfx;
var body = this.frame.$el.contents().find('body');
var cssc = this.config.em.get('CssComposer');
var conf = this.config.em.get('Config');
body.append(wrap.render()).append(cssc.render());
var protCss = conf.protectedCss;
var frameCss = '.' + this.ppfx + 'dashed *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' +
'.' + this.ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' +
'.' + this.ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+
'.' + this.ppfx + 'freezed{opacity: 0.5; pointer-events: none}' +
'.' + this.ppfx + 'no-pointer{pointer-events: none}' +
'.' + this.ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}';
var frameCss = '.' + ppfx + 'dashed *{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}';
if(protCss)
body.append('<style>' + frameCss + protCss + '</style>');
this.config.em.trigger('loaded');
@ -135,17 +136,20 @@ function(Backbone, FrameView) {
var frame = this.frame;
frame.el.onload = this.renderBody;
}
this.toolsEl = $('<div>', { id: this.ppfx + 'tools' }).get(0);
this.hlEl = $('<div>', { class: this.ppfx + 'highlighter' }).get(0);
this.badgeEl = $('<div>', {class: this.ppfx + 'badge'}).get(0);
this.placerEl = $('<div>', {class: this.ppfx + 'placeholder'}).get(0);
this.placerIntEl = $('<div>', {class: this.ppfx + 'placeholder-int'}).get(0);
this.ghostEl = $('<div>', {class: this.ppfx + 'ghost'}).get(0);
this.placerEl.appendChild(this.placerIntEl);
this.toolsEl.appendChild(this.hlEl);
this.toolsEl.appendChild(this.badgeEl);
this.toolsEl.appendChild(this.placerEl);
this.toolsEl.appendChild(this.ghostEl);
var ppfx = this.ppfx;
this.toolsEl = $('<div>', { id: ppfx + 'tools' }).get(0);
this.hlEl = $('<div>', { class: ppfx + 'highlighter' }).get(0);
this.badgeEl = $('<div>', {class: ppfx + 'badge'}).get(0);
this.placerEl = $('<div>', {class: ppfx + 'placeholder'}).get(0);
this.placerIntEl = $('<div>', {class: ppfx + 'placeholder-int'}).get(0);
this.ghostEl = $('<div>', {class: ppfx + 'ghost'}).get(0);
this.toolbarEl = $('<div>', {class: ppfx + 'toolbar'}).get(0);
this.placerEl.appendChild(this.placerIntEl);
this.toolsEl.appendChild(this.hlEl);
this.toolsEl.appendChild(this.badgeEl);
this.toolsEl.appendChild(this.placerEl);
this.toolsEl.appendChild(this.ghostEl);
this.toolsEl.appendChild(this.toolbarEl);
this.$el.append(this.toolsEl);
var rte = this.em.get('rte');

26
src/commands/view/MoveComponent.js

@ -12,7 +12,7 @@ define(['backbone', './SelectComponent','./SelectPosition'],
this.noSelClass = this.ppfx + 'no-select';
},
enable: function(){
enable: function() {
SelectComponent.enable.apply(this, arguments);
this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass);
@ -40,6 +40,7 @@ define(['backbone', './SelectComponent','./SelectPosition'],
var drag = el.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
this.startSelectPosition(e.target, this.frameEl.contentDocument);
@ -50,6 +51,29 @@ define(['backbone', './SelectComponent','./SelectPosition'],
this.getContentWindow().on('keydown', this.rollback);
},
/**
* Init sorter from model
* @param {Object} model
* @private
*/
initSorterFromModel: function(model) {
var drag = model.get('draggable');
if(!drag)
return;
// Avoid badge showing on move
this.cacheEl = null;
var el = model.get('view').el;
this.startSelectPosition(el, this.frameEl.contentDocument);
this.sorter.draggable = drag;
this.sorter.onEndMove = this.onEndMoveFromModel.bind(this);
this.stopSelectComponent();
this.getContentWindow().on('keydown', this.rollback);
},
onEndMoveFromModel: function() {
this.getContentWindow().off('keydown', this.rollback);
},
/**
* Callback after sorting
* @private

126
src/commands/view/SelectComponent.js

@ -1,8 +1,11 @@
define(function() {
define(function(require) {
/**
* @class SelectComponent
* @private
* */
var ToolbarView = require('DomComponents/view/ToolbarView');
var Toolbar = require('DomComponents/model/Toolbar');
return {
init: function(o){
@ -16,6 +19,7 @@ define(function() {
var config = this.config.em.get('Config');
this.startSelectComponent();
this.toggleClipboard(config.copyPaste);
this.config.em.on('change:canvasOffset', this.onFrameScroll);
},
/**
@ -96,17 +100,20 @@ define(function() {
var key = e.which || e.keyCode;
var comp = this.editorModel.get('selectedComponent');
var focused = this.frameEl.contentDocument.activeElement.tagName !== 'BODY';
// On CANC (46) or Backspace (8)
if(key == 8 || key == 46) {
if(!focused)
e.preventDefault();
if(comp && !focused){
if(comp && !focused) {
if(!comp.get('removable'))
return;
return;
comp.set('status','');
comp.destroy();
this.hideBadge();
this.clean();
this.editorModel.set('selectedComponent',null);
this.hideHighlighter();
this.editorModel.set('selectedComponent', null);
}
}
},
@ -138,8 +145,14 @@ define(function() {
onOut: function(e) {
e.stopPropagation();
this.hideBadge();
if(this.hl)
this.hl.css({ left: -10000, top:-10000 });
this.hideHighlighter();
},
/**
* Hide Highlighter element
*/
hideHighlighter: function () {
this.canvas.getHighlighter().style.display = 'none';
},
/**
@ -190,14 +203,14 @@ define(function() {
* @private
*/
updateHighlighter: function(el, pos) {
if(!this.hl)
this.hl = $(this.canvas.getHighlighter());
this.hl.css({
left: pos.left,
top: pos.top,
height: pos.height,
width: pos.width
});
var hlEl = this.canvas.getHighlighter();
var hlStyle = hlEl.style;
var unit = 'px';
hlStyle.left = pos.left + unit;
hlStyle.top = pos.top + unit;
hlStyle.height = pos.height + unit;
hlStyle.width = pos.width + unit;
hlStyle.display = 'block';
},
/**
@ -223,7 +236,7 @@ define(function() {
m.set('open', 0);
}
var parent = nMd.collection ? nMd.collection.parent : null;
while(parent){
while(parent) {
parent.set('open', 1);
opened[parent.cid] = parent;
parent = parent.collection ? parent.collection.parent : null;
@ -231,9 +244,74 @@ define(function() {
this.editorModel.set('selectedComponent', nMd);
nMd.set('status','selected');
this.updateToolbar(nMd);
}
},
/**
* Update toolbar if the component has one
* @param {Object} model
*/
updateToolbar: function(model) {
var toolbar = model.get('toolbar');
var ppfx = this.ppfx;
var showToolbar = this.config.em.get('Config').showToolbar;
if (showToolbar && toolbar && toolbar.length) {
if(!this.toolbar) {
var toolbarEl = this.canvas.getToolbarEl();
toolbarEl.innerHTML = '';
this.toolbar = new Toolbar(toolbar);
var toolbarView = new ToolbarView({
collection: this.toolbar,
editor: this.editor
});
toolbarEl.appendChild(toolbarView.render().el);
}
this.toolbar.reset(toolbar);
var view = model.get('view');
if(view) {
this.updateToolbarPos(view.el);
}
}
},
/**
* Update toolbar positions
* @param {HTMLElement} el
* @param {Object} pos
*/
updateToolbarPos: function(el, elPos) {
var toolbarEl = this.canvas.getToolbarEl();
var canvasPos = this.getCanvasPosition();
var pos = elPos || this.getElementPos(el);
var toolbarStyle = toolbarEl.style;
var unit = 'px';
toolbarStyle.display = 'flex';
var elTop = pos.top - toolbarEl.offsetHeight;
var elLeft = pos.left + pos.width - toolbarEl.offsetWidth;
var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft;
// This will make the toolbar follow the window up
// and down while scrolling
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;
},
/**
* Return canvas dimensions and positions
* @return {Object}
*/
getCanvasPosition: function () {
return this.canvas.getCanvasView().getPosition();
},
/**
* Removes all highlighting effects on components
* @private
@ -258,8 +336,16 @@ define(function() {
*/
onFrameScroll: function(e){
var el = this.cacheEl;
if(el)
this.updateBadge(el, this.getElementPos(el));
if(el){
var elPos = this.getElementPos(el);
this.updateBadge(el, elPos);
var model = this.editorModel.get('selectedComponent');
if (model) {
var view = model.get('view');
this.updateToolbarPos(view.el);
}
}
},
/**
@ -303,7 +389,9 @@ define(function() {
return this.contWindow;
},
run: function(em, sender) {
run: function(em) {
if(em && em.get)
this.editor = em.get('Editor');
this.enable();
},
@ -314,6 +402,8 @@ define(function() {
this.em.set('selectedComponent', null);
this.toggleClipboard();
this.hideBadge();
this.canvas.getToolbarEl().style.display = 'none';
this.config.em.off('change:canvasOffset', this.onFrameScroll);
}
};
});

35
src/demo.js

@ -329,5 +329,40 @@ require(['config/require-config'], function() {
window.editor = editor;
/*
// Test toolbar commands
var cmd = editor.Commands;
cmd.add('tlb-delete', {
run: function(ed){
var sel = ed.getSelected();
if(!sel)
return;
sel.destroy();
ed.Canvas.getToolbarEl().style.display = 'none';
},
});
cmd.add('tlb-clone', {
run: function(ed){
var sel = ed.getSelected();
var collection = sel.collection;
var index = collection.indexOf(sel);
collection.add(sel.clone(), {at: index + 1});
},
});
cmd.add('tlb-move', {
run: function(ed){
var sel = ed.getSelected();
ed.editor.stopDefault();
var cmdMove = cmd.get('move-comp');
cmdMove.onEndMoveFromModel = function() {
ed.editor.runDefault();
};
cmdMove.initSorterFromModel(sel);
ed.Canvas.getToolbarEl().style.display = 'none';
},
});
*/
});
});

11
src/dom_components/model/Component.js

@ -41,6 +41,16 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
attributes: {},
classes: '',
traits: ['id', 'title'],
toolbar: [{
attributes: {class: 'fa fa-arrows'},
command: 'tlb-move',
},{
attributes: {class: 'fa fa-clone'},
command: 'tlb-clone',
},{
attributes: {class: 'fa fa-trash-o'},
command: 'tlb-delete',
}],
},
initialize: function(o, opt) {
@ -132,6 +142,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
});
}
attr.status = '';
attr.view = '';
return new this.constructor(attr, {sm: this.sm});
},

13
src/dom_components/model/ComponentImage.js

@ -10,6 +10,19 @@ define(['./Component'],
void: 1,
droppable: false,
traits: ['alt'],
toolbar: [{
attributes: {class: 'fa fa-arrows'},
command: 'tlb-move',
},{
attributes: {class: 'fa fa-clone'},
command: 'tlb-clone',
},{
attributes: {class: 'fa fa-pencil'},
command: 'tlb-edit',
},{
attributes: {class: 'fa fa-trash-o'},
command: 'tlb-delete',
}],
}),
initialize: function(o, opt) {

6
src/dom_components/model/Toolbar.js

@ -0,0 +1,6 @@
define(['backbone','./ToolbarButton'],
function (Backbone, ToolbarButton) {
return Backbone.Collection.extend({model: ToolbarButton});
});

13
src/dom_components/model/ToolbarButton.js

@ -0,0 +1,13 @@
define(['backbone'],
function(Backbone) {
return Backbone.Model.extend({
defaults: {
command: '',
attributes: {},
},
});
});

3
src/dom_components/view/ComponentView.js

@ -25,7 +25,8 @@ define(['backbone', './ComponentsView'],
this.listenTo(this.model, 'change:status', this.updateStatus);
this.listenTo(this.model, 'change:state', this.updateState);
this.listenTo(this.model.get('classes'), 'add remove change', this.updateClasses);
this.$el.data("model", this.model);
this.$el.data('model', this.model);
this.model.set('view', this);
this.$el.data("collection", this.components);
if(this.model.get('classes').length)

37
src/dom_components/view/ToolbarButtonView.js

@ -0,0 +1,37 @@
define(['backbone'],
function (Backbone) {
return Backbone.View.extend({
events: {
'mousedown': 'handleClick',
},
attributes: function () {
return this.model.get('attributes');
},
initialize: function(opts) {
this.editor = opts.config.editor;
},
handleClick: function() {
var command = this.model.get('command');
if (typeof command === 'function') {
command(this.editor);
}
if (typeof command === 'string') {
this.editor.runCommand(command);
}
},
render: function () {
var config = this.editor.getConfig();
this.el.className += ' ' + config.stylePrefix + 'toolbar-item';
return this;
},
});
});

15
src/dom_components/view/ToolbarView.js

@ -0,0 +1,15 @@
define(['backbone', 'Abstract/view/DomainViews', './ToolbarButtonView'],
function (Backbone, DomainViews, ToolbarButtonView) {
return DomainViews.extend({
itemView: ToolbarButtonView,
initialize: function(opts) {
this.config = {editor: opts.editor || ''};
this.listenTo(this.collection, 'reset', this.render);
},
});
});

3
src/editor/config/config.js

@ -26,6 +26,9 @@ define(function () {
// Default command
defaultCommand: 'select-comp',
// Show a toolbar when the component is selected
showToolbar: 1,
// If true render a select of available devices
showDevices: 1,

11
styles/css/main.css

@ -2801,6 +2801,17 @@ div.gjs-select {
.gjs-frame {
transition: width 0.35s ease; }
.gjs-toolbar {
position: absolute;
background-color: #3b97e3;
color: white;
z-index: 10; }
.gjs-toolbar-item {
padding: 5px 7px;
font-size: 0.8rem;
cursor: pointer; }
.btn-cl, .gjs-mdl-dialog .gjs-mdl-btn-close, .gjs-am-assets-cont #gjs-am-close {
font-size: 25px;
opacity: 0.3;

13
styles/scss/main.scss

@ -330,6 +330,19 @@ div.#{$app-prefix}select {
transition: width 0.35s ease;
}
.#{$app-prefix}toolbar {
position: absolute;
background-color: $colorBlue;
color: white;
z-index: 10;
}
.#{$app-prefix}toolbar-item {
padding: 5px 7px;
font-size: 0.8rem;
cursor: pointer;
}
.btn-cl {
font-size: 25px;
@include opacity(0.3);

Loading…
Cancel
Save