Juicy/juicy-html

Redesign flow to build a partial.

Closed this issue · 19 comments

We are facing more, and more issues that suggest we should reconsider overall design of <x-html>.

I have decided to create this umbrella issue, to track general discussions about new designs, and flows.

Here is the list of issues that, led us here:

  • #7 Model binding does not work in Polymer 0.2.2
  • #6 External script support
  • #3 Sometimes <script>'s are being executed before HTML was attached to DOM.
  • Polyjuice/Launcher#10 Chase between external js and HTML imports
  • Polyjuice/Launcher#12 Sortable-list does not work with current merger and x-html

There were and are many ideas, but for now I'll describe my recent one:

I have already submitted a proposition to change <x-html> to <template is="x-html"> (. It seems to give many benefits:

  1. First, of all, as it is <template> we will get .model out of the box (#7),
  2. We would not have to wrap every <x-html> with <template bind="{{scope}}"> as we can do it with <template is="x-html" bind="{{scope}}"> (see example ),
  3. It will be absolutely clear now, that scripts and HTML Imports are handled exactly as in any other <template>.(#3, #6)
    If we would like to change also this behavior I believe we should do it with other Custom Element (probably by extending this one) (Polyjuice/Launcher#10)
  4. Partial content will naturally appear as element's siblings (Polyjuice/Launcher#12)
  5. It works with current (Polymer#master(23044b02e0)).

I believe, that it will give us fully featured <template> simply extended by safe-HTML support, without messing with/blocking/re-implementing any other stuff

Would it still support two usage scenarios that we have right now?

<template is="x-html" bind content="<b>Some HTML</b>"></template>
<template is="x-html" bind content="./partial.html"></template>

Point 4 seems to be the biggest winner for me.

Points 1-2 are implementation details, that don't matter now.

Point 3 is where we lose the current syntactic sugar. Could we please further investigate if it is possible for scripts to be handled exactly as in an HTML Import? (from my test it looks that they load with blocking, which is what we want). I agree that this can be another Custom Element that extends this one, I would just use it instead.

Yes, it will. Please take a look at examples.

Regarding 3., I'm affraid, just HTML Import behavior is not entirely what
we want, as it runs script when loaded, and cannot be imported more than
once.
But still, we can cover subpage scenario and control scripts flow with new
Element.

I think we can keep support for the simplicity of the old <x-html> tag and still cater for big and complex partials.

In this post, I will use the old name <x/html> although it will probably be renamed.

We need two versions of <x-html>. One to stamp out a singleton and one to enhance a <template> element. Otherwise, they should work the same.

<template is="html-import" src="/test.html"></template>
<x-html src="/test.html"></x-html>

The html-import element

It uses the <link rel="import"> standard. In this way, the user can enjoy things as dependency management (not loading the same stuff many times) and script execution order (the script manipulating the instance will run once for every stamp-out and the other stuff will only run once). The good part is that the behavior is (will be) well documented by the W3C. But to keep the simplicity of the old use-case and to allow the developer not to know about templates and html imports, we also provide a fall back that allows for ill-behaved or simple partials.

Ill-behaved partials

An ill behaved partial will believe it is the only instance in the document. It will use document.getElementById() or $("mything") and risk on addressing other elements than inside its own scope. This will lead to a very unstable system.

Providing protection

There are basically three levels of encapsulation available.

  1. Global DOM
  2. Shadow DOM
  3. <iframe>

The idea is to avoid the <iframe> only when it is safe.

Detecting ill behaved partials

The imported document fragement from test.html will be queried for a <template> and a <title>

  1. If there is a no <title>, we will consider this a well behaved partial
  2. If not, we will consider this an ill behaved partial (there is one exception, see below)

Dealing with ill-behaved partials

If it is an ill behaved partial, we will put it in an <iframe> if it contains a <title>. If not, we can upgrade the fragment to being well behaved. There is no Javascript, so a shadow dom is a better option. In this way, we provide the same functionality as for the old <x-html> tag and also allow for inline html.

Well behaved partials

The well behaved partial will be put it the shadow dom. The well behaved partial will be responsible for not leaking its logic. Shadow DOM should be used for individual parts of the partial to allow mixing while at the same time protecting internal styling.

The x-html element

Same as the template but creates an instance in the DOM.

I'm going to start development of <template is="html-import">, but I doubt if html-import is the name we should use, as it could lead to confusion with W3C HTML Imports. Maybe template-import? - it is not so confusing when used alone, however, in code <template is="template-import"> looks a bit weird.

BTW, are we going to keep current <x-html> as it is or are we going to use <template is="x-html"> as I proposed in here which is in my opinion serves exactly same functionality but cleaner and minimized.

To summarise:

  1. The well behaved partials should be put in the shadow dom.
  2. The ill behaved partials should be put in an <iframe>

We detect the existence of a <title> element to identify who is who.

Example of a naive but (hopefully) well behaved partial

<div>
I'm well behaved because I have no title. I do not believe I'm on my own.
</div>
<script>
what.is.going.on();
</script>

Example of an ill-behaved partial

<head>
   <script src="lib/jquery.js"></script>
   <title>I'm my own boss</title>
</head>
<div id="main">
   I will be put in an iframe because I might believe I'm on my own (and I do scripting).
   Please contain me.
</div>
<script>$("main").textContent = "Typical me";</script>

Example of a performant and well behaved partial

<link rel="import" href="lib/jquery.html"> <!-- well behaved partials can load dependencies as
                                                they are guaranteed not to run multiple times --->
<template>
   <div>I might be cloned in many places in the document</div>
   </template>
   <script>
      console.log("I will run whenever I'm stamped out in by an owner document");
   </script>
</template>
<script>I will run only once</script>

Simple partials

<link rel="import" href="lib/handsontable.html">
<div>{{FirstName}} {{LastName}}</div>

Simple partials

<div>hello world</div>

How do we detect well behaved partials?

Difference between x-html and new element, names:

For simple use cases, when we need to put just HTML (either inline or from file), without any additional magic, or scripting solutions, there will be current <x-html>

<template is="x-html" content="./file.html" bind></template>
<template is="x-html" content="<li>{name}</li>" repeat="{{person in people}}"></template>

as a extended <template>. That gives us benefits described above.

To get better control over scripting inside template we need additional extension for <template is="x-html">, that will add with some HTML Imports features, and handle various scenarios of partial's content.

<template is="imported-template" content="./file.html" bind></template>

Partials detection

At first attempt lets try something simple:

Well behaved partial

Partial that is aware that it could be replicated, and delivers <template> to clone, as well as <script>,<link>s, etc. that will be used only once.

  • contain <template> on root level
<link rel="import" href="my/custom/element.html">
<script src="external.js"></script>
<template>
    <my-element><strong>{{Name}}</strong></my-element>
    <script>console.log("my-element stamped");</script>
</template>

Ill behaved (<iframe>)

  • does not contain <template> on root level
  • but does contain at least one <script>, or <link>
<script src="external.js"></script>
<div><h1>My App</h1></div>
<script>console.log("My App rule the world!");</script>

Simple partial

Something that we can simply put as document fragment to <template>.content

  • HTML given as string
  • HTML file (document) that does not contain neither <script>, <link>, nor <template>
<li><strong>{{Name}}</strong></li>

I'm afraid there will be a problem with handling ill behaved ones.
We cannot query HTML document to load before, well.. loading it first.
So if we are going to use HTML Imports, scripts from ill behaved partial will be already executed.
If we are going to do XHR as before, then we will need to perform it also for well behaved ones,, and for every single instance of template (unless we will implement some caching magic), and then, we would need to parse entire document.

For sure, it would be way much simpler if ill behaved flag would be given from outside as attribute.
Then someone responsible for providing URL for HTML file, would be responsible also for providing information if it is a ill behaved or well behaved (simple vs. composite partial could be easily distinguished by our Element)
Current examples available in here

There is also a problem with putting well behaved ones into ShadowDOM, as it will break partials that were designed to server multiple nodes on root level, for examples merged output from Polujuice/Launcher.
To solve this we will probably need, any of those:

  1. a feature to handle multiple templates in single partial,
  2. put <sortable-list> element into merged partial,
  3. change Launcher's merging flow even more.

@Starcounter-Jack I'm afraid we should reconsider changing design once again.

Good point. Let's assume they are well behaved for now. We need to work against the demo.

Sent from my iPhone

On 26 Mar 2014, at 18:19, Tomek Wytrębowicz notifications@github.com wrote:

I'm afraid there will be a problem with handling ill behaved ones.
We cannot query HTML document to load before, well.. loading it first.
So if we are going to use HTML Imports, scripts from ill behaved partial will be already executed.
If we are going to do XHR as before, then we will need to perform it also for well behaved ones,, and for every single instance of template (unless we will implement some caching magic), and then, we would need to parse entire document.

For sure, it would be way much simpler if ill behaved flag would be given from outside as attribute.
Then someone responsible for providing URL for HTML file, would be responsible also for providing information if it is a ill behaved or well behaved (simple vs. composite partial could be easily distinguished by our Element)


Reply to this email directly or view it on GitHub.

Let's do it first thing in the morning (hangout)

On 26 Mar 2014, at 23:23, Tomek Wytrębowicz notifications@github.com wrote:

There is also a problem with putting well behaved ones into ShadowDOM, as it will break partials that were designed to server multiple nodes on root level, for examples merged output from Polujuice/Launcher.

@Starcounter-Jack I'm afraid we should reconsider changing design once again.


Reply to this email directly or view it on GitHub.

I have an idea how could we solve ShadowDOM issue, add support for <content></content> syntax in our <imported-template> as it works in native <template>. So we could write:

<template is="imported-template">
  <sortable-list order="{{order}}">
    <content></content>
  </sortable-list>
</template>

But i still do not have any idea how to solve iframe detection on client side.

This issue has been solved back in March/April. In result, 2 options are available: