summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/fastdom-promised.js77
-rw-r--r--extensions/fastdom-sandbox.js147
2 files changed, 224 insertions, 0 deletions
diff --git a/extensions/fastdom-promised.js b/extensions/fastdom-promised.js
new file mode 100644
index 0000000..e002072
--- /dev/null
+++ b/extensions/fastdom-promised.js
@@ -0,0 +1,77 @@
+!(function() {
+
+/**
+ * Wraps fastdom in a Promise API
+ * for improved control-flow.
+ *
+ * @example
+ *
+ * // returning a result
+ * fastdom.measure(() => el.clientWidth)
+ * .then(result => ...);
+ *
+ * // returning promises from tasks
+ * fastdom.measure(() => {
+ * var w = el1.clientWidth;
+ * return fastdom.mutate(() => el2.style.width = w + 'px');
+ * }).then(() => console.log('all done'));
+ *
+ * // clearing pending tasks
+ * var promise = fastdom.measure(...)
+ * fastdom.clear(promise);
+ *
+ * @type {Object}
+ */
+var exports = {
+ initialize: function() {
+ this._tasks = new Map();
+ },
+
+ mutate: function(fn, ctx) {
+ return create(this, 'mutate', fn, ctx);
+ },
+
+ measure: function(fn, ctx) {
+ return create(this, 'measure', fn, ctx);
+ },
+
+ clear: function(promise) {
+ var tasks = this._tasks;
+ var task = tasks.get(promise);
+ this.fastdom.clear(task);
+ tasks.delete(task);
+ }
+};
+
+/**
+ * Create a fastdom task wrapped in
+ * a 'cancellable' Promise.
+ *
+ * @param {FastDom} fastdom
+ * @param {String} type - 'measure'|'muatate'
+ * @param {Function} fn
+ * @return {Promise}
+ */
+function create(promised, type, fn, ctx) {
+ var tasks = promised._tasks;
+ var fastdom = promised.fastdom;
+ var task;
+
+ var promise = new Promise(function(resolve, reject) {
+ task = fastdom[type](function() {
+ tasks.delete(promise);
+ try { resolve(fn()); }
+ catch (e) { reject(e); }
+ }, ctx);
+ });
+
+ tasks.set(promise, task);
+ return promise;
+}
+
+// Expose to CJS, AMD or global
+if ((typeof define)[0] == 'f') define(function() { return exports; });
+else if ((typeof module)[0] == 'o') module.exports = exports;
+else window.fastdomPromised = exports;
+
+})(); \ No newline at end of file
diff --git a/extensions/fastdom-sandbox.js b/extensions/fastdom-sandbox.js
new file mode 100644
index 0000000..39afc28
--- /dev/null
+++ b/extensions/fastdom-sandbox.js
@@ -0,0 +1,147 @@
+(function(exports) {
+
+/**
+ * Mini logger
+ *
+ * @return {Function}
+ */
+var debug = 0 ? console.log.bind(console, '[fastdom-sandbox]') : function() {};
+
+/**
+ * Exports
+ */
+
+/**
+ * Create a new `Sandbox`.
+ *
+ * Scheduling tasks via a sandbox is
+ * useful because you can clear all
+ * sandboxed tasks in one go.
+ *
+ * This is handy when working with view
+ * components. You can create one sandbox
+ * per component and call `.clear()` when
+ * tearing down.
+ *
+ * @example
+ *
+ * var sandbox = fastdom.sandbox();
+ *
+ * sandbox.measure(function() { console.log(1); });
+ * sandbox.measure(function() { console.log(2); });
+ *
+ * fastdom.measure(function() { console.log(3); });
+ * fastdom.measure(function() { console.log(4); });
+ *
+ * sandbox.clear();
+ *
+ * // => 3
+ * // => 4
+ *
+ * @return {Sandbox}
+ * @public
+ */
+exports.sandbox = function() {
+ return new Sandbox(this.fastdom);
+};
+
+/**
+ * Initialize a new `Sandbox`
+ *
+ * @param {FastDom} fastdom
+ */
+
+function Sandbox(fastdom) {
+ this.fastdom = fastdom;
+ this.tasks = [];
+ debug('initialized');
+}
+
+/**
+ * Schedule a 'measure' task.
+ *
+ * @param {Function} fn
+ * @param {Object} ctx
+ * @return {Object} can be passed to .clear()
+ */
+Sandbox.prototype.measure = function(fn, ctx) {
+ var tasks = this.tasks;
+ var task = this.fastdom.measure(function() {
+ tasks.splice(tasks.indexOf(task));
+ fn.call(ctx);
+ });
+
+ tasks.push(task);
+ return task;
+};
+
+/**
+ * Schedule a 'mutate' task.
+ *
+ * @param {Function} fn
+ * @param {Object} ctx
+ * @return {Object} can be passed to .clear()
+ */
+Sandbox.prototype.mutate = function(fn, ctx) {
+ var tasks = this.tasks;
+ var task = this.fastdom.mutate(function() {
+ tasks.splice(tasks.indexOf(task));
+ fn.call(ctx);
+ });
+
+ this.tasks.push(task);
+ return task;
+};
+
+/**
+ * Clear a single task or is no task is
+ * passsed, all tasks in the `Sandbox`.
+ *
+ * @param {Object} task (optional)
+ */
+
+Sandbox.prototype.clear = function(task) {
+ if (!arguments.length) clearAll(this.fastdom, this.tasks);
+ remove(this.tasks, task);
+ return this.fastdom.clear(task);
+};
+
+/**
+ * Clears all the given tasks from
+ * the given `FastDom`.
+ *
+ * @param {FastDom} fastdom
+ * @param {Array} tasks
+ * @private
+ */
+
+function clearAll(fastdom, tasks) {
+ debug('clear all', fastdom, tasks);
+ var i = tasks.length;
+ while (i--) {
+ fastdom.clear(tasks[i]);
+ tasks.splice(i, 1);
+ }
+}
+
+/**
+ * Remove an item from an Array.
+ *
+ * @param {Array} array
+ * @param {*} item
+ * @return {Boolean}
+ */
+function remove(array, item) {
+ var index = array.indexOf(item);
+ return !!~index && !!array.splice(index, 1);
+}
+
+/**
+ * Expose
+ */
+
+if ((typeof define)[0] == 'f') define(function() { return exports; });
+else if ((typeof module)[0] == 'o') module.exports = exports;
+else window.fastdomSandbox = exports;
+
+})({});