Coder Social home page Coder Social logo

htmlbars's People

Contributors

alisdair avatar amiller-gh avatar bantic avatar chadhietala avatar chancancode avatar davidgoli avatar ebryn avatar ef4 avatar eventualbuddha avatar g13013 avatar jayphelps avatar jdjkelly avatar johanneswuerbach avatar krisselden avatar machty avatar marcioj avatar mixonic avatar mmun avatar nopik avatar oneeman avatar ronco avatar rwjblue avatar samio avatar seanpdoyle avatar serabe avatar stefanpenner avatar tilde-engineering avatar tomdale avatar twokul avatar wycats avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

htmlbars's Issues

Unwrap ambiguous mustaches in attributes to their id

The part I haven't done yet but wanted to do is to unwrap ambiguous mustaches (like in both of the above examples) into a plain ID node. This is just a minor optimization.

Concretely, foo={{bar}} should have an attr value of

id('bar')

instead of the current

sexpr([ id('bar') ])

and similarly foo="a{{b}}{{c d}}" should have a value of

[ string("a"), id('b'), sexpr([ id('c'), id('d') ]) ]

instead of the current

[ string("a"), sexpr([ id('b') ]), sexpr([ id('c'), id('d') ]) ]

This seems natural and will remove some unnecessary hooks.subexpr boilerplate in the template.

getElementById

getElementById(detachedDocumentFragmentOrElement, id)

Runtime block params

Block params need to be reimplemented to not rely on JavaScript's lexical scoping at compile time. This is so that {{partial}} will continue to work as if you had cut and paste the contents of the partial into the template.

The strategy will be to use env.set(context, {blockParamName}, blockArguments[i]) to stash the block param on the context (in ember this will probably be on context._keywords). We will need to rollback the "pass by value" changes and instead just pass the path to helpers like we were already doing.

boolean attributes syntax

An example attribute in HTMLBars today:

<span class="{{myClass}}"></span>

The implementation (based on setAttribute) seems to be well supported across recent browser versions across the board.

Boolean attributes are a different story. A first stab at a list of boolean attributes (ignoring read-only attributes):

checked irrelevant draggable disabled
scoped reversed isMap seamless autoplay
controls muted pause active async defer
open multiple hidden default autosubmit

These attributes are always true if present. From the living spec:

A number of attributes are boolean attributes. The presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value.

If the attribute is present, its value must either be the empty string or a value that is an ASCII case-insensitive match for the attribute's canonical name, with no leading or trailing whitespace.

The values "true" and "false" are not allowed on boolean attributes. To represent a false value, the attribute has to be omitted altogether.

So this means:

<input type="checkbox" checked="{{checked}}"></span>

can only ever be checked with HTMLBars today. Kicked this around with @bantic today and we came up with three options for a syntax. Would appreciate feedback:

null removes and attribute

@mixonic is leaning toward this

If the value of context.checked is null, and only if it is null, the checked attribute will be removed with removeAttribute. For all other values it is setAttribute as we do today. The template syntax would be unchanged:

<input type="checkbox" checked="{{checked}}">

When context.checked is null, the attribute is removed. When it is anything else, it is set.

if works inside an element

We don't have an unbound if yet, but possibly this could be handled by an if handler inside nodes?

<input type="checkbox" {{#if isChecked}}checked{{/if}}>

@mmun is this possible? If it is this might be the best option. Or maybe it is already supported by your helper stab and just needs a test.

special helper

The worst option would be some special helper or hook:

<input type="checkbox" {{boolean-attribute 'checked' isChecked}}>

Implement block params parsing in HTML syntax

<todays-date as |day month year|>
  hello!
</todays-date>

should parse to the same AST as

{{#todays-date as |day month year|}}
  hello!
{{/todays-date}}

Currently as |day month year| will be treated as 4 different attributes: as, |day, month, year|.

No module-less runtime present in dist/

It would be nice to have a runtime distribution that exposes window.HTMLBars in environments that don't use a module system.

Is this possible given the fact that the project is relying heavily on modules?

Mark root template with isTop

export function compile(string) {
  var program = compileSpec(string);
  return new Function("return " + program)();
}

Needs to be changed to

export function compile(string) {
  var program = compileSpec(string);
  var template = new Function("return " + program)();
  template.isTop = true;
  return template;
}

This is to support the {{outlet}} helper in Ember. Should also add a test that confirms the root template has isTop === true but that child templates don't have this property.

If someone could explain to me how exactly isTop is used in Ember that would be great too :D Maybe there's a better solution.

Name change

I'm sure you guys have thought of this, and I'm not sure of the best place to put this, but to my mind the progression from Handlebars should be something like Goatee or Musketeer
imperial
muskateer

.

Concat hook called when only one path is provided

This:
<div class="{{path}}"></div>

Will generate this:
attribute(env, element14, "class", concat(env, [get(env, context, "path")]));

It calls the concat hook when only a get() will suffice. When there is only one mustache in an attribute, concat should not be called.

Don't concat unquoted attribute values

An AttrNode is composed of a name and a value. The value can be either a string primitive or a MustacheNode. Here is a summary of the different cases today (the MustacheNodes are written as their equivalent mustache template syntax for brevity).

<div foo="bar">            -->     name: "foo", value: "bar"
<div foo="bar{{baz}}">     -->     name: "foo", value: {{concat 'bar' baz}}
<div foo="{{baz}}">        -->     name: "foo", value: {{concat baz}}
<div foo={{baz}}>          -->     name: "foo", value: {{concat baz}}

Note that 3 & 4 both call concat on baz. Instead we need 4 to be just

<div foo={{baz}}>          -->     name: "foo", value: {{baz}}

The work required is pretty minimal. Right now we use the same handler for unquoted and quoted attribute values. See https://github.com/tildeio/htmlbars/blob/master/packages/htmlbars-compiler/lib/html-parser/token-handlers.js#L9-L11. Just need to add the new behavior in the unquoted case.

Indentation for attribute hook is incorrect.

(function() {
return (function() {
  function build(dom) {
    var el0 = dom.createElement("div");
    var el1 = dom.createTextNode("Hi!");
    dom.appendChild(el0, el1);
    return el0;
  }
  var cachedFragment;
  return function template(context, env, contextualElement) {
    var dom = env.dom, hooks = env.hooks, get = env.get;
    dom.detectNamespace(contextualElement);
    if (cachedFragment === undefined) {
      cachedFragment = build(dom);
    }
    var fragment = dom.cloneNode(cachedFragment, true);
    var element0 = fragment;
  hooks.attribute(element0, "data-name", undefined, context, [hooks.subexpr("name", context, [], {},{type:"id",paramTypes:[],hashTypes:{}}, env)], {paramTypes:["sexpr"],hashTypes:{}}, env);
    return fragment;
  };
}())
})

The hook.attribute line should be the same indentation as the line directly above it.

Use text node for morph is too fragile when combined with other libraries

As continued discussion of emberjs/ember.js#9498, I think using empty text node for morph might be too fragile since the node is practically invisible. That might be the whole point but at the same time this makes it hard for it to work with other libraries (particularly jQuery plugins) that may want to wrap the DOM node.

If the reason to use empty text node is to avoid CSS selector issue, then there are other non-element DOM nodes that can be used, like comment node.

Pass `escaped` to morph instead of helper

Instead of

var morph0 = dom.createMorph(fragment,0,1,contextualElement);
hooks.content(morph0, "foo", context, [], {escaped:true}, env);

we should generate

var morph0 = dom.createEscapedMorph(fragment,0,1,contextualElement);
hooks.content(morph0, "foo", context, [], {}, env);

Mustache attr shorthand

Valid

<p class="{{foo}}">Omg</p>

Invalid

<p class={{foo}}>Omg</p>

TODO

This: <p class=foo>Omg</p>
Is presently treated as: <p class="foo">Omg</p>
Should probably be auto-converted shorthand for: <p class="{{foo}}">Omg</p>

The way this breaks is weird:
<p class={{foo}}>Omg</p>

Should either break loudly or autoconvert to
<p class="{{foo}}">Omg</p>

official Release

There is no change for 3 weeks and still a lot to be done. Checking the EmberJS website this library should have gone 1.0.0 around beginning of this year. So my question is:
What happened and when can we look at the first release?

Don't cache the fragment on the first pass

To speed up initial renders we should not cache & clone the fragment on the first execution of the template. Instead we should cache the fragment on the second execution.

publish to npm

There is a package.json here and working code, but htmlbars isn't on npm. Publish it before somebody else does!

Finalize Hooks

Source Generated Hook
Block params set(env, context, path, value)
PathExpression get(env, context, path)
SubExpression subexpr(env, context, path, params, hash)
Attr. Interpolation concat(env, parts)
{{foo}} content(env, context, path, morph)
{{foo bar}} inline(env, context, path, params, hash, morph)
{{#foo}}{{/foo}} block(env, context, path, params, hash, morph, template, inverse)
<x-foo></x-foo> component(env, context, path, attributes, morph, template)
<p id={{id}}></p> attribute(env, element, name, value)
<img {{foo bar}}> element(env, context, path, params, hash, element)

Bring theese guys some beer and pizza!

Hey!

Is there a donation we can do? :-)

A think a lot lot lot of devs are waiting for this to happen (myself and my team included).

Loading >300 records, every one with some metamorph if's, couple of relations, and it's not usable.

It's profiling hell, and it's not getting any better. We're hacking the hell out of handlebars, but we all know it's BS.

So, I'll bring you guys evetyghing you need to code this jewel (well.. ember) just to finish this in the best way you can :-)

Of course this is kind-of haha-issue, but I'm sure I'm not the only one cheering on this thing to be completed, it means a lot to the community :-)

Have a great one!

[Performance] HTMLbars twice as slow as Handlebars 1.3

Hi,

I've read that HTMLbars should improve performance of most Ember apps with 2-3 times. But, running latest ember canary with latest ember-cli-htmlbars results in htmlbars begin 2 times slower than Handlebars 1.3;

For example, these are screenshots of the same Ember app rendering a list of 10 items in a table. You can see that Handlebars is 2x faster:

Handlebars:

HTMLBars

Why is this happening? I know it is still in beta, but would like to know if this will be better later on.

Finalize AST

  • Introduce ElementModifier AST node.
  • Rename ElementNode.helpers โ†’ ElementNode.modifiers

Build output does not contain license comment or version information

Though it's clear HTMLBars is licensed MIT, the build output in the npm package does not contain a license comment or version information.

If HTMLBars is bundled in other projects, it's important to indicate its license without requiring that the LICENSE file itself be bundled.

Invalid code generated from invalid module syntax

Currently both in htmlbars and handlebars there is a common occurrence of the following:

import {compile, compileSpec} from "./htmlbars-compiler/compiler";
export {compile, compileSpec};

import Morph from "./morph/morph";
export var Morph;

import DOMHelper from "./morph/dom-helper";
export var DOMHelper;

Which transpiles into:

"use strict";
var compile = require("./htmlbars-compiler/compiler").compile;
var compileSpec = require("./htmlbars-compiler/compiler").compileSpec;
exports.compile = compile;
exports.compileSpec = compileSpec;

var Morph = require("./morph/morph")["default"];
var Morph;
exports.Morph = Morph;
var DOMHelper = require("./morph/dom-helper")["default"];
var DOMHelper;
exports.DOMHelper = DOMHelper;

As you can see we end up with a static error by re-declaring identifiers. I would propose adjusting to the following:

export {compile, compileSpec} from "./htmlbars-compiler/compiler";

import _Morph from "./morph/morph";
export var Morph = _Morph;

import _DOMHelper from "./morph/dom-helper";
export var DOMHelper = _DOMHelper;

Which transpiles to:

"use strict";
exports.compile = require("./htmlbars-compiler/compiler").compile;
exports.compileSpec = require("./htmlbars-compiler/compiler").compileSpec;

var _Morph = require("./morph/morph")["default"];
var Morph = _Morph;
exports.Morph = Morph;
var _DOMHelper = require("./morph/dom-helper")["default"];
var DOMHelper = _DOMHelper;
exports.DOMHelper = DOMHelper;

There are better ways to write this technically and in relation to the ES6 Modules spec but the transpiler doesn't produce good results from them currently. It might with the latest branch of es6-module-transpiler coming eventually.

Investigate why test failures are not reported

Currently IE 10 and 11 don't pass the htmlbars test suite, but are only marked as finished and not as failed. Also the test output is not published as expected.

Example: https://saucelabs.com/tests/2e3b919384ea4ce48261a61447a2935c

Workaround to get the test output:

  1. Open the build, e.g. https://saucelabs.com/tests/2e3b919384ea4ce48261a61447a2935c
  2. Open the "Commands" tab
  3. Click on "POST execute" and copy the JSON behind "=> " into http://jsonformatter.curiousconcept.com/

this.element is undefined if bind-attr is after a no-value attribute

With this markup:

<form autocomplete="on" novalidate {{bind-attr style=style}}>
  ...
</form>

I would hit an exception trying to read setAttribute on undefined.

Shuffling the attributes around made it work:

<form autocomplete="on" {{bind-attr style=style}} novalidate>
  ...
</form>

Split paths at compile time

The template {{foo.bar.baz}} currently generates the hydration hook

hooks.content(morph0, "foo.bar.baz", context, [], {...}, env);

Instead it should split the path at runtime so that the strings are interned:

hooks.content(morph0, ["foo", "bar", "baz"], context, [], {...}, env);

Single segment paths can just pass a string, e.g. {{foo}} should result in. Edit: Just keep it simple for now and always pass an array.

hooks.content(morph0, "foo", context, [], {...}, env);

This should also affect params and hashes.

Simplify AttrNode

The AttrNode AST node is confusing. We should remove quoted from the AST and make value a simple node, instead of an array. Specific proposal:

interface AttrNode {
    type: "AttrNode";
    name: string;
    value: TextNode | MustacheStatement | ConcatStatement,
}

interface ConcatStatement {
    type: "ConcatStatement";
    parts: [ Expression ];
}

which would map to

<div id></div> - TextNode
<div id=foo></div> - TextNode
<div id="foo"></div> - TextNode
<div id={{foo}}></div> - MustacheStatement
<div id={{foo bar}}></div> - MustacheStatement
<div id="{{bar}}"></div> - ConcatStatement
<div id="foo{{bar}}baz"></div> - ConcatStatement

Cannot build with "npm run-script build" on latest master branch

Whenever I try to build with "npm run-script build", I got this:
Build failed.

Error: ENOENT, no such file or directory '/Users/xxxx/ruby-edge/htmlbars/tmp/tree_merger-tmp_dest_dir-qLGm9Yds.tmp/htmlbars/'
  at Object.fs.lstatSync (fs.js:690:18)
  at Object.copyRecursivelySync (/Users/xxxx/ruby-edge/htmlbars/node_modules/broccoli-static-compiler/node_modules/broccoli-kitchen-sink-helpers/index.js:142:21)
  at /Users/xxxx/ruby-edge/htmlbars/node_modules/broccoli-static-compiler/index.js:20:15
  at $$$internal$$tryCatch (/Users/xxxx/ruby-edge/htmlbars/node_modules/rsvp/dist/rsvp.js:470:16)
  at $$$internal$$invokeCallback (/Users/xxxx/ruby-edge/htmlbars/node_modules/rsvp/dist/rsvp.js:482:17)
  at $$$internal$$publish (/Users/xxxx/ruby-edge/htmlbars/node_modules/rsvp/dist/rsvp.js:453:11)
  at $$rsvp$asap$$flush (/Users/xxxx/ruby-edge/htmlbars/node_modules/rsvp/dist/rsvp.js:1531:9)
  at process._tickCallback (node.js:419:13)
  at Function.Module.runMain (module.js:499:11)
  at startup (node.js:119:16)
  at node.js:906:3

Is there anything I did wrong here?

Helper API clean up

Status quo

Hooks that appear in compiled templates

  • content(morph, helperName, context, params, options)
  • webComponent(morph, tagName, context, options, helpers)
  • element(domElement, helperName, context, params, options)
  • subexpr(helperName, context, params, options)

Secondary hook utilities

HTMLBars:

  • webComponentFallback(morph, tagName, context, options, helpers)
  • lookupHelper(helperName, context, options)
  • simple(context, name, options)

bound-templates:

  • streamifyArgs(context, params, options, hooks)
  • streamFor(context, path)
  • lookupHelper(name, helpers)

Built-in helpers

HTMLBars:

  • attribute(context, params, options)
  • concat(context, params, options)

bound-templates:

  • attribute(element, params, options)
  • concat(params, options)

The future?

Hooks

They should have these signatures:

  content(   morph, context, path, params, options, env)
  subexpr(          context, path, params, options, env)
  element( element, context, path, params, options, env)
component(   morph, context, path,         options, env)
  • options contains information specific to the invocation of that particular hook/mustache, like types, hash, hashTypes, render, inverse, escaped/raw.
  • env contains stuff that is intended to be inherited to child templates, like dom, hooks, lookupHelper, keywords, data. Purposely omitted is helpers. See below.
  • content should be built up from subexpr.

Helpers & questions

  • Should all helper resolution should pass through lookupHelper rather than direct lookups on a helpers hash? "Scoped" helpers could be implemented by overriding the lookupHelper method on env. var newHelpers = Object.create(oldHelpers) may be good enough.
  • Both content and element helpers should have the signature:

    helper(morphOrElement, values, options, env)

    where values is an array of primitives or streams. Basically, for each param, if the type is id streamify that param against the context, otherwise just pass the primitive through. Not sure if context should be included in the signature, since all the id-values should have been resolved. Is there any reason to include context?
  • There are also "pure" helpers that don't operate on a morph or an element, mostly they appear in subexpressions, e.g. concat or query-params.
    • Should element helpers like bind-attr and action be allowed to have different signatures than content helpers like link-to or if? I think yes. Element helpers should be passed the element as their first arg. Content helpers may need the morph as their first arg, so that bound helpers can update their morph. I think the each helper probably would benefit from access to the morph.
    • Should attribute continue to be an element helper or should it be promoted to a hook?
    • Seems weird that params is pulled out of the options but hash isn't, especially if the params aren't spread anyways.
    • Does keywords belong in options.data or env? What goes in options.data?
    • How do you safely override stuff in env? newEnv = Object.create(env)?

Closing and reopening tags dynamically doesn't compile

I'm not sure if I'm logging this issue in the right place or not. This is the first time I've ever created an issue on GitHub.

I experienced this issue in Ember using HTMLBars so I downloaded this repository and attempted to add a test - it looked like the following file would be the most appropriate place:

htmlbars/packages/htmlbars-compiler/tests/combined_ast_node-test.js

The template is defined as:

<ul>{{#each foo}} {{#if startNewList}}</ul><ul>{{/if}} <li>item</li> {{/each}}</ul>

The test failed because an error was thrown - the same error I experienced in Ember.

Error: Closing tag 'ul' (on line 1) did not match last open tag 'undefined'.
    at HTMLProcessor.tokenHandlers.EndTag (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3079:17)
    at HTMLProcessor.acceptToken (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3211:47)
    at forEach (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3260:20)
    at HTMLProcessor.nodeHandlers.ContentStatement (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:2889:16)
    at HTMLProcessor.acceptNode (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3206:43)
    at HTMLProcessor.nodeHandlers.Program (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:2833:16)
    at HTMLProcessor.acceptNode (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3206:43)
    at HTMLProcessor.nodeHandlers.BlockStatement (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:2863:60)
    at HTMLProcessor.acceptNode (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:3206:43)
    at HTMLProcessor.nodeHandlers.Program (http://0.0.0.0:4200/amd/htmlbars-compiler.amd.js:2833:16)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.