Browse Source

Merge branch 'dev' into flexbox-support-dev

pull/1710/head
David Polak 7 years ago
parent
commit
b841f8b07c
  1. 2
      dist/css/grapes.min.css
  2. 30
      docs/api/component.md
  3. 90
      docs/api/components.md
  4. 4
      docs/api/editor.md
  5. 1
      docs/api/style_manager.md
  6. 2
      docs/modules/Components.md
  7. 2
      docs/modules/Style-manager.md
  8. 49
      src/block_manager/index.js
  9. 12
      src/block_manager/view/BlocksView.js
  10. 11
      src/canvas/config/config.js
  11. 24
      src/canvas/index.js
  12. 2
      src/canvas/view/CanvasView.js
  13. 26
      src/commands/view/SelectComponent.js
  14. 78
      src/css_composer/index.js
  15. 3
      src/editor/index.js
  16. 1
      src/editor/model/Editor.js
  17. 22
      src/modal_dialog/index.js
  18. 2
      src/parser/index.js
  19. 2
      src/parser/model/BrowserParserCss.js
  20. 84
      src/selector_manager/index.js
  21. 2
      src/selector_manager/model/Selectors.js
  22. 4
      src/storage_manager/config/config.js
  23. 14
      src/storage_manager/model/RemoteStorage.js
  24. 6
      src/style_manager/model/PropertyFactory.js
  25. 2
      src/styles/scss/_gjs_traits.scss
  26. 9
      src/utils/mixins.js
  27. 114
      test/specs/css_composer/index.js
  28. 60
      test/specs/selector_manager/index.js
  29. 45
      test/specs/storage_manager/model/Models.js
  30. 30
      test/specs/style_manager/model/Models.js

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

30
docs/api/component.md

@ -57,6 +57,24 @@ component.get('tagName');
By default, when `toolbar` property is falsy the editor will add automatically commands like `move`, `delete`, etc. based on its properties. By default, when `toolbar` property is falsy the editor will add automatically commands like `move`, `delete`, etc. based on its properties.
- `components` **Collection<[Component][9]>?** Children components. Default: `null` - `components` **Collection<[Component][9]>?** Children components. Default: `null`
## init
Hook method, called once the model is created
## updated
Hook method, called when the model has been updated (eg. updated some model's property)
### Parameters
- `property` **[String][1]** Property name, if triggered after some property update
- `value` **any** Property value, if triggered after some property update
- `previous` **any** Property previous value, if triggered after some property update
## removed
Hook method, called once the model has been removed
## is ## is
Check component's type Check component's type
@ -74,6 +92,12 @@ component.is('image')
Returns **[Boolean][3]** Returns **[Boolean][3]**
## index
Get the index of the component in the parent collection.
Returns **[Number][10]**
## find ## find
Find inner components by query string. Find inner components by query string.
@ -397,7 +421,7 @@ Returns **this**
Get the DOM element of the component. Get the DOM element of the component.
This works only if the component is already rendered This works only if the component is already rendered
Returns **[HTMLElement][10]** Returns **[HTMLElement][11]**
## getView ## getView
@ -448,4 +472,6 @@ Returns **this**
[9]: #component [9]: #component
[10]: https://developer.mozilla.org/docs/Web/HTML/Element [10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[11]: https://developer.mozilla.org/docs/Web/HTML/Element

90
docs/api/components.md

@ -24,7 +24,10 @@ const domComponents = editor.DomComponents;
- [clear][5] - [clear][5]
- [load][6] - [load][6]
- [store][7] - [store][7]
- [render][8] - [addType][8]
- [getType][9]
- [getTypes][10]
- [render][11]
## load ## load
@ -34,9 +37,9 @@ The fetched data will be added to the collection
### Parameters ### Parameters
- `data` **[Object][9]** Object of data to load (optional, default `''`) - `data` **[Object][12]** Object of data to load (optional, default `''`)
Returns **[Object][9]** Loaded data Returns **[Object][12]** Loaded data
## store ## store
@ -44,9 +47,9 @@ Store components on the selected storage
### Parameters ### Parameters
- `noStore` **[Boolean][10]** If true, won't store - `noStore` **[Boolean][13]** If true, won't store
Returns **[Object][9]** Data to store Returns **[Object][12]** Data to store
## getWrapper ## getWrapper
@ -104,18 +107,18 @@ as 'domComponents.getComponents().add(...)'
### Parameters ### Parameters
- `component` **([Object][9] | Component | [Array][11]<[Object][9]>)** Component/s to add - `component` **([Object][12] | Component | [Array][14]<[Object][12]>)** Component/s to add
- `component.tagName` **[string][12]** Tag name (optional, default `'div'`) - `component.tagName` **[string][15]** Tag name (optional, default `'div'`)
- `component.type` **[string][12]** Type of the component. Available: ''(default), 'text', 'image' (optional, default `''`) - `component.type` **[string][15]** Type of the component. Available: ''(default), 'text', 'image' (optional, default `''`)
- `component.removable` **[boolean][10]** If component is removable (optional, default `true`) - `component.removable` **[boolean][13]** If component is removable (optional, default `true`)
- `component.draggable` **[boolean][10]** If is possible to move the component around the structure (optional, default `true`) - `component.draggable` **[boolean][13]** If is possible to move the component around the structure (optional, default `true`)
- `component.droppable` **[boolean][10]** If is possible to drop inside other components (optional, default `true`) - `component.droppable` **[boolean][13]** If is possible to drop inside other components (optional, default `true`)
- `component.badgable` **[boolean][10]** If the badge is visible when the component is selected (optional, default `true`) - `component.badgable` **[boolean][13]** If the badge is visible when the component is selected (optional, default `true`)
- `component.stylable` **[boolean][10]** If is possible to style component (optional, default `true`) - `component.stylable` **[boolean][13]** If is possible to style component (optional, default `true`)
- `component.copyable` **[boolean][10]** If is possible to copy&paste the component (optional, default `true`) - `component.copyable` **[boolean][13]** If is possible to copy&paste the component (optional, default `true`)
- `component.content` **[string][12]** String inside component (optional, default `''`) - `component.content` **[string][15]** String inside component (optional, default `''`)
- `component.style` **[Object][9]** Style object (optional, default `{}`) - `component.style` **[Object][12]** Style object (optional, default `{}`)
- `component.attributes` **[Object][9]** Attribute object (optional, default `{}`) - `component.attributes` **[Object][12]** Attribute object (optional, default `{}`)
### Examples ### Examples
@ -132,7 +135,7 @@ var comp1 = domComponents.addComponent({
}); });
``` ```
Returns **(Component | [Array][11]<Component>)** Component/s added Returns **(Component | [Array][14]<Component>)** Component/s added
## render ## render
@ -141,7 +144,7 @@ Once the wrapper is rendered, and it's what happens when you init the editor,
the all new components will be added automatically and property changes are all the all new components will be added automatically and property changes are all
updated immediately updated immediately
Returns **[HTMLElement][13]** Returns **[HTMLElement][16]**
## clear ## clear
@ -149,6 +152,35 @@ Remove all components
Returns **this** Returns **this**
## addType
Add new component type.
Read more about this in [Define New Component][17]
### Parameters
- `type` **[string][15]** Component ID
- `methods` **[Object][12]** Component methods
Returns **this**
## getType
Get component type.
Read more about this in [Define New Component][17]
### Parameters
- `type` **[string][15]** Component ID
Returns **[Object][12]** Component type defintion, eg. `{ model: ..., view: ... }`
## getTypes
Return the array of all types
Returns **[Array][14]**
[1]: https://github.com/artf/grapesjs/blob/master/src/dom_components/config/config.js [1]: https://github.com/artf/grapesjs/blob/master/src/dom_components/config/config.js
[2]: #getwrapper [2]: #getwrapper
@ -163,14 +195,22 @@ Returns **this**
[7]: #store [7]: #store
[8]: #render [8]: #addtype
[9]: #gettype
[10]: #gettypes
[11]: #render
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object [13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array [15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String [16]: https://developer.mozilla.org/docs/Web/HTML/Element
[13]: https://developer.mozilla.org/docs/Web/HTML/Element [17]: https://grapesjs.com/docs/modules/Components.html#define-new-component

4
docs/api/editor.md

@ -23,11 +23,11 @@ editor.on('EVENT-NAME', (some, argument) => {
### Components ### Components
- `component:create` - Component is created (only the model, is not yet mounted in the canvas) - `component:create` - Component is created (only the model, is not yet mounted in the canvas), called after the init() method
- `component:mount` - Component is monted to an element and rendered in canvas - `component:mount` - Component is monted to an element and rendered in canvas
- `component:add` - Triggered when a new component is added to the editor, the model is passed as an argument to the callback - `component:add` - Triggered when a new component is added to the editor, the model is passed as an argument to the callback
- `component:remove` - Triggered when a component is removed, the model is passed as an argument to the callback - `component:remove` - Triggered when a component is removed, the model is passed as an argument to the callback
- `component:clone` - Triggered when a new component is added by a clone command, the model is passed as an argument to the callback - `component:clone` - Triggered when a component is cloned, the new model is passed as an argument to the callback
- `component:update` - Triggered when a component is updated (moved, styled, etc.), the model is passed as an argument to the callback - `component:update` - Triggered when a component is updated (moved, styled, etc.), the model is passed as an argument to the callback
- `component:update:{propertyName}` - Listen any property change, the model is passed as an argument to the callback - `component:update:{propertyName}` - Listen any property change, the model is passed as an argument to the callback
- `component:styleUpdate` - Triggered when the style of the component is updated, the model is passed as an argument to the callback - `component:styleUpdate` - Triggered when the style of the component is updated, the model is passed as an argument to the callback

1
docs/api/style_manager.md

@ -29,7 +29,6 @@ const styleManager = editor.StyleManager;
- [removeProperty][9] - [removeProperty][9]
- [getProperties][10] - [getProperties][10]
- [getModelToStyle][11] - [getModelToStyle][11]
- [getModelToStyle][11]
- [addType][12] - [addType][12]
- [getType][13] - [getType][13]
- [getTypes][14] - [getTypes][14]

2
docs/modules/Components.md

@ -398,7 +398,7 @@ editor.on(`component:remove`, model => console.log('Global hook: component:remov
## Components & JS ## Components & JS
If you want to know how to create Components with javascript attached (eg. counters, galleries, slideshows, etc.) check the dedicated page If you want to know how to create Components with javascript attached (eg. counters, galleries, slideshows, etc.) check the dedicated page
[Components & JS](Components-&-JS) [Components & JS](Components-js.html)

2
docs/modules/Style-manager.md

@ -13,7 +13,7 @@ Coming soon
Here you can find all the available built-in properties that you can use inside Style Manager via `buildProps`: Here you can find all the available built-in properties that you can use inside Style Manager via `buildProps`:
`float`, `position`, `text-align`, `display`, `font-family`, `font-weight`, `border`, `border-style`, `border-color`, `border-width`, `box-shadow`, `background-repeat`, `background-position`, `background-attachment`, `background-size`, `transition`, `transition-duration`, `transition-property`, `transition-timing-function`, `top`, `right`, `bottom`, `left`, `margin`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `padding`, `padding-top`, `padding-right`, `padding-bottom`, `padding-left`, `width`, `height`, `min-width`, `min-height`, `max-width`, `max-height`, `font-size`, `letter-spacing`, `line-height`, `text-shadow`, `border-radius`, `border-top-left-radius`, `border-top-right-radius`, `border-bottom-left-radius`, `border-bottom-right-radius`, `perspective`, `transform`, `transform-rotate-x`, `transform-rotate-y`, `transform-rotate-z`, `transform-scale-x`, `transform-scale-y`, `transform-scale-z`, `color`, `background-color`, `background`, `background-image`, `cursor`, `flex-direction`, `flex-wrap`, `justify-content`, `align-items`, `align-content`, `order`, `flex-basis`, `flex-grow`, `flex-shrink`, `align-self` `float`, `position`, `text-align`, `display`, `font-family`, `font-weight`, `border`, `border-style`, `border-color`, `border-width`, `box-shadow`, `background-repeat`, `background-position`, `background-attachment`, `background-size`, `transition`, `transition-duration`, `transition-property`, `transition-timing-function`, `top`, `right`, `bottom`, `left`, `margin`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `padding`, `padding-top`, `padding-right`, `padding-bottom`, `padding-left`, `width`, `height`, `min-width`, `min-height`, `max-width`, `max-height`, `font-size`, `letter-spacing`, `line-height`, `text-shadow`, `border-radius`, `border-top-left-radius`, `border-top-right-radius`, `border-bottom-left-radius`, `border-bottom-right-radius`, `perspective`, `transform`, `transform-rotate-x`, `transform-rotate-y`, `transform-rotate-z`, `transform-scale-x`, `transform-scale-y`, `transform-scale-z`, `color`, `background-color`, `background`, `background-image`, `cursor`, `flex-direction`, `flex-wrap`, `justify-content`, `align-items`, `align-content`, `order`, `flex-basis`, `flex-grow`, `flex-shrink`, `align-self`, `overflow`, `overflow-x`, `overflow-y`
Example usage: Example usage:
```js ```js

49
src/block_manager/index.js

@ -63,15 +63,14 @@ module.exports = () => {
// Global blocks collection // Global blocks collection
blocks = new Blocks([]); blocks = new Blocks([]);
blocksVisible = new Blocks([]); blocksVisible = new Blocks([]);
(categories = new BlockCategories()), categories = new BlockCategories();
(blocksView = new BlocksView( blocksView = new BlocksView(
{ {
// Visible collection collection: blocksVisible,
collection: blocksVisible, categories
categories },
}, c
c );
));
// Setup the sync between the global and public collections // Setup the sync between the global and public collections
blocks.listenTo(blocks, 'add', model => { blocks.listenTo(blocks, 'add', model => {
@ -205,8 +204,10 @@ module.exports = () => {
/** /**
* Render blocks * Render blocks
* @param {Array} blocks Blocks to render, without the argument will render * @param {Array} blocks Blocks to render, without the argument will render all global blocks
* all global blocks * @param {Object} [opts={}] Options
* @param {Boolean} [opts.external] Render blocks in a new container (HTMLElement will be returned)
* @param {Boolean} [opts.ignoreCategories] Render blocks without categories
* @return {HTMLElement} Rendered element * @return {HTMLElement} Rendered element
* @example * @example
* // Render all blocks (inside the global collection) * // Render all blocks (inside the global collection)
@ -214,9 +215,9 @@ module.exports = () => {
* *
* // Render new set of blocks * // Render new set of blocks
* const blocks = blockManager.getAll(); * const blocks = blockManager.getAll();
* blockManager.render(blocks.filter( * const filtered = blocks.filter(block => block.get('category') == 'sections')
* block => block.get('category') == 'sections' *
* )); * blockManager.render(filtered);
* // Or a new set from an array * // Or a new set from an array
* blockManager.render([ * blockManager.render([
* {label: 'Label text', content: '<div>Content</div>'} * {label: 'Label text', content: '<div>Content</div>'}
@ -224,15 +225,33 @@ module.exports = () => {
* *
* // Back to blocks from the global collection * // Back to blocks from the global collection
* blockManager.render(); * blockManager.render();
*
* // You can also render your blocks outside of the main block container
* const newBlocksEl = blockManager.render(filtered, { external: true });
* document.getElementById('some-id').appendChild(newBlocksEl);
*/ */
render(blocks) { render(blocks, opts = {}) {
const toRender = blocks || this.getAll().models; const toRender = blocks || this.getAll().models;
if (opts.external) {
return new BlocksView(
{
collection: new Blocks(toRender),
categories
},
{
...c,
...opts
}
).render().el;
}
if (!blocksView.rendered) { if (!blocksView.rendered) {
blocksView.render(); blocksView.render();
blocksView.rendered = 1; blocksView.rendered = 1;
} }
blocksView.updateConfig(opts);
blocksView.collection.reset(toRender); blocksView.collection.reset(toRender);
return this.getContainer(); return this.getContainer();
} }

12
src/block_manager/view/BlocksView.js

@ -27,6 +27,13 @@ module.exports = require('backbone').View.extend({
} }
}, },
updateConfig(opts = {}) {
this.config = {
...this.config,
...opts
};
},
/** /**
* Get sorter * Get sorter
* @private * @private
@ -103,19 +110,20 @@ module.exports = require('backbone').View.extend({
* @private * @private
* */ * */
add(model, fragment) { add(model, fragment) {
const { config } = this;
var frag = fragment || null; var frag = fragment || null;
var view = new BlockView( var view = new BlockView(
{ {
model, model,
attributes: model.get('attributes') attributes: model.get('attributes')
}, },
this.config config
); );
var rendered = view.render().el; var rendered = view.render().el;
var category = model.get('category'); var category = model.get('category');
// Check for categories // Check for categories
if (category && this.categories) { if (category && this.categories && !config.ignoreCategories) {
if (isString(category)) { if (isString(category)) {
category = { category = {
id: category, id: category,

11
src/canvas/config/config.js

@ -6,7 +6,7 @@ module.exports = {
* Be aware that these scripts will not be printed in the export code * Be aware that these scripts will not be printed in the export code
* @example * @example
* scripts: [ 'https://...1.js', 'https://...2.js' ] * scripts: [ 'https://...1.js', 'https://...2.js' ]
*/ */
scripts: [], scripts: [],
/* /*
@ -14,7 +14,7 @@ module.exports = {
* Be aware that these styles will not be printed in the export code * Be aware that these styles will not be printed in the export code
* @example * @example
* styles: [ 'https://...1.css', 'https://...2.css' ] * styles: [ 'https://...1.css', 'https://...2.css' ]
*/ */
styles: [], styles: [],
/** /**
@ -26,10 +26,15 @@ module.exports = {
*/ */
customBadgeLabel: '', customBadgeLabel: '',
/**
* Indicate when to start the auto scroll of the canvas on component/block dragging (value in px )
*/
autoscrollLimit: 50,
/** /**
* When some textable component is selected and focused (eg. input or text component) the editor * When some textable component is selected and focused (eg. input or text component) the editor
* stops some commands (eg. disables the copy/paste of components with CTRL+C/V to allow the copy/paste of the text). * stops some commands (eg. disables the copy/paste of components with CTRL+C/V to allow the copy/paste of the text).
* This option allows to customize, by a selector, which element should not be considered textable * This option allows to customize, by a selector, which element should not be considered textable
*/ */
notTextable: ['button', 'input[type=checkbox]', 'input[type=radio]'] notTextable: ['button', 'a', 'input[type=checkbox]', 'input[type=radio]']
}; };

24
src/canvas/index.js

@ -28,9 +28,11 @@
* @module Canvas * @module Canvas
*/ */
import { on, off, hasDnd, getElement } from 'utils/mixins'; import { on, off, hasDnd, getElement, getPointerEvent } from 'utils/mixins';
import Droppable from 'utils/Droppable'; import Droppable from 'utils/Droppable';
const { requestAnimationFrame } = window;
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
@ -81,6 +83,7 @@ module.exports = () => {
this.startAutoscroll = this.startAutoscroll.bind(this); this.startAutoscroll = this.startAutoscroll.bind(this);
this.stopAutoscroll = this.stopAutoscroll.bind(this); this.stopAutoscroll = this.stopAutoscroll.bind(this);
this.autoscroll = this.autoscroll.bind(this); this.autoscroll = this.autoscroll.bind(this);
this.updateClientY = this.updateClientY.bind(this);
return this; return this;
}, },
@ -452,22 +455,27 @@ module.exports = () => {
// By detaching those from the stack avoid browsers lags // By detaching those from the stack avoid browsers lags
// Noticeable with "fast" drag of blocks // Noticeable with "fast" drag of blocks
setTimeout(() => { setTimeout(() => {
on(toListen, 'mousemove', this.autoscroll); on(toListen, 'mousemove dragover', this.updateClientY);
on(toListen, 'mouseup', this.stopAutoscroll); on(toListen, 'mouseup', this.stopAutoscroll);
requestAnimationFrame(this.autoscroll);
}, 0); }, 0);
}, },
updateClientY(ev) {
ev.preventDefault();
this.lastClientY = getPointerEvent(ev).clientY;
},
/** /**
* @private * @private
*/ */
autoscroll(e) { autoscroll() {
e.preventDefault();
if (this.dragging) { if (this.dragging) {
let frameWindow = this.getFrameEl().contentWindow; let frameWindow = this.getFrameEl().contentWindow;
let actualTop = frameWindow.document.body.scrollTop; let actualTop = frameWindow.document.body.scrollTop;
let nextTop = actualTop; let nextTop = actualTop;
let clientY = e.clientY; let clientY = this.lastClientY;
let limitTop = 50; let limitTop = this.getConfig().autoscrollLimit;
let limitBottom = frameRect.height - limitTop; let limitBottom = frameRect.height - limitTop;
if (clientY < limitTop) { if (clientY < limitTop) {
@ -478,8 +486,8 @@ module.exports = () => {
nextTop += clientY - limitBottom; nextTop += clientY - limitBottom;
} }
//console.log(`actualTop: ${actualTop} clientY: ${clientY} nextTop: ${nextTop} frameHeigh: ${frameRect.height}`);
frameWindow.scrollTo(0, nextTop); frameWindow.scrollTo(0, nextTop);
requestAnimationFrame(this.autoscroll);
} }
}, },
@ -490,7 +498,7 @@ module.exports = () => {
stopAutoscroll() { stopAutoscroll() {
this.dragging = 0; this.dragging = 0;
let toListen = this.getScrollListeners(); let toListen = this.getScrollListeners();
off(toListen, 'mousemove', this.autoscroll); off(toListen, 'mousemove dragover', this.updateClientY);
off(toListen, 'mouseup', this.stopAutoscroll); off(toListen, 'mouseup', this.stopAutoscroll);
}, },

2
src/canvas/view/CanvasView.js

@ -25,7 +25,7 @@ module.exports = Backbone.View.extend({
*/ */
isElInViewport(el) { isElInViewport(el) {
const rect = getElement(el).getBoundingClientRect(); const rect = getElement(el).getBoundingClientRect();
const frameRect = this.getFrameOffset(1); const frameRect = this.getFrameOffset();
const rTop = rect.top; const rTop = rect.top;
const rLeft = rect.left; const rLeft = rect.left;
return ( return (

26
src/commands/view/SelectComponent.js

@ -527,15 +527,33 @@ module.exports = {
* @param {Object} pos * @param {Object} pos
*/ */
updateToolbarPos(el, elPos) { updateToolbarPos(el, elPos) {
var unit = 'px'; const { canvas } = this;
var toolbarEl = this.canvas.getToolbarEl(); const unit = 'px';
var toolbarStyle = toolbarEl.style; const toolbarEl = canvas.getToolbarEl();
const toolbarStyle = toolbarEl.style;
toolbarStyle.opacity = 0; toolbarStyle.opacity = 0;
var pos = this.canvas.getTargetToElementDim(toolbarEl, el, { const pos = canvas.getTargetToElementDim(toolbarEl, el, {
elPos, elPos,
event: 'toolbarPosUpdate' event: 'toolbarPosUpdate'
}); });
if (pos) { if (pos) {
const frameOffset = canvas.getCanvasView().getFrameOffset();
// Scroll with the window if the top edge is reached and the
// element is bigger than the canvas
if (
pos.top <= pos.canvasTop &&
!(pos.elementHeight + pos.targetHeight >= frameOffset.height)
) {
pos.top = pos.elementTop + pos.elementHeight;
}
// Check if not outside of the canvas
if (pos.left < pos.canvasLeft) {
pos.left = pos.canvasLeft;
}
var leftPos = pos.left + pos.elementWidth - pos.targetWidth; var leftPos = pos.left + pos.elementWidth - pos.targetWidth;
toolbarStyle.top = pos.top + unit; toolbarStyle.top = pos.top + unit;
toolbarStyle.left = (leftPos < 0 ? 0 : leftPos) + unit; toolbarStyle.left = (leftPos < 0 ? 0 : leftPos) + unit;

78
src/css_composer/index.js

@ -21,10 +21,8 @@
* * [get](#get) * * [get](#get)
* * [getAll](#getall) * * [getAll](#getall)
* * [clear](#clear) * * [clear](#clear)
* * [setIdRule](#setidrule) * * [setRule](#setrule)
* * [getIdRule](#getidrule) * * [getRule](#getrule)
* * [setClassRule](#setclassrule)
* * [getClassRule](#getclassrule)
* *
* @module CssComposer * @module CssComposer
*/ */
@ -304,12 +302,81 @@ module.exports = () => {
return result; return result;
}, },
/**
* Add/update the CSS rule with a generic selector
* @param {string} selectors Selector, eg. '.myclass'
* @param {Object} style Style properties and values
* @param {Object} [opts={}] Additional properties
* @param {String} [opts.atRuleType=''] At-rule type, eg. 'media'
* @param {String} [opts.atRuleParams=''] At-rule parameters, eg. '(min-width: 500px)'
* @return {CssRule} The new/updated rule
* @example
* // Simple class-based rule
* const rule = cc.setRule('.class1.class2', { color: 'red' });
* console.log(rule.toCSS()) // output: .class1.class2 { color: red }
* // With state and other mixed selector
* const rule = cc.setRule('.class1.class2:hover, div#myid', { color: 'red' });
* // output: .class1.class2:hover, div#myid { color: red }
* // With media
* const rule = cc.setRule('.class1:hover', { color: 'red' }, {
* atRuleType: 'media',
* atRuleParams: '(min-width: 500px)',
* });
* // output: @media (min-width: 500px) { .class1:hover { color: red } }
*/
setRule(selectors, style, opts = {}) {
const { atRuleType, atRuleParams } = opts;
const node = em.get('Parser').parserCss.checkNode({
selectors,
style
})[0];
const { state, selectorsAdd } = node;
const sm = em.get('SelectorManager');
const selector = sm.add(node.selectors);
const rule = this.add(selector, state, atRuleParams, {
selectorsAdd,
atRule: atRuleType
});
rule.setStyle(style, opts);
return rule;
},
/**
* Get the CSS rule by a generic selector
* @param {string} selectors Selector, eg. '.myclass:hover'
* @param {String} [opts.atRuleType=''] At-rule type, eg. 'media'
* @param {String} [opts.atRuleParams=''] At-rule parameters, eg. '(min-width: 500px)'
* @return {CssRule}
* @example
* const rule = cc.getRule('.myclass1:hover');
* const rule2 = cc.getRule('.myclass1:hover, div#myid');
* const rule3 = cc.getRule('.myclass1', {
* atRuleType: 'media',
* atRuleParams: '(min-width: 500px)',
* });
*/
getRule(selectors, opts = {}) {
const sm = em.get('SelectorManager');
const node = em.get('Parser').parserCss.checkNode({ selectors })[0];
const selector = sm.get(node.selectors);
const { state, selectorsAdd } = node;
const { atRuleType, atRuleParams } = opts;
return (
selector &&
this.get(selector, state, atRuleParams, {
selectorsAdd,
atRule: atRuleType
})
);
},
/** /**
* Add/update the CSS rule with id selector * Add/update the CSS rule with id selector
* @param {string} name Id selector name, eg. 'my-id' * @param {string} name Id selector name, eg. 'my-id'
* @param {Object} style Style properties and values * @param {Object} style Style properties and values
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule * @return {CssRule} The new/updated rule
* @private
* @example * @example
* const rule = cc.setIdRule('myid', { color: 'red' }); * const rule = cc.setIdRule('myid', { color: 'red' });
* const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' }); * const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' });
@ -332,6 +399,7 @@ module.exports = () => {
* @param {string} name Id selector name, eg. 'my-id' * @param {string} name Id selector name, eg. 'my-id'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} * @return {CssRule}
* @private
* @example * @example
* const rule = cc.getIdRule('myid'); * const rule = cc.getIdRule('myid');
* const ruleHover = cc.setIdRule('myid', { state: 'hover' }); * const ruleHover = cc.setIdRule('myid', { state: 'hover' });
@ -349,6 +417,7 @@ module.exports = () => {
* @param {Object} style Style properties and values * @param {Object} style Style properties and values
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule * @return {CssRule} The new/updated rule
* @private
* @example * @example
* const rule = cc.setClassRule('myclass', { color: 'red' }); * const rule = cc.setClassRule('myclass', { color: 'red' });
* const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' }); * const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' });
@ -371,6 +440,7 @@ module.exports = () => {
* @param {string} name Class selector name, eg. 'my-class' * @param {string} name Class selector name, eg. 'my-class'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} * @return {CssRule}
* @private
* @example * @example
* const rule = cc.getClassRule('myclass'); * const rule = cc.getClassRule('myclass');
* const ruleHover = cc.getClassRule('myclass', { state: 'hover' }); * const ruleHover = cc.getClassRule('myclass', { state: 'hover' });

3
src/editor/index.js

@ -76,6 +76,9 @@
* ### RTE * ### RTE
* * `rte:enable` - RTE enabled. The view, on which RTE is enabled, is passed as an argument * * `rte:enable` - RTE enabled. The view, on which RTE is enabled, is passed as an argument
* * `rte:disable` - RTE disabled. The view, on which RTE is disabled, is passed as an argument * * `rte:disable` - RTE disabled. The view, on which RTE is disabled, is passed as an argument
* ### Modal
* * `modal:open` - Modal is opened
* * `modal:close` - Modal is closed
* ### Commands * ### Commands
* * `run:{commandName}` - Triggered when some command is called to run (eg. editor.runCommand('preview')) * * `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')) * * `stop:{commandName}` - Triggered when some command is called to stop (eg. editor.stopCommand('preview'))

1
src/editor/model/Editor.js

@ -563,6 +563,7 @@ module.exports = Backbone.Model.extend({
* @private * @private
*/ */
refreshCanvas() { refreshCanvas() {
this.set('canvasOffset', null);
this.set('canvasOffset', this.get('Canvas').getOffset()); this.set('canvasOffset', this.get('Canvas').getOffset());
}, },

22
src/modal_dialog/index.js

@ -40,17 +40,22 @@ module.exports = () => {
*/ */
name: 'Modal', name: 'Modal',
getConfig() {
return c;
},
/** /**
* Initialize module. Automatically called with a new instance of the editor * Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations * @param {Object} config Configurations
* @private * @private
*/ */
init(config) { init(config = {}) {
c = config || {}; c = {
for (var name in defaults) { ...defaults,
if (!(name in c)) c[name] = defaults[name]; ...config
} };
this.em = c.em;
var ppfx = c.pStylePrefix; var ppfx = c.pStylePrefix;
if (ppfx) c.stylePrefix = ppfx + c.stylePrefix; if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
@ -68,6 +73,11 @@ module.exports = () => {
this.render().appendTo(el); this.render().appendTo(el);
}, },
triggerEvent(event) {
const { em } = this;
em && em.trigger(`modal:${event}`);
},
/** /**
* Open the modal window * Open the modal window
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
@ -79,6 +89,7 @@ module.exports = () => {
opts.title && this.setTitle(opts.title); opts.title && this.setTitle(opts.title);
opts.content && this.setContent(opts.content); opts.content && this.setContent(opts.content);
modal.show(); modal.show();
this.triggerEvent('open');
return this; return this;
}, },
@ -88,6 +99,7 @@ module.exports = () => {
*/ */
close() { close() {
modal.hide(); modal.hide();
this.triggerEvent('close');
return this; return this;
}, },

2
src/parser/index.js

@ -48,6 +48,8 @@ module.exports = () => {
pHtml = new parserHtml(conf); pHtml = new parserHtml(conf);
pCss = new parserCss(conf); pCss = new parserCss(conf);
this.em = conf.em; this.em = conf.em;
this.parserCss = pCss;
this.parserHtml = pHtml;
return this; return this;
}, },

2
src/parser/model/BrowserParserCss.js

@ -101,7 +101,7 @@ export const parseCondition = node => {
* @param {Object} style Key-value object of style declarations * @param {Object} style Key-value object of style declarations
* @return {Object} * @return {Object}
*/ */
export const createNode = (selectors, style, opts = {}) => { export const createNode = (selectors, style = {}, opts = {}) => {
const node = {}; const node = {};
const selLen = selectors.length; const selLen = selectors.length;
const lastClass = selectors[selLen - 1]; const lastClass = selectors[selLen - 1];

84
src/selector_manager/index.js

@ -44,7 +44,7 @@
* @module SelectorManager * @module SelectorManager
*/ */
import { isString, isElement, isObject } from 'underscore'; import { isString, isElement, isObject, isArray } from 'underscore';
const isId = str => isString(str) && str[0] == '#'; const isId = str => isString(str) && str[0] == '#';
const isClass = str => isString(str) && str[0] == '.'; const isClass = str => isString(str) && str[0] == '.';
@ -118,22 +118,9 @@ module.exports = config => {
} }
}, },
/** addSelector(name, opt = {}) {
* Add a new selector to collection if it's not already exists. Class type is a default one let opts = { ...opt };
* @param {String} name Selector name
* @param {Object} opts Selector options
* @param {String} [opts.label=''] Label for the selector, if it's not provided the label will be the same as the name
* @param {String} [opts.type=1] Type of the selector. At the moment, only 'class' (1) is available
* @return {Model}
* @example
* var selector = selectorManager.add('selectorName');
* // Same as
* var selector = selectorManager.add('selectorName', {
* type: 1,
* label: 'selectorName'
* });
* */
add(name, opts = {}) {
if (isObject(name)) { if (isObject(name)) {
opts = name; opts = name;
} else { } else {
@ -143,6 +130,8 @@ module.exports = config => {
if (isId(opts.name)) { if (isId(opts.name)) {
opts.name = opts.name.substr(1); opts.name = opts.name.substr(1);
opts.type = Selector.TYPE_ID; opts.type = Selector.TYPE_ID;
} else if (isClass(opts.name)) {
opts.name = opts.name.substr(1);
} }
if (opts.label && !opts.name) { if (opts.label && !opts.name) {
@ -161,6 +150,42 @@ module.exports = config => {
return selector; return selector;
}, },
getSelector(name, type = Selector.TYPE_CLASS) {
if (isId(name)) {
name = name.substr(1);
type = Selector.TYPE_ID;
} else if (isClass(name)) {
name = name.substr(1);
}
return selectors.where({ name, type })[0];
},
/**
* Add a new selector to collection if it's not already exists. Class type is a default one
* @param {String|Array} name Selector/s name
* @param {Object} opts Selector options
* @param {String} [opts.label=''] Label for the selector, if it's not provided the label will be the same as the name
* @param {String} [opts.type=1] Type of the selector. At the moment, only 'class' (1) is available
* @return {Model|Array}
* @example
* const selector = selectorManager.add('selectorName');
* // Same as
* const selector = selectorManager.add('selectorName', {
* type: 1,
* label: 'selectorName'
* });
* // Multiple selectors
* const selectors = selectorManager.add(['.class1', '.class2', '#id1']);
* */
add(name, opts = {}) {
if (isArray(name)) {
return name.map(item => this.addSelector(item, opts));
} else {
return this.addSelector(name, opts);
}
},
/** /**
* Add class selectors * Add class selectors
* @param {Array|string} classes Array or string of classes * @param {Array|string} classes Array or string of classes
@ -184,18 +209,27 @@ module.exports = config => {
/** /**
* Get the selector by its name * Get the selector by its name
* @param {String} name Selector name * @param {String|Array} name Selector name
* @param {String} tyoe Selector type * @param {String} tyoe Selector type
* @return {Model|null} * @return {Model|Array}
* @example * @example
* var selector = selectorManager.get('selectorName'); * const selector = selectorManager.get('selectorName');
* // or get an array
* const selectors = selectorManager.get(['class1', 'class2']);
* */ * */
get(name, type = Selector.TYPE_CLASS) { get(name, type) {
if (isId(name)) { if (isArray(name)) {
name = name.substr(1); const result = [];
type = Selector.TYPE_ID; const selectors = name
.map(item => this.getSelector(item))
.filter(item => item);
selectors.forEach(
item => result.indexOf(item) < 0 && result.push(item)
);
return result;
} else {
return this.getSelector(name, type);
} }
return selectors.where({ name, type })[0];
}, },
/** /**

2
src/selector_manager/model/Selectors.js

@ -4,6 +4,8 @@ const Selector = require('./Selector');
module.exports = require('backbone').Collection.extend({ module.exports = require('backbone').Collection.extend({
model: Selector, model: Selector,
modelId: attr => `${attr.name}_${attr.type || Selector.TYPE_CLASS}`,
getStyleable() { getStyleable() {
return filter( return filter(
this.models, this.models,

4
src/storage_manager/config/config.js

@ -53,5 +53,7 @@ module.exports = {
// set contentType paramater of $.ajax // set contentType paramater of $.ajax
// true: application/json; charset=utf-8' // true: application/json; charset=utf-8'
// false: 'x-www-form-urlencoded' // false: 'x-www-form-urlencoded'
contentTypeJson: false contentTypeJson: false,
credentials: 'include'
}; };

14
src/storage_manager/model/RemoteStorage.js

@ -10,7 +10,8 @@ module.exports = require('backbone').Model.extend({
params: {}, params: {},
beforeSend() {}, beforeSend() {},
onComplete() {}, onComplete() {},
contentTypeJson: false contentTypeJson: false,
credentials: 'include'
}, },
/** /**
@ -113,7 +114,7 @@ module.exports = require('backbone').Model.extend({
} }
fetchOptions = { fetchOptions = {
method: opts.method || 'post', method: opts.method || 'post',
credentials: 'include', credentials: this.get('credentials'),
headers headers
}; };
@ -124,11 +125,10 @@ module.exports = require('backbone').Model.extend({
this.onStart(); this.onStart();
this.fetch(url, fetchOptions) this.fetch(url, fetchOptions)
.then( .then(res =>
res => ((res.status / 200) | 0) == 1
((res.status / 200) | 0) == 1 ? res.text()
? res.text() : res.text().then(text => Promise.reject(text))
: res.text().then(text => Promise.reject(text))
) )
.then(text => this.onResponse(text, clb)) .then(text => this.onResponse(text, clb))
.catch(err => this.onError(err, clbErr)); .catch(err => this.onError(err, clbErr));

6
src/style_manager/model/PropertyFactory.js

@ -91,6 +91,8 @@ module.exports = () => ({
case 'transition-timing-function': case 'transition-timing-function':
case 'cursor': case 'cursor':
case 'overflow': case 'overflow':
case 'overflow-x':
case 'overflow-y':
obj.type = 'select'; obj.type = 'select';
break; break;
case 'top': case 'top':
@ -299,6 +301,8 @@ module.exports = () => ({
obj.defaults = 'ease'; obj.defaults = 'ease';
break; break;
case 'overflow': case 'overflow':
case 'overflow-x':
case 'overflow-y':
obj.defaults = 'visible'; obj.defaults = 'visible';
break; break;
} }
@ -668,6 +672,8 @@ module.exports = () => ({
]; ];
break; break;
case 'overflow': case 'overflow':
case 'overflow-x':
case 'overflow-y':
obj.list = [ obj.list = [
{ value: 'visible' }, { value: 'visible' },
{ value: 'hidden' }, { value: 'hidden' },

2
src/styles/scss/_gjs_traits.scss

@ -15,7 +15,7 @@
.#{$trt-prefix}trait { .#{$trt-prefix}trait {
display: flex; display: flex;
justify-content: start; justify-content: flex-start;
padding: 5px 10px; padding: 5px 10px;
font-weight: lighter; font-weight: lighter;

9
src/utils/mixins.js

@ -121,6 +121,14 @@ const getModel = (el, $) => {
return model; return model;
}; };
/**
* Get cross-device pointer event
* @param {Event} ev
* @return {Event}
*/
const getPointerEvent = ev =>
ev.touches && ev.touches[0] ? ev.touches[0] : ev;
export { export {
on, on,
off, off,
@ -132,5 +140,6 @@ export {
getElement, getElement,
shallowDiff, shallowDiff,
normalizeFloat, normalizeFloat,
getPointerEvent,
getUnitFromValue getUnitFromValue
}; };

114
test/specs/css_composer/index.js

@ -207,6 +207,120 @@ describe('Css Composer', () => {
const rule = obj.getClassRule(name, { state }); const rule = obj.getClassRule(name, { state });
expect(rule.selectorsToString()).toEqual(`.${name}:${state}`); expect(rule.selectorsToString()).toEqual(`.${name}:${state}`);
}); });
test('Create a simple class-based rule with setRule', () => {
const selector = '.test';
const result = obj.setRule(selector, { color: 'red' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:red;`);
});
test('Avoid creating multiple rules with the same selector', () => {
const selector = '.test';
obj.setRule(selector, { color: 'red' });
obj.setRule(selector, { color: 'blue' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:blue;`);
});
test('Create a class-based rule with setRule', () => {
const selector = '.test.test2';
const result = obj.setRule(selector, { color: 'red' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:red;`);
});
test('Create a class-based rule with a state, by using setRule', () => {
const selector = '.test.test2:hover';
const result = obj.setRule(selector, { color: 'red' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:red;`);
});
test('Create a rule with class-based and mixed selectors', () => {
const selector = '.test.test2:hover, #test .selector';
obj.setRule(selector, { color: 'red' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:red;`);
});
test('Create a rule with only mixed selectors', () => {
const selector = '#test1 .class1, .class2 > #id2';
obj.setRule(selector, { color: 'red' });
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector);
expect(rule.get('selectors').length).toEqual(0);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.styleToString()).toEqual(`color:red;`);
});
test('Create a rule with atRule', () => {
const toTest = [
{
selector: '.class1:hover',
style: { color: 'blue' },
opts: {
atRuleType: 'media',
atRuleParams: 'screen and (min-width: 480px)'
}
},
{
selector: '.class1:hover',
style: { color: 'red' },
opts: {
atRuleType: 'media',
atRuleParams: 'screen and (min-width: 480px)'
}
}
];
toTest.forEach(test => {
const { selector, style, opts } = test;
const result = obj.setRule(selector, style, opts);
expect(obj.getAll().length).toEqual(1);
const rule = obj.getRule(selector, opts);
expect(rule.getAtRule()).toEqual(
`@${opts.atRuleType} ${opts.atRuleParams}`
);
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.getStyle()).toEqual(style);
});
});
test('Create different rules by using setRule', () => {
const toTest = [
{ selector: '.class1:hover', style: { color: '#111' } },
{ selector: '.class1.class2', style: { color: '#222' } },
{ selector: '.class1, .class2 .class3', style: { color: 'red' } },
{ selector: '.class1, .class2 .class4', style: { color: 'green' } },
{ selector: '.class4, .class1 .class2', style: { color: 'blue' } },
{
selector: '.class4, .class1 .class2',
style: { color: 'blue' },
opt: { atRuleType: 'media', atRuleParams: '(min-width: 480px)' }
}
];
toTest.forEach(test => {
const { selector, style, opt = {} } = test;
obj.setRule(selector, style, opt);
const rule = obj.getRule(selector, opt);
const atRule = `${opt.atRuleType || ''} ${opt.atRuleParams ||
''}`.trim();
expect(rule.getAtRule()).toEqual(atRule ? `@${atRule}` : '');
expect(rule.selectorsToString()).toEqual(selector);
expect(rule.getStyle()).toEqual(style);
});
expect(obj.getAll().length).toEqual(toTest.length);
});
}); });
Models.run(); Models.run();

60
test/specs/selector_manager/index.js

@ -60,6 +60,13 @@ describe('SelectorManager', () => {
expect(sel.get('label')).toEqual(name); expect(sel.get('label')).toEqual(name);
}); });
test('Check name property by adding as class', () => {
var name = 'test';
var sel = obj.add(`.${name}`);
expect(sel.get('name')).toEqual(name);
expect(sel.get('label')).toEqual(name);
});
test('Add 2 selectors', () => { test('Add 2 selectors', () => {
obj.add('test'); obj.add('test');
obj.add('test2'); obj.add('test2');
@ -72,6 +79,59 @@ describe('SelectorManager', () => {
expect(obj.getAll().length).toEqual(1); expect(obj.getAll().length).toEqual(1);
}); });
test('Add multiple selectors', () => {
const cls = [
'.test1',
'test1',
'.test2',
'.test2',
'#test3',
'test3',
'test3',
'#test3'
];
const result = obj.add(cls);
expect(Array.isArray(result)).toEqual(true);
const concat = obj
.getAll()
.map(item => item.getFullName())
.join('');
expect(concat).toEqual('.test1.test2#test3.test3');
expect(obj.getAll().length).toEqual(4);
expect(
obj
.getAll()
.at(0)
.getFullName()
).toEqual('.test1');
expect(
obj
.getAll()
.at(1)
.getFullName()
).toEqual('.test2');
expect(
obj
.getAll()
.at(2)
.getFullName()
).toEqual('#test3');
expect(
obj
.getAll()
.at(3)
.getFullName()
).toEqual('.test3');
expect(obj.get(cls).length).toEqual(4);
expect(
obj
.get(cls)
.map(item => item.getFullName())
.join('')
).toEqual(concat);
});
test('Get selector', () => { test('Get selector', () => {
var name = 'test'; var name = 'test';
var sel = obj.add(name); var sel = obj.add(name);

45
test/specs/storage_manager/model/Models.js

@ -96,6 +96,51 @@ module.exports = {
expect(callResult.called).toEqual(true); expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[0]).toEqual(endpointLoad); expect(callResult.firstCall.args[0]).toEqual(endpointLoad);
}); });
test("Load data with credentials option as 'include' by default", () => {
obj.load(['item1', 'item2']);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[1]).toMatchObject({
credentials: 'include'
});
});
test("Store data with credentials option as 'include' by default", () => {
obj.store(data);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[1]).toMatchObject({
credentials: 'include'
});
});
test('Store data with credentials option as false ', () => {
obj = new RemoteStorage({ ...storageOptions, credentials: false });
sinon
.stub(obj, 'fetch')
.returns(Promise.resolve(mockResponse({ data: 1 })));
obj.store(data);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[1]).toMatchObject({
credentials: false
});
});
test('Load data with credentials option as false', () => {
obj = new RemoteStorage({ ...storageOptions, credentials: false });
sinon
.stub(obj, 'fetch')
.returns(Promise.resolve(mockResponse({ data: 1 })));
obj.load(['item1', 'item2']);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[1]).toMatchObject({
credentials: false
});
});
}); });
} }
}; };

30
test/specs/style_manager/model/Models.js

@ -1155,6 +1155,36 @@ module.exports = {
}; };
expect(obj.build('overflow')).toEqual([res]); expect(obj.build('overflow')).toEqual([res]);
}); });
test('Build overflow-x', () => {
var res = {
type: 'select',
property: 'overflow-x',
defaults: 'visible',
list: [
{ value: 'visible' },
{ value: 'hidden' },
{ value: 'scroll' },
{ value: 'auto' }
]
};
expect(obj.build('overflow-x')).toEqual([res]);
});
test('Build overflow-y', () => {
var res = {
type: 'select',
property: 'overflow-y',
defaults: 'visible',
list: [
{ value: 'visible' },
{ value: 'hidden' },
{ value: 'scroll' },
{ value: 'auto' }
]
};
expect(obj.build('overflow-y')).toEqual([res]);
});
}); });
} }
}; };

Loading…
Cancel
Save