Created
January 27, 2013 01:08
-
-
Save cuppster/4645643 to your computer and use it in GitHub Desktop.
Backbone.js client for Leonardo API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ## global namespace | |
// | |
var Leo = {} | |
// ## Leonardo Options | |
// | |
Leo.options = (function() { | |
return { | |
api : 'http://dev.leonar.do/api', | |
agent : 'demo', | |
key : 'demo' | |
}; | |
})(); | |
// FIXME remove this! | |
Leo.ignoreArt = function(model) { | |
model.ignore(); | |
} | |
// ## custom backbone.js sync method | |
// | |
Leo.sync = function(method, model, options) { | |
// send auth headers | |
var new_options = _.extend({ | |
beforeSend: function(xhr) { | |
var cred = $.base64.encode(Leo.options.key + ':' + Leo.options.agent); | |
xhr.setRequestHeader("Authorization", "Basic " + cred); | |
} | |
}, options); | |
return Backbone.sync(method, model, new_options); | |
} | |
Leo.util = { | |
tasteString: function(taste) { | |
var verb = taste.get('verb'); | |
console.log('tasteString', taste); | |
switch (verb) { | |
case 0: | |
var thumb = taste.get('thumb'); | |
return {desc: 'Similar to', thumb: thumb }; | |
break; | |
case 2: | |
return {desc: 'With tag: ' + taste.get('tagtext')}; | |
break; | |
case 4: | |
return {desc: 'By Artist: ' + taste.get('artist_name')}; | |
break; | |
default: | |
return {desc: 'Other...'}; | |
} | |
}, | |
}; | |
// ## Sync Model, reused throughout | |
// | |
Leo.SyncModel = Backbone.Model.extend({ | |
sync: Leo.sync | |
}); | |
// ## Models | |
// | |
Leo.Models = (function() { | |
// ### Art Model | |
// | |
var ArtModel = Leo.SyncModel.extend({ | |
url : function() { | |
return Leo.options.api + '/art/' + this.id; | |
}, | |
// add to cart | |
// | |
putIntoCart : function() { | |
var cartCollection = new Leo.Collections.Cart(); | |
cartCollection.create(new Leo.SyncModel({lid: this.id})); | |
}, | |
// mark this art as 'seen' | |
// | |
markSeen : function() { | |
var seenCollection = new Leo.Collections.SeenArt(); | |
seenCollection.create(new Leo.SyncModel({lid: this.id})); | |
}, | |
// ignore this art work, it was 'skipped' | |
// | |
ignore: function() { | |
var taste = new Leo.Models.Taste({ | |
ignore : 'lid', | |
lid : this.id | |
}); | |
taste.save(null, { | |
success: function() { | |
console.log("saving IGNORE: ", this); | |
}, | |
error: function() { | |
alert('error saving taste'); | |
} | |
}); | |
}, | |
}); | |
// ### Taste Model | |
// | |
var TasteModel = Leo.SyncModel.extend({ | |
url: function() { | |
return Leo.options.api + '/taste'; | |
}, | |
}); | |
// ### Taste Collection Model | |
// | |
var TasteCollectionModel = Leo.SyncModel.extend({ | |
id: true, | |
url: function() { | |
return Leo.options.api + '/taste'; | |
}, | |
}); | |
// ## Artist Model | |
// | |
var ArtistModel = Leo.SyncModel.extend({ | |
url : function() { | |
return Leo.options.api + '/artists/' + this.id; | |
}, | |
}); | |
// ### Group Collection Model | |
// | |
var CartCollectionModel = Leo.SyncModel.extend({ | |
id: true, | |
url: function() { | |
return Leo.options.api + '/cart'; | |
}, | |
}); | |
// interface | |
// | |
return { | |
Art : ArtModel, | |
Taste : TasteModel, | |
TasteCollection : TasteCollectionModel, | |
Artist : ArtistModel, | |
CartCollection : CartCollectionModel | |
}; | |
})(); | |
// ## Collections | |
// | |
Leo.Collections = (function() { | |
// ## Taste Collection | |
// | |
var TasteCollection = Backbone.Collection.extend({ | |
initialize: function(models, options) { | |
this.options = options || {}; | |
_.defaults(this.options, { label: 'default' }); | |
}, | |
url : function() { return Leo.options.api + '/taste/' + this.options.label; }, | |
model: Leo.Models.Taste, | |
// ### Retrieve an instance of this collection as a model | |
// | |
asModel: function() { | |
return new Leo.Models.TasteCollection(); | |
}, | |
sync: function(method, model, options) { | |
options['data'] = { count: 50 }; | |
return Leo.sync(method, model, options); | |
}, | |
parse: function(response) { | |
response = _.map(response, function(taste) { | |
switch (taste.verb) { | |
case 2: /* tag like */ | |
return { tag: taste.context, karma: taste.karma }; | |
case 4: /* artist like */ | |
return { artist: taste.artist_name, karma: taste.karma }; | |
default: | |
return { tag: 'unknown' }; | |
} | |
}); | |
return response; | |
} | |
}); | |
// ### Recommendations By Single Taste | |
// | |
var RecommendationByTaste = Backbone.Collection.extend({ | |
model: Leo.Models.Taste, | |
url : function() { return Leo.options.api + '/suggest/taste/' + this.options.tasteid; }, | |
sync: Leo.sync, | |
initialize: function(models, options) { | |
this.options = options; | |
}, | |
}); | |
// ### Recommendation Tastes | |
// | |
var RecommendationTastes = Backbone.Collection.extend({ | |
model: Leo.Models.Taste, | |
url : function() { return Leo.options.api + '/suggest/tastes'; }, | |
sync: function(method, model, options) { | |
// merge | |
_.extend(options['data'], this.options); | |
console.log('options', options); | |
return Leo.sync(method, model, options); | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
}, | |
}); | |
// ### Recommendation Tastes | |
// | |
var RecommendationTopTastes = Backbone.Collection.extend({ | |
model: Leo.Models.Taste, | |
url : function() { return Leo.options.api + '/suggest/tastes/top'; }, | |
sync: function(method, model, options) { | |
// set data to send | |
options['data'] = {}; | |
// merge | |
_.extend(options['data'], _.pick(this.options, 'global')); | |
return Leo.sync(method, model, options); | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
}, | |
}); | |
// ### Cart Recommendation Collection | |
// | |
var CartRecommendations = Backbone.Collection.extend({ | |
model: Leo.Models.Art, | |
options: {}, | |
url : function() { return Leo.options.api + '/suggest/cart'; }, | |
sync: function(method, model, options) { | |
// empty rest data | |
var restData = {}; | |
// max count | |
restData.count = 50; | |
// set data to send | |
options['data'] = restData; | |
// merge | |
_.extend(options['data'], this.options); | |
return Leo.sync(method, model, options); | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
}, | |
}); | |
// ### Recommendation Collection | |
// | |
var Recommendations = Backbone.Collection.extend({ | |
model: Leo.Models.Art, | |
options: {}, | |
url : function() { return Leo.options.api + '/suggest'; }, | |
sync: function(method, model, options) { | |
// empty rest data | |
var restData = {}; | |
// max count | |
restData.count = 50; | |
// set data to send | |
options['data'] = restData; | |
// merge | |
_.extend(options['data'], this.options); | |
console.log('options', options); | |
return Leo.sync(method, model, options); | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
}, | |
}); | |
// ### Streaming Recommendations | |
// | |
var StreamRecommendations = Recommendations.extend({ | |
url : function() { return Leo.options.api + '/stream/suggest'; }, | |
}); | |
// ### Art Collection | |
// | |
var LeoArtCollection = Backbone.Collection.extend({ | |
model: Leo.Models.Art, | |
sync: function(method, model, options) { | |
var params = {}; | |
if (this.options.id) | |
params.ids = this.options.ids; | |
if (this.options.title) | |
params.title = this.options.title; | |
if (this.options.artist) | |
params.artist = this.options.artist; | |
if (this.options.artistid) | |
params.artistid = this.options.artistid; | |
if (this.options.tags) | |
params.tags = this.options.tags; | |
if (this.options.tag) | |
params.tag = this.options.tag; | |
if (this.options.count) | |
params.count = this.options.count; | |
if (this.options.coll) | |
params.coll = this.options.coll; | |
if (this.options.random) | |
params.random = 1; | |
if (this.options.unseen) | |
params.unseen = 1; | |
if (this.options.artistid) | |
params.artistid = this.options.artistid | |
if (this.options.maxtaggedcount) | |
params.maxtaggedcount = this.options.maxtaggedcount; | |
if (this.options.keyword) | |
params.q = this.options.keyword; | |
options['data'] = params; | |
return Leo.sync(method, model, options); | |
}, | |
url : function() { | |
return Leo.options.api + '/art'; | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
} | |
}); | |
// ## "Liked" Art | |
// | |
var LeoArtLikes = LeoArtCollection.extend({ | |
url : function() { | |
return Leo.options.api + '/art/like'; | |
}, | |
}); | |
//## Artist Collection | |
// | |
var LeoArtistCollection = Backbone.Collection.extend({ | |
model: Leo.Models.Artist, | |
sync: function(method, model, options) { | |
var params = {}; | |
//params.hastags = 1; | |
if (this.options.artist) | |
params.artist = this.options.artist; | |
options['data'] = params; | |
return Leo.sync(method, model, options); | |
}, | |
url : function() { | |
return Leo.options.api + '/artists'; | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
} | |
}); | |
// ## Shopping Cart Collection | |
// | |
var LeoCartCollection = Backbone.Collection.extend({ | |
sync: Leo.sync, | |
url: function() { | |
return Leo.options.api + '/cart'; | |
}, | |
// ### Retrieve an instance of this collection as a model | |
// | |
asModel: function() { | |
return new Leo.Models.CartCollection(/* TODO: init with group id */); | |
}, | |
}); | |
// ## Art that's been marked as 'seen' | |
// | |
var LeoSeenArtCollection = Backbone.Collection.extend({ | |
sync: Leo.sync, | |
url: function() { | |
return Leo.options.api + '/art/seen'; | |
} | |
}); | |
// ## Feature Stream Collection | |
// | |
var LeoStreamCollection = Backbone.Collection.extend({ | |
sync: Leo.sync, | |
url : function() { | |
return Leo.options.api + '/features/' + this.options.streamid; | |
}, | |
initialize: function(models, options) { | |
this.options = options || {}; | |
} | |
}); | |
// interface | |
return { | |
Tastes : TasteCollection, | |
Recommendations : Recommendations, | |
RecommendationTastes : RecommendationTastes, | |
RecommendationTopTastes : RecommendationTopTastes, | |
RecommendationByTaste : RecommendationByTaste, | |
StreamRecommendations : StreamRecommendations, | |
Likes : LeoArtLikes, | |
Art : LeoArtCollection, | |
Artists : LeoArtistCollection, | |
Stream : LeoStreamCollection, | |
SeenArt : LeoSeenArtCollection, | |
Cart : LeoCartCollection, | |
CartRecommendations : CartRecommendations | |
}; | |
})(); | |
// ## A special view that understands "View Models" | |
// | |
// If 'models' is passed via view options, | |
// models is set on the view. | |
// | |
// A special hash can setup property change events: | |
// | |
// | |
Backbone.ViewModelView = Backbone.View.extend({ | |
_simpleViewModels: function(keys) { | |
if (_.isObject(keys)) | |
return keys.toJSON(); // model was passed | |
var simple = {}; // do more than one model | |
if (this.models) { | |
if (!keys) | |
keys = _.keys(this.models); | |
var view = this; | |
_.each(keys, function(key) { | |
simple[key] = view.models[key].toJSON(); | |
}); | |
} | |
return simple; | |
}, | |
_initViewModels: function() { | |
if (this.options.models) { | |
this.models = this.options.models; | |
delete this.options.models; | |
if (this.modelEvents) { | |
var view = this; | |
_.each(_.keys(view.modelEvents), function(key) { | |
var parts = key.split(' '); | |
if (2 <= parts.length) { | |
var handler = view.modelEvents[key]; | |
var event = parts[0]; | |
var model = parts[1]; | |
var sel = (3 == parts.length) ? parts[2] : _.isString(handler) ? handler : null; | |
if (view.models[model]) { | |
if (_.isFunction(handler)) | |
view.models[model].on(event, handler, view); | |
if (sel) { | |
view.$el.find(sel).data('model', view.models[model]); // attached model as data to DOM el | |
var updateHandler = function() { | |
var eventParts = event.split(':'); | |
if (2 == eventParts.length) { | |
var prop = eventParts[1]; | |
view.$el.find(sel).text(view.models[model].get(prop)); | |
} | |
} | |
updateHandler(); // udpate immediately | |
view.models[model].on(event, updateHandler); // udpate on event | |
} | |
} | |
} | |
}); | |
} | |
} | |
}, | |
initialize: function() { | |
this._initViewModels(); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment