ultra_markdown 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/ultra_markdown.rb +85 -0
- data/lib/ultra_markdown/engine.rb +7 -0
- data/lib/ultra_markdown/engine3.rb +7 -0
- data/lib/ultra_markdown/filter/bbcode_image.rb +18 -0
- data/lib/ultra_markdown/filter/block_quote.rb +69 -0
- data/lib/ultra_markdown/filter/code_block.rb +119 -0
- data/lib/ultra_markdown/filter/gist_tag.rb +29 -0
- data/lib/ultra_markdown/filter/image_tag.rb +32 -0
- data/lib/ultra_markdown/filter/result_sanitize.rb +90 -0
- data/lib/ultra_markdown/markdown_processor.rb +91 -0
- data/lib/ultra_markdown/markdown_snippets.rb +35 -0
- data/lib/ultra_markdown/railtie.rb +6 -0
- data/lib/ultra_markdown/syntax_convertor.rb +33 -0
- data/lib/ultra_markdown/version.rb +3 -0
- data/ultra_markdown.gemspec +28 -0
- data/vendor/assets/stylesheets/solarized.css +68 -0
- metadata +166 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Logdown Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# UltraMarkdown
|
2
|
+
|
3
|
+
Markdown Parser for various purposes
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'ultra_markdown'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install ultra_markdown
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "ultra_markdown/version"
|
2
|
+
require "ultra_markdown/markdown_processor"
|
3
|
+
require "ultra_markdown/syntax_convertor"
|
4
|
+
require "ultra_markdown/markdown_snippets"
|
5
|
+
|
6
|
+
case ::Rails.version.to_s
|
7
|
+
when /^4/
|
8
|
+
require 'ultra_markdown/engine'
|
9
|
+
when /^3\.[12]/
|
10
|
+
require 'ultra_markdown/engine3'
|
11
|
+
when /^3\.[0]/
|
12
|
+
require 'ultra_markdown/railtie'
|
13
|
+
end
|
14
|
+
|
15
|
+
module UltraMarkdown
|
16
|
+
|
17
|
+
class HTMLforPost < Redcarpet::Render::HTMLwithSyntaxHighlight
|
18
|
+
def is_rss
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class HTMLforRSS < Redcarpet::Render::HTMLwithSyntaxHighlight
|
24
|
+
def is_rss
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class MarkdownProcessor
|
30
|
+
include Singleton
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
options = {
|
34
|
+
:autolink => true,
|
35
|
+
:strikethrough => true,
|
36
|
+
:space_after_headers => false,
|
37
|
+
:tables => true,
|
38
|
+
:lax_spacing => true,
|
39
|
+
:no_intra_emphasis => true,
|
40
|
+
:footnotes => true
|
41
|
+
}
|
42
|
+
|
43
|
+
@converter = Redcarpet::Markdown.new(HTMLforPost.new, options)
|
44
|
+
@converter_for_rss = Redcarpet::Markdown.new(HTMLforRSS.new, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.compile(raw)
|
48
|
+
self.instance.format(raw)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.compile_for_rss(raw)
|
52
|
+
self.instance.format(raw, true)
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def format(raw, is_rss = false)
|
57
|
+
text = raw.clone
|
58
|
+
return '' if text.blank?
|
59
|
+
|
60
|
+
result = if is_rss
|
61
|
+
@converter_for_rss.render(text)
|
62
|
+
else
|
63
|
+
@converter.render(text)
|
64
|
+
end
|
65
|
+
|
66
|
+
#result = Modules::ResultSanitize.clean(result)
|
67
|
+
|
68
|
+
doc = Nokogiri::HTML.fragment(result)
|
69
|
+
|
70
|
+
return doc.to_html
|
71
|
+
rescue => e
|
72
|
+
Airbrake.notify(e)
|
73
|
+
puts "MarkdownTopicConverter.format ERROR: #{e}"
|
74
|
+
return text
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module UltraMarkdown
|
2
|
+
|
3
|
+
module Filter
|
4
|
+
module BbcodeImage
|
5
|
+
|
6
|
+
# convert bbcode-style image tag [img]url[/img] to markdown syntax 
|
7
|
+
def convert_bbcode_img(text)
|
8
|
+
text.gsub!(/\[img\](.+?)\[\/img\]/i) {""}
|
9
|
+
end
|
10
|
+
|
11
|
+
def image_alt(src)
|
12
|
+
File.basename(src, '.*').capitalize
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module UltraMarkdown
|
3
|
+
|
4
|
+
module Filter
|
5
|
+
module BlockQuote
|
6
|
+
|
7
|
+
FullCiteWithTitle = /(\S.*)\s+(https?:\/\/)(\S+)\s+(.+)/i
|
8
|
+
FullCite = /(\S.*)\s+(https?:\/\/)(\S+)/i
|
9
|
+
AuthorTitle = /([^,]+),([^,]+)/
|
10
|
+
Author = /(.+)/
|
11
|
+
|
12
|
+
|
13
|
+
def liquid_blockquote(input)
|
14
|
+
|
15
|
+
input.gsub!(/^\{\% *blockquote([^\n\}]+)?\%\} ?\n?(.+?)\n?\{\% *endblockquote *\%\}/m) do
|
16
|
+
markup = $1
|
17
|
+
content = $2
|
18
|
+
by = nil
|
19
|
+
source = nil
|
20
|
+
title = nil
|
21
|
+
author = nil
|
22
|
+
|
23
|
+
if markup =~ FullCiteWithTitle
|
24
|
+
by = $1
|
25
|
+
source = $2 + $3
|
26
|
+
title = $4.titlecase.strip
|
27
|
+
elsif markup =~ FullCite
|
28
|
+
by = $1
|
29
|
+
source = $2 + $3
|
30
|
+
elsif markup =~ AuthorTitle
|
31
|
+
by = $1
|
32
|
+
title = $2.titlecase.strip
|
33
|
+
elsif markup =~ Author
|
34
|
+
by = $1
|
35
|
+
end
|
36
|
+
|
37
|
+
quote = "<p>#{content.lstrip.rstrip.gsub(/\n\s*\n/, '</p><p>').gsub(/\n/, '<br/>')}</p>"
|
38
|
+
author = "<strong>#{by.strip}</strong>" if by && !by.blank?
|
39
|
+
|
40
|
+
if source
|
41
|
+
url = source.match(/https?:\/\/(.+)/)[1].split('/')
|
42
|
+
parts = []
|
43
|
+
url.each do |part|
|
44
|
+
if (parts + [part]).join('/').length < 32
|
45
|
+
parts << part
|
46
|
+
end
|
47
|
+
end
|
48
|
+
source_temp = parts.join('/')
|
49
|
+
source << '/…' if source_temp != source
|
50
|
+
end
|
51
|
+
|
52
|
+
if !source.nil?
|
53
|
+
cite = " <cite><a href='#{source}'>#{(title || source)}</a></cite>"
|
54
|
+
elsif !title.nil?
|
55
|
+
cite = " <cite>#{title}</cite>"
|
56
|
+
end
|
57
|
+
|
58
|
+
blockquote = "<blockquote>#{quote}</blockquote>"
|
59
|
+
caption = ""
|
60
|
+
caption = "<figcaption>— #{author}#{cite}</figcaption>" if author or cite
|
61
|
+
|
62
|
+
"<figure class='figure-quote'>#{blockquote}#{caption}</figure>"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'erb'
|
3
|
+
module UltraMarkdown
|
4
|
+
module Filter
|
5
|
+
module CodeBlock
|
6
|
+
include ERB::Util
|
7
|
+
|
8
|
+
# for code_block
|
9
|
+
AllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/i
|
10
|
+
LangCaption = /([^\s]+)\s*(.+)?/i
|
11
|
+
|
12
|
+
# for liquid_code_block
|
13
|
+
CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/i
|
14
|
+
Caption = /(\S[\S\s]*)/
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
# convert ```ruby title ``` like code block
|
19
|
+
def code_block(input)
|
20
|
+
|
21
|
+
input.gsub!(/^`{3} *([^\n]+)?\n(.+?)\n`{3}/m) do
|
22
|
+
caption = nil
|
23
|
+
options = $1 || ''
|
24
|
+
lang = nil
|
25
|
+
str = $2
|
26
|
+
|
27
|
+
if options =~ AllOptions
|
28
|
+
lang = $1
|
29
|
+
caption = "<figcaption><span>#{$2}\n</span><a href='#{$3}'>#{$4 || 'link'}</a></figcaption>"
|
30
|
+
elsif options =~ LangCaption
|
31
|
+
lang = $1
|
32
|
+
caption = "<figcaption><span>#{$2}\n</span></figcaption>"
|
33
|
+
end
|
34
|
+
|
35
|
+
if str.match(/\A( {4}|\t)/)
|
36
|
+
str = str.gsub(/^( {4}|\t)/, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
render_octopress_like_code_block(lang, str, caption, options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def liquid_code_block(input)
|
45
|
+
|
46
|
+
input.gsub!(/^\{\% *codeblock([^\n\}]+)?\%\}.?\n?(.+?)\{\% *endcodeblock *\%\}/m) do
|
47
|
+
caption = nil
|
48
|
+
options = $1
|
49
|
+
str = $2
|
50
|
+
lang = nil
|
51
|
+
|
52
|
+
if options =~ /\s*lang:(\S+)/i
|
53
|
+
lang = $1
|
54
|
+
options = options.sub(/\s*lang:(\S+)/i,'')
|
55
|
+
end
|
56
|
+
|
57
|
+
if options =~ CaptionUrlTitle
|
58
|
+
file = $1
|
59
|
+
caption = "<figcaption><span>#{$1}\n</span><a href='#{$2}'>#{$3 || 'link'}</a></figcaption>"
|
60
|
+
elsif options =~ Caption
|
61
|
+
file = $1
|
62
|
+
caption = "<figcaption><span>#{$1}\n</span></figcaption>"
|
63
|
+
end
|
64
|
+
if file =~ /\S[\S\s]*\w+\.(\w+)/ && lang.nil?
|
65
|
+
lang = $1
|
66
|
+
end
|
67
|
+
|
68
|
+
if str.match(/\A( {4}|\t)/)
|
69
|
+
str = str.gsub(/^( {4}|\t)/, '')
|
70
|
+
end
|
71
|
+
|
72
|
+
render_octopress_like_code_block(lang, str, caption, options)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def render_octopress_like_code_block(lang, str, caption, options)
|
78
|
+
if is_rss
|
79
|
+
code = block_code(str, "text")
|
80
|
+
"<figure class='figure-code code'>#{caption}#{code}</figure>"
|
81
|
+
elsif lang.nil? || lang == 'plain'
|
82
|
+
code = block_code(str, nil)
|
83
|
+
"<figure class='figure-code code'>#{caption}#{code}</figure>"
|
84
|
+
elsif lang == 'mathjax'
|
85
|
+
"<script type=\"math/tex; mode=display\">#{str}</script>"
|
86
|
+
else
|
87
|
+
if lang.include? "-raw"
|
88
|
+
raw = "``` #{options.sub('-raw', '')}\n"
|
89
|
+
raw += str
|
90
|
+
raw += "\n```\n"
|
91
|
+
else
|
92
|
+
code = block_code(str, lang)
|
93
|
+
"<figure class='figure-code code'>#{caption}#{code}</figure>"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
def block_code(code, language)
|
101
|
+
Pygments.highlight(code, :lexer => language)
|
102
|
+
rescue => e
|
103
|
+
return Pygments.highlight(code, :lexer => nil)
|
104
|
+
end
|
105
|
+
|
106
|
+
def codespan(code)
|
107
|
+
return "" if !code
|
108
|
+
|
109
|
+
if code[0] == "$" && code[-1] == "$"
|
110
|
+
code.gsub!(/^\$/,'')
|
111
|
+
code.gsub!(/\$$/,'')
|
112
|
+
"<script type=\"math/tex\">#{code}</script>"
|
113
|
+
else
|
114
|
+
"<code>#{ERB::Util.html_escape(code)}</code>"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module UltraMarkdown
|
3
|
+
module Filter
|
4
|
+
module GistTag
|
5
|
+
|
6
|
+
def script_url_for(gist_id, filename)
|
7
|
+
url = "https://gist.github.com/#{gist_id}.js"
|
8
|
+
url = "#{url}?file=#{filename}" unless filename.nil? or filename.empty?
|
9
|
+
url
|
10
|
+
end
|
11
|
+
|
12
|
+
def gist_tag(input)
|
13
|
+
input.gsub!(/^\{\% *gist ([^\n\}]+)\%\}/m) do
|
14
|
+
markup = $1
|
15
|
+
|
16
|
+
if markup =~ /([a-zA-Z\d]*) (.*)/
|
17
|
+
gist = $1
|
18
|
+
file = $2.strip if $2
|
19
|
+
|
20
|
+
script_url = script_url_for(gist, file)
|
21
|
+
|
22
|
+
"<script src='#{script_url}'> </script>"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module UltraMarkdown
|
3
|
+
module Filter
|
4
|
+
module ImageTag
|
5
|
+
def liquid_image_tag(input)
|
6
|
+
attributes = ['class', 'src', 'width', 'height', 'title']
|
7
|
+
img = nil
|
8
|
+
|
9
|
+
|
10
|
+
input.gsub!(/^\{\% *img ([^\n\}]+)\%\}/m) do
|
11
|
+
markup = $1
|
12
|
+
|
13
|
+
if markup =~ /(?<class>\S.*\s+)?(?<src>(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?<width>\d+))?(?:\s+(?<height>\d+))?(?<title>\s+.+)?/i
|
14
|
+
img = attributes.reduce({}) { |img_temp, attr| img_temp[attr] = $~[attr].strip if $~[attr]; img_temp }
|
15
|
+
if /(?:"|')(?<title>[^"']+)?(?:"|')\s+(?:"|')(?<alt>[^"']+)?(?:"|')/ =~ img['title']
|
16
|
+
img['title'] = title
|
17
|
+
img['alt'] = alt
|
18
|
+
else
|
19
|
+
if img['title']
|
20
|
+
img['title'].gsub!(/"/, '"')
|
21
|
+
img['alt'] = img['title']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
img['class'].gsub!(/"/, '') if img['class']
|
25
|
+
end
|
26
|
+
|
27
|
+
"<img #{img.collect {|k,v| "#{k}=\"#{v}\"" if v}.join(" ")}>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module UltraMarkdown
|
3
|
+
module Filter
|
4
|
+
module ResultSanitize
|
5
|
+
|
6
|
+
ScriptTransformer = lambda do |env|
|
7
|
+
node = env[:node]
|
8
|
+
node_name = env[:node_name]
|
9
|
+
|
10
|
+
return if env[:is_whitelisted] || !node.element?
|
11
|
+
return if node_name != 'script'
|
12
|
+
|
13
|
+
is_not_mathtex = node[:type] != "math/tex; mode=display"
|
14
|
+
is_not_gist = (node['src'] =~ /\Ahttps:\/\/(?:gist\.)?github(?:-nocookie)?\.com\//) == nil
|
15
|
+
is_not_speakerdeck = (node['src'] =~ /\A(https?:)?\/\/(?:www\.)?speakerdeck(?:-nocookie)?\.com\//) == nil
|
16
|
+
|
17
|
+
return if is_not_mathtex && is_not_gist && is_not_speakerdeck
|
18
|
+
|
19
|
+
{:node_whitelist => [node]}
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
CommentTransformer = lambda do |env|
|
24
|
+
node = env[:node]
|
25
|
+
node_name = env[:node_name]
|
26
|
+
|
27
|
+
return if env[:is_whitelisted]
|
28
|
+
return if node_name != 'comment'
|
29
|
+
|
30
|
+
is_not_more = (node.content =~ /^\s*more\s*$/i) == nil
|
31
|
+
|
32
|
+
return if is_not_more
|
33
|
+
|
34
|
+
{:node_whitelist => [node]}
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
SanitizeSetting = {
|
42
|
+
:elements => %w[
|
43
|
+
a abbr b bdo blockquote br caption cite code col colgroup dd del dfn dl
|
44
|
+
dt em figcaption figure h1 h2 h3 h4 h5 h6 hgroup i img ins kbd li mark
|
45
|
+
ol p pre q rp rt ruby s samp small strike strong sub sup table tbody td
|
46
|
+
tfoot th thead time tr u ul var wbr span iframe hr
|
47
|
+
],
|
48
|
+
|
49
|
+
:attributes => {
|
50
|
+
:all => ['dir', 'lang', 'title', 'class'],
|
51
|
+
'a' => ['href'],
|
52
|
+
'blockquote' => ['cite'],
|
53
|
+
'col' => ['span', 'width'],
|
54
|
+
'colgroup' => ['span', 'width'],
|
55
|
+
'del' => ['cite', 'datetime'],
|
56
|
+
'img' => ['align', 'alt', 'height', 'src', 'width'],
|
57
|
+
'ins' => ['cite', 'datetime'],
|
58
|
+
'ol' => ['start', 'reversed', 'type'],
|
59
|
+
'q' => ['cite'],
|
60
|
+
'table' => ['summary', 'width'],
|
61
|
+
'td' => ['abbr', 'axis', 'colspan', 'rowspan', 'width'],
|
62
|
+
'th' => ['abbr', 'axis', 'colspan', 'rowspan', 'scope', 'width'],
|
63
|
+
'time' => ['datetime', 'pubdate'],
|
64
|
+
'ul' => ['type'],
|
65
|
+
'iframe' => ['allowfullscreen', 'frameborder', 'height', 'src', 'width']
|
66
|
+
},
|
67
|
+
|
68
|
+
:protocols => {
|
69
|
+
'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]},
|
70
|
+
'blockquote' => {'cite' => ['http', 'https', :relative]},
|
71
|
+
'del' => {'cite' => ['http', 'https', :relative]},
|
72
|
+
'img' => {'src' => ['http', 'https', :relative]},
|
73
|
+
'ins' => {'cite' => ['http', 'https', :relative]},
|
74
|
+
'q' => {'cite' => ['http', 'https', :relative]}
|
75
|
+
},
|
76
|
+
|
77
|
+
:transformers => [
|
78
|
+
ScriptTransformer,
|
79
|
+
CommentTransformer
|
80
|
+
]
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
def self.clean(str)
|
85
|
+
Sanitize.clean(str, SanitizeSetting)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'rails'
|
3
|
+
require 'rails_autolink'
|
4
|
+
require 'redcarpet'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
|
8
|
+
module Redcarpet
|
9
|
+
module Render
|
10
|
+
class HTMLwithSyntaxHighlight < HTML
|
11
|
+
|
12
|
+
def initialize(extensions={})
|
13
|
+
@syntax_converter = UltraMarkdown::SyntaxConverter.new({:is_rss => is_rss})
|
14
|
+
|
15
|
+
|
16
|
+
super(extensions.merge(
|
17
|
+
:xhtml => true,
|
18
|
+
:no_styles => true,
|
19
|
+
:filter_html => false,
|
20
|
+
:hard_wrap => true
|
21
|
+
))
|
22
|
+
end
|
23
|
+
|
24
|
+
def preprocess(full_document)
|
25
|
+
@syntax_converter.convert_bbcode_img(full_document)
|
26
|
+
@syntax_converter.code_block(full_document)
|
27
|
+
@syntax_converter.liquid_code_block(full_document)
|
28
|
+
@syntax_converter.liquid_image_tag(full_document)
|
29
|
+
@syntax_converter.liquid_blockquote(full_document)
|
30
|
+
@syntax_converter.gist_tag(full_document)
|
31
|
+
|
32
|
+
full_document
|
33
|
+
end
|
34
|
+
|
35
|
+
def postprocess(full_document)
|
36
|
+
full_document
|
37
|
+
end
|
38
|
+
|
39
|
+
def block_code(code, language)
|
40
|
+
@syntax_converter.render_octopress_like_code_block(language, code, nil, nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
def codespan(code)
|
44
|
+
@syntax_converter.codespan(code)
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def autolink(link, link_type)
|
49
|
+
# return link
|
50
|
+
if link_type.to_s == "email"
|
51
|
+
ActionController::Base.helpers.mail_to(link, nil, :encode => :hex)
|
52
|
+
else
|
53
|
+
begin
|
54
|
+
# 防止 C 的 autolink 出來的內容有編碼錯誤,萬一有就直接跳過轉換
|
55
|
+
# 比如這句:
|
56
|
+
# 此版本並非線上的http://yavaeye.com的源碼.
|
57
|
+
link.match(/.+?/)
|
58
|
+
rescue
|
59
|
+
return link
|
60
|
+
end
|
61
|
+
# Fix Chinese neer the URL
|
62
|
+
bad_text = link.match(/[^\w:\/\-\~\,\$\!\.=\?&#+\|\%]+/im).to_s
|
63
|
+
link.gsub!(bad_text, '')
|
64
|
+
"<a href=\"#{link}\" rel=\"nofollow\" target=\"_blank\">#{link}</a>#{bad_text}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Topic 裡面,所有的 head 改為 h2 顯示
|
69
|
+
def header(text, header_level)
|
70
|
+
header_level += 1
|
71
|
+
"<h#{header_level}>#{text}</h#{header_level}>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
class HTMLforPost < Redcarpet::Render::HTMLwithSyntaxHighlight
|
80
|
+
def is_rss
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class HTMLforRSS < Redcarpet::Render::HTMLwithSyntaxHighlight
|
86
|
+
def is_rss
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module UltraMarkdown
|
3
|
+
module MarkdownSnippets
|
4
|
+
UL = <<-EOS
|
5
|
+
- item
|
6
|
+
- item
|
7
|
+
- item
|
8
|
+
EOS
|
9
|
+
|
10
|
+
OL = <<-EOS
|
11
|
+
1. item
|
12
|
+
2. item
|
13
|
+
3. item
|
14
|
+
EOS
|
15
|
+
|
16
|
+
BLOCKQUOTE = <<-EOS
|
17
|
+
> Quotation
|
18
|
+
EOS
|
19
|
+
|
20
|
+
|
21
|
+
MORE = <<-EOS
|
22
|
+
<!--more-->
|
23
|
+
EOS
|
24
|
+
|
25
|
+
|
26
|
+
MORE_REGEX = /<!--\s*more\s*-->/i
|
27
|
+
|
28
|
+
MATHJAX = <<-EOS
|
29
|
+
```mathjax
|
30
|
+
|
31
|
+
```
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require "ultra_markdown/filter/bbcode_image"
|
3
|
+
require "ultra_markdown/filter/block_quote"
|
4
|
+
require "ultra_markdown/filter/code_block"
|
5
|
+
require "ultra_markdown/filter/gist_tag"
|
6
|
+
require "ultra_markdown/filter/image_tag"
|
7
|
+
require "ultra_markdown/filter/result_sanitize"
|
8
|
+
|
9
|
+
module UltraMarkdown
|
10
|
+
class SyntaxConverter
|
11
|
+
include UltraMarkdown::Filter::CodeBlock
|
12
|
+
include UltraMarkdown::Filter::BlockQuote
|
13
|
+
include UltraMarkdown::Filter::BbcodeImage
|
14
|
+
include UltraMarkdown::Filter::ImageTag
|
15
|
+
include UltraMarkdown::Filter::GistTag
|
16
|
+
|
17
|
+
def initialize(options={})
|
18
|
+
@options = options
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_rss
|
22
|
+
if !@options[:is_rss]
|
23
|
+
return false
|
24
|
+
else
|
25
|
+
return @options[:is_rss]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ultra_markdown/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ultra_markdown"
|
8
|
+
spec.version = UltraMarkdown::VERSION
|
9
|
+
spec.authors = ["tonilin","xdite"]
|
10
|
+
spec.email = ["tonilin@gmail.com", "xuite.joke@gmail.com"]
|
11
|
+
spec.description = %q{Markdown Parser for various purposes}
|
12
|
+
spec.summary = %q{Markdown Parser for various purposes}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'nokogiri'
|
22
|
+
spec.add_dependency 'redcarpet'
|
23
|
+
spec.add_dependency 'airbrake'
|
24
|
+
spec.add_dependency 'rails_autolink'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
.code .c { color: #586E75 } /* Comment */
|
2
|
+
.code .err { color: #93A1A1 } /* Error */
|
3
|
+
.code .g { color: #93A1A1 } /* Generic */
|
4
|
+
.code .k { color: #859900 } /* Keyword */
|
5
|
+
.code .l { color: #93A1A1 } /* Literal */
|
6
|
+
.code .n { color: #93A1A1 } /* Name */
|
7
|
+
.code .o { color: #859900 } /* Operator */
|
8
|
+
.code .x { color: #CB4B16 } /* Other */
|
9
|
+
.code .p { color: #93A1A1 } /* Punctuation */
|
10
|
+
.code .cm { color: #586E75 } /* Comment.Multiline */
|
11
|
+
.code .cp { color: #859900 } /* Comment.Preproc */
|
12
|
+
.code .c1 { color: #586E75 } /* Comment.Single */
|
13
|
+
.code .cs { color: #859900 } /* Comment.Special */
|
14
|
+
.code .gd { color: #2AA198 } /* Generic.Deleted */
|
15
|
+
.code .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */
|
16
|
+
.code .gr { color: #DC322F } /* Generic.Error */
|
17
|
+
.code .gh { color: #CB4B16 } /* Generic.Heading */
|
18
|
+
.code .gi { color: #859900 } /* Generic.Inserted */
|
19
|
+
.code .go { color: #93A1A1 } /* Generic.Output */
|
20
|
+
.code .gp { color: #93A1A1 } /* Generic.Prompt */
|
21
|
+
.code .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */
|
22
|
+
.code .gu { color: #CB4B16 } /* Generic.Subheading */
|
23
|
+
.code .gt { color: #93A1A1 } /* Generic.Traceback */
|
24
|
+
.code .kc { color: #CB4B16 } /* Keyword.Constant */
|
25
|
+
.code .kd { color: #268BD2 } /* Keyword.Declaration */
|
26
|
+
.code .kn { color: #859900 } /* Keyword.Namespace */
|
27
|
+
.code .kp { color: #859900 } /* Keyword.Pseudo */
|
28
|
+
.code .kr { color: #268BD2 } /* Keyword.Reserved */
|
29
|
+
.code .kt { color: #DC322F } /* Keyword.Type */
|
30
|
+
.code .ld { color: #93A1A1 } /* Literal.Date */
|
31
|
+
.code .m { color: #2AA198 } /* Literal.Number */
|
32
|
+
.code .s { color: #2AA198 } /* Literal.String */
|
33
|
+
.code .na { color: #93A1A1 } /* Name.Attribute */
|
34
|
+
.code .nb { color: #B58900 } /* Name.Builtin */
|
35
|
+
.code .nc { color: #268BD2 } /* Name.Class */
|
36
|
+
.code .no { color: #CB4B16 } /* Name.Constant */
|
37
|
+
.code .nd { color: #268BD2 } /* Name.Decorator */
|
38
|
+
.code .ni { color: #CB4B16 } /* Name.Entity */
|
39
|
+
.code .ne { color: #CB4B16 } /* Name.Exception */
|
40
|
+
.code .nf { color: #268BD2 } /* Name.Function */
|
41
|
+
.code .nl { color: #93A1A1 } /* Name.Label */
|
42
|
+
.code .nn { color: #93A1A1 } /* Name.Namespace */
|
43
|
+
.code .nx { color: #93A1A1 } /* Name.Other */
|
44
|
+
.code .py { color: #93A1A1 } /* Name.Property */
|
45
|
+
.code .nt { color: #268BD2 } /* Name.Tag */
|
46
|
+
.code .nv { color: #268BD2 } /* Name.Variable */
|
47
|
+
.code .ow { color: #859900 } /* Operator.Word */
|
48
|
+
.code .w { color: #93A1A1 } /* Text.Whitespace */
|
49
|
+
.code .mf { color: #2AA198 } /* Literal.Number.Float */
|
50
|
+
.code .mh { color: #2AA198 } /* Literal.Number.Hex */
|
51
|
+
.code .mi { color: #2AA198 } /* Literal.Number.Integer */
|
52
|
+
.code .mo { color: #2AA198 } /* Literal.Number.Oct */
|
53
|
+
.code .sb { color: #586E75 } /* Literal.String.Backtick */
|
54
|
+
.code .sc { color: #2AA198 } /* Literal.String.Char */
|
55
|
+
.code .sd { color: #93A1A1 } /* Literal.String.Doc */
|
56
|
+
.code .s2 { color: #2AA198 } /* Literal.String.Double */
|
57
|
+
.code .se { color: #CB4B16 } /* Literal.String.Escape */
|
58
|
+
.code .sh { color: #93A1A1 } /* Literal.String.Heredoc */
|
59
|
+
.code .si { color: #2AA198 } /* Literal.String.Interpol */
|
60
|
+
.code .sx { color: #2AA198 } /* Literal.String.Other */
|
61
|
+
.code .sr { color: #DC322F } /* Literal.String.Regex */
|
62
|
+
.code .s1 { color: #2AA198 } /* Literal.String.Single */
|
63
|
+
.code .ss { color: #2AA198 } /* Literal.String.Symbol */
|
64
|
+
.code .bp { color: #268BD2 } /* Name.Builtin.Pseudo */
|
65
|
+
.code .vc { color: #268BD2 } /* Name.Variable.Class */
|
66
|
+
.code .vg { color: #268BD2 } /* Name.Variable.Global */
|
67
|
+
.code .vi { color: #268BD2 } /* Name.Variable.Instance */
|
68
|
+
.code .il { color: #2AA198 } /* Literal.Number.Integer.Long */
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ultra_markdown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- tonilin
|
9
|
+
- xdite
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-12-19 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: redcarpet
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: airbrake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rails_autolink
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: bundler
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ~>
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '1.3'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '1.3'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rake
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Markdown Parser for various purposes
|
112
|
+
email:
|
113
|
+
- tonilin@gmail.com
|
114
|
+
- xuite.joke@gmail.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- lib/ultra_markdown.rb
|
125
|
+
- lib/ultra_markdown/engine.rb
|
126
|
+
- lib/ultra_markdown/engine3.rb
|
127
|
+
- lib/ultra_markdown/filter/bbcode_image.rb
|
128
|
+
- lib/ultra_markdown/filter/block_quote.rb
|
129
|
+
- lib/ultra_markdown/filter/code_block.rb
|
130
|
+
- lib/ultra_markdown/filter/gist_tag.rb
|
131
|
+
- lib/ultra_markdown/filter/image_tag.rb
|
132
|
+
- lib/ultra_markdown/filter/result_sanitize.rb
|
133
|
+
- lib/ultra_markdown/markdown_processor.rb
|
134
|
+
- lib/ultra_markdown/markdown_snippets.rb
|
135
|
+
- lib/ultra_markdown/railtie.rb
|
136
|
+
- lib/ultra_markdown/syntax_convertor.rb
|
137
|
+
- lib/ultra_markdown/version.rb
|
138
|
+
- ultra_markdown.gemspec
|
139
|
+
- vendor/assets/stylesheets/solarized.css
|
140
|
+
homepage: ''
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
requirements: []
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 1.8.25
|
162
|
+
signing_key:
|
163
|
+
specification_version: 3
|
164
|
+
summary: Markdown Parser for various purposes
|
165
|
+
test_files: []
|
166
|
+
has_rdoc:
|