From: Scott Baker Date: Tue, 8 Jul 2014 00:06:07 +0000 (-0700) Subject: xoslib wip X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=1dd345e62241dcd1b4560826d83a43f7c56bbbae;p=plstackapi.git xoslib wip --- diff --git a/planetstack/core/xoslib/README b/planetstack/core/xoslib/README new file mode 100644 index 0000000..a5af121 --- /dev/null +++ b/planetstack/core/xoslib/README @@ -0,0 +1,7 @@ +Add to the following in settings.py + + STATICFILES_DIRS= + "/opt/planetstack/core/xoslib/static/", + + TEMPLATE_DIRS= + "/opt/planetstack/xoslib/templates", \ No newline at end of file diff --git a/planetstack/core/xoslib/dashboards/sliverListTest.html b/planetstack/core/xoslib/dashboards/sliverListTest.html new file mode 100644 index 0000000..2238181 --- /dev/null +++ b/planetstack/core/xoslib/dashboards/sliverListTest.html @@ -0,0 +1,26 @@ +{% load mustache %} +{% load straight_include %} + + + + + + + + + + + + + + + +
+ {% mustache "mustache/listApp" %} +
diff --git a/planetstack/core/xoslib/static/js/sliverListTest.js b/planetstack/core/xoslib/static/js/sliverListTest.js new file mode 100644 index 0000000..294ffd3 --- /dev/null +++ b/planetstack/core/xoslib/static/js/sliverListTest.js @@ -0,0 +1,177 @@ +(function(){ + +window.SliverView = Backbone.View.extend({ + tagName: 'li', + className: 'XOSLib.sliver', + + events: { + 'click .permalink': 'navigate' + }, + + initialize: function(){ + this.model.bind('change', this.render, this); + }, + + navigate: function(e){ + this.trigger('navigate', this.model); + e.preventDefault(); + }, + + render: function(){ + $(this.el).html(ich.sliverTemplate(this.model.toJSON())); + return this; + } +}); + + +window.DetailApp = Backbone.View.extend({ + events: { + 'click .home': 'home' + }, + + home: function(e){ + this.trigger('home'); + e.preventDefault(); + }, + + render: function(){ + $(this.el).html(ich.detailApp(this.model.toJSON())); + return this; + } +}); + +window.InputView = Backbone.View.extend({ + events: { + 'click .sliver': 'createSliver', + 'keypress #message': 'createOnEnter' + }, + + createOnEnter: function(e){ + if((e.keyCode || e.which) == 13){ + this.createSliver(); + e.preventDefault(); + } + + }, + + createSliver: function(){ + var message = this.$('#message').val(); + if(message){ + this.collection.create({ + message: message + }); + this.$('#message').val(''); + } + } + +}); + +window.ListView = Backbone.View.extend({ + initialize: function(){ + _.bindAll(this, 'addOne', 'addAll'); + + this.collection.bind('add', this.addOne); + this.collection.bind('reset', this.addAll, this); + this.views = []; + }, + + addAll: function(){ + this.views = []; + this.collection.each(this.addOne); + }, + + addOne: function(sliver){ + var view = new SliverView({ + model: XOSLib.sliver + }); + $(this.el).prepend(view.render().el); + this.views.push(view); + view.bind('all', this.rethrow, this); + }, + + rethrow: function(){ + this.trigger.apply(this, arguments); + } + +}); + +window.ListApp = Backbone.View.extend({ + el: "#app", + + rethrow: function(){ + this.trigger.apply(this, arguments); + }, + + render: function(){ + console.log("listApp.render"); + $(this.el).html(ich.listApp({})); + var list = new ListView({ + collection: this.collection, + el: this.$('#slivers') + }); + list.addAll(); + list.bind('all', this.rethrow, this); + new InputView({ + collection: this.collection, + el: this.$('#input') + }); + } +}); + + +window.Router = Backbone.Router.extend({ + routes: { + '': 'list', + ':id/': 'detail' + }, + + navigate_to: function(model){ + var path = (model && model.get('id') + '/') || ''; + console.log("Router.navigate_to"); + this.navigate(path, true); + }, + + detail: function(){ console.log("Router.detail"); }, + + list: function(){ console.log("Router.list"); } +}); + +$(function(){ + window.app = window.app || {}; + app.router = new Router(); + app.slivers = new XOSLib.slivers(); + app.list = new ListApp({ + el: $("#app"), + collection: app.slivers + }); + app.detail = new DetailApp({ + el: $("#app") + }); + app.router.bind('route:list', function(){ + console.log("Router:list2"); + app.slivers.maybeFetch({ + success: _.bind(app.list.render, app.list) + }); + }); + app.router.bind('route:detail', function(id){ + console.log("Router:detail2"); + app.slivers.getOrFetch(app.slivers.urlRoot + id + '/', { + success: function(model){ + app.detail.model = model; + app.detail.render(); + } + }); + }); + + app.slivers.maybeFetch({ + success: _.bind(app.list.render, app.list) + }); + + app.list.bind('navigate', app.router.navigate_to, app.router); + app.detail.bind('home', app.router.navigate_to, app.router); + Backbone.history.start({ + pushState: true, + silent: app.loaded + }); +}); +})(); diff --git a/planetstack/core/xoslib/static/js/xos-backbone.js b/planetstack/core/xoslib/static/js/xos-backbone.js new file mode 100644 index 0000000..99f0784 --- /dev/null +++ b/planetstack/core/xoslib/static/js/xos-backbone.js @@ -0,0 +1,49 @@ +SLIVER_API = "/plstackapi/slivers/"; + +XOSCollection = Backbone.Collection.extend({ + maybeFetch: function(options){ + // Helper function to fetch only if this collection has not been fetched before. + if(this._fetched){ + // If this has already been fetched, call the success, if it exists + options.success && options.success(); + console.log("alreadyFetched"); + return; + } + + // when the original success function completes mark this collection as fetched + var self = this, + successWrapper = function(success){ + return function(){ + self._fetched = true; + success && success.apply(this, arguments); + }; + }; + options.success = successWrapper(options.success); + console.log("call fetch"); + this.fetch(options); + }, + + getOrFetch: function(id, options){ + // Helper function to use this collection as a cache for models on the server + var model = this.get(id); + + if(model){ + options.success && options.success(model); + return; + } + + model = new Sliver({ + resource_uri: id + }); + + model.fetch(options); + } +}); + +function xoslib() { + this.sliver = Backbone.Model.extend({ urlRoot: SLIVER_API }); + this.slivers = XOSCollection.extend({ urlRoot: SLIVER_API, + model: this.sliver}); +}; + +XOSLib = new xoslib(); diff --git a/planetstack/core/xoslib/templates/mustache/detailApp.mustache b/planetstack/core/xoslib/templates/mustache/detailApp.mustache new file mode 100644 index 0000000..e415945 --- /dev/null +++ b/planetstack/core/xoslib/templates/mustache/detailApp.mustache @@ -0,0 +1,8 @@ +

+ All Slivers +

+ diff --git a/planetstack/core/xoslib/templates/mustache/listApp.mustache b/planetstack/core/xoslib/templates/mustache/listApp.mustache new file mode 100644 index 0000000..3af7ebe --- /dev/null +++ b/planetstack/core/xoslib/templates/mustache/listApp.mustache @@ -0,0 +1,3 @@ +

All Slivers

+ diff --git a/planetstack/core/xoslib/templates/mustache/sliverTemplate.mustache b/planetstack/core/xoslib/templates/mustache/sliverTemplate.mustache new file mode 100644 index 0000000..9959a19 --- /dev/null +++ b/planetstack/core/xoslib/templates/mustache/sliverTemplate.mustache @@ -0,0 +1 @@ + diff --git a/planetstack/core/xoslib/templatetags/mustache.py b/planetstack/core/xoslib/templatetags/mustache.py new file mode 100644 index 0000000..a3b3b2a --- /dev/null +++ b/planetstack/core/xoslib/templatetags/mustache.py @@ -0,0 +1,51 @@ +from django import template +from django.conf import settings +import pystache +import os + +register = template.Library() + +class View(pystache.View): + template_path = settings.TEMPLATE_DIRS[0] + + def __init__(self, template_dir, template_name, context): + self.template_path = template_dir + self.template_name = template_name + return super(View, self).__init__(context=context) + +class MustacheNode(template.Node): + def __init__(self, template_name, attr=None): + for template_dir in settings.TEMPLATE_DIRS: + if os.path.exists(os.path.join(template_dir, template_name) + ".mustache"): + break + else: + raise IOError("failed to find %s in %s" % (template_name, str(settings.TEMPLATE_DIRS))) + + self.template_path = template_dir + self.template = template_name + self.attr = attr + + def render(self, context): + mcontext = context[self.attr] if self.attr else {} + view = View(self.template_path, self.template, context=mcontext) + return view.render() + +def do_mustache(parser, token): + """ + Loads a mustache template and render it inline + + Example:: + + {% mustache "foo/bar" data %} + + """ + bits = token.split_contents() + if len(bits) not in [2,3]: + raise template.TemplateSyntaxError("%r tag takes two arguments: the location of the template file, and the template context" % bits[0]) + path = bits[1] + path = path[1:-1] + attrs = bits[2:] + return MustacheNode(path, *attrs) + + +register.tag("mustache", do_mustache) diff --git a/planetstack/core/xoslib/templatetags/straight_include.py b/planetstack/core/xoslib/templatetags/straight_include.py new file mode 100644 index 0000000..54710f3 --- /dev/null +++ b/planetstack/core/xoslib/templatetags/straight_include.py @@ -0,0 +1,62 @@ +""" +Straight Include template tag by @HenrikJoreteg + +Django templates don't give us any way to escape template tags. + +So if you ever need to include client side templates for ICanHaz.js (or anything else that +may confuse django's templating engine) You can is this little snippet. + +Just use it as you would a normal {% include %} tag. It just won't process the included text. + +It assumes your included templates are in you django templates directory. + +Usage: + +{% load straight_include %} + +{% straight_include "my_icanhaz_templates.html" %} + +""" + +import os +from django import template +from django.conf import settings + + +register = template.Library() + + +class StraightIncludeNode(template.Node): + def __init__(self, template_path): + for template_dir in settings.TEMPLATE_DIRS: + self.filepath = '%s/%s' % (template_dir, template_path) + if os.path.exists(self.filepath): + break + else: + raise IOError("cannot find %s in %s" % (template_path, str(TEMPLATE_DIRS))) + + def render(self, context): + fp = open(self.filepath, 'r') + output = fp.read() + fp.close() + return output + + +def do_straight_include(parser, token): + """ + Loads a template and includes it without processing it + + Example:: + + {% straight_include "foo/some_include" %} + + """ + bits = token.split_contents() + if len(bits) != 2: + raise template.TemplateSyntaxError("%r tag takes one argument: the location of the file within the template folder" % bits[0]) + path = bits[1][1:-1] + + return StraightIncludeNode(path) + + +register.tag("straight_include", do_straight_include) diff --git a/planetstack/core/xoslib/up.sh b/planetstack/core/xoslib/up.sh new file mode 100755 index 0000000..1121892 --- /dev/null +++ b/planetstack/core/xoslib/up.sh @@ -0,0 +1,3 @@ +scp static/js/*.js princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/core/xoslib/static/js/ +scp templates/mustache/*.mustache princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/core/xoslib/templates/mustache/ +scp dashboards/*.html princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/templates/admin/dashboard/