From a18a8bd22949dc9c43cd45ac55983f6229fc40b2 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Mon, 13 Aug 2018 14:12:15 +0200 Subject: [PATCH] Added Component API in documentation --- docs/.vuepress/config.js | 1 + docs/README.md | 7 + docs/api.js | 1 + docs/api/component.md | 413 ++++++++++++++++++++++++++ src/dom_components/model/Component.js | 309 ++++++++++--------- 5 files changed, 587 insertions(+), 144 deletions(-) create mode 100644 docs/api/component.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index dbc72e320..774deebb3 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -63,6 +63,7 @@ module.exports = { ['/api/block_manager', 'Block Manager'], ['/api/commands', 'Commands'], ['/api/components', 'DOM Components'], + ['/api/component', ' - Component'], ['/api/panels', 'Panels'], ['/api/style_manager', 'Style Manager'], ['/api/storage_manager', 'Storage Manager'], diff --git a/docs/README.md b/docs/README.md index b828f099e..daef7c849 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,3 +47,10 @@ You can download GrapesJS from one of this sources * `npm i grapesjs` * git * `git clone https://github.com/artf/grapesjs.git` + + + + +## Changelog + +To track changes made in the library we rely on [Github Releases](https://github.com/artf/grapesjs/releases) diff --git a/docs/api.js b/docs/api.js index 33749e140..b98892483 100644 --- a/docs/api.js +++ b/docs/api.js @@ -10,6 +10,7 @@ const cmds = [ ['block_manager/index.js', 'block_manager.md'], ['commands/index.js', 'commands.md'], ['dom_components/index.js', 'components.md'], + ['dom_components/model/Component.js', 'component.md'], ['panels/index.js', 'panels.md'], ['style_manager/index.js', 'style_manager.md'], ['storage_manager/index.js', 'storage_manager.md'], diff --git a/docs/api/component.md b/docs/api/component.md new file mode 100644 index 000000000..70ade8c7e --- /dev/null +++ b/docs/api/component.md @@ -0,0 +1,413 @@ + + +## Component + +The Component object represents a single node of our template structure, so when you update its properties the changes are +immediatly reflected on the canvas and in the code to export (indeed, when you ask to export the code we just go through all +the tree of nodes). +An example on how to update properties: + +```js +component.set({ + tagName: 'span', + attributes: { ... }, + removable: false, +}); +component.get('tagName'); +// -> 'span' +``` + +### Properties + +- `type` **[String][1]?** Component type, eg. `text`, `image`, `video`, etc. +- `tagName` **[String][1]?** HTML tag of the component, eg. `span`. Default: `div` +- `attributes` **[Object][2]?** Key-value object of the component's attributes, eg. `{ title: 'Hello' }` Default: `{}` +- `name` **[String][1]?** Name of the component. Will be used, for example, in Layers and badges +- `removable` **[Boolean][3]?** When `true` the component is removable from the canvas, default: `true` +- `draggable` **([Boolean][3] \| [String][1])?** Indicates if it's possible to drag the component inside others. + You can also specify a query string to indentify elements, + eg. `'.some-class[title=Hello], [data-gjs-type=column]'` means you can drag the component only inside elements + containing `some-class` class and `Hello` title, and `column` components. Default: `true` +- `droppable` **([Boolean][3] \| [String][1])?** Indicates if it's possible to drop other components inside. You can use + a query string as with `draggable`. Default: `true` +- `badgable` **[Boolean][3]?** Set to false if you don't want to see the badge (with the name) over the component. Default: `true` +- `stylable` **([Boolean][3] \| [Array][4]<[String][1]>)?** True if it's possible to style the component. + You can also indicate an array of CSS properties which is possible to style, eg. `['color', 'width']`, all other properties + will be hidden from the style manager. Default: `true` +- `stylable-require` **[Array][4]<[String][1]>?** Indicate an array of style properties to show up which has been marked as `toRequire`. Default: `[]` +- `unstylable` **[Array][4]<[String][1]>?** Indicate an array of style properties which should be hidden from the style manager. Default: `[]` +- `highlightable` **[Boolean][3]?** It can be highlighted with 'dotted' borders if true. Default: `true` +- `copyable` **[Boolean][3]?** True if it's possible to clone the component. Default: `true` +- `resizable` **[Boolean][3]?** Indicates if it's possible to resize the component. It's also possible to pass an object as [options for the Resizer][5]. Default: `false` +- `editable` **[Boolean][3]?** Allow to edit the content of the component (used on Text components). Default: `false` +- `layerable` **[Boolean][3]?** Set to `false` if you need to hide the component inside Layers. Default: `true` +- `selectable` **[Boolean][3]?** Allow component to be selected when clicked. Default: `true` +- `hoverable` **[Boolean][3]?** Shows a highlight outline when hovering on the element if `true`. Default: `true` +- `void` **[Boolean][3]?** This property is used by the HTML exporter as void elements don't have closing tags, eg. `
`, `
`, etc. Default: `false` +- `content` **[String][1]?** Content of the component (not escaped) which will be appended before children rendering. Default: `''` +- `icon` **[String][1]?** Component's icon, this string will be inserted before the name (in Layers and badge), eg. it can be an HTML string ''. Default: `''` +- `script` **([String][1] \| [Function][6])?** Component's javascript. More about it [here][7]. Default: `''` +- `traits` **[Array][4]<([Object][2] \| [String][1])>?** Component's traits. More about it [here][8]. Default: `['id', 'title']` +- `propagate` **[Array][4]<[String][1]>?** Indicates an array of properties which will be inhereted by all NEW appended children. + For example if you create a component likes this: `{ removable: false, draggable: false, propagate: ['removable', 'draggable'] }` + and append some new component inside, the new added component will get the exact same properties indicated in the `propagate` array (and the `propagate` property itself). Default: `[]` +- `toolbar` **[Array][4]<[Object][2]>?** Set an array of items to show up inside the toolbar when the component is selected (move, clone, delete). + Eg. `toolbar: [ { attributes: {class: 'fa fa-arrows'}, command: 'tlb-move' }, ... ]`. + 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` + +## is + +Check component's type + +### Parameters + +- `type` **[string][1]** Component type + +### Examples + +```javascript +component.is('image') +// -> false +``` + +Returns **[Boolean][3]** + +## find + +Find inner components by query string. +**ATTENTION**: this method works only with already rendered component + +### Parameters + +- `query` **[String][1]** Query string + +### Examples + +```javascript +component.find('div > .class'); +// -> [Component, Component, ...] +``` + +Returns **[Array][4]** Array of components + +## closest + +Find the closest parent component by query string. +**ATTENTION**: this method works only with already rendered component + +### Parameters + +- `query` **[string][1]** Query string + +### Examples + +```javascript +component.closest('div.some-class'); +// -> Component +``` + +Returns **[Component][9]** + +## replaceWith + +Replace a component with another one + +### Parameters + +- `el` **([String][1] \| [Component][9])** Component or HTML string + +### Examples + +```javascript +component.replaceWith('
Some new content
'); +// -> Component +``` + +Returns **([Component][9] \| [Array][4]<[Component][9]>)** New added component/s + +## setAttributes + +Update attributes of the component + +### Parameters + +- `attrs` **[Object][2]** Key value attributes + +### Examples + +```javascript +component.setAttributes({ id: 'test', 'data-key': 'value' }); +``` + +Returns **this** + +## addAttributes + +Add attributes to the component + +### Parameters + +- `attrs` **[Object][2]** Key value attributes + +### Examples + +```javascript +component.addAttributes({ 'data-key': 'value' }); +``` + +Returns **this** + +## getStyle + +Get the style of the component + +Returns **[Object][2]** + +## setStyle + +Set the style on the component + +### Parameters + +- `prop` **[Object][2]** Key value style object (optional, default `{}`) +- `opts` (optional, default `{}`) + +### Examples + +```javascript +component.setStyle({ color: 'red' }); +``` + +Returns **[Object][2]** + +## getAttributes + +Return all component's attributes + +Returns **[Object][2]** + +## addClass + +Add classes + +### Parameters + +- `classes` **([Array][4]<[String][1]> | [String][1])** Array or string of classes + +### Examples + +```javascript +model.addClass('class1'); +model.addClass('class1 class2'); +model.addClass(['class1', 'class2']); +// -> [SelectorObject, ...] +``` + +Returns **[Array][4]** Array of added selectors + +## setClass + +Set classes (resets current collection) + +### Parameters + +- `classes` **([Array][4]<[String][1]> | [String][1])** Array or string of classes + +### Examples + +```javascript +model.setClass('class1'); +model.setClass('class1 class2'); +model.setClass(['class1', 'class2']); +// -> [SelectorObject, ...] +``` + +Returns **[Array][4]** Array of added selectors + +## removeClass + +Remove classes + +### Parameters + +- `classes` **([Array][4]<[String][1]> | [String][1])** Array or string of classes + +### Examples + +```javascript +model.removeClass('class1'); +model.removeClass('class1 class2'); +model.removeClass(['class1', 'class2']); +// -> [SelectorObject, ...] +``` + +Returns **[Array][4]** Array of removed selectors + +## append + +Add new component children + +### Parameters + +- `components` **([Component][9] \| [String][1])** Component to add +- `opts` **[Object][2]** Options, same as in `model.add()`(from backbone) (optional, default `{}`) + +### Examples + +```javascript +someComponent.get('components').length // -> 0 +const videoComponent = someComponent.append('
')[0]; +// This will add 2 components (`video` and `div`) to your `someComponent` +someComponent.get('components').length // -> 2 +// You can pass components directly +otherComponent.append(otherComponent2); +otherComponent.append([otherComponent3, otherComponent4]); +``` + +Returns **[Array][4]** Array of appended components + +## components + +Set new collection if `components` are provided, otherwise the +current collection is returned + +### Parameters + +- `components` **([Component][9] \| [String][1])?** Components to set + +### Examples + +```javascript +// Set new collection +component.components('
'); +// Get current collection +const collection = component.components(); +console.log(collection.length); +// -> 2 +``` + +Returns **(Collection | [Array][4]<[Component][9]>)** + +## parent + +Get the parent component, if exists + +### Examples + +```javascript +component.parent(); +// -> Component +``` + +Returns **[Component][9]** + +## getName + +Get the name of the component + +Returns **[String][1]** + +## getIcon + +Get the icon string + +Returns **[String][1]** + +## toHTML + +Return HTML string of the component + +### Parameters + +- `opts` **[Object][2]** Options (optional, default `{}`) + - `opts.attributes` **([Object][2] \| [Function][6])** You can pass an object of custom attributes to replace + with the current one or you can even pass a function to generate attributes dynamically (optional, default `null`) + +### Examples + +```javascript +// Simple HTML return +component.set({ tagName: 'span' }); +component.setAttributes({ title: 'Hello' }); +component.toHTML(); +// -> + +// Custom attributes +component.toHTML({ attributes: { 'data-test': 'Hello' } }); +// -> + +// Custom dynamic attributes +component.toHTML({ + attributes(component, attributes) { + if (component.get('tagName') == 'span') { + attributes.title = 'Custom attribute'; + } + return attributes; + }, +}); +// -> +``` + +Returns **[String][1]** HTML string + +## getId + +Return the component id + +Returns **[String][1]** + +## setId + +Set new id on the component + +### Parameters + +- `id` **[String][1]** + +Returns **this** + +## getEl + +Get the DOM element of the component. This works only of the +component is already rendered + +Returns **[HTMLElement][10]** + +## onAll + +Execute callback function on itself and all inner components + +### Parameters + +- `clb` **[Function][6]** Callback function, the model is passed as an argument + +### Examples + +```javascript +component.onAll(component => { + // do something with component +}) +``` + +Returns **this** + +[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String + +[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object + +[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean + +[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array + +[5]: https://github.com/artf/grapesjs/blob/master/src/utils/Resizer.js + +[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function + +[7]: /modules/Components-js.html + +[8]: /modules/Traits.html + +[9]: #component + +[10]: https://developer.mozilla.org/docs/Web/HTML/Element diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index bcaef6964..6ea8677cd 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -29,121 +29,90 @@ const escapeRegExp = str => { const avoidInline = em => em && em.getConfig('avoidInlineStyle'); +/** + * The Component object represents a single node of our template structure, so when you update its properties the changes are + * immediatly reflected on the canvas and in the code to export (indeed, when you ask to export the code we just go through all + * the tree of nodes). + * An example on how to update properties: + * ```js + * component.set({ + * tagName: 'span', + * attributes: { ... }, + * removable: false, + * }); + * component.get('tagName'); + * // -> 'span' + * ``` + * + * @typedef Component + * @property {String} [type=''] Component type, eg. `text`, `image`, `video`, etc. + * @property {String} [tagName='div'] HTML tag of the component, eg. `span`. Default: `div` + * @property {Object} [attributes={}] Key-value object of the component's attributes, eg. `{ title: 'Hello' }` Default: `{}` + * @property {String} [name=''] Name of the component. Will be used, for example, in Layers and badges + * @property {Boolean} [removable=true] When `true` the component is removable from the canvas, default: `true` + * @property {Boolean|String} [draggable=true] Indicates if it's possible to drag the component inside others. + * You can also specify a query string to indentify elements, + * eg. `'.some-class[title=Hello], [data-gjs-type=column]'` means you can drag the component only inside elements + * containing `some-class` class and `Hello` title, and `column` components. Default: `true` + * @property {Boolean|String} [droppable=true] Indicates if it's possible to drop other components inside. You can use + * a query string as with `draggable`. Default: `true` + * @property {Boolean} [badgable=true] Set to false if you don't want to see the badge (with the name) over the component. Default: `true` + * @property {Boolean|Array} [stylable=true] True if it's possible to style the component. + * You can also indicate an array of CSS properties which is possible to style, eg. `['color', 'width']`, all other properties + * will be hidden from the style manager. Default: `true` + * @property {Array} [stylable-require=[]] Indicate an array of style properties to show up which has been marked as `toRequire`. Default: `[]` + * @property {Array} [unstylable=[]] Indicate an array of style properties which should be hidden from the style manager. Default: `[]` + * @property {Boolean} [highlightable=true] It can be highlighted with 'dotted' borders if true. Default: `true` + * @property {Boolean} [copyable=true] True if it's possible to clone the component. Default: `true` + * @property {Boolean} [resizable=false] Indicates if it's possible to resize the component. It's also possible to pass an object as [options for the Resizer](https://github.com/artf/grapesjs/blob/master/src/utils/Resizer.js). Default: `false` + * @property {Boolean} [editable=false] Allow to edit the content of the component (used on Text components). Default: `false` + * @property {Boolean} [layerable=true] Set to `false` if you need to hide the component inside Layers. Default: `true` + * @property {Boolean} [selectable=true] Allow component to be selected when clicked. Default: `true` + * @property {Boolean} [hoverable=true] Shows a highlight outline when hovering on the element if `true`. Default: `true` + * @property {Boolean} [void=false] This property is used by the HTML exporter as void elements don't have closing tags, eg. `
`, `
`, etc. Default: `false` + * @property {String} [content=''] Content of the component (not escaped) which will be appended before children rendering. Default: `''` + * @property {String} [icon=''] Component's icon, this string will be inserted before the name (in Layers and badge), eg. it can be an HTML string ''. Default: `''` + * @property {String|Function} [script=''] Component's javascript. More about it [here](/modules/Components-js.html). Default: `''` + * @property {Array} [traits=''] Component's traits. More about it [here](/modules/Traits.html). Default: `['id', 'title']` + * @property {Array} [propagate=[]] Indicates an array of properties which will be inhereted by all NEW appended children. + * For example if you create a component likes this: `{ removable: false, draggable: false, propagate: ['removable', 'draggable'] }` + * and append some new component inside, the new added component will get the exact same properties indicated in the `propagate` array (and the `propagate` property itself). Default: `[]` + * @property {Array} [toolbar=null] Set an array of items to show up inside the toolbar when the component is selected (move, clone, delete). + * Eg. `toolbar: [ { attributes: {class: 'fa fa-arrows'}, command: 'tlb-move' }, ... ]`. + * By default, when `toolbar` property is falsy the editor will add automatically commands like `move`, `delete`, etc. based on its properties. + * @property {Collection} [components=null] Children components. Default: `null` + */ const Component = Backbone.Model.extend(Styleable).extend( { defaults: { - // HTML tag of the component tagName: 'div', - - // Component type, eg. 'text', 'image', 'video', etc. type: '', - - // Name of the component. Will be used, for example, in layers and badges name: '', - - // True if the component is removable from the canvas removable: true, - - // Indicates if it's possible to drag the component inside others - // Tip: Indicate an array of selectors where it could be dropped inside draggable: true, - - // Indicates if it's possible to drop other components inside - // Tip: Indicate an array of selectors which could be dropped inside droppable: true, - - // Set false if don't want to see the badge (with the name) over the component badgable: true, - - // True if it's possible to style it - // Tip: - // Indicate an array of CSS properties which is possible to style, eg. ['color', 'width'] - // All other properties will be hidden from the style manager stylable: true, - - // Indicate an array of style properties to show up which has been marked as `toRequire` 'stylable-require': '', - - // Indicate an array of style properties which should be hidden from the style manager unstylable: '', - - // Highlightable with 'dotted' style if true highlightable: true, - - // True if it's possible to clone the component copyable: true, - - // Indicates if it's possible to resize the component (at the moment implemented only on Image Components) - // It's also possible to pass an object as options for the Resizer resizable: false, - - // Allow to edit the content of the component (used on Text components) editable: false, - - // Hide the component inside Layers layerable: true, - - // Allow component to be selected when clicked selectable: true, - - // Shows a highlight outline when hovering on the element if true hoverable: true, - - // This property is used by the HTML exporter as void elements do not - // have closing tag, eg.
,
, etc. void: false, - - // Indicates if the component is in some CSS state like ':hover', ':active', etc. - state: '', - - // State, eg. 'selected' - status: '', - - // Content of the component (not escaped) which will be appended before children rendering + state: '', // Indicates if the component is in some CSS state like ':hover', ':active', etc. + status: '', // State, eg. 'selected' content: '', - - // Component icon, this string will be inserted before the name, eg. '' icon: '', - - // Component related style - style: '', - - // Key-value object of the component's attributes - attributes: '', - - // Array of classes - classes: '', - - // Component's javascript + style: '', // Component related style + classes: '', // Array of classes script: '', - - // Traits + attributes: '', traits: ['id', 'title'], - - // Indicates an array of properties which will be inhereted by - // all NEW appended children - // - // If you create a model likes this - // removable: false, - // draggable: false, - // propagate: ['removable', 'draggable'] - // When you append some new component inside, the new added model - // will get the exact same properties indicated in `propagate` array - // (as the `propagate` property itself) - // propagate: '', - - /** - * Set an array of items to show up inside the toolbar (eg. move, clone, delete) - * when the component is selected - * toolbar: [{ - * attributes: {class: 'fa fa-arrows'}, - * command: 'tlb-move', - * },{ - * attributes: {class: 'fa fa-clone'}, - * command: 'tlb-clone', - * }] - */ toolbar: null }, @@ -206,7 +175,7 @@ const Component = Backbone.Model.extend(Styleable).extend( * @param {string} type Component type * @return {Boolean} * @example - * model.is('image') + * component.is('image') * // -> false */ is(type) { @@ -214,12 +183,12 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Find inner models by query string - * ATTENTION: this method works only with alredy rendered component - * @param {string} query Query string - * @return {Array} Array of models + * Find inner components by query string. + * **ATTENTION**: this method works only with already rendered component + * @param {String} query Query string + * @return {Array} Array of components * @example - * model.find('div > .class'); + * component.find('div > .class'); * // -> [Component, Component, ...] */ find(query) { @@ -235,12 +204,13 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Find closest model by query string - * ATTENTION: this method works only with alredy rendered component - * @param {string} query Query string + * Find the closest parent component by query string. + * **ATTENTION**: this method works only with already rendered component + * @param {string} query Query string * @return {Component} * @example - * model.closest('div'); + * component.closest('div.some-class'); + * // -> Component */ closest(query) { const result = this.view.$el.closest(query); @@ -249,6 +219,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Once the tag is updated I have to remove the node and replace it + * @private */ tagUpdated() { const coll = this.collection; @@ -260,8 +231,10 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Replace a component with another one * @param {String|Component} el Component or HTML string - * @return {Array|Component} New added component/s - * @private + * @return {Component|Array} New added component/s + * @example + * component.replaceWith('
Some new content
'); + * // -> Component */ replaceWith(el) { const coll = this.collection; @@ -272,6 +245,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Emit changes for each updated attribute + * @private */ attrUpdated() { const attrPrev = { ...this.previous('attributes') }; @@ -281,10 +255,11 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Update attributes of the model + * Update attributes of the component * @param {Object} attrs Key value attributes + * @return {this} * @example - * model.setAttributes({id: 'test', 'data-key': 'value'}); + * component.setAttributes({ id: 'test', 'data-key': 'value' }); */ setAttributes(attrs) { attrs = { ...attrs }; @@ -300,19 +275,28 @@ const Component = Backbone.Model.extend(Styleable).extend( delete attrs.style; this.set('attributes', attrs); + + return this; }, /** - * Add attributes to the model + * Add attributes to the component * @param {Object} attrs Key value attributes + * @return {this} * @example - * model.addAttributes({id: 'test'}); + * component.addAttributes({ 'data-key': 'value' }); */ addAttributes(attrs) { const newAttrs = { ...this.getAttributes(), ...attrs }; this.setAttributes(newAttrs); + + return this; }, + /** + * Get the style of the component + * @return {Object} + */ getStyle() { const em = this.em; @@ -330,6 +314,13 @@ const Component = Backbone.Model.extend(Styleable).extend( return Styleable.getStyle.call(this); }, + /** + * Set the style on the component + * @param {Object} prop Key value style object + * @return {Object} + * @example + * component.setStyle({ color: 'red' }); + */ setStyle(prop = {}, opts = {}) { const em = this.em; @@ -351,7 +342,7 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Return attributes + * Return all component's attributes * @return {Object} */ getAttributes() { @@ -387,7 +378,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Add classes - * @param {Array|string} classes Array or string of classes + * @param {Array|String} classes Array or string of classes * @return {Array} Array of added selectors * @example * model.addClass('class1'); @@ -402,7 +393,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Set classes (resets current collection) - * @param {Array|string} classes Array or string of classes + * @param {Array|String} classes Array or string of classes * @return {Array} Array of added selectors * @example * model.setClass('class1'); @@ -417,7 +408,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Remove classes - * @param {Array|string} classes Array or string of classes + * @param {Array|String} classes Array or string of classes * @return {Array} Array of removed selectors * @example * model.removeClass('class1'); @@ -458,24 +449,21 @@ const Component = Backbone.Model.extend(Styleable).extend( return this; }, - /** - * Initialize callback - */ init() {}, /** * Add new component children - * @param {Component|string} components Component to add + * @param {Component|String} components Component to add * @param {Object} [opts={}] Options, same as in `model.add()`(from backbone) * @return {Array} Array of appended components * @example - * someModel.get('components').length // -> 0 - * const videoComponent = someModel.append('
')[0]; - * // This will add 2 components (`video` and `div`) to your `someModel` - * someModel.get('components').length // -> 2 + * someComponent.get('components').length // -> 0 + * const videoComponent = someComponent.append('
')[0]; + * // This will add 2 components (`video` and `div`) to your `someComponent` + * someComponent.get('components').length // -> 2 * // You can pass components directly - * otherModel.append(otherModel2); - * otherModel.append([otherModel3, otherModel4]); + * otherComponent.append(otherComponent2); + * otherComponent.append([otherComponent3, otherComponent4]); */ append(components, opts = {}) { const result = this.components().add(components, opts); @@ -485,13 +473,15 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Set new collection if `components` are provided, otherwise the * current collection is returned - * @param {Component|string} [components] Components to set - * @return {Collection|undefined} + * @param {Component|String} [components] Components to set + * @return {Collection|Array} * @example - * // Get current collection - * const collection = model.components(); * // Set new collection - * model.components('
'); + * component.components('
'); + * // Get current collection + * const collection = component.components(); + * console.log(collection.length); + * // -> 2 */ components(components) { const coll = this.get('components'); @@ -500,13 +490,16 @@ const Component = Backbone.Model.extend(Styleable).extend( return coll; } else { coll.reset(); - components && this.append(components); + return components && this.append(components); } }, /** - * Get parent model + * Get the parent component, if exists * @return {Component} + * @example + * component.parent(); + * // -> Component */ parent() { const coll = this.collection; @@ -515,6 +508,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Script updated + * @private */ scriptUpdated() { this.set('scriptUpdated', 1); @@ -522,6 +516,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Once traits are updated I have to populates model's attributes + * @private */ traitsUpdated() { let found = 0; @@ -549,6 +544,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Init toolbar + * @private */ initToolbar() { var model = this; @@ -661,15 +657,12 @@ const Component = Backbone.Model.extend(Styleable).extend( attr.style = style; } - return new this.constructor( - attr, - opts - ); + return new this.constructor(attr, opts); }, /** * Get the name of the component - * @return {string} + * @return {String} * */ getName() { let customName = this.get('name') || this.get('custom-name'); @@ -682,7 +675,7 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Get the icon string - * @return {string} + * @return {String} */ getIcon() { let icon = this.get('icon'); @@ -691,9 +684,31 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Return HTML string of the component - * @param {Object} opts Options - * @return {string} HTML string - * @private + * @param {Object} [opts={}] Options + * @param {Object|Function} [opts.attributes=null] You can pass an object of custom attributes to replace + * with the current one or you can even pass a function to generate attributes dynamically + * @return {String} HTML string + * @example + * // Simple HTML return + * component.set({ tagName: 'span' }); + * component.setAttributes({ title: 'Hello' }); + * component.toHTML(); + * // -> + * + * // Custom attributes + * component.toHTML({ attributes: { 'data-test': 'Hello' } }); + * // -> + * + * // Custom dynamic attributes + * component.toHTML({ + * attributes(component, attributes) { + * if (component.get('tagName') == 'span') { + * attributes.title = 'Custom attribute'; + * } + * return attributes; + * }, + * }); + * // -> */ toHTML(opts = {}) { const model = this; @@ -789,8 +804,8 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Return model id - * @return {string} + * Return the component id + * @return {String} */ getId() { let attrs = this.get('attributes') || {}; @@ -798,9 +813,9 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Return model id + * Set new id on the component * @param {String} id - * @return {self} + * @return {this} */ setId(id) { const attrs = { ...this.get('attributes') }; @@ -810,8 +825,8 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Get the DOM element of the model. This works only of the - * model is alredy rendered + * Get the DOM element of the component. This works only of the + * component is already rendered * @return {HTMLElement} */ getEl() { @@ -862,9 +877,13 @@ const Component = Backbone.Model.extend(Styleable).extend( }, /** - * Execute callback function on all components + * Execute callback function on itself and all inner components * @param {Function} clb Callback function, the model is passed as an argument - * @return {self} + * @return {this} + * @example + * component.onAll(component => { + * // do something with component + * }) */ onAll(clb) { if (isFunction(clb)) { @@ -877,7 +896,8 @@ const Component = Backbone.Model.extend(Styleable).extend( /** * Reset id of the component and any of its style rule * @param {Object} [opts={}] Options - * @return {self} + * @return {this} + * @private */ resetId(opts = {}) { const { em } = this; @@ -909,6 +929,7 @@ const Component = Backbone.Model.extend(Styleable).extend( * store and load them back, you might hit collisions with new components * @param {Model} model * @return {string} + * @private */ createId(model) { componentIndex++;