Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

templejs

Package Overview
Dependencies
Maintainers
2
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

templejs - npm Package Compare versions

Comparing version 0.2.12 to 0.3.1

lib/binding.js

4

bower.json
{
"name": "temple",
"version": "0.2.11",
"version": "0.3.0-alpha",
"description": "A modern JavaScript view framework.",

@@ -29,2 +29,2 @@ "repo": "BeneathTheInk/Temple",

]
}
}
{
"name": "temple",
"version": "0.2.11",
"version": "0.3.0-alpha",
"description": "A modern JavaScript view framework.",

@@ -25,2 +25,2 @@ "repository": "BeneathTheInk/Temple",

]
}
}

@@ -0,1 +1,4 @@

// Copy of https://github.com/meteor/meteor/commits/e78861b7d0dbb60e5e2bf59bab2cb06ce6596c04/packages/deps/deps.js
// (c) 2011-2014 Meteor Development Group
//////////////////////////////////////////////////

@@ -5,4 +8,3 @@ // Package docs at http://docs.meteor.com/#deps //

var Deps =
module.exports = {};
var Deps = module.exports = {};

@@ -20,14 +22,2 @@ // http://docs.meteor.com/#deps_active

// _assign is like _.extend or the upcoming Object.assign.
// Copy src's own, enumerable properties onto tgt and return
// tgt.
var _hasOwnProperty = Object.prototype.hasOwnProperty;
var _assign = function (tgt, src) {
for (var k in src) {
if (_hasOwnProperty.call(src, k))
tgt[k] = src[k];
}
return tgt;
};
var _debugFunc = function () {

@@ -50,13 +40,17 @@ // lazy evaluation because `Meteor` does not exist right away

// Like `Meteor._noYieldsAllowed(function () { f(comp); })` but shorter,
// and doesn't clutter the stack with an extra frame on the client,
// where `_noYieldsAllowed` is a no-op. `f` may be a computation
// function or an onInvalidate callback.
var callWithNoYieldsAllowed = function (f, comp) {
// Takes a function `f`, and wraps it in a `Meteor._noYieldsAllowed`
// block if we are running on the server. On the client, returns the
// original function (since `Meteor._noYieldsAllowed` is a
// no-op). This has the benefit of not adding an unnecessary stack
// frame on the client.
var withNoYieldsAllowed = function (f) {
if ((typeof Meteor === 'undefined') || Meteor.isClient) {
f(comp);
return f;
} else {
Meteor._noYieldsAllowed(function () {
f(comp);
});
return function () {
var args = arguments;
Meteor._noYieldsAllowed(function () {
f.apply(null, args);
});
};
}

@@ -88,3 +82,3 @@ };

if (! willFlush) {
requestAnimationFrame(Deps.flush);
setTimeout(Deps.flush, 0);
willFlush = true;

@@ -101,3 +95,3 @@ }

//
Deps.Computation = function (f, parent) {
Deps.Computation = function (f, parent, ctx) {
if (! constructingComputation)

@@ -125,2 +119,3 @@ throw new Error(

self._func = f;
self._context = ctx || this;
self._recomputing = false;

@@ -139,91 +134,89 @@

_assign(Deps.Computation.prototype, {
// http://docs.meteor.com/#computation_oninvalidate
Deps.Computation.prototype.onInvalidate = function (f, ctx) {
var self = this;
// http://docs.meteor.com/#computation_oninvalidate
onInvalidate: function (f) {
var self = this;
if (typeof f !== 'function')
throw new Error("onInvalidate requires a function");
if (typeof f !== 'function')
throw new Error("onInvalidate requires a function");
if (self.invalidated) {
Deps.nonreactive(function () {
withNoYieldsAllowed(f).call(ctx || self._context, self);
});
} else {
f._context = ctx;
self._onInvalidateCallbacks.push(f);
}
};
if (self.invalidated) {
Deps.nonreactive(function () {
callWithNoYieldsAllowed(f, self);
});
} else {
self._onInvalidateCallbacks.push(f);
// http://docs.meteor.com/#computation_invalidate
Deps.Computation.prototype.invalidate = function () {
var self = this;
if (! self.invalidated) {
// if we're currently in _recompute(), don't enqueue
// ourselves, since we'll rerun immediately anyway.
if (! self._recomputing && ! self.stopped) {
requireFlush();
pendingComputations.push(this);
}
},
// http://docs.meteor.com/#computation_invalidate
invalidate: function () {
var self = this;
if (! self.invalidated) {
// if we're currently in _recompute(), don't enqueue
// ourselves, since we'll rerun immediately anyway.
if (! self._recomputing && ! self.stopped) {
requireFlush();
pendingComputations.push(this);
}
self.invalidated = true;
self.invalidated = true;
// callbacks can't add callbacks, because
// self.invalidated === true.
for(var i = 0, f; f = self._onInvalidateCallbacks[i]; i++) {
Deps.nonreactive(function () {
callWithNoYieldsAllowed(f, self);
});
}
self._onInvalidateCallbacks = [];
// callbacks can't add callbacks, because
// self.invalidated === true.
for(var i = 0, f; f = self._onInvalidateCallbacks[i]; i++) {
Deps.nonreactive(function () {
withNoYieldsAllowed(f).call(f._context || self._context, self);
});
}
},
self._onInvalidateCallbacks = [];
}
};
// http://docs.meteor.com/#computation_stop
stop: function () {
if (! this.stopped) {
this.stopped = true;
this.invalidate();
}
},
// http://docs.meteor.com/#computation_stop
Deps.Computation.prototype.stop = function () {
if (! this.stopped) {
this.stopped = true;
this.invalidate();
}
};
_compute: function () {
var self = this;
self.invalidated = false;
Deps.Computation.prototype._compute = function () {
var self = this;
self.invalidated = false;
var previous = Deps.currentComputation;
setCurrentComputation(self);
var previousInCompute = inCompute;
inCompute = true;
try {
callWithNoYieldsAllowed(self._func, self);
} finally {
setCurrentComputation(previous);
inCompute = false;
}
},
var previous = Deps.currentComputation;
setCurrentComputation(self);
var previousInCompute = inCompute;
inCompute = true;
try {
withNoYieldsAllowed(self._func).call(self._context, self);
} finally {
setCurrentComputation(previous);
inCompute = false;
}
};
_recompute: function () {
var self = this;
Deps.Computation.prototype._recompute = function () {
var self = this;
self._recomputing = true;
try {
while (self.invalidated && ! self.stopped) {
try {
self._compute();
} catch (e) {
_throwOrLog("recompute", e);
}
// If _compute() invalidated us, we run again immediately.
// A computation that invalidates itself indefinitely is an
// infinite loop, of course.
//
// We could put an iteration counter here and catch run-away
// loops.
self._recomputing = true;
try {
while (self.invalidated && ! self.stopped) {
try {
self._compute();
} catch (e) {
_throwOrLog("recompute", e);
}
} finally {
self._recomputing = false;
// If _compute() invalidated us, we run again immediately.
// A computation that invalidates itself indefinitely is an
// infinite loop, of course.
//
// We could put an iteration counter here and catch run-away
// loops.
}
} finally {
self._recomputing = false;
}
});
};

@@ -237,155 +230,160 @@ //

_assign(Deps.Dependency.prototype, {
// http://docs.meteor.com/#dependency_depend
//
// Adds `computation` to this set if it is not already
// present. Returns true if `computation` is a new member of the set.
// If no argument, defaults to currentComputation, or does nothing
// if there is no currentComputation.
depend: function (computation) {
if (! computation) {
if (! Deps.active)
return false;
// http://docs.meteor.com/#dependency_depend
//
// Adds `computation` to this set if it is not already
// present. Returns true if `computation` is a new member of the set.
// If no argument, defaults to currentComputation, or does nothing
// if there is no currentComputation.
Deps.Dependency.prototype.depend = function (computation) {
if (! computation) {
if (! Deps.active)
return false;
computation = Deps.currentComputation;
}
var self = this;
var id = computation._id;
if (! (id in self._dependentsById)) {
self._dependentsById[id] = computation;
computation.onInvalidate(function () {
delete self._dependentsById[id];
});
return true;
}
return false;
},
computation = Deps.currentComputation;
}
var self = this;
var id = computation._id;
if (! (id in self._dependentsById)) {
self._dependentsById[id] = computation;
computation.onInvalidate(function () {
delete self._dependentsById[id];
});
return true;
}
return false;
};
// http://docs.meteor.com/#dependency_changed
changed: function () {
var self = this;
for (var id in self._dependentsById)
self._dependentsById[id].invalidate();
},
// http://docs.meteor.com/#dependency_changed
Deps.Dependency.prototype.changed = function () {
var self = this;
for (var id in self._dependentsById)
self._dependentsById[id].invalidate();
};
// http://docs.meteor.com/#dependency_hasdependents
hasDependents: function () {
var self = this;
for(var id in self._dependentsById)
return true;
return false;
}
});
// http://docs.meteor.com/#dependency_hasdependents
Deps.Dependency.prototype.hasDependents = function () {
var self = this;
for(var id in self._dependentsById)
return true;
return false;
};
_assign(Deps, {
// http://docs.meteor.com/#deps_flush
flush: function (_opts) {
// XXX What part of the comment below is still true? (We no longer
// have Spark)
//
// Nested flush could plausibly happen if, say, a flush causes
// DOM mutation, which causes a "blur" event, which runs an
// app event handler that calls Deps.flush. At the moment
// Spark blocks event handlers during DOM mutation anyway,
// because the LiveRange tree isn't valid. And we don't have
// any useful notion of a nested flush.
//
// https://app.asana.com/0/159908330244/385138233856
if (inFlush)
throw new Error("Can't call Deps.flush while flushing");
// http://docs.meteor.com/#deps_flush
Deps.flush = function (_opts) {
// XXX What part of the comment below is still true? (We no longer
// have Spark)
//
// Nested flush could plausibly happen if, say, a flush causes
// DOM mutation, which causes a "blur" event, which runs an
// app event handler that calls Deps.flush. At the moment
// Spark blocks event handlers during DOM mutation anyway,
// because the LiveRange tree isn't valid. And we don't have
// any useful notion of a nested flush.
//
// https://app.asana.com/0/159908330244/385138233856
if (inFlush)
throw new Error("Can't call Deps.flush while flushing");
if (inCompute)
throw new Error("Can't flush inside Deps.autorun");
if (inCompute)
throw new Error("Can't flush inside Deps.autorun");
inFlush = true;
willFlush = true;
throwFirstError = !! (_opts && _opts._throwFirstError);
inFlush = true;
willFlush = true;
throwFirstError = !! (_opts && _opts._throwFirstError);
var finishedTry = false;
try {
while (pendingComputations.length ||
afterFlushCallbacks.length) {
var finishedTry = false;
try {
while (pendingComputations.length ||
afterFlushCallbacks.length) {
// recompute all pending computations
while (pendingComputations.length) {
var comp = pendingComputations.shift();
comp._recompute();
}
// recompute all pending computations
while (pendingComputations.length) {
var comp = pendingComputations.shift();
comp._recompute();
}
if (afterFlushCallbacks.length) {
// call one afterFlush callback, which may
// invalidate more computations
var func = afterFlushCallbacks.shift();
try {
func();
} catch (e) {
_throwOrLog("afterFlush function", e);
}
if (afterFlushCallbacks.length) {
// call one afterFlush callback, which may
// invalidate more computations
var func = afterFlushCallbacks.shift();
try {
func.call(func._context);
} catch (e) {
_throwOrLog("afterFlush function", e);
}
}
finishedTry = true;
} finally {
if (! finishedTry) {
// we're erroring
inFlush = false; // needed before calling `Deps.flush()` again
Deps.flush({_throwFirstError: false}); // finish flushing
}
willFlush = false;
inFlush = false;
}
},
finishedTry = true;
} finally {
if (! finishedTry) {
// we're erroring
inFlush = false; // needed before calling `Deps.flush()` again
Deps.flush({_throwFirstError: false}); // finish flushing
}
willFlush = false;
inFlush = false;
}
};
// http://docs.meteor.com/#deps_autorun
//
// Run f(). Record its dependencies. Rerun it whenever the
// dependencies change.
//
// Returns a new Computation, which is also passed to f.
//
// Links the computation to the current computation
// so that it is stopped if the current computation is invalidated.
autorun: function (f) {
if (typeof f !== 'function')
throw new Error('Deps.autorun requires a function argument');
// http://docs.meteor.com/#deps_autorun
//
// Run f(). Record its dependencies. Rerun it whenever the
// dependencies change.
//
// Returns a new Computation, which is also passed to f.
//
// Links the computation to the current computation
// so that it is stopped if the current computation is invalidated.
Deps.autorun = function (f, ctx) {
if (typeof f !== 'function')
throw new Error('Deps.autorun requires a function argument');
constructingComputation = true;
var c = new Deps.Computation(f, Deps.currentComputation);
constructingComputation = true;
var c = new Deps.Computation(f, Deps.currentComputation, ctx);
if (Deps.active)
Deps.onInvalidate(function () {
c.stop();
});
if (Deps.active)
Deps.onInvalidate(function () {
c.stop();
});
return c;
},
return c;
};
// http://docs.meteor.com/#deps_nonreactive
//
// Run `f` with no current computation, returning the return value
// of `f`. Used to turn off reactivity for the duration of `f`,
// so that reactive data sources accessed by `f` will not result in any
// computations being invalidated.
nonreactive: function (f) {
var previous = Deps.currentComputation;
setCurrentComputation(null);
try {
return f();
} finally {
setCurrentComputation(previous);
}
},
// http://docs.meteor.com/#deps_nonreactive
//
// Run `f` with no current computation, returning the return value
// of `f`. Used to turn off reactivity for the duration of `f`,
// so that reactive data sources accessed by `f` will not result in any
// computations being invalidated.
Deps.nonreactive = function (f, ctx) {
var previous = Deps.currentComputation;
setCurrentComputation(null);
try {
return f.call(ctx);
} finally {
setCurrentComputation(previous);
}
};
// http://docs.meteor.com/#deps_oninvalidate
onInvalidate: function (f) {
if (! Deps.active)
throw new Error("Deps.onInvalidate requires a currentComputation");
// similar to nonreactive but returns a function instead of
// exectuing fn immediately. really just some sugar
Deps.nonreactable = function (f, ctx) {
return function() {
return Deps.nonreactive(f, ctx || this);
}
}
Deps.currentComputation.onInvalidate(f);
},
// http://docs.meteor.com/#deps_oninvalidate
Deps.onInvalidate = function (f, ctx) {
if (! Deps.active)
throw new Error("Deps.onInvalidate requires a currentComputation");
// http://docs.meteor.com/#deps_afterflush
afterFlush: function (f) {
afterFlushCallbacks.push(f);
requireFlush();
}
});
Deps.currentComputation.onInvalidate(f, ctx);
};
// http://docs.meteor.com/#deps_afterflush
Deps.afterFlush = function (f, ctx) {
f._context = ctx;
afterFlushCallbacks.push(f);
requireFlush();
};

@@ -1,2 +0,2 @@

var _ = require("underscore");
var util = require("./util");

@@ -12,3 +12,3 @@ // Backbone.Events

// var object = {};
// _.extend(object, Backbone.Events);
// util.extend(object, Backbone.Events);
// object.on('expand', function(){ alert('expanded'); });

@@ -34,8 +34,8 @@ // object.trigger('expand');

var self = this;
var once = _.once(function() {
self.off(name, once);
var fn = once(function() {
self.off(name, fn);
callback.apply(this, arguments);
});
once._callback = callback;
return this.on(name, once, context);
fn._callback = callback;
return this.on(name, fn, context);
},

@@ -54,3 +54,3 @@

}
names = name ? [name] : _.keys(this._events);
names = name ? [name] : Object.keys(this._events);
for (i = 0, l = names.length; i < l; i++) {

@@ -102,3 +102,3 @@ name = names[i];

obj.off(name, callback, this);
if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
if (remove || isEmpty(obj._events)) delete this._listeningTo[id];
}

@@ -158,6 +158,6 @@ return this;

// listening to.
_.each(listenMethods, function(implementation, method) {
util.each(listenMethods, function(implementation, method) {
Events[method] = function(obj, name, callback) {
var listeningTo = this._listeningTo || (this._listeningTo = {});
var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
var id = obj._listenId || (obj._listenId = util.uniqueId('l'));
listeningTo[id] = obj;

@@ -172,2 +172,20 @@ if (!callback && typeof name === 'object') callback = this;

Events.bind = Events.on;
Events.unbind = Events.off;
Events.unbind = Events.off;
function isEmpty(obj) {
if (obj == null) return true;
if (Array.isArray(obj) || typeof obj === "string") return obj.length === 0;
for (var key in obj) if (util.has(obj, key)) return false;
return true;
}
function once(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
}
}

@@ -1,17 +0,78 @@

var _ = require("underscore");
var toArray =
exports.toArray = function(obj) {
return Array.prototype.slice.call(obj, 0);
}
// tests value as pojo (plain old javascript object)
var isPlainObject =
exports.isPlainObject = function(obj) {
return obj != null && obj.__proto__ === Object.prototype;
var has =
exports.has = function(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
// tests obj as a subclass of parent
// here, a class is technically a subclass of itself
exports.isSubClass = function(parent, obj) {
return obj === parent || (obj != null && obj.prototype instanceof parent);
var extend =
exports.extend = function(obj) {
toArray(arguments).slice(1).forEach(function(mixin) {
if (!mixin) return;
for (var key in mixin) {
obj[key] = mixin[key];
}
});
return obj;
}
var each =
exports.each = function(obj, iterator, context) {
if (obj == null) return obj;
if (obj.forEach === Array.prototype.forEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
iterator.call(context, obj[i], i, obj);
}
} else {
var keys = Object.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
iterator.call(context, obj[keys[i]], keys[i], obj);
}
}
return obj;
}
var flatten =
exports.flatten = function(input, output) {
if (output == null) output = [];
each(input, function(value) {
if (Array.isArray(value)) flatten(value, output);
else output.push(value);
});
return output;
}
exports.pick = function(obj) {
return flatten(toArray(arguments).slice(1))
.reduce(function(nobj, key) {
nobj[key] = obj[key];
return nobj;
}, {});
}
var isObject =
exports.isObject = function(obj) {
return obj === Object(obj);
}
exports.uniqueId = (function() {
var id = 0;
return function(prefix) {
return (prefix || "") + (++id);
}
})();
// the subclassing function found in Backbone
var subclass =
exports.subclass = function(protoProps, staticProps) {

@@ -24,3 +85,3 @@ var parent = this;

// by us to simply call the parent's constructor.
if (protoProps && _.has(protoProps, 'constructor')) {
if (protoProps && has(protoProps, 'constructor')) {
child = protoProps.constructor;

@@ -32,3 +93,3 @@ } else {

// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
extend(child, parent, staticProps);

@@ -43,3 +104,3 @@ // Set the prototype chain to inherit from `parent`, without calling

// if supplied.
if (protoProps) _.extend(child.prototype, protoProps);
if (protoProps) extend(child.prototype, protoProps);

@@ -53,356 +114,87 @@ // Set a convenience property in case the parent's prototype is needed

// cleans an array of path parts
var sanitizePathParts =
exports.sanitizePathParts = function(parts) {
return parts.filter(function(a) {
return a != null && a !== "";
}).map(function(a) {
var s = a.toString();
if (s[0] === ".") s = s.substr(1);
if (s.substr(-1) === ".") s = s.substr(0, s.length - 1);
return s;
});
exports.isNodeAtDOMPosition = function(node, parent, before) {
return node.parentNode === parent && node.nextSibling === before;
}
// splits a path by period
var splitPath =
exports.splitPath = function(path) {
var parts = _.isArray(path) ? path : _.isString(path) ? path.split(".") : [ path ];
return sanitizePathParts(parts);
}
var matchesSelector = Element.prototype.matches ||
Element.prototype.webkitMatchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector;
// parses a string path as a dynamic path
var parsePath =
exports.parsePath = function(path) {
return splitPath(path).map(function(part) {
if (part.indexOf("*") > -1 && part !== "**") {
return new RegExp("^" + part.split("*").join("([^\\.]*)") + "$");
}
return part;
});
exports.matchesSelector = function(elem, selector) {
return matchesSelector.call(elem, selector)
}
// concats path parts together into a string
var joinPathParts =
exports.joinPathParts = function() {
return sanitizePathParts(_.flatten(_.toArray(arguments))).join(".");
}
var Deps = require("./deps");
// deeply looks for a value at path in obj
var get =
exports.get = function(obj, parts, getter) {
parts = splitPath(parts);
var defineReactiveProperty =
exports.defineReactiveProperty = function(obj, prop, value, coerce) {
if (!isObject(obj)) throw new Error("Expecting object to define the reactive property on.");
if (typeof prop !== "string") throw new Error("Expecting string for property name.");
// custom getter
if (!_.isFunction(getter)) {
getter = function(obj, path) { return obj[path]; }
if (typeof value === "function" && coerce == null) {
coerce = value;
value = void 0;
}
while (parts.length) {
if (obj == null) return;
obj = getter(obj, parts.shift());
}
if (typeof coerce !== "function") coerce = function(v) { return v; };
return obj;
}
// reduces paths so they are unique and short
var findShallowestUniquePaths =
exports.findShallowestUniquePaths = function(paths) {
return paths.reduce(function(m, keys) {
// first check if a shorter or equal path exists
if (m.some(function(k) {
return arrayStartsWith(keys, k);
})) return m;
// next check for any longer paths that need to be removed
m.slice(0).forEach(function(k, index) {
if (arrayStartsWith(k, keys)) m.splice(index, 1);
// runs the coercion function non-reactively to prevent infinite loops
function process(v) {
return Deps.nonreactive(function() {
return coerce.call(obj, v, prop, obj);
});
// and lastly add the path to output
m.push(keys);
return m;
}, []);
}
// determines if the values of array match the start of another array
// can be read as: does [a1] start with [a2]
var arrayStartsWith =
exports.arrayStartsWith = function(a1, a2) {
var max = a2.length;
return max <= a1.length && _.isEqual(a2, a1.slice(0, max));
}
// finds all changed, matching subpaths
var findAllChanges =
exports.findAllChanges = function(chg, parts, onPath, ctx) {
var parts, paths, base, getter,
args = _.toArray(arguments).slice(2);
// clone parts so we don't affect the original
parts = parts.slice(0);
// match the beginning of parts
if (!matchPathStart(chg.keypath, parts)) return;
paths = [];
base = joinPathParts(chg.keypath);
getter = function(obj, path) {
return chg.model.createHandle(obj)("get", path);
}
// generate a list of effected paths
findAllMatchingPaths(chg.model, chg.value, parts, paths);
findAllMatchingPaths(chg.model, chg.oldValue, parts, paths);
paths = findShallowestUniquePaths(paths);
var dep = new Deps.Dependency;
value = process(value);
// fire the callback on each path that changed
paths.forEach(function(keys, index, list) {
var nval, oval;
nval = get(chg.value, keys, getter);
oval = get(chg.oldValue, keys, getter);
if (nval === oval) return;
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: true,
set: function(val) {
val = process(val);
onPath.call(ctx, {
model: chg.model.getModel(keys),
keypath: chg.keypath.concat(keys),
type: changeType(nval, oval),
value: nval,
oldValue: oval
});
});
}
if (val !== value) {
value = val;
dep.changed();
}
// matchs the start of a keypath to a list of match parts
// parts is modified to the remaining segments that were not matched
var matchPathStart =
exports.matchPathStart = function(keys, parts) {
var i, part;
for (i = 0; i < keys.length; i++) {
part = parts.shift();
if (_.isRegExp(part) && part.test(keys[i])) continue;
if (part === "**") {
// look ahead
if (parts[0] == null || parts[0] !== keys[i + 1]) {
parts.unshift(part);
}
continue;
return value;
},
get: function() {
dep.depend();
return value;
}
if (part !== keys[i]) return false;
}
});
return true;
return obj;
}
// deeply traverses a value in search of all paths that match parts
var findAllMatchingPaths =
exports.findAllMatchingPaths = function(model, value, parts, paths, base) {
if (paths == null) paths = [];
if (base == null) base = [];
if (!parts.length) {
paths.push(base);
return paths;
exports.defineReactiveProperties = function(obj, props, coerce) {
for (var prop in props) {
defineReactiveProperty(obj, prop, props[prop], coerce || false);
}
var handle = model.createHandle(value),
part = parts[0],
rest = parts.slice(1);
if (_.isRegExp(part)) {
handle("keys").forEach(function(k) {
findAllMatchingPaths(model.getModel(k), handle("get", k), rest, paths, base.concat(k));
});
} else if (part === "**") {
if (handle("isLeaf")) {
if (!rest.length) paths.push(base);
return paths;
}
handle("keys").forEach(function(k) {
var _rest = rest,
_base = base;
// look ahead
if (rest[0] == null || rest[0] !== k) {
_rest = [part].concat(rest);
_base = base.concat(k);
}
findAllMatchingPaths(model.getModel(k), handle("get", k), _rest, paths, _base);
});
} else {
findAllMatchingPaths(model.getModel(part), handle("get", part), rest, paths, base.concat(part));
}
return paths;
return obj;
}
// array write operations
var mutatorMethods = [ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift' ];
var defineComputedProperty =
exports.defineComputedProperty = function(obj, prop, value) {
if (typeof value !== "function")
throw new Error("Expecting function for computed property value.");
// patches an array so we can listen to write operations
var patchArray =
exports.patchArray = function(arr) {
if (arr._patched) return arr;
var patchedArrayProto = [],
observers = [];
Object.defineProperty(patchedArrayProto, "_patched", { value: true });
Object.defineProperty(patchedArrayProto, "_observers", { value: [] });
Object.defineProperty(patchedArrayProto, "observe", {
value: function(fn) {
if (typeof fn !== "function") throw new Error("Expecting function to observe with.");
this._observers.push(fn);
return this;
Object.defineProperty(obj, prop, {
configurable: true,
enumerable: true,
get: function() {
return value.call(obj);
}
});
}
Object.defineProperty(patchedArrayProto, "stopObserving", {
value: function(fn) {
var index = this._observers.indexOf(fn);
if (index > -1) this._observers.splice(index, 1);
return this;
}
exports.defineComputedProperties = function(obj, props) {
Object.keys(props).forEach(function(key) {
defineComputedProperty(obj, key, props[key]);
});
mutatorMethods.forEach(function(methodName) {
Object.defineProperty(patchedArrayProto, methodName, {
value: method
});
function method() {
var spliceEquivalent, summary, start,
original, size, i, index, result;
// push, pop, shift and unshift can all be represented as a splice operation.
// this makes life easier later
spliceEquivalent = getSpliceEquivalent(this, methodName, _.toArray(arguments));
summary = summariseSpliceOperation(this, spliceEquivalent);
// make a copy of the original values
if (summary != null) {
start = summary.start;
original = Array.prototype.slice.call(this, start, !summary.balance ? start + summary.added : void 0);
size = (summary.balance > 0 ? summary.added : 0) + original.length;
} else {
start = 0;
original = Array.prototype.slice.call(this, 0);
size = original.length;
}
// apply the underlying method
result = Array.prototype[methodName].apply(this, arguments);
// trigger changes
for (i = 0; i < size; i++) {
index = i + start;
this._observers.forEach(function(fn) {
fn.call(this, index, this[index], original[i]);
}, this);
}
return result;
};
});
if (({}).__proto__) arr.__proto__ = patchedArrayProto;
else {
mutatorMethods.forEach(function(methodName) {
Object.defineProperty(arr, methodName, {
value: patchedArrayProto[methodName],
configurable: true
});
});
}
return arr;
}
// converts array write operations into splice equivalent arguments
var getSpliceEquivalent =
exports.getSpliceEquivalent = function ( array, methodName, args ) {
switch ( methodName ) {
case 'splice':
return args;
case 'sort':
case 'reverse':
return null;
case 'pop':
if ( array.length ) {
return [ -1 ];
}
return null;
case 'push':
return [ array.length, 0 ].concat( args );
case 'shift':
return [ 0, 1 ];
case 'unshift':
return [ 0, 0 ].concat( args );
}
}
// returns a summary pf how an array will be changed after the splice operation
var summariseSpliceOperation =
exports.summariseSpliceOperation = function ( array, args ) {
var start, addedItems, removedItems, balance;
if ( !args ) {
return null;
}
// figure out where the changes started...
start = +( args[0] < 0 ? array.length + args[0] : args[0] );
// ...and how many items were added to or removed from the array
addedItems = Math.max( 0, args.length - 2 );
removedItems = ( args[1] !== undefined ? args[1] : array.length - start );
// It's possible to do e.g. [ 1, 2, 3 ].splice( 2, 2 ) - i.e. the second argument
// means removing more items from the end of the array than there are. In these
// cases we need to curb JavaScript's enthusiasm or we'll get out of sync
removedItems = Math.min( removedItems, array.length - start );
balance = addedItems - removedItems;
return {
start: start,
balance: balance,
added: addedItems,
removed: removedItems
};
}
// tests a node against a selector
exports.matchSelector = function(node, selector) {
var nodes, i;
nodes = ( node.parentNode || node.ownerDocument ).querySelectorAll( selector );
i = nodes.length;
while ( i-- ) {
if ( nodes[i] === node ) {
return true;
}
}
return false;
}
// returns the type of changes based on old and new values
// expects oval !== nval
var changeType =
exports.changeType = function(nval, oval) {
return _.isUndefined(oval) ? "add" : _.isUndefined(nval) ? "delete" : "update";
}
{
"name": "templejs",
"version": "0.2.12",
"version": "0.3.1",
"description": "A modern JavaScript view framework.",

@@ -17,16 +17,11 @@ "author": "Beneath the Ink <info@beneaththeink.com>",

},
"main": "./lib/temple.js",
"dependencies": {
"debug": "1.0.2",
"hogan.js": "3.0.2",
"underscore": "1.6.0"
},
"main": "./lib/index.js",
"dependencies": {},
"devDependencies": {
"grunt": "0.4.5",
"grunt-browserify": "2.1.0",
"grunt-browserify": "2.1.3",
"grunt-contrib-clean": "0.5.0",
"grunt-contrib-copy": "0.5.0",
"grunt-contrib-uglify": "0.5.0",
"grunt-contrib-watch": "0.6.1",
"grunt-peg": "1.4.0",
"grunt-wait": "0.1.0",
"grunt-wrap2000": "0.1.0"

@@ -36,14 +31,10 @@ },

"keywords": [
"mustache",
"view",
"framework",
"DOM",
"html",
"template",
"templating",
"data binding",
"binding",
"declarative",
"view model",
"reactive"
"reactive",
"dependency"
]
}

@@ -5,5 +5,6 @@ # Temple

* __Reactive__ - Powered by a ViewModel that automatically updates the DOM as the data changes.
* __Modular & Extensible__ - Views are encapsulated, reusable components, making testing and separation of concerns easy.
* __Mustache__ - Includes an *optional* [Mustache](http://mustache.github.io/) + XML language parser and renderer.
* __Data Neutral__ - Temple is focused purely on the View aspect of web applications and can be easily integrated with existing frameworks and platforms.
* __Tiny__ - Temple has no external dependencies and weighs in at just under 19KB minified.
* __Reactive__ - Keep the interface up-to-date flexibly with auto-running computations powered by [Meteor](http://meteor.com)'s [dependency package](https://github.com/meteor/meteor/blob/e78861b7d0dbb60e5e2bf59bab2cb06ce6596c04/packages/deps/deps.js).

@@ -29,28 +30,41 @@ __Note: This library is under active development. Use at your own risk!__

```javascript
// create a template
new Temple.Mustache("<span style='color: {{ color }};'>{{ message }}</span>")
// A simple clock component
var Clock = Temple.extend({
// on init, append a new text binding to hold the time value
initialize: function() {
this.time = this.appendChild(Clock.getTime());
},
// add data
.set({
colors: [ "red", "blue", "green" ],
colorIndex: 0,
message: "Hello World",
color: function() {
return this.get("colors." + this.get("colorIndex"));
// start an interval on mount that will continiously update the time
beforeMount: function(comp) {
this.interval = setInterval(this.invalidate.bind(this), 500);
},
// when the view is unmounted, clear the interval
onStop: function() {
clearInterval(this.interval);
delete this.interval;
},
// updates the value of the text binding to the current time
render: function() {
this.time.setValue(Clock.getTime());
}
})
}, {
// a static method that returns the current time as a string
getTime: function() {
var date = new Date;
// mix in some reactive changes
.use(function() {
this.toggleColor = function() {
var newIndex = (this.get("colorIndex") + 1) % this.get("colors.length");
this.set("colorIndex", newIndex);
return newIndex;
return [
date.getHours(),
date.getMinutes(),
date.getSeconds()
].map(function(digit) {
return (digit < 10 ? "0" : "") + digit;
}).join(":");
}
});
setInterval(this.toggleColor.bind(this), 500);
})
// apply to DOM
.paint(document.body);
```
// render a new instance of clock in the body element
new Clock().mount().paint("body");
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc