gem 'paperclip', '~> 2.0'
gem 'deadlock_retry', '>= 1.2.0'
+# Markdown formatting support
+gem 'redcarpet'
+
# Character conversion support for ruby 1.8
gem 'iconv', :platforms => :ruby_18
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
+ redcarpet (2.1.0)
rinku (1.5.1)
ruby-openid (2.1.8)
sanitize (2.0.3)
pg
rails (= 3.2.2)
rails-i18n (>= 0.5.1)
+ redcarpet
rinku (>= 1.2.2)
sanitize
sass-rails (~> 3.2.3)
module ApplicationHelper
require 'rexml/document'
- def sanitize(text)
- Sanitize.clean(text, Sanitize::Config::OSM).html_safe
- end
-
- def htmlize(text)
- return linkify(sanitize(simple_format(text)))
- end
-
def linkify(text)
if text.html_safe?
Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe
attr_accessible :body
+ after_initialize :set_defaults
+
+ def body
+ RichText.new(read_attribute(:body_format), read_attribute(:body))
+ end
+
def digest
md5 = Digest::MD5.new
md5 << diary_entry_id.to_s
md5 << body
md5.hexdigest
end
+
+private
+
+ def set_defaults
+ self.body_format = "markdown" unless self.attribute_present?(:body_format)
+ end
end
validates_associated :language
attr_accessible :title, :body, :language_code, :latitude, :longitude
+
+ after_initialize :set_defaults
+
+ def body
+ RichText.new(read_attribute(:body_format), read_attribute(:body))
+ end
+
+private
+
+ def set_defaults
+ self.body_format = "markdown" unless self.attribute_present?(:body_format)
+ end
end
attr_accessible :title, :body
+ after_initialize :set_defaults
+
+ def body
+ RichText.new(read_attribute(:body_format), read_attribute(:body))
+ end
+
def digest
md5 = Digest::MD5.new
md5 << from_user_id.to_s
md5 << body
md5.hexdigest
end
+
+private
+
+ def set_defaults
+ self.body_format = "markdown" unless self.attribute_present?(:body_format)
+ end
end
attr_accessible :display_name, :email, :email_confirmation, :openid_url,
:pass_crypt, :pass_crypt_confirmation, :consider_pd
- after_initialize :set_creation_time
+ after_initialize :set_defaults
before_save :encrypt_password
has_attached_file :image,
return el1
end
+ def description
+ RichText.new(read_attribute(:description_format), read_attribute(:description))
+ end
+
def languages
attribute_present?(:languages) ? read_attribute(:languages).split(/ *, */) : []
end
private
- def set_creation_time
+ def set_defaults
self.creation_time = Time.now.getutc unless self.attribute_present?(:creation_time)
+ self.description_format = "markdown" unless self.attribute_present?(:description_format)
end
def encrypt_password
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id
+ after_initialize :set_defaults
+
PERIODS = USER_BLOCK_PERIODS
+ ##
+ # return a renderable version of the reason text.
+ def reason
+ RichText.new(read_attribute(:reason_format), read_attribute(:reason))
+ end
+
##
# returns true if the block is currently active (i.e: the user can't
# use the API).
}, :without_protection => true)
end
- private
+private
+
+ ##
+ # set default values for new records.
+ def set_defaults
+ self.reason_format = "markdown" unless self.attribute_present?(:reason_format)
+ end
+
##
# validate that only moderators are allowed to change the
# block. this should be caught and dealt with in the controller,
<%= user_thumbnail diary_comment.user %>
<h4 id="comment<%= diary_comment.id %>"><%= raw(t('diary_entry.diary_comment.comment_from', :link_user => (link_to h(diary_comment.user.display_name), :controller => 'user', :action => 'view', :display_name => diary_comment.user.display_name), :comment_created_at => l(diary_comment.created_at, :format => :friendly))) %></h4>
-<%= htmlize(diary_comment.body) %>
+<%= diary_comment.body.to_html %>
<%= if_administrator(:span) do %>
<%= link_to t('diary_entry.diary_comment.hide_link'), {:action => 'hidecomment', :display_name => diary_comment.diary_entry.user.display_name, :id => diary_comment.diary_entry.id, :comment => diary_comment.id}, {:confirm => t('diary_entry.diary_comment.confirm')} %>
<% end %>
<b><%= link_to h(diary_entry.title), :action => 'view', :display_name => diary_entry.user.display_name, :id => diary_entry.id %></b><br />
<div xml:lang="<%= diary_entry.language_code %>" lang="<%= diary_entry.language_code %>">
- <%= htmlize(diary_entry.body) %>
+ <%= diary_entry.body.to_html %>
</div>
<% if diary_entry.latitude and diary_entry.longitude %>
<tr class="<%= cl %>">
<td><%= link_to comment.diary_entry.title, :action => :view, :display_name => comment.diary_entry.user.display_name, :id => comment.diary_entry.id %></td>
<td><span title="<%= l comment.created_at, :format => :friendly %>"><%= t 'diary_entry.comments.ago', :ago => time_ago_in_words(comment.created_at) %></span></td>
- <td><%= htmlize(comment.body) %></td>
+ <td><%= comment.body.to_html %></td>
</tr>
<% end -%>
</table>
xml.title h(entry.title)
xml.link url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :only_path => false)
xml.guid url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :only_path => false)
- xml.description htmlize(entry.body)
+ xml.description entry.body.to_html
xml.author entry.user.display_name
xml.pubDate entry.created_at.to_s(:rfc822)
xml.comments url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :anchor => "comments", :only_path => false)
</tr>
<tr>
<th></th>
- <td><%= htmlize(@message.body) %></td>
+ <td><%= @message.body.to_html %></td>
<td></td>
</tr>
</table>
</tr>
<tr>
<th></th>
- <td><%= htmlize(@message.body) %></td>
+ <td><%= @message.body.to_html %></td>
<td></td>
</tr>
</table>
<%= t'notifier.diary_comment_notification.header', :from_user => @from_user, :subject => @title %>
==
-<%= raw @text %>
+<%= raw @text.to_text %>
==
<%= t'notifier.diary_comment_notification.footer', :readurl => @readurl, :commenturl => @commenturl, :replyurl => @replyurl %>
<p><%= raw t'notifier.message_notification.header', :from_user => link_to(@from_user, :host => SERVER_URL, :controller => :user, :action => :view, :display_name => @from_user), :subject => @title %></p>
==
-<%= htmlize @text %>
+<%= @text.to_html %>
==
<p>
<%= raw t'notifier.message_notification.header', :from_user => @from_user, :subject => @title %>
==
-<%= raw @text %>
+<%= raw @text.to_text %>
==
<%= raw t'notifier.message_notification.footer1', :readurl => @readurl %>
%>
<% end %>
</p>
- <%= htmlize(user.description) %>
+ <%= user.description.to_html %>
</td>
<td>
<%= check_box_tag "user_#{user.id}", "", false, :name => "user[#{user.id}]" %>
<h3><%= t 'user.view.description' %></h3>
-<div id="description"><%= htmlize(@this_user.description) %></div>
+<div id="description"><%= @this_user.description.to_html %></div>
<% if @user and @this_user.id == @user.id %>
<div id="map" class="user_map">
<p><b><%= t'user_block.show.status' %></b>: <%= block_status(@user_block) %></p>
<p><b><%= t'user_block.show.reason' %></b></p>
-<%= htmlize(@user_block.reason) %>
+<%= @user_block.reason.to_html %>
<% if @user_block.ends_at > Time.now.getutc %>
<% if @user and @user.id == @user_block.creator_id %>
--- /dev/null
+require 'migrate'
+
+class AddTextFormat < ActiveRecord::Migration
+ def up
+ create_enumeration :format_enum, ["html", "markdown"]
+ add_column :users, :description_format, :format_enum, :null => false, :default => "html"
+ add_column :user_blocks, :reason_format, :format_enum, :null => false, :default => "html"
+ add_column :diary_entries, :body_format, :format_enum, :null => false, :default => "html"
+ add_column :diary_comments, :body_format, :format_enum, :null => false, :default => "html"
+ add_column :messages, :body_format, :format_enum, :null => false, :default => "html"
+ end
+
+ def down
+ remove_column :messages, :body_format
+ remove_column :diary_comments, :body_format
+ remove_column :diary_entries, :body_format
+ remove_column :user_blocks, :reason_format
+ remove_column :users, :description_format
+ drop_enumeration :format_enum
+ end
+end
--- /dev/null
+module RichText
+ def self.new(format, text)
+ case format
+ when "html"; HTML.new(text || "")
+ when "markdown"; Markdown.new(text || "")
+ else; nil
+ end
+ end
+
+ class HTML < String
+ include ActionView::Helpers::TextHelper
+ include ActionView::Helpers::TagHelper
+
+ def to_html
+ linkify(sanitize(simple_format(self)))
+ end
+
+ def to_text
+ self
+ end
+
+ private
+
+ def sanitize(text)
+ Sanitize.clean(text, Sanitize::Config::OSM).html_safe
+ end
+
+ def linkify(text)
+ if text.html_safe?
+ Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe
+ else
+ Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow"))
+ end
+ end
+ end
+
+ class Markdown < String
+ def to_html
+ html_parser.render(self).html_safe
+ end
+
+ def to_text
+ self
+ end
+
+ private
+
+ def html_parser
+ @@html_renderer ||= Redcarpet::Render::XHTML.new({
+ :filter_html => true, :safe_links_only => true
+ })
+ @@html_parser ||= Redcarpet::Markdown.new(@@html_renderer, {
+ :no_intra_emphasis => true, :autolink => true, :space_after_headers => true
+ })
+ end
+ end
+end