Permalink
Browse files

add a couple of examples

  • Loading branch information...
1 parent dc4a563 commit 8e41ddd2abb4bcd212d68a5be9b3b6993788e48a @politician committed Feb 14, 2012
Showing with 270 additions and 0 deletions.
  1. +69 −0 examples/example1.html
  2. +117 −0 examples/example2.html
  3. +84 −0 examples/lib/backbone.localStorage.js
View
69 examples/example1.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
+ <title>Example 1</title>
+
+ <!-- include source files here... -->
+ <script type="text/javascript" src="../lib/jquery.js"></script>
+ <script type="text/javascript" src="../lib/underscore.js"></script>
+ <script type="text/javascript" src="../lib/backbone.js"></script>
+ <script type="text/javascript" src="../lib/rj.min.js"></script>
+ <script type="text/javascript" src="../outback.js"></script>
+
+</head>
+<body id="fixture">
+
+ <h2>A trivial example</h2>
+
+ <p>This example demonstrates basic interactivity using the <i>enable</i>, <i>disable</i>, and <i>visible</i> bindings.</p>
+
+ <button id="show" data-bind="disable: @shouldShowMessage">Reveal Text</button>
+ <button id="reset" data-bind="enable: @shouldShowMessage">Reset</button>
+
+ <div data-bind="visible: @shouldShowMessage">
+ <p>You will see this message only when "shouldShowMessage" holds a true value.</p>
+ </div>
+
+ <script type="text/javascript">
+ var MainView = Backbone.View.extend({
+ el: '#fixture',
+
+ events: {
+ 'click #show': 'showMessage',
+ 'click #reset': 'hideMessage'
+ },
+
+ initialize: function() {
+ this.render();
+ },
+
+ render: function() {
+ Backbone.outback.bind(this);
+ },
+
+ remove: function() {
+ Backbone.outback.unbind(this);
+ },
+
+ showMessage: function() {
+ this.model.set("shouldShowMessage", true);
+ },
+
+ hideMessage: function() {
+ this.model.set("shouldShowMessage", false);
+ },
+
+ bindingSummary: function(summary) {
+ console.log(summary);
+ }
+ });
+
+ $(function () {
+ window.app = new MainView({
+ model: new Backbone.Model({shouldShowMessage: false})
+ });
+ });
+ </script>
+</body>
+</html>
View
117 examples/example2.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
+ <title>Example 2</title>
+
+ <!-- include source files here... -->
+ <script type="text/javascript" src="../lib/jquery.js"></script>
+ <script type="text/javascript" src="../lib/underscore.js"></script>
+ <script type="text/javascript" src="../lib/backbone.js"></script>
+ <script type="text/javascript" src="lib/backbone.localStorage.js"></script>
+ <script type="text/javascript" src="../lib/rj.min.js"></script>
+ <script type="text/javascript" src="../outback.js"></script>
+
+</head>
+<body id="fixture">
+
+ <h2>The "Hello, World" Example</h2>
+
+ <p>This example uses the <i>text</i> and <i>value</i> bindings to keep a span updated with the values of the form fields. The span is bound to a function on the view's model which is comparable to a Knockout computed observable (albeit, less magical).<p>
+
+ <p>First name: <input data-bind="value: @firstName" /></p>
+ <p>Last name: <input data-bind="value: @lastName" /></p>
+ <h3>Hello, <span data-bind="text: @fullName"> </span>!</h3>
+
+ <button id="exploit">Inject &lt;script&gt;</button>
+
+
+ <script type="text/javascript">
+
+// MainView is the ... main view.
+
+ var MainView = Backbone.View.extend({
+ el: '#fixture',
+
+// Listen to the DOM.
+
+ events: {
+ 'click #exploit': 'injectPayload',
+ },
+
+ initialize: function() {
+ this.render();
+ },
+
+ render: function() {
+
+// Tell outback to get to work.
+
+ Backbone.outback.bind(this);
+ },
+
+ remove: function() {
+
+// Tell outback to clean up event handlers and whatnot.
+
+ Backbone.outback.unbind(this);
+ },
+
+ injectPayload: function() {
+
+// This function simulates an XSS attack on your page. Malicious ads do stuff
+// like this.
+
+ this.model.set("firstName", "<script>alert('xss')<" + "/script>");
+ },
+
+ bindingSummary: function(summary) {
+ if (!console || typeof console.log !== 'function') return;
+
+// This is an optional hook which outback will call when it's finished binding
+// the view. It's useful for debugging.
+
+ console.log(summary);
+ }
+ });
+
+
+// MainModel holds the details of our form.
+
+ var MainModel = Backbone.Model.extend({
+ defaults: {
+ firstName: 'Planet',
+ lastName: 'Earth'
+ },
+
+ initialize: function() {
+
+// Setup the fullName dependency on initialize.
+
+ this.on('change:firstName change:lastName', this.fullName, this);
+
+ this.fullName();
+ },
+
+ fullName: function() {
+
+// This function computes the fullName attribute when its dependencies change.
+// It's not as magical as Knockout computed observables, but it gets the job
+// done.
+
+ var value = this.get("firstName") + " " + this.get("lastName");
+ this.set("fullName", value);
+ },
+
+ });
+
+// ... and lift off!
+
+ $(function () {
+ window.app = new MainView({
+ model: new MainModel()
+ });
+ });
+ </script>
+</body>
+</html>
View
84 examples/lib/backbone.localStorage.js
@@ -0,0 +1,84 @@
+// A simple module to replace `Backbone.sync` with *localStorage*-based
+// persistence. Models are given GUIDS, and saved into a JSON object. Simple
+// as that.
+
+// Generate four random hex digits.
+function S4() {
+ return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
+};
+
+// Generate a pseudo-GUID by concatenating random hexadecimal.
+function guid() {
+ return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
+};
+
+// Our Store is represented by a single JS object in *localStorage*. Create it
+// with a meaningful name, like the name you'd give a table.
+var Store = function(name) {
+ this.name = name;
+ var store = localStorage.getItem(this.name);
+ this.data = (store && JSON.parse(store)) || {};
+};
+
+_.extend(Store.prototype, {
+
+ // Save the current state of the **Store** to *localStorage*.
+ save: function() {
+ localStorage.setItem(this.name, JSON.stringify(this.data));
+ },
+
+ // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
+ // have an id of it's own.
+ create: function(model) {
+ if (!model.id) model.id = model.attributes.id = guid();
+ this.data[model.id] = model;
+ this.save();
+ return model;
+ },
+
+ // Update a model by replacing its copy in `this.data`.
+ update: function(model) {
+ this.data[model.id] = model;
+ this.save();
+ return model;
+ },
+
+ // Retrieve a model from `this.data` by id.
+ find: function(model) {
+ return this.data[model.id];
+ },
+
+ // Return the array of all models currently in storage.
+ findAll: function() {
+ return _.values(this.data);
+ },
+
+ // Delete a model from `this.data`, returning it.
+ destroy: function(model) {
+ delete this.data[model.id];
+ this.save();
+ return model;
+ }
+
+});
+
+// Override `Backbone.sync` to use delegate to the model or collection's
+// *localStorage* property, which should be an instance of `Store`.
+Backbone.sync = function(method, model, options) {
+
+ var resp;
+ var store = model.localStorage || model.collection.localStorage;
+
+ switch (method) {
+ case "read": resp = model.id ? store.find(model) : store.findAll(); break;
+ case "create": resp = store.create(model); break;
+ case "update": resp = store.update(model); break;
+ case "delete": resp = store.destroy(model); break;
+ }
+
+ if (resp) {
+ options.success(resp);
+ } else {
+ options.error("Record not found");
+ }
+};

0 comments on commit 8e41ddd

Please sign in to comment.