Skip to content

Commit

Permalink
added support for SVG 1.1 tags (see mauricemach#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
flosse committed Jan 25, 2012
1 parent c87c3ee commit 07ffa72
Showing 1 changed file with 45 additions and 31 deletions.
76 changes: 45 additions & 31 deletions src/coffeekup.coffee
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# **CoffeeKup** lets you to write HTML templates in 100% pure
# [CoffeeScript](http://coffeescript.org).
#
#
# You can run it on [node.js](http://nodejs.org) or the browser, or compile your
# templates down to self-contained javascript functions, that will take in data
# and options and return generated HTML on any JS runtime.
#
#
# The concept is directly stolen from the amazing
# [Markaby](http://markaby.rubyforge.org/) by Tim Fletcher and why the lucky
# stiff.
Expand Down Expand Up @@ -65,6 +65,19 @@ elements =
select small span strong style sub summary sup table tbody td textarea tfoot
th thead time title tr u ul video'

# Support for SVG 1.1 tags
svg: 'a altGlyph altGlyphDef altGlyphItem animate animateColor animateMotion
animateTransform circle clipPath color-profile cursor defs desc ellipse
feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix
feDiffuseLighting feDisplacementMap feDistantLight feFlood feFuncA feFuncB
feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology
feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence
filter font font-face font-face-format font-face-name font-face-src
font-face-uri foreignObject g glyph glyphRef hkern image line linearGradient
marker mask metadata missing-glyph mpath path pattern polygon polyline
radialGradient rect script set stop style svg switch symbol text textPath
title tref tspan use view vkern'

# Valid self-closing HTML 5 elements.
void: 'area base br col command embed hr img input keygen link meta param
source track wbr'
Expand All @@ -86,14 +99,15 @@ merge_elements = (args...) ->
# 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'
coffeekup.tags = merge_elements 'regular', 'obsolete', 'void', 'obsolete_void',
'svg'

# 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.
# 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.
Expand All @@ -106,7 +120,7 @@ skeleton = (data = {}) ->
# Internal CoffeeKup stuff.
__ck =
buffer: []

esc: (txt) ->
if data.autoescape then h(txt) else String(txt)

Expand All @@ -124,15 +138,15 @@ skeleton = (data = {}) ->

render_idclass: (str) ->
classes = []

for i in str.split '.'
if '#' in i
id = i.replace '#', ''
else
classes.push i unless i is ''

text " id=\"#{id}\"" if id

if classes.length > 0
text " class=\""
for c in classes
Expand All @@ -144,7 +158,7 @@ skeleton = (data = {}) ->
for k, v of obj
# `true` is rendered as `selected="selected"`.
v = k if typeof v is 'boolean' and v

# Functions are rendered in an executable form.
v = "(#{v}).call(this);" if typeof v is 'function'

Expand Down Expand Up @@ -174,22 +188,22 @@ skeleton = (data = {}) ->

render_tag: (name, idclass, attrs, contents) ->
@indent()

text "<#{name}"
@render_idclass(idclass) if idclass
@render_attrs(attrs) if attrs

if name in @self_closing
text ' />'
text '\n' if data.format
else
text '>'

@render_contents(contents)

text "</#{name}>"
text '\n' if data.format

null

tag = (name, args...) ->
Expand Down Expand Up @@ -225,19 +239,19 @@ skeleton = (data = {}) ->
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')

doctype = (type = 'default') ->
text __ck.doctypes[type]
text '\n' if data.format

text = (txt) ->
__ck.buffer.push String(txt)
null

comment = (cmt) ->
text "<!--#{cmt}-->"
text '\n' if data.format

coffeescript = (param) ->
switch typeof param
# `coffeescript -> alert 'hi'` becomes:
Expand All @@ -253,11 +267,11 @@ skeleton = (data = {}) ->
when 'object'
param.type = 'text/coffeescript'
script param

# Conditional IE comments.
ie = (condition, contents) ->
__ck.indent()

text "<!--[if #{condition}]>"
__ck.render_contents(contents)
text "<![endif]-->"
Expand All @@ -284,9 +298,9 @@ coffeekup.compile = (template, options = {}) ->

# 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).
# 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'
Expand All @@ -298,11 +312,11 @@ coffeekup.compile = (template, options = {}) ->
# all hundred-odd tags wasting space in the compiled function.
tag_functions = ''
tags_used = []

for t in coffeekup.tags
if template.indexOf(t) > -1 or hardcoded_locals.indexOf(t) > -1
tags_used.push t

tag_functions += "var #{tags_used.join ','};"
for t in tags_used
tag_functions += "#{t} = function(){return __ck.tag('#{t}', arguments);};"
Expand All @@ -320,16 +334,16 @@ coffeekup.compile = (template, options = {}) ->
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`.
#
#
# Accepts an option `cache`, by default `false`. If set to `false` templates will
# be recompiled each time.
#
#
# `options` is just a convenience parameter to pass options separately from the
# data, but the two will be merged and passed down to the compiler (which uses
# `locals` and `hardcode`), and the template (which understands `locals`, `format`
Expand All @@ -348,24 +362,24 @@ unless window?
# Legacy adapters for when CoffeeKup expected data in the `context` attribute.
simple: coffeekup.render
meryl: coffeekup.render

express:
TemplateError: class extends Error
constructor: (@message) ->
Error.call this, @message
Error.captureStackTrace this, arguments.callee
name: 'TemplateError'
compile: (template, data) ->

compile: (template, data) ->
# Allows `partial 'foo'` instead of `text @partial 'foo'`.
data.hardcode ?= {}
data.hardcode.partial = ->
text @partial.apply @, arguments

TemplateError = @TemplateError
try tpl = coffeekup.compile(template, data)
catch e then throw new TemplateError "Error compiling #{data.filename}: #{e.message}"

return ->
try tpl arguments...
catch e then throw new TemplateError "Error rendering #{data.filename}: #{e.message}"
catch e then throw new TemplateError "Error rendering #{data.filename}: #{e.message}"

0 comments on commit 07ffa72

Please sign in to comment.