Skip to content

Instantly share code, notes, and snippets.

@chytreg
Created January 13, 2012 13:03
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save chytreg/802d87e1fd6495cc4727 to your computer and use it in GitHub Desktop.
Save chytreg/802d87e1fd6495cc4727 to your computer and use it in GitHub Desktop.
html_helpers for hamlc
# 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
@marioizquierdo
Copy link

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

@marioizquierdo
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment