ultra_markdown 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 ![alt](url)
|
7
|
+
def convert_bbcode_img(text)
|
8
|
+
text.gsub!(/\[img\](.+?)\[\/img\]/i) {"![#{image_alt $1}](#{$1})"}
|
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:
|