My First Rails Plugin - Usertext

48
My First Rails Plugin Marking up user content

description

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

Transcript of My First Rails Plugin - Usertext

Page 1: My First Rails Plugin - Usertext

My First Rails PluginMarking up user content

Page 2: My First Rails Plugin - Usertext

The problem

Page 3: My First Rails Plugin - Usertext

Lots of websites invite user input.

Page 4: My First Rails Plugin - Usertext

Blogs

Page 5: My First Rails Plugin - Usertext

Forums

Page 6: My First Rails Plugin - Usertext

Wikis

Page 7: My First Rails Plugin - Usertext

‘Web 2.0’ sites

Page 8: My First Rails Plugin - Usertext

And they all have to format it somehow.

Page 9: My First Rails Plugin - Usertext

There are some existing solutions

Page 10: My First Rails Plugin - Usertext

‘Some HTML accepted’

Page 11: My First Rails Plugin - Usertext

Textile

Page 12: My First Rails Plugin - Usertext

Markdown

Page 13: My First Rails Plugin - Usertext

But asking users to pick between them is confusing!

Page 14: My First Rails Plugin - Usertext

Some of the syntax is a bit unnatural too...

Page 15: My First Rails Plugin - Usertext

Textile

“Test”:http://www.test.com

# Ordered list# Ordered list

Page 16: My First Rails Plugin - Usertext

Textile

Page 17: My First Rails Plugin - Usertext

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>

Page 18: My First Rails Plugin - Usertext

Users shouldn’t have to think about the markup

syntax!

Page 19: My First Rails Plugin - Usertext

Instead, interpret what they’ve typed and make

intelligent guesses!

Page 20: My First Rails Plugin - Usertext

I decided to write my own code...

Page 21: My First Rails Plugin - Usertext

...as a Ruby on Rails plugin

Page 22: My First Rails Plugin - Usertext

I want to support...Paragraphs

Unordered lists

Ordered lists

Blockquotes

Code examples

Page 23: My First Rails Plugin - Usertext

Rails already has a simple_format(text) helper

Page 24: My First Rails Plugin - Usertext

simple_format(text)

simple_format(“Hello.

Are you my mummy?”)

=> “<p>Hello.</p>

<p>Are you my mummy?</p>”

Page 25: My First Rails Plugin - Usertext

How does simple_format work?

Page 26: My First Rails Plugin - Usertext

simple_format()def simple_format(text, html_options={}) start_tag = tag('p', html_options, true)

text = text.to_s.dup text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n

text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br

text.insert 0, start_tag text << "</p>"

end

Page 27: My First Rails Plugin - Usertext

So borrowing from that...

Page 28: My First Rails Plugin - Usertext

Dealing with newlinesdef cleanup_newlines(text) text.gsub(/\r\n?/, "\n") # \r\n and \r -> \nend

Page 29: My First Rails Plugin - Usertext

Block elementsUnordered list:

* Item* Item

Ordered list:

1. Item2. Item

Or

1) Item2) Item

Blockquotes:

“To be, or not to be.”

Page 30: My First Rails Plugin - Usertext

Block elementsdef block_element_markup(text) blocks = text.split("\n\n") new_text = Array.new blocks.each do |block| # Work out what type of block element it is. end return new_text.join("\n\n")end

Page 31: My First Rails Plugin - Usertext

Block elementsif block.match(/((^\*\s.*$\n?)+)/) lines = Array.new block.each_line do |line| lines << line.gsub(/\*\s(.*)$/, '<li>\1</li>') end new_text << content_tag("ul", "\n" + lines.join("") + "\n")

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("ol", "\n" + lines.join("") + "\n") ...end

Page 32: My First Rails Plugin - Usertext

Block elementselsif block.match(/^“.*”$/) new_text << content_tag("blockquote", content_tag("p", block.gsub(/^“(.*)”$/, '\1'))) elsif block.match(/(^<code>.*<\/code>$)/) new_text << content_tag("div", block)else new_text << content_tag("p", block)end

Page 33: My First Rails Plugin - Usertext

Dealing with links... def auto_link_urls(text, href_options = {})

extra_options = tag_options(href_options.stringify_keys) || ""

auto_link_re = %r{

( # leading text

<\w+.*?>| # leading HTML tag, or [^=!:'"/]| # 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 + "<a href=\"" + b + c + "\">" + truncate_in_middle(c, 40) + "</a>" + $5

end

end

Page 34: My First Rails Plugin - Usertext

Truncate URLS in the middle...

def truncate_in_middle(text, length = 30, truncate_string = "...") 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 endend

Page 35: My First Rails Plugin - Usertext

Detecting code snippetsdef mark_code(text) h(text). gsub(/(^&lt;[a-zA-Z]+.*$|&lt;[a-zA-Z]+.*&gt;)/) do text = "<code>" + ($1) + "</code>" endend

<html> => <code>&lt;html&gt;</code>

Page 36: My First Rails Plugin - Usertext

Detecting phone numbers

def auto_link_phone_numbers(text) text.gsub(/(\s|^)((0|\+44)\d{10,10})\b/) do text = $1 + "<a href=\"tel:" + $2 + "\">" + $2 + "</a>" endend

07736111111

=> <a tel="07736111111"> 07736111111</a>

Page 37: My First Rails Plugin - Usertext

Typography" => “ / ”

' => ‘ / ’ (quote) / ’ (apos) / ' (prime)

... => …

etc...

Page 38: My First Rails Plugin - Usertext

Typography

gsub(/([^\.])\.\.\.([^\.]|$)/, '\1…\2')

gsub(/([^\s]+)\"/, '\1”')

gsub(/([^\s]+)\'(\s)/, '\1’\2')

gsub(/([^\s])\'([^\s])/, '\1’\2')

etc...

Page 39: My First Rails Plugin - Usertext

Tests!

Page 40: My First Rails Plugin - Usertext

Hosting

http://code.google.com/p/usertext/

Page 41: My First Rails Plugin - Usertext

Live demo!

http://www.usertext.org

Page 42: My First Rails Plugin - Usertext

What next?

Page 43: My First Rails Plugin - Usertext

What next?• Test on some real user input!

Page 44: My First Rails Plugin - Usertext

What next?• Test on some real user input!

• Make it configurable

Page 45: My First Rails Plugin - Usertext

What next?• Test on some real user input!

• Make it configurable

• Port to PHP (for Wordpress)?

Page 46: My First Rails Plugin - Usertext

What next?• Test on some real user input!

• Make it configurable

• Port to PHP (for Wordpress)?

• gem vs plugin?

Page 47: My First Rails Plugin - Usertext

What next?• Test on some real user input!

• Make it configurable

• Port to PHP (for Wordpress)?

• gem vs plugin?

• Get feedback from other developers.