traces-vendor 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/lib/traces-vendor/version.rb +5 -0
- data/lib/traces-vendor.rb +7 -0
- data/traces-vendor.gemspec +24 -0
- data/vendor/assets/javascripts/backbone-couchdb.js +236 -0
- data/vendor/assets/javascripts/backbone-min.js +37 -0
- data/vendor/assets/javascripts/mustache.js +325 -0
- data/vendor/assets/javascripts/showdown.js +1302 -0
- data/vendor/assets/javascripts/underscore-min.js +31 -0
- metadata +57 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "traces-vendor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "traces-vendor"
|
7
|
+
s.version = Traces::Vendor::VERSION
|
8
|
+
s.authors = ["Winfield"]
|
9
|
+
s.email = ["winfield301@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Trace Vendor}
|
12
|
+
s.description = %q{Trace Vendor}
|
13
|
+
|
14
|
+
s.rubyforge_project = "traces-vendor"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
// (c) 2011 Jan Monschke
|
2
|
+
// backbone-couchdb.js is licensed under the MIT license.
|
3
|
+
// I developed this connector because I didn't want to write an own server that persists
|
4
|
+
// the models that Backbone.js ceated. Instead I now only have to write a simple design document
|
5
|
+
// containing one simple view and I'm done with server-side code.
|
6
|
+
// So have fun reading the doc and [RELAX](http://vimeo.com/11852209) :D
|
7
|
+
|
8
|
+
// I added the connector to the Backbone object.
|
9
|
+
Backbone.couchConnector = {
|
10
|
+
// Name of the Database.
|
11
|
+
databaseName : "test1",
|
12
|
+
// Name of the design document that contains the views.
|
13
|
+
ddocName : "backbone",
|
14
|
+
// Name of the view.
|
15
|
+
viewName : "byCollection",
|
16
|
+
// Enable updates via the couchdb _changes feed
|
17
|
+
enableChanges : false,
|
18
|
+
// If `baseUrl` is set, the default uri of jquery.couch.js will be overridden.
|
19
|
+
// This is useful if you want to access a couch on another server e.g. `http://127.0.0.1:5984`
|
20
|
+
// Important: Be aware of the Cross-Origin Policy.
|
21
|
+
baseUrl : null,
|
22
|
+
// A simple lookup table for collections that should be synched.
|
23
|
+
_watchList : [],
|
24
|
+
// Creates a couchDB object from the given model object.
|
25
|
+
makeDb : function(model){
|
26
|
+
var db = $.couch.db(this.databaseName);
|
27
|
+
if(this.baseUrl){
|
28
|
+
db.uri = this.baseUrl + "/" + this.databaseName + "/";
|
29
|
+
}
|
30
|
+
return db;
|
31
|
+
},
|
32
|
+
// Fetches all docs from the given collection.
|
33
|
+
// Therefore all docs from the view `ddocName`/`viewName` will be requested.
|
34
|
+
// A simple view could look like this:
|
35
|
+
//
|
36
|
+
// function(doc) {
|
37
|
+
// if(doc.collection)
|
38
|
+
// emit(doc.collection, doc);
|
39
|
+
// }
|
40
|
+
//
|
41
|
+
// doc.collection represents the url property of the collection and is automatically added to the model.
|
42
|
+
readCollection : function(coll, _success, _error){
|
43
|
+
var db = this.makeDb(coll);
|
44
|
+
//var query = this.ddocName + "/" + this.viewName;
|
45
|
+
var query = coll.ddoc + "/" + coll.view;
|
46
|
+
// Query equals ddocName/viewName
|
47
|
+
var queryOptions = {
|
48
|
+
descending : coll.descending,
|
49
|
+
limit : coll.limit,
|
50
|
+
success:function(result){
|
51
|
+
if(result.rows.length > 0){
|
52
|
+
var arr = [];
|
53
|
+
var model = {};
|
54
|
+
var curr = {};
|
55
|
+
// Prepare the result set for Backbone -> Only return the docs and no meta data.
|
56
|
+
for (var i=0; i < result.rows.length; i++) {
|
57
|
+
curr = result.rows[i];
|
58
|
+
model = curr.value;
|
59
|
+
if(!model.id)
|
60
|
+
model.id = curr.id;
|
61
|
+
arr.push(model);
|
62
|
+
}
|
63
|
+
_success(arr);
|
64
|
+
}else{
|
65
|
+
_success(null);
|
66
|
+
}
|
67
|
+
},
|
68
|
+
error: _error
|
69
|
+
};
|
70
|
+
if (coll.key != "")
|
71
|
+
queryOptions.key = coll.key;
|
72
|
+
|
73
|
+
db.view(query,queryOptions);
|
74
|
+
// Add the collection to the `_watchlist`.
|
75
|
+
if(!this._watchList[coll.change_id]){
|
76
|
+
this._watchList[coll.change_id] = coll;
|
77
|
+
}
|
78
|
+
|
79
|
+
},
|
80
|
+
// Reads the state of one specific model from the server.
|
81
|
+
readModel : function(model, _success, _error){
|
82
|
+
var db = this.makeDb(model);
|
83
|
+
db.openDoc(model.id,{
|
84
|
+
success : function(doc){
|
85
|
+
_success(doc);
|
86
|
+
},
|
87
|
+
error : _error
|
88
|
+
});
|
89
|
+
},
|
90
|
+
// Creates a document.
|
91
|
+
create : function(model, _success, _error){
|
92
|
+
var db = this.makeDb(model);
|
93
|
+
var data = model.toJSON();
|
94
|
+
|
95
|
+
// Backbone finds out that an element has been
|
96
|
+
// synched by checking for the existance of an `id` property in the model.
|
97
|
+
// By returning the an object with an `id` we mark the model as synched.
|
98
|
+
if(!data.id && data._id){
|
99
|
+
data.id = data._id;
|
100
|
+
}
|
101
|
+
// jquery.couch.js automatically finds out whether the document is new
|
102
|
+
// or already exists by checking for the _id property.
|
103
|
+
db.saveDoc(data,{
|
104
|
+
success : function(resp){
|
105
|
+
// When the document has been successfully created/altered, return
|
106
|
+
// the created/changed values.
|
107
|
+
_success({
|
108
|
+
"id" : resp.id,
|
109
|
+
"_id" : resp.id,
|
110
|
+
"_rev" : resp.rev
|
111
|
+
});
|
112
|
+
},
|
113
|
+
error : function(nr){
|
114
|
+
// document already exists, we don't care ;)
|
115
|
+
if(nr == 409){
|
116
|
+
_error();
|
117
|
+
}else{
|
118
|
+
_error();
|
119
|
+
}
|
120
|
+
}
|
121
|
+
});
|
122
|
+
},
|
123
|
+
// jquery.couch.js provides the same method for updating and creating a document,
|
124
|
+
// so we can use the `create` method here.
|
125
|
+
update : function(model, _success, _error){
|
126
|
+
this.create(model, _success, _error);
|
127
|
+
},
|
128
|
+
// Deletes the document via the removeDoc method.
|
129
|
+
del : function(model, _success, _error){
|
130
|
+
var db = this.makeDb(model);
|
131
|
+
var data = model.toJSON();
|
132
|
+
db.removeDoc(data,{
|
133
|
+
success: function(){
|
134
|
+
_success();
|
135
|
+
},
|
136
|
+
error: function(nr,req,e){
|
137
|
+
if(e == "deleted"){
|
138
|
+
console.log("The Doc could not be deleted because it was already deleted from the server.");
|
139
|
+
_success();
|
140
|
+
}else{
|
141
|
+
_error();
|
142
|
+
}
|
143
|
+
|
144
|
+
}
|
145
|
+
});
|
146
|
+
},
|
147
|
+
// The _changes feed is one of the coolest things about CouchDB in my opinion.
|
148
|
+
// It enables you to get real time updates of changes in your database.
|
149
|
+
// If `enableChanges` is true the connector automatically listens to changes in the database
|
150
|
+
// and updates the changed models. -> Remotely triggered events in your models and collections. YES!
|
151
|
+
_changes : function(model){
|
152
|
+
var db = this.makeDb(model);
|
153
|
+
var change_id = model.change_id;
|
154
|
+
var filter_name = this.ddocName + "/" + model.filter;
|
155
|
+
var connector = this;
|
156
|
+
// First grab the `update_seq` from the database info, so that we only receive newest changes.
|
157
|
+
db.info({
|
158
|
+
success : function(data){
|
159
|
+
var since = (data.update_seq || 0)
|
160
|
+
// Connect to the changes feed.
|
161
|
+
connector.changesFeed = db.changes(since,{include_docs:true, filter:filter_name});
|
162
|
+
connector.changesFeed.onChange(function(changes){
|
163
|
+
var doc,coll,model,ID;
|
164
|
+
// Iterate over the changed docs and validate them.
|
165
|
+
for (var i=0; i < changes.results.length; i++) {
|
166
|
+
doc = changes.results[i].doc;
|
167
|
+
|
168
|
+
// The doc has been deleted on the server
|
169
|
+
if (doc._deleted) {
|
170
|
+
// Find the doc and the corresponsing collection
|
171
|
+
var dd = connector.findDocAndColl(doc._id);
|
172
|
+
// Only if both are found, remove the doc from the collection
|
173
|
+
if(dd.elem && dd.coll) {
|
174
|
+
// will trigger the `remove` event on the collection
|
175
|
+
dd.coll.remove(dd.elem);
|
176
|
+
}
|
177
|
+
} else {
|
178
|
+
coll = connector._watchList[change_id];
|
179
|
+
if (coll) {
|
180
|
+
ID = (doc.id || doc._id);
|
181
|
+
model = coll.get(ID);
|
182
|
+
if (model) {
|
183
|
+
// Check if the model on this client has changed by comparing `rev`.
|
184
|
+
if(doc._rev != model.get("_rev")){
|
185
|
+
// `doc._rev` is newer than the `rev` attribute of the model, so we update it.
|
186
|
+
// Currently all properties are updated, will maybe diff in the future.
|
187
|
+
model.set(doc);
|
188
|
+
}
|
189
|
+
} else {
|
190
|
+
// Create a new element, set its id and add it to the collection.
|
191
|
+
if (!doc.id)
|
192
|
+
doc.id = doc._id;
|
193
|
+
//coll.create(doc);
|
194
|
+
coll.add(doc)
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
});
|
200
|
+
}
|
201
|
+
});
|
202
|
+
},
|
203
|
+
|
204
|
+
// Finds a document and its collection by the document id
|
205
|
+
findDocAndColl : function(id){
|
206
|
+
var coll,elem;
|
207
|
+
for (coll in this._watchList) {
|
208
|
+
coll = this._watchList[coll];
|
209
|
+
elem = coll.get(id);
|
210
|
+
if(elem){
|
211
|
+
break;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
return { "coll" : coll , "elem" : elem};
|
215
|
+
}
|
216
|
+
};
|
217
|
+
|
218
|
+
// Override the standard sync method.
|
219
|
+
Backbone.sync = function(method, model, options) {
|
220
|
+
if(method == "create" || method == "update"){
|
221
|
+
Backbone.couchConnector.create(model, options.success, options.error);
|
222
|
+
}else if(method == "read"){
|
223
|
+
// Decide whether to read a whole collection or just one specific model
|
224
|
+
if(model.collection)
|
225
|
+
Backbone.couchConnector.readModel(model, options.success, options.error);
|
226
|
+
else
|
227
|
+
Backbone.couchConnector.readCollection(model, options.success, options.error);
|
228
|
+
}else if(method == "delete"){
|
229
|
+
Backbone.couchConnector.del(model, options.success, options.error);
|
230
|
+
}
|
231
|
+
|
232
|
+
// Activate real time changes feed
|
233
|
+
if(Backbone.couchConnector.enableChanges && !Backbone.couchConnector.changesFeed){
|
234
|
+
Backbone.couchConnector._changes(model);
|
235
|
+
}
|
236
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
// Backbone.js 0.9.1
|
2
|
+
|
3
|
+
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
4
|
+
// Backbone may be freely distributed under the MIT license.
|
5
|
+
// For all details and documentation:
|
6
|
+
// http://backbonejs.org
|
7
|
+
(function(){var i=this,r=i.Backbone,s=Array.prototype.slice,t=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:i.Backbone={};g.VERSION="0.9.1";var f=i._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var h=i.jQuery||i.Zepto||i.ender;g.setDomLibrary=function(a){h=a};g.noConflict=function(){i.Backbone=r;return this};g.emulateHTTP=!1;g.emulateJSON=!1;g.Events={on:function(a,b,c){for(var d,a=a.split(/\s+/),e=this._callbacks||(this._callbacks={});d=a.shift();){d=e[d]||(e[d]=
|
8
|
+
{});var f=d.tail||(d.tail=d.next={});f.callback=b;f.context=c;d.tail=f.next={}}return this},off:function(a,b,c){var d,e,f;if(a){if(e=this._callbacks)for(a=a.split(/\s+/);d=a.shift();)if(f=e[d],delete e[d],b&&f)for(;(f=f.next)&&f.next;)if(!(f.callback===b&&(!c||f.context===c)))this.on(d,f.callback,f.context)}else delete this._callbacks;return this},trigger:function(a){var b,c,d,e;if(!(d=this._callbacks))return this;e=d.all;for((a=a.split(/\s+/)).push(null);b=a.shift();)e&&a.push({next:e.next,tail:e.tail,
|
9
|
+
event:b}),(c=d[b])&&a.push({next:c.next,tail:c.tail});for(e=s.call(arguments,1);c=a.pop();){b=c.tail;for(d=c.event?[c.event].concat(e):e;(c=c.next)!==b;)c.callback.apply(c.context||this,d)}return this}};g.Events.bind=g.Events.on;g.Events.unbind=g.Events.off;g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=j(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");if(!this.set(a,
|
10
|
+
{silent:!0}))throw Error("Can't create an invalid model");delete this._changed;this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(g.Model.prototype,g.Events,{idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.attributes[a];return this._escapedAttributes[a]=f.escape(null==b?"":""+b)},has:function(a){return null!=
|
11
|
+
this.attributes[a]},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof g.Model&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=this.attributes,k=this._escapedAttributes,n=this._previousAttributes||{},h=this._setting;this._changed||(this._changed={});this._setting=!0;for(e in d)if(a=d[e],f.isEqual(b[e],a)||delete k[e],c.unset?delete b[e]:b[e]=
|
12
|
+
a,this._changing&&!f.isEqual(this._changed[e],a)&&(this.trigger("change:"+e,this,a,c),this._moreChanges=!0),delete this._changed[e],!f.isEqual(n[e],a)||f.has(b,e)!=f.has(n,e))this._changed[e]=a;h||(!c.silent&&this.hasChanged()&&this.change(c),this._setting=!1);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,
|
13
|
+
e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};c.wait&&(e=f.clone(this.attributes));a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var k=this,h=c.success;c.success=function(a,b,e){b=k.parse(a,e);c.wait&&(b=f.extend(d||{},b));if(!k.set(b,c))return!1;h?h(k,a):k.trigger("sync",k,a,c)};c.error=g.wrapError(c.error,
|
14
|
+
k,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d();a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=j(this.collection,"url")||j(this,"urlRoot")||o();return this.isNew()?
|
15
|
+
a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){if(this._changing||!this.hasChanged())return this;this._moreChanges=this._changing=!0;for(var b in this._changed)this.trigger("change:"+b,this,this._changed[b],a);for(;this._moreChanges;)this._moreChanges=!1,this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);
|
16
|
+
delete this._changed;this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this._changed):this._changed&&f.has(this._changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this._changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},
|
17
|
+
isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});g.Collection=function(a,b){b||(b={});b.comparator&&(this.comparator=b.comparator);this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(g.Collection.prototype,g.Events,{model:g.Model,initialize:function(){},
|
18
|
+
toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){var c,d,e,g,h,i={},j={};b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");if(i[g=e.cid]||this._byCid[g]||null!=(h=e.id)&&(j[h]||this._byId[h]))throw Error("Can't add the same model to a collection twice");i[g]=j[h]=e}for(c=0;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=
|
19
|
+
e.id&&(this._byId[e.id]=e);this.length+=d;t.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;for(c=0,d=this.models.length;c<d;c++)if(i[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,
|
20
|
+
1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},get:function(a){return null==a?null:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",
|
21
|
+
this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,{silent:!0,parse:b.parse});b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,
|
22
|
+
b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_prepareModel:function(a,b){a instanceof g.Model?a.collection||
|
23
|
+
(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),
|
24
|
+
function(a){g.Collection.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)};var u=/:\w+/g,v=/\*\w+/g,w=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(g.Router.prototype,g.Events,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new g.History);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=
|
25
|
+
this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(w,"\\$&").replace(u,"([^/]+)").replace(v,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,
|
26
|
+
b){return a.exec(b).slice(1)}});g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")};var m=/^[#\/]/,x=/msie [\w.]+/,l=!1;f.extend(g.History.prototype,g.Events,{interval:50,getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=window.location.hash;a=decodeURIComponent(a);a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(m,"")},start:function(a){if(l)throw Error("Backbone.history has already been started");
|
27
|
+
this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=x.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=h('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?h(window).bind("popstate",
|
28
|
+
this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?h(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,this.interval));this.fragment=a;l=!0;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&
|
29
|
+
(this.fragment=a.hash.replace(m,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},stop:function(){h(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);l=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.iframe.location.hash));
|
30
|
+
if(a==this.fragment||a==decodeURIComponent(this.fragment))return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(window.location.hash)},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!l)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(m,"");this.fragment==c||this.fragment==decodeURIComponent(c)||(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=
|
31
|
+
this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.iframe.location.hash)&&(b.replace||this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,
|
32
|
+
"")+"#"+b):a.hash=b}});g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var y=/^(\S+)\s*(.*)$/,p="model,collection,el,id,attributes,className,tagName".split(",");f.extend(g.View.prototype,g.Events,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);
|
33
|
+
b&&h(a).attr(b);c&&h(a).html(c);return a},setElement:function(a,b){this.$el=h(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=j(this,"events"))){this.undelegateEvents();for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Event "'+a[b]+'" does not exist');var d=b.match(y),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+
|
34
|
+
this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=p.length;b<c;b++){var d=p[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,!1);else{var a=j(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});g.Model.extend=g.Collection.extend=g.Router.extend=g.View.extend=function(a,b){var c=z(this,a,b);c.extend=this.extend;return c};
|
35
|
+
var A={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=A[a],e={type:d,dataType:"json"};c.url||(e.url=j(b,"url")||o());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",
|
36
|
+
d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return h.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var q=function(){},z=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);q.prototype=a.prototype;d.prototype=new q;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},j=function(a,b){return!a||!a[b]?
|
37
|
+
null:f.isFunction(a[b])?a[b]():a[b]},o=function(){throw Error('A "url" property or function must be specified');}}).call(this);
|
@@ -0,0 +1,325 @@
|
|
1
|
+
/*
|
2
|
+
mustache.js — Logic-less templates in JavaScript
|
3
|
+
|
4
|
+
See http://mustache.github.com/ for more info.
|
5
|
+
*/
|
6
|
+
|
7
|
+
var Mustache = function() {
|
8
|
+
var Renderer = function() {};
|
9
|
+
|
10
|
+
Renderer.prototype = {
|
11
|
+
otag: "{{",
|
12
|
+
ctag: "}}",
|
13
|
+
pragmas: {},
|
14
|
+
buffer: [],
|
15
|
+
pragmas_implemented: {
|
16
|
+
"IMPLICIT-ITERATOR": true
|
17
|
+
},
|
18
|
+
context: {},
|
19
|
+
|
20
|
+
render: function(template, context, partials, in_recursion) {
|
21
|
+
// reset buffer & set context
|
22
|
+
if(!in_recursion) {
|
23
|
+
this.context = context;
|
24
|
+
this.buffer = []; // TODO: make this non-lazy
|
25
|
+
}
|
26
|
+
|
27
|
+
// fail fast
|
28
|
+
if(!this.includes("", template)) {
|
29
|
+
if(in_recursion) {
|
30
|
+
return template;
|
31
|
+
} else {
|
32
|
+
this.send(template);
|
33
|
+
return;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
template = this.render_pragmas(template);
|
38
|
+
var html = this.render_section(template, context, partials);
|
39
|
+
if(in_recursion) {
|
40
|
+
return this.render_tags(html, context, partials, in_recursion);
|
41
|
+
}
|
42
|
+
|
43
|
+
this.render_tags(html, context, partials, in_recursion);
|
44
|
+
},
|
45
|
+
|
46
|
+
/*
|
47
|
+
Sends parsed lines
|
48
|
+
*/
|
49
|
+
send: function(line) {
|
50
|
+
if(line != "") {
|
51
|
+
this.buffer.push(line);
|
52
|
+
}
|
53
|
+
},
|
54
|
+
|
55
|
+
/*
|
56
|
+
Looks for %PRAGMAS
|
57
|
+
*/
|
58
|
+
render_pragmas: function(template) {
|
59
|
+
// no pragmas
|
60
|
+
if(!this.includes("%", template)) {
|
61
|
+
return template;
|
62
|
+
}
|
63
|
+
|
64
|
+
var that = this;
|
65
|
+
var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
|
66
|
+
this.ctag);
|
67
|
+
return template.replace(regex, function(match, pragma, options) {
|
68
|
+
if(!that.pragmas_implemented[pragma]) {
|
69
|
+
throw({message:
|
70
|
+
"This implementation of mustache doesn't understand the '" +
|
71
|
+
pragma + "' pragma"});
|
72
|
+
}
|
73
|
+
that.pragmas[pragma] = {};
|
74
|
+
if(options) {
|
75
|
+
var opts = options.split("=");
|
76
|
+
that.pragmas[pragma][opts[0]] = opts[1];
|
77
|
+
}
|
78
|
+
return "";
|
79
|
+
// ignore unknown pragmas silently
|
80
|
+
});
|
81
|
+
},
|
82
|
+
|
83
|
+
/*
|
84
|
+
Tries to find a partial in the curent scope and render it
|
85
|
+
*/
|
86
|
+
render_partial: function(name, context, partials) {
|
87
|
+
name = this.trim(name);
|
88
|
+
if(!partials || partials[name] === undefined) {
|
89
|
+
throw({message: "unknown_partial '" + name + "'"});
|
90
|
+
}
|
91
|
+
if(typeof(context[name]) != "object") {
|
92
|
+
return this.render(partials[name], context, partials, true);
|
93
|
+
}
|
94
|
+
return this.render(partials[name], context[name], partials, true);
|
95
|
+
},
|
96
|
+
|
97
|
+
/*
|
98
|
+
Renders inverted (^) and normal (#) sections
|
99
|
+
*/
|
100
|
+
render_section: function(template, context, partials) {
|
101
|
+
if(!this.includes("#", template) && !this.includes("^", template)) {
|
102
|
+
return template;
|
103
|
+
}
|
104
|
+
|
105
|
+
var that = this;
|
106
|
+
// CSW - Added "+?" so it finds the tighest bound, not the widest
|
107
|
+
var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
|
108
|
+
"\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
|
109
|
+
"\\s*", "mg");
|
110
|
+
|
111
|
+
// for each {{#foo}}{{/foo}} section do...
|
112
|
+
return template.replace(regex, function(match, type, name, content) {
|
113
|
+
var value = that.find(name, context);
|
114
|
+
if(type == "^") { // inverted section
|
115
|
+
if(!value || that.is_array(value) && value.length === 0) {
|
116
|
+
// false or empty list, render it
|
117
|
+
return that.render(content, context, partials, true);
|
118
|
+
} else {
|
119
|
+
return "";
|
120
|
+
}
|
121
|
+
} else if(type == "#") { // normal section
|
122
|
+
if(that.is_array(value)) { // Enumerable, Let's loop!
|
123
|
+
return that.map(value, function(row) {
|
124
|
+
return that.render(content, that.create_context(row),
|
125
|
+
partials, true);
|
126
|
+
}).join("");
|
127
|
+
} else if(that.is_object(value)) { // Object, Use it as subcontext!
|
128
|
+
return that.render(content, that.create_context(value),
|
129
|
+
partials, true);
|
130
|
+
} else if(typeof value === "function") {
|
131
|
+
// higher order section
|
132
|
+
return value.call(context, content, function(text) {
|
133
|
+
return that.render(text, context, partials, true);
|
134
|
+
});
|
135
|
+
} else if(value) { // boolean section
|
136
|
+
return that.render(content, context, partials, true);
|
137
|
+
} else {
|
138
|
+
return "";
|
139
|
+
}
|
140
|
+
}
|
141
|
+
});
|
142
|
+
},
|
143
|
+
|
144
|
+
/*
|
145
|
+
Replace {{foo}} and friends with values from our view
|
146
|
+
*/
|
147
|
+
render_tags: function(template, context, partials, in_recursion) {
|
148
|
+
// tit for tat
|
149
|
+
var that = this;
|
150
|
+
|
151
|
+
var new_regex = function() {
|
152
|
+
return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
|
153
|
+
that.ctag + "+", "g");
|
154
|
+
};
|
155
|
+
|
156
|
+
var regex = new_regex();
|
157
|
+
var tag_replace_callback = function(match, operator, name) {
|
158
|
+
switch(operator) {
|
159
|
+
case "!": // ignore comments
|
160
|
+
return "";
|
161
|
+
case "=": // set new delimiters, rebuild the replace regexp
|
162
|
+
that.set_delimiters(name);
|
163
|
+
regex = new_regex();
|
164
|
+
return "";
|
165
|
+
case ">": // render partial
|
166
|
+
return that.render_partial(name, context, partials);
|
167
|
+
case "{": // the triple mustache is unescaped
|
168
|
+
return that.find(name, context);
|
169
|
+
default: // escape the value
|
170
|
+
return that.escape(that.find(name, context));
|
171
|
+
}
|
172
|
+
};
|
173
|
+
var lines = template.split("\n");
|
174
|
+
for(var i = 0; i < lines.length; i++) {
|
175
|
+
lines[i] = lines[i].replace(regex, tag_replace_callback, this);
|
176
|
+
if(!in_recursion) {
|
177
|
+
this.send(lines[i]);
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
if(in_recursion) {
|
182
|
+
return lines.join("\n");
|
183
|
+
}
|
184
|
+
},
|
185
|
+
|
186
|
+
set_delimiters: function(delimiters) {
|
187
|
+
var dels = delimiters.split(" ");
|
188
|
+
this.otag = this.escape_regex(dels[0]);
|
189
|
+
this.ctag = this.escape_regex(dels[1]);
|
190
|
+
},
|
191
|
+
|
192
|
+
escape_regex: function(text) {
|
193
|
+
// thank you Simon Willison
|
194
|
+
if(!arguments.callee.sRE) {
|
195
|
+
var specials = [
|
196
|
+
'/', '.', '*', '+', '?', '|',
|
197
|
+
'(', ')', '[', ']', '{', '}', '\\'
|
198
|
+
];
|
199
|
+
arguments.callee.sRE = new RegExp(
|
200
|
+
'(\\' + specials.join('|\\') + ')', 'g'
|
201
|
+
);
|
202
|
+
}
|
203
|
+
return text.replace(arguments.callee.sRE, '\\$1');
|
204
|
+
},
|
205
|
+
|
206
|
+
/*
|
207
|
+
find `name` in current `context`. That is find me a value
|
208
|
+
from the view object
|
209
|
+
*/
|
210
|
+
find: function(name, context) {
|
211
|
+
name = this.trim(name);
|
212
|
+
|
213
|
+
// Checks whether a value is thruthy or false or 0
|
214
|
+
function is_kinda_truthy(bool) {
|
215
|
+
return bool === false || bool === 0 || bool;
|
216
|
+
}
|
217
|
+
|
218
|
+
var value;
|
219
|
+
if(is_kinda_truthy(context[name])) {
|
220
|
+
value = context[name];
|
221
|
+
} else if(is_kinda_truthy(this.context[name])) {
|
222
|
+
value = this.context[name];
|
223
|
+
}
|
224
|
+
|
225
|
+
if(typeof value === "function") {
|
226
|
+
return value.apply(context);
|
227
|
+
}
|
228
|
+
if(value !== undefined) {
|
229
|
+
return value;
|
230
|
+
}
|
231
|
+
// silently ignore unkown variables
|
232
|
+
return "";
|
233
|
+
},
|
234
|
+
|
235
|
+
// Utility methods
|
236
|
+
|
237
|
+
/* includes tag */
|
238
|
+
includes: function(needle, haystack) {
|
239
|
+
return haystack.indexOf(this.otag + needle) != -1;
|
240
|
+
},
|
241
|
+
|
242
|
+
/*
|
243
|
+
Does away with nasty characters
|
244
|
+
*/
|
245
|
+
escape: function(s) {
|
246
|
+
s = String(s === null ? "" : s);
|
247
|
+
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
|
248
|
+
switch(s) {
|
249
|
+
case "&": return "&";
|
250
|
+
case "\\": return "\\\\";
|
251
|
+
case '"': return '"';
|
252
|
+
case "'": return ''';
|
253
|
+
case "<": return "<";
|
254
|
+
case ">": return ">";
|
255
|
+
default: return s;
|
256
|
+
}
|
257
|
+
});
|
258
|
+
},
|
259
|
+
|
260
|
+
// by @langalex, support for arrays of strings
|
261
|
+
create_context: function(_context) {
|
262
|
+
if(this.is_object(_context)) {
|
263
|
+
return _context;
|
264
|
+
} else {
|
265
|
+
var iterator = ".";
|
266
|
+
if(this.pragmas["IMPLICIT-ITERATOR"]) {
|
267
|
+
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
|
268
|
+
}
|
269
|
+
var ctx = {};
|
270
|
+
ctx[iterator] = _context;
|
271
|
+
return ctx;
|
272
|
+
}
|
273
|
+
},
|
274
|
+
|
275
|
+
is_object: function(a) {
|
276
|
+
return a && typeof a == "object";
|
277
|
+
},
|
278
|
+
|
279
|
+
is_array: function(a) {
|
280
|
+
return Object.prototype.toString.call(a) === '[object Array]';
|
281
|
+
},
|
282
|
+
|
283
|
+
/*
|
284
|
+
Gets rid of leading and trailing whitespace
|
285
|
+
*/
|
286
|
+
trim: function(s) {
|
287
|
+
return s.replace(/^\s*|\s*$/g, "");
|
288
|
+
},
|
289
|
+
|
290
|
+
/*
|
291
|
+
Why, why, why? Because IE. Cry, cry cry.
|
292
|
+
*/
|
293
|
+
map: function(array, fn) {
|
294
|
+
if (typeof array.map == "function") {
|
295
|
+
return array.map(fn);
|
296
|
+
} else {
|
297
|
+
var r = [];
|
298
|
+
var l = array.length;
|
299
|
+
for(var i = 0; i < l; i++) {
|
300
|
+
r.push(fn(array[i]));
|
301
|
+
}
|
302
|
+
return r;
|
303
|
+
}
|
304
|
+
}
|
305
|
+
};
|
306
|
+
|
307
|
+
return({
|
308
|
+
name: "mustache.js",
|
309
|
+
version: "0.3.1-dev",
|
310
|
+
|
311
|
+
/*
|
312
|
+
Turns a template and view into HTML
|
313
|
+
*/
|
314
|
+
to_html: function(template, view, partials, send_fun) {
|
315
|
+
var renderer = new Renderer();
|
316
|
+
if(send_fun) {
|
317
|
+
renderer.send = send_fun;
|
318
|
+
}
|
319
|
+
renderer.render(template, view, partials);
|
320
|
+
if(!send_fun) {
|
321
|
+
return renderer.buffer.join("\n");
|
322
|
+
}
|
323
|
+
}
|
324
|
+
});
|
325
|
+
}();
|