Example #1
0
test('converts entities to their char/string equivalent', function () {
  var ast = preprocess("<div title=\"&quot;Foo &amp; Bar&quot;\">lol &lt; &#60;&#x3c; &#x3C; &LT; &NotGreaterFullEqual; &Borksnorlax;</div>");
  var fragment = fragmentFor(ast);

  equal(fragment.getAttribute('title'), '"Foo & Bar"');
  equal(fragment.textContent, "lol < << < < ≧̸ &Borksnorlax;");
});
test("it works", function testFunction() {
  /* jshint evil: true */
  var ast = preprocess('<div>{{#if working}}Hello {{firstName}} {{lastName}}!{{/if}}</div>');
  var compiler = new TemplateCompiler();
  var program = compiler.compile(ast);
  var template = new Function("dom", "Morph", "return " + program)(dom, Morph);
  var frag = template(
    { working: true, firstName: 'Kris', lastName: 'Selden' },
    { hooks: hooks }
  );
  equalHTML(frag, '<div>Hello Kris Selden!</div>');
});
function actionsEqual(input, expectedActions) {
  var ast = preprocess(input);

  var templateVisitor = new TemplateVisitor();
  templateVisitor.visit(ast);
  var actualActions = templateVisitor.actions;

  // Remove the AST node reference from the actions to keep tests leaner
  for (var i = 0; i < actualActions.length; i++) {
    actualActions[i][1].shift();
  }

  deepEqual(actualActions, expectedActions);
}
Example #4
0
test('test auto insertion of text nodes for needed edges a fragment with morph mustaches', function () {
  var ast = preprocess("{{first}}<p>{{second}}</p>{{third}}");
  var fragment = dom.cloneNode(fragmentFor(ast), true);
  var hydrate = hydratorFor(ast);

  var morphs = [];
  var fakeMorphDOM = new DOMHelper();
  fakeMorphDOM.createMorphAt = function(){
    var morph = DOMHelper.prototype.createMorphAt.apply(this, arguments);
    morphs.push(morph);
    return morph;
  };

  var contentResolves = [];
  var context = {};
  var env = {
    dom: fakeMorphDOM,
    hooks: {
      content: function(morph, path, context, params, options) {
        contentResolves.push({
          morph: morph,
          context: context,
          path: path,
          params: params,
          options: options
        });
      }
    }
  };

  hydrate(fragment, context, env.dom, env.hooks, env, document.body);

  equal(morphs.length, 3);

  var t = morphs[0].start;
  equal(t.nodeType, 3);
  equal(t.textContent , '');
  equal(morphs[1].start, null);
  equal(morphs[1].end, null);

  equal(morphs[2].start, morphs[1].parent());
  equal(morphs[2].end.nodeType, 3);
  equal(morphs[2].end.textContent, '');

  morphs[0].update('A');
  morphs[1].update('B');
  morphs[2].update('C');

  equalHTML(fragment, "A<p>B</p>C");
});
Example #5
0
test('test auto insertion of text nodes for needed edges a fragment with morph mustaches', function () {
  var ast = preprocess("{{first}}<p>{{second}}</p>{{third}}");
  var fragment = fragmentFor(ast).cloneNode(true);
  var hydrate = hydratorFor(ast);

  var morphs = [];
  var FakeMorph = {
    create: function (start, startIndex, endIndex) {
      var morph = Morph.create(start, startIndex, endIndex);
      morphs.push(morph);
      return morph;
    }
  };

  var contentResolves = [];
  var context = {};
  var helpers = {};
  var hooks = {
    content: function(morph, path, context, params, options) {
      contentResolves.push({
        morph: morph,
        context: context,
        path: path,
        params: params,
        options: options
      });
    }
  };

  hydrate(FakeMorph, fragment, context, hooks, helpers);

  equal(morphs.length, 3);

  var t = morphs[0].start;
  equal(t.nodeType, 3);
  equal(t.textContent , '');
  equal(morphs[1].start, null);
  equal(morphs[1].end, null);

  equal(morphs[2].start, morphs[1].parent());
  equal(morphs[2].end.nodeType, 3);
  equal(morphs[2].end.textContent, '');

  morphs[0].update('A');
  morphs[1].update('B');
  morphs[2].update('C');

  equalHTML(fragment, "A<p>B</p>C");
});
Example #6
0
test('hydrates a fragment with morph mustaches', function () {
  var ast = preprocess("<div>{{foo \"foo\" 3 blah bar=baz ack=\"syn\"}} bar {{baz}}</div>");
  var fragment = fragmentFor(ast).cloneNode(true);
  var hydrate = hydratorFor(ast);

  var contentResolves = [];
  var context = {};
  var env = {
    dom: dom,
    hooks: {
      content: function(morph, path, context, params, options) {
        contentResolves.push({
          morph: morph,
          context: context,
          path: path,
          params: params,
          options: options
        });
      }
    }
  };

  hydrate(fragment, context, env.dom, env.hooks, env);

  equal(contentResolves.length, 2);

  var foo = contentResolves[0];
  equal(foo.morph.parent(), fragment);
  equal(foo.context, context);
  equal(foo.path, 'foo');
  deepEqual(foo.params, ["foo",3,"blah"]);
  deepEqual(foo.options.types, ["string","number","id"]);
  deepEqual(foo.options.hash, {ack:"syn",bar:"baz"});
  deepEqual(foo.options.hashTypes, {ack:"string",bar:"id"});
  equal(foo.options.escaped, true);

  var baz = contentResolves[1];
  equal(baz.morph.parent(), fragment);
  equal(baz.context, context);
  equal(baz.path, 'baz');
  equal(baz.params.length, 0);
  equal(baz.options.escaped, true);

  foo.morph.update('A');
  baz.morph.update('B');

  equalHTML(fragment, "<div>A bar B</div>");
});
Example #7
0
function opcodesFor(html, options) {
  var ast = preprocess(html, options),
      compiler1 = new HydrationOpcodeCompiler(options);
  compiler1.compile(ast);
  return compiler1.opcodes;
}
Example #8
0
test('compiles a fragment', function () {
  var ast = preprocess("<div>{{foo}} bar {{baz}}</div>");
  var fragment = fragmentFor(ast);

  equalHTML(fragment, "<div> bar </div>");
});
Example #9
0
test("visits ast in an order friendly to opcode generation", function () {
  var input = "A{{#if}}B{{#block}}C{{/block}}{{#block}}D{{/block}}{{else}}E{{#block}}F{{/block}}{{/if}}<div>G{{#block}}H{{gnarly}}{{/block}}<span>{{woot}}{{foo}}</span><em></em><a><em {{foo}}>{{bar}}</em></a><em {{baz}}></em><a {{foo}} {{bar}}></a></div>{{bar}}";
  var expected = "[0: [0: 'C' 1: 'D'] 'B{{0}}{{1}}' 1: [0: 'F'] 'E{{0}}' 2: 'H'] 'A{{0,1}}<div 5>G{{2}}<span 2></span><em 0></em><a 1><em 2></em></a><em 1></em><a 2></a></div>'";

  var ast = preprocess(input);

  var visitor = {
    opcodes: [],
    templateId: 0,
    startTemplate: function (program, childTemplateCount) {
      this.templateId = 0;
      this.opcodes.push(['startTemplate', childTemplateCount]);
    },
    endTemplate: function () {
      this.opcodes.push(['pushTemplate']);
    },
    openElement: function (element, a, b, mustacheCount) {
      this.opcodes.push(['openTag', element.tag, mustacheCount]);
    },
    text: function (text) {
      this.opcodes.push(['text', text.chars]);
    },
    closeElement: function (element) {
      this.opcodes.push(['closeTag', element.tag]);
    },
    block: function (block) {
      this.opcodes.push(['block', this.templateId++, block.inverse === null ? null : this.templateId++]);
    },
    node: function (node) { }
  };

  var walker = new ASTWalker(visitor);
  walker.visit(ast);

  var compiler = {
    stack: [],
    template: null,
    startTemplate: function (childCount) {
      this.template = '';
      var childId = 0, child;
      if (childCount > 0) {
        this.template += '[';
        while (childCount--) {
          child = this.stack.pop();
          if (childId > 0) this.template += ' ';
          this.template += '' + childId++ + ': ' + child;
        }
        this.template += '] ';
      }
      this.template += "'";
    },
    pushTemplate: function () {
      this.template += "'";
      this.stack.push(this.template);
    },
    openTag: function (tag, mustacheCount) {
      this.template += '<' + tag + ' ' + mustacheCount + '>';
    },
    closeTag: function (tag) {
      this.template += '</' + tag + '>';
    },
    text: function (str) {
      this.template += str;
    },
    block: function (programId, inverseId) {
      this.template += '{{' + programId;
      if (inverseId !== null) {
        this.template += ',' + inverseId;
      }

      this.template += '}}';
    },
    compile: function (opcodes) {
      var opcode;
      for (var i=0; i<opcodes.length; i++) {
        opcode = opcodes[i];
        this[opcode[0]].apply(this, opcode.slice(1));
      }
      return this.stack.pop();
    }
  };

  var output = compiler.compile(visitor.opcodes);

  equal(output, expected);
});