Almirah 0.1.5 → 0.1.7
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 +4 -4
- data/lib/almirah/doc_fabric.rb +8 -1
- data/lib/almirah/doc_items/heading.rb +40 -29
- data/lib/almirah/doc_items/text_line.rb +243 -113
- data/lib/almirah/doc_types/base_document.rb +3 -1
- data/lib/almirah/dom/doc_section.rb +28 -0
- data/lib/almirah/dom/document.rb +63 -0
- data/lib/almirah/navigation_pane.rb +7 -13
- data/lib/almirah/project.rb +4 -5
- data/lib/almirah/templates/page.html +29 -13
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9e49efacc05e9b7d14bb1aa9acd2797de76395eb7c21ae40242b6319e59a55b
|
4
|
+
data.tar.gz: 6cdba1580e4c9501de9c3e8cf2d1e009a127014a67d0c0fe79d142bb1d8ac662
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62705f4cd221a3964cb579309a09dadcda38688f1df974f026e4957dc3d2380089c690a2b95b7395ec1cdd64eeebb8fdb7ac94f869fb3e348814fba795aec1f6
|
7
|
+
data.tar.gz: 53aa6e81cbe3b3156107e3a71fc3c95e9bc8920dfe1615a43d0a9f2de6f0d04fe4325368b9f5563b2833b7f9dfa1a76186a4df18ec223e8a140ccabae18c6dbd
|
data/lib/almirah/doc_fabric.rb
CHANGED
@@ -17,6 +17,8 @@ require_relative "doc_items/image"
|
|
17
17
|
require_relative "doc_items/markdown_list"
|
18
18
|
require_relative "doc_items/doc_footer"
|
19
19
|
|
20
|
+
require_relative "dom/document"
|
21
|
+
|
20
22
|
class DocFabric
|
21
23
|
|
22
24
|
def self.add_lazy_doc_id(path)
|
@@ -65,6 +67,7 @@ class DocFabric
|
|
65
67
|
|
66
68
|
if level == 1 && doc.title == ""
|
67
69
|
doc.title = value
|
70
|
+
level = 0 # Doc Title is a Root
|
68
71
|
Heading.reset_global_section_number()
|
69
72
|
end
|
70
73
|
|
@@ -82,7 +85,7 @@ class DocFabric
|
|
82
85
|
Heading.reset_global_section_number()
|
83
86
|
end
|
84
87
|
|
85
|
-
item = Heading.new(title,
|
88
|
+
item = Heading.new(title, 0)
|
86
89
|
item.parent_doc = doc
|
87
90
|
doc.items.append(item)
|
88
91
|
doc.headings.append(item)
|
@@ -366,5 +369,9 @@ class DocFabric
|
|
366
369
|
item = DocFooter.new
|
367
370
|
item.parent_doc = doc
|
368
371
|
doc.items.append(item)
|
372
|
+
# Build dom
|
373
|
+
if doc.is_a?(Specification)
|
374
|
+
doc.dom = Document.new(doc.headings)
|
375
|
+
end
|
369
376
|
end
|
370
377
|
end
|
@@ -11,57 +11,68 @@ class Heading < Paragraph
|
|
11
11
|
def initialize(text, level)
|
12
12
|
@text = text
|
13
13
|
@level = level
|
14
|
-
@anchor_id = getTextWithoutSpaces()
|
15
14
|
|
16
|
-
if
|
17
|
-
@@global_section_number
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
if level != 0 # skip Doc Title
|
16
|
+
if @@global_section_number == ""
|
17
|
+
@@global_section_number = "1"
|
18
|
+
for n in 1..(level-1) do
|
19
|
+
@@global_section_number += ".1"
|
20
|
+
end
|
21
|
+
else
|
22
|
+
previous_level = @@global_section_number.split(".").length
|
23
23
|
|
24
|
-
|
24
|
+
if previous_level == level
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
a = @@global_section_number.split(".")
|
27
|
+
a[-1] = (a[-1].to_i() +1).to_s
|
28
|
+
@@global_section_number = a.join(".")
|
29
29
|
|
30
|
-
|
30
|
+
elsif level > previous_level
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
a = @@global_section_number.split(".")
|
33
|
+
a.push("1")
|
34
|
+
@@global_section_number = a.join(".")
|
35
|
+
|
36
|
+
else # level < previous_level
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
a = @@global_section_number.split(".")
|
39
|
+
delta = previous_level - level
|
40
|
+
a.pop(delta)
|
41
|
+
@@global_section_number = a.join(".")
|
42
|
+
# increment
|
43
|
+
a = @@global_section_number.split(".")
|
44
|
+
a[-1] = (a[-1].to_i() +1).to_s
|
45
|
+
@@global_section_number = a.join(".")
|
46
|
+
end
|
46
47
|
end
|
47
48
|
end
|
48
49
|
@section_number = @@global_section_number
|
50
|
+
@anchor_id = get_anchor_text()
|
49
51
|
end
|
50
52
|
|
51
53
|
def get_section_info
|
52
54
|
s = @section_number + " " + @text
|
53
55
|
end
|
54
56
|
|
57
|
+
def get_anchor_text()
|
58
|
+
s = @section_number + "-" + getTextWithoutSpaces()
|
59
|
+
end
|
60
|
+
|
55
61
|
def to_html
|
56
62
|
s = ''
|
57
63
|
if @@htmlTableRenderInProgress
|
58
64
|
s += "</table>\n"
|
59
65
|
@@htmlTableRenderInProgress = false
|
60
66
|
end
|
61
|
-
|
67
|
+
heading_level = level.to_s
|
68
|
+
heading_text = get_section_info()
|
69
|
+
if level == 0
|
70
|
+
heading_level = 1.to_s # Render Doc Title as a regular h1
|
71
|
+
heading_text = @text # Doc Title does not have a section number
|
72
|
+
end
|
62
73
|
s += "<a name=\"#{@anchor_id}\"></a>\n"
|
63
|
-
s += "<h#{
|
64
|
-
s += "¶</a></h#{
|
74
|
+
s += "<h#{heading_level}> #{heading_text} <a href=\"\##{@anchor_id}\" class=\"heading_anchor\">"
|
75
|
+
s += "¶</a></h#{heading_level}>"
|
65
76
|
return s
|
66
77
|
end
|
67
78
|
|
@@ -1,139 +1,270 @@
|
|
1
|
-
class
|
1
|
+
class TextLineToken
|
2
|
+
attr_accessor :value
|
3
|
+
def initialize()
|
4
|
+
@value = ""
|
5
|
+
end
|
6
|
+
end
|
2
7
|
|
3
|
-
|
8
|
+
class ItalicToken < TextLineToken
|
9
|
+
attr_accessor :value
|
10
|
+
def initialize()
|
11
|
+
@value = "*"
|
12
|
+
end
|
13
|
+
end
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
15
|
+
class BoldToken < TextLineToken
|
16
|
+
attr_accessor :value
|
17
|
+
def initialize()
|
18
|
+
@value = "**"
|
8
19
|
end
|
20
|
+
end
|
9
21
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
link_text = ''
|
17
|
-
link_url = ''
|
18
|
-
str.each_char do |c|
|
19
|
-
if c == '*'
|
20
|
-
if state == 'default'
|
21
|
-
prev_state, state = change_state(c, state, 'first_asterisk_detected')
|
22
|
-
|
23
|
-
elsif state == 'first_asterisk_detected'
|
24
|
-
prev_state, state = change_state(c, state, 'second_asterisk_detected')
|
25
|
-
|
26
|
-
elsif state == 'second_asterisk_detected'
|
27
|
-
prev_state, state = change_state(c, state, 'third_asterisk_detected')
|
28
|
-
|
29
|
-
elsif state == 'second_asterisk_detected'
|
30
|
-
prev_state, state = change_state(c, state, 'third_asterisk_detected')
|
31
|
-
|
32
|
-
elsif state == 'italic_started'
|
33
|
-
prev_state, state = change_state(c, state, 'default')
|
34
|
-
result += italic(stack)
|
35
|
-
|
36
|
-
elsif state == 'bold_started'
|
37
|
-
prev_state, state = change_state(c, state, 'first_asterisk_after_bold_detected')
|
38
|
-
|
39
|
-
elsif state == 'first_asterisk_after_bold_detected'
|
40
|
-
prev_state, state = change_state(c, state, 'default')
|
41
|
-
result += bold(stack)
|
42
|
-
|
43
|
-
elsif state == 'bold_and_italic_started'
|
44
|
-
prev_state, state = change_state(c, state, 'first_asterisk_after_bold_and_italic_detected')
|
45
|
-
|
46
|
-
elsif state == 'first_asterisk_after_bold_and_italic_detected'
|
47
|
-
prev_state, state = change_state(c, state, 'second_asterisk_after_bold_and_italic_detected')
|
48
|
-
|
49
|
-
elsif state == 'second_asterisk_after_bold_and_italic_detected'
|
50
|
-
prev_state, state = change_state(c, state, 'default')
|
51
|
-
result += bold_and_italic(stack)
|
22
|
+
class BoldAndItalicToken < TextLineToken
|
23
|
+
attr_accessor :value
|
24
|
+
def initialize()
|
25
|
+
@value = "***"
|
26
|
+
end
|
27
|
+
end
|
52
28
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
elsif c == ']'
|
61
|
-
if state == 'square_bracket_left_detected'
|
62
|
-
prev_state, state = change_state(c, state, 'default')
|
63
|
-
result += '[]'
|
29
|
+
class ParentheseLeft < TextLineToken
|
30
|
+
attr_accessor :value
|
31
|
+
def initialize()
|
32
|
+
@value = "("
|
33
|
+
end
|
34
|
+
end
|
64
35
|
|
65
|
-
|
66
|
-
|
67
|
-
|
36
|
+
class ParentheseRight < TextLineToken
|
37
|
+
attr_accessor :value
|
38
|
+
def initialize()
|
39
|
+
@value = ")"
|
40
|
+
end
|
41
|
+
end
|
68
42
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
43
|
+
class SquareBracketLeft < TextLineToken
|
44
|
+
attr_accessor :value
|
45
|
+
def initialize()
|
46
|
+
@value = "["
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class SquareBracketRight < TextLineToken
|
51
|
+
attr_accessor :value
|
52
|
+
def initialize()
|
53
|
+
@value = "]"
|
54
|
+
end
|
55
|
+
end
|
81
56
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
57
|
+
class SquareBracketRightAndParentheseLeft < TextLineToken
|
58
|
+
attr_accessor :value
|
59
|
+
def initialize()
|
60
|
+
@value = "]("
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class TextLineParser
|
65
|
+
attr_accessor :supported_tokens
|
66
|
+
|
67
|
+
def initialize()
|
68
|
+
@supported_tokens = Array.new
|
69
|
+
@supported_tokens.append(BoldAndItalicToken.new)
|
70
|
+
@supported_tokens.append(BoldToken.new)
|
71
|
+
@supported_tokens.append(ItalicToken.new)
|
72
|
+
@supported_tokens.append(SquareBracketRightAndParentheseLeft.new)
|
73
|
+
@supported_tokens.append(ParentheseLeft.new)
|
74
|
+
@supported_tokens.append(ParentheseRight.new)
|
75
|
+
@supported_tokens.append(SquareBracketLeft.new)
|
76
|
+
@supported_tokens.append(SquareBracketRight.new)
|
77
|
+
@supported_tokens.append(TextLineToken.new)
|
78
|
+
end
|
86
79
|
|
80
|
+
def tokenize(str)
|
81
|
+
result = Array.new
|
82
|
+
sl = str.length
|
83
|
+
si = 0
|
84
|
+
while si < sl
|
85
|
+
@supported_tokens.each do |t|
|
86
|
+
tl = t.value.length
|
87
|
+
if tl != 0 # literal is the last supported token in the list
|
88
|
+
projected_end_position = si+tl-1
|
89
|
+
if projected_end_position > sl
|
90
|
+
next
|
91
|
+
end
|
92
|
+
buf = str[si..projected_end_position]
|
93
|
+
if buf == t.value
|
94
|
+
result.append(t)
|
95
|
+
si = projected_end_position +1
|
96
|
+
break
|
97
|
+
end
|
87
98
|
else
|
88
|
-
result
|
99
|
+
if (result.length > 0) and (result[-1].instance_of? TextLineToken)
|
100
|
+
literal = result[-1]
|
101
|
+
literal.value += str[si]
|
102
|
+
else
|
103
|
+
literal = TextLineToken.new
|
104
|
+
literal.value = str[si]
|
105
|
+
result.append(literal)
|
106
|
+
end
|
107
|
+
si += 1
|
89
108
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
prev_state, state = change_state(c, state, 'italic_started')
|
96
|
-
stack = ''
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return result
|
112
|
+
end
|
113
|
+
end
|
97
114
|
|
98
|
-
|
99
|
-
prev_state, state = change_state(c, state, 'bold_started')
|
100
|
-
stack = ''
|
115
|
+
class TextLineBuilderContext
|
101
116
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
elsif state == 'first_asterisk_after_bold_detected'
|
107
|
-
prev_state, state = change_state(c, state, 'bold_started')
|
117
|
+
def italic(str)
|
118
|
+
return str
|
119
|
+
end
|
108
120
|
|
109
|
-
|
110
|
-
|
121
|
+
def bold(str)
|
122
|
+
return str
|
123
|
+
end
|
111
124
|
|
112
|
-
|
113
|
-
|
125
|
+
def bold_and_italic(str)
|
126
|
+
return str
|
127
|
+
end
|
114
128
|
|
115
|
-
|
116
|
-
|
117
|
-
|
129
|
+
def link(link_text, link_url)
|
130
|
+
return link_url
|
131
|
+
end
|
132
|
+
end
|
118
133
|
|
119
|
-
|
120
|
-
|
121
|
-
result += stack + c
|
122
|
-
c = ''
|
134
|
+
class TextLineBuilder
|
135
|
+
attr_accessor :builder_context
|
123
136
|
|
124
|
-
|
125
|
-
|
126
|
-
|
137
|
+
def initialize(builder_context)
|
138
|
+
@builder_context = builder_context
|
139
|
+
end
|
127
140
|
|
128
|
-
|
129
|
-
|
130
|
-
|
141
|
+
def restore(token_list)
|
142
|
+
result = ""
|
143
|
+
if token_list == nil
|
144
|
+
return ""
|
145
|
+
end
|
146
|
+
sub_list_url_text = nil
|
147
|
+
sub_list_url_address = nil
|
148
|
+
tl = token_list.length
|
149
|
+
ti = 0
|
150
|
+
while ti < tl
|
151
|
+
case token_list[ti].class.name
|
152
|
+
when "ItalicToken"
|
153
|
+
is_found = false
|
154
|
+
ti_starting_position = ti
|
155
|
+
# try to find closing part
|
156
|
+
tii = ti + 1
|
157
|
+
while tii < tl
|
158
|
+
if token_list[tii].instance_of? ItalicToken
|
159
|
+
sub_list = token_list[(ti+1)..(tii-1)]
|
160
|
+
result += @builder_context.italic(restore(sub_list))
|
161
|
+
ti = tii +1
|
162
|
+
is_found = true
|
163
|
+
break
|
164
|
+
end
|
165
|
+
tii += 1
|
166
|
+
end
|
167
|
+
unless is_found
|
168
|
+
result += "*"
|
169
|
+
ti = ti_starting_position + 1
|
170
|
+
end
|
171
|
+
when "BoldToken"
|
172
|
+
is_found = false
|
173
|
+
ti_starting_position = ti
|
174
|
+
# try to find closing part
|
175
|
+
tii = ti + 1
|
176
|
+
while tii < tl
|
177
|
+
if token_list[tii].instance_of? BoldToken
|
178
|
+
sub_list = token_list[(ti+1)..(tii-1)]
|
179
|
+
result += @builder_context.bold(restore(sub_list))
|
180
|
+
ti = tii +1
|
181
|
+
is_found = true
|
182
|
+
break
|
183
|
+
end
|
184
|
+
tii += 1
|
185
|
+
end
|
186
|
+
unless is_found
|
187
|
+
result += "**"
|
188
|
+
ti = ti_starting_position + 1
|
189
|
+
end
|
190
|
+
when "BoldAndItalicToken"
|
191
|
+
is_found = false
|
192
|
+
ti_starting_position = ti
|
193
|
+
# try to find closing part
|
194
|
+
tii = ti + 1
|
195
|
+
while tii < tl
|
196
|
+
if token_list[tii].instance_of? BoldAndItalicToken
|
197
|
+
sub_list = token_list[(ti+1)..(tii-1)]
|
198
|
+
result += @builder_context.bold_and_italic(restore(sub_list))
|
199
|
+
ti = tii +1
|
200
|
+
is_found = true
|
201
|
+
break
|
202
|
+
end
|
203
|
+
tii += 1
|
204
|
+
end
|
205
|
+
unless is_found
|
206
|
+
result += "***"
|
207
|
+
ti = ti_starting_position + 1
|
131
208
|
end
|
209
|
+
when "SquareBracketLeft"
|
210
|
+
# try to find closing part
|
211
|
+
is_found = false
|
212
|
+
tii = ti + 1
|
213
|
+
ti_starting_position = ti
|
214
|
+
while tii < tl
|
215
|
+
case token_list[tii].class.name
|
216
|
+
when "SquareBracketRightAndParentheseLeft"
|
217
|
+
sub_list_url_text = token_list[(ti+1)..(tii-1)]
|
218
|
+
ti = tii +1
|
219
|
+
tiii = ti
|
220
|
+
while tiii < tl
|
221
|
+
case token_list[tiii].class.name
|
222
|
+
when "ParentheseRight"
|
223
|
+
sub_list_url_address = token_list[(tii+1)..(tiii-1)]
|
224
|
+
ti = tiii +1
|
225
|
+
is_found = true
|
226
|
+
break
|
227
|
+
end
|
228
|
+
tiii += 1
|
229
|
+
end
|
230
|
+
break
|
231
|
+
when "SquareBracketRight"
|
232
|
+
break
|
233
|
+
end
|
234
|
+
tii += 1
|
235
|
+
end
|
236
|
+
if is_found
|
237
|
+
result += @builder_context.link(restore(sub_list_url_text), restore(sub_list_url_address))
|
238
|
+
else
|
239
|
+
result += "["
|
240
|
+
ti = ti_starting_position + 1
|
241
|
+
end
|
242
|
+
|
243
|
+
when "TextLineToken", "ParentheseLeft", "ParentheseRight", "SquareBracketLeft", "SquareBracketRight"
|
244
|
+
result += token_list[ti].value
|
245
|
+
ti += 1
|
246
|
+
else
|
247
|
+
ti += 1
|
132
248
|
end
|
133
|
-
prev_c = c
|
134
249
|
end
|
135
250
|
return result
|
136
251
|
end
|
252
|
+
end
|
253
|
+
|
254
|
+
class TextLine < TextLineBuilderContext
|
255
|
+
|
256
|
+
@@lazy_doc_id_dict = Hash.new
|
257
|
+
|
258
|
+
def self.add_lazy_doc_id(id)
|
259
|
+
doc_id = id.to_s.downcase
|
260
|
+
@@lazy_doc_id_dict[doc_id] = doc_id
|
261
|
+
end
|
262
|
+
|
263
|
+
def format_string(str)
|
264
|
+
tlp = TextLineParser.new
|
265
|
+
tlb = TextLineBuilder.new(self)
|
266
|
+
tlb.restore(tlp.tokenize(str))
|
267
|
+
end
|
137
268
|
|
138
269
|
def change_state(c, cur_state, new_state)
|
139
270
|
# puts "[#{c}] Transition: #{cur_state} --> #{new_state}"
|
@@ -153,7 +284,6 @@ class TextLine
|
|
153
284
|
end
|
154
285
|
|
155
286
|
def link(link_text, link_url)
|
156
|
-
|
157
287
|
# define default result first
|
158
288
|
result = "<a target=\"_blank\" rel=\"noopener\" href=\"#{link_url}\" class=\"external\">#{link_text}</a>"
|
159
289
|
|
@@ -6,6 +6,7 @@ class BaseDocument
|
|
6
6
|
attr_accessor :headings
|
7
7
|
attr_accessor :title
|
8
8
|
attr_accessor :id
|
9
|
+
attr_accessor :dom
|
9
10
|
|
10
11
|
def initialize(fele_path)
|
11
12
|
|
@@ -14,6 +15,7 @@ class BaseDocument
|
|
14
15
|
@headings = Array.new
|
15
16
|
@title = ""
|
16
17
|
@id = ""
|
18
|
+
@dom = nil
|
17
19
|
end
|
18
20
|
|
19
21
|
def save_html_to_file html_rows, nav_pane, output_file_path
|
@@ -37,7 +39,7 @@ class BaseDocument
|
|
37
39
|
file.puts r
|
38
40
|
end
|
39
41
|
elsif s.include?('{{NAV_PANE}}')
|
40
|
-
if nav_pane
|
42
|
+
if nav_pane
|
41
43
|
file.puts nav_pane.to_html
|
42
44
|
end
|
43
45
|
elsif s.include?('{{DOCUMENT_TITLE}}')
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class DocSection
|
2
|
+
|
3
|
+
attr_accessor :sections
|
4
|
+
attr_accessor :heading
|
5
|
+
attr_accessor :parent_section
|
6
|
+
|
7
|
+
def initialize(heading)
|
8
|
+
@sections = Array.new
|
9
|
+
@heading = heading
|
10
|
+
@parent_section = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_html
|
14
|
+
s = ''
|
15
|
+
s += "\t<li><span class=\"fa-li\"><i class=\"fa fa-sticky-note-o\"> </i></span>"
|
16
|
+
s += "<a href=\"\#" + @heading.anchor_id.to_s + "\">" + @heading.get_section_info + "</a>\n"
|
17
|
+
if @sections.length >0
|
18
|
+
s += "\t\t<ul class=\"fa-ul\">\n"
|
19
|
+
@sections.each do |sub_section|
|
20
|
+
s += sub_section.to_html()
|
21
|
+
end
|
22
|
+
s += "\t\t</ul>\n"
|
23
|
+
end
|
24
|
+
s += "</li>\n"
|
25
|
+
return s
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative "doc_section"
|
2
|
+
|
3
|
+
class Document
|
4
|
+
|
5
|
+
attr_accessor :root_section
|
6
|
+
|
7
|
+
@@sections_stack = Array.new
|
8
|
+
|
9
|
+
def initialize(headings_list)
|
10
|
+
@root_section = nil
|
11
|
+
|
12
|
+
build_sections_tree(headings_list)
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_sections_tree(headings_list)
|
16
|
+
|
17
|
+
headings_list.each do |h|
|
18
|
+
|
19
|
+
if @root_section == nil
|
20
|
+
|
21
|
+
s = DocSection.new(h)
|
22
|
+
s.parent_section = nil
|
23
|
+
@root_section = s
|
24
|
+
@@sections_stack.push s
|
25
|
+
|
26
|
+
elsif @@sections_stack[-1].heading.level == h.level
|
27
|
+
|
28
|
+
s = DocSection.new(h)
|
29
|
+
@@sections_stack[-2].sections.append(s)
|
30
|
+
@@sections_stack[-1] = s
|
31
|
+
|
32
|
+
elsif h.level > @@sections_stack[-1].heading.level
|
33
|
+
|
34
|
+
s = DocSection.new(h)
|
35
|
+
@@sections_stack[-1].sections.append(s)
|
36
|
+
@@sections_stack.push s
|
37
|
+
|
38
|
+
else
|
39
|
+
while h.level < @@sections_stack[-1].heading.level
|
40
|
+
@@sections_stack.pop
|
41
|
+
end
|
42
|
+
|
43
|
+
s = DocSection.new(h)
|
44
|
+
@@sections_stack[-2].sections.append(s)
|
45
|
+
@@sections_stack[-1] = s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def section_tree_to_html
|
51
|
+
s = ''
|
52
|
+
s += "<a href=\"\#" + @root_section.heading.anchor_id.to_s + "\">" + @root_section.heading.text + "</a>\n"
|
53
|
+
if @root_section.sections.length >0
|
54
|
+
s += "\t<ul class=\"fa-ul\" style=\"margin-top: 2px;\">\n"
|
55
|
+
@root_section.sections.each do |sub_section|
|
56
|
+
s += sub_section.to_html()
|
57
|
+
end
|
58
|
+
s += "\t</ul>\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
return s
|
62
|
+
end
|
63
|
+
end
|
@@ -3,21 +3,15 @@ class NavigationPane
|
|
3
3
|
|
4
4
|
attr_accessor :specifications
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
6
|
+
def initialize(specification)
|
7
|
+
@doc = specification
|
8
8
|
end
|
9
9
|
|
10
|
-
def to_html
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
s += "\t\t\t<li><span class=\"fa-li\"><i class=\"fa fa-plus-square-o\"> </i></span>\n"
|
16
|
-
s += "\t\t\t\t<a href=\".\\..\\#{spec.id }\\#{spec.id }.html\">#{spec.title}</a>\n"
|
17
|
-
s += "\t\t\t</li>\n"
|
18
|
-
s += "\t\t</ul>\n"
|
19
|
-
s += "\t</li>\n"
|
10
|
+
def to_html
|
11
|
+
if @doc.dom
|
12
|
+
return @doc.dom.section_tree_to_html()
|
13
|
+
else
|
14
|
+
return ''
|
20
15
|
end
|
21
|
-
s += "</ul>\n"
|
22
16
|
end
|
23
17
|
end
|
data/lib/almirah/project.rb
CHANGED
@@ -227,10 +227,7 @@ class Project
|
|
227
227
|
@index = Index.new( @project )
|
228
228
|
end
|
229
229
|
|
230
|
-
def render_all_specifications(spec_list)
|
231
|
-
|
232
|
-
# create a sidebar first
|
233
|
-
# nav_pane = NavigationPane.new(@specifications)
|
230
|
+
def render_all_specifications(spec_list)
|
234
231
|
|
235
232
|
pass = @project_root_directory
|
236
233
|
|
@@ -249,7 +246,9 @@ class Project
|
|
249
246
|
FileUtils.copy_entry( img_src_dir, img_dst_dir )
|
250
247
|
end
|
251
248
|
|
252
|
-
|
249
|
+
# create a sidebar first
|
250
|
+
nav_pane = NavigationPane.new(doc)
|
251
|
+
doc.to_html( nav_pane, "#{pass}/build/specifications/" )
|
253
252
|
end
|
254
253
|
end
|
255
254
|
|
@@ -173,14 +173,30 @@
|
|
173
173
|
#modal_image_id{
|
174
174
|
cursor: default;
|
175
175
|
}
|
176
|
+
#closed_nav_pane{
|
177
|
+
padding: 0px;
|
178
|
+
background: #169;
|
179
|
+
border: 0px;
|
180
|
+
position: fixed;
|
181
|
+
width: 5px;
|
182
|
+
height: 100%; /* 100% Full-height */
|
183
|
+
visibility: visible;
|
184
|
+
cursor: pointer;
|
185
|
+
}
|
186
|
+
#closed_nav_pane:hover{
|
187
|
+
width: 10px;
|
188
|
+
}
|
176
189
|
#nav_pane{
|
177
190
|
flex-shrink: 0;
|
178
|
-
padding:
|
191
|
+
padding: 32px 8px 8px 8px;
|
179
192
|
background: #EEEEEE;
|
180
|
-
border
|
193
|
+
border: 1px solid #ddd;
|
181
194
|
position: fixed;
|
182
195
|
height: 100%; /* 100% Full-height */
|
183
196
|
visibility: hidden;
|
197
|
+
z-index: 1;
|
198
|
+
overflow-y: auto;
|
199
|
+
cursor: pointer;
|
184
200
|
}
|
185
201
|
@media screen and (min-width: 0px) and (max-width: 1089px) {#nav_pane{width: 22%;}}
|
186
202
|
@media screen and (min-width: 1090px) and (max-width: 1279px) {#nav_pane{width: 240px;}}
|
@@ -188,12 +204,13 @@
|
|
188
204
|
@media screen and (min-width: 1600px) and (max-width: 1919px) {#nav_pane{width: 320px;}}
|
189
205
|
@media screen and (min-width: 1920px) and (max-width: 2559px) {#nav_pane{width: 360px;}}
|
190
206
|
@media screen and (min-width: 2560px) {#nav_pane{width: 380px;}}
|
207
|
+
|
191
208
|
#top_nav{
|
192
209
|
background-color: #169;
|
193
210
|
overflow: hidden;
|
194
211
|
position: fixed;
|
195
212
|
width: 100%;
|
196
|
-
z-index:
|
213
|
+
z-index: 2;
|
197
214
|
}
|
198
215
|
#top_nav a {
|
199
216
|
float: left;
|
@@ -286,12 +303,10 @@
|
|
286
303
|
<script>
|
287
304
|
function openNav() {
|
288
305
|
document.getElementById("nav_pane").style.visibility = "visible";
|
289
|
-
console.log("Mouse In")
|
290
306
|
}
|
291
307
|
|
292
308
|
function closeNav() {
|
293
309
|
document.getElementById("nav_pane").style.visibility = "hidden";
|
294
|
-
console.log("Mouse Out");
|
295
310
|
}
|
296
311
|
|
297
312
|
window.onload = (event) => {
|
@@ -304,12 +319,12 @@ window.onload = (event) => {
|
|
304
319
|
}
|
305
320
|
}
|
306
321
|
// Scroll a bit to make navigated anchor visible
|
307
|
-
setTimeout(function() {
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
322
|
+
//setTimeout(function() {
|
323
|
+
// window.scrollBy({
|
324
|
+
// top: -40,
|
325
|
+
// behavior: "smooth"
|
326
|
+
// });
|
327
|
+
// }, 200);
|
313
328
|
};
|
314
329
|
|
315
330
|
function downlink_OnClick(clicked){
|
@@ -350,11 +365,12 @@ function modal_close_OnClick(clicked){
|
|
350
365
|
<body>
|
351
366
|
<div id="top_nav">
|
352
367
|
<a href="javascript:void(0)" onclick="navigate_to_home()"><span><i class="fa fa-home" aria-hidden="true"></i></span> Home</a>
|
353
|
-
<!--a href="javascript:void(0)"> About</a-->
|
354
368
|
<a class="split">{{DOCUMENT_TITLE}}</a>
|
355
369
|
</div>
|
356
370
|
<div id="main">
|
357
|
-
<div id="
|
371
|
+
<div id="closed_nav_pane" href="javascript:void(0)" onclick="openNav()">
|
372
|
+
</div>
|
373
|
+
<div id="nav_pane" onclick="closeNav()">
|
358
374
|
{{NAV_PANE}}
|
359
375
|
</div>
|
360
376
|
<div id="content" href="javascript:void(0)" onclick="closeNav()">
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Almirah
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleksandr Ivanov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The software part of the Almirah framework
|
14
14
|
email: oleksandr.ivanov.development@gmail.com
|
@@ -40,6 +40,8 @@ files:
|
|
40
40
|
- lib/almirah/doc_types/protocol.rb
|
41
41
|
- lib/almirah/doc_types/specification.rb
|
42
42
|
- lib/almirah/doc_types/traceability.rb
|
43
|
+
- lib/almirah/dom/doc_section.rb
|
44
|
+
- lib/almirah/dom/document.rb
|
43
45
|
- lib/almirah/navigation_pane.rb
|
44
46
|
- lib/almirah/project.rb
|
45
47
|
- lib/almirah/templates/page.html
|