secret
Last active

html_helpers for hamlc

  • Download Gist
gistfile1.coffee
CoffeeScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
# HTML Tag class
#
# Purpose: Programmatically generate HTML so you aren't scotch-taping
# strings together all the time.
#
# Usage: targetString = Tag.make(tagName, attributeHash, text)
#
# Where: targetString: is what you will eventually inject into the DOM -- the HTML
# tagName: is the actual tag name (i.e., "tr" or "input")
# attributeHash: is the set of tag attributes, for example --
# class: "even-row", id: "row#{indexVar}", title: "Yo, Dog!"
# Note that repeating hash keys is a BAD idea. so:
# class: "even-row", class: "zebra-stripe"
# will not do what you expect. It works on the "last one wins"
# principle. Instead, use:
# class: "even-row zebra-stripe"
# text: is the text enclosed in the tag. If it is a self-closing
# tag like img or input, then leave the text empty.
 
class Tag
@make: (tagName, attributes, text...) ->
t = new Tag
t.name = tagName
t.attributes = attributes
t.text = ''
t.text = text.join('')
t
 
openTag: ->
attributeStrings = []
close = null
unless @text
close = ' />'
else
close = '>'
 
attributeStrings.push("#{key}=\"#{attribute}\"") for key, attribute of @attributes when key != 'text'
attributeString = if attributeStrings.length > 0 then ' ' + attributeStrings.join(' ') else ''
 
"<#{@name}#{attributeString}#{close}"
 
closeTag: (name) ->
"</#{@name}>"
 
tag: ->
parts = [@openTag()]
parts.push @text
parts.push @closeTag() if @text.length > 0
parts.join('')
toString: ->
@tag()
 
@HtmlHelpers =
linkTo: (name, href, options = {}) ->
options['href'] ||= href
Tag.make('a', options, name).toString()
 
textFieldTag: (name, value = "", options = {}) ->
options['type'] = 'text'
options['name'] = name
options['value'] = value
Tag.make('input', options, null).toString()
 
passwordFieldTag: (name, value = "", options = {}) ->
options['type'] = 'password'
options['name'] = name
options['value'] = value
Tag.make('input', options, null).toString()
 
textArea: (name, options = {}) ->
options['name'] = name
Tag.make('textarea', options).toString()
 
fileFieldTag: (name, options = {}) ->
options['name'] = name
options['type'] = 'file'
Tag.make('input', options).toString()
 
select: (name, collection = [], options = {}) ->
options['name'] = name
selectBody = []
selectBody.push Tag.make('option', {}, null) if options.include_blank?
for opt in collection
if opt instanceof Array
body = opt[0]
value = opt[1]
else
body = opt
value = opt
selectOptions = {}
selectOptions['value'] = value
selectOptions['selected'] = 'selected' if options['selected'] && options['selected'].toString() == value.toString()
selectBody.push Tag.make('option', selectOptions, body)
tagOptions = _.clone(options)
_.map ['selected', 'collection', 'as'], (key) -> delete tagOptions[key]
Tag.make('select', tagOptions, selectBody.join('')).toString()
 
checkBoxTag: (name, value = 1, checked = false, options = {}) ->
options['type'] = 'checkbox'
options['name'] = name
options['id'] ||= name
options['value'] = value
if checked
options['checked'] = 'checked'
Tag.make('input', options, null).toString()
 
labelTag: (name, content = null, options = {}) ->
options['for'] = name
Tag.make('label', options, content).toString()
 
submitTag: (value = "", options = {}) ->
options['type'] = 'submit'
options['value'] = value
Tag.make('input', options, null).toString()
 
FormBuilder: class FormBuilder
constructor: (model) ->
@model = model
self = this
_.map ['string', 'select', 'checkbox', 'text', 'file', 'password'], (key) ->
self[key] = (name, options = {}) ->
options['as'] = key
self['input'](name, options)
 
errors: (method) =>
if @model.get('errors') && @model.get('errors')[method]
Tag.make('div', 'class': 'errors', (@model.get('errors')[method].join(', ')))
else
""
 
input: (name, options = {}) =>
method = name.replace(/\]/, '').replace(/\[/, '.')
label = HtmlHelpers.labelTag(name, options?.label || _.humanize(name))
input = switch options['as']
when 'select'
options['selected'] ||= @model.get(method)
HtmlHelpers.select(name, options.collection || [], options)
when 'checkbox'
HtmlHelpers.checkBoxTag(name, 1, @model.get(method) || false, options)
when 'text'
options['value'] ||= @model.get(method) || ''
HtmlHelpers.textArea(name, options)
when 'file'
HtmlHelpers.fileFieldTag(name, options)
when 'password'
HtmlHelpers.passwordFieldTag(name, "", options)
else
value = options['value'] || @model.get(method) || ''
HtmlHelpers.textFieldTag(name, value, options)
 
Tag.make('div', 'class': 'input', (label + input + @errors(method))).toString()
 
button: (value = null, options = {}) =>
value ||= if @model.isNew() then 'Create' else 'Update'
HtmlHelpers.submitTag(value, options)
 
HAML.globals = -> HtmlHelpers

This helpers have to be used with the escape symbol in HAML, for example:

!= @linkTo "mysite", 'http://example.com"

If you want to use "unsafe" text, it won't be escaped:

!= @linkTo @userGeneratedText, 'http://example.com"

This is very dangerous.
I wrote wrote a version with support for escape text in a fork gist
With that code, you can do this:

!= @linkTo @userGeneratedText, 'http://example.com", escapeText: true

Sorry, last fork gist URL is wrong and I can not edit the comment.
The fork gist is here.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.