{"action":"created","issue":{"url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/358","labels_url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/358/labels{/name}","comments_url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/358/comments","events_url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/358/events","html_url":"https://github.com/ceylon/ceylon-sdk/issues/358","id":60367586,"number":358,"title":"Simplify ceylon.html's content model enforcement","user":{"login":"jvasileff","id":236050,"avatar_url":"https://avatars.githubusercontent.com/u/236050?v=3","gravatar_id":"","url":"https://api.github.com/users/jvasileff","html_url":"https://github.com/jvasileff","followers_url":"https://api.github.com/users/jvasileff/followers","following_url":"https://api.github.com/users/jvasileff/following{/other_user}","gists_url":"https://api.github.com/users/jvasileff/gists{/gist_id}","starred_url":"https://api.github.com/users/jvasileff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jvasileff/subscriptions","organizations_url":"https://api.github.com/users/jvasileff/orgs","repos_url":"https://api.github.com/users/jvasileff/repos","events_url":"https://api.github.com/users/jvasileff/events{/privacy}","received_events_url":"https://api.github.com/users/jvasileff/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/ceylon/ceylon-sdk/labels/html","name":"html","color":"000000"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-03-09T16:11:44Z","updated_at":"2015-03-09T18:58:17Z","closed_at":null,"body":"`ceylon.html` strictly enforces content models that prevent you from doing stupid things like having a `p` element as a child of a document's `head` element. It does this through a high level organization structure:\r\n\r\n```ceylon\r\ninterface ElementType of BlockElement | InlineElement | TableElement\r\n```\r\n\r\nand also with some special cases, including some nodes that do not satisfy any `ElementType`:\r\n\r\n```ceylon\r\nshared HeadElements=> Title|Meta|Link|Script\r\n```\r\n\r\nI believe, that in practice, the restrictions placed on the content model are heavy-handed, and at times contrary to common practices, even when technically correct.\r\n\r\nBut importantly, many of the restrictions are not correct. The `html5` spec does not include `block` or `inline` elements, but instead defines the following [content categories](http://www.w3.org/TR/html5/dom.html#kinds-of-content):\r\n\r\n* Metadata content\r\n* Flow content\r\n* Sectioning content\r\n* Heading content\r\n* Phrasing content\r\n* Embedded content\r\n* Interactive content\r\n\r\nwith each element belonging to any number of categories, and specifying any number of allowable categories for it's children. And of course, each element may have additional rules or exceptions.\r\n\r\nFurther, the use of `BlockElement` alone (without also including `InlineElement` nodes), seems to contradict the spec (even after taking significant liberties translating the models) as [all `phrasing` content is `flow` content](http://www.w3.org/TR/html5/dom.html#element-definitions):\r\n\r\n> For simplicity, only the most specific expectations are listed. For example, an element that is both flow content and phrasing content can be used anywhere that either flow content or phrasing content is expected, but since anywhere that flow content is expected, phrasing content is also expected (since all phrasing content is flow content), only \"where phrasing content is expected\" will be listed.\r\n\r\n![screen shot 2015-03-09 at 11 42 47 am](https://cloud.githubusercontent.com/assets/236050/6558261/923e35e2-c651-11e4-9c57-7b109d2bf799.png)\r\n\r\nSo the following is valid, but not supported:\r\n\r\n```ceylon\r\nvalue body = Body { B(\"boldedText\") };\r\n// error: {B+} is not assignable to {BlockElement|Null|Script|Snippet<BlockElement>|{BlockElement*}|{Script*}*}\r\n```\r\n\r\nThe spec also defines [`transparent`](http://www.w3.org/TR/html5/dom.html#transparent) content for elements that should derive their content models from their parents. An example of this is the `<a>` tag, for which in `ceylon.html` the following is not currently possible:\r\n\r\n```ceylon\r\nvalue bigLink = A { H1(\"My Heading\") };\r\n// error: {H1+} is not assignable to {InlineElement|{InlineElement*}|Snippet<InlineElement>|Null*}\r\n```\r\n---------------------\r\n\r\nGiven all of the above, I believe that `ceylon.html`s content model should be greatly simplified. While it would be possible to more accurately represent `html5`'s content models in Ceylon's type system, I believe it would require significant effort and provide limited value, and at times, be too restrictive when you need to \"break the rules\".\r\n\r\nA primary change would be for `children`, for nearly all elements, to be defined something like:\r\n\r\n```ceylon\r\nshared formal {<Node|String|{Node|String*}|Snippet|Null>*} children;\r\n```\r\n\r\nwith more strict rules being reserved for very clear and special cases, such as disallowing children for `<script>`.\r\n\r\nI imagine there will be many more implementation questions and concerns, but for now, I'll leave it at that pending discussion on the overall approach."},"comment":{"url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/comments/77919082","html_url":"https://github.com/ceylon/ceylon-sdk/issues/358#issuecomment-77919082","issue_url":"https://api.github.com/repos/ceylon/ceylon-sdk/issues/358","id":77919082,"user":{"login":"lucaswerkmeister","id":2346599,"avatar_url":"https://avatars.githubusercontent.com/u/2346599?v=3","gravatar_id":"","url":"https://api.github.com/users/lucaswerkmeister","html_url":"https://github.com/lucaswerkmeister","followers_url":"https://api.github.com/users/lucaswerkmeister/followers","following_url":"https://api.github.com/users/lucaswerkmeister/following{/other_user}","gists_url":"https://api.github.com/users/lucaswerkmeister/gists{/gist_id}","starred_url":"https://api.github.com/users/lucaswerkmeister/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucaswerkmeister/subscriptions","organizations_url":"https://api.github.com/users/lucaswerkmeister/orgs","repos_url":"https://api.github.com/users/lucaswerkmeister/repos","events_url":"https://api.github.com/users/lucaswerkmeister/events{/privacy}","received_events_url":"https://api.github.com/users/lucaswerkmeister/received_events","type":"User","site_admin":false},"created_at":"2015-03-09T18:58:16Z","updated_at":"2015-03-09T18:58:16Z","body":"> There's no suggestion here that there's something here we can't *correctly* represent within our type system\r\n\r\nI don’t think it’s possible to represent *all* restrictions in the Ceylon type system. `transparent` feels tricky, but it can probably be done with generics. But there’s also [`a`](http://www.w3.org/TR/html5/text-level-semantics.html#the-a-element):\r\n\r\n> Transparent, but there must be no interactive content descendant.\r\n\r\nwhich is essentially complement types (which IIRC would make the type system undecidable), and [`ruby`](http://www.w3.org/TR/html5/text-level-semantics.html#the-ruby-element):\r\n\r\n>  The content model of ruby elements consists of one or more of the following sequences:\r\n> \r\n> 1. One or more phrasing content nodes or `rb` elements.\r\n> 2. One or more `rt` or `rtc` elements, each of which either immediately preceded or followed by an `rp` elements.\r\n\r\nwhich is, even if possible, way too complicated (for instance, the error messages would be horrible)."}}