Skip to content

Instantly share code, notes, and snippets.

@k33g
Created August 23, 2012 08:59
Show Gist options
  • Save k33g/3434421 to your computer and use it in GitHub Desktop.
Save k33g/3434421 to your computer and use it in GitHub Desktop.
Dart, first steps

#Ebauche d'un framework MVC (Client) en Dart

##Installation

##Créer un 1er projet

Nommer le projet "cubitus", modifier cubitus.html

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <title>Cubitus</title>
    <link rel="stylesheet" href="cubitus.css">
  </head>
  <body>

	<p></p>

    <script type="application/dart" src="cubitus.dart"></script>
    <script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
  </body>
</html>

##Créer une librairie

C'est un fichier .dart avec une déclaration en en-tête de code : #library("nom_de_la_librairie"). Ensuite pour la référencer dans un code source, on utilise : #import("chemin_et_nom_du_fichier_dart_de_la_librairie").

###cubitus.mvc.dart et 1ère classe "Model"

Créez un fichier cubitus.mvc.dart avec le code ci-dessous. Notre classe Model ne fait pas grand chose, si ce n'est recevoir une map d'attributs comme paramètre du constructeur, et avoir 2 méthodes pour affecter ou récupérer la valeur d'un attribut ("à la" Backbone) :

#library("cubitusmvc");
#import('dart:json');

class Model {
  Map attributes;
  
  //Constructeur
  Model(this.attributes) {
    
  }
  
  Object get(String attributeName) {
    return this.attributes[attributeName];
  }
  
  void set(String attributeName, Object value) {
    this.attributes[attributeName] = value;
  }

  String toJSON() {
    return JSON.stringify(this.attributes);
  }
}

##1ère Utilisation de notre librairie

Dans le fichier principal cubitus.dart :

#import('dart:html');
#import('cubitus.mvc.dart');

class Human extends Model {
  Human(attrs) : super(attrs) {}
}


void main() {
  
  var p = query("p");
  
  var bob = new Human({"firstName":"Bob", "lastName":"Morane"});
  
  print(bob.toJSON());
  
  bob.set("firstName","Bobby");
  
  print(bob.toJSON());
  
  p.innerHTML = """
    <b>FirstName : </b>${bob.get("firstName")}<br>
    <b>LastName : </b>${bob.get("lastName")}
  """;
  
}

##Ajoutons une classe View à notre librairie cubitus.mvc.dart

Tout d'abord ajouter #import('dart:html');, puis le code de la classe View :

class View {
  Element e;
  String tpl;

  View(this.e) { }
  
  render() {
    this.e.innerHTML = this.tpl;
  }
  
}

###Utilisation de notre vue :

Dans le fichier principal cubitus.dart :

#import('dart:html');
#import('cubitus.mvc.dart');

class Human extends Model {
  Human(attrs) : super(attrs) {}

  sayHello() {
    print(this.toJSON());
  }
}

class HumanView extends View {
  HumanView(el) : super(el) {}
  
  View useSingleModelTemplate(Model data) {
    this.tpl = """    
        <b>FirstName : </b>${data.get("firstName")}<br>
        <b>LastName : </b>${data.get("lastName")}
    """;
    return this;
  }

}

void main() {
  
  var p = query("p");
  
  var bob = new Human({"firstName":"Bob", "lastName":"Morane"});
  var humanView = new HumanView(p);
   
  bob.set("firstName","Bobby");
  
  humanView.useSingleModelTemplate(bob).render();
    
}

##Collection (à la Backbone) et encore View

Dans cubitus.mvc.dart, ajouter :

class Models {
  List list;
  Models(this.list){  }
  
  List getList() {
    return this.list;
  }
  
  Models add(Model model) {
    this.list.add(model);
    return this;
  }

}

###Utilisation

Dans cubitus.html ajouter <ul></ul> après <p></p>, puis dans le fichier principal cubitus.dart :

Créer une class Humans qui hérite de Models :

class Humans extends Models {
  Humans(list) : super(list) {}
}

Modifier la vue HumanView en lui ajoutant une méthode useSeveralModelsTemplate :

class HumanView extends View {
  HumanView(el) : super(el) {}
  
  View useSingleModelTemplate(Model data) {
    this.tpl = """    
        <b>FirstName : </b>${data.get("firstName")}<br>
        <b>LastName : </b>${data.get("lastName")}
    """;
    return this;
  }
  
  View useSeveralModelsTemplate(Models data) {
    var html = new StringBuffer();
    data.getList().forEach((model) =>
      html.add("<li>${model.get("firstName")} ${model.get("lastName")}</li>"));
    this.tpl = html.toString();
    return this;
  }

}

