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

saddle

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

saddle - npm Package Compare versions

Comparing version 0.0.2 to 0.2.0

test/serialize.mocha.js

50

example/expressions.js

@@ -1,7 +0,1 @@

module.exports = {
Expression: Expression
, ElseExpression: ElseExpression
, ContextMeta: ContextMeta
, Context: Context
};

@@ -22,2 +16,13 @@ //// Example framework-specific classes ////

// Expression::truthy(context)
if (typeof require === 'function') {
var serializeObject = require('serialize-object');
}
module.exports = {
Expression: Expression,
ElseExpression: ElseExpression,
Context: Context
};
function Expression(source) {

@@ -30,3 +35,6 @@ this.source = source;

Expression.prototype.get = function(context) {
return (this.source == null) ? context.data : context._get(this.source);
return ((this.source == null)
? context.data
: context._get(this.source)
);
};

@@ -36,2 +44,7 @@ Expression.prototype.truthy = function(context) {

};
Expression.prototype.module = 'expressions';
Expression.prototype.type = 'Expression';
Expression.prototype.serialize = function() {
return serializeObject.instance(this, this.source);
};

@@ -43,8 +56,6 @@ function ElseExpression() {}

};
ElseExpression.prototype.type = 'ElseExpression';
function templateTruthy(value) {
if (Array.isArray(value)) {
return value.length > 0;
}
return value != null && value !== false && value !== '';
return (Array.isArray(value)) ? value.length > 0 : !!value;
}

@@ -59,4 +70,4 @@

// The required interface methods are:
// Context::onAdd(binding)
// Context::onRemove(binding)
// Context::addBinding(binding)
// Context::removeBinding(binding)
// Context::child(expression)

@@ -69,7 +80,8 @@ // Context::eachChild(index)

}
Context.prototype.onAdd = function(binding) {
this.meta.onAdd(binding);
Context.prototype = new Expression();
Context.prototype.addBinding = function(binding) {
this.meta.addBinding(binding);
};
Context.prototype.onRemove = function(binding) {
this.meta.onRemove(binding);
Context.prototype.removeBinding = function(binding) {
this.meta.removeBinding(binding);
};

@@ -89,5 +101,1 @@ Context.prototype.child = function(expression) {

};
function ContextMeta(options) {
this.onAdd = options.onAdd || noop;
this.onRemove = options.onRemove || noop;
}

@@ -0,3 +1,7 @@

if (typeof require === 'function') {
var serializeObject = require('serialize-object');
}
// UPDATE_PROPERTIES map HTML attribute names to an Element DOM property that
// should be used for setting on bindings updates instead of setAttribute.
// should be used for setting on bindings updates instead of s'test'Attribute.
//

@@ -66,2 +70,3 @@ // https://github.com/jquery/jquery/blob/1.x-master/src/attributes/prop.js

, Template: Template
, Doctype: Doctype
, Text: Text

@@ -78,3 +83,2 @@ , DynamicText: DynamicText

, DynamicAttribute: DynamicAttribute
, AttributesMap: AttributesMap

@@ -86,4 +90,2 @@ // Binding Classes

, RangeBinding: RangeBinding
, replaceBindings: replaceBindings
};

@@ -105,6 +107,49 @@

};
Template.prototype.attachTo = function(parent, node, context) {
return attachContent(parent, node, this.content, context);
};
Template.prototype.stringify = function(value) {
return (value == null) ? '' : value + '';
};
Template.prototype.module = 'templates';
Template.prototype.type = 'Template';
Template.prototype.serialize = function() {
return serializeObject.instance(this, this.content);
};
function Doctype(name, publicId, systemId) {
this.name = name;
this.publicId = publicId;
this.systemId = systemId;
}
Doctype.prototype = new Template();
Doctype.prototype.get = function() {
var publicText = (this.publicId) ?
' PUBLIC "' + this.publicId + '"' :
'';
var systemText = (this.systemId) ?
(this.publicId) ?
' "' + this.systemId + '"' :
' SYSTEM "' + this.systemId + '"' :
'';
return '<!DOCTYPE ' + this.name + publicText + systemText + '>';
};
Doctype.prototype.appendTo = function() {
// Doctype could be created via:
// document.implementation.createDocumentType(this.name, this.publicId, this.systemId)
// However, it does not appear possible or useful to append it to the
// document fragment. Therefore, just don't render it in the browser
};
Doctype.prototype.attachTo = function(parent, node) {
if (!node || node.nodeType !== 10) {
throw attachError(parent, node);
}
return node.nextSibling;
};
Doctype.prototype.type = 'Doctype';
Doctype.prototype.serialize = function() {
return serializeObject.instance(this, this.name, this.publicId, this.systemId);
};
function Text(data) {

@@ -122,2 +167,9 @@ this.data = data;

};
Text.prototype.attachTo = function(parent, node) {
return attachText(parent, node, this.data, this);
};
Text.prototype.type = 'Text';
Text.prototype.serialize = function() {
return serializeObject.instance(this, this.data);
};

@@ -148,8 +200,51 @@ function DynamicText(expression) {

parent.appendChild(node);
context.onAdd(new NodeBinding(this, context, node));
addNodeBinding(this, context, node);
};
DynamicText.prototype.attachTo = function(parent, node, context) {
var value = this.expression.get(context);
if (value instanceof Template) {
return value.attachTo(parent, node, context);
}
var data = this.stringify(value);
return attachText(parent, node, data, this, context);
};
DynamicText.prototype.update = function(context, binding) {
binding.node.data = this.stringify(this.expression.get(context));
};
DynamicText.prototype.type = 'DynamicText';
DynamicText.prototype.serialize = function() {
return serializeObject.instance(this, this.expression);
};
function attachText(parent, node, data, template, context) {
if (!node) {
var newNode = document.createTextNode(data);
parent.appendChild(newNode);
addNodeBinding(template, context, newNode);
return;
}
if (node.nodeType === 3) {
// Proceed if nodes already match
if (node.data === data) {
addNodeBinding(template, context, node);
return node.nextSibling;
}
// Split adjacent text nodes that would have been merged together in HTML
var nextNode = splitData(node, data.length);
if (node.data !== data) {
throw attachError(parent, node);
}
addNodeBinding(template, context, node);
return nextNode;
}
// An empty text node might not be created at the end of some text
if (data === '') {
var newNode = document.createTextNode('');
parent.insertBefore(newNode, node || null);
addNodeBinding(template, context, newNode);
return node;
}
throw attachError(parent, node);
}
function Comment(data) {

@@ -166,2 +261,9 @@ this.data = data;

};
Comment.prototype.attachTo = function(parent, node) {
return attachComment(parent, node, this.data);
};
Comment.prototype.type = 'Comment';
Comment.prototype.serialize = function() {
return serializeObject.instance(this, this.data);
}

