X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=vendor%2Frails%2Factionpack%2Flib%2Faction_view%2Fhelpers%2Ftext_helper.rb;fp=vendor%2Frails%2Factionpack%2Flib%2Faction_view%2Fhelpers%2Ftext_helper.rb;h=36f757565208a22ccb24fff4431bd5b17d145020;hb=d115f2e23823271635bad69229a42cd8ac68debe;hp=0000000000000000000000000000000000000000;hpb=37cb670bf3ddde90b214e591f100ed4446469484;p=depot.git
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb
new file mode 100644
index 0000000..36f7575
--- /dev/null
+++ b/vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb
@@ -0,0 +1,601 @@
+require 'action_view/helpers/tag_helper'
+
+begin
+ require 'html/document'
+rescue LoadError
+ html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
+ if File.directory?(html_scanner_path)
+ $:.unshift html_scanner_path
+ require 'html/document'
+ end
+end
+
+module ActionView
+ module Helpers #:nodoc:
+ # The TextHelper module provides a set of methods for filtering, formatting
+ # and transforming strings, which can reduce the amount of inline Ruby code in
+ # your views. These helper methods extend ActionView making them callable
+ # within your template files.
+ module TextHelper
+ # The preferred method of outputting text in your views is to use the
+ # <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
+ # do not operate as expected in an eRuby code block. If you absolutely must
+ # output text within a non-output code block (i.e., <% %>), you can use the concat method.
+ #
+ # ==== Examples
+ # <%
+ # concat "hello"
+ # # is the equivalent of <%= "hello" %>
+ #
+ # if (logged_in == true):
+ # concat "Logged in!"
+ # else
+ # concat link_to('login', :action => login)
+ # end
+ # # will either display "Logged in!" or a login link
+ # %>
+ def concat(string, unused_binding = nil)
+ if unused_binding
+ ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
+ end
+
+ output_buffer << string
+ end
+
+ # Truncates a given +text+ after a given :length if +text+ is longer than :length
+ # (defaults to 30). The last characters will be replaced with the :omission (defaults to "...").
+ #
+ # ==== Examples
+ #
+ # truncate("Once upon a time in a world far far away")
+ # # => Once upon a time in a world f...
+ #
+ # truncate("Once upon a time in a world far far away", :length => 14)
+ # # => Once upon a...
+ #
+ # truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
+ # # => And they found that many (clipped)
+ #
+ # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 15)
+ # # => And they found... (continued)
+ #
+ # You can still use truncate with the old API that accepts the
+ # +length+ as its optional second and the +ellipsis+ as its
+ # optional third parameter:
+ # truncate("Once upon a time in a world far far away", 14)
+ # # => Once upon a time in a world f...
+ #
+ # truncate("And they found that many people were sleeping better.", 15, "... (continued)")
+ # # => And they found... (continued)
+ def truncate(text, *args)
+ options = args.extract_options!
+ unless args.empty?
+ ActiveSupport::Deprecation.warn('truncate takes an option hash instead of separate ' +
+ 'length and omission arguments', caller)
+
+ options[:length] = args[0] || 30
+ options[:omission] = args[1] || "..."
+ end
+ options.reverse_merge!(:length => 30, :omission => "...")
+
+ if text
+ l = options[:length] - options[:omission].mb_chars.length
+ chars = text.mb_chars
+ (chars.length > options[:length] ? chars[0...l] + options[:omission] : text).to_s
+ end
+ end
+
+ # Highlights one or more +phrases+ everywhere in +text+ by inserting it into
+ # a :highlighter string. The highlighter can be specialized by passing :highlighter
+ # as a single-quoted string with \1 where the phrase is to be inserted (defaults to
+ # '\1')
+ #
+ # ==== Examples
+ # highlight('You searched for: rails', 'rails')
+ # # => You searched for: rails
+ #
+ # highlight('You searched for: ruby, rails, dhh', 'actionpack')
+ # # => You searched for: ruby, rails, dhh
+ #
+ # highlight('You searched for: rails', ['for', 'rails'], :highlighter => '\1')
+ # # => You searched for: rails
+ #
+ # highlight('You searched for: rails', 'rails', :highlighter => '\1')
+ # # => You searched for: rails
+ #
+ # You can still use highlight with the old API that accepts the
+ # +highlighter+ as its optional third parameter:
+ # highlight('You searched for: rails', 'rails', '\1') # => You searched for: rails
+ def highlight(text, phrases, *args)
+ options = args.extract_options!
+ unless args.empty?
+ options[:highlighter] = args[0] || '\1'
+ end
+ options.reverse_merge!(:highlighter => '\1')
+
+ if text.blank? || phrases.blank?
+ text
+ else
+ match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
+ text.gsub(/(#{match})/i, options[:highlighter])
+ end
+ end
+
+ # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
+ # The :radius option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
+ # defined in :radius (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
+ # then the :omission option (which defaults to "...") will be prepended/appended accordingly. The resulting string
+ # will be stripped in any case. If the +phrase+ isn't found, nil is returned.
+ #
+ # ==== Examples
+ # excerpt('This is an example', 'an', :radius => 5)
+ # # => ...s is an exam...
+ #
+ # excerpt('This is an example', 'is', :radius => 5)
+ # # => This is a...
+ #
+ # excerpt('This is an example', 'is')
+ # # => This is an example
+ #
+ # excerpt('This next thing is an example', 'ex', :radius => 2)
+ # # => ...next...
+ #
+ # excerpt('This is also an example', 'an', :radius => 8, :omission => ' ')
+ # # => is also an example
+ #
+ # You can still use excerpt with the old API that accepts the
+ # +radius+ as its optional third and the +ellipsis+ as its
+ # optional forth parameter:
+ # excerpt('This is an example', 'an', 5) # => ...s is an exam...
+ # excerpt('This is also an example', 'an', 8, ' ') # => is also an example
+ def excerpt(text, phrase, *args)
+ options = args.extract_options!
+ unless args.empty?
+ options[:radius] = args[0] || 100
+ options[:omission] = args[1] || "..."
+ end
+ options.reverse_merge!(:radius => 100, :omission => "...")
+
+ if text && phrase
+ phrase = Regexp.escape(phrase)
+
+ if found_pos = text.mb_chars =~ /(#{phrase})/i
+ start_pos = [ found_pos - options[:radius], 0 ].max
+ end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
+
+ prefix = start_pos > 0 ? options[:omission] : ""
+ postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
+
+ prefix + text.mb_chars[start_pos..end_pos].strip + postfix
+ else
+ nil
+ end
+ end
+ end
+
+ # Attempts to pluralize the +singular+ word unless +count+ is 1. If
+ # +plural+ is supplied, it will use that when count is > 1, otherwise
+ # it will use the Inflector to determine the plural form
+ #
+ # ==== Examples
+ # pluralize(1, 'person')
+ # # => 1 person
+ #
+ # pluralize(2, 'person')
+ # # => 2 people
+ #
+ # pluralize(3, 'person', 'users')
+ # # => 3 users
+ #
+ # pluralize(0, 'person')
+ # # => 0 people
+ def pluralize(count, singular, plural = nil)
+ "#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
+ end
+
+ # Wraps the +text+ into lines no longer than +line_width+ width. This method
+ # breaks on the first whitespace character that does not exceed +line_width+
+ # (which is 80 by default).
+ #
+ # ==== Examples
+ #
+ # word_wrap('Once upon a time')
+ # # => Once upon a time
+ #
+ # word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
+ # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined...
+ #
+ # word_wrap('Once upon a time', :line_width => 8)
+ # # => Once upon\na time
+ #
+ # word_wrap('Once upon a time', :line_width => 1)
+ # # => Once\nupon\na\ntime
+ #
+ # You can still use word_wrap with the old API that accepts the
+ # +line_width+ as its optional second parameter:
+ # word_wrap('Once upon a time', 8) # => Once upon\na time
+ def word_wrap(text, *args)
+ options = args.extract_options!
+ unless args.blank?
+ options[:line_width] = args[0] || 80
+ end
+ options.reverse_merge!(:line_width => 80)
+
+ text.split("\n").collect do |line|
+ line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
+ end * "\n"
+ end
+
+ begin
+ require_library_or_gem "redcloth" unless Object.const_defined?(:RedCloth)
+
+ # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
+ #
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
+ # This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
+ # is available.
+ #
+ # ==== Examples
+ # textilize("*This is Textile!* Rejoice!")
+ # # => "This is Textile! Rejoice!
"
+ #
+ # textilize("I _love_ ROR(Ruby on Rails)!")
+ # # => "I love ROR!
"
+ #
+ # textilize("h2. Textile makes markup -easy- simple!")
+ # # => "Textile makes markup easy simple!
"
+ #
+ # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
+ # # => "Visit the Rails website here.
"
+ def textilize(text)
+ if text.blank?
+ ""
+ else
+ textilized = RedCloth.new(text, [ :hard_breaks ])
+ textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
+ textilized.to_html
+ end
+ end
+
+ # Returns the text with all the Textile codes turned into HTML tags,
+ # but without the bounding tag that RedCloth adds.
+ #
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
+ # This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
+ # is available.
+ #
+ # ==== Examples
+ # textilize_without_paragraph("*This is Textile!* Rejoice!")
+ # # => "This is Textile! Rejoice!"
+ #
+ # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
+ # # => "I love ROR!"
+ #
+ # textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
+ # # => "
Textile makes markup easy simple!
"
+ #
+ # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
+ # # => "Visit the Rails website here."
+ def textilize_without_paragraph(text)
+ textiled = textilize(text)
+ if textiled[0..2] == "" then textiled = textiled[3..-1] end
+ if textiled[-4..-1] == "
" then textiled = textiled[0..-5] end
+ return textiled
+ end
+ rescue LoadError
+ # We can't really help what's not there
+ end
+
+ begin
+ require_library_or_gem "bluecloth" unless Object.const_defined?(:BlueCloth)
+
+ # Returns the text with all the Markdown codes turned into HTML tags.
+ # This method is only available if BlueCloth[http://www.deveiate.org/projects/BlueCloth]
+ # is available.
+ #
+ # ==== Examples
+ # markdown("We are using __Markdown__ now!")
+ # # => "We are using Markdown now!
"
+ #
+ # markdown("We like to _write_ `code`, not just _read_ it!")
+ # # => "We like to write code
, not just read it!
"
+ #
+ # markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
+ # # => "The Markdown website
+ # # has more information.
"
+ #
+ # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
+ # # => ''
+ def markdown(text)
+ text.blank? ? "" : BlueCloth.new(text).to_html
+ end
+ rescue LoadError
+ # We can't really help what's not there
+ end
+
+ # Returns +text+ transformed into HTML using simple formatting rules.
+ # Two or more consecutive newlines(\n\n) are considered as a
+ # paragraph and wrapped in tags. One newline (\n) is
+ # considered as a linebreak and a
tag is appended. This
+ # method does not remove the newlines from the +text+.
+ #
+ # You can pass any HTML attributes into html_options. These
+ # will be added to all created paragraphs.
+ # ==== Examples
+ # my_text = "Here is some basic text...\n...with a line break."
+ #
+ # simple_format(my_text)
+ # # => "
Here is some basic text...\n
...with a line break.
"
+ #
+ # more_text = "We want to put a paragraph...\n\n...right there."
+ #
+ # simple_format(more_text)
+ # # => "We want to put a paragraph...
\n\n...right there.
"
+ #
+ # simple_format("Look ma! A class!", :class => 'description')
+ # # => "Look ma! A class!
"
+ 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+/, "
\n\n#{start_tag}") # 2+ newline -> paragraph
+ text.gsub!(/([^\n]\n)(?=[^\n])/, '\1
') # 1 newline -> br
+ text.insert 0, start_tag
+ text << ""
+ end
+
+ # Turns all URLs and e-mail addresses into clickable links. The :link option
+ # will limit what should be linked. You can add HTML attributes to the links using
+ # :href_options. Possible values for :link are :all (default),
+ # :email_addresses, and :urls. If a block is given, each URL and
+ # e-mail address is yielded and the result is used as the link text.
+ #
+ # ==== Examples
+ # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
+ # # => "Go to http://www.rubyonrails.org and
+ # # say hello to david@loudthinking.com"
+ #
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
+ # # => "Visit http://www.loudthinking.com/
+ # # or e-mail david@loudthinking.com"
+ #
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
+ # # => "Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com"
+ #
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
+ # auto_link(post_body, :href_options => { :target => '_blank' }) do |text|
+ # truncate(text, 15)
+ # end
+ # # => "Welcome to my new blog at http://www.m....
+ # Please e-mail me at me@email.com."
+ #
+ #
+ # You can still use auto_link with the old API that accepts the
+ # +link+ as its optional second parameter and the +html_options+ hash
+ # as its optional third parameter:
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
+ # auto_link(post_body, :urls) # => Once upon\na time
+ # # => "Welcome to my new blog at http://www.myblog.com.
+ # Please e-mail me at me@email.com."
+ #
+ # auto_link(post_body, :all, :target => "_blank") # => Once upon\na time
+ # # => "Welcome to my new blog at http://www.myblog.com.
+ # Please e-mail me at me@email.com."
+ def auto_link(text, *args, &block)#link = :all, href_options = {}, &block)
+ return '' if text.blank?
+
+ options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
+ unless args.empty?
+ options[:link] = args[0] || :all
+ options[:html] = args[1] || {}
+ end
+ options.reverse_merge!(:link => :all, :html => {})
+
+ case options[:link].to_sym
+ when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), &block)
+ when :email_addresses then auto_link_email_addresses(text, &block)
+ when :urls then auto_link_urls(text, options[:html], &block)
+ end
+ end
+
+ # Creates a Cycle object whose _to_s_ method cycles through elements of an
+ # array every time it is called. This can be used for example, to alternate
+ # classes for table rows. You can use named cycles to allow nesting in loops.
+ # Passing a Hash as the last parameter with a :name key will create a
+ # named cycle. The default name for a cycle without a +:name+ key is
+ # "default". You can manually reset a cycle by calling reset_cycle
+ # and passing the name of the cycle. The current cycle string can be obtained
+ # anytime using the current_cycle method.
+ #
+ # ==== Examples
+ # # Alternate CSS classes for even and odd numbers...
+ # @items = [1,2,3,4]
+ #
+ # <% @items.each do |item| %>
+ # ">
+ # item |
+ #
+ # <% end %>
+ #
+ #
+ #
+ # # Cycle CSS classes for rows, and text colors for values within each row
+ # @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
+ # {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
+ # {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
+ # <% @items.each do |item| %>
+ # "row_class") -%>">
+ #
+ # <% item.values.each do |value| %>
+ # <%# Create a named cycle "colors" %>
+ # "colors") -%>">
+ # <%= value %>
+ #
+ # <% end %>
+ # <% reset_cycle("colors") %>
+ # |
+ #
+ # <% end %>
+ def cycle(first_value, *values)
+ if (values.last.instance_of? Hash)
+ params = values.pop
+ name = params[:name]
+ else
+ name = "default"
+ end
+ values.unshift(first_value)
+
+ cycle = get_cycle(name)
+ if (cycle.nil? || cycle.values != values)
+ cycle = set_cycle(name, Cycle.new(*values))
+ end
+ return cycle.to_s
+ end
+
+ # Returns the current cycle string after a cycle has been started. Useful
+ # for complex table highlighing or any other design need which requires
+ # the current cycle string in more than one place.
+ #
+ # ==== Example
+ # # Alternate background colors
+ # @items = [1,2,3,4]
+ # <% @items.each do |item| %>
+ # ">
+ # <%= item %>
+ #
+ # <% end %>
+ def current_cycle(name = "default")
+ cycle = get_cycle(name)
+ cycle.current_value unless cycle.nil?
+ end
+
+ # Resets a cycle so that it starts from the first element the next time
+ # it is called. Pass in +name+ to reset a named cycle.
+ #
+ # ==== Example
+ # # Alternate CSS classes for even and odd numbers...
+ # @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
+ #
+ # <% @items.each do |item| %>
+ # ">
+ # <% item.each do |value| %>
+ # "colors") -%>">
+ # <%= value %>
+ #
+ # <% end %>
+ #
+ # <% reset_cycle("colors") %>
+ #
+ # <% end %>
+ #
+ def reset_cycle(name = "default")
+ cycle = get_cycle(name)
+ cycle.reset unless cycle.nil?
+ end
+
+ class Cycle #:nodoc:
+ attr_reader :values
+
+ def initialize(first_value, *values)
+ @values = values.unshift(first_value)
+ reset
+ end
+
+ def reset
+ @index = 0
+ end
+
+ def current_value
+ @values[previous_index].to_s
+ end
+
+ def to_s
+ value = @values[@index].to_s
+ @index = next_index
+ return value
+ end
+
+ private
+
+ def next_index
+ step_index(1)
+ end
+
+ def previous_index
+ step_index(-1)
+ end
+
+ def step_index(n)
+ (@index + n) % @values.size
+ end
+ end
+
+ private
+ # The cycle helpers need to store the cycles in a place that is
+ # guaranteed to be reset every time a page is rendered, so it
+ # uses an instance variable of ActionView::Base.
+ def get_cycle(name)
+ @_cycles = Hash.new unless defined?(@_cycles)
+ return @_cycles[name]
+ end
+
+ def set_cycle(name, cycle_object)
+ @_cycles = Hash.new unless defined?(@_cycles)
+ @_cycles[name] = cycle_object
+ end
+
+ AUTO_LINK_RE = %r{
+ ( # leading text
+ <\w+.*?>| # leading HTML tag, or
+ [^=!:'"/]| # leading punctuation, or
+ ^ # beginning of line
+ )
+ (
+ (?:https?://)| # protocol spec, or
+ (?:www\.) # www.*
+ )
+ (
+ [-\w]+ # subdomain or domain
+ (?:\.[-\w]+)* # remaining subdomains or domain
+ (?::\d+)? # port
+ (?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
+ (?:\?[\w\+@%&=.;:-]+)? # query string
+ (?:\#[\w\-]*)? # trailing anchor
+ )
+ ([[:punct:]]|<|$|) # trailing text
+ }x unless const_defined?(:AUTO_LINK_RE)
+
+ # Turns all urls into clickable links. If a block is given, each url
+ # is yielded and the result is used as the link text.
+ def auto_link_urls(text, html_options = {})
+ extra_options = tag_options(html_options.stringify_keys) || ""
+ text.gsub(AUTO_LINK_RE) do
+ all, a, b, c, d = $&, $1, $2, $3, $4
+ if a =~ /#{text}#{d})
+ end
+ end
+ end
+
+ # Turns all email addresses into clickable links. If a block is given,
+ # each email is yielded and the result is used as the link text.
+ def auto_link_email_addresses(text)
+ body = text.dup
+ text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
+ text = $1
+
+ if body.match(/]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
+ text
+ else
+ display_text = (block_given?) ? yield(text) : text
+ %{#{display_text}}
+ end
+ end
+ end
+ end
+ end
+end