# 05. __Widgets__

[![+Professional Support](https://www.totaljs.com/img/badge-support.svg)](https://www.totaljs.com/support/) [![+Chat with contributors](https://www.totaljs.com/img/badge-chat.svg)](https://messenger.totaljs.com)

Widgets are very important part of CMS editor and they can extend functionality for visitors. Widgets can be used in __CMS editor__ in `Pages`, `Posts`, `Newsletter` and `Products` section.

- [Download __CMS widgets__](https://componentator.com/widgets/)
- [GitHub Repository](https://github.com/totaljs/widgets)

## Structure

A widget can contain CSS, HTML, JavaScript client-side (+ editor scripting) and server-side code together.

__Example__:

```html
<style>

	/* optional, client-side styles */
	.wcontent {}
	/* All styles (from all widgets) will be merged into the /widgets.css */

</style>

<script>

	// optional, client-side scripting
	alert('OK');
	// All scripts (from all widgets) will be merged into the /widgets.js

</script>

<script editor>

	// optional, client-side editor scripting

	// Defines an option into the widget settings
	// Docs: https://componentator.com/#j-multioptions
	// Optional, can be defined multiple times
	// Additional CMS types: "Navigations", "Posts", "Signals", "Notices", "Partial", "Languages", "file", "color"
	// option(key, label, def_value, [type], [max], [min], [step]);
	option('size', 'Font size', 18);    
	
	// Optional
	// The method below is executed when the widget settings is modified
	exports.configure = function(options, element, prev) {

		// this    === Object and it contains all dependencies key/value
		// options === Object
		// element === jQuery element
		// prev    === Object (previous settings)

		// you can transform "element" by your needs
		// e.g.
		
		element.find('.wcontent').css('font-size', options.size);
		
	};
	
</script>

<script total>

	// optional, server-side scripting

	// Optional
	// Is executed if the widget is modified or init
	exports.install = function() {

		// This method registers a new record in PageGlobals (if not exists)
		this.variable('key', 'value');
		
	};
	
	// Optional
	// Is executed if the widget is removed/modified
	exports.uninstall = function() {
	};
	
	// Optional
	// Is executed before the widget is rendered
	exports.render = function(options, html, next, template) {
	
		this;
		// A controller (default: EMPTY CONTROLLER)
		// returns {Controller}
	
		options;
		// Custom options defined in <script editor>
		// returns {Object}
		
		html;
		// HTML from the widget
		// returns {String}
		
		// New content replaces the widget implementation in the HTML body
		next(html + '<div>UPDATED CONTENT</div>');
		
		template;
		// A template, a value from <script type="text/html"></script> tag
		// return {String}

	};
	
</script>

<!-- EXAMPLE: CONTENT WIDGET -->
<div class="wb wm wp">
	<div class="yourclass CMS_edit">HTML content</div>
</div>
```

```html
<!-- EXAMPLE: INLINE WIDGET -->
<div class="wm">
	<div class="yourclass CMS_edit">HTML content</div>
</div>
```

- all styles from all widgets are merged into the one style file called `widgets.css`
- all client-side scripts from all widgets are merged into the one script file called `widgets.js`
- CSS and JS files are reloaded when some widget is modified with a new tiemstamp
- class `wm` determines a bottom margin (by default `15px`) for each content/column widget
- class `wmi` determines a bottom margin (by default `15px`) for each inline widget
- class `wp` determines padding for `Content`, `Columns` widgets only
- class `wpi` determines padding for `Inline` widgets only
- class `wb` determines the body of the widget and CMS editor can enable/disable `wm` and `wp` classes according to this class (it's used for `content` and `colums` widgets in most cases)
- class `wbi` determines the body of the inline widget and CMS editor can enable/disable `wmi` and `wpi` classes
- class `nowrap` adds hellip (...) if the text is too long and in mobile devices this class enables horizontal scrollbar

__Default global styles__:

```css
/* content/layout widget body */
.wb {}

/* content/layout widget padding (left + right) */
.wp { padding-left: 0; padding-right: 0; }

/* nested content/layout widget padding (left + right) */
/* !! define it !! if .wp doesn't contain any padding */
.wb .wp { padding-left: 20px; padding-right: 20px; }

/* content/layout widget margin (bottom) */
.wm { margin-bottom: 20px; }

/* inline widget body */
.wbi {}

/* inline widget padding (left + right) */
.wpi { padding-left: 0; padding-right: 0; }

/* inline widget margin (bottom) */
.wmi { margin-bottom: 15px; }

/* content/layout widget body */
.wnowrap { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }

@media(max-width: 768px) {
	.wnowrap { overflow-x: auto; text-overflow: clip; overflow-scrolling: touch; }
}
```

## CMS editor markup

__IMPORTANT__: all below classes must be defined under `<div id="CMS">` element because CMS editor takes the entire content from this element and store it in database.

### CMS editor classes

- `CMS_edit`
The content will be editable in CMS editor. It works with most of elements like `div`, `span`, `p`, `img`, `h1`, `h2`, etc. and it supports editing of `Font-Awesome` elements with `fa-` class.

- `CMS_remove`
The element can be removed in CMS editor directly. Be careful because removed element can't be recovered.

- `CMS_unwrap`
The element will be unwrapped when the body will be rendered on server-side. In other words the element will be removed and the content stays.

- `CMS_repeat`
The element can be cloned. So user can clone the element with its content and each cloned element will contain `CMS_remove` class automatically.
	
- `CMS_widgets`
CMS editor allows to add new widgets into this element. This element read `data-cms-category=""` attribute, read more below.

- `CMS_attribute`
User can change basic attributes of this element (classes, styles, ID, etc). The element can contain `data-cms-theme=""` for choosing theme.

- `CMS_multiline`
CMS editor allows a multiline for `CMS_edit`. Otherwise newline is disabled. Important note: different browsers can add different elements for adding new lines, e.g. `div` or `p`.

- `CMS_summary`
The content of this element will be used as a summary in `Page` or `Post`. Summary can be used e.g. in some listing or in some search result. Please keep the one element with this class per content.

- `CMS_search`
The content of each element with this attribute will be used for full-text search. You can use multiple elements with this class.

- `CMS_hidden`:
The content of each element is hidden in CMS editor (this class is defined in `editor.css` in specific theme).

- `CMS_visible`:
The content of each element is visible in CMS editor (this class is defined in `editor.css` in specific theme). It can be used with `hidden` class.

- `totaljs`:
The content will be filled as a form input. It's targeted for widgets with a form content.

- `jcomponent`:
Class will be removed after the page will be rendered. The class contains `visibility:hidden`, so some UI components will be hidden when the page is rendering.

### CMS editor attributes

- `data-cms-category="CategoryA, CategoryN"`
Optional, widget form shows the widgets within defined categories. Categories need to be typed with the full name of category. CMS knows these categories only: `Layouts`, `Columns`, `Content`, `Newsletter` and `Inline`.

- `data-cms-width="200px"`
Optional, image `width` for the picture cropper and it works with element `<img` + class `CMS_edit`. Important: `data-cms-width` needs `data-cms-height` attribute. 

- `data-cms-height="200px"`
Optional, image `height` for the picture cropper and it works with element `<img` + class `CMS_edit`. Important: `data-cms-height` needs `data-cms-width` attribute. 

- `data-cms-size="80%"`
Optional. This attribute can be used for image galleries. The value needs to be entered in percentage and it means that system resizes an image about this percentage.

- `data-cms-bg="#00000"`
Optional, default is `empty` which menas `transparent`. This attribute can set a default background color for picture cropper. The cropper will save picture as `jpg` type.

- `data-cms-src="URL_TO_IMAGE"`
Optional. This attribute can be used for image galleries with `data-cms-size` attribute. If the attribute contains some value then the CMS image editor adds a link to the image with full size.

- `data-cms-theme="Red|red,Blue|blue,Green|green"`
Optional, class themes `name|class,name|class` can be used with `CMS_attribute`.

- __NEW__: `data-cms-info="Shows info in a yellow bubble"`
Optional, can be created by the widget.

### Cases

```html
<!-- The text bellow can be modified and newline is blocked -->
<div class="CMS_edit">Lorem Ipsum</div>

<!-- The text bellow can be modified and newline is allowed -->
<div class="CMS_edit CMS_multiline">Lorem Ipsum</div>

<!-- The content bellow can be duplicated -->
<div class="CMS_repeat">
	<h2 class="CMS_edit">Lorem Ipsum</h2>
</div>

<div class="CMS_widgets">
	<!-- Here can be added widgets -->
</div>

<div class="CMS_widgets" data-cms-category="Content, Inline">
	<!-- Here can be added widgets from categories: Content and Inline -->
</div>

<!-- Theme can be changed in attributes settings -->
<div class="CMS_attribute class-red" data-cms-themes="Red|class-red,Green|class-green,Blue|class-blue">
	<div>NEXT CONTENT</div>
</div>

<!-- User can upload a picture with different size -->
<img src="base64:blabla" class="CMS_edit img-responsive" />

<!-- Editor shows a picture editor with the fixed width and height -->
<img src="base64:blabla" class="CMS_edit img-responsive" data-cms-width="600" data-cms-height="400" />

<!--
	Editor shows a picture editor with the fixed width and height,
	and it creates data-cms-original="" with the full path to large picture.
	<img src="" will contain a link to miniature with "?s=80%" argument.
-->
<img src="base64:blabla" class="CMS_edit img-responsive" data-cms-width="600" data-cms-height="400" data-cms-size="80%" />

<!-- "<span" with "CMS_unwrap" class will be unwrapped -->
<h1><i class="fa fa-home CMS_edit"></i><span class="CMS_unwrap CMS_edit">Title</span></h1>
```

## Global variables

```javascript
MAIN.css;
// Contains a relative URL address to widget styles.
// returns {String}

MAIN.js;
// Contains a relative URL address to widget scripts.
// returns {String}

MAIN.widgets;
// Internal, contains all registered and compiled widgets.
// returns {Object}
```

## Very important to know

Added widgets into the CMS editor won't be updated if the widget definition will be changed because __CMS editor__ works with HTML as it is. Only settings can be modified.

__Removed widgets aren't removed__ from the content (`pages`, `posts`, `newsletter` or `products`), you need to remove them manually from each page.