So, in HTML, the following are equivalent, and both mean that a checkbox is checked, because the `checked` attribute is present:
- `<input type="checkbox" checked>`
- `<input type="checkbox" checked="">`
We can't mess with that. On the other hand, in Spacebars before this commit, the following would *also* result in the checkbox being checked, regardless of whether `foo` evaluates to null, undefined, false, or the empty string:
- `<input type="checkbox" checked={{foo}}>`
- `<input type="checkbox" checked="{{foo}}">`
With this commit, the checkbox will NOT be checked if `foo` evaluates to null, undefined, or false.
To achieve this:
- In HTMLjs, an attribute is considered absent if its value is "nully" after being fully evaluated (i.e. after expanding functions and components via HTML.evaluateDynamicAttributes / HTML.evaluate). A nully value is one consisting of null, undefined, an empty array, or an array of those things. `false` is not nully and renders as "false". An empty string is not nully, and will "prop open" an attribute that would otherwise collapse into absence.
- Spacebars.mustache converts null, undefined, and false to null. So if you use {{foo}} anywhere in a template and foo evaluates to "false", that gets to converted to a null in HTMLjs (which is ignored). (true is rendered as "true".)
- When parsing HTML, an attribute that consists of *no tokens* becomes an empty string in the HTMLjs, which props open the attribute (unlike null or an empty array). (Since comment tokens are stripped during tokenization, if there are only comments in an attribute value that counts as no tokens.)
We were weirdly ignoring helpers that were falsy constants, so in `Template.main.foo = 0` / `{{foo}}` you'd get nothing, while if you did `Template.main.foo = function () { return 0; }` you would get "0".
A helper can return an object with a set of element attributes via
`<p {{attrs}}>`. When it re-runs due to a dependency changing the
value for a given attribute might stay the same. Test that the
attribute is not set on the DOM element.
- When helpers return SafeStrings, compare their underlying
strings.
- When helpers return objects (such as for dynamic attributes),
never isolate. The objects may have been mutated directly.
AttributeHandler ends up only affecting real changes.
Do the appropriate equality check for three cases:
(1) helpers in text nodes
(2) helpers in element attributes
(3) helpers in dynamic template inclusion
Also, assert that helpers passed to template inclusion indeed
return components or null.
More specifically, a helper re-runs and its return value hash't
changed, nothing should change in the DOM. Test this for:
(1) helpers in text nodes
(2) helpers in element attributes
(3) helpers in dynamic template inclusion
All existing listener callbacks were already calling complete()
synchronously, so this should not be a functional change.
This allows us to also eliminate the callback from crossbar.fire().
This in turn allows us to eliminate the `proxy_write` in
Meteor.refresh. The only purpose of that write was to keep the current
write fence open until fire's async callback got called; now that fire
works synchronously, it's not necessary! (This relies on the fact that
write fences never get armed while they are the current write fence,
which now has an assertion.)
Trying to include them later with {{> content}}
fails. We could disallow the other built-ins,
eg 'if' and 'elseContent' but sounds less likely
that users will try to define templates with
those names, and this simple change lets us
not duplicate code.
- use startsWith for strings rather than x.indexOf(y) && x[y.length] === '.'
- more comments with examples
- consistent naming isSimple => simpleRange, simpleInequality, etc
Previously, certain errors on the client/proxy socket would result in
the proxy keeping the websocket to the server open forever rather than
closing it. For example, disconnecting the client from the internet
without a graceful shutdown. This could easily be reproduced with any
app using `facts`, eg https://github.com/tarangp/test-observers.
Run the app, connect locally with one browser, connect from a second
computer, observe sessions going to 2, disconnect the second computer.
With this commit, sessions will go back to 1 in about a minute. Without
it, it never will.
This particular fix is not very compelling, since it uses undocumented
features of the stream interface. I will file an issue with the
node-http-proxy project tonight asking how we're supposed to do this.
This addresses #1769. I'll close that once we have a more compelling
fix, and once the similar bug is fixed in the proxies used in the
`meteor deploy` server and in Galaxy.
We would choke on CR line endings, because we didn't implement the preprocessing step of converting CR(LF)? to LF. Now we correctly convert (or ignore) CR inside tags, in text nodes, in attributes, and in comments.
- Fix the pruning `expectedScalarIsObject`
- Limit $gt,$lt,... to numbers only (since there needs to be more logic to support dates and strings later)
- Add comments on dubious parts