bluedoc-sml 0.5.2
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +30 -0
- data/lib/bluedoc-sml.rb +15 -0
- data/lib/bluedoc/plantuml.rb +53 -0
- data/lib/bluedoc/sml/base.rb +12 -0
- data/lib/bluedoc/sml/config.rb +8 -0
- data/lib/bluedoc/sml/renderer.rb +68 -0
- data/lib/bluedoc/sml/rules.rb +25 -0
- data/lib/bluedoc/sml/rules/base.rb +70 -0
- data/lib/bluedoc/sml/rules/blockquote.rb +18 -0
- data/lib/bluedoc/sml/rules/br.rb +13 -0
- data/lib/bluedoc/sml/rules/codeblock.rb +25 -0
- data/lib/bluedoc/sml/rules/file.rb +32 -0
- data/lib/bluedoc/sml/rules/heading.rb +27 -0
- data/lib/bluedoc/sml/rules/hr.rb +13 -0
- data/lib/bluedoc/sml/rules/image.rb +25 -0
- data/lib/bluedoc/sml/rules/link.rb +18 -0
- data/lib/bluedoc/sml/rules/list.rb +86 -0
- data/lib/bluedoc/sml/rules/math.rb +22 -0
- data/lib/bluedoc/sml/rules/paragraph.rb +19 -0
- data/lib/bluedoc/sml/rules/plantuml.rb +20 -0
- data/lib/bluedoc/sml/rules/root.rb +14 -0
- data/lib/bluedoc/sml/rules/span.rb +16 -0
- data/lib/bluedoc/sml/rules/span_with_mark.rb +47 -0
- data/lib/bluedoc/sml/rules/table.rb +16 -0
- data/lib/bluedoc/sml/rules/td.rb +19 -0
- data/lib/bluedoc/sml/rules/text.rb +13 -0
- data/lib/bluedoc/sml/rules/tr.rb +16 -0
- data/lib/bluedoc/sml/rules/video.rb +32 -0
- data/lib/bluedoc/sml/utils.rb +45 -0
- data/lib/bluedoc/sml/version.rb +7 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 40d3fbabc52157a7a48ee82bea31d367c8f9bc58bdac3306c273ac21ee6d24a8
|
4
|
+
data.tar.gz: e2d7b3f1e44cf5b1d574ba1f3d1342d0f618950ab999fc9dbf06f73fd3377289
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7751835475a13fecb9fc8ca6d32163a020cd16a271123941b9a393e2da99cc04b25eab2621ed869f1cc8fe74f6b52bcef87a9e9cdc8b4c366369611552e295ee
|
7
|
+
data.tar.gz: c1fbc2dc08ef51738ba72ec656ffdc923c10aad6abea0ce5959c5d9b6357c7081976f62db8d71106641995913d2e5bffd41a588186320a76ae774b5f536f59f6
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Jason Lee
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# BlueDoc::SML
|
2
|
+
|
3
|
+
[](https://circleci.com/gh/bluedoc-org/bluedoc-sml/tree/master)
|
4
|
+
|
5
|
+
SML __(Slate markup language)__ is a rich text format for describe of the BlueDoc rich contents.
|
6
|
+
|
7
|
+
It base on [JsonML](http://jsonml.org) format, and including custom DSL.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```rb
|
12
|
+
gem "bluedoc-sml"
|
13
|
+
```
|
14
|
+
|
15
|
+
and then run `bundle install`
|
16
|
+
|
17
|
+
```rb
|
18
|
+
$ sml = %(["p", { align: "center", indent: 1 }, "Hello world"])
|
19
|
+
$ renderer = BlueDoc::SML.parse(sml)
|
20
|
+
$ renderer.to_html
|
21
|
+
=> <p style="text-align: center; text-indent: 32px;">Hello world</p>
|
22
|
+
$ renderer.to_text
|
23
|
+
=> "Hello world"
|
24
|
+
```
|
25
|
+
|
26
|
+
## License
|
27
|
+
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "bundler/setup"
|
5
|
+
rescue LoadError
|
6
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
7
|
+
end
|
8
|
+
|
9
|
+
require "rdoc/task"
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = "rdoc"
|
13
|
+
rdoc.title = "Jsonml"
|
14
|
+
rdoc.options << "--line-numbers"
|
15
|
+
rdoc.rdoc_files.include("README.md")
|
16
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
17
|
+
end
|
18
|
+
|
19
|
+
require "bundler/gem_tasks"
|
20
|
+
|
21
|
+
require "rake/testtask"
|
22
|
+
|
23
|
+
Rake::TestTask.new(:test) do |t|
|
24
|
+
t.libs << "test"
|
25
|
+
t.pattern = "test/**/*_test.rb"
|
26
|
+
t.verbose = false
|
27
|
+
t.warning = false
|
28
|
+
end
|
29
|
+
|
30
|
+
task default: :test
|
data/lib/bluedoc-sml.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "bluedoc/plantuml"
|
5
|
+
require "bluedoc/sml/version"
|
6
|
+
require "bluedoc/sml/utils"
|
7
|
+
require "bluedoc/sml/rules"
|
8
|
+
require "bluedoc/sml/config"
|
9
|
+
require "bluedoc/sml/renderer"
|
10
|
+
require "bluedoc/sml/base"
|
11
|
+
|
12
|
+
module BlueDoc
|
13
|
+
module SML
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "zlib"
|
2
|
+
|
3
|
+
module BlueDoc
|
4
|
+
class Plantuml
|
5
|
+
class << self
|
6
|
+
def encode(text)
|
7
|
+
result = ""
|
8
|
+
compressedData = Zlib::Deflate.deflate(text)
|
9
|
+
compressedData.chars.each_slice(3) do |bytes|
|
10
|
+
#print bytes[0], ' ' , bytes[1] , ' ' , bytes[2]
|
11
|
+
b1 = bytes[0].nil? ? 0 : (bytes[0].ord & 0xFF)
|
12
|
+
b2 = bytes[1].nil? ? 0 : (bytes[1].ord & 0xFF)
|
13
|
+
b3 = bytes[2].nil? ? 0 : (bytes[2].ord & 0xFF)
|
14
|
+
result += append3bytes(b1, b2, b3)
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def append3bytes(b1, b2, b3)
|
20
|
+
c1 = b1 >> 2
|
21
|
+
c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
|
22
|
+
c3 = ((b2 & 0xF) << 2) | (b3 >> 6)
|
23
|
+
c4 = b3 & 0x3F
|
24
|
+
return encode6bit(c1 & 0x3F).chr +
|
25
|
+
encode6bit(c2 & 0x3F).chr +
|
26
|
+
encode6bit(c3 & 0x3F).chr +
|
27
|
+
encode6bit(c4 & 0x3F).chr
|
28
|
+
end
|
29
|
+
|
30
|
+
def encode6bit(b)
|
31
|
+
if b < 10
|
32
|
+
return ('0'.ord + b).chr
|
33
|
+
end
|
34
|
+
b = b - 10
|
35
|
+
if b < 26
|
36
|
+
return ('A'.ord + b).chr
|
37
|
+
end
|
38
|
+
b = b - 26
|
39
|
+
if b < 26
|
40
|
+
return ('a'.ord + b).chr
|
41
|
+
end
|
42
|
+
b = b - 26
|
43
|
+
if b == 0
|
44
|
+
return '-'
|
45
|
+
end
|
46
|
+
if b == 1
|
47
|
+
return '_'
|
48
|
+
end
|
49
|
+
return '?'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext"
|
4
|
+
|
5
|
+
module BlueDoc::SML
|
6
|
+
class Renderer
|
7
|
+
include BlueDoc::SML::Utils
|
8
|
+
|
9
|
+
attr_accessor :sml, :value, :config
|
10
|
+
|
11
|
+
# For table, list for temp mark in block
|
12
|
+
attr_accessor :in_block
|
13
|
+
|
14
|
+
def initialize(sml, options)
|
15
|
+
@sml = sml
|
16
|
+
@config = Config.new
|
17
|
+
@config.plantuml_service_host = options[:plantuml_service_host]
|
18
|
+
@config.mathjax_service_host = options[:mathjax_service_host]
|
19
|
+
@value = YAML.load(sml)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_html
|
23
|
+
node_to_html(self.value)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
to_html
|
28
|
+
end
|
29
|
+
|
30
|
+
def node_to_html(node, opts = {})
|
31
|
+
opts[:renderer] = self
|
32
|
+
|
33
|
+
rule = BlueDoc::SML::Rules::find_by_node(node)
|
34
|
+
rule.to_html(node, opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
def children_to_html(node)
|
38
|
+
return node if node.is_a?(String)
|
39
|
+
|
40
|
+
children = self.class.get_children(node)
|
41
|
+
children.each_with_index.map do |child, idx|
|
42
|
+
prev_node = idx > 0 ? children[idx - 1] : nil
|
43
|
+
next_node = idx < children.length ? children[idx + 1] : nil
|
44
|
+
|
45
|
+
node_to_html(child, prev: prev_node, next: next_node)
|
46
|
+
end.join("")
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_text
|
50
|
+
node_to_text(self.value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def node_to_text(node, opts = {})
|
54
|
+
opts[:renderer] = self
|
55
|
+
rule = BlueDoc::SML::Rules::find_by_node(node)
|
56
|
+
rule.to_text(node, opts)&.strip
|
57
|
+
end
|
58
|
+
|
59
|
+
def children_to_text(node)
|
60
|
+
return node if node.is_a?(String)
|
61
|
+
children = self.class.get_children(node)
|
62
|
+
children.each_with_index.map do |child, idx|
|
63
|
+
text = node_to_text(child, {})
|
64
|
+
text.blank? ? nil : text
|
65
|
+
end.compact.join(" ")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bluedoc/sml/rules/base"
|
4
|
+
|
5
|
+
module BlueDoc::SML
|
6
|
+
module Rules
|
7
|
+
def self.all
|
8
|
+
return @rules if defined? @rules
|
9
|
+
rules = []
|
10
|
+
Dir.glob(::File.expand_path("rules/*.rb", __dir__)).each do |path|
|
11
|
+
rule_name = ::File.basename(path, ".rb")
|
12
|
+
require "bluedoc/sml/rules/#{rule_name}"
|
13
|
+
|
14
|
+
next if rule_name == "base"
|
15
|
+
rules << "BlueDoc::SML::Rules::#{rule_name.classify}".constantize
|
16
|
+
end
|
17
|
+
@rules = rules
|
18
|
+
@rules
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_by_node(node)
|
22
|
+
all.find { |rule| rule.match?(node) } || BlueDoc::SML::Rules::Base
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "escape_utils"
|
4
|
+
|
5
|
+
module BlueDoc::SML::Rules
|
6
|
+
class SyntaxError < Exception; end
|
7
|
+
|
8
|
+
class Base
|
9
|
+
include BlueDoc::SML::Utils
|
10
|
+
|
11
|
+
INDENT_PX = 8
|
12
|
+
|
13
|
+
class << self
|
14
|
+
include EscapeUtils
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def self.match?(node)
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.to_html(node, opts = {})
|
23
|
+
children = opts[:renderer].children_to_html(node)
|
24
|
+
tag = tag_name(node)
|
25
|
+
%(<#{tag}>#{children}</#{tag}>)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_text(node, opts = {})
|
29
|
+
opts[:renderer].children_to_text(node)
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
def self.style_for_attrs(attrs, style = {})
|
34
|
+
attrs ||= {}
|
35
|
+
if attrs[:align]
|
36
|
+
style["text-align"] = attrs[:align]
|
37
|
+
end
|
38
|
+
|
39
|
+
if attrs[:indent]
|
40
|
+
if attrs[:indent].is_a?(Hash)
|
41
|
+
# text-indent
|
42
|
+
text_indent = attrs.dig(:indent, :firstline)
|
43
|
+
style["text-indent"] = "#{4 * INDENT_PX}px" if text_indent && text_indent > 0
|
44
|
+
|
45
|
+
# padding-left
|
46
|
+
indent_left = attrs.dig(:indent, :left)
|
47
|
+
style["padding-left"] = "#{indent_left * INDENT_PX}px" if indent_left && indent_left > 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
props = css_attrs(style)
|
52
|
+
return "" if props.strip.blank?
|
53
|
+
%( style="#{props}")
|
54
|
+
rescue => e
|
55
|
+
""
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.css_attrs(style)
|
59
|
+
style.map { |k, v| "#{k}: #{v};" }.join(" ")
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.html_attrs(attrs)
|
63
|
+
attrs[:width] = nil if attrs[:width].to_i == 0
|
64
|
+
attrs[:height] = nil if attrs[:height].to_i == 0
|
65
|
+
|
66
|
+
props = attrs.map { |k, v| v.present? ? %(#{k}="#{v}") : nil }.compact.join(" ")
|
67
|
+
%( #{props})
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Blockquote < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "blockquote"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
attrs = attributes(node)
|
12
|
+
|
13
|
+
children = renderer.children_to_html(node)
|
14
|
+
|
15
|
+
%(<blockquote>#{children}</blockquote>)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rouge"
|
4
|
+
require "rouge/plugins/redcarpet"
|
5
|
+
|
6
|
+
module BlueDoc::SML::Rules
|
7
|
+
class Codeblock < Base
|
8
|
+
class << self
|
9
|
+
include Rouge::Plugins::Redcarpet
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.match?(node)
|
13
|
+
tag_name(node) == "codeblock"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.to_html(node, opts = {})
|
17
|
+
attrs = attributes(node)
|
18
|
+
|
19
|
+
language = attrs[:language]
|
20
|
+
code = attrs[:code] || ""
|
21
|
+
|
22
|
+
block_code(code, language)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class File < Base
|
5
|
+
class << self
|
6
|
+
include ActiveSupport::NumberHelper
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.match?(node)
|
10
|
+
tag_name(node) == "file"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.to_html(node, opts = {})
|
14
|
+
attrs = attributes(node)
|
15
|
+
attrs[:name] ||= ""
|
16
|
+
|
17
|
+
return attrs[:name] if attrs[:src].blank?
|
18
|
+
|
19
|
+
humanize_size = number_to_human_size(attrs[:size] || 0)
|
20
|
+
|
21
|
+
out = <<~HTML
|
22
|
+
<a class="attachment-file" title="#{attrs[:name]}" target="_blank" href="#{attrs[:src]}">
|
23
|
+
<span class="icon-box"><i class="fas fa-file"></i></span>
|
24
|
+
<span class="filename">#{escape_html(attrs[:name])}</span>
|
25
|
+
<span class="filesize">#{escape_html(humanize_size)}</span>
|
26
|
+
</a>
|
27
|
+
HTML
|
28
|
+
|
29
|
+
out
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest/md5"
|
4
|
+
|
5
|
+
module BlueDoc::SML::Rules
|
6
|
+
class Heading < Base
|
7
|
+
def self.match?(node)
|
8
|
+
%w[h1 h2 h3 h4 h5 h6].include?(tag_name(node))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.to_html(node, opts = {})
|
12
|
+
renderer = opts[:renderer]
|
13
|
+
title = renderer.children_to_html(node) || ""
|
14
|
+
heading_tag = tag_name(node)
|
15
|
+
|
16
|
+
title_length = title.length
|
17
|
+
min_length = title_length * 0.3
|
18
|
+
words_length = /[a-z0-9]/i.match(title)&.length || 0
|
19
|
+
header_id = title.gsub(/[^a-z0-9]+/i, "-").downcase.gsub(/^\-|\-$/, "")
|
20
|
+
if title_length - header_id.length > min_length
|
21
|
+
header_id = Digest::MD5.hexdigest(title.strip)[0..8]
|
22
|
+
end
|
23
|
+
|
24
|
+
%(<#{heading_tag} id="#{header_id}"><a href="##{header_id}" class="heading-anchor">#</a>#{title}</#{heading_tag}>)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Image < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "image"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
attrs = attributes(node)
|
11
|
+
attrs[:name] ||= ""
|
12
|
+
|
13
|
+
return attrs[:name] if attrs[:src].blank?
|
14
|
+
|
15
|
+
attr_html = html_attrs(
|
16
|
+
src: attrs[:src],
|
17
|
+
alt: attrs[:name],
|
18
|
+
width: attrs[:width],
|
19
|
+
height: attrs[:height]
|
20
|
+
)
|
21
|
+
|
22
|
+
%(<img#{attr_html}>)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Link < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "link"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
attrs = attributes(node)
|
12
|
+
name = renderer.children_to_html(node)
|
13
|
+
return name if attrs[:href].blank?
|
14
|
+
|
15
|
+
%(<a href="#{attrs[:href]}" title="#{attrs[:title]}" target="_blank">#{name}</a>)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class List < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "list"
|
7
|
+
end
|
8
|
+
|
9
|
+
INDENT_PX = 8
|
10
|
+
|
11
|
+
def self.to_html(node, opts = {})
|
12
|
+
renderer = opts[:renderer]
|
13
|
+
attrs = attributes(node)
|
14
|
+
children = renderer.children_to_html(node)
|
15
|
+
|
16
|
+
# Normal paragraph data
|
17
|
+
text_align = attrs[:align] || "left"
|
18
|
+
indent = attrs[:indent]
|
19
|
+
text_indent = indent && indent[:firstline]
|
20
|
+
indent_left = indent ? indent[:left] : 0
|
21
|
+
|
22
|
+
# List style
|
23
|
+
nid = attrs[:nid]
|
24
|
+
list_type = attrs[:type] || "bulleted"
|
25
|
+
level = attrs[:level] || 1
|
26
|
+
num = (attrs[:num] || 0) + 1
|
27
|
+
|
28
|
+
style_attrs = style_for_attrs(attrs,
|
29
|
+
"padding-left": "#{indent_left * INDENT_PX}px"
|
30
|
+
)
|
31
|
+
|
32
|
+
wrap_tag = list_type == "bulleted" ? "ul" : "ol"
|
33
|
+
|
34
|
+
|
35
|
+
# <ul>
|
36
|
+
# <li>Bold text</li>
|
37
|
+
# <li>Important text
|
38
|
+
# <ul>
|
39
|
+
# <li>Emphasized text</li>
|
40
|
+
# <li>
|
41
|
+
# Small text
|
42
|
+
# <ul>
|
43
|
+
# <li>Subscript text</li>
|
44
|
+
# </ul>
|
45
|
+
# </li>
|
46
|
+
# </ul>
|
47
|
+
# </li>
|
48
|
+
# </ul>
|
49
|
+
|
50
|
+
# get prev attrs
|
51
|
+
prev_name = tag_name(opts[:prev])
|
52
|
+
next_name = tag_name(opts[:next])
|
53
|
+
prev_level = attributes(opts[:prev])[:level]
|
54
|
+
next_level = attributes(opts[:next])[:level]
|
55
|
+
|
56
|
+
outs = []
|
57
|
+
|
58
|
+
|
59
|
+
if prev_name != "list" || prev_level != level
|
60
|
+
outs << %(<#{wrap_tag} data-level="#{level}">)
|
61
|
+
end
|
62
|
+
|
63
|
+
li_item = "<li>#{children}"
|
64
|
+
|
65
|
+
if next_name == "list"
|
66
|
+
if next_level < level
|
67
|
+
(level - next_level + 1).times do
|
68
|
+
li_item += "</li></#{wrap_tag}>"
|
69
|
+
end
|
70
|
+
elsif next_level == level
|
71
|
+
li_item += "</li>"
|
72
|
+
else
|
73
|
+
li_item += "\n"
|
74
|
+
end
|
75
|
+
else
|
76
|
+
(level - 1 + 1).times do
|
77
|
+
li_item += "</li></#{wrap_tag}>"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
outs << li_item
|
82
|
+
|
83
|
+
outs.join("\n")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Math < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "math"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
attrs = attributes(node)
|
12
|
+
|
13
|
+
code = (attrs[:code] || "").strip
|
14
|
+
return "" if code.blank?
|
15
|
+
|
16
|
+
svg_code = URI::encode(code)
|
17
|
+
src = "#{renderer.config.mathjax_service_host}/svg?tex=#{svg_code}"
|
18
|
+
|
19
|
+
%(<img class="tex-image" src="#{src}">)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Paragraph < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "p"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
children = renderer.children_to_html(node)
|
12
|
+
attrs = attributes(node)
|
13
|
+
|
14
|
+
style_attrs = style_for_attrs(attrs)
|
15
|
+
|
16
|
+
%(<p#{style_attrs}>#{children}</p>)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Plantuml < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "plantuml"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
attrs = attributes(node)
|
11
|
+
renderer = opts[:renderer]
|
12
|
+
|
13
|
+
code = (attrs[:code] || "").strip
|
14
|
+
return "" if code.blank?
|
15
|
+
|
16
|
+
svg_code = BlueDoc::Plantuml.encode(code)
|
17
|
+
%(<img src="#{renderer.config.plantuml_service_host}/svg/#{svg_code}" class="plantuml-image" />)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Root < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "root"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
renderer.children_to_html(node)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Span < Base
|
5
|
+
def self.match?(node)
|
6
|
+
return false unless tag_name(node) == "span"
|
7
|
+
attrs = attributes(node)
|
8
|
+
attrs[:t] == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.to_html(node, opts = {})
|
12
|
+
renderer = opts[:renderer]
|
13
|
+
renderer.children_to_html(node)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class SpanWithMark < Base
|
5
|
+
MARKS = {
|
6
|
+
cd: ["<code>", "</code>"],
|
7
|
+
b: ["<strong>", "</strong>"],
|
8
|
+
i: ["<i>", "</i>"],
|
9
|
+
s: ["<del>", "</del>"],
|
10
|
+
u: ["<u>", "</u>"],
|
11
|
+
m: ["<mark>", "</mark>"],
|
12
|
+
sup: ["<sup>", "</sup>"],
|
13
|
+
sub: ["<sub>", "</sub>"],
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
def self.match?(node)
|
18
|
+
return false unless tag_name(node) == "span"
|
19
|
+
attrs = attributes(node)
|
20
|
+
attrs[:t] == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.to_html(node, opts = {})
|
24
|
+
attrs = attributes(node)
|
25
|
+
renderer = opts[:renderer]
|
26
|
+
if attrs[:cd] == 1
|
27
|
+
children = renderer.children_to_text(node)
|
28
|
+
else
|
29
|
+
children = renderer.children_to_html(node)
|
30
|
+
end
|
31
|
+
|
32
|
+
case attrs[:va]
|
33
|
+
when "superscript" then attrs[:sup] = 1
|
34
|
+
when "subscript" then attrs[:sub] = 1
|
35
|
+
end
|
36
|
+
|
37
|
+
MARKS.each_key do |key|
|
38
|
+
if attrs[key] == 1
|
39
|
+
mark = MARKS[key]
|
40
|
+
children = "#{mark.first}#{children}#{mark.last}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
children
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Table < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "table"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
children = renderer.children_to_html(node)
|
12
|
+
|
13
|
+
%(<table>#{children}</table>)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Td < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "tc"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
attrs = attributes(node)
|
12
|
+
children = renderer.children_to_html(node)
|
13
|
+
|
14
|
+
style = {}
|
15
|
+
style_attrs = style_for_attrs(attrs, style)
|
16
|
+
%(<td#{style_attrs}>#{children}</td>)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Tr < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "tr"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
renderer = opts[:renderer]
|
11
|
+
children = renderer.children_to_html(node)
|
12
|
+
|
13
|
+
%(<tr>#{children}</tr>)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML::Rules
|
4
|
+
class Video < Base
|
5
|
+
def self.match?(node)
|
6
|
+
tag_name(node) == "video"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.to_html(node, opts = {})
|
10
|
+
attrs = attributes(node)
|
11
|
+
|
12
|
+
return "" if attrs[:src].blank?
|
13
|
+
|
14
|
+
width = attrs[:width]
|
15
|
+
if width == 0 || width.blank?
|
16
|
+
width = "100%"
|
17
|
+
end
|
18
|
+
|
19
|
+
video_attrs = html_attrs(
|
20
|
+
width: width
|
21
|
+
)
|
22
|
+
|
23
|
+
out = <<~HTML
|
24
|
+
<video controls preload="no"#{video_attrs}>
|
25
|
+
<source src="#{attrs[:src]}" type="#{attrs[:type]}">
|
26
|
+
</video>
|
27
|
+
HTML
|
28
|
+
|
29
|
+
out
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BlueDoc::SML
|
4
|
+
module Utils
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def get_children(node)
|
9
|
+
has_attributes?(node) ? node[2..-1] : node[1..-1]
|
10
|
+
end
|
11
|
+
|
12
|
+
def tag_name(node)
|
13
|
+
return nil if node.blank?
|
14
|
+
node[0] || ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def attributes(node, add_if_mission: false)
|
18
|
+
return {} if node.blank?
|
19
|
+
return node[1].deep_symbolize_keys if has_attributes?(node)
|
20
|
+
return {} unless add_if_mission
|
21
|
+
|
22
|
+
name = node.shift || ""
|
23
|
+
attrs = {}
|
24
|
+
node.unshift(attrs)
|
25
|
+
node.unshift(name)
|
26
|
+
|
27
|
+
attrs
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_attributes?(node)
|
31
|
+
return false unless element?(node)
|
32
|
+
attributes?(node[1])
|
33
|
+
end
|
34
|
+
|
35
|
+
def attributes?(node)
|
36
|
+
return false if node.nil?
|
37
|
+
node.is_a?(Hash)
|
38
|
+
end
|
39
|
+
|
40
|
+
def element?(node)
|
41
|
+
node.is_a?(Array) && node[0].is_a?(String)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bluedoc-sml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason Lee
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-02-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rouge
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: escape_utils
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: SML is a rich text format for describe of the BlueDoc rich contents,
|
56
|
+
base on [JsonML](http://jsonml.org).
|
57
|
+
email:
|
58
|
+
- huacnlee@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- MIT-LICENSE
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/bluedoc-sml.rb
|
67
|
+
- lib/bluedoc/plantuml.rb
|
68
|
+
- lib/bluedoc/sml/base.rb
|
69
|
+
- lib/bluedoc/sml/config.rb
|
70
|
+
- lib/bluedoc/sml/renderer.rb
|
71
|
+
- lib/bluedoc/sml/rules.rb
|
72
|
+
- lib/bluedoc/sml/rules/base.rb
|
73
|
+
- lib/bluedoc/sml/rules/blockquote.rb
|
74
|
+
- lib/bluedoc/sml/rules/br.rb
|
75
|
+
- lib/bluedoc/sml/rules/codeblock.rb
|
76
|
+
- lib/bluedoc/sml/rules/file.rb
|
77
|
+
- lib/bluedoc/sml/rules/heading.rb
|
78
|
+
- lib/bluedoc/sml/rules/hr.rb
|
79
|
+
- lib/bluedoc/sml/rules/image.rb
|
80
|
+
- lib/bluedoc/sml/rules/link.rb
|
81
|
+
- lib/bluedoc/sml/rules/list.rb
|
82
|
+
- lib/bluedoc/sml/rules/math.rb
|
83
|
+
- lib/bluedoc/sml/rules/paragraph.rb
|
84
|
+
- lib/bluedoc/sml/rules/plantuml.rb
|
85
|
+
- lib/bluedoc/sml/rules/root.rb
|
86
|
+
- lib/bluedoc/sml/rules/span.rb
|
87
|
+
- lib/bluedoc/sml/rules/span_with_mark.rb
|
88
|
+
- lib/bluedoc/sml/rules/table.rb
|
89
|
+
- lib/bluedoc/sml/rules/td.rb
|
90
|
+
- lib/bluedoc/sml/rules/text.rb
|
91
|
+
- lib/bluedoc/sml/rules/tr.rb
|
92
|
+
- lib/bluedoc/sml/rules/video.rb
|
93
|
+
- lib/bluedoc/sml/utils.rb
|
94
|
+
- lib/bluedoc/sml/version.rb
|
95
|
+
homepage: https://bluedoc.org
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubygems_version: 3.0.1
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: SML is a rich text format for describe of the BlueDoc rich contents.
|
118
|
+
test_files: []
|