Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active February 20, 2016 10:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitaku/3d4329dccfb4ef9dd4ed to your computer and use it in GitHub Desktop.
Save nitaku/3d4329dccfb4ef9dd4ed to your computer and use it in GitHub Desktop.
Backbone.js exercise
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>
// Generated by CoffeeScript 1.10.0
(function() {
var list;
list = new Items();
new AppView({
el: 'body',
collection: list
});
}).call(this);
window.Item = Backbone.Model.extend
defaults:
string: null
color: null
window.Items = Backbone.Collection.extend
model: Item
localStorage: new Backbone.LocalStorage("itemexample-backbone")
// Generated by CoffeeScript 1.10.0
(function() {
window.Item = Backbone.Model.extend({
defaults: {
string: null,
color: null
}
});
window.Items = Backbone.Collection.extend({
model: Item,
localStorage: new Backbone.LocalStorage("itemexample-backbone")
});
}).call(this);
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