A minimal example of Backbone.js.
| window.AppView = Backbone.D3View.extend | |
| events: | |
| 'click .create_btn': 'new_item' | |
| initialize: () -> | |
| @bar = @d3el.append 'div' | |
| .attr | |
| class: 'bar' | |
| @input = @bar.append 'input' | |
| .attr | |
| class: 'input_field' | |
| @input.node().value = 'Empty item' | |
| @bar.append 'button' | |
| .text 'Create' | |
| .attr | |
| class: 'create_btn' | |
| @list = @d3el.append 'div' | |
| .attr | |
| class: 'list' | |
| @listenTo @collection, 'add', @render_one | |
| @listenTo @collection, 'reset', @render_all | |
| @collection.fetch() | |
| render_one: (item) -> | |
| view = new ItemView | |
| model: item | |
| @list.node().appendChild(view.el) | |
| view.render() | |
| render_all: () -> | |
| @collection.each(@render_one, this) | |
| new_item: () -> | |
| @collection.create | |
| string: @input.node().value | |
| color: [Math.random()*360,20,90] | |
| // Generated by CoffeeScript 1.10.0 | |
| (function() { | |
| window.AppView = Backbone.D3View.extend({ | |
| events: { | |
| 'click .create_btn': 'new_item' | |
| }, | |
| initialize: function() { | |
| this.bar = this.d3el.append('div').attr({ | |
| "class": 'bar' | |
| }); | |
| this.input = this.bar.append('input').attr({ | |
| "class": 'input_field' | |
| }); | |
| this.input.node().value = 'Empty item'; | |
| this.bar.append('button').text('Create').attr({ | |
| "class": 'create_btn' | |
| }); | |
| this.list = this.d3el.append('div').attr({ | |
| "class": 'list' | |
| }); | |
| this.listenTo(this.collection, 'add', this.render_one); | |
| this.listenTo(this.collection, 'reset', this.render_all); | |
| return this.collection.fetch(); | |
| }, | |
| render_one: function(item) { | |
| var view; | |
| view = new ItemView({ | |
| model: item | |
| }); | |
| this.list.node().appendChild(view.el); | |
| return view.render(); | |
| }, | |
| render_all: function() { | |
| return this.collection.each(this.render_one, this); | |
| }, | |
| new_item: function() { | |
| return this.collection.create({ | |
| string: this.input.node().value, | |
| color: [Math.random() * 360, 20, 90] | |
| }); | |
| } | |
| }); | |
| }).call(this); |
| // Backbone.D3View.js 0.3.1 | |
| // --------------- | |
| // (c) 2015 Adam Krebs | |
| // Backbone.D3View may be freely distributed under the MIT license. | |
| // For all details and documentation: | |
| // https://github.com/akre54/Backbone.D3View | |
| (function (factory) { | |
| if (typeof define === 'function' && define.amd) { define(['backbone', 'd3'], factory); | |
| } else if (typeof exports === 'object') { module.exports = factory(require('backbone'), require('d3')); | |
| } else { factory(Backbone, d3); } | |
| }(function (Backbone, d3) { | |
| // Cached regex to match an opening '<' of an HTML tag, possibly left-padded | |
| // with whitespace. | |
| var paddedLt = /^\s*</; | |
| var ElementProto = (typeof Element !== 'undefined' && Element.prototype) || {}; | |
| var matchesSelector = ElementProto.matches || | |
| ElementProto.webkitMatchesSelector || | |
| ElementProto.mozMatchesSelector || | |
| ElementProto.msMatchesSelector || | |
| ElementProto.oMatchesSelector; | |
| Backbone.D3ViewMixin = { | |
| // A reference to the d3 selection backing the view. | |
| d3el: null, | |
| namespace: d3.ns.prefix.svg, | |
| $: function(selector) { | |
| return this.el.querySelectorAll(selector); | |
| }, | |
| $$: function(selector) { | |
| return this.d3el.selectAll(selector); | |
| }, | |
| _removeElement: function() { | |
| this.undelegateEvents(); | |
| this.d3el.remove(); | |
| }, | |
| _createElement: function(tagName) { | |
| var ns = typeof this.namespace === 'function' ? this.namespace() : this.namespace; | |
| return ns ? | |
| document.createElementNS(ns, tagName) : | |
| document.createElement(tagName); | |
| }, | |
| _setElement: function(element) { | |
| if (typeof element == 'string') { | |
| if (paddedLt.test(element)) { | |
| var el = document.createElement('div'); | |
| el.innerHTML = element; | |
| this.el = el.firstChild; | |
| } else { | |
| this.el = document.querySelector(element); | |
| } | |
| } else { | |
| this.el = element; | |
| } | |
| this.d3el = d3.select(this.el); | |
| }, | |
| _setAttributes: function(attributes) { | |
| this.d3el.attr(attributes); | |
| }, | |
| // `delegate` supports two- and three-arg forms. The `selector` is optional. | |
| delegate: function(eventName, selector, listener) { | |
| if (listener === undefined) { | |
| listener = selector; | |
| selector = null; | |
| } | |
| var view = this; | |
| var wrapped = function(event) { | |
| var node = event.target, | |
| idx = 0, | |
| o = d3.event; | |
| d3.event = event; | |
| // The `event` object is stored in `d3.event` but Backbone expects it as | |
| // the first argument to the listener. | |
| if (!selector) { | |
| listener.call(view, d3.event, node.__data__, idx++); | |
| d3.event = o; | |
| return; | |
| } | |
| while (node && node !== view.el) { | |
| if (matchesSelector.call(node, selector)) { | |
| listener.call(view, d3.event, node.__data__, idx++); | |
| } | |
| node = node.parentNode; | |
| } | |
| d3.event = o; | |
| }; | |
| var map = this._domEvents || (this._domEvents = {}); | |
| var handlers = map[eventName] || (map[eventName] = []); | |
| handlers.push({selector: selector, listener: listener, wrapped: wrapped}); | |
| this.el.addEventListener(eventName, wrapped, false); | |
| return this; | |
| }, | |
| undelegate: function(eventName, selector, listener) { | |
| if (!this._domEvents || !this._domEvents[eventName]) return; | |
| if (typeof selector !== 'string') { | |
| listener = selector; | |
| selector = null; | |
| } | |
| var handlers = this._domEvents[eventName].slice(); | |
| var i = handlers.length; | |
| while (i--) { | |
| var handler = handlers[i]; | |
| var match = (listener ? handler.listener === listener : true) && | |
| (selector ? handler.selector === selector : true); | |
| if (!match) continue; | |
| this.el.removeEventListener(eventName, handler.wrapped, false); | |
| this._domEvents[eventName].splice(i, 1); | |
| } | |
| }, | |
| undelegateEvents: function() { | |
| var map = this._domEvents, el = this.el; | |
| if (!el || !map) return; | |
| Object.keys(map).forEach(function(eventName) { | |
| map[eventName].forEach(function(handler) { | |
| el.removeEventListener(eventName, handler.wrapped, false); | |
| }); | |
| }); | |
| this._domEvents = {}; | |
| return this; | |
| } | |
| }; | |
| Backbone.D3View = Backbone.View.extend(Backbone.D3ViewMixin); | |
| return Backbone.D3View; | |
| })); |
| /** | |
| * Backbone localStorage Adapter | |
| * Version 1.1.16 | |
| * | |
| * https://github.com/jeromegn/Backbone.localStorage | |
| */(function(a,b){typeof exports=="object"&&typeof require=="function"?module.exports=b(require("backbone")):typeof define=="function"&&define.amd?define(["backbone"],function(c){return b(c||a.Backbone)}):b(Backbone)})(this,function(a){function b(){return((1+Math.random())*65536|0).toString(16).substring(1)}function c(){return b()+b()+"-"+b()+"-"+b()+"-"+b()+"-"+b()+b()+b()}function d(a){return a===Object(a)}function e(a,b){var c=a.length;while(c--)if(a[c]===b)return!0;return!1}function f(a,b){for(var c in b)a[c]=b[c];return a}function g(a,b){if(a==null)return void 0;var c=a[b];return typeof c=="function"?a[b]():c}return a.LocalStorage=window.Store=function(a,b){if(!this.localStorage)throw"Backbone.localStorage: Environment does not support localStorage.";this.name=a,this.serializer=b||{serialize:function(a){return d(a)?JSON.stringify(a):a},deserialize:function(a){return a&&JSON.parse(a)}};var c=this.localStorage().getItem(this.name);this.records=c&&c.split(",")||[]},f(a.LocalStorage.prototype,{save:function(){this.localStorage().setItem(this.name,this.records.join(","))},create:function(a){return!a.id&&a.id!==0&&(a.id=c(),a.set(a.idAttribute,a.id)),this.localStorage().setItem(this._itemName(a.id),this.serializer.serialize(a)),this.records.push(a.id.toString()),this.save(),this.find(a)},update:function(a){this.localStorage().setItem(this._itemName(a.id),this.serializer.serialize(a));var b=a.id.toString();return e(this.records,b)||(this.records.push(b),this.save()),this.find(a)},find:function(a){return this.serializer.deserialize(this.localStorage().getItem(this._itemName(a.id)))},findAll:function(){var a=[];for(var b=0,c,d;b<this.records.length;b++)c=this.records[b],d=this.serializer.deserialize(this.localStorage().getItem(this._itemName(c))),d!=null&&a.push(d);return a},destroy:function(a){this.localStorage().removeItem(this._itemName(a.id));var b=a.id.toString();for(var c=0,d;c<this.records.length;c++)this.records[c]===b&&this.records.splice(c,1);return this.save(),a},localStorage:function(){return localStorage},_clear:function(){var a=this.localStorage(),b=new RegExp("^"+this.name+"-");a.removeItem(this.name);for(var c in a)b.test(c)&&a.removeItem(c);this.records.length=0},_storageSize:function(){return this.localStorage().length},_itemName:function(a){return this.name+"-"+a}}),a.LocalStorage.sync=window.Store.sync=a.localSync=function(b,c,d){var e=g(c,"localStorage")||g(c.collection,"localStorage"),f,h,i=a.$?a.$.Deferred&&a.$.Deferred():a.Deferred&&a.Deferred();try{switch(b){case"read":f=c.id!=undefined?e.find(c):e.findAll();break;case"create":f=e.create(c);break;case"update":f=e.update(c);break;case"delete":f=e.destroy(c)}}catch(j){j.code===22&&e._storageSize()===0?h="Private browsing is unsupported":h=j.message}return f?(d&&d.success&&(a.VERSION==="0.9.10"?d.success(c,f,d):d.success(f)),i&&i.resolve(f)):(h=h?h:"Record Not Found",d&&d.error&&(a.VERSION==="0.9.10"?d.error(c,h,d):d.error(h)),i&&i.reject(h)),d&&d.complete&&d.complete(f),i&&i.promise()},a.ajaxSync=a.sync,a.getSyncMethod=function(b,c){var d=c&&c.ajaxSync;return!d&&(g(b,"localStorage")||g(b.collection,"localStorage"))?a.localSync:a.ajaxSync},a.sync=function(b,c,d){return a.getSyncMethod(c,d).apply(this,[b,c,d])},a.LocalStorage}); |
| list = new Items() | |
| new AppView | |
| el: 'body' | |
| collection: list | |
| html, body { | |
| padding: 0; | |
| margin: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| body { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .bar { | |
| height: 28px; | |
| background: #DDD; | |
| border-bottom: 1px solid gray; | |
| padding: 4px; | |
| } | |
| .bar > * { | |
| height: 100%; | |
| box-sizing: border-box; | |
| margin-right: 4px; | |
| } | |
| .list { | |
| height: 0; | |
| flex-grow: 1; | |
| } | |
| .item { | |
| font-family: sans-serif; | |
| font-size: 14px; | |
| padding: 6px; | |
| } | |
| .item:hover { | |
| text-decoration: line-through; | |
| cursor: pointer; | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Backbone</title> | |
| <link type="text/css" href="index.css" rel="stylesheet"/> | |
| <!-- dependencies --> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://underscorejs.org/underscore-min.js"></script> | |
| <script src="http://backbonejs.org/backbone-min.js"></script> | |
| <script src="backbone.d3view.js"></script> | |
| <script src="backbone.localStorage-min.js"></script> | |
| <!-- your views go here --> | |
| <script src="AppView.js"></script> | |
| <script src="ItemView.js"></script> | |
| <!-- your models go here --> | |
| <script src="Items.js"></script> | |
| </head> | |
| <body> | |
| <script src="index.js"></script> | |
| </body> | |
| </html> |
| window.Item = Backbone.Model.extend | |
| defaults: | |
| string: null | |
| color: null | |
| window.Items = Backbone.Collection.extend | |
| model: Item | |
| localStorage: new Backbone.LocalStorage("itemexample-backbone") | |
| window.ItemView = Backbone.D3View.extend | |
| namespace: null | |
| tagName: 'div' | |
| events: | |
| 'click': 'suicide' | |
| initialize: () -> | |
| @d3el.classed 'item', true | |
| @listenTo @model, 'change', @render | |
| @listenTo @model, 'destroy', @remove | |
| render: () -> | |
| @d3el.text @model.get 'string' | |
| @d3el | |
| .style | |
| background: d3.hcl.apply this, @model.get 'color' | |
| suicide: () -> | |
| @model.destroy() | |
| // Generated by CoffeeScript 1.10.0 | |
| (function() { | |
| window.ItemView = Backbone.D3View.extend({ | |
| namespace: null, | |
| tagName: 'div', | |
| events: { | |
| 'click': 'suicide' | |
| }, | |
| initialize: function() { | |
| this.d3el.classed('item', true); | |
| this.listenTo(this.model, 'change', this.render); | |
| return this.listenTo(this.model, 'destroy', this.remove); | |
| }, | |
| render: function() { | |
| this.d3el.text(this.model.get('string')); | |
| return this.d3el.style({ | |
| background: d3.hcl.apply(this, this.model.get('color')) | |
| }); | |
| }, | |
| suicide: function() { | |
| return this.model.destroy(); | |
| } | |
| }); | |
| }).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment