Backbone.Model exemple

Démonstration d'une écoute sur l'évènement 'change' d'un modèle Backbone. http://www.atinux.fr

by Atinux

HTML

<link rel="stylesheet" href="https://raw.github.com/raphaelgoetter/KNACSS/master/css/knacss.css">
<link rel="stylesheet" href="https://raw.github.com/necolas/css3-github-buttons/master/gh-buttons.css">
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="http://documentcloud.github.com/backbone/backbone-min.js"></script>
<div id="content">
    <div id="search">
      Library : <input type="text" name="q" placeholder="jQuery, backbone.js..." class="q" /> <button class="button icon add">Add library</button>
    </div>
    <div id="edition"></div>
    <div id="listing">
      <div class="info">Searching...</div>
      <div class="libs"></div>
    </div>
  </div>
  <script type="text/template" id="ListingEntryTemplate">
    <img src="<%- this.model.get('image') %>" />
    <div class="infos">
      <b><%- this.model.get('name') %></b>
      <a href="<%- this.model.get('website') %>" target="_blank" class="button icon home">Website</a><button class="button icon edit">Edit</button>
    </div>
  </script>
  <script type="text/template" id="EditionTemplate">
    <div style="padding: 10px;">
      <a class="close">x</a>
      Library name:<br/>
      <input type="text" value="<%- this.model.get('name') %>" name="name" placeholder="Spine.js, Underscore.js..." /><br/>
      Website:<br/>
      <input type="text" value="<%- this.model.get('website') %>" name="website" placeholder="https://github.com/mrdoob/three.js/..." /><br/>
      Image :<br/>
      <input type="text" value="<%- this.model.get('image') %>" name="image" placeholder="http://backbonejs.org/docs/images/backbone.png..." /><br/>
      <button class="button icon approve">Save</button> <button class="button icon remove danger">Remove</button>
    </div>
  </script>

CSS

/*
** Style by Atinux
*/
body {
  overflow-y: scroll;
}
#content {
  max-width: 800px;
  margin: auto;
}
#edition {
  background: rgb(227,227,227);
  font-size: 1.4em;
  line-height: 30px;
  position: relative;
  overflow: hidden;
  height: 0;
}
#edition .button {
  margin-top: 10px;
}
#edition .close {
  font-size: 1.1em;
  font-weight: bold;
  position: absolute;
  right: 10px;
  top: 10px;
  background: rgb(220,220,220);
  border: 1px solid rgb(210,210,210);
  display: inline-block;
  padding: 5px;
  line-height: 12px;
  color: rgb(80,80,80);
  cursor: pointer;
}
#edition .close:hover {
  background: rgb(210,210,210);
  color: rgb(60,60,60);
}
#listing {
  font-size: 1.4em;
}
#listing .info {
  padding: 10px;
  text-align: center;
  color: rgb(80,80,80);
}
#listing .libs {
  font-size: 1.4em;
   /* Prevent vertical gaps */
   line-height: 0;
   -webkit-column-count: 3;
   -webkit-column-gap:   0px;
   -moz-column-count:    3;
   -moz-column-gap:      0px;
   column-count:         3;
   column-gap:           0px;
}

#listing .libs > div {
  margin: 5px;
  position: relative;
  border: 2px rgb(200,200,200) solid;
}
#listing .libs > div .infos {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  text-align: center;
  height: 40px;
  font-size: 1.2em;
  opacity: 0;
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
  transition: all 0.2s ease;
}
#listing .libs > div .infos b {
  font-size: 0.7em;
  display: block;
  margin-bottom: 15px;
}
#listing .libs img {
  width: 100% !important;
  height: auto !important;
  min-height: 70px;
  background: rgb(230,230,230);
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
  transition: all 0.2s ease;
}
#listing .libs > div:hover {
  border: 2px rgb(220,220,220) solid;
}
#listing .libs > div:hover img {
  opacity: 0.1;
}
#listing .libs > div:hover .infos {
  opacity: 1;
}

#search {
 ...

JavaScript

// Namespace
window.app = {
  API: 'http://api-as-a-service.jit.su/api',
  Views: {},
  Models: {},
  e: _.extend({}, Backbone.Events),
  callAPI: function (params) {
    var url = (typeof(params) === 'string' ? params : params.url),
        data = params.data || {},
        type = params.type || params.method || 'GET';
    if (type === 'GET') {
      data = $.param(data);
      return $.getJSON(url, data);
    }
    data = JSON.stringify(data);
    return $.ajax({
      url: url,
      contentType: 'application/json',
      dataType: 'json',
      data: data,
      type: type
    });
  },
  init: function () {
    // Init views
    // ** search
    new app.Views.Search();
    // ** listing
    new app.Views.Listing();
    // ** edition
    new app.Views.Edition();
  }
};

// Model
app.Models.Library = Backbone.Model.extend({
  defaults: {
    name: 'Library name missing',
    website: 'http://www.atinux.fr',
    image: 'https://encrypted-tbn0.google.com/images?q=tbn:ANd9GcReILs3s72cLDuX2EqaIiIM_3KtUW9rtDKJujLJhvEHeKerHw3x'
  }
});

// Views
// ** Search
app.Views.Search = Backbone.View.extend({
  initialize: function () {
    this.search();
  },
  el: '#search',
  events: {
    'keyup input': 'search',
    'click .add': 'addLibrary'
  },
  search: function (e) {
    var params = {};
    params.q = this.$('.q').val();
    // Trigger a "search" event
    app.e.trigger('search', params);
    // call API to get matching results
    app.callAPI({
      url: app.API + '/libraries',
      data: params
    })
    .success(function (res) {
      app.e.trigger('searchResults', null, res);
    })
    .error(function (err) {
      app.e.trigger('searchResults', err);
    });
  },
  addLibrary: function (e) {
    app.e.trigger('add');
  }
});
// ** Listing
app.Views.Listing = Backbone.View.extend({
  el: '#listing',
  initialize: function () {
    _.bindAll(this);
    
    this.$info = this.$('.info');
    this.$libs = this.$('.libs');
    
    app.e.on('search',...