Browse Source

Merge pull request #856 from artf/dev

Merge dev branch
pull/883/head
Artur Arseniev 9 years ago
committed by GitHub
parent
commit
01254dc218
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 2
      dist/css/grapes.min.css
  3. 2385
      dist/grapes.js
  4. 6
      dist/grapes.min.js
  5. 2573
      package-lock.json
  6. 26
      package.json
  7. 4
      src/asset_manager/view/AssetsView.js
  8. 4
      src/block_manager/config/config.js
  9. 13
      src/block_manager/index.js
  10. 4
      src/block_manager/view/BlocksView.js
  11. 24
      src/canvas/view/CanvasView.js
  12. 2
      src/commands/index.js
  13. 40
      src/commands/view/OpenLayers.js
  14. 2
      src/commands/view/SelectComponent.js
  15. 2
      src/commands/view/SelectPosition.js
  16. 3
      src/dom_components/index.js
  17. 8
      src/dom_components/view/ComponentView.js
  18. 9
      src/domain_abstract/model/Styleable.js
  19. 12
      src/domain_abstract/ui/InputNumber.js
  20. 5
      src/editor/config/config.js
  21. 6
      src/editor/index.js
  22. 17
      src/editor/model/Editor.js
  23. 6
      src/index.js
  24. 6
      src/modal_dialog/index.js
  25. 2
      src/modal_dialog/view/ModalView.js
  26. 6
      src/navigator/config/config.js
  27. 77
      src/navigator/index.js
  28. 108
      src/navigator/view/ItemView.js
  29. 47
      src/navigator/view/ItemsView.js
  30. 2
      src/panels/view/ButtonsView.js
  31. 41
      src/panels/view/PanelView.js
  32. 32
      src/panels/view/PanelsView.js
  33. 4
      src/selector_manager/config/config.js
  34. 15
      src/selector_manager/index.js
  35. 16
      src/selector_manager/view/ClassTagsView.js
  36. 5
      src/storage_manager/index.js
  37. 4
      src/style_manager/config/config.js
  38. 11
      src/style_manager/index.js
  39. 17
      src/style_manager/model/Property.js
  40. 11
      src/style_manager/model/PropertyComposite.js
  41. 13
      src/style_manager/model/PropertyInteger.js
  42. 3
      src/style_manager/view/PropertiesView.js
  43. 8
      src/style_manager/view/PropertyCompositeView.js
  44. 6
      src/style_manager/view/PropertyIntegerView.js
  45. 10
      src/style_manager/view/PropertySliderView.js
  46. 7
      src/style_manager/view/PropertyStackView.js
  47. 11
      src/style_manager/view/PropertyView.js
  48. 25
      src/style_manager/view/SectorsView.js
  49. 3
      src/styles/scss/_gjs_blocks.scss
  50. 4
      src/styles/scss/_gjs_canvas.scss
  51. 211
      src/styles/scss/_gjs_layers.scss
  52. 71
      src/styles/scss/_gjs_panels.scss
  53. 91
      src/styles/scss/_gjs_selectors.scss
  54. 4
      src/styles/scss/_gjs_style_manager.scss
  55. 29
      src/styles/scss/_gjs_traits.scss
  56. 11
      src/styles/scss/_gjs_variables.scss
  57. 241
      src/styles/scss/main.scss
  58. 4
      src/trait_manager/config/config.js
  59. 20
      src/trait_manager/index.js
  60. 11
      src/trait_manager/view/TraitsView.js
  61. 73
      src/utils/Resizer.js
  62. 17
      src/utils/Sorter.js
  63. 8
      test/specs/style_manager/view/PropertyCompositeView.js

1
README.md

@ -191,6 +191,7 @@ $ npm test
* [grapesjs-style-gradient](https://github.com/artf/grapesjs-style-gradient) - Add a gradient type input
* [grapesjs-blocks-flexbox](https://github.com/artf/grapesjs-blocks-flexbox) - Add the flexbox block
* [grapesjs-lory-slider](https://github.com/artf/grapesjs-lory-slider) - Slider component by using [lory](https://github.com/meandmax/lory)
* [grapesjs-tabs](https://github.com/artf/grapesjs-tabs) - Simple tabs component
### Presets
* [grapesjs-preset-webpage](https://github.com/artf/grapesjs-preset-webpage) - Webpage Builder

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

2385
dist/grapes.js

File diff suppressed because it is too large

6
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2573
package-lock.json

File diff suppressed because it is too large

26
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.13.8",
"version": "0.14.5",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -13,8 +13,8 @@
"dependencies": {
"backbone": "^1.3.3",
"backbone-undo": "^0.2.5",
"cash-dom": "^1.3.5",
"codemirror": "^5.21.0",
"cash-dom": "^1.3.7",
"codemirror": "^5.34.0",
"codemirror-formatting": "^1.0.0",
"font-awesome": "^4.7.0",
"keymaster": "^1.6.2",
@ -27,23 +27,23 @@
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.1",
"chai": "^4.1.2",
"cross-env": "^5.0.5",
"documentation": "^5.3.0",
"eslint": "^4.1.1",
"cross-env": "^5.1.3",
"documentation": "^5.3.5",
"eslint": "^4.17.0",
"expect": "^1.20.2",
"html-webpack-plugin": "^2.30.1",
"husky": "^0.14.3",
"istanbul": "^0.4.2",
"jsdom": "^11.2.0",
"lint-staged": "^6.0.0",
"jsdom": "^11.6.2",
"lint-staged": "^6.1.0",
"mocha": "^3.1.2",
"node-sass": "^4.5.3",
"prettier": "1.10.1",
"promise-polyfill": "^6.0.2",
"node-sass": "^4.7.2",
"prettier": "1.10.2",
"promise-polyfill": "^6.1.0",
"sinon": "^3.2.1",
"string-replace-loader": "^1.3.0",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.11.1",
"whatwg-fetch": "^2.0.3"
},
"keywords": [

4
src/asset_manager/view/AssetsView.js

@ -20,10 +20,6 @@ module.exports = Backbone.View.extend({
<button class="${ppfx}btn-prim">${view.config.addBtnText}</button>
<div style="clear:both"></div>
</form>
<div class="${pfx}dips" style="display:none">
<button class="fa fa-th <%${ppfx}btnt"></button>
<button class="fa fa-th-list <%${ppfx}btnt"></button>
</div>
</div>
<div class="${pfx}assets" data-el="assets"></div>
<div style="clear:both"></div>

4
src/block_manager/config/config.js

@ -1,4 +1,8 @@
module.exports = {
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
blocks: [],
appendTo: ''

13
src/block_manager/index.js

@ -28,6 +28,8 @@
* }
* ...
*/
import { isElement } from 'underscore';
module.exports = () => {
var c = {},
defaults = require('./config/config'),
@ -108,6 +110,15 @@ module.exports = () => {
!blocks.length && blocks.reset(c.blocks);
},
postRender() {
const elTo = this.getConfig().appendTo;
if (elTo) {
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
el.appendChild(this.render());
}
},
/**
* Add new block to the collection.
* @param {string} id Block id
@ -199,6 +210,7 @@ module.exports = () => {
* Render blocks
* @param {Array} blocks Blocks to render, without the argument will render
* all global blocks
* @return {HTMLElement} Rendered element
* @example
* // Render all blocks (inside the global collection)
* blockManager.render();
@ -225,6 +237,7 @@ module.exports = () => {
}
blocksView.collection.reset(toRender);
return this.getContainer();
}
};
};

4
src/block_manager/view/BlocksView.js

@ -174,6 +174,7 @@ module.exports = require('backbone').View.extend({
},
render() {
const ppfx = this.ppfx;
const frag = document.createDocumentFragment();
this.catsEl = null;
this.blocksEl = null;
@ -187,7 +188,8 @@ module.exports = require('backbone').View.extend({
this.collection.each(model => this.add(model, frag));
this.append(frag);
this.$el.addClass(this.blockContClass + 's');
const cls = `${this.blockContClass}s ${ppfx}one-bg ${ppfx}two-color`;
this.$el.addClass(cls);
return this;
}
});

24
src/canvas/view/CanvasView.js

@ -128,11 +128,12 @@ module.exports = Backbone.View.extend({
.${ppfx}dashed *[data-highlightable] {
outline: 1px dashed rgba(170,170,170,0.7);
outline-offset: -3px
outline-offset: -2px;
}
.${ppfx}comp-selected {
outline: 3px solid #3b97e3 !important;
outline-offset: -3px;
}
.${ppfx}comp-selected-parent {
@ -206,8 +207,8 @@ module.exports = Backbone.View.extend({
// the keyCode/which will be always `0`. Even if it's an old/deprecated
// property keymaster (and many others) still use it... using `defineProperty`
// hack seems the only way
const createCustomEvent = e => {
var oEvent = new KeyboardEvent(e.type, e);
const createCustomEvent = (e, cls) => {
var oEvent = new window[cls](e.type, e);
oEvent.keyCodeVal = e.keyCode;
['keyCode', 'which'].forEach(prop => {
Object.defineProperty(oEvent, prop, {
@ -218,12 +219,17 @@ module.exports = Backbone.View.extend({
});
return oEvent;
};
fdoc.addEventListener('keydown', e => {
doc.dispatchEvent(createCustomEvent(e));
});
fdoc.addEventListener('keyup', e => {
doc.dispatchEvent(createCustomEvent(e));
});
[
{ event: 'keydown keyup', class: 'KeyboardEvent' }
//{ event: 'mousedown mousemove mouseup', class: 'MouseEvent' },
].forEach(obj =>
obj.event.split(' ').forEach(event => {
fdoc.addEventListener(event, e =>
doc.dispatchEvent(createCustomEvent(e, obj.class))
);
})
);
}
},

2
src/commands/index.js

@ -204,7 +204,7 @@ module.exports = () => {
cmdMove.initSorterFromModel(sel);
}
sel.set('status', 'selected');
sel.set('status', 'freezed-selected');
}
};

40
src/commands/view/OpenLayers.js

@ -2,36 +2,24 @@ const Layers = require('navigator');
const $ = Backbone.$;
module.exports = {
run(em, sender) {
if (!this.toAppend) {
var collection = em.DomComponents.getComponent().get('components');
var config = em.getConfig();
var pfx = config.stylePrefix;
var panels = em.Panels;
var lyStylePfx = config.layers.stylePrefix || 'nv-';
run(editor) {
const lm = editor.LayerManager;
const pn = editor.Panels;
config.layers.stylePrefix = config.stylePrefix + lyStylePfx;
config.layers.pStylePrefix = config.stylePrefix;
config.layers.em = em.editor;
config.layers.opened = em.editor.get('opened');
// Check if panel exists otherwise crate it
if (!panels.getPanel('views-container'))
this.panel = panels.addPanel({ id: 'views-container' });
else this.panel = panels.getPanel('views-container');
const toAppend = $(`<div class="${pfx}layers"></div>`);
this.panel.set('appendContent', toAppend).trigger('change:appendContent');
config.layers.sortContainer = toAppend.get(0);
const layers = new Layers().init(collection, config.layers);
this.$layers = layers.render();
toAppend.append(this.$layers);
this.toAppend = toAppend;
if (!this.layers) {
const id = 'views-container';
const layers = document.createElement('div');
const panels = pn.getPanel(id) || pn.addPanel({ id });
layers.appendChild(lm.render());
panels.set('appendContent', layers).trigger('change:appendContent');
this.layers = layers;
}
this.toAppend.show();
this.layers.style.display = 'block';
},
stop() {
this.toAppend && this.toAppend.hide();
const layers = this.layers;
layers && (layers.style.display = 'none');
}
};

2
src/commands/view/SelectComponent.js

@ -52,7 +52,7 @@ module.exports = {
methods[method](body, 'mouseover', this.onHover);
methods[method](body, 'mouseout', this.onOut);
methods[method](body, 'click', this.onClick);
methods[method](win, 'scroll', this.onFrameScroll);
methods[method](win, 'scroll resize', this.onFrameScroll);
methods[method](win, 'keydown', this.onKeyPress);
em[method]('change:selectedComponent', this.onSelect, this);
},

2
src/commands/view/SelectPosition.js

@ -23,7 +23,7 @@ module.exports = {
em: this.editorModel,
canvasRelative: 1
});
this.sorter.startSort(trg);
trg && this.sorter.startSort(trg);
},
/**

3
src/dom_components/index.js

@ -513,12 +513,11 @@ module.exports = () => {
const previousModel = em.previous('selectedComponent');
// Deselect the previous component
if (previousModel) {
previousModel &&
previousModel.set({
status: '',
state: ''
});
}
model && model.set('status', 'selected');
}

8
src/dom_components/view/ComponentView.js

@ -106,6 +106,7 @@ module.exports = Backbone.View.extend({
var selectedCls = pfx + 'selected';
var selectedParentCls = selectedCls + '-parent';
var freezedCls = `${ppfx}freezed`;
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`);
var actualCls = el.getAttribute('class') || '';
var cls = '';
@ -119,10 +120,9 @@ module.exports = Backbone.View.extend({
case 'freezed':
cls = `${actualCls} ${freezedCls}`;
break;
default:
this.$el.removeClass(
`${selectedCls} ${selectedParentCls} ${freezedCls}`
);
case 'freezed-selected':
cls = `${actualCls} ${freezedCls} ${selectedCls}`;
break;
}
cls = cls.trim();

9
src/domain_abstract/model/Styleable.js

@ -39,7 +39,14 @@ export default {
const propNew = { ...prop };
this.set('style', propNew, opts);
const diff = shallowDiff(propOrig, propNew);
keys(diff).forEach(pr => this.trigger(`change:style:${pr}`));
keys(diff).forEach(pr => {
const em = this.em;
this.trigger(`change:style:${pr}`);
if (em) {
em.trigger(`styleable:change`);
em.trigger(`styleable:change:${pr}`);
}
});
return propNew;
},

12
src/domain_abstract/ui/InputNumber.js

@ -1,4 +1,4 @@
import { bindAll } from 'underscore';
import { bindAll, isUndefined } from 'underscore';
import { on, off } from 'utils/mixins';
const Input = require('./Input');
const Backbone = require('backbone');
@ -228,7 +228,8 @@ module.exports = Input.extend({
var force = 0;
var opt = opts || {};
var model = this.model;
var val = value !== '' ? value : model.get('defaults');
const defValue = ''; //model.get('defaults');
var val = !isUndefined(value) ? value : defValue;
var units = model.get('units') || [];
var unit = model.get('unit') || (units.length && units[0]) || '';
var max = model.get('max');
@ -248,7 +249,7 @@ module.exports = Input.extend({
var valCopy = val + '';
val += ''; // Make it suitable for replace
val = parseFloat(val.replace(',', '.'));
val = !isNaN(val) ? val : model.get('defaults');
val = !isNaN(val) ? val : defValue;
var uN = valCopy.replace(val, '');
// Check if exists as unit
if (_.indexOf(units, uN) >= 0) unit = uN;
@ -256,9 +257,8 @@ module.exports = Input.extend({
}
}
if (typeof max !== 'undefined' && max !== '') val = val > max ? max : val;
if (typeof min !== 'undefined' && min !== '') val = val < min ? min : val;
if (!isUndefined(max) && max !== '') val = val > max ? max : val;
if (!isUndefined(min) && min !== '') val = val < min ? min : val;
return {
force,

5
src/editor/config/config.js

@ -230,9 +230,12 @@ module.exports = {
]
},
//Configurations for Block Manager
// Configurations for Block Manager
blockManager: {},
// Configurations for Trait Manager
traitManager: {},
// Texts
textViewCode: 'Code'

6
src/editor/index.js

@ -124,6 +124,12 @@ module.exports = config => {
*/
DomComponents: em.get('DomComponents'),
/**
* @property {LayerManager}
* @private
*/
LayerManager: em.get('LayerManager'),
/**
* @property {CssComposer}
* @private

17
src/editor/model/Editor.js

@ -1,4 +1,4 @@
import { isUndefined, defaults } from 'underscore';
import { isUndefined, isElement, defaults } from 'underscore';
const deps = [
require('utils'),
@ -17,6 +17,7 @@ const deps = [
require('css_composer'),
require('trait_manager'),
require('dom_components'),
require('navigator'),
require('canvas'),
require('commands'),
require('block_manager')
@ -216,20 +217,14 @@ module.exports = Backbone.Model.extend({
/**
* Select a component
* @param {Component|HTMLElement} el Component to select
* @param {Object} opts Options, optional
* @param {Object} [opts={}] Options, optional
* @private
*/
setSelected(el, opts = {}) {
let model = el;
if (el instanceof window.HTMLElement) {
model = $(el).data('model');
}
if (model && !model.get('selectable')) {
return;
}
isElement(el) && (model = $(el).data('model'));
if (model && !model.get('selectable')) return;
opts.forceChange && this.set('selectedComponent', '');
this.set('selectedComponent', model, opts);
},

6
src/index.js

@ -1,7 +1,8 @@
import $ from 'cash-dom';
import Editor from './editor';
import PluginManager from './plugin_manager';
import { isElement } from 'underscore';
import polyfills from 'utils/polyfills';
import PluginManager from './plugin_manager';
polyfills();
@ -48,8 +49,7 @@ module.exports = (() => {
const els = config.container;
if (!els) throw new Error("'container' is required");
config = { ...defaultConfig, ...config };
const ilEl = els instanceof window.HTMLElement;
config.el = ilEl ? els : document.querySelector(els);
config.el = isElement(els) ? els : document.querySelector(els);
const editor = new Editor(config).init();
// Load plugins

6
src/modal_dialog/index.js

@ -52,9 +52,9 @@ module.exports = () => {
return this;
},
postRender(editorView) {
// c.em.config.el || 'body'
this.render().appendTo(editorView.el);
postRender(view) {
const el = view.model.getConfig().el || view.el;
this.render().appendTo(el);
},
/**

2
src/modal_dialog/view/ModalView.js

@ -1,6 +1,6 @@
module.exports = require('backbone').View.extend({
template({ pfx, ppfx, content, title }) {
return `<div class="${pfx}dialog ${ppfx}one-bg">
return `<div class="${pfx}dialog ${ppfx}one-bg ${ppfx}two-color">
<div class="${pfx}header">
<div class="${pfx}title">${title}</div>
<div class="${pfx}btn-close">&Cross;</div>

6
src/navigator/config/config.js

@ -1,5 +1,9 @@
module.exports = {
stylePrefix: 'nv-',
stylePrefix: '',
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
// Enable/Disable globally the possibility to sort layers
sortable: 1,

77
src/navigator/index.js

@ -1,42 +1,62 @@
import defaults from './config/config';
import ItemView from './view/ItemView';
import ItemsView from './view/ItemsView';
import { isElement } from 'underscore';
module.exports = () => {
let itemsView;
let em;
let layers;
let config = {};
const defaults = require('./config/config');
const ItemView = require('./view/ItemView');
const ItemsView = require('./view/ItemsView');
let View = ItemsView;
return {
init(collection, opts) {
config = opts || config;
const em = config.em;
name: 'LayerManager',
// Set default options
for (var name in defaults) {
if (!(name in config)) config[name] = defaults[name];
}
init(opts = {}) {
config = { ...defaults, ...opts };
config.stylePrefix = opts.pStylePrefix;
em = config.em;
return this;
},
let View = ItemsView;
const level = 0;
const opened = opts.opened || {};
onLoad() {
const collection = em.get('DomComponents').getComponents();
const parent = collection.parent;
const options = {
level,
level: 0,
config,
opened
opened: config.opened || {}
};
// Show wrapper if requested
if (config.showWrapper && collection.parent) {
if (config.showWrapper && parent) {
View = ItemView;
options.model = collection.parent;
options.model = parent;
} else {
options.collection = collection;
}
itemsView = new View(options);
em && em.on('change:selectedComponent', this.componentChanged);
layers = new View(options);
em && em.on('component:selected', this.componentChanged);
this.componentChanged();
},
return this;
postRender() {
const elTo = config.appendTo;
if (elTo) {
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
el.appendChild(this.render());
}
},
/**
* Return the view of layers
* @return {View}
*/
getAll() {
return layers;
},
/**
@ -44,18 +64,11 @@ module.exports = () => {
* @private
*/
componentChanged(e, md, opts = {}) {
if (opts.fromLayers) {
return;
}
const em = config.em;
if (opts.fromLayers) return;
const opened = em.get('opened');
const model = em.get('selectedComponent');
const model = em.getSelected();
let parent = model && model.collection ? model.collection.parent : null;
for (let cid in opened) {
opened[cid].set('open', 0);
}
for (let cid in opened) opened[cid].set('open', 0);
while (parent) {
parent.set('open', 1);
@ -65,7 +78,7 @@ module.exports = () => {
},
render() {
return itemsView.render().$el;
return layers.render().el;
}
};
};

108
src/navigator/view/ItemView.js

@ -1,5 +1,6 @@
import { isUndefined } from 'underscore';
const ComponentView = require('dom_components/view/ComponentView');
const inputProp = 'contentEditable';
let ItemsView;
module.exports = require('backbone').View.extend({
@ -8,8 +9,8 @@ module.exports = require('backbone').View.extend({
'click [data-toggle-visible]': 'toggleVisibility',
'click [data-toggle-select]': 'handleSelect',
'click [data-toggle-open]': 'toggleOpening',
'dblclick input': 'handleEdit',
'focusout input': 'handleEditEnd'
'dblclick [data-name]': 'handleEdit',
'focusout [data-name]': 'handleEditEnd'
},
template(model) {
@ -17,36 +18,37 @@ module.exports = require('backbone').View.extend({
const ppfx = this.ppfx;
const hidable = this.config.hidable;
const count = this.countChildren(model);
const addClass = !count ? `${pfx}no-chld` : '';
const addClass = !count ? this.clsNoChild : '';
const clsTitle = `${this.clsTitle} ${addClass}`;
const clsTitleC = `${this.clsTitleC} ${ppfx}one-bg`;
const clsCaret = `${this.clsCaret} fa fa-chevron-right`;
const clsInput = `${this.inputNameCls} ${ppfx}no-app`;
const level = this.level + 1;
const gut = `${30 + level * 10}px`;
const name = model.getName();
return `
${
hidable
? `<i id="${pfx}btn-eye" class="${pfx}btn fa fa-eye ${
? `<i class="${pfx}layer-vis fa fa-eye ${
this.isVisible() ? '' : 'fa-eye-slash'
}" data-toggle-visible></i>`
: ''
}
<div class="${pfx}title-c ${ppfx}one-bg">
<div class="${pfx}title ${addClass}" style="padding-left: ${30 +
level * 10}px" data-toggle-select>
<div class="${pfx}title-inn">
<i id="${pfx}caret" class="fa fa-chevron-right ${
this.caretCls
}" data-toggle-open></i>
<div class="${clsTitleC}">
<div class="${clsTitle}" style="padding-left: ${gut}" data-toggle-select>
<div class="${pfx}layer-title-inn">
<i class="${clsCaret}" data-toggle-open></i>
${model.getIcon()}
<input class="${ppfx}no-app ${
this.inputNameCls
}" value="${model.getName()}" readonly>
<span class="${clsInput}" data-name>${name}</span>
</div>
</div>
</div>
<div id="${pfx}counter">${count ? count : ''}</div>
<div id="${pfx}move" data-toggle-move>
<div class="${this.clsCount}">${count || ''}</div>
<div class="${this.clsMove}" data-toggle-move>
<i class="fa fa-arrows"></i>
</div>
<div class="${pfx}children"></div>
<div class="${this.clsChildren}"></div>
`;
},
@ -68,18 +70,22 @@ module.exports = require('backbone').View.extend({
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}item no-select`;
this.editBtnCls = `${pfx}nav-item-edit`;
this.inputNameCls = `${ppfx}nav-comp-name`;
this.caretCls = `${ppfx}nav-item-caret`;
this.titleCls = `${pfx}title`;
this.className = `${pfx}layer no-select ${ppfx}two-color`;
this.inputNameCls = `${ppfx}layer-name`;
this.clsTitleC = `${pfx}layer-title-c`;
this.clsTitle = `${pfx}layer-title`;
this.clsCaret = `${pfx}layer-caret`;
this.clsCount = `${pfx}layer-count`;
this.clsMove = `${pfx}layer-move`;
this.clsChildren = `${pfx}layer-children`;
this.clsNoChild = `${pfx}layer-no-chld`;
this.$el.data('model', model);
this.$el.data('collection', components);
},
getVisibilityEl() {
if (!this.eyeEl) {
this.eyeEl = this.$el.children(`#${this.pfx}btn-eye`);
this.eyeEl = this.$el.children(`.${this.pfx}layer-vis`);
}
return this.eyeEl;
@ -88,7 +94,7 @@ module.exports = require('backbone').View.extend({
updateVisibility() {
const pfx = this.pfx;
const model = this.model;
const hClass = `${pfx}hide`;
const hClass = `${pfx}layer-hidden`;
const hideIcon = 'fa-eye-slash';
const hidden = model.getStyle().display == 'none';
const method = hidden ? 'addClass' : 'removeClass';
@ -121,20 +127,21 @@ module.exports = require('backbone').View.extend({
* Handle the edit of the component name
*/
handleEdit(e) {
e.stopPropagation();
var inputName = this.getInputName();
inputName.readOnly = false;
inputName.focus();
e && e.stopPropagation();
const inputEl = this.getInputName();
inputEl[inputProp] = true;
inputEl.focus();
},
/**
* Handle with the end of editing of the component name
*/
handleEditEnd(e) {
e.stopPropagation();
var inputName = this.getInputName();
inputName.readOnly = true;
this.model.set('custom-name', inputName.value);
e && e.stopPropagation();
const inputEl = this.getInputName();
const name = inputEl.textContent;
inputEl[inputProp] = false;
this.model.set({ name });
},
/**
@ -143,7 +150,7 @@ module.exports = require('backbone').View.extend({
*/
getInputName() {
if (!this.inputName) {
this.inputName = this.el.querySelector('.' + this.inputNameCls);
this.inputName = this.el.querySelector(`.${this.inputNameCls}`);
}
return this.inputName;
},
@ -197,13 +204,10 @@ module.exports = require('backbone').View.extend({
* */
startSort(e) {
e.stopPropagation();
//Right or middel click
if (e.button !== 0) {
return;
}
this.sorter && this.sorter.startSort(e.target);
const sorter = this.sorter;
// Right or middel click
if (e.button !== 0) return;
sorter && sorter.startSort(e.target);
},
/**
@ -252,19 +256,21 @@ module.exports = require('backbone').View.extend({
const model = this.model;
const c = this.countChildren(model);
const pfx = this.pfx;
const noChildCls = `${pfx}no-chld`;
const title = this.$el.children(`.${pfx}title-c`).children(`.${pfx}title`);
//tC = `> .${pfx}title-c > .${pfx}title`;
if (!this.$counter) {
this.$counter = this.$el.children(`#${pfx}counter`);
const noChildCls = this.clsNoChild;
const title = this.$el
.children(`.${this.clsTitleC}`)
.children(`.${this.clsTitle}`);
if (!this.cnt) {
this.cnt = this.$el.children(`.${this.clsCount}`);
}
if (c) {
title.removeClass(noChildCls);
this.$counter.html(c);
this.cnt.html(c);
} else {
title.addClass(noChildCls);
this.$counter.empty();
this.cnt.empty();
model.set('open', 0);
}
},
@ -289,7 +295,9 @@ module.exports = require('backbone').View.extend({
getCaret() {
if (!this.caret) {
const pfx = this.pfx;
this.caret = this.$el.children(`.${pfx}title-c`).find(`#${pfx}caret`);
this.caret = this.$el
.children(`.${this.clsTitleC}`)
.find(`.${this.clsCaret}`);
}
return this.caret;
@ -315,10 +323,10 @@ module.exports = require('backbone').View.extend({
parent: model,
level
}).render().$el;
el.find(`.${pfx}children`).append(children);
el.find(`.${this.clsChildren}`).append(children);
if (!model.get('draggable') || !this.config.sortable) {
el.children(`#${pfx}move`).remove();
el.children(`.${this.clsMove}`).remove();
}
!vis && (this.className += ` ${pfx}hide`);

47
src/navigator/view/ItemsView.js

@ -1,7 +1,6 @@
var Backbone = require('backbone');
var ItemView = require('./ItemView');
const ItemView = require('./ItemView');
module.exports = Backbone.View.extend({
module.exports = require('backbone').View.extend({
initialize(o = {}) {
this.opt = o;
const config = o.config || {};
@ -11,33 +10,38 @@ module.exports = Backbone.View.extend({
this.ppfx = config.pStylePrefix || '';
this.pfx = config.stylePrefix || '';
this.parent = o.parent;
this.listenTo(this.collection, 'add', this.addTo);
this.listenTo(this.collection, 'reset resetNavigator', this.render);
this.className = this.pfx + 'items';
const pfx = this.pfx;
const ppfx = this.ppfx;
const parent = this.parent;
const coll = this.collection;
this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset resetNavigator', this.render);
this.className = `${pfx}layers`;
const em = config.em;
if (config.sortable && !this.opt.sorter) {
var pfx = this.pfx;
var utils = config.em.get('Utils');
const utils = em.get('Utils');
this.opt.sorter = new utils.Sorter({
container: config.sortContainer || this.el,
containerSel: '.' + pfx + 'items',
itemSel: '.' + pfx + 'item',
ppfx: this.ppfx,
containerSel: `.${this.className}`,
itemSel: `.${pfx}layer`,
ignoreViewChildren: 1,
onEndMove(created, sorter) {
const srcModel = sorter.getSourceModel();
em.setSelected(srcModel, { forceChange: 1 });
},
avoidSelectOnEnd: 1,
pfx,
nested: 1
nested: 1,
ppfx,
pfx
});
}
this.sorter = this.opt.sorter || '';
// For the sorter
this.$el.data('collection', this.collection);
if (this.parent) {
this.$el.data('model', this.parent);
}
this.$el.data('collection', coll);
parent && this.$el.data('model', parent);
},
/**
@ -123,10 +127,11 @@ module.exports = Backbone.View.extend({
render() {
const frag = document.createDocumentFragment();
this.el.innerHTML = '';
const el = this.el;
el.innerHTML = '';
this.collection.each(model => this.addToCollection(model, frag));
this.el.appendChild(frag);
this.$el.attr('class', this.className);
el.appendChild(frag);
el.className = this.className;
return this;
}
});

2
src/panels/view/ButtonsView.js

@ -8,7 +8,7 @@ module.exports = Backbone.View.extend({
this.pfx = this.config.stylePrefix || '';
this.parentM = this.opt.parentM || null;
this.listenTo(this.collection, 'add', this.addTo);
this.listenTo(this.collection, 'reset', this.render);
this.listenTo(this.collection, 'reset remove', this.render);
this.className = this.pfx + 'buttons';
},

41
src/panels/view/PanelView.js

@ -68,16 +68,35 @@ module.exports = Backbone.View.extend({
bl: 0,
br: 0,
appendTo: this.el,
silentFrames: 1,
avoidContainerUpdate: 1,
prefix: editor.getConfig().stylePrefix,
posFetcher: el => {
var rect = el.getBoundingClientRect();
onEnd() {
em && em.trigger('change:canvasOffset');
},
posFetcher: (el, { target }) => {
const style = el.style;
const config = resizer.getConfig();
const keyWidth = config.keyWidth;
const keyHeight = config.keyHeight;
const rect = el.getBoundingClientRect();
const forContainer = target == 'container';
const styleWidth = style[keyWidth];
const styleHeight = style[keyHeight];
const width =
styleWidth && !forContainer ? parseFloat(styleWidth) : rect.width;
const height =
styleHeight && !forContainer
? parseFloat(styleHeight)
: rect.height;
return {
left: 0,
top: 0,
width: rect.width,
height: rect.height
width,
height
};
}
},
...resizable
});
resizer.blur = () => {};
resizer.focus(this.el);
@ -85,20 +104,20 @@ module.exports = Backbone.View.extend({
},
render() {
const el = this.$el;
const pfx = this.ppfx;
el.attr('class', `${this.className} ${pfx}one-bg`);
this.id && el.attr('id', this.id);
const $el = this.$el;
const ppfx = this.ppfx;
const cls = `${this.className} ${this.id} ${ppfx}one-bg ${ppfx}two-color`;
$el.addClass(cls);
if (this.buttons.length) {
var buttons = new ButtonsView({
collection: this.buttons,
config: this.config
});
el.append(buttons.render().el);
$el.append(buttons.render().el);
}
el.append(this.model.get('content'));
$el.append(this.model.get('content'));
return this;
}
});

32
src/panels/view/PanelsView.js

@ -32,15 +32,20 @@ module.exports = Backbone.View.extend({
* @private
* */
addToCollection(model, fragmentEl) {
var fragment = fragmentEl || null;
var view = new PanelView({
const fragment = fragmentEl || null;
const config = this.config;
const el = model.get('el');
const view = new PanelView({
el,
model,
config: this.config
config
});
var rendered = view.render().el;
var appendTo = model.get('appendTo');
const rendered = view.render().el;
const appendTo = model.get('appendTo');
if (appendTo) {
// Do nothing if the panel was requested to be another element
if (el) {
} else if (appendTo) {
var appendEl = document.querySelector(appendTo);
appendEl.appendChild(rendered);
} else {
@ -56,15 +61,12 @@ module.exports = Backbone.View.extend({
},
render() {
var fragment = document.createDocumentFragment();
this.$el.empty();
this.collection.each(function(model) {
this.addToCollection(model, fragment);
}, this);
this.$el.append(fragment);
this.$el.attr('class', this.className);
const $el = this.$el;
const frag = document.createDocumentFragment();
$el.empty();
this.collection.each(model => this.addToCollection(model, frag));
$el.append(frag);
$el.attr('class', this.className);
return this;
}
});

4
src/selector_manager/config/config.js

@ -2,6 +2,10 @@ module.exports = {
// Style prefix
stylePrefix: 'clm-',
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
// Default selectors
selectors: [],

15
src/selector_manager/index.js

@ -49,7 +49,7 @@
* }
*/
import { isString } from 'underscore';
import { isString, isElement } from 'underscore';
module.exports = config => {
var c = config || {},
@ -80,6 +80,10 @@ module.exports = config => {
return c;
},
getConfig() {
return c;
},
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
@ -112,6 +116,15 @@ module.exports = config => {
return this;
},
postRender() {
const elTo = this.getConfig().appendTo;
if (elTo) {
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
el.appendChild(this.render([]));
}
},
/**
* Add a new selector to collection if it's not already exists. Class type is a default one
* @param {String} name Selector name

16
src/selector_manager/view/ClassTagsView.js

@ -303,8 +303,10 @@ module.exports = Backbone.View.extend({
},
render() {
const ppfx = this.ppfx;
const config = this.config;
this.$el.html(
const $el = this.$el;
$el.html(
this.template({
selectedLabel: config.selectedLabel,
statesLabel: config.statesLabel,
@ -313,14 +315,14 @@ module.exports = Backbone.View.extend({
ppfx: this.ppfx
})
);
this.$input = this.$el.find('input#' + this.newInputId);
this.$addBtn = this.$el.find('#' + this.addBtnId);
this.$classes = this.$el.find('#' + this.pfx + 'tags-c');
this.$states = this.$el.find('#' + this.stateInputId);
this.$statesC = this.$el.find('#' + this.stateInputC);
this.$input = $el.find('input#' + this.newInputId);
this.$addBtn = $el.find('#' + this.addBtnId);
this.$classes = $el.find('#' + this.pfx + 'tags-c');
this.$states = $el.find('#' + this.stateInputId);
this.$statesC = $el.find('#' + this.stateInputC);
this.$states.append(this.getStateOptions());
this.renderClasses();
this.$el.attr('class', this.className);
$el.attr('class', `${this.className} ${ppfx}one-bg ${ppfx}two-color`);
return this;
}
});

5
src/storage_manager/index.js

@ -193,7 +193,7 @@ module.exports = () => {
for (var i = 0, len = keys.length; i < len; i++)
keysF.push(c.id + keys[i]);
st &&
if (st) {
st.load(keysF, res => {
// Restore keys name
var reg = new RegExp('^' + c.id + '');
@ -204,6 +204,9 @@ module.exports = () => {
clb && clb(result);
});
} else {
clb && clb(result);
}
},
/**

4
src/style_manager/config/config.js

@ -3,6 +3,10 @@ module.exports = {
sectors: [],
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
// Text to show in case no element selected
textNoElement: 'Select an element before using Style Manager',

11
src/style_manager/index.js

@ -38,6 +38,8 @@
* }
* ...
*/
import { isElement } from 'underscore';
module.exports = () => {
var c = {},
defaults = require('./config/config'),
@ -87,6 +89,15 @@ module.exports = () => {
return this;
},
postRender() {
const elTo = this.getConfig().appendTo;
if (elTo) {
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
el.appendChild(this.render());
}
},
/**
* Add new sector to the collection. If the sector with the same id already exists,
* that one will be returned

17
src/style_manager/model/Property.js

@ -1,3 +1,5 @@
import { isUndefined } from 'underscore';
module.exports = require('backbone').Model.extend({
defaults: {
name: '',
@ -36,6 +38,15 @@ module.exports = require('backbone').Model.extend({
init && init();
},
/**
* Clear the value
* @return {this}
*/
clearValue(opts = {}) {
this.set({ value: undefined }, opts);
return this;
},
/**
* Update value
* @param {any} value
@ -117,12 +128,12 @@ module.exports = require('backbone').Model.extend({
*/
getFullValue(val) {
const fn = this.get('functionName');
let value = val || this.get('value');
let value = isUndefined(val) ? this.get('value') : val;
if (fn) {
if (fn && !isUndefined(value)) {
value = `${fn}(${value})`;
}
return value;
return value || '';
}
});

11
src/style_manager/model/PropertyComposite.js

@ -28,11 +28,20 @@ module.exports = Property.extend({
this.listenTo(this, 'change:value', this.updateValues);
},
/**
* Clear the value
* @return {this}
*/
clearValue(opts = {}) {
this.get('properties').each(property => property.clearValue());
return Property.prototype.clearValue.apply(this, arguments);
},
/**
* Update property values
*/
updateValues() {
const values = this.get('value').split(this.get('separator'));
const values = this.getFullValue().split(this.get('separator'));
this.get('properties').each((property, i) => {
const len = values.length;
// Try to get value from a shorthand:

13
src/style_manager/model/PropertyInteger.js

@ -1,3 +1,5 @@
import { isUndefined } from 'underscore';
const Property = require('./Property');
const InputNumber = require('domain_abstract/ui/InputNumber');
@ -30,6 +32,11 @@ module.exports = Property.extend({
}
},
clearValue(opts = {}) {
this.set({ value: undefined, unit: undefined }, opts);
return this;
},
parseValue(val) {
const parsed = Property.prototype.parseValue.apply(this, arguments);
const { value, unit } = this.input.validateInputValue(parsed.value, {
@ -41,7 +48,11 @@ module.exports = Property.extend({
},
getFullValue() {
let value = this.get('value') + this.get('unit');
let value = this.get('value');
let unit = this.get('unit');
value = !isUndefined(value) ? value : '';
unit = !isUndefined(unit) && value ? unit : '';
value = `${value}${unit}`;
return Property.prototype.getFullValue.apply(this, [value]);
}
});

3
src/style_manager/view/PropertiesView.js

@ -16,6 +16,7 @@ module.exports = Backbone.View.extend({
this.onChange = o.onChange;
this.onInputRender = o.onInputRender || {};
this.customValue = o.customValue || {};
this.properties = [];
const coll = this.collection;
this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset', this.render);
@ -43,6 +44,7 @@ module.exports = Backbone.View.extend({
view.render();
const el = view.el;
this.properties.push(view);
if (frag) {
frag.appendChild(el);
@ -52,6 +54,7 @@ module.exports = Backbone.View.extend({
},
render() {
this.properties = [];
const fragment = document.createDocumentFragment();
this.collection.each(model => this.add(model, fragment));
this.$el.append(fragment);

8
src/style_manager/view/PropertyCompositeView.js

@ -19,6 +19,12 @@ module.exports = PropertyView.extend({
}
},
clear(e) {
const props = this.properties;
props && props.forEach(propView => propView.clear());
PropertyView.prototype.clear.apply(this, arguments);
},
/**
* Renders input
* */
@ -26,6 +32,7 @@ module.exports = PropertyView.extend({
var model = this.model;
var props = model.get('properties') || [];
var self = this;
this.properties = [];
if (props.length) {
if (!this.$input) {
@ -50,6 +57,7 @@ module.exports = PropertyView.extend({
var PropertiesView = require('./PropertiesView');
var propsView = new PropertiesView(this.getPropsConfig());
this.$props = propsView.render().$el;
this.properties = propsView.properties;
this.$el.find(`#${this.pfx}input-holder`).append(this.$props);
}
}

6
src/style_manager/view/PropertyIntegerView.js

@ -1,7 +1,9 @@
const InputNumber = require('domain_abstract/ui/InputNumber');
const PropertyView = require('./PropertyView');
const $ = Backbone.$;
let timeout;
module.exports = require('./PropertyView').extend({
module.exports = PropertyView.extend({
templateInput() {
return '';
},
@ -13,6 +15,8 @@ module.exports = require('./PropertyView').extend({
},
setValue(value) {
const parsed = this.model.parseValue(value);
value = `${parsed.value}${parsed.unit}`;
this.inputInst.setValue(value, { silent: 1 });
},

10
src/style_manager/view/PropertySliderView.js

@ -1,9 +1,13 @@
const Property = require('./PropertyIntegerView');
module.exports = Property.extend({
events: {
'change [type=range]': 'inputValueChanged',
'input [type=range]': 'inputValueChangedSoft'
events() {
return {
...Property.prototype.events,
'change [type=range]': 'inputValueChanged',
'input [type=range]': 'inputValueChangedSoft',
change: ''
};
},
templateInput(model) {

7
src/style_manager/view/PropertyStackView.js

@ -23,6 +23,13 @@ module.exports = PropertyCompositeView.extend({
this.delegateEvents();
},
clear(e) {
e && e.stopPropagation();
this.model.get('layers').reset();
this.model.clearValue();
this.targetUpdated();
},
/**
* Fired when the target is updated.
* With detached mode the component will be always empty as its value

11
src/style_manager/view/PropertyView.js

@ -1,4 +1,4 @@
import { bindAll, isArray } from 'underscore';
import { bindAll, isArray, isUndefined } from 'underscore';
import { camelCase } from 'utils/mixins';
const clearProp = 'data-clear-style';
@ -66,6 +66,7 @@ module.exports = Backbone.View.extend({
}
em && em.on(`update:component:style:${this.property}`, this.targetUpdated);
//em && em.on(`styleable:change:${this.property}`, this.targetUpdated);
this.listenTo(this.propTarget, 'update', this.targetUpdated);
this.listenTo(model, 'destroy remove', this.remove);
this.listenTo(model, 'change:value', this.modelValueChanged);
@ -111,9 +112,9 @@ module.exports = Backbone.View.extend({
/**
* Clear the property from the target
*/
clear() {
const target = this.getTargetModel();
target.removeStyle(this.model.get('property'));
clear(e) {
e && e.stopPropagation();
this.model.clearValue();
this.targetUpdated();
},
@ -435,7 +436,7 @@ module.exports = Backbone.View.extend({
* */
setValue(value) {
const model = this.model;
let val = value || model.getDefaultValue();
let val = isUndefined(value) ? model.getDefaultValue() : value;
const input = this.getInputEl();
input && (input.value = val);
},

25
src/style_manager/view/SectorsView.js

@ -3,10 +3,12 @@ import { extend } from 'underscore';
const SectorView = require('./SectorView');
module.exports = Backbone.View.extend({
initialize(o) {
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
initialize(o = {}) {
const config = o.config || {};
this.pfx = config.stylePrefix || '';
this.ppfx = config.pStylePrefix || '';
this.target = o.target || {};
this.config = config;
// The target that will emit events for properties
const target = {};
@ -117,15 +119,14 @@ module.exports = Backbone.View.extend({
},
render() {
var fragment = document.createDocumentFragment();
this.$el.empty();
this.collection.each(function(model) {
this.addToCollection(model, fragment);
}, this);
this.$el.attr('id', this.pfx + 'sectors');
this.$el.append(fragment);
const frag = document.createDocumentFragment();
const $el = this.$el;
const pfx = this.pfx;
const ppfx = this.ppfx;
$el.empty();
this.collection.each(model => this.addToCollection(model, frag));
$el.append(frag);
$el.addClass(`${pfx}sectors ${ppfx}one-bg ${ppfx}two-color`);
return this;
}
});

3
src/styles/scss/_gjs_blocks.scss

@ -35,6 +35,7 @@
cursor: all-scroll;
font-size: 11px;
font-weight: lighter;
text-align: center;
display: flex;
flex-direction: column;
justify-content: flex-end;
@ -51,7 +52,7 @@
}
.#{$app-prefix}block-svg {
width: 61%;
width: 54px;
fill: currentColor;
}

4
src/styles/scss/_gjs_canvas.scss

@ -94,6 +94,10 @@ $canvasTop: 40px;
@extend .#{$app-prefix}no-pointer-events;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 9;
}

211
src/styles/scss/_gjs_layers.scss

@ -1,140 +1,117 @@
.#{$nv-prefix} {
&selected-parent {
border: 1px solid $colorYell;
}
.#{$nv-prefix}selected-parent {
border: 1px solid $colorYell;
}
.#{$nv-prefix}opac50{
@include opacity(0.50);
}
.#{$app-prefix}layers {
position:relative;
height: 100%;
##{$nv-prefix}placeholder{
width: 100%;
position: absolute;
##{$nv-prefix}plh-int{
height: 100%;
padding: 1px;
&.#{$nv-prefix}insert{
background-color: $colorGreen;
}
}
&opac50 {
@include opacity(0.5);
}
.#{$nv-prefix}item {
&layer {
font-weight: lighter;
text-align: left;
position: relative;
background-color: rgba(0, 0, 0, 0.1);
}
.#{$nv-prefix}item.#{$nv-prefix}hide {
@include opacity(0.55);
}
.#{$nv-prefix}item ##{$nv-prefix}counter {
font-size: 10px;
position: absolute;
right: 27px;
top: 9px;
}
.#{$nv-prefix}item ##{$nv-prefix}btn-eye{
@extend .btn;
height: auto !important; width: auto !important;
font-size: 13px;
left: 0; top: 0;
padding: 7px 5px 7px 10px;
position: absolute;
cursor:pointer;
z-index: 1;
}
}
font-size: $fontSizeS;
.#{$nv-prefix}item ##{$nv-prefix}caret {
font-size: 7px;
width: 8px;
padding: 2px;
cursor: pointer;
position: absolute;
left: -9px;
top: 6px;
@include opacity(0.7);
&:hover {
@include opacity(1);
}
}
&-hidden {
@include opacity(0.55);
}
.#{$nv-prefix}title {
@extend .#{$app-prefix}category-title;
&-count {
position: absolute;
right: 27px;
top: 9px;
}
padding: 3px 10px 5px 30px;
display: flex;
align-items: center;
}
&-vis {
height: auto !important;
width: auto !important;
left: 0;
top: 0;
padding: 7px 5px 7px 10px;
position: absolute;
cursor: pointer;
z-index: 1;
}
.#{$nv-prefix}title-inn {
position: relative;
}
&-caret {
font-size: 0.5rem;
width: 8px;
padding: 2px;
cursor: pointer;
position: absolute;
left: -9px;
top: 6px;
@include opacity(0.7);
&:hover {
@include opacity(1);
}
}
.#{$nv-prefix}item .#{$nv-prefix}children .#{$nv-prefix}title{
border-left: 1px solid lighten($mainDkColor,2%);
}
.#{$nv-prefix}item > .#{$nv-prefix}children {
display: none;
}
.#{$nv-prefix}item.open > .#{$nv-prefix}children {
display: block;
}
&-title {
@extend .#{$app-prefix}category-title;
.#{$nv-prefix}item > .#{$nv-prefix}no-chld > ##{$nv-prefix}caret::before{
content:'';
}
padding: 3px 10px 5px 30px;
display: flex;
align-items: center;
.#{$nv-prefix}no-chld > .#{$nv-prefix}title-inn > ##{$nv-prefix}caret {
display:none;
}
&-inn {
position: relative;
}
}
.#{$nv-prefix}item > ##{$nv-prefix}move {
position: absolute;
cursor: move;
font-size: 12px;
right: 0; top: 0;
padding: 7px 10px 7px 5px;
}
/*
.#{$nv-prefix}item{
&.#{$nv-prefix}selected{
border: 2px solid $colorBlue;
}
}
*/
.#{$nv-prefix}selected .#{$nv-prefix}title {
background-color: rgba(255,255,255,0.1);
}
&-name {
padding: 5px;
display: inline-block;
box-sizing: content-box;
@extend .#{$app-prefix}no-user-select;
}
.#{$nv-prefix}nav-item-edit {
visibility: hidden;
padding: 5px;
font-size: 9px;
position: absolute;
left: -27px;
top: 1px;
> .#{$nv-prefix}layer-children {
display: none;
}
@include opacity(0.7);
&.open > .#{$nv-prefix}layer-children {
display: block;
}
&:hover {
@include opacity(1);
}
}
&-no-chld > .#{$nv-prefix}layer-title-inn > .#{$nv-prefix}layer-caret {
display: none;
}
.#{$nv-prefix}title-c:hover {
&-move {
padding: 7px 10px 7px 5px;
position: absolute;
font-size: 12px;
cursor: move;
right: 0;
top: 0;
}
.#{$nv-prefix}nav-item-edit {
visibility: visible;
cursor: pointer;
&.#{$nv-prefix}selected .#{$nv-prefix}layer-title {
background-color: rgba(255, 255, 255, 0.1);
}
}
}
.#{$app-prefix}nav-comp-name {
padding: 5px;
box-sizing: content-box;
@extend .#{$app-prefix}no-user-select;
.#{$app-prefix}layers {
position: relative;
height: 100%;
##{$nv-prefix}placeholder {
width: 100%;
position: absolute;
##{$nv-prefix}plh-int {
height: 100%;
padding: 1px;
&.#{$nv-prefix}insert {
background-color: $colorGreen;
}
}
}
}

71
src/styles/scss/_gjs_panels.scss

@ -0,0 +1,71 @@
.#{$pn-prefix} {
&panel {
display: inline-block;
position: absolute;
box-sizing: border-box;
text-align: center;
padding: 5px;
z-index: 3;
.icon-undo,
.icon-redo {
font-size: 20px;
height: 30px;
width: 25px;
}
}
&commands {
width: (100% - $leftWidth);
left: 0;
top: 0;
box-shadow: 0 0 5px $mainDkColor;
}
&options {
right: $leftWidth;
top: 0;
}
&views {
border-bottom: 2px solid $mainDkColor;
right: 0;
width: $leftWidth;
z-index: 4;
&-container {
height: 100%;
padding: 42px 0 0;
right: 0;
width: $leftWidth;
overflow: auto;
box-shadow: 0 0 5px $mainDkColor;
}
}
&buttons {
align-items: center;
display: flex;
justify-content: space-between;
}
&btn {
box-sizing: border-box;
height: 30px;
width: 30px;
line-height: 21px;
background-color: transparent;
border: none;
font-size: 18px;
margin-right: 5px;
border-radius: 2px;
padding: 5px;
position: relative;
cursor: pointer;
&.#{$pn-prefix}active {
background-color: rgba(0, 0, 0, 0.15);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25) inset;
}
}
}

91
src/styles/scss/_gjs_selectors.scss

@ -0,0 +1,91 @@
.#{$clm-prefix}field {
@extend .#{$sm-prefix}field
}
.#{$clm-prefix}select {
@extend .#{$sm-prefix}field.#{$sm-prefix}select;
}
.#{$clm-prefix}tags {
@extend .#{$sm-prefix}sector;
font-size: $fontSizeS;
padding: 10px 5px;
##{$clm-prefix}label,
##{$clm-prefix}sel {
padding: 7px 0;
float: left;
}
##{$clm-prefix}sel {
font-style: italic;
margin-left: 5px;
}
##{$clm-prefix}status-c {
float: right;
}
##{$clm-prefix}tags-field {
clear: both;
padding: 5px;
margin-bottom: 5px;
}
##{$clm-prefix}tags-c {
display: inline-block;
vertical-align: top;
}
##{$clm-prefix}add-tag {
background-color: rgba(255, 255, 255, 0.15);
border-radius: 2px;
padding: $paddElClm;
box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2) inset;
border: 1px solid rgba(0, 0, 0, 0.15);
cursor: pointer;
}
##{$clm-prefix}new {
@extend .#{$app-prefix}invis-invis;
color: $fontColor;
padding: $paddElClm;
display: none;
}
.#{$clm-prefix}tag {
display: inline-block;
border-radius: 3px;
margin: 0 3px 3px 0;
padding: 5px;
cursor: default;
}
##{$clm-prefix}close {
@extend .opac50;
font-size: 20px;
line-height: 0;
cursor: pointer;
color: rgba(255, 255, 255, 0.9);
@extend .no-select;
&:hover {
@include opacity(0.7);
}
}
##{$clm-prefix}checkbox {
color: rgba(255, 255, 255, 0.9);
vertical-align: middle;
cursor: pointer;
font-size: 9px;
}
##{$clm-prefix}tag-label {
padding: 0 3px;
cursor: text;
}
}

4
src/styles/scss/_gjs_style_manager.scss

@ -1,19 +1,17 @@
.#{$sm-prefix} {
&clear {
font-size: 1rem;
line-height: 0;
cursor: pointer;
}
&header {
font-size: 11px;
font-weight: lighter;
padding: 10px;
}
&properties {
font-size: 11px;
font-size: $fontSizeS;
padding: 10px 5px;
display: flex;
flex-wrap: wrap;

29
src/styles/scss/_gjs_traits.scss

@ -0,0 +1,29 @@
.#{$app-prefix} {
&traits-label {
border-bottom: 1px solid $mainDkColor;
font-weight: lighter;
margin-bottom: 5px;
padding: 10px;
text-align: left;
}
}
.#{$trt-prefix}trait {
display: flex;
justify-content: start;
padding: 5px 10px;
font-weight: lighter;
&s {
font-size: $fontSizeS;
}
.#{$app-prefix}label {
width: 30%;
text-align: left;
}
.#{$app-prefix}field {
width: 70%;
}
}

11
src/styles/scss/_gjs_variables.scss

@ -1,7 +1,7 @@
/* Class names prefixes */
$app-prefix: 'gjs-' !default;
$nv-prefix: $app-prefix + 'nv-' !default;
$nv-prefix: $app-prefix !default;
$rte-prefix: $app-prefix + 'rte-' !default;
$comp-prefix: $app-prefix + 'comp-' !default;
$mdl-prefix: $app-prefix + 'mdl-' !default;
@ -29,12 +29,6 @@ $mainColor: #444 !default; /* Light: #573454 Dark: #3b2639 -moz-linear-g
$fontColor: #ddd !default; /* l: #d8d7db */
$fontColorActive: #f8f8f8 !default;
/* Light theme
$mainColor: #fff;
$fontColor: #9299a3;
$fontColorActive: #4f8ef7;
*/
$mainDkColor: rgba(0, 0, 0, 0.2) !default;/* darken($mainColor, 4%) - #383838 */
$mainDklColor: rgba(0, 0, 0, 0.1) !default;
$mainLhColor: rgba(255, 255, 255, 0.1) !default; /* #515151 */
@ -80,4 +74,5 @@ $mainFont: Helvetica, sans-serif !default;
$fontPath: '../fonts' !default;
$fontName: 'main-fonts' !default;
$fontSize: 0.7rem;
$fontV: 20 !default;//random(1000)
$fontSizeS: 0.75rem;
$fontV: 20 !default;//random(1000)

241
src/styles/scss/main.scss

@ -215,7 +215,7 @@ $prefix: $app-prefix;
.#{$app-prefix}editor {
font-family: $mainFont;
font-size: $fontSize;
font-size: $fontSizeS;
position: relative;
box-sizing: border-box;
height: 100%;
@ -227,33 +227,7 @@ $prefix: $app-prefix;
pointer-events: none;
}
/************* TRAITS ****************/
.#{$app-prefix}traits-label {
border-bottom: 1px solid $mainDkColor;
font-size: 13px;
font-weight: lighter;
margin-bottom: 5px;
padding: 10px;
text-align: left;
}
.#{$trt-prefix}trait {
display: flex;
justify-content: start;
padding: 5px 10px;
font-weight: lighter;
.#{$app-prefix}label {
width: 30%;
text-align: left;
}
.#{$app-prefix}field {
width: 70%;
}
}
/************* CANVAS ****************/
@import "gjs_traits";
@import "gjs_canvas";
/********* COMMANDS **********/
@ -330,112 +304,7 @@ $prefix: $app-prefix;
outline: none;
}
/********* PANELS **********/
.#{$pn-prefix}panel {
//@extend .#{$app-prefix}bg-main;
//@extend .#{$app-prefix}color-main;
display: inline-block;
padding: 5px;
position: absolute;
box-sizing: border-box;
text-align: center;
z-index:3;
&##{$pn-prefix}commands{
width: (100% - $leftWidth);
left:0; top: 0;
box-shadow: 0 0 5px $mainDkColor;
}
&##{$pn-prefix}options{
right: $leftWidth;
top: 0;
}
&##{$pn-prefix}options2{
@extend ##{$pn-prefix}commands;
bottom: 150px;
height: auto;
}
.icon-undo, .icon-redo{
font-size: 20px;
height: 30px;
width: 25px;
}
&##{$pn-prefix}views{
border-bottom: 2px solid $mainDkColor;
right: 0;
width: $leftWidth;
z-index: 4;
}
&##{$pn-prefix}views-container{
height: 100%;
padding: 42px 0 0;
right: 0;
width: $leftWidth;
overflow: auto;
box-shadow: 0 0 5px $mainDkColor;
}
}
.#{$pn-prefix}buttons {
align-items: center;
display: flex;
justify-content: space-between;
}
.#{$pn-prefix}btn, .#{$app-prefix}btnt {
box-sizing: border-box;
height: 30px; width: 30px;
line-height: 21px;
background-color: transparent;
border:none;
font-size: 18px;
margin-right: 5px;
border-radius: 2px;
cursor: pointer;
padding: 5px;
position: relative;
&.#{$pn-prefix}active {
background-color: rgba(0, 0, 0, 0.15);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25) inset;
}
> .#{$pn-prefix}arrow-rd {
border-bottom: 5px solid $mainLhlColor;
border-left: 5px solid transparent;
bottom: 2px; right: 2px;
position: absolute;
}
> .#{$pn-prefix}buttons{
background-color: $mainColor;
border-radius: 2px;
position: absolute;
display: none;
left: 50px;
top: 0;
padding: 5px;
&.#{$pn-prefix}visible{ display: block; }
> .#{$pn-prefix}arrow-l {
border-bottom: 5px solid transparent;
border-right: 5px solid $mainColor;
border-top: 5px solid transparent;
left: -5px; top: 15px;
position: absolute;
}
}
}
/* pa-refresh pa-rocket pa-trash pa-columns pa-rotate-left/right */
.btn.expand{ background-image: none;}
@import 'gjs_panels';
/*********** Components *************/
@ -474,7 +343,6 @@ $prefix: $app-prefix;
font-weight: lighter;
background-color: $mainDklColor;
font-size: 13px;
letter-spacing: 1px;
padding: 9px 10px 9px 20px;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
@ -483,108 +351,11 @@ $prefix: $app-prefix;
cursor: pointer;
}
/********* Style Manager **********/
@import "gjs_style_manager";
/********* Blocks **********/
@import "gjs_blocks";
/************* Navigator *************/
@import "gjs_layers";
/********* Class manager **********/
.#{$clm-prefix}field{
@extend .#{$sm-prefix}field
}
.#{$clm-prefix}select{
@extend .#{$sm-prefix}field.#{$sm-prefix}select;
}
.#{$clm-prefix}tags{
@extend .#{$sm-prefix}sector;
font-size: 11px;
padding: 10px 5px;
##{$clm-prefix}label, ##{$clm-prefix}sel{
padding: 7px 0;
float:left;
}
##{$clm-prefix}sel{
font-style: italic;
margin-left: 5px;
}
##{$clm-prefix}status-c{
float:right;
}
##{$clm-prefix}tags-field{
clear:both;
padding: 5px;
margin-bottom: 5px;
}
##{$clm-prefix}tags-c{
display: inline-block;
vertical-align: top;
}
##{$clm-prefix}add-tag{
background-color: rgba(255, 255, 255, 0.15);
border-radius: 2px;
padding: $paddElClm;
box-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2) inset;
border: 1px solid rgba(0, 0, 0, 0.15);
cursor: pointer;
}
##{$clm-prefix}new {
@extend .#{$app-prefix}invis-invis;
color: $fontColor;
padding: $paddElClm;
display:none;
}
.#{$clm-prefix}tag {
display: inline-block;
border-radius:3px;
margin: 0 3px 3px 0;
padding: 5px;
cursor: default;
}
##{$clm-prefix}close {
@extend .opac50;
font-size: 20px;
line-height: 0;
cursor:pointer;
color: rgba(255, 255, 255, 0.9);
@extend .no-select;
&:hover{
@include opacity(0.7);
}
}
##{$clm-prefix}checkbox {
color: rgba(255, 255, 255, 0.9);
vertical-align: middle;
cursor: pointer;
font-size: 9px;
}
##{$clm-prefix}tag-label {
padding: 0 3px;
cursor: text;
}
}
/********* END Class manager **********/
/********* Modal dialog **********/
@import "gjs_selectors";
@import "gjs_modal";
/********* Assets Manager **********/
@import "gjs_assets";
/********* File uploader **********/
@ -752,3 +523,7 @@ $prefix: $app-prefix;
opacity: 0;
}
}
.cm-s-hopscotch span.cm-error {
color: #ffffff;
}

