#### Limitless - UI

##### Fancy tree

Trees /trees/

###### Overview

Fancytree is a JavaScript dynamic tree view plugin for jQuery with support for persistence, keyboard, checkboxes, tables, drag'n'drop, and lazy loading. Main features:

- Lazy loading and very efficient and performant handling of large data sets
- Keyboard navigation
- (Hierarchical) selection and checkboxes
- Table view (gridview)
- Drag and drop
- Persistence of expansion, selection and active state
- Inline editing
- Themable (comes with WinXP, Win7, Win8, OS X Lion, and Glyph samples)
- The tree behaves like a single form control, i.e. it is 'tabbable' (example)
- Rich object oriented API
- Extensible modular design
- and more ...

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load jQuery UI -->
    <script src="../../../../global_assets/js/plugins/extensions/jquery_ui/full.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/trees/fancytree_all.min.js"></script>

Add element with attributes:

    <!-- Add list markup -->
    <div class="tree-default">
    	<ul>
    		<li class="folder expanded">Expanded folder with children
    			<ul>
    				<li class="expanded">Expanded sub-item
    					<ul>
    						<li class="active focused">Active sub-item (active and focus on init)</li>
    						<li>Basic <i>menu item</i> with <strong class="font-weight-semibold">HTML support</strong></li>
    					</ul>
    				</li>
    				<li>Collapsed sub-item
    					<ul>
    						<li>Sub-item 2.2.1</li>
    						<li>Sub-item 2.2.2</li>
    					</ul>
    				</li>
    			</ul>
    		</li>
    		<li class="has-tooltip" title="Look, a tool tip!">Menu item with key and tooltip</li>
    		<li class="folder">Collapsed folder
    			<ul>
    				<li>Sub-item 1.1</li>
    				<li>Sub-item 1.2</li>
    			</ul>
    		</li>
    		<li class="selected">This is a selected item</li>
    		<li class="expanded">Document with some children (expanded on init)
    			<ul>
    				<li>Document sub-item</li>
    				<li>Another document sub-item
    					<ul>
    						<li>Sub-item 2.1.1</li>
    						<li>Sub-item 2.1.2</li>
    					</ul>
    				</li>
    			</ul>
    		</li>
    	</ul>
    </div>

Call the plugin via JavaScript:

    // Basic initialization
    $('.tree-default').fancytree({
        init: function(event, data) {
            $('.has-tooltip .fancytree-title').tooltip();
        }
    });

###### Plugin options

Option | Type | Description
--- | --- | ---
`activeVisible` | true | Boolean. Make sure that the active node is always visible, i.e. its parents are expanded
`ajax` | - | Object. Default options for ajax requests
`aria` | false | Boolean. Add WAI-ARIA attributes to markup
`autoActivate` | true | Boolean. Activate a node when focused with the keyboard
`autoCollapse` | false | Boolean. Automatically collapse all siblings, when a node is expanded
`autoScroll` | false | Boolean. Scroll node into visible area, when focused by keyboard
`checkbox` | false | Boolean. Display checkboxes to allow selection
`clickFolderMode` | 4 | Integer. Defines what happens, when the user click a folder node. 1: `activate`, 2: `expand`, 3: `activate and expand`, 4: `activate/dblclick expands`
`debugLevel` | null | Integer. 0..2 (null: use global setting `$.ui.fancytree.debugInfo`)
`defaultKey` | null | Callback(node) is called for ner nodes without a key. Must return a new unique key. (default `null`: generates default keys like that: "_" + counter)
`enableAspx` | true | Boolean. Accept passing ajax data in a property named ``d``
`extensions` | [] | String[]. List of active extensions
`focusOnSelect` | false | Boolean. Set focus when node is checked by a mouse click
`generateIds` | false | Boolean. Add `id="..."` to node markup
`icons` | true | Boolean. Display node icons
`idPrefix` | "ft_" | String. ID prefix
`imagePath` | null, using 'skin/' subdirectory | String. Path to a folder containing icons
`keyboard` | true | Boolean. Support keyboard navigation
`keyPathSeparator` | "/" | String
`minExpandLevel` | 1 | Integer. 2: top-level nodes are not collapsible
`quicksearch` | false | Boolean. Navigate to next node by typing the first letters
`scrollOfs` | {top: 0, bottom: 0} | Object. Optional margins for `node.scrollIntoView()`
`scrollParent` | $container | Scrollable container for `node.scrollIntoView()`
`selectMode` | 2 | Integer. 1: single, 2: multi, 3: multi-hier
`source` | any | Used to Initialize the tree
`strings` | - | Strings. Translation table
`tabbable` | - | Boolean. Add `tabindex='0'` to container, so tree can be reached using `tab`
`titlesTabbable` | - | Boolean. Add `tabindex='0'` to node title span, so it can receive keyboard focus
`toggleEffect` | { effect: "blind", options: {direction: "vertical", scale: "box"}, duration: 200 } | Object. Animation options, `false`: off

###### Plugin events

Events are called like this: ``CALLBACK_NAME(event, data)`` where ``event`` is a jQuery Event object and ``data`` is of type EventData The ``this`` context is set to tree's the HTMLDivElement:

