{"action":"created","comment":{"url":"https://api.github.com/repos/emberjs/rfcs/pulls/comments/25543654","id":25543654,"diff_hunk":"@@ -0,0 +1,198 @@\n+- Start Date: 2015-02-27\n+- RFC PR:\n+- Ember Issue:\n+\n+# Summary\n+\n+Introduce `Ember.Fragment` and the `<element>` and `<fragment>`\n+template keywords.\n+\n+# Motivation\n+\n+This RFC addresses two key problems:\n+\n+ - Ember has no clear concept of a \"tagless component\". We need such a\n+   concept now that we're moving to a component-centric world.\n+\n+ - Today users are forced to learn two separate APIs for setting\n+   element attributes, one that works only for a component's top-level\n+   element (and cannot be used from inside templates), and one that\n+   works everywhere else.\n+\n+# Detailed design\n+\n+`Ember.Fragment` is introduced to represent \"tagless\n+components\". Every Fragment's template must be defined with the\n+`<fragment>` keyword.\n+\n+`Ember.Component` continues to *only* represent components with\n+tags. This is consistent with a web-component world. Every Component's\n+template **must** be defined with the `<element>` keyword.\n+\n+## `<element>` semantics by example\n+\n+If you place this template in `my-component.hbs`:\n+\n+````handlebars\n+<element class=\"special {{class}}\" data-my-id={{id}}>\n+  Hello {{name}}.\n+</element>\n+````\n+\n+It can be invoked like this:\n+\n+````handlebars\n+<my-component id=1 name=\"Tomster\" class=\"magical\">\n+````\n+\n+And will result in this output:\n+\n+````html\n+<div class=\"special magical\" data-my-id=\"1\">\n+  Hello Tomster.\n+</div>\n+````\n+\n+`<element>` accepts an optional `tagName`, so if we changed the\n+template to:\n+\n+````handlebars\n+<element class=\"special {{class}}\" data-my-id={{id}} tagName=\"span\">\n+  Hello {{name}}.\n+</element>\n+````\n+\n+The output changes to\n+\n+````html\n+<span clas=\"special magical\" data-my-id=\"1\">\n+  Hello Tomster.\n+</span>\n+````\n+\n+## `<fragment>` semantics\n+\n+`<fragment>` is very simple, it just declares that your template is a\n+fragment and not a component. It doesn't generate any output in the\n+DOM and it doesn't take any arguments. This:\n+\n+````handlebars\n+<fragment>\n+  This is a fragment.\n+</fragment>\n+````\n+\n+Outputs:\n+\n+````html\n+This is a fragment.\n+````\n+\n+## Invoking Components and Fragments\n+\n+Components in Ember 2.0 can be invoked with angle bracket syntax:\n+\n+````handlebars\n+<my-component>Hola</my-component>\n+````\n+\n+But fragments are always invoked with curlies:\n+\n+````handlebars\n+{{my-fragment}}Hola{{/my-fragment}}\n+````\n+\n+This lets the reader of a template know exactly what they're dealing\n+with.\n+\n+## What happens to `attributeBindings`, `classNames` and `classNameBindings`\n+\n+In the vast majority of cases, users won't need these anymore, and\n+will be able to get the same control directly from their template\n+using `<element>`.\n+\n+However, we will still keep them to handle trickier inheritance\n+situations, where a base class or mixin needs to control element\n+attributes in all derived classes. Only library authors are likely to\n+need to know about them, and most users should be steered toward using\n+`<element>` instead.\n+\n+We can also put:\n+\n+````js\n+  attributeBindings: ['tagName', 'class']\n+````\n+in the base `Component` implementation so that these properties will\n+propagate from the caller to the `<element>` by default.\n+\n+Any attributes set directly on `<element>` in a component's definition\n+**take precedence over** `attributeBindings`. We make a special\n+exception for `class`: `classNameBindings` and `classNames` will be\n+merged with any value for `class` provided on the `<element>`. \n+\n+## Fragment names\n+\n+Components need a dash for compatibility with web components. But this\n+constraint does not apply to fragments, so fragment's names **do not**\n+need to include a dash.\n+\n+\n+## Why are `<element>` and `<fragment>` mandatory?\n+\n+If we want to distinguish between Component templates and Fragment\n+templates, at least one of them needs to be mandatory. It makes sense\n+for `<element>` to be the mandatory one, since `<element>` does useful\n+work and represents a real DOM element.\n+\n+`<fragment>` is only needed due to upgrade-compatibility\n+concerns. Some day we'll be able to treat any component without an\n+`<element>` as a Fragment by default, but right now that would alter\n+the behavior of existing components.\n+\n+Therefore, templates with neither `<element>` nor `<fragment>` will\n+receive legacy behavior.\n+\n+## Ember.Component and Ember.Fragment classes\n+\n+Components must extend `Ember.Component`, the same as today.\n+\n+Fragments must extend `Ember.Fragment`.\n+\n+Mismatching the class and the template will throw an exception at\n+instantiation.\n+\n+`Ember.Fragment` is probably an ancestor of `Ember.Component`, so that\n+it can define behaviors common to both.\n+\n+# Drawbacks\n+\n+Adds a tiny amount of arguable boilerplate to templates that was not\n+there before.\n+\n+This proposal doesn't eliminate `attributeBindings`,\n+`classNameBindings`, and `classNames`. I think it would be a good idea\n+to eliminate them, but we need a detailed design for some other way to\n+do inheritance -- one idea would be template macro expansion.\n+\n+# Alternatives\n+\n+Instead of `<element>`, components could just use their own real tag\n+in its place. But this makes it hard to distinguish template\n+definition from template invocation.\n+\n+We could avoid introducing `<fragment>` and treat any template without\n+an `<element>` as a fragment, but this makes the upgrade painful.\n+\n+We could detect whether a template has a single top-level element or\n+not and automatically make it by a Component or Fragment. This idea\n+was rejected because it's a footgun -- for example, accidentally\n+changing your template from one kind to the other would change the\n+sematnics of your `$` method.\n+\n+# Unresolved questions\n+\n+ - Should `Ember.Component` extend `Ember.Fragment`?\n+\n+ - Should `Ember.Fragment` have a `$` method that matches its DOM","path":"active/0000-element-and-fragment.md","position":196,"original_position":196,"commit_id":"1bede8dd12b04ee7f9fb36c854efe8ed2723d022","original_commit_id":"1bede8dd12b04ee7f9fb36c854efe8ed2723d022","user":{"login":"stefanpenner","id":1377,"avatar_url":"https://avatars.githubusercontent.com/u/1377?v=3","gravatar_id":"","url":"https://api.github.com/users/stefanpenner","html_url":"https://github.com/stefanpenner","followers_url":"https://api.github.com/users/stefanpenner/followers","following_url":"https://api.github.com/users/stefanpenner/following{/other_user}","gists_url":"https://api.github.com/users/stefanpenner/gists{/gist_id}","starred_url":"https://api.github.com/users/stefanpenner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stefanpenner/subscriptions","organizations_url":"https://api.github.com/users/stefanpenner/orgs","repos_url":"https://api.github.com/users/stefanpenner/repos","events_url":"https://api.github.com/users/stefanpenner/events{/privacy}","received_events_url":"https://api.github.com/users/stefanpenner/received_events","type":"User","site_admin":false},"body":"as its dom range is dynamic, I don't believe so. Imagine the following scenario, `this.$()` can easily become stale, and we have to mechanism by which to update it.\r\n\r\n```hbs\r\n<fragment>\r\n  <h1>asdf</h1>\r\n  {{#if theSkyIsFalling}}\r\n    <p>Run!!</p>\r\n  {{/if}}\r\n</fragment>\r\n```","created_at":"2015-02-27T22:18:59Z","updated_at":"2015-02-27T22:18:59Z","html_url":"https://github.com/emberjs/rfcs/pull/37#discussion_r25543654","pull_request_url":"https://api.github.com/repos/emberjs/rfcs/pulls/37","_links":{"self":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/comments/25543654"},"html":{"href":"https://github.com/emberjs/rfcs/pull/37#discussion_r25543654"},"pull_request":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/37"}}},"pull_request":{"url":"https://api.github.com/repos/emberjs/rfcs/pulls/37","id":30198370,"html_url":"https://github.com/emberjs/rfcs/pull/37","diff_url":"https://github.com/emberjs/rfcs/pull/37.diff","patch_url":"https://github.com/emberjs/rfcs/pull/37.patch","issue_url":"https://api.github.com/repos/emberjs/rfcs/issues/37","number":37,"state":"open","locked":false,"title":"Element and Fragment RFC","user":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"body":"[RFC](https://github.com/ef4/rfcs/blob/element-and-fragment/active/0000-element-and-fragment.md)","created_at":"2015-02-27T20:31:56Z","updated_at":"2015-02-27T22:18:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b831281bdf8e5572a9e5479f6af1a4e55dcbcd89","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/emberjs/rfcs/pulls/37/commits","review_comments_url":"https://api.github.com/repos/emberjs/rfcs/pulls/37/comments","review_comment_url":"https://api.github.com/repos/emberjs/rfcs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/emberjs/rfcs/issues/37/comments","statuses_url":"https://api.github.com/repos/emberjs/rfcs/statuses/1bede8dd12b04ee7f9fb36c854efe8ed2723d022","head":{"label":"ef4:element-and-fragment","ref":"element-and-fragment","sha":"1bede8dd12b04ee7f9fb36c854efe8ed2723d022","user":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"repo":{"id":31437820,"name":"rfcs","full_name":"ef4/rfcs","owner":{"login":"ef4","id":319282,"avatar_url":"https://avatars.githubusercontent.com/u/319282?v=3","gravatar_id":"","url":"https://api.github.com/users/ef4","html_url":"https://github.com/ef4","followers_url":"https://api.github.com/users/ef4/followers","following_url":"https://api.github.com/users/ef4/following{/other_user}","gists_url":"https://api.github.com/users/ef4/gists{/gist_id}","starred_url":"https://api.github.com/users/ef4/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ef4/subscriptions","organizations_url":"https://api.github.com/users/ef4/orgs","repos_url":"https://api.github.com/users/ef4/repos","events_url":"https://api.github.com/users/ef4/events{/privacy}","received_events_url":"https://api.github.com/users/ef4/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ef4/rfcs","description":"RFCs for changes to Ember","fork":true,"url":"https://api.github.com/repos/ef4/rfcs","forks_url":"https://api.github.com/repos/ef4/rfcs/forks","keys_url":"https://api.github.com/repos/ef4/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ef4/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ef4/rfcs/teams","hooks_url":"https://api.github.com/repos/ef4/rfcs/hooks","issue_events_url":"https://api.github.com/repos/ef4/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/ef4/rfcs/events","assignees_url":"https://api.github.com/repos/ef4/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/ef4/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/ef4/rfcs/tags","blobs_url":"https://api.github.com/repos/ef4/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ef4/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ef4/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/ef4/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ef4/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/ef4/rfcs/languages","stargazers_url":"https://api.github.com/repos/ef4/rfcs/stargazers","contributors_url":"https://api.github.com/repos/ef4/rfcs/contributors","subscribers_url":"https://api.github.com/repos/ef4/rfcs/subscribers","subscription_url":"https://api.github.com/repos/ef4/rfcs/subscription","commits_url":"https://api.github.com/repos/ef4/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/ef4/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/ef4/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/ef4/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/ef4/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/ef4/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ef4/rfcs/merges","archive_url":"https://api.github.com/repos/ef4/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ef4/rfcs/downloads","issues_url":"https://api.github.com/repos/ef4/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/ef4/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/ef4/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/ef4/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ef4/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/ef4/rfcs/releases{/id}","created_at":"2015-02-27T20:30:08Z","updated_at":"2015-02-27T07:10:03Z","pushed_at":"2015-02-27T20:30:35Z","git_url":"git://github.com/ef4/rfcs.git","ssh_url":"git@github.com:ef4/rfcs.git","clone_url":"https://github.com/ef4/rfcs.git","svn_url":"https://github.com/ef4/rfcs","homepage":null,"size":776,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"emberjs:master","ref":"master","sha":"a3cc226c73fdf9b29d74e85299c16388d3064729","user":{"login":"emberjs","id":1253363,"avatar_url":"https://avatars.githubusercontent.com/u/1253363?v=3","gravatar_id":"","url":"https://api.github.com/users/emberjs","html_url":"https://github.com/emberjs","followers_url":"https://api.github.com/users/emberjs/followers","following_url":"https://api.github.com/users/emberjs/following{/other_user}","gists_url":"https://api.github.com/users/emberjs/gists{/gist_id}","starred_url":"https://api.github.com/users/emberjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emberjs/subscriptions","organizations_url":"https://api.github.com/users/emberjs/orgs","repos_url":"https://api.github.com/users/emberjs/repos","events_url":"https://api.github.com/users/emberjs/events{/privacy}","received_events_url":"https://api.github.com/users/emberjs/received_events","type":"Organization","site_admin":false},"repo":{"id":22664562,"name":"rfcs","full_name":"emberjs/rfcs","owner":{"login":"emberjs","id":1253363,"avatar_url":"https://avatars.githubusercontent.com/u/1253363?v=3","gravatar_id":"","url":"https://api.github.com/users/emberjs","html_url":"https://github.com/emberjs","followers_url":"https://api.github.com/users/emberjs/followers","following_url":"https://api.github.com/users/emberjs/following{/other_user}","gists_url":"https://api.github.com/users/emberjs/gists{/gist_id}","starred_url":"https://api.github.com/users/emberjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emberjs/subscriptions","organizations_url":"https://api.github.com/users/emberjs/orgs","repos_url":"https://api.github.com/users/emberjs/repos","events_url":"https://api.github.com/users/emberjs/events{/privacy}","received_events_url":"https://api.github.com/users/emberjs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/emberjs/rfcs","description":"RFCs for changes to Ember","fork":false,"url":"https://api.github.com/repos/emberjs/rfcs","forks_url":"https://api.github.com/repos/emberjs/rfcs/forks","keys_url":"https://api.github.com/repos/emberjs/rfcs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/emberjs/rfcs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/emberjs/rfcs/teams","hooks_url":"https://api.github.com/repos/emberjs/rfcs/hooks","issue_events_url":"https://api.github.com/repos/emberjs/rfcs/issues/events{/number}","events_url":"https://api.github.com/repos/emberjs/rfcs/events","assignees_url":"https://api.github.com/repos/emberjs/rfcs/assignees{/user}","branches_url":"https://api.github.com/repos/emberjs/rfcs/branches{/branch}","tags_url":"https://api.github.com/repos/emberjs/rfcs/tags","blobs_url":"https://api.github.com/repos/emberjs/rfcs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/emberjs/rfcs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/emberjs/rfcs/git/refs{/sha}","trees_url":"https://api.github.com/repos/emberjs/rfcs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/emberjs/rfcs/statuses/{sha}","languages_url":"https://api.github.com/repos/emberjs/rfcs/languages","stargazers_url":"https://api.github.com/repos/emberjs/rfcs/stargazers","contributors_url":"https://api.github.com/repos/emberjs/rfcs/contributors","subscribers_url":"https://api.github.com/repos/emberjs/rfcs/subscribers","subscription_url":"https://api.github.com/repos/emberjs/rfcs/subscription","commits_url":"https://api.github.com/repos/emberjs/rfcs/commits{/sha}","git_commits_url":"https://api.github.com/repos/emberjs/rfcs/git/commits{/sha}","comments_url":"https://api.github.com/repos/emberjs/rfcs/comments{/number}","issue_comment_url":"https://api.github.com/repos/emberjs/rfcs/issues/comments{/number}","contents_url":"https://api.github.com/repos/emberjs/rfcs/contents/{+path}","compare_url":"https://api.github.com/repos/emberjs/rfcs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/emberjs/rfcs/merges","archive_url":"https://api.github.com/repos/emberjs/rfcs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/emberjs/rfcs/downloads","issues_url":"https://api.github.com/repos/emberjs/rfcs/issues{/number}","pulls_url":"https://api.github.com/repos/emberjs/rfcs/pulls{/number}","milestones_url":"https://api.github.com/repos/emberjs/rfcs/milestones{/number}","notifications_url":"https://api.github.com/repos/emberjs/rfcs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/emberjs/rfcs/labels{/name}","releases_url":"https://api.github.com/repos/emberjs/rfcs/releases{/id}","created_at":"2014-08-06T00:49:22Z","updated_at":"2015-02-27T07:10:03Z","pushed_at":"2015-02-05T08:10:43Z","git_url":"git://github.com/emberjs/rfcs.git","ssh_url":"git@github.com:emberjs/rfcs.git","clone_url":"https://github.com/emberjs/rfcs.git","svn_url":"https://github.com/emberjs/rfcs","homepage":null,"size":776,"stargazers_count":222,"watchers_count":222,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":36,"mirror_url":null,"open_issues_count":24,"forks":36,"open_issues":24,"watchers":222,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/37"},"html":{"href":"https://github.com/emberjs/rfcs/pull/37"},"issue":{"href":"https://api.github.com/repos/emberjs/rfcs/issues/37"},"comments":{"href":"https://api.github.com/repos/emberjs/rfcs/issues/37/comments"},"review_comments":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/37/comments"},"review_comment":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/emberjs/rfcs/pulls/37/commits"},"statuses":{"href":"https://api.github.com/repos/emberjs/rfcs/statuses/1bede8dd12b04ee7f9fb36c854efe8ed2723d022"}}}}