@@ -174,10 +276,17 @@ function DynamicComment(expression) {

var value = getUnescapedValue(this.expression, context);
return '<!--' + this.stringify(value) + '-->';
var data = this.stringify(value);
return '<!--' + data + '-->';
};
DynamicComment.prototype.appendTo = function(parent, context) {
var value = getUnescapedValue(this.expression, context);
var node = document.createComment(this.stringify(value));
var data = this.stringify(value);
var node = document.createComment(data);
parent.appendChild(node);
context.onAdd(new NodeBinding(this, context, node));
addNodeBinding(this, context, node);
};
DynamicComment.prototype.attachTo = function(parent, node, context) {
var value = getUnescapedValue(this.expression, context);
var data = this.stringify(value);
return attachComment(parent, node, data, this, context);
};
DynamicComment.prototype.update = function(context, binding) {

@@ -187,3 +296,29 @@ var value = getUnescapedValue(this.expression, context);

};
DynamicComment.prototype.type = 'DynamicComment';
DynamicComment.prototype.serialize = function() {
return serializeObject.instance(this, this.expression);
}
function attachComment(parent, node, data, template, context) {
// Sometimes IE fails to create Comment nodes from HTML or innerHTML.
// This is an issue inside of <select> elements, for example.
if (!node || node.nodeType !== 8) {
var newNode = document.createComment(data);
parent.insertBefore(newNode, node || null);
addNodeBinding(template, context, newNode);
return node;
}
// Proceed if nodes already match
if (node.data === data) {
addNodeBinding(template, context, node);
return node.nextSibling;
}
throw attachError(parent, node);
}
function addNodeBinding(template, context, node) {
if (!context) return;
context.addBinding(new NodeBinding(template, context, node));
}
function Attribute(data) {

@@ -195,18 +330,25 @@ this.data = data;

};
Attribute.prototype.module = Template.prototype.module;
Attribute.prototype.type = 'Attribute';
Attribute.prototype.serialize = function() {
return serializeObject.instance(this, this.data);
};
function DynamicAttribute(template) {
// In attributes, template may be an instance of Template or Expression
this.template = template;
function DynamicAttribute(expression) {
// In attributes, expression may be an instance of Template or Expression
this.expression = expression;
}
DynamicAttribute.prototype = new Attribute();
DynamicAttribute.prototype.get = function(context) {
return getUnescapedValue(this.template, context);
return getUnescapedValue(this.expression, context);
};
DynamicAttribute.prototype.getBound = function(context, element, name) {
context.onAdd(new AttributeBinding(this, context, element, name));
return getUnescapedValue(this.template, context);
context.addBinding(new AttributeBinding(this, context, element, name));
return getUnescapedValue(this.expression, context);
};
DynamicAttribute.prototype.update = function(context, binding) {
var value = getUnescapedValue(this.template, context);
var value = getUnescapedValue(this.expression, context);
var propertyName = UPDATE_PROPERTIES[binding.name];
if (propertyName) {
if (value === void 0) value = null;
binding.element[propertyName] = value;

@@ -221,2 +363,6 @@ } else if (value === false || value == null) {

};
DynamicAttribute.prototype.type = 'DynamicAttribute';
DynamicAttribute.prototype.serialize = function() {
return serializeObject.instance(this, this.expression);
};

@@ -232,15 +378,19 @@ function getUnescapedValue(expression, context) {

function AttributesMap(object) {
if (object) mergeInto(object, this);
}
function Element(tag, attributes, content) {
this.tag = tag;
function Element(tagName, attributes, content, hooks, selfClosing, notClosed) {
this.tagName = tagName;
this.attributes = attributes;
this.content = content;
this.isVoid = VOID_ELEMENTS[tag.toLowerCase()];
this.hooks = hooks;
this.selfClosing = selfClosing;
this.notClosed = notClosed;
var lowerTagName = tagName.toLowerCase();
var isVoid = VOID_ELEMENTS[lowerTagName];
this.startClose = (selfClosing) ? ' />' : '>';
this.endTag = (notClosed || isVoid) ? '' : '</' + tagName + '>';
this.unescapedContent = (lowerTagName === 'script' || lowerTagName === 'style');
}
Element.prototype = new Template();
Element.prototype.get = function(context) {
var tagItems = [this.tag];
var tagItems = [this.tagName];
for (var key in this.attributes) {

@@ -254,12 +404,12 @@ var value = this.attributes[key].get(context);

}
var startTag = '<' + tagItems.join(' ') + '>';
var endTag = '</' + this.tag + '>';
var startTag = '<' + tagItems.join(' ') + this.startClose;
if (this.content) {
var inner = contentHtml(this.content, context);
return startTag + inner + endTag;
var inner = contentHtml(this.content, context, this.unescapedContent);
return startTag + inner + this.endTag;
}
return (this.isVoid) ? startTag : startTag + endTag;
return startTag + this.endTag;
};
Element.prototype.appendTo = function(parent, context) {
var element = document.createElement(this.tag);
var element = document.createElement(this.tagName);
emitHooks(this.hooks, context, element);
for (var key in this.attributes) {

@@ -269,2 +419,3 @@ var value = this.attributes[key].getBound(context, element, key);

if (propertyName) {
if (value === void 0) value = null;
element[propertyName] = value;

@@ -280,3 +431,45 @@ } else if (value === true) {

};
Element.prototype.attachTo = function(parent, node, context) {
if (
!node ||
node.nodeType !== 1 ||
(node.tagName).toLowerCase() !== (this.tagName).toLowerCase()
) {
throw attachError(parent, node);
}
emitHooks(this.hooks, context, node);
for (var key in this.attributes) {
// Get each attribute to create bindings
this.attributes[key].getBound(context, node, key);
// TODO: Ideally, this would also check that the node's current attributes
// are equivalent, but there are some tricky edge cases
}
if (this.content) attachContent(node, node.firstChild, this.content, context);
return node.nextSibling;
};
Element.prototype.type = 'Element';
Element.prototype.serialize = function() {
return serializeObject.instance(
this
, this.tagName
, this.attributes
, this.content
, this.hooks
, this.selfClosing
, this.notClosed
);
};
function getAttributeValue(element, name) {
var propertyName = UPDATE_PROPERTIES[name];
return (propertyName) ? element[propertyName] : element.getAttribute(name);
}
function emitHooks(hooks, context, value) {
if (!hooks) return;
for (var i = 0, len = hooks.length; i < len; i++) {
hooks[i].emit(context, value);
}
}
function Block(expression, content) {

@@ -301,2 +494,12 @@ this.expression = expression;

};
Block.prototype.attachTo = function(parent, node, context) {
var blockContext = context.child(this.expression);
var start = document.createComment(this.expression);
var end = document.createComment(this.ending);
parent.insertBefore(start, node || null);
node = attachContent(parent, node, this.content, blockContext);
parent.insertBefore(end, node || null);
updateRange(context, null, this, start, end);
return node;
};
Block.prototype.update = function(context, binding) {

@@ -309,6 +512,10 @@ // Get start and end in advance, since binding is mutated in getFragment

};
Block.prototype.type = 'Block';
Block.prototype.serialize = function() {
return serializeObject.instance(this, this.expression, this.content);
};
function ConditionalBlock(expressions, contents) {
this.expressions = expressions;
this.beginning = expressions[0];
this.beginning = expressions.join('; ');
this.ending = '/' + this.beginning;

@@ -323,3 +530,4 @@ this.contents = contents;

if (expression.truthy(context)) {
html += contentHtml(this.contents[i], context.child(expression), unescaped);
var blockContext = context.child(expression);
html += contentHtml(this.contents[i], blockContext, unescaped);
break;

@@ -337,3 +545,4 @@ }

if (expression.truthy(context)) {
appendContent(parent, this.contents[i], context.child(expression));
var blockContext = context.child(expression);
appendContent(parent, this.contents[i], blockContext);
break;

@@ -345,2 +554,22 @@ }

};
ConditionalBlock.prototype.attachTo = function(parent, node, context) {
var start = document.createComment(this.beginning);
var end = document.createComment(this.ending);
parent.insertBefore(start, node || null);
for (var i = 0, len = this.expressions.length; i < len; i++) {
var expression = this.expressions[i];
if (expression.truthy(context)) {
var blockContext = context.child(expression);
node = attachContent(parent, node, this.contents[i], blockContext);
break;
}
}
parent.insertBefore(end, node || null);
updateRange(context, null, this, start, end);
return node;
};
ConditionalBlock.prototype.type = 'ConditionalBlock';
ConditionalBlock.prototype.serialize = function() {
return serializeObject.instance(this, this.expressions, this.contents);
};

@@ -399,2 +628,33 @@ function EachBlock(expression, content, elseContent) {

};
EachBlock.prototype.attachTo = function(parent, node, context) {
var items = this.expression.get(context);
var listContext = context.child(this.expression);
var start = document.createComment(this.expression);
var end = document.createComment(this.ending);
parent.insertBefore(start, node || null);
if (items && items.length) {
for (var i = 0, len = items.length; i < len; i++) {
var itemContext = listContext.eachChild(i);
node = this.attachItemTo(parent, node, itemContext);
}
} else if (this.elseContent) {
node = attachContent(parent, node, this.elseContent, listContext);
}
parent.insertBefore(end, node || null);
updateRange(context, null, this, start, end);
return node;
};
EachBlock.prototype.attachItemTo = function(parent, node, context) {
var start, end;
var nextNode = attachContent(parent, node, this.content, context);
if (nextNode === node) {
start = end = document.createComment('empty');
parent.insertBefore(start, node || null);
} else {
start = node;
end = (nextNode && nextNode.previousSibling) || parent.lastChild;
}
updateRange(context, null, this, start, end, true);
return nextNode;
};
EachBlock.prototype.update = function(context, binding) {

@@ -420,3 +680,3 @@ var start = binding.start;

}
binding.start.parentNode.insertBefore(fragment, node);
binding.start.parentNode.insertBefore(fragment, node || null);
};

@@ -450,4 +710,8 @@ EachBlock.prototype.remove = function(context, binding, index, howMany) {

node = indexStartNode(binding.start, to, binding.end);
binding.start.parentNode.insertBefore(fragment, node);
binding.start.parentNode.insertBefore(fragment, node || null);
};
EachBlock.prototype.type = 'EachBlock';
EachBlock.prototype.serialize = function() {
return serializeObject.instance(this, this.expression, this.content, this.elseContent);
};

@@ -472,3 +736,3 @@ function indexStartNode(node, index, endBound) {

} else {
context.onAdd(new RangeBinding(template, context, start, end, isItem));
context.addBinding(new RangeBinding(template, context, start, end, isItem));
}

@@ -482,2 +746,8 @@ }

}
function attachContent(parent, node, content, context) {
for (var i = 0, len = content.length; i < len; i++) {
node = content[i].attachTo(parent, node, context);
}
return node;
}
function contentHtml(content, context, unescaped) {

@@ -492,2 +762,5 @@ var html = '';

var parent = start.parentNode;
// This shouldn't happen if bindings are cleaned up properly, but check
// in case they aren't
if (!parent) return;
if (start === end) {

@@ -509,13 +782,13 @@ parent.replaceChild(fragment, start);

// This also works if nextNode is null, by doing an append
parent.insertBefore(fragment, nextNode);
parent.insertBefore(fragment, nextNode || null);
}
function emitRemoved(context, node, ignore) {
var binding = node.$bindNode;
if (binding && binding !== ignore) context.onRemove(binding);
if (binding && binding !== ignore) context.removeBinding(binding);
binding = node.$bindStart;
if (binding && binding !== ignore) context.onRemove(binding);
if (binding && binding !== ignore) context.removeBinding(binding);
var attributes = node.$bindAttributes;
if (attributes) {
for (var key in attributes) {
context.onRemove(attributes[key]);
context.removeBinding(attributes[key]);
}

@@ -528,3 +801,15 @@ }

function Binding() {}
function attachError(parent, node) {
if (typeof console !== 'undefined') {
console.error('Attach failed for', node, 'within', parent);
}
return new Error('Attaching bindings failed, because HTML structure ' +
'does not match client rendering.'
);
}
function Binding() {
this.meta = null;
}
Binding.prototype.type = 'Binding';
Binding.prototype.update = function() {

@@ -538,5 +823,7 @@ this.template.update(this.context, this);

this.node = node;
this.meta = null;
setNodeProperty(node, '$bindNode', this);
}
NodeBinding.prototype = new Binding();
NodeBinding.prototype.type = 'NodeBinding';

@@ -549,2 +836,3 @@ function AttributeBindingsMap() {}

this.name = name;
this.meta = null;
var map = element.$bindAttributes ||

@@ -555,2 +843,3 @@ (element.$bindAttributes = new AttributeBindingsMap());

AttributeBinding.prototype = new Binding();
AttributeBinding.prototype.type = 'AttributeBinding';

@@ -563,2 +852,3 @@ function RangeBinding(template, context, start, end, isItem) {

this.isItem = isItem;
this.meta = null;
setNodeProperty(start, '$bindStart', this);

@@ -568,2 +858,3 @@ setNodeProperty(end, '$bindEnd', this);

RangeBinding.prototype = new Binding();
RangeBinding.prototype.type = 'RangeBinding';
RangeBinding.prototype.insert = function(index, howMany) {

@@ -580,101 +871,2 @@ this.template.insert(this.context, this, index, howMany);

//// HTML page initialization ////
function replaceBindings(fragment, mirror) {
var node = fragment.firstChild;
var mirrorNode = mirror.firstChild;
var nextMirrorNode;
do {
nextMirrorNode = mirrorNode && mirrorNode.nextSibling;
// Split or create empty TextNodes as needed
if (node.nodeType === 3) {
if (mirrorNode && mirrorNode.nodeType === 3) {
if (node.data !== mirrorNode.data) {
nextMirrorNode = splitData(mirrorNode, node.data.length);
}
} else {
nextMirrorNode = mirrorNode;
mirrorNode = document.createTextNode('');
// Also works if nextMirrorNode is null
mirror.insertBefore(mirrorNode, nextMirrorNode);
}
// Create missing CommentNodes. Comments are used as DOM location markers
// when rendering bindings, but not when rendering HTML. In addition, old
// versions of IE fail to create some CommentNodes when parsing HTML
} else if (node.nodeType === 8) {
if (
!mirrorNode ||
(mirrorNode.nodeType !== 8) ||
(node.data !== mirrorNode.data)
) {
nextMirrorNode = mirrorNode;
mirrorNode = node.cloneNode(false);
mirror.insertBefore(mirrorNode, nextMirrorNode);
}
}
// Verify that the nodes are equivalent
if (mismatchedNodes(node, mirrorNode)) {
throw new Error('Attaching bindings failed, because HTML structure ' +
'does not match client rendering'
);
}
// Move bindings on the fragment to the corresponding node on the mirror
replaceNodeBindings(node, mirrorNode);
// Recursively traverse within Elements
if (node.nodeType === 1 && node.hasChildNodes()) {
replaceBindings(node, mirrorNode);
}
mirrorNode = nextMirrorNode;
node = node.nextSibling;
} while (node);
}
function mismatchedNodes(node, mirrorNode) {
// Check that nodes are of matching types
if (!node || !mirrorNode) return true;
var type = node.nodeType;
if (type !== mirrorNode.nodeType) return true;
// Check that elements are of the same element type
if (type === 1) {
if (node.tagName !== mirrorNode.tagName) return true;
// Check that TextNodes and CommentNodes have the same content
} else if (type === 3 || type === 8) {
if (node.data !== mirrorNode.data) return true;
}
}
function replaceNodeBindings(node, mirrorNode) {
var binding = node.$bindNode;
if (binding) {
binding.node = mirrorNode;
setNodeProperty(node, '$bindNode', binding);
}
binding = node.$bindStart;
if (binding) {
binding.start = mirrorNode;
setNodeProperty(mirrorNode, '$bindStart', binding);
}
binding = node.$bindEnd;
if (binding) {
binding.end = mirrorNode;
setNodeProperty(mirrorNode, '$bindEnd', binding);
}
var attributes = node.$bindAttributes;
if (attributes) {
for (var key in attributes) {
attributes[key].element = mirrorNode;
}
mirrorNode.$bindAttributes = attributes;
}
}
//// Utility functions ////

@@ -705,2 +897,8 @@

// General notes:
//
// In all cases, Node.insertBefore should have `|| null` after its second
// argument. IE works correctly when the argument is ommitted or equal
// to null, but it throws and error if it is equal to undefined.
if (!Array.isArray) {

@@ -717,3 +915,3 @@ Array.isArray = function(value) {

node.deleteData(index, node.length - index);
node.parentNode.insertBefore(newNode, node.nextSibling);
node.parentNode.insertBefore(newNode, node.nextSibling || null);
return newNode;

@@ -766,3 +964,3 @@ }

proxyNode.$bindProxy = node;
node.parentNode.insertBefore(proxyNode, node.nextSibling);
node.parentNode.insertBefore(proxyNode, node.nextSibling || null);
}

@@ -774,3 +972,3 @@ } else {

proxyNode.$bindProxy = node;
node.parentNode.insertBefore(proxyNode, node);
node.parentNode.insertBefore(proxyNode, node || null);
}

@@ -777,0 +975,0 @@ }

@@ -9,16 +9,15 @@ {

},
"version": "0.0.2",
"version": "0.2.0",
"main": "./lib/index.js",
"scripts": {
"test": "grunt test"
"test": "mocha --recursive test --bail --colors --reporter spec --debug"
},
"dependencies": {},
"dependencies": {
"serialize-object": "~0.0.2"
},
"devDependencies": {
"grunt": "~0.4.1",
"mocha": "~1.9.0",
"expect.js": "~0.2.0",
"grunt-simple-mocha": "~0.4.0",
"grunt-contrib-jshint": "~0.4.3"
"expect.js": "~0.2.0"
},
"optionalDependencies": {}
}

@@ -66,7 +66,7 @@ describe('Static rendering', function() {

test({
template: new saddle.Element('div', new saddle.AttributesMap({
template: new saddle.Element('div', {
id: new saddle.Attribute('page')
, 'data-x': new saddle.Attribute('24')
, 'class': new saddle.Attribute('content fit')
}))
})
, html: '<div id="page" data-x="24" class="content fit"></div>'

@@ -85,5 +85,5 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('input', new saddle.AttributesMap({
template: new saddle.Element('input', {
autofocus: new saddle.Attribute(true)
}))
})
, html: '<input autofocus>'

@@ -100,5 +100,5 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('input', new saddle.AttributesMap({
template: new saddle.Element('input', {
autofocus: new saddle.Attribute(false)
}))
})
, html: '<input>'

@@ -206,5 +206,5 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('input', new saddle.AttributesMap({
template: new saddle.Element('input', {
value: new saddle.Attribute('hello')
}))
})
, html: '<input value="hello">'

@@ -220,6 +220,6 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('input', new saddle.AttributesMap({
template: new saddle.Element('input', {
type: new saddle.Attribute('radio')
, checked: new saddle.Attribute(true)
}))
})
, html: '<input type="radio" checked>'

@@ -234,6 +234,6 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('input', new saddle.AttributesMap({
template: new saddle.Element('input', {
type: new saddle.Attribute('radio')
, checked: new saddle.Attribute(false)
}))
})
, html: '<input type="radio">'

@@ -252,3 +252,3 @@ , fragment: function(fragment) {

test({
template: new saddle.Element('div', new saddle.AttributesMap({
template: new saddle.Element('div', {
'class': new saddle.DynamicAttribute(new saddle.Template([

@@ -262,3 +262,3 @@ new saddle.Text('dropdown')

]))
}))
})
, html: '<div class="dropdown show"></div>'

@@ -275,28 +275,83 @@ , fragment: function(fragment) {

describe('replaceBindings', function() {
describe('attachTo', function() {
var fixture = document.getElementById('fixture');
after(function() {
var fixture = document.getElementById('fixture');
fixture.innerHTML = '';
removeChildren(fixture);
});
function renderAndReplace(template) {
var fixture = document.getElementById('fixture');
fixture.innerHTML = template.get();
var fragment = template.getFragment();
saddle.replaceBindings(fragment, fixture);
function renderAndAttach(template, context) {
removeChildren(fixture);
fixture.innerHTML = template.get(context);
template.attachTo(fixture, fixture.firstChild, context);
}
it('traverses a simple, valid DOM tree', function() {
it('splits static text nodes', function() {
var template = new saddle.Template([
new saddle.Comment('Hi')
, new saddle.Element('ul', null, [
new saddle.Text('Hi')
, new saddle.Text(' there.')
]);
renderAndAttach(template);
expect(fixture.childNodes.length).equal(2);
});
it('splits empty static text nodes', function() {
var template = new saddle.Template([
new saddle.Text('')
, new saddle.Text('')
]);
renderAndAttach(template);
expect(fixture.childNodes.length).equal(2);
});
it('splits mixed empty static text nodes', function() {
var template = new saddle.Template([
new saddle.Text('')
, new saddle.Text('Hi')
, new saddle.Text('')
, new saddle.Text('')
, new saddle.Text(' there.')
, new saddle.Text('')
]);
renderAndAttach(template);
expect(fixture.childNodes.length).equal(6);
});
it('adds empty text nodes around a comment', function() {
var template = new saddle.Template([
new saddle.Text('Hi')
, new saddle.Text('')
, new saddle.Comment('cool')
, new saddle.Comment('thing')
, new saddle.Text('')
]);
renderAndAttach(template);
expect(fixture.childNodes.length).equal(5);
});
it('attaches to nested elements', function() {
var template = new saddle.Template([
new saddle.Element('ul', null, [
new saddle.Element('li', null, [
new saddle.Text('Hi')
new saddle.Text('One')
])
, new saddle.Element('li', null, [
new saddle.Text('Two')
])
])
]);
renderAndReplace(template);
renderAndAttach(template);
});
it('attaches to element attributes', function() {
var template = new saddle.Template([
new saddle.Element('input', {
type: new saddle.Attribute('text')
, autofocus: new saddle.Attribute(true)
, placeholder: new saddle.Attribute(null)
})
]);
renderAndAttach(template);
});
it('traverses with comments in a table and select', function() {

@@ -323,3 +378,3 @@ // IE fails to create comments in certain locations when parsing HTML

]);
renderAndReplace(template);
renderAndAttach(template);
});

@@ -340,3 +395,3 @@

expect(function() {
renderAndReplace(template)
renderAndAttach(template);
}).to.throwException();

@@ -351,14 +406,32 @@ });

after(function() {
fixture.innerHTML = '';
removeChildren(fixture);
});
function render(template, data) {
fixture.innerHTML = '';
var bindings = [];
var context = getContext(data, bindings);
var fragment = template.getFragment(context);
fixture.appendChild(fragment);
return bindings;
}
describe('getFragment', function() {
testBindingUpdates(function render(template, data) {
var bindings = [];
var context = getContext(data, bindings);
var fragment = template.getFragment(context);
removeChildren(fixture);
fixture.appendChild(fragment);
return bindings;
});
});
describe('get + attachTo', function() {
testBindingUpdates(function render(template, data) {
var bindings = [];
var context = getContext(data, bindings);
removeChildren(fixture);
fixture.innerHTML = template.get(context);
template.attachTo(fixture, fixture.firstChild, context);
return bindings;
});
});
});
function testBindingUpdates(render) {
var fixture = document.getElementById('fixture');
it('updates a single TextNode', function() {

@@ -405,6 +478,6 @@ var template = new saddle.Template([

var template = new saddle.Template([
new saddle.Element('div', new saddle.AttributesMap({
new saddle.Element('div', {
'class': new saddle.Attribute('message')
, 'data-greeting': new saddle.DynamicAttribute(new expressions.Expression('greeting'))
}))
})
]);

@@ -671,14 +744,20 @@ var binding = render(template).pop();

it('removes all items from a list with an else');
}
});
function getContext(data, bindings) {
var contextMeta = new expressions.ContextMeta({
onAdd: function(binding) {
var contextMeta = {
addBinding: function(binding) {
bindings && bindings.push(binding);
}
});
, removeBinding: function() {}
};
return new expressions.Context(contextMeta, data);
}
function removeChildren(node) {
while (node && node.firstChild) {
node.removeChild(node.firstChild);
}
}
// IE <=8 return comments for Node.children

@@ -685,0 +764,0 @@ function getChildren(node) {

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