Skip to content

Instantly share code, notes, and snippets.

@cuppster
Created January 27, 2013 01:08
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 cuppster/4645643 to your computer and use it in GitHub Desktop.
Save cuppster/4645643 to your computer and use it in GitHub Desktop.
Backbone.js client for Leonardo API
// ## 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