bluedoc-sml 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![CircleCI](https://circleci.com/gh/bluedoc-org/bluedoc-sml/tree/master.svg?style=shield&circle-token=231806e2ce24e58a85190a0cd167b7d2da27c0b9)](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: []
|