Event | Description
--- | ---
`activate` | `data.node` was activated
`beforeActivate` | `data.node` is about to tbe (de)activated. Current status is `data.node.isActive()`. Return `false` to prevent default processing
`beforeExpand` | `data.node` is about to tbe collapsed/expanded. Current status is `data.node.isExpanded()`. Return `false` to prevent default processing
`beforeSelect` | `data.node` is about to tbe (de)selected. Current status is data.node.isSelected(). Return `false` to prevent default processing
`blur` | `data.node` lost keyboard focus
`blurTree` | `data.tree` lost keyboard focus
`click` | `data.node` was clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. activating, expanding, selecting, etc
`collapse` | `data.node` was collapsed
`create` | Widget was created (called only once, even if re-initialized)
`createNode` | Allow tweaking and binding, after node was created for the first time (NOTE: this event is only available as callback, but not for `bind()`)
`dblclick` | `data.node` was double-clicked. `data.targetType` contains the region ("title", "expander", ...). Return `false` to prevent default processing, i.e. expanding, etc
`deactivate` | `data.node` was deactivated
`expand` | `data.node` was expanded
`focus` | `data.node` received keyboard focus
`focusTree` | `data.tree` received keyboard focus
`iconClass` | Allows to override the class names added to the `data.node` icon markup to define custom icons or glyphs
`init` | Widget was (re-)initialized
`keydown` | `data.node` received key. `event.which` contains the key. Return `false` to prevent default processing, i.e. navigation. Call `data.result = "preventNav";` to prevent navigation but still allow default handling inside embedded input controls
`keypress` | (currently unused)
`lazyLoad` | `data.node` is a lazy node that is expanded for the first time. The new child data must be returned in the `data.result` property (see `source` option for available formats)
`loadChildren` | Node data was loaded, i.e. `node.nodeLoadChildren()` finished
`loadError` | A load error occurred. Return `false` to prevent default processing
`postProcess` | Allows to modify the ajax response
`removeNode` | `data.node` was removed (NOTE: this event is only available as callback, but not for `bind()`)
`renderColumns` | (used by table extension)
`renderNode` | Allow tweaking after node state was rendered (NOTE: this event is only available as callback, but not for `bind()`)
`renderTitle` | Allow replacing the `'<span class='fancytree-title'>`` markup (NOTE: this event is only available as callback, but not for `bind()`)
`restore` | Text-persist has expanded, selected, and activated the previous state
`select` | `data.node` was selected

###### Plugin info

Property | Description
--- | ---
File name | fancytree_all.min.js, fancytree_childcounter.js
Location | global_assets/js/plugins/trees/
Links | Official plugin website Project wiki Full documentation Github project page

##### Full calendar

Calendars /ui/fullcalendar/

###### Overview

FullCalendar is a drag-n-drop jQuery plugin for displaying events on a full-sized calendar. FullCalendar is great for displaying events, but it isn't a complete solution for event content-management. Beyond dragging an event to a different time/day, you cannot change an event's name or other associated data. It is up to you to add this functionality through FullCalendar's event hooks.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load Moment.js extensions -->
    <script src="../../../../global_assets/js/plugins/ui/moment/moment.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/ui/fullcalendar/fullcalendar.min.js"></script>

Add element with attributes:

    <!-- Add DIV element -->
    <div class="fullcalendar-basic"></div>

Call the plugin via JavaScript:

    // Basic initialization
    $('.fullcalendar-basic').fullCalendar({
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,basicWeek,basicDay'
        },
        defaultDate: '2014-11-12',
        editable: true,
        events: [
            {
                title: 'All Day Event',
                start: '2014-11-01'
            },
            {
                title: 'Long Event',
                start: '2014-11-07',
                end: '2014-11-10'
            },
            ...
        ]
    });

###### Fullcalendar documentation

Complete Fullcalendar documentation can be found online on Official library website. It's quite big, with a lot of options, events and methods. Also check out Google Calendar integration. I find it useless to copy them all and paste to the Limitless documentation, nobody can represent and describe library features better than its creators. Below you can find additional links related to Fullcalendar library.

###### Plugin info

Property | Description
--- | ---
File name | fullcalendar.min.js
Location | global_assets/js/plugins/ui/fullcalendar/
Links | Official plugin website Full documentation Github project page

##### Headroom

Navigation /ui/headroom/

###### Overview

Headroom.js is a lightweight, high-performance JS widget (with no dependencies!) that allows you to react to the user's scroll. The header on this site is a living example, it slides out of view when scrolling down and slides back in when scrolling up. Headroom.js allows you to bring elements into view when appropriate, and give focus to your content the rest of the time.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load core -->
    <script src="../../../../global_assets/js/plugins/ui/headroom/headroom.min.js"></script>

Add element with attributes:

    <!-- Add navbar markup -->
    <div class="navbar navbar-dark navbar-slide-top fixed-top">
    	<div class="navbar-header">
    		...
    	</div>

    	<div class="navbar-collapse collapse" id="navbar-mobile">
    		...
    	</div>
    </div>

Call the plugin via JavaScript:

    // Basic initialization
    // Construct an instance of Headroom, passing the element
    var headroomTop  = new Headroom(document.querySelector('.navbar-slide-top'), {
        offset: navbarTop.offsetHeight,
        tolerance: {
            up: 10,
            down: 10
        },
        onUnpin : function() {
            $('.headroom').find('.show').removeClass('show');
        }
    });

    // Initialise
    headroomTop.init();

###### How does it work?

At it's most basic `headroom.js` simply adds and removes CSS classes from an element in response to a scroll event. This means you must supply your own CSS styles separately. The classes that are used in headroom.js that are added and removed are:

    <!-- Initially -->
    <div class="headroom">

    <!-- Scrolling down -->
    <div class="headroom headroom--unpinned">

    <!-- Scrolling up -->
    <div class="headroom headroom--pinned">

Relying on CSS classes affords `headroom.js` incredible flexibility. The choice of what to do when scrolling up or down is now entirely yours - anything you can do with CSS you can do in response to the user's scroll.

###### Plugin options

Headroom.js can also accept an options object to alter the way it behaves. You can see the default options by inspecting Headroom.options. The structure of an options object is as follows:

    // Basic initialization
    {
        // vertical offset in px before element is first unpinned
        offset : 0,

        // scroll tolerance in px before state changes
        tolerance : 0,

        // or you can specify tolerance individually for up/down scroll
        tolerance : {
            up : 5,
            down : 0
        },

        // css classes to apply
        classes : {

            // when element is initialised
            initial : "headroom",

            // when scrolling up
            pinned : "headroom--pinned",

            // when scrolling down
            unpinned : "headroom--unpinned",

            // when above offset
            top : "headroom--top",

            // when below offset
            notTop : "headroom--not-top"
        },

        // element to listen to scroll events on, defaults to `window`
        scroller : someElement,

        // callback when pinned, `this` is headroom object
        onPin : function() {},

        // callback when unpinned, `this` is headroom object
        onUnpin : function() {},

        // callback when above offset, `this` is headroom object
        onTop : function() {},

        // callback when below offset, `this` is headroom object
        onNotTop : function() {}
    }

###### Plugin info

Property | Description
--- | ---
File name | headroom.min.js, headroom_jquery.min.js
Location | global_assets/js/plugins/ui/headroom/
Links | Official plugin website Demonstration Github project page

##### Sticky kit

Misc sticky.min.js

###### Overview

Sticky kit is a jQuery plugin for making smart sticky elements - it provides an easy way to attach elements to the page when the user scrolls such that the element is always visible.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="assets/js/plugins/ui/sticky.min.js"></script>

Add element with attributes:

    <!-- Add sidebar markup -->
    <div class="sidebar-sticky w-100 w-md-auto order-1 order-md-2">
    	<div class="sidebar sidebar-light sidebar-component sidebar-component-right sidebar-expand-md">
    		<div class="sidebar-content">
    			<div class="card">
    				[...]
    			</div>
            </div>
    	</div>
    </div>

Just call `stick_in_parent` on the elements you want to be stuck inside of their parent. Sticky elements “bottom out” so they never leave the container, no more worrying if a sticky element will accidentally cover your footer:

    // Basic initialization
    $('.sidebar-sticky .sidebar').stick_in_parent({
        offset_top: 20,
        parent: '.content'
    });

###### Plugin options

You can pass a hash of options to configure how Sticky Kit works. The following options are accepted, each one is optional:

Option | Description
--- | ---
`parent` | The element will be the parent of the sticky item. The dimensions of the parent control when the sticky element bottoms out. Defaults to the closest parent of the sticky element. Can be a selector.
`inner_scrolling` | Boolean to enable or disable the ability of the sticky element to scroll independently of the scrollbar when it’s taller than the viewport. Defaults to `true` for enabled.
`sticky_class` | The name of the CSS class to apply to elements when they have become stuck. Defaults to `"is_stuck"`
`offset_top` | Offsets the initial sticking position by of number of pixels, can be either negative or positive
`spacer` | either a selector to use for the spacer element, or `false` to disable the spacer. The selector is passed to closest, so you should nest the sticky element within the spacer. Defaults to Stiky Kit creating its own spacer.
`bottoming` | Boolean to control whether elements bottom out. Defaults to `true`
`recalc_every` | Integer specifying that a recalc should automatically take place between that many ticks. A tick takes place on every scroll event. Defaults to never calling recalc on a tick.

###### Plugin events

Various events are triggered from a sticky element when its state changes. They are:

Option | Description
--- | ---
`sticky_kit:stick` | Triggered when element becomes stuck.
`sticky_kit:unstick` | Triggered when element becomes unstuck. (Note: an element is still considered stuck when it has bottomed out)
`sticky_kit:bottom` | Triggered when element bottoms out.
`sticky_kit:unbottom` | Triggered when element is no longer bottomed out.
`sticky_kit:recalc` | Trigger this event to cause all sticky elements to be recalculated.
`sticky_kit:detach` | Remove sticky kit and restore element to original positionю If you want to remove sticky kit from an element after applying it you can send that element a sticky_kit:detach event

###### Scrolling performance

StickyKit takes scrolling performance very seriously. It’s built from the ground up to let you have sticky elements without incurring scroll lag or jank.

Probably the biggest cause of scrolling lag is `onscroll` handlers that do too much work, trigger page reflows, etc. StickyKit avoids this by having a very light scroll handler that operates on cached values.

If you notice that your sticky element is acting strange, like it pops to the bottom of the page, or jumps around, then your cached value are most likely outdated. Luckily it’s easy to fix, read Recalculating Sticky Elements below.

Sticky Kit has two internal callbacks:

- `recalc` — Updates the cached sizes of the elements it checks
- `tick` — Checks and updates if necessary the sticky state from the cached values

A `tick` happens on every scroll event. It’s designed to be as fast as possible.
A `recalc` happens whenever the cached values need to be updated. It’s (comparatively) slower, so you don’t want to run this on every scroll event. A recalc can happen automatically in the following cases: Sticky kit is first initialized, on the following tick after the height of the document changes.

###### Recalculating Sticky Elements

If you're changing the markup of your page on the fly by removing, adding or resizing elements then you most likely need to tell Sticky Kit to recalculate the sticky elements to guarantee they're positioned correctly.

You can manually cause a recalculation to happen by triggering an event on document.body:

    // Recalc
    $(document.body).trigger('sticky_kit:recalc');

Typically you only need to trigger a recalculation if you are changing the positions/sizes of elements above the sticky element, adjacent to it, or the sticky element itself.

Instead of manually calling `sticky_kit:recalc` you can use the recalc_every option described above to periodically do a recalculation between ticks. Setting it to 1 will cause a recalculation to happen on every scroll event, preventing the state from ever being out of date.

    // Recalc
    $('#sticky_item').stick_in_parent({recalc_every: 1});

###### Plugin info

Property | Description
--- | ---
File name | sticky.min.js
Location | global_assets/js/plugins/ui/
Links | Official plugin website Github project page

##### Slinky

Navigations slinky.min.js

###### Overview

A light-weight, responsive, mobile-like navigation menu plugin

Core features:

- Single light weight file
- Unlimited navigation levels
- Easy styling through SASS/CSS
- Fully integrated with jQuery
- Advanced configuration via available options and events
- Tested for all major browsers desktop and mobile versions
- Tip: set `.active` class on the last child `ul` element to jump there on init

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="assets/js/plugins/ui/slinky.min.js"></script>

Call the plugin via JavaScript:

    // Attach drill down menu to menu list with child levels
    $('.nav-item-multi').one('shown.bs.dropdown', function () {
        $('.dropdown-item-group').each(function() {
            $(this).slinky({
                title: true,
                speed: 200
            });
        });
    });

###### Plugin options

Option | Default | Description
--- | --- | ---
`resize` | true | Resize menu height to match content on navigation
`speed` | 300 | Animation speed in milliseconds
`theme` | slinky-theme-default | Slinky theme
`title` | false | Show title of sub menu

###### Plugin API

.home(animate)

Navigate back to the root menu

Option | Default | Description
--- | --- | ---
`animate` | true | Pass `false` to skip animation

.jump(target, animate)

Navigate to a sub menu

Option | Default | Description
--- | --- | ---
`to` | null | Selector for `ul` target to jump to
`animate` | true | Pass `false` to skip animation

.destroy() Remove Slinky

###### Plugin info

Property | Description
--- | ---
File name | slinky.min.js
Location | global_assets/js/plugins/ui/
Links | Official plugin website Github project page

##### Perfect scrollbar

Navigations perfect_scrolbar.min.js

###### Overview

Minimalistic but perfect custom scrollbar plugin. Main highlights:

- No change on design layout
- No manipulation on DOM tree
- Use plain `scrollTop` and `scrollLeft`
- Scrollbar style is fully customizable/li>
- Efficient update on layout change

###### Before using perfect-scrollbar

The following requirements should meet.

- the container must have a `position` style.
- the container must be a normal container element.

The following requirements are included in the basic CSS, but please keep in mind when you'd like to change the CSS files.

- the container must have an `overflow: hidden` css style.
- the scrollbar's position must be `absolute`.
- the scrollbar-x must have `bottom` or `top`, and the scrollbar-y must have `right` or `left`.

Finally, scroll hooking is generally considered as a bad practice, and perfect-scrollbar should be used carefully. Unless custom scroll is really needed, using browser-native scroll is always recommended.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/ui/perfect_scrollbar.min.js"></script>

Call the plugin via JavaScript:

    // Initialize
    var ps = new PerfectScrollbar('.sidebar-fixed .sidebar-content', {
        wheelSpeed: 2,
        wheelPropagation: true
    });

###### Plugin options

Option | Default | Description
--- | --- | ---
`handlers {String[]}` | ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'] | It is a list of handlers to scroll the element.
`wheelSpeed {Number}` | 1 | The scroll speed applied to mousewheel event.
`wheelPropagation {Boolean}` | false | If this option is true, when the scroll reaches the end of the side, mousewheel event will be propagated to parent element.
`swipeEasing {Boolean}` | true | If this option is true, swipe scrolling will be eased.
`minScrollbarLength {Number?}` | null | When set to an integer value, the thumb part of the scrollbar will not shrink below that number of pixels.
`maxScrollbarLength {Number?}` | null | When set to an integer value, the thumb part of the scrollbar will not expand over that number of pixels.
`scrollingThreshold {Number}` | 1000 | This sets threashold for `ps--scrolling-x` and `ps--scrolling-y` classes to remain. In the default CSS, they make scrollbars shown regardless of hover state. The unit is millisecond.
`useBothWheelAxes {Boolean}` | false | When set to true, and only one (vertical or horizontal) scrollbar is visible then both vertical and horizontal scrolling will affect the scrollbar.
`suppressScrollX {Boolean}` | false | When set to true, the scroll bar in X axis will not be available, regardless of the content width.
`suppressScrollY {Boolean}` | false | When set to true, the scroll bar in Y axis will not be available, regardless of the content height.
`scrollXMarginOffset {Number}` | 0 | The number of pixels the content width can surpass the container width without enabling the X axis scroll bar. Allows some "wiggle room" or "offset break", so that X axis scroll bar is not enabled just because of a few pixels.
`scrollYMarginOffset {Number}` | 0 | The number of pixels the content height can surpass the container height without enabling the Y axis scroll bar. Allows some "wiggle room" or "offset break", so that Y axis scroll bar is not enabled just because of a few pixels.

###### Plugin events

perfect-scrollbar dispatches custom events.

    // Register event
    container.addEventListener('ps-scroll-x', () => ...);

Option | Description
--- | ---
`ps-scroll-y` | This event fires when the y-axis is scrolled in either direction.
`ps-scroll-x` | This event fires when the x-axis is scrolled in either direction.
`ps-scroll-up` | This event fires when scrolling upwards.
`ps-scroll-down` | This event fires when scrolling downwards.
`ps-scroll-left` | This event fires when scrolling to the left.
`ps-scroll-right` | This event fires when scrolling to the right.
`ps-y-reach-start` | This event fires when scrolling reaches the start of the y-axis.
`ps-y-reach-end` | This event fires when scrolling reaches the end of the y-axis (useful for infinite scroll).
`ps-x-reach-start` | This event fires when scrolling reaches the start of the x-axis.
`ps-x-reach-end` | This event fires when scrolling reaches the end of the x-axis.

###### Plugin info

Property | Description
--- | ---
File name | prefect_scrollbar.min.js
Location | global_assets/js/plugins/ui/
Links | Official plugin website Github project page

##### Ion range slider

Sliders ion_rangeslider.min.js

###### Overview

Ion.RangeSlider. Is an easy, flexible and responsive range slider with tons of options. Supports events and public methods, has flexible settings, can be completely altered with CSS. Cross-browser: Google Chrome, Mozilla Firefox 3.6+, Opera 12+, Safari 5+, Internet Explorer 8+. Also supports touch-devices (iPhone, iPad, Nexus, etc.). Key slider features:

- Skin support
- Any number of sliders at one page without conflicts and big performance problems
- Two slider types single (1 slider) and double (2 sliders)
- Support of negative and fractional values
- Ability to set custom step and snap grid to step
- Support of custom values diapason
- Customisable grid of values
- Ability to disable UI elements (min and max, current value, grid)
- Postfixes and prefixes for your numbers ($20, 20 € etc.)
- Additional postfix for maximum value (eg. $0 — $100+)
- Ability to prettify large numbers (eg. 10000000 -> 10 000 000 or 10.000.000)
- Slider writes its value right into input value field. This makes it easy to use in any html form
- Any slider value can be set through input data-attribute (eg. data-min="10")
- Slider supports disable param. You can set it true to make slider inactive
- Slider supports external methods (update, reset and remove) to control it after creation
- For advanced users slider has callbacks (onStart, onChange, onFinish, onUpdate). Slider pastes all its params to callback first argument as object
- Slider supports date and time

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/sliders/ion_rangeslider.min.js"></script>

Add element with attributes:

    <!-- Add DIV element -->
    <div id="ion-slider-default"></div>

Call the plugin via JavaScript:

    // Initialize
    $("#ion-slider-default").ionRangeSlider({
    	// options
    });

###### Plugin options

Option | Defaults | Type | Description
--- | --- | --- | ---
type data-type | "single" | string | Choose slider type, could be `single` - for one handle, or `double` for two handles
min data-min | 10 | number | Set slider minimum value
max data-max | 100 | number | Set slider maximum value
from data-from | min | number | Set start position for left handle (or for single handle)
to data-to | max | number | Set start position for right handle
step data-step | 1 | number | Set sliders step. Always > 0. Could be fractional.
min_interval data-min-interval | — | number | Set minimum diapason between sliders. Only in "double" type
max_interval data-max-interval | — | number | Set maximum diapason between sliders. Only in "double" type
drag_interval data-drag-interval | false | boolean | Allow user to drag whole range. Only in "double" type (beta)
values data-values | [] | array | Set up your own array of possible slider values. They could be numbers or strings. If the values array is set up, min, max and step param, are no longer can be changed.
from_fixed data-from-fixed | false | boolean | Fix position of left (or single) handle.
from_min data-from-min | min | number | Set minimum limit for left handle.
from_max data-from-max | max | number | Set the maximum limit for left handle
from_shadow data-from-shadow | false | boolean | Highlight the limits for left handle
to_fixed data-to-fixed | false | boolean | Fix position of right handle.
to_min data-to-min | min | number | Set the minimum limit for right handle
to_max data-to-max | max | number | Set the maximum limit for right handle
to_shadow data-to-shadow | false | boolean | Highlight the limits for right handle
prettify_enabled data-prettify-enabled | true | boolean | Improve readability of long numbers. 10000000 → 10 000 000
prettify_separator data-prettify-separator | " " | string | Set up your own separator for long numbers. 10 000, 10.000, 10-000 и т.п.
prettify — | null | function | Set up your own prettify function. Can be anything. For example, you can set up unix time as slider values and than transform them to cool looking dates.
force_edges data-force-edges | false | boolean | Slider will be always inside it's container.
keyboard data-keyboard | false | boolean | Activates keyboard controls. Move left: ←, ↓, A, S. Move right: →, ↑, W, D.
keyboard_step data-keyboard-step | 5 | number | Movement step, than controling from keyboard. In percents.
grid data-grid | false | boolean | Enables grid of values.
grid_margin data-grid-margin | true | boolean | Set left and right grid borders.
grid_num data-grid-num | 4 | number | Number of grid units.
grid_snap data-grid-snap | false | boolean | Snap grid to sliders step (step param). If activated, grid_num will not be used.
hide_min_max data-hide-min-max | false | boolean | Hides min and max labels
hide_from_to data-hide-from-to | false | boolean | Hide from and to lables
prefix data-prefix | — | string | Set prefix for values. Will be set up right before the number: $100
postfix data-postfix | — | string | Set postfix for values. Will be set up right after the number: 100k
max_postfix data-max-postfix | — | string | Special postfix, used only for maximum value. Will be showed after handle will reach maximum right position. For example 0 — 100+
decorate_both data-decorate-both | true | boolean | Used for "double" type and only if prefix or postfix was set up. Determine how to decorate close values. For example: $10k — $100k or $10 — 100k
values_separator data-values-separator | " — " | string | Set your own separator for close values. Used for "double" type. Default: 10 — 100. Or you may set: 10 to 100, 10 + 100, 10 → 100 etc.
input_values_separator data-input-values-separator | " ; " | string | Separator for double values in input value property.
disable data-disable | false | boolean | Locks slider and makes it inactive.
onStart — | null | function | Callback. Is called on slider start.
onChange — | null | function | Callback. IS called on each values change.
onFinish — | null | function | Callback. Is called than user releases handle.
onUpdate — | null | function | Callback. Is called than slider is modified by external methods `update` or `reset`.

###### Plugin info

Property | Description
--- | ---
File name | ion_rangeslider.min.js
Location | global_assets/js/plugins/sliders/
Links | Official plugin website Github project page

##### NoUI slider

Sliders nouislider.min.js

###### Overview

noUiSlider is a range slider without bloat. It offers a ton off features, and it is as small, lightweight and minimal as possible, which is great for mobile use on the many supported devices, including iPhone, iPad, Android devices & Windows (Phone) 8 desktops, tablets and all-in-ones. It works on desktops too, of course!

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/sliders/nouislider.min.js"></script>

Add element with attributes:

    <!-- Add DIV element -->
    <div id="noui-slider-handles"></div>

Call the plugin via JavaScript:

    // Define element
    var slider = document.getElementById('noui-slider-default');

    // Initialize with options
    var slider_handles = document.getElementById('noui-slider-handles');
    noUiSlider.create(slider_handles, {
        start: [40, 80],
        range: {
            'min': [20],
            'max': [100]
        },
        direction: $('html').attr('dir') == 'rtl' ? 'rtl' : 'ltr'
    });

###### Plugin options

noUiSlider can be configured with a wide variety of options, which can be use to customize the slider in to doing exactly what you want:

Option | Default | Description
--- | --- | ---
`start` | Default: none Accepted: number, array[number], array[number, number] | The start option sets the number of handles and their start positions, relative to `range`
`connect` | Default: false Accepted: "lower", "upper", true, false | The connect setting can be used to control the (green) bar between the handles, or the edges of the slider. Use `"lower"` to connect to the lower side, or `"upper"` to connect to the upper side. Setting `true` sets the bar between the handles
`margin` | Default: none Accepted: number | When using two handles, the minimum distance between the handles can be set using the `margin` option. The margin value is relative to the value set in `'range'`. This option is only available on standard linear sliders
`limit` | Default: none Accepted: number | The `limit` option is the oposite of the margin option, limiting the maximum distance between two handles. As with the `margin` option, the `limit` option can only be used on linear sliders
`padding` | Default: 0 Accepted: number | Padding limits how close to the slider edges handles can be.
`step` | Default: none Accepted: number | By default, the slider slides fluently. In order to make the handles jump between intervals, you can use this option. The `step` option is relative to the values provided to range
`Orientation` | Default: "horizontal" Accepted: "vertical", "horizontal" | The `orientation` setting can be used to set the slider to `"vertical"` or `"horizontal"`
`Direction` | Default: "ltr" Accepted: "ltr", "rtl" | By default the sliders are top-to-bottom and left-to-right, but you can change this using the direction option, which decides where the upper side of the slider is
`Tooltips` | Default: false Accepted: false, true, formatter, array | noUiSlider can provide a basic tooltip using the `tooltips` option. This option can also accept formatting options to format the tooltips content. In that case, pass an array with a formatter for each handle, `true` to use the default or `false` to display no tooltip.
`Animate` | Default: true Accepted: true, false | Set the animate option to `false` to prevent the slider from animating to a new value with when calling `.val()`

###### Slider behaviour

noUiSlider offers several ways to handle user interaction. The range can be set to drag, and handles can move to taps. All these effects are optional, and can be enable by adding their keyword to the `behaviour` option. This option accepts a "-" separated list of "drag", "tap", "fixed", "snap" or "none".

Behaviour | Description
--- | ---
`drag` | Make the range draggable. Handles are always draggable
`drag-fixed` | The range is draggable. The range width can't be changed, so dragging one handle will move the other, too
`tap` | Make the closest handle when the slider gets tapped
`tap-drag` | Make the closest handle jump when the slider bar is tapped, make the range draggable
`none` | Turn off all behaviour, except for standard moving

###### Plugin info

Property | Description
--- | ---
File name | nouislider.min.js
Location | global_assets/js/plugins/sliders/
Links | Official plugin website Github project page

##### Image cropper

Media cropper.min.js

###### Overview

A simple jQuery image cropping plugin with enhanced features and suppot of: options, methods, events, touch devices, zomoing, rotation, scale, canvas and multiple croppers on the page.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/media/cropper.min.js"></script>

Wrap the image or canvas element with a block element:

    <!-- Basic markup -->
    <div class="container">
    	<img src="picture.jpg">
    </div>

Finally call the plugin via JavaScript:

    // Initialize
    $('.container > img').cropper({
    	aspectRatio: 16 / 9,
    	crop: function(e) {
    		// Output the result data for cropping image.
    		console.log(e.x);
    		console.log(e.y);
    		console.log(e.width);
    		console.log(e.height);
    		console.log(e.rotate);
    		console.log(e.scaleX);
    		console.log(e.scaleY);
    	}
    });

###### Plugin options

You may set cropper options with `$().cropper(options)`. If you want to change the global default options, you may use `$.fn.cropper.setDefaults(options)`.

Option | Default | Description
--- | --- | ---
`aspectRatio` | NaN | Number. Set the aspect ratio of the crop box. By default, the crop box is free ratio
`data` | null | Object. The previous cropped data if you had stored, will be passed to `setData` method automatically
`preview` | '' | String. Add extra elements (containers) for previewing
`strict` | true | Boolean. In strict mode, the canvas (image wrapper) cannot be smaller than the container, and the crop box cannot be outside of the canvas (image wrapper)
`responsive` | true | Boolean. Rebuild the cropper when resize the window
`checkImageOrigin` | true | Boolean. By default, the plugin will check the image origin, and if it is a cross-origin image, a `crossOrigin` attribute will be added to the image element and a timestamp will be added to the image url to reload the image for `"getCroppedCanvas"`. By adding `crossOrigin` attribute to image will stop adding timestamp to image url, and stop reload of image
`modal` | true | Boolean. Show the black modal above the image and under the crop box
`guides` | true | Boolean. Show the dashed lines above the crop box
`center` | true | Boolean. Show the center indicator above the crop box
`highlight` | true | Boolean. Show the white modal above the crop box (highlight the crop box)
`background` | true | Boolean. Show the grid background of the container
`autoCrop` | true | Boolean. Enable to crop the image automatically when initialize
`autoCropArea` | 0.8 (80% of the image) | Number. A number between `0` and `1`. Define the automatic cropping area size (percentage)
`dragCrop` | true | Boolean. Enable to remove the current crop box and create a new one by dragging over the image
`movable` | true | Boolean. Enable to move the image
`rotatable` | true | Boolean. Enable to rotate the image
`scalable` | true | Boolean. Enable to scale the image
`zoomable` | true | Boolean. Enable to zoom the image
`mouseWheelZoom` | true | Boolean. Enable to zoom the image by wheeling mouse
`wheelZoomRatio` | 0.1 | Number. Define zoom ratio when zoom the image by wheeling mouse
`touchDragZoom` | true | Boolean. Enable to zoom the image by dragging touch
`cropBoxMovable` | true | Boolean. Enable to move the crop box
`cropBoxResizable` | true | Boolean. Enable to resize the crop box
`doubleClickToggle` | true | Boolean. Enable to toggle drag mode between `"crop"` and `"move"` when double click on the cropper
`minContainerWidth` | 200 | Number. The minimum width of the container
`minContainerHeight` | 100 | Number. The minimum height of the container
`minCanvasWidth` | 0 | Number. The minimum width of the canvas (image wrapper)
`minCanvasHeight` | 0 | Number. The minimum height of the canvas (image wrapper)
`minCropBoxWidth` | 0 | Number. The minimum width of the crop box
`minCropBoxHeight` | 0 | Number. The minimum height of the crop box
`build` | null | Function. A shortcut of the `"build.cropper"` event
`built` | null | Function. A shortcut of the `"built.cropper"` event
`cropstart` | null | Function. A shortcut of the `"cropstart.cropper"` event
`cropmove` | null | Function. A shortcut of the `"cropmove.cropper"` event
`cropend` | null | Function. A shortcut of the `"cropend.cropper"` event
`crop` | null | Function. A shortcut of the `"crop.cropper"` event
`zoom` | null | Function. A shortcut of the `"zoom.cropper"` event

###### Plugin events

Example usage:

    // Events example
    $().on('cropstart.cropper', function (e) {
    	console.log(e.type); // cropstart
    	console.log(e.namespace); // cropper
    	console.log(e.action); // ...
    	console.log(e.originalEvent.pageX);

    	// Prevent to start cropping, moving, etc if necessary
    	if (e.action === 'crop') {
    		e.preventDefault();
    	}
    });

Available events:

Option | Description
--- | ---
`build.cropper` | This event fires when a cropper instance starts to load an image
`built.cropper` | This event fires when a cropper instance has built completely
`cropstart.cropper` | This event fires when the canvas (image wrapper) or the crop box starts to change
`cropmove.cropper` | This event fires when the canvas (image wrapper) or the crop box is changing
`cropend.cropper` | This event fires when the canvas (image wrapper) or the crop box stops to change
`crop.cropper` | This event fires when the canvas (image wrapper) or the crop box changed
`zoom.cropper` | This event fires when a cropper instance starts to zoom in or zoom out its canvas (image wrapper)

###### Plugin info

Property | Description
--- | ---
File name | cropper.min.js
Location | global_assets/js/plugins/media/
Links | Official plugin website Full documentation Github project page

##### Fancybox

Media fancybox.min.js

###### Overview

FancyBox is a tool that offers a nice and elegant way to add zooming functionality for images, html content and multi-media on your webpages. It is built on the top of the popular JavaScript framework jQuery and is both easy to implement and a snap to customize.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/media/fancybox.min.js"></script>

Create link elements whose href attributes will contain the path of the element you wish to open within the fancyBox:

    <!-- Image 1 -->
    <a class="fancybox" rel="group" href="big_image_1.jpg">
    	<img src="small_image_1.jpg" alt="">
    </a>

    <!-- Image 1 -->
    <a class="fancybox" rel="group" href="big_image_2.jpg">
    	<img src="small_image_2.jpg" alt="">
    </a>

Finally call the plugin via JavaScript:

    // Initialize
    $(document).ready(function() {
    	$(".fancybox").fancybox({
    		// options
    	});
    });

###### Plugin options

You can pass these options as key/value object to `fancybox()` method. It is also possible to modify defaults directly at fancyBox JS file or `$.fancybox.defaults`

Option | Default | Description
--- | --- | ---
`padding` | 15 | Space inside fancyBox around content. Can be set as array - `[top, right, bottom, left]`
`margin` | 20 | Minimum space between viewport and fancyBox. Can be set as array - `[top, right, bottom, left]`. Right and bottom margins are ignored if content dimensions exceeds viewport
`width` | 800 | Default width for `'iframe'` and `'swf'` content. Also for 'inline', 'ajax' and 'html' if 'autoSize' is set to 'false'. Can be `numeric` or `'auto'`.
`height` | 600 | Default height for `'iframe'` and `'swf'` content. Also for 'inline', 'ajax' and 'html' if 'autoSize' is set to 'false'. Can be `numeric` or `'auto'`
`minWidth` | 100 | Minimum width fancyBox should be allowed to resize to
`minHeight` | 100 | Minimum height fancyBox should be allowed to resize to
`maxWidth` | 9999 | Maximum width fancyBox should be allowed to resize to
`maxHeight` | 9999 | Maximum height fancyBox should be allowed to resize to
`autoSize` | true | If `true`, then sets both `autoHeight` and `autoWidth` to `true`
`autoHeight` | false | If set to true, for `'inline'`, `'ajax'` and `'html'` type content width is auto determined. If no dimensions set this may give unexpected results
`autoWidth` | false | If set to `true`, for `'inline'`, `'ajax'` and `'html'` type content height is auto determined. If no dimensions set this may give unexpected results
`autoResize` | !isTouch | If set to `true`, the content will be resized after window resize event
`autoCenter` | !isTouch | If set to `true`, the content will always be centered
`fitToView` | true | If set to `true`, fancyBox is resized to fit inside viewport before opening
`aspectRatio` | false | If set to `true`, resizing is constrained by the original aspect ratio (images always keep ratio)
`topRatio` | 0.5 | Top space ratio for vertical centering. If set to `0.5`, then vertical and bottom space will be equal. If `0` - fancyBox will be at the viewport top
`leftRatio` | 0.5 | Left space ratio for horizontal centering. If set to `0.5`, then left and right space will be equal. If `0` - fancyBox will be at the viewport left
`scrolling` | 'auto' | Set the overflow CSS property to create or hide scrollbars. Can be set to 'auto', 'yes', 'no' or 'visible'
`wrapCSS` | - | Customizable CSS class for wrapping element (useful for custom styling)
`arrows` | true | If set to `true`, navigation arrows will be displayed
`closeBtn` | true | If set to `true`, close button will be displayed
`closeClick` | false | If set to `true`, fancyBox will be closed when user clicks the content
`nextClick` | false | If set to `true`, will navigate to next gallery item when user clicks the content
`mouseWheel` | true | If set to `true`, you will be able to navigate gallery using the mouse wheel
`autoPlay` | false | If set to `true`, slideshow will start after opening the first gallery item
`playSpeed` | 3000 | Slideshow speed in milliseconds
`preload` | 3 | Number of gallery images to preload
`modal` | false | If set to `true`, will disable navigation and closing
`loop` | true | If set to `true`, enables cyclic navigation. This means, if you click `"next"` after you reach the last element, first element will be displayed (and vice versa)
`ajax` | - | Options for ajax request: `dataType` and `headers`
`iframe` | - | Options for content type "iframe": `scrolling` and `preload`
`swf` | - | Options for content type "swf": `wmode`, `allowfullscreen` and `allowscriptaccess`
`keys` | - | Define keyboard keys for gallery navigation, closing and slideshow
`direction` | - | Default navigation direction (for navigation arrows, too): `next` and `prev`
`scrollOutside` | true | If `true`, the script will try to avoid horizontal scrolling for iframes and html content
`index` | 0 | Overrides group start index
`type` | null | Overrides type for content. Supported types are `'image'`, `'inline'`, `'ajax'`, `'iframe'`, `'swf'` and `'html'`
`href` | null | Overrides content source link
`content` | null | Overrides content to be displayed
`title` | null | Overrides title content, accepts any HTML
`live` | true | If set to `true`, fancyBox uses `"live"` to assign click event. Set to `false`, if you need to apply only to current collection
`parent` | 'body' | Parent element of the container

###### Plugin info

Property | Description
--- | ---
File name | fancybox.min.js
Location | global_assets/js/plugins/media/
Links | Official plugin website Full documentation Github project page

##### Bootstrap progress bar

Styling progressbar.min.js

###### Overview

Bootstrap progressbar is a jQuery plugin which extends the basic bootstrap progressbar. It provides the ability to animate the progressbar by adding Javascript in combination with the preexisting css transitions. Additionally you can display the current progress information in the bar or get the value via callback.

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load jQuery -->
    <script src="../../../../global_assets/js/main/jquery.min.js"></script>

    <!-- Load Bootstrap -->
    <script src="../../../../global_assets/js/main/bootstrap.min.js"></script>

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/loaders/progressbar.min.js"></script>

Set the `aria` attribute and remove the `width` style attribute (alternatively you can set it to 0):

    // Basic markup
    <div class="progress">
    	<div class="progress-bar" data-transitiongoal="75" aria-valuemin="-1337" aria-valuemax="9000"></div>
    </div>

Finally call the plugin via JavaScript:

    // Initialize
    $('.progress .progress-bar').progressbar({
    	// options
    });

###### Plugin options

Option | Default | Description
--- | --- | ---
`transition_delay` | 300 | Is the time in milliseconds until the animation starts
`refresh_speed` | 50 | Is the time in milliseconds which will elapse between every text refresh, `aria-valuenow` attribute update and update callback call
`display_text` | 'none' | Determines if and where to display text on the progressbar. Possible options: none, fill and center
`use_percentage` | true | If text will be displayed - this option determines whether to show the percentage value or the amount. So if `use_percentage` is `false` and `aria-valuemin` and `aria-valuemax` are not set (or to 0 and 100) the value will be the same but `amount_format` will be used to format the result
`percent_format` | function(percent) { return percent + '%'; } | Is a function which returns the text format for progressbar with `use_percentage: true`. It takes 1 argument which is the current percent value
`amount_format` | function(amount_part, amount_total) { return amount_part + ' / ' + amount_total; } | Is a function which returns the text format for progressbar with `use_percentage: false`. It takes 3 argument which are the current-, the max- and the min-amount
`update` | $.noop | Is a callback function which will be called while the progressbar is transitioning. Depends on `refresh_speed`. It takes 2 argument which is the current percent value and a reference to the attached progressbar element
`done` | $.noop | Is a callback function which will be called when the transition process is done. It takes 1 argument which is a reference to the attached progressbar element.
`fail` | $.noop | Is a callback function which will be called when an error occurs. It takes 1 argument which is the error message

###### Plugin info

Property | Description
--- | ---
File name | progressbar.min.js
Location | global_assets/js/plugins/loaders/
Links | Official plugin website Demonstration Github project page

##### Ladda buttons

Styling ladda.min.js

###### Overview

A UI concept which merges loading indicators into the action that invoked them. Primarily intended for use with forms where it gives users immediate feedback upon submit rather than leaving them wondering while the browser does its thing

###### Usage

Note: You need to include both `ladda.min.js` and `spin.min.js` files, because these 2 libraries work together.

Ladda buttons must be given the class ladda-button and the button label needs to have the ladda-label class. The ladda-label will be automatically created if it does not exist in the DOM. Below is an example of a button which will use the expand-right animation style:

    <!-- Markup -->
    <button class="ladda-button" data-style="expand-right">
    	<span class="ladda-label">Submit</span>
    </button>

If you will be using the loading animation for a form that is submitted to the server (always resulting in a page reload) you can use the `ladda('bind')` method:

    // Automatically trigger the loading animation on click
    $( 'input[type=submit]' ).ladda( 'bind' );

    // Same as the above but automatically stops after two seconds
    $( 'input[type=submit]' ).ladda( 'bind', { timeout: 2000 } );

If you want JavaScript control over your buttons you can use the following approach:

    // Create a new instance of ladda for the specified button
    var l = $( '.my-button' ).ladda();

    // Start loading
    l.ladda( 'start' );

    // Will display a progress bar for 50% of the button width
    l.ladda( 'setProgress', 0.5 );

    // Stop loading
    l.ladda( 'stop' );

    // Toggle between loading/not loading states
    l.ladda( 'toggle' );

    // Check the current state
    l.ladda( 'isLoading' );

    // Stop all loading animations
    $.ladda( 'stopAll' );

###### Options

Option | Value | Description
--- | --- | ---
`data-style` | expand-* (left, right, up, down) slide-* (left, right, up, down) contract, contract-overlay zoom-in, zoom-out | One of the button styles. This option is required
`data-spinner-size` | 40 | Pixel dimensions of spinner, defaults to dynamic size based on the button height
`data-spinner-color` | true | A hex code or any named CSS color
`data-spinner-lines` | 12 | The number of lines the for the spinner, defaults to 12

###### Plugin info

Property | Description
--- | ---
File name | ladda.min.js, spin.min.js
Location | global_assets/js/plugins/buttons/
Links | Official plugin website Github project page

##### Dragula - drag and drop

UI dragula.min.js

###### Overview

Dragula - drag and drop library that just works. It doesn't just depend on bloated frameworks and actually understands where to place the elements when they are dropped. And it doesn't need you to do a zillion things to get it to work. Dragula provides the easiest possible API to make drag and drop a breeze in your applications. Key library features:

- Super easy to set up
- No bloated dependencies
- Figures out sort order on its own
- A shadow where the item would be dropped offers visual feedback
- Touch events!
- Seamlessly handles clicks without any configuration

###### Usage

Include the following lines of code in the `<head>` section of your HTML:

    <!-- Load plugin -->
    <script src="../../../../global_assets/js/plugins/ui/dragula.min.js"></script>

By default, dragula will allow the user to drag an element in any of the containers and drop it in any other container in the list. If the element is dropped anywhere that's not one of the containers, the event will be gracefully cancelled according to the `revertOnSpill` and `removeOnSpill` options.

    <!-- Left container -->
    <div id="left">
    	...
    </div>
    <!-- /left container -->

    <!-- Right container -->
    <div id="right">
    	...
    </div>
    <!-- /right container -->

Call the plugin via JavaScript:

    // Initialize
    dragula([
    	document.querySelector('#left'),
    	document.querySelector('#right')
    ]);

###### Plugin options

You can also provide an options object. Here's an overview of the default values:

    // Defaults
    dragula(containers, {
    	isContainer: function (el) {
    		return false; // only elements in drake.containers will be taken into account
    	},
    	moves: function (el, source, handle, sibling) {
    		return true; // elements are always draggable by default
    	},
    	accepts: function (el, target, source, sibling) {
    		return true; // elements can be dropped in any of the `containers` by default
    	},
    	invalid: function (el, target) {
    		return false; // don't prevent any drags from initiating by default
    	},
    	direction: 'vertical',             // Y axis is considered when determining where an element would be dropped
    	copy: false,                       // elements are moved by default, not copied
    	copySortSource: false,             // elements in copy-source containers can be reordered
    	revertOnSpill: false,              // spilling will put the element back where it was dragged from, if this is true
    	removeOnSpill: false,              // spilling will `.remove` the element, if this is true
    	mirrorContainer: document.body,    // set the element that gets mirror elements appended
    	ignoreInputTextSelection: true     // allows users to select input text, see details below
    });

###### Plugin options

Option | Description
--- | ---
`options.containers` | Setting this option is effectively the same as passing the containers in the first argument to `dragula(containers, options)`
`options.isContainer` | Besides the containers that you pass to dragula, or the containers you dynamically push or unshift from `drake.containers`, you can also use this method to specify any sort of logic that defines what is a container for this particular `drake` instance.
`options.moves` | You can define a `moves` method which will be invoked with (`el`, `source`, `handle`, `sibling`) whenever an element is clicked. If this method returns `false`, a drag event won't begin, and the event won't be prevented either. The `handle` element will be the original click target, which comes in handy to test if that element is an expected "drag handle".
`options.accepts` | You can set `accepts` to a method with the following signature: (`el`, `target`, `source`, `sibling`). It'll be called to make sure that an element `el`, that came from container `source`, can be dropped on container target before a sibling element. The `sibling` can be `null`, which would mean that the element would be placed as the last element in the container
`options.copy` | If `copy` is set to `true` (or a method that returns `true`), items will be copied rather than moved
`options.copySortSource` | If `copy` is set to `true` (or a method that returns `true`) and `copySortSource` is `true` as well, users will be able to sort elements in copy-source containers
`options.revertOnSpill` | By default, spilling an element outside of any containers will move the element back to the drop position previewed by the feedback shadow. Setting `revertOnSpill` to `true` will ensure elements dropped outside of any approved containers are moved back to the source element where the drag event began, rather than stay at the drop position previewed by the feedback shadow
`options.removeOnSpill` | By default, spilling an element outside of any containers will move the element back to the drop position previewed by the feedback shadow. Setting `removeOnSpill` to `true` will ensure elements dropped outside of any approved containers are removed from the DOM
`options.direction` | When an element is dropped onto a container, it'll be placed near the point where the mouse was released. If the `direction` is `'vertical'`, the default value, the Y axis will be considered. Otherwise, if the direction is `'horizontal'`, the X axis will be considered
`options.invalid` | You can provide an `invalid` method with a (`el`, `target`) signature. This method should return `true` for elements that shouldn't trigger a drag
`options.mirrorContainer` | The DOM element where the mirror element displayed while dragging will be appended to. Defaults to `document.body`
`options.ignoreInputTextSelection` | When this option is enabled, if the user clicks on an input element the drag won't start until their mouse pointer exits the input. This translates into the user being able to select text in inputs contained inside draggable elements, and still drag the element by moving their mouse outside of the input -- so you get the best of both worlds

###### Plugin events

Event Name | Listener Arguments | Event Description
--- | --- | ---
`drag` | `el, source` | `el` was lifted from `source`
`dragend` | `el` | Dragging event for `el` ended with either `cancel`, `remove`, or `drop`
`drop` | `el, target, source, sibling` | `el` was dropped into `target` before a `sibling` element, and originally came from `source`
`cancel` | `el, container, source` | `el` was being dragged but it got nowhere and went back into `container`, its last stable parent; `el` originally came from `source`
`remove` | `el, container, source` | `el` was being dragged but it got nowhere and it was removed from the DOM. Its last stable parent was `container`, and originally came from `source`
`shadow` | `el, container, source` | `el`, the visual aid shadow, was moved into `container`. May trigger many times as the position of `el` changes, even within the same `container`; `el` originally came from `source`
`over` | `el, container, source` | `el` is over `container`, and originally came from `source`
`out` | `el, container, source` | `el` was dragged out of `container` or dropped, and originally came from `source`
`cloned` | `clone, original, type` | DOM element `original` was cloned as `clone`, of `type` (`'mirror'` or `'copy'`). Fired for mirror images and when `copy: true`

###### Plugin info

Property | Description
--- | ---
File name | dragula.min.js
Location | global_assets/js/plugins/ui/
Links | Official plugin website Github project page