####Utiliser :

Dans main() { ... } :

var humansList = new Humans([bob, sam, john]);
var u = query("ul");
var humansView = new HumanView(u);
humansView.useSeveralModelsTemplate(humansList).render();

##Le routeur "Router"

Nous allons faire très simple (pas de passage de paramètre dans l'url), dans cubitus.mvc.dart, ajouter :

class Router {
  Map routes;
  Router(this.routes) {
    window.on.popState.add((event) {
      var tmp = window.location.toString().split("#");
      if(tmp.length > 1) {
        print(tmp[1]);
        this.routes[tmp[1]]();
      } else {
        //root
        this.routes["root"]();
      }
    });
  }
}

##Utiliser notre routeur

Changer le code de main() dans cubitus.dart par :

void main() {

  var p = query("p")
  ,   u = query("ul")
  ,   bob = new Human({"firstName":"Bob", "lastName":"Morane"})
  ,   sam = new Human({"firstName":"Sam", "lastName":"LePirate"})
  ,   john = new Human({"firstName":"John", "lastName":"Doe"})
  ,   humansList = new Humans([bob, sam, john])
  ,   humanView = new HumanView(p)
  ,   humansView = new HumanView(u)
  ,   router;
  
  router = new Router({
    "/display/all" : () => humansView.useSeveralModelsTemplate(humansList).render(),
    "/display/bob" : () => humanView.useSingleModelTemplate(bob).render(),
    "root" : () => p.innerHTML = "<h1>Welcome !!!</h1>"
  });
  
}

##Conclusion

Je trouve Dart intéressant et agréable à utiliser, probablement plus "cadré" que Javascript, mais si on fait un effort, on peut faire autant de c... en Dart qu'en Javascript (vous remarquerez que même si elles existent, je n'ai pas eu besoin d'interface par exemple et je peux indifférement utiliser Model ou Human même si elles ont des signatures différentes).

Je vais continuer à creuser, mais pour le moment ma préférence reste à Javascript. Il n'y a pas d'interopérabilité entre Dart et Javascript et c'est un peu dommage. J'aurais préféré un système façon Coffeescript avec des accolades ;).

#import('dart:html');
#import('cubitus.mvc.dart');
class Human extends Model {
Human(attrs) : super(attrs) {}
sayHello() {
print(this.toJSON());
}
}
class Humans extends Models {
Humans(list) : super(list) {}
}
class HumanView extends View {
HumanView(el) : super(el) {}
View useSingleModelTemplate(Model data) {
this.tpl = """
<b>FirstName : </b>${data.get("firstName")}<br>
<b>LastName : </b>${data.get("lastName")}
""";
return this;
}
View useSeveralModelsTemplate(Models data) {
var html = new StringBuffer();
data.getList().forEach((model) =>
html.add("<li>${model.get("firstName")} ${model.get("lastName")}</li>"));
this.tpl = html.toString();
return this;
}
}
void main() {
var p = query("p")
, u = query("ul")
, bob = new Human({"firstName":"Bob", "lastName":"Morane"})
, sam = new Human({"firstName":"Sam", "lastName":"LePirate"})
, john = new Human({"firstName":"John", "lastName":"Doe"})
, humansList = new Humans([bob, sam, john])
, humanView = new HumanView(p)
, humansView = new HumanView(u)
, router;
router = new Router({
"/display/all" : () => humansView.useSeveralModelsTemplate(humansList).render(),
"/display/bob" : () => humanView.useSingleModelTemplate(bob).render(),
"root" : () => p.innerHTML = "<h1>Welcome !!!</h1>"
});
}
#library("cubitusmvc");
#import('dart:html');
#import('dart:json');
class Models {
List list;
Models(this.list){ }
List getList() {
return this.list;
}
Models add(Model model) {
this.list.add(model);
return this;
}
}
class Model {
Map attributes;
//Constructeur
Model(this.attributes) { }
Object get(String attributeName) {
return this.attributes[attributeName];
}
void set(String attributeName, Object value) {
this.attributes[attributeName] = value;
}
String toJSON() {
return JSON.stringify(this.attributes);
}
}
class View {
Element e;
String tpl;
View(this.e) { }
render() {
this.e.innerHTML = this.tpl;
}
}
class Router {
Map routes;
Router(this.routes) {
window.on.popState.add((event) {
var tmp = window.location.toString().split("#");
if(tmp.length > 1) {
print(tmp[1]);
this.routes[tmp[1]]();
} else {
//root
this.routes["root"]();
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment