My First Rails Plugin - Usertext

2,153 views

Published on

Presentation given at BarCamp Sheffield 2008. See my blog post on the subject for more info: http://www.frankieroberto.com/weblog/1332

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,153
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
21
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

My First Rails Plugin - Usertext

  1. 1. My First Rails Plugin Marking up user content
  2. 2. The problem
  3. 3. Lots of websites invite user input.
  4. 4. Blogs
  5. 5. Forums
  6. 6. Wikis
  7. 7. ‘Web 2.0’ sites
  8. 8. And they all have to format it somehow.
  9. 9. There are some existing solutions
  10. 10. ‘Some HTML accepted’
  11. 11. Textile
  12. 12. Markdown
  13. 13. But asking users to pick between them is confusing!
  14. 14. Some of the syntax is a bit unnatural too...
  15. 15. Textile “Test”:http://www.test.com # Ordered list # Ordered list
  16. 16. Textile
  17. 17. Markdown > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. > > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse > id sem consectetuer libero luctus adipiscing. => <blockquote><p>This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p></blockquote>
  18. 18. Users shouldn’t have to think about the markup syntax!
  19. 19. Instead, interpret what they’ve typed and make intelligent guesses!
  20. 20. I decided to write my own code...
  21. 21. ...as a Ruby on Rails plugin
  22. 22. I want to support... Paragraphs Unordered lists Ordered lists Blockquotes Code examples
  23. 23. Rails already has a simple_format(text) helper
  24. 24. simple_format(text) simple_format(“Hello. Are you my mummy?”) => “<p>Hello.</p> <p>Are you my mummy?</p>”
  25. 25. How does simple_format work?
  26. 26. simple_format() def simple_format(text, html_options={}) start_tag = tag('p', html_options, true) text = text.to_s.dup text.gsub!(/rn?/, quot;nquot;) # rn and r -> n text.gsub!(/nn+/, quot;</p>nn#{start_tag}quot;) # 2+ newline -> paragraph text.gsub!(/([^n]n)(?=[^n])/, '1<br />') # 1 newline -> br text.insert 0, start_tag text << quot;</p>quot; end
  27. 27. So borrowing from that...
  28. 28. Dealing with newlines def cleanup_newlines(text) text.gsub(/rn?/, quot;nquot;) # rn and r -> n end
  29. 29. Block elements Unordered list: Blockquotes: * Item “To be, or not to * Item be.” Ordered list: 1. Item 2. Item Or 1) Item 2) Item
  30. 30. Block elements def block_element_markup(text) blocks = text.split(quot;nnquot;) new_text = Array.new blocks.each do |block| # Work out what type of block element it is. end return new_text.join(quot;nnquot;) end
  31. 31. Block elements if block.match(/((^*s.*$n?)+)/) lines = Array.new block.each_line do |line| lines << line.gsub(/*s(.*)$/, '<li>1</li>') end new_text << content_tag(quot;ulquot;, quot;nquot; + lines.join(quot;quot;) + quot;nquot;) elsif block.match(/((^d+[.)]s.*$n?)+)/) lines = Array.new block.each_line do |line| lines << line.gsub(/d+.s(.*)$/, '<li>1</li>') end new_text << content_tag(quot;olquot;, quot;nquot; + lines.join(quot;quot;) + quot;nquot;) ... end
  32. 32. Block elements elsif block.match(/^“.*”$/) new_text << content_tag(quot;blockquotequot;, content_tag(quot;pquot;, block.gsub(/ ^“(.*)”$/, '1'))) elsif block.match(/(^<code>.*</code>$)/) new_text << content_tag(quot;divquot;, block) else new_text << content_tag(quot;pquot;, block) end
  33. 33. Dealing with links... def auto_link_urls(text, href_options = {}) extra_options = tag_options(href_options.stringify_keys) || quot;quot; auto_link_re = %r{ ( # leading text <w+.*?>| # leading HTML tag, or [^=!:'quot;/]| # leading punctuation, or ^ # beginning of line ) (https?://|ftp://) # protocol spec ( [-w]+ # subdomain or domain (?:.[-w]+)* # remaining subdomains or domain (?::d+)? # port (?:/(?:(?:[~w+@%-]|(?:[,.;:][^s$]))+)?)* # path (?:?[w+@%&=.;-]+)? # query string (?:#[w-/]*)? # trailing anchor )(([[:punct:]]|s|<|$)) # trailing text }x text.gsub(auto_link_re) do all, a, b, c, d = $&, $1, $2, $3, $5 text = a + quot;<a href=quot;quot; + b + c + quot;quot;>quot; + truncate_in_middle(c, 40) + quot;</a>quot; + $5 end end
  34. 34. Truncate URLS in the middle... def truncate_in_middle(text, length = 30, truncate_string = quot;...quot;) if text l = ((length - truncate_string.chars.length) / 2).to_int chars = text.chars return (chars.length > length ? chars[0...l] + truncate_string + chars[chars.length-l...chars.length] : text).to_s end end
  35. 35. Detecting code snippets def mark_code(text) h(text). gsub(/(^&lt;[a-zA-Z]+.*$|&lt;[a-zA-Z]+.*&gt;)/) do text = quot;<code>quot; + ($1) + quot;</code>quot; end end <html> => <code>&lt;html&gt;</code>
  36. 36. Detecting phone numbers 07736111111 => <a tel=quot;07736111111quot;> 07736111111</a> def auto_link_phone_numbers(text) text.gsub(/(s|^)((0|+44)d{10,10})b/) do text = $1 + quot;<a href=quot;tel:quot; + $2 + quot;quot;>quot; + $2 + quot;</a>quot; end end
  37. 37. Typography quot; => “ / ” ' => ‘ / ’ (quote) / ’ (apos) / ' (prime) ... => … etc...
  38. 38. Typography gsub(/([^.])...([^.]|$)/, '1…2') gsub(/([^s]+)quot;/, '1”') gsub(/([^s]+)'(s)/, '1’2') gsub(/([^s])'([^s])/, '1’2') etc...
  39. 39. Tests!
  40. 40. Hosting http://code.google.com/p/usertext/
  41. 41. Live demo! http://www.usertext.org
  42. 42. What next?
  43. 43. What next? • Test on some real user input!
  44. 44. What next? • Test on some real user input! • Make it configurable
  45. 45. What next? • Test on some real user input! • Make it configurable • Port to PHP (for Wordpress)?
  46. 46. What next? • Test on some real user input! • Make it configurable • Port to PHP (for Wordpress)? • gem vs plugin?
  47. 47. What next? • Test on some real user input! • Make it configurable • Port to PHP (for Wordpress)? • gem vs plugin? • Get feedback from other developers.
  48. 48. Thanks... Frankie Roberto frankie@frankieroberto.com

×