From 059ec7d628c11a105ea7c2bbad3473933631f82b Mon Sep 17 00:00:00 2001 From: mauricemach Date: Sat, 20 Aug 2011 23:20:13 -0300 Subject: [PATCH] Added missing elements from the HTML 5 spec (both valid and obsolete). Closes #66 (thanks @aeosynth). --- CHANGELOG.md | 1 + docs/coffeekup.html | 78 +++++++++++++++++++++++++------------------- src/coffeekup.coffee | 54 +++++++++++++++++++++--------- 3 files changed, 84 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7904e6b..b5ce5ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ **v0.3.0beta2** (xxxx-xx-xx): - Fixed #64 (`hardcode` option masked in express adapter). [smathy] + - Added missing elements from the HTML 5 spec (both valid and obsolete). Closes #66 (thanks @aeosynth). **v0.3.0beta** (2011-07-27): diff --git a/docs/coffeekup.html b/docs/coffeekup.html index 9f243d0..05bf1b6 100644 --- a/docs/coffeekup.html +++ b/docs/coffeekup.html @@ -42,23 +42,33 @@ for (var i = 0, l = this.length; i < l; i++) { if (this[i] === item) return i; } return -1; }; -""".replace /\n/g, ''

All possible HTML tags, from all versions (hopefully). But only those -referenced in the template will be included in the compiled function.

coffeekup.tags = 'a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont
-|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup
-|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption
-|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr
-|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta
-|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre
-|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike
-|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title
-|tr|tt|u|ul|video|xmp'.replace(/\n/g, '').split '|'
-
-coffeekup.self_closing = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr',
-  'img', 'input', 'link', 'meta', 'param']

This is the basic material from which compiled templates will be formed. +""".replace /\n/g, ''

Private HTML element reference. +Please mind the gap (1 space at the beginning of each subsequent line).

elements =

Valid HTML 5 elements requiring a closing tag. +Note: the var element is out for obvious reasons, please use tag 'var'.

  regular: 'a abbr address article aside audio b bdi bdo blockquote body button
+ canvas caption cite code colgroup datalist dd del details dfn div dl dt em
+ fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup
+ html i iframe ins kbd label legend li map mark menu meter nav noscript object
+ ol optgroup option output p pre progress q rp rt ruby s samp script section
+ select small span strong style sub summary sup table tbody td textarea tfoot
+ th thead time title tr u ul video'

Valid self-closing HTML 5 elements.

  void: 'area base br col command embed hr img input keygen link meta param
+ source track wbr'
+
+  obsolete: 'applet acronym bgsound dir frameset noframes isindex listing
+ nextid noembed plaintext rb strike xmp big blink center font marquee multicol
+ nobr spacer tt'
+
+  obsolete_void: 'basefont frame'

Create a unique list of element names merging the desired groups.

merge_elements = (args...) ->
+  result = []
+  for a in args
+    for element in elements[a].split ' '
+      result.push element unless result.indexOf(element) > -1
+  result

Public/customizable list of possible elements. +For each name in this list that is also present in the input template code, +a function with the same name will be added to the compiled template.

coffeekup.tags = merge_elements 'regular', 'obsolete', 'void', 'obsolete_void'

Public/customizable list of elements that should be rendered self-closed.

coffeekup.self_closing = merge_elements 'void', 'obsolete_void'

This is the basic material from which compiled templates will be formed. It will be manipulated in its string form at the coffeekup.compile function -to generate the final template function.

skeleton = (data = {}) ->

Whether to generate formatted HTML with indentation and line breaks, or -just the natural "faux-minified" output.

  data.format ?= off

Whether to autoescape all content or let you handle it on a case by case -basis with the h function.

  data.autoescape ?= off

Internal CoffeeKup stuff.

  __ck =
+to generate the final template function. 

skeleton = (data = {}) ->

Whether to generate formatted HTML with indentation and line breaks, or +just the natural "faux-minified" output.

  data.format ?= off

Whether to autoescape all content or let you handle it on a case by case +basis with the h function.

  data.autoescape ?= off

Internal CoffeeKup stuff.

  __ck =
     buffer: []
       
     esc: (txt) ->
@@ -68,7 +78,7 @@
 
     repeat: (string, count) -> Array(count + 1).join string
 
-    indent: -> text @repeat('  ', @tabs) if data.format

Adapter to keep the builtin tag functions DRY.

    tag: (name, args) ->
+    indent: -> text @repeat('  ', @tabs) if data.format

Adapter to keep the builtin tag functions DRY.

    tag: (name, args) ->
       combo = [name]
       combo.push i for i in args
       tag.apply data, combo
@@ -92,8 +102,8 @@
         text '"'
 
     render_attrs: (obj) ->
-      for k, v of obj

true is rendered as selected="selected".

        if typeof v is 'boolean' and v
-          v = k

undefined, false and null result in the attribute not being rendered.

        if v

strings, numbers, objects, arrays and functions are rendered "as is".

          text " #{k}=\"#{@esc(v)}\""
+      for k, v of obj

true is rendered as selected="selected".

        if typeof v is 'boolean' and v
+          v = k

undefined, false and null result in the attribute not being rendered.

        if v

strings, numbers, objects, arrays and functions are rendered "as is".

          text " #{k}=\"#{@esc(v)}\""
 
     render_contents: (contents) ->
       switch typeof contents
@@ -169,15 +179,15 @@
     text '\n' if data.format
   
   coffeescript = (param) ->
-    switch typeof param

coffeescript -> alert 'hi' becomes: + switch typeof param

coffeescript -> alert 'hi' becomes: <script>;(function () {return alert('hi');})();</script>

      when 'function'
-        script "#{__ck.coffeescript_helpers}(#{param}).call(this);"

coffeescript "alert 'hi'" becomes: + script "#{__ck.coffeescript_helpers}(#{param}).call(this);"

coffeescript "alert 'hi'" becomes: <script type="text/coffeescript">alert 'hi'</script>

      when 'string'
-        script type: 'text/coffeescript', -> param

coffeescript src: 'script.coffee' becomes: + script type: 'text/coffeescript', -> param

coffeescript src: 'script.coffee' becomes: <script type="text/coffeescript" src="script.coffee"></script>

      when 'object'
         param.type = 'text/coffeescript'
         script param
-  

Conditional IE comments.

  ie = (condition, contents) ->
+  

Conditional IE comments.

  ie = (condition, contents) ->
     __ck.indent()
     
     text "<!--[if #{condition}]>"
@@ -185,23 +195,23 @@
     text "<![endif]-->"
     text '\n' if data.format
 
-  null

Stringify the skeleton and unwrap it from its enclosing function(){}, then + null

Stringify the skeleton and unwrap it from its enclosing function(){}, then add the CoffeeScript helpers.

skeleton = String(skeleton)
   .replace(/function\s*\(.*\)\s*\{/, '')
   .replace(/return null;\s*\}$/, '')
 
-skeleton = coffeescript_helpers + skeleton

Compiles a template into a standalone JavaScript function.

coffeekup.compile = (template, options = {}) ->

The template can be provided as either a function or a CoffeeScript string +skeleton = coffeescript_helpers + skeleton

Compiles a template into a standalone JavaScript function.

coffeekup.compile = (template, options = {}) ->

The template can be provided as either a function or a CoffeeScript string (in the latter case, the CoffeeScript compiler must be available).

  if typeof template is 'function' then template = String(template)
   else if typeof template is 'string' and coffee?
     template = coffee.compile template, bare: yes
-    template = "function(){#{template}}"

If an object hardcode is provided, insert the stringified value + template = "function(){#{template}}"

If an object hardcode is provided, insert the stringified value of each variable directly in the function body. This is a less flexible but faster alternative to the standard method of using with (see below).

  hardcoded_locals = ''
   
   if options.hardcode
     for k, v of options.hardcode
-      if typeof v is 'function'

Make sure these functions have access to data as @/this.

        hardcoded_locals += "var #{k} = function(){return (#{v}).apply(data, arguments);};"
-      else hardcoded_locals += "var #{k} = #{JSON.stringify v};"

Add a function for each tag this template references. We don't want to have + if typeof v is 'function'

Make sure these functions have access to data as @/this.

        hardcoded_locals += "var #{k} = function(){return (#{v}).apply(data, arguments);};"
+      else hardcoded_locals += "var #{k} = #{JSON.stringify v};"

Add a function for each tag this template references. We don't want to have all hundred-odd tags wasting space in the compiled function.

  tag_functions = ''
   tags_used = []
   
@@ -211,19 +221,19 @@
       
   tag_functions += "var #{tags_used.join ','};"
   for t in tags_used
-    tag_functions += "#{t} = function(){return __ck.tag('#{t}', arguments);};"

Main function assembly.

  code = tag_functions + hardcoded_locals + skeleton
+    tag_functions += "#{t} = function(){return __ck.tag('#{t}', arguments);};"

Main function assembly.

  code = tag_functions + hardcoded_locals + skeleton
 
   code += "__ck.doctypes = #{JSON.stringify coffeekup.doctypes};"
   code += "__ck.coffeescript_helpers = #{JSON.stringify coffeescript_helpers};"
-  code += "__ck.self_closing = #{JSON.stringify coffeekup.self_closing};"

If locals is set, wrap the template inside a with block. This is the + code += "__ck.self_closing = #{JSON.stringify coffeekup.self_closing};"

If locals is set, wrap the template inside a with block. This is the most flexible but slower approach to specifying local variables.

  code += 'with(data.locals){' if options.locals
   code += "(#{template}).call(data);"
   code += '}' if options.locals
   code += "return __ck.buffer.join('');"
-
+  
   new Function('data', code)
 
-cache = {}

Template in, HTML out. Accepts functions or strings as does coffeekup.compile.

+cache = {}

Template in, HTML out. Accepts functions or strings as does coffeekup.compile.

Accepts an option cache, by default false. If set to false templates will be recompiled each time.

@@ -241,9 +251,9 @@ tpl(data) unless window? - coffeekup.adapters =

Legacy adapters for when CoffeeKup expected data in the context attribute.

    simple: coffeekup.render
+  coffeekup.adapters =

Legacy adapters for when CoffeeKup expected data in the context attribute.

    simple: coffeekup.render
     meryl: coffeekup.render
-    

Allows partial 'foo' instead of text @partial 'foo'.

    express:
+    

Allows partial 'foo' instead of text @partial 'foo'.

    express:
       compile: (template, data) -> 
         data.hardcode ?= {}
         data.hardcode.partial = ->
diff --git a/src/coffeekup.coffee b/src/coffeekup.coffee
index 422ce6f..96cdb67 100644
--- a/src/coffeekup.coffee
+++ b/src/coffeekup.coffee
@@ -52,20 +52,44 @@ coffeescript_helpers = """
     } return -1; };
 """.replace /\n/g, ''
 
-# All possible HTML tags, from all versions (hopefully). But only those
-# referenced in the template will be included in the compiled function.
-coffeekup.tags = 'a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont
-|bdo|big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup
-|command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|figcaption
-|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr
-|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|link|map|mark|menu|meta
-|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre
-|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strike
-|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title
-|tr|tt|u|ul|video|xmp'.replace(/\n/g, '').split '|'
-
-coffeekup.self_closing = ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr',
-  'img', 'input', 'link', 'meta', 'param']
+# Private HTML element reference.
+# Please mind the gap (1 space at the beginning of each subsequent line).
+elements =
+  # Valid HTML 5 elements requiring a closing tag.
+  # Note: the `var` element is out for obvious reasons, please use `tag 'var'`.
+  regular: 'a abbr address article aside audio b bdi bdo blockquote body button
+ canvas caption cite code colgroup datalist dd del details dfn div dl dt em
+ fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup
+ html i iframe ins kbd label legend li map mark menu meter nav noscript object
+ ol optgroup option output p pre progress q rp rt ruby s samp script section
+ select small span strong style sub summary sup table tbody td textarea tfoot
+ th thead time title tr u ul video'
+
+  # Valid self-closing HTML 5 elements.
+  void: 'area base br col command embed hr img input keygen link meta param
+ source track wbr'
+
+  obsolete: 'applet acronym bgsound dir frameset noframes isindex listing
+ nextid noembed plaintext rb strike xmp big blink center font marquee multicol
+ nobr spacer tt'
+
+  obsolete_void: 'basefont frame'
+
+# Create a unique list of element names merging the desired groups.
+merge_elements = (args...) ->
+  result = []
+  for a in args
+    for element in elements[a].split ' '
+      result.push element unless result.indexOf(element) > -1
+  result
+
+# Public/customizable list of possible elements.
+# For each name in this list that is also present in the input template code,
+# a function with the same name will be added to the compiled template.
+coffeekup.tags = merge_elements 'regular', 'obsolete', 'void', 'obsolete_void'
+
+# Public/customizable list of elements that should be rendered self-closed.
+coffeekup.self_closing = merge_elements 'void', 'obsolete_void'
 
 # This is the basic material from which compiled templates will be formed.
 # It will be manipulated in its string form at the `coffeekup.compile` function
@@ -281,7 +305,7 @@ coffeekup.compile = (template, options = {}) ->
   code += "(#{template}).call(data);"
   code += '}' if options.locals
   code += "return __ck.buffer.join('');"
-
+  
   new Function('data', code)
 
 cache = {}