# Nito

**A jQuery library for building user interfaces.**

By establishing a *declarative approach* with *pure updates*,
Nito's helpers and conventions make jQuery applications
modular and maintainable.


## Quick Tour

Setting up Nito is as simple as including jQuery:

```html
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://cdn.rawgit.com/morris/nito/v2.0.0/nito.min.js"></script>
```

With Nito, HTML is just HTML&mdash;no sugar required.
Use semantic classes and templates as needed.
For example, a todo app's base HTML could look like this:

```html
<div class="todo">
  <h1>Todo</h1>
  <ul class="items">
    <li class="item"> <!-- This <li> is a template used by .nest() -->
      <strong class="title">Example item</strong>
    </li>
  </ul>
</div>
```

We can now add behavior by defining *mount* functions.
These functions can do anything to setup behavior
but should follow a few conventions:

- Minimize state and keep it outside the DOM
- Only do DOM manipulation on an `update` event
- Make the `update` handler *pure*, i.e. independent of prior state and complete
- Change state on application events and trigger updates with `.update()`

```js
function Todo( $el ) {

  // some state, minimized and outside the DOM
  var items = [
    { title: 'Get Nito', completed: false },
    { title: 'Create something', completed: false }
  ];

  $el.on( 'update', update );
  $el.on( 'todo-toggle', toggle );

  function update() {
    // The "update" event should be the only place with DOM manipulation
    // Repeat item HTML for each item, reusing existing DOM
    $el.find( '.items' ).nest( items );
  }

  function toggle( e, item ) {
    // Modify state and trigger pure update
    item.completed = !item.completed;
    $el.update();
  }

}

function TodoItem( $el ) {

  $el.on( 'update', update );
  $el.on( 'click', toggle );

  function update() {
    // Set title and toggle "completed" class
    // DOM is only manipulated if item has changed since last update
    var item = $el.data( 'item' );
    $el.find( '.title' ).ftext( item.title );
    $el.classes( { completed: item.completed } );
  }

  function toggle() {
    $el.trigger( 'todo-toggle', $el.data( 'item' ) );
  }

}
```

Note the `nest` helper which repeats the `<li>` template for each given item.
The `classes` and `ftext` helpers apply changes softly,
i.e. only if the existing DOM differs.

Also note how the definitions are entirely decoupled from the current document,
and don't do anything by themselves.
To take effect we have to *mount* them on elements in the document:

```js
$( 'body' ).mount( '.todo', Todo );
$( 'body' ).mount( '.todo .item', TodoItem );
```

Mounting is *declarative*:
The above ensures that any elements matching `.todo` and `.todo .item`
are mounted with `Todo` and `TodoItem` exactly once,
*regardless of how and when they are added to the document.*

This is key to make jQuery modules viable.
Functionality can be entirely wrapped in mount functions&mdash;mounting
and updating happens automatically under the hood.


## Examples

### [Todo](https://cdn.rawgit.com/morris/nito/v2.0.0/examples/todo/)

A simple client-side todo app with TodoMVC-like features.


## Core

At its core, Nito allows to declare the behavior of elements
*now and in the future.*
Additionally, using `update` events for pure UI updates and
any DOM manipulation simplifies reasoning about the interface state
at any point in time.

#### `$scope.mount( selector, fn )`

- Ensure that any element under `$scope` matching `selector` is mounted
  with `fn` exactly once, *now and in the future*
- `fn` is called on each matching element, with `$( el )` as its only argument
- This also applies to elements appended in the future
- Mounting may take place immediately or in the next frame
- Return `$scope`

#### `$els.update()`

- Enqueue an `update` event on each element in `$els`
- Elements receive at most one `update` event per frame
- Return `$els`

#### `$els.dispatch( type, data )`

- Trigger an event in the next frame
- Useful in situations where mounting may not be safely finished
- Return `$els`


## Nesting

Efficiently nest elements in any container using `nest` or `nestOne`.
Use these functions on `update`, *not* at mount-time.

#### `$els.nest( items, base )`

- Nest a `base` element for each item
- Populate `$el.data( 'item' )` with each respective item
- If `base` is omitted, cache the first child in the container as `base`
- `$els` should only have children generated by `nest`
- Return `$els`

```js
$( '<ul></ul>' ).nest( [
  { title: 'Write code', done: true },
  { title: 'Write readme', done: false }
], '<li class="item"></li>' );
```

#### `$els.nestOne( item, base )`

- Same as `nest`, but for one item
- Pass falsy item to not nest anything
- Return `$els`


## Manipulation

The following methods are helpful and/or speed optimized
for usage on `update` events.

#### `$els.classes( map )`

- Set classes on `$els` softly
- Classes not present in map are not touched
- Function values are computed using each element as `this`
- Return `$els`

```js
$( '.form-group' ).classes( {
  'has-success': true,
  'has-error': false
} );
```

#### `$els.fhtml( html )`

- Set inner HTML in `$els` softly
- Faster than `$els.html`
- Return `$els`

#### `$els.ftext( text )`

- Set text content in `$els` softly
- Faster than `$els.text`
- Return `$els`


## Forms

#### `$els.serializeData()`

- Serialize named form controls in `$els` into an object
- Supports all controls and nested names like `object[key]`, `array[index]`, `multiple[]`
- Checkboxes are serialized with their `value`, or `'on'` if no value is present
- Return an object containing the values

#### `$els.fill( data )`

- Fill named form controls in `$els` with given data (JSON-like)
- Supports all controls and nested data
- Return `$els`

```js
$( '[name]' ).fill( {
  title: 'Nito',
  description: '...'
} );
```

#### `$els.fillDef( data )`

- Same as `fill` but for default values
- Return `$els`

#### `$els.fval( value )`

- Set form control value in `$els` softly
- User input will be overwritten
- Form defaults are not modified
- Return `$els`

#### `$els.fdef( value )`

- Set default form control value in `$els` softly
- Modifies DOM attributes like `value` and `selected`, *not* the properties
- Inputs modified by the user will still reflect the user input
- Return `$els`

#### `$els.reset()`

- Reset each form or individual form control in `$els` (without children)
- Return `$els`