4
src/trait_manager/config/config.js

@ -1,6 +1,10 @@
module.exports = {
stylePrefix: 'trt-',
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
labelContainer: 'Component settings',
// Placeholder label for text input types

20
src/trait_manager/index.js

@ -1,9 +1,10 @@
import { defaults } from 'underscore';
import { defaults, isElement } from 'underscore';
const defaultOpts = require('./config/config');
const TraitsView = require('./view/TraitsView');
module.exports = () => {
let c = {};
const defaultOpts = require('./config/config');
const TraitsView = require('./view/TraitsView');
let TraitsViewer;
return {
@ -42,6 +43,15 @@ module.exports = () => {
return this;
},
postRender() {
const elTo = this.getConfig().appendTo;
if (elTo) {
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
el.appendChild(this.render());
}
},
/**
*
* Get Traits viewer
@ -68,6 +78,10 @@ module.exports = () => {
*/
getType(name) {
return TraitsViewer.itemsView[name];
},
render() {
return TraitsViewer.render().el;
}
};
};

11
src/trait_manager/view/TraitsView.js

@ -16,10 +16,12 @@ module.exports = DomainViews.extend({
color: TraitColorView
},
initialize(o) {
this.config = o.config || {};
initialize(o = {}) {
const config = o.config || {};
this.config = config;
this.em = o.editor;
this.pfx = this.config.stylePrefix || '';
this.pfx = config.stylePrefix || '';
this.ppfx = config.pStylePrefix || '';
this.className = this.pfx + 'traits';
this.listenTo(this.em, 'change:selectedComponent', this.updatedCollection);
this.updatedCollection();
@ -30,7 +32,8 @@ module.exports = DomainViews.extend({
* @private
*/
updatedCollection() {
this.el.className = this.className;
const ppfx = this.ppfx;
this.el.className = `${this.className} ${ppfx}one-bg ${ppfx}two-color`;
var comp = this.em.get('selectedComponent');
if (comp) {
this.collection = comp.get('traits');

73
src/utils/Resizer.js

@ -1,4 +1,4 @@
import { bindAll, defaults, isFunction } from 'underscore';
import { bindAll, defaults, isFunction, each } from 'underscore';
import { on, off, normalizeFloat } from 'utils/mixins';
var defaultOpts = {
@ -38,6 +38,13 @@ var defaultOpts = {
// from the current focused element (currently used only in SelectComponent)
currentUnit: 1,
// With this option active the mousemove event won't be altered when
// the pointer comes over iframes
silentFrames: 0,
// If true the container of handlers won't be updated
avoidContainerUpdate: 0,
// Handlers
tl: 1, // Top left
tc: 1, // Top center
@ -137,6 +144,17 @@ class Resizer {
this.onEnd = opts.onEnd;
}
/**
* Toggle iframes pointer event
* @param {Boolean} silent If true, iframes will be silented
*/
toggleFrames(silent) {
if (this.opts.silentFrames) {
const frames = document.querySelectorAll('iframe');
each(frames, frame => (frame.style.pointerEvents = silent ? 'none' : ''));
}
}
/**
* Detects if the passed element is a resize handler
* @param {HTMLElement} el
@ -170,11 +188,12 @@ class Resizer {
/**
* Return element position
* @param {HTMLElement} el
* @param {Object} opts Custom options
* @return {Object}
*/
getElementPos(el) {
getElementPos(el, opts = {}) {
var posFetcher = this.posFetcher || '';
return posFetcher ? posFetcher(el) : getBoundingRect(el);
return posFetcher ? posFetcher(el, opts) : getBoundingRect(el);
}
/**
@ -189,15 +208,19 @@ class Resizer {
// Show the handlers
this.el = el;
var unit = 'px';
var rect = this.getElementPos(el);
var container = this.container;
var contStyle = container.style;
contStyle.left = rect.left + unit;
contStyle.top = rect.top + unit;
contStyle.width = rect.width + unit;
contStyle.height = rect.height + unit;
container.style.display = 'block';
const config = this.opts;
const unit = 'px';
const rect = this.getElementPos(el, { target: 'container' });
const container = this.container;
const contStyle = container.style;
if (!config.avoidContainerUpdate) {
contStyle.left = rect.left + unit;
contStyle.top = rect.top + unit;
contStyle.width = rect.width + unit;
contStyle.height = rect.height + unit;
contStyle.display = 'block';
}
on(this.getDocumentEl(), 'mousedown', this.handleMouseDown);
}
@ -220,16 +243,14 @@ class Resizer {
*/
start(e) {
//Right or middel click
if (e.button !== 0) {
return;
}
if (e.button !== 0) return;
e.preventDefault();
e.stopPropagation();
const el = this.el;
const resizer = this;
const config = this.opts || {};
var attrName = 'data-' + config.prefix + 'handler';
var rect = this.getElementPos(el);
var rect = this.getElementPos(el, { target: 'el' });
this.handlerAttr = e.target.getAttribute(attrName);
this.clickedHandler = e.target;
this.startDim = {
@ -256,6 +277,7 @@ class Resizer {
on(doc, 'mouseup', this.stop);
isFunction(this.onStart) &&
this.onStart(e, { docs: doc, config, el, resizer });
this.toggleFrames(1);
this.move(e);
}
@ -307,6 +329,7 @@ class Resizer {
off(doc, 'keydown', this.handleKeyDown);
off(doc, 'mouseup', this.stop);
this.updateRect(1);
this.toggleFrames();
isFunction(this.onEnd) && this.onEnd(e, { docs: doc, config });
}
@ -321,7 +344,7 @@ class Resizer {
const conStyle = this.container.style;
const updateTarget = this.updateTarget;
const selectedHandler = this.getSelectedHandler();
const { unitHeight, unitWidth } = config;
const { unitHeight, unitWidth, keyWidth, keyHeight } = config;
// Use custom updating strategy if requested
if (isFunction(updateTarget)) {
@ -333,16 +356,18 @@ class Resizer {
});
} else {
const elStyle = el.style;
elStyle.width = rect.w + unitWidth;
elStyle.height = rect.h + unitHeight;
elStyle[keyWidth] = rect.w + unitWidth;
elStyle[keyHeight] = rect.h + unitHeight;
}
const unitRect = 'px';
const rectEl = this.getElementPos(el);
conStyle.left = rectEl.left + unitRect;
conStyle.top = rectEl.top + unitRect;
conStyle.width = rectEl.width + unitRect;
conStyle.height = rectEl.height + unitRect;
const rectEl = this.getElementPos(el, { target: 'container' });
if (!config.avoidContainerUpdate) {
conStyle.left = rectEl.left + unitRect;
conStyle.top = rectEl.top + unitRect;
conStyle.width = rectEl.width + unitRect;
conStyle.height = rectEl.height + unitRect;
}
}
/**

17
src/utils/Sorter.js

@ -1,4 +1,4 @@
import { isString } from 'underscore';
import { isString, isFunction } from 'underscore';
import { on, off, matches } from 'utils/mixins';
const $ = Backbone.$;
@ -670,7 +670,6 @@ module.exports = Backbone.View.extend({
const width = rect.width;
const height = rect.height;
//console.log(pos, {top, left});
if (
y < top + off || // near top edge
y > top + height - off || // near bottom edge
@ -719,8 +718,6 @@ module.exports = Backbone.View.extend({
width = el.offsetWidth;
}
//console.log('get dim', top, left, this.canvasRelative);
return [top, left, height, width];
},
@ -918,12 +915,11 @@ module.exports = Backbone.View.extend({
var clsReg = new RegExp('(?:^|\\s)' + this.freezeClass + '(?!\\S)', 'gi');
let src = this.eV;
if (src) {
if (src && this.selectOnEnd) {
var srcModel = this.getSourceModel();
if (srcModel && srcModel.set) {
srcModel.set('status', '');
srcModel.set('status', 'selected');
//this.selectOnEnd && srcModel.set('status', 'selected');
}
}
@ -932,9 +928,7 @@ module.exports = Backbone.View.extend({
}
if (this.plh) this.plh.style.display = 'none';
if (typeof this.onEndMove === 'function') this.onEndMove(created);
if (isFunction(this.onEndMove)) this.onEndMove(created, this);
var dragHelper = this.dragHelper;
if (dragHelper) {
@ -974,7 +968,8 @@ module.exports = Backbone.View.extend({
var opts = { at: index, noIncrement: 1 };
if (!dropContent) {
modelTemp = targetCollection.add({}, { ...opts, avoidStore: 1 });
// Putting `avoidStore` here will make the UndoManager behave wrong
modelTemp = targetCollection.add({}, { ...opts });
if (model) {
modelToDrop = model.collection.remove(model);
@ -988,7 +983,7 @@ module.exports = Backbone.View.extend({
created = targetCollection.add(modelToDrop, opts);
if (!dropContent) {
targetCollection.remove(modelTemp, { avoidStore: 1 });
targetCollection.remove(modelTemp);
} else {
this.dropContent = null;
}

8
test/specs/style_manager/view/PropertyCompositeView.js

@ -89,13 +89,13 @@ module.exports = {
});
it('Input value is empty', () => {
expect(model.getFullValue()).toEqual('0% val2');
expect(model.getFullValue()).toEqual('0 val2');
});
it('Update input on value change', () => {
view.model.set('value', propValue);
// Fetch always values from properties
expect(view.getInputValue()).toEqual('0% val2');
expect(view.getInputValue()).toEqual('0 val2');
});
describe('With target setted', () => {
@ -123,7 +123,7 @@ module.exports = {
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
prop3Val = properties[2].list[2].value;
finalResult = propValue + ' ' + prop2Val + prop2Unit + ' ' + prop3Val;
finalResult = propValue + ' ' + prop2Val + ' ' + prop3Val;
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
@ -151,7 +151,7 @@ module.exports = {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
assertStyle[propName] = propValue + ' 0 val2';
expect(compStyle).toEqual(assertStyle);
});

Loading…
Cancel
Save