From f61d15e3eba275b687997bd84d35ce15d4337597 Mon Sep 17 00:00:00 2001 From: Geoff Schmidt Date: Fri, 27 Jul 2012 00:07:33 -0700 Subject: [PATCH] Create Spark package. WIP --- packages/spark/package.js | 43 +++++++++++++++++++ packages/spark/spark.js | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 packages/spark/package.js create mode 100644 packages/spark/spark.js diff --git a/packages/spark/package.js b/packages/spark/package.js new file mode 100644 index 0000000000..2f78e7e823 --- /dev/null +++ b/packages/spark/package.js @@ -0,0 +1,43 @@ +Package.describe({ + summary: "Toolkit for live-updating HTML interfaces", + internal: true +}); + +Package.on_use(function (api) { + api.use('livedata'); + api.use(['underscore', 'session'], 'client'); + + // XXX Depends on jquery because we need a selector engine to resolve + // event maps. What would be nice is, if you've included jquery or + // zepto, use one of those; if not, ship our own copy of sizzle (but, + // you still want the event object normalization that jquery provides?) + api.use('jquery'); + + api.add_files('spark.js', 'client'); +/* + api.add_files(['liveevents_w3c.js', 'liveevents_now3c.js'], 'client'); + api.add_files(['liveevents.js'], 'client'); + api.add_files(['livedocument.js'], 'client'); + api.add_files(['liverange.js', 'liveui.js', 'innerhtml.js', 'patcher.js'], + 'client'); +*/ +}); + +Package.on_test(function (api) { +/* + api.use(['tinytest', 'templating', 'htmljs']); + api.use(['liveui', 'test-helpers'], 'client'); + + api.add_files('form_responder.js', 'server'); + + api.add_files([ + 'livedocument_tests.js', + 'liverange_test_helpers.js', + 'liveui_tests.js', + 'liveui_tests.html', + 'liverange_tests.js', + 'patcher_tests.js', + 'liveevents_tests.js' + ], 'client'); +*/ +}); diff --git a/packages/spark/spark.js b/packages/spark/spark.js new file mode 100644 index 0000000000..71e6e6ef9a --- /dev/null +++ b/packages/spark/spark.js @@ -0,0 +1,88 @@ +// XXX figure out good liverange tag names. should they be symbolic constants? +// in liverange-land they should probably start with "_"? + + +Spark = Spark || {}; + +Spark._currentRenderer = new Meteor.EnvironmentVariable; + +Spark._Renderer = function () { + // Map from annotation ID to an annotation function, which is called + // at render time and receives (startNode, endNode.) + this.annotations = {}; +}; + +_.extend(Spark._Renderer.prototype, { + createId: function () { + var id = ""; + var chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + for (var i = 0; i < 8; i++) { + id += hexDigits.substr(Math.floor(Meteor.random() * 0x10), 1); + } + return id; + }, + + // what can be a function that takes a LiveRange, or just a set of + // attributes to add to the liverange. + annotate: function (html, tag, what) { + var id = tag + "-" + this.createId(); + this.annotations[id] = function (start, end) { + var range = new Meteor.ui._LiveRange(tag, start, end); + if (what instanceof Function) + what(range); + else + _.extend(range, what); + } + + return "<$" + id + ">" + html + ""; + } +}); + +Spark.render = function (htmlFunc) { + var renderer = new Spark.Renderer; + var html = Spark.currentRenderer.withValue(renderer, function () { + return Spark.barrier(htmlFunc); + }); + + // XXX turn html into DOM and attach liveranges + + + // HERE + // + // - Move LiveRange to global scope + // - Create DomUtils package (or something like that) + // - First thing in DomUtils is htmlToFragment from innerhtml.js + // - Later, will add stuff from domutils.js + // - _rangeToHtml will go in LiveRange (possibly the test helpers) + +}; + +Spark.setContext = function (html, context) { + var renderer = Spark._currentRenderer.get(); + if (!renderer) + return html; + + return renderer.annotate(html, "_context", { context: context }); +}; + +Spark.getContext = function (node) { + var range = Meteor.ui._LiveRange.findRange("_context", node); + return range && range.context; +} + +Spark.barrier = function (htmlFunc) { + var renderer = Spark._currentRenderer.get(); + if (!renderer) + return htmlFunc(); + + var ctx = new Meteor.deps.Context; + var html = + renderer.annotate(ctx.run(htmlFunc), "_barrier", function (range) { + ctx.on_invalidate(function () { + // XXX update with patching + }); + }); + + return html; +};