# Tutorial

This tutorial uses [webpack](https://webpack.github.io/) as main dependency to bundle all files together.
It's not obligatory to use it, but It's recommended

If you use webpack we recommend you to use [webpack.ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/). This plugin is useful by letting you not to write ```require("coffeescript-ui/public/cui.js")``` in each file.

## Dependencies

**package.json**
```json
    {
     ...
     "devDependencies": {
        "coffee-loader": "^0.7.3",
        "coffee-script": "^1.12.7",
        "coffeescript-ui": "git+https://github.com/programmfabrik/coffeescript-ui.git",
        "css-loader": "^0.28.7",
        "node-sass": "^4.5.3",
        "sass-loader": "^6.0.2",
        "style-loader": "^0.18.2",
        "webpack": "^2.2.1"
      }
    }
```

## Get started
### Hello world

```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')
CUI.alert({text: "Hello world"})
```

### Main class

First of all, we create a main class which will be the input file of webpack. 
Also this class will have the responsibility of render the main structure of the site.

Inside that class we require **coffeescript-ui** so we can use its *ready* event and *dom.append* function.

**App.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')

class App
  constructor: ->
    body = "Hello world!"
    CUI.dom.append(document.body, body)
  
CUI.ready ->
    new App()
```

### Add a main layout

There is different types of layouts that we can use as main dom element. We use **VerticalLayout** as example.

**App.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')
  
class App
  constructor: ->
    body = new CUI.VerticalLayout
      top:
        content: new CUI.Label
          text: "Welcome to Coffeescript UI Tutorial"
      center:
        content: new CUI.Label
          icon: "fa-home"
          text: "Hello world"
      bottom:
        content: new CUI.Label
          text: "This is the bottom"
    CUI.dom.append(document.body, body)
  
CUI.ready ->
  new App()
```

### Add some styles

We create a **base.scss** inside *scss* directory and we require it in **App** class. 
After that we have to choose which classes our elements should use.

**App.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')
require('./scss/base.scss')
  
class App
  constructor: ->
    body = new CUI.VerticalLayout
      class: "tutorial-main-layout"
      top:
        class: "tutorial-main-layout-top"
        content: new CUI.Label
          text: "Welcome to Coffeescript UI Tutorial"
          icon: "fa-star"
      center:
        content: new CUI.Label
          icon: "fa-home"
          text: "Hello world"
      bottom:
        class: "tutorial-main-layout-bottom"
        content: new CUI.Label
          text: "This is the bottom"
    CUI.dom.append(document.body, body)
  
CUI.ready ->
  new App()
```

**scss/base.scss**
```scss
.tutorial-main-layout {
  background-color: #eef0f1;
}

.tutorial-main-layout-top {
  display: block;
  font-size: 20px;
}

.tutorial-main-layout-bottom {
  text-align: center;
  font-size: 10px
}
```
### Fetching data

It's easy to fetch data with *CUI.XHR*. Also we combine it with *CUI.Deferred* as an example, 
but It's not necesarry because the method *start()* of *CUI.XHR* class returns a CUI.Promise.

So, to separate responsibilities, we create a new class called "WeatherService". Its responsibility will be just fetch data from the api-rest.
(As an example, we get a json file instead of invoking a real api.)

**modules/weather/WeatherService.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
	
class WeatherService
	
  @urlService = "public/weather-service.json?city="
	
  @getWeather: (city) ->
    deferred = new CUI.Deferred()
	
    xhr = new CUI.XHR 
      url: @urlService + city
	
    xhr.start().done((response) =>
      deferred.resolve(response.data)
    )
	
    return deferred.promise()
	
module.exports = WeatherService
```

After that, we modify the main class so it can use this new class and get the data and render it.

**App.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')
require('./scss/base.scss')
  
WeatherService = require('./modules/weather/WeatherService.coffee')
  
class App
  constructor: ->
    body = new CUI.VerticalLayout
      class: "tutorial-main-layout"
      top:
        class: "tutorial-main-layout-top"
        content: new CUI.Label
          text: "Welcome to Coffeescript UI Tutorial"
          icon: "fa-star"
      center:
        content: new CUI.Label
          icon: "fa-spinner"
          text: "Fetching data..."
      bottom:
        class: "tutorial-main-layout-bottom"
        content: new CUI.Label
          text: "This is the bottom"
  
    @fetchAndRenderData(body)
  
    CUI.dom.append(document.body, body)
  
  fetchAndRenderData: (body) ->
    WeatherService.getWeather("Berlin").done((data) ->
      ul = CUI.dom.ul()
      temperature = CUI.dom.append(CUI.dom.li(), data.temperature)
      CUI.dom.append(ul, temperature)
      skytext = CUI.dom.append(CUI.dom.li(), data.skytext)
      CUI.dom.append(ul, skytext)
      humidity = CUI.dom.append(CUI.dom.li(), data.humidity)
      CUI.dom.append(ul, humidity)
  
      body.replace(ul, "center")
    )
  
CUI.ready ->
  new App()
```

The function **fetchAndRenderData** is responsible of invoke **WeatherService** and render the data. 
To render the data we use the method *append* of *VerticalLayout*, and we pass the "key" of which "slot" we want to replace. 
In this case we replace the *center* "slot", which has the "loading" message. 

Please, don't pay to much attention to **CUI.dom.append** invocations, because it's not the best way to render data.

### Create a new template

**CUI.dom.append** is an useful function, but it has to be the last resource to use. 
So, we will use a custom template to render our data and remove those CUI.dom.append functions.

The first step is to create a *html* file, which has all the html structure of our desired *template*.

The main element has to have a *data-template* attribute with the name of our template, and optionally is possible to add *slots* inside that element.
*Slots* are used to put values inside them, and each one needs a *data-slot* attribute to access them.


**modules/weather/weather.html**
```html
<div data-template="weather">
    <ul>
        <li>
            <label>Temperature:</label>
            <span data-slot="temperature"></span>
        </li>
        <li>
            <label>Skytext:</label>
            <span data-slot="skytext"></span>
        </li>
        <li>
            <label>Humidity:</label>
            <span data-slot="humidity"></span>
        </li>
    </ul>
</div>
```

Then, we create a class which will have all the responsibilities about "weather". 
This is not obligatory to use templates, but it's a good way to organise your code, and avoid having all the responsibilities in just a class.

**modules/weather/Weather.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
WeatherService = require('./WeatherService.coffee')
htmlTemplate = require('./weather.html')
 
CUI.Template.loadTemplateText(htmlTemplate);
 
class Weather extends CUI.Element
 
  initOpts: ->
    super()
    @addOpts
      city:
        mandatory: true
        check: String
 
  render: ->
    template = new CUI.Template
      name: "weather"
      map:
        temperature: true
        skytext: true
        humidity: true
 
    waitBlock = new CUI.WaitBlock(element: template)
    waitBlock.show()
 
    WeatherService.getWeather(@_city)
      .always =>
        waitBlock.destroy()
      .done((data) =>
        for key of template.map
          template.append(data[key], key)
      )
 
    template
 
module.exports = Weather
```

To wire our new template with our application is needed to use the function *CUI.Template.loadTemplateText*

This new class has two methods: *initOpts* and *render*. 
The first one is used by the constructor of our extended class *CUI.Element* and It's basically used to map all *options* and check for restrictions on those *options*.
In this case we add a restriction on *city* attribute, it must be a String and mandatory.

The function **render** is the responsible for invoke the service to fetch the data, use the new template to render the data obtained and then return the template.
As we know, **WeatherService.getWeather** is a promise, so the render method will return an empty template until the data is fetched. 
That's why we used a CUI element called **WaitBlock**. It basically render an spinner until we destroy it. 

The main class suffered some modifications in the wake of these changes.

**App.coffee**
```coffeescript
CUI = require("coffeescript-ui/public/cui.js")
require('coffeescript-ui/public/cui.css')
require('./scss/base.scss')
 
Weather = require('./modules/weather/Weather.coffee')
 
class App
  constructor: ->
    body = new CUI.VerticalLayout
      class: "tutorial-main-layout"
      top:
        class: "tutorial-main-layout-top"
        content: new CUI.Label
          text: "Welcome to Coffeescript UI Tutorial"
          icon: "fa-star"
      center:
        content: new Weather(city: "Berlin").render()
      bottom:
        class: "tutorial-main-layout-bottom"
        content: new CUI.Label
          text: "This is the bottom"
 
    CUI.dom.append(document.body, body)
 
CUI.ready ->
  new App()
```

**------In progress------**
