var Scanner = HTMLTools.Scanner;
var getContent = HTMLTools.Parse.getContent;
var CharRef = HTML.CharRef;
var Comment = HTML.Comment;
var TemplateTag = HTMLTools.TemplateTag;
var Attrs = HTML.Attrs;
var BR = HTML.BR;
var HR = HTML.HR;
var INPUT = HTML.INPUT;
var A = HTML.A;
var DIV = HTML.DIV;
var P = HTML.P;
var TEXTAREA = HTML.TEXTAREA;
Tinytest.add("html-tools - parser getContent", function (test) {
var succeed = function (input, expected) {
var endPos = input.indexOf('^^^');
if (endPos < 0)
endPos = input.length;
var scanner = new Scanner(input.replace('^^^', ''));
var result = getContent(scanner);
test.equal(scanner.pos, endPos);
test.equal(BlazeTools.toJS(result), BlazeTools.toJS(expected));
};
var fatal = function (input, messageContains) {
var scanner = new Scanner(input);
var error;
try {
getContent(scanner);
} catch (e) {
error = e;
}
test.isTrue(error);
if (messageContains)
test.isTrue(messageContains && error.message.indexOf(messageContains) >= 0, error.message);
};
succeed('', null);
succeed('abc', 'abc');
succeed('abc^^^', 'abc');
succeed('a<b', ['a', CharRef({html: '<', str: '<'}), 'b']);
succeed('', Comment(' x '));
succeed('∾̳', CharRef({html: '∾̳', str: '\u223e\u0333'}));
succeed('𝕫', CharRef({html: '𝕫', str: '\ud835\udd6b'}));
succeed('&&>&g>;', ['&&>&g', CharRef({html: '>', str: '>'}), ';']);
// Can't have an unescaped `&` if followed by certain names like `gt`
fatal('>&');
// tests for other failure cases
fatal('<');
succeed('
', BR());
succeed('
', BR());
fatal('
'); fatal('Foo'); fatal('Foo'); succeed('', TEXTAREA({value: "asdf"})); succeed('', TEXTAREA({x: "y", value: "asdf"})); succeed('', TEXTAREA({value: "
"}));
succeed('',
TEXTAREA({value: ["a", CharRef({html: '&', str: '&'}), "b"]}));
succeed('', TEXTAREA({value: "\n', TEXTAREA());
succeed('', TEXTAREA({value: "asdf"}));
succeed('', TEXTAREA({value: "\nasdf"}));
succeed('', TEXTAREA({value: "\n"}));
succeed('', TEXTAREA({value: "asdf\n"}));
succeed('', TEXTAREA({value: ""}));
succeed('', TEXTAREA({value: "asdf"}));
fatal('');
succeed('
', BR({x:''}));
succeed('
', BR({x:''}));
succeed('
', BR({x:'y'}));
succeed('
', BR({x:'y'}));
succeed('
', BR({x:'y'}));
succeed('
', BR({x:'y'}));
succeed('
', BR({x:'y'}));
succeed('', Comment('\n'));
succeed('', Comment('\n'));
succeed('
', BR({x:'\n\n'}));
succeed('
', BR({x:'\n\n'}));
succeed('
', BR({x:'y'}));
fatal('
');
});
Tinytest.add("html-tools - parseFragment", function (test) {
test.equal(BlazeTools.toJS(HTMLTools.parseFragment("
Hello
x
'); test.equal(p.tagName, 'p'); test.equal(p.attrs, null); test.isTrue(p instanceof HTML.Tag); test.equal(p.children.length, 1); test.equal(p.children[0], 'x'); })(); (function () { var p = HTMLTools.parseFragment('xA
'); test.equal(p.tagName, 'p'); test.equal(p.attrs, null); test.isTrue(p instanceof HTML.Tag); test.equal(p.children.length, 2); test.equal(p.children[0], 'x'); test.isTrue(p.children[1] instanceof HTML.CharRef); test.equal(p.children[1].html, 'A'); test.equal(p.children[1].str, 'A'); })(); (function () { var pp = HTMLTools.parseFragment('x
y
'); test.isTrue(pp instanceof Array); test.equal(pp.length, 2); test.equal(pp[0].tagName, 'p'); test.equal(pp[0].attrs, null); test.isTrue(pp[0] instanceof HTML.Tag); test.equal(pp[0].children.length, 1); test.equal(pp[0].children[0], 'x'); test.equal(pp[1].tagName, 'p'); test.equal(pp[1].attrs, null); test.isTrue(pp[1] instanceof HTML.Tag); test.equal(pp[1].children.length, 1); test.equal(pp[1].children[0], 'y'); })(); var scanner = new Scanner('asdf'); scanner.pos = 1; test.equal(HTMLTools.parseFragment(scanner), 'sdf'); test.throws(function () { var scanner = new Scanner('asdf'); scanner.pos = 1; HTMLTools.parseFragment(scanner); }); }); Tinytest.add("html-tools - getTemplateTag", function (test) { // match a simple tag consisting of `{{`, an optional `!`, one // or more ASCII letters, spaces or html tags, and a closing `}}`. var mustache = /^\{\{(!?[a-zA-Z 0-9>]+)\}\}/; // This implementation of `getTemplateTag` looks for "{{" and if it // finds it, it will match the regex above or fail fatally trying. // The object it returns is opaque to the tokenizer/parser and can // be anything we want. var getTemplateTag = function (scanner, position) { if (! (scanner.peek() === '{' && // one-char peek is just an optimization scanner.rest().slice(0, 2) === '{{')) return null; var match = mustache.exec(scanner.rest()); if (! match) scanner.fatal("Bad mustache"); scanner.pos += match[0].length; if (match[1].charAt(0) === '!') return null; // `{{!foo}}` is like a comment return TemplateTag({ stuff: match[1] }); }; var succeed = function (input, expected) { var endPos = input.indexOf('^^^'); if (endPos < 0) endPos = input.length; var scanner = new Scanner(input.replace('^^^', '')); scanner.getTemplateTag = getTemplateTag; var result; try { result = getContent(scanner); } catch (e) { result = String(e); } test.equal(scanner.pos, endPos); test.equal(BlazeTools.toJS(result), BlazeTools.toJS(expected)); }; var fatal = function (input, messageContains) { var scanner = new Scanner(input); scanner.getTemplateTag = getTemplateTag; var error; try { getContent(scanner); } catch (e) { error = e; } test.isTrue(error); if (messageContains) test.isTrue(messageContains && error.message.indexOf(messageContains) >= 0, error.message); }; succeed('{{foo}}', TemplateTag({stuff: 'foo'})); succeed('{{foo}}', A({href: "http://www.apple.com/"}, TemplateTag({stuff: 'foo'}))); // tags not parsed in comments succeed('', Comment("{{foo}}")); succeed('', Comment("{{foo")); succeed('&am{{foo}}p;', ['&am', TemplateTag({stuff: 'foo'}), 'p;']); // can't start a mustache and not finish it fatal('{{foo'); fatal('{{'); // no mustache allowed in tag name fatal('<{{a}}>'); fatal('<{{a}}b>'); fatal(''); // single curly brace is no biggie succeed('a{b', 'a{b'); succeed('