giblish 0.8.2 → 1.0.0.rc2

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/unit_tests.yml +30 -0
  3. data/.gitignore +7 -3
  4. data/.ruby-version +1 -1
  5. data/Changelog.adoc +61 -0
  6. data/README.adoc +267 -0
  7. data/docs/concepts/text_search.adoc +213 -0
  8. data/docs/concepts/text_search_im/cgi-search_request.puml +35 -0
  9. data/docs/concepts/text_search_im/cgi-search_request.svg +397 -0
  10. data/docs/concepts/text_search_im/search_request.puml +40 -0
  11. data/docs/concepts/text_search_im/search_request.svg +408 -0
  12. data/docs/howtos/trigger_generation.adoc +180 -0
  13. data/docs/{setup_server_assets → howtos/trigger_generation_im}/Render Documents.png +0 -0
  14. data/docs/{setup_server_assets → howtos/trigger_generation_im}/View Documents.png +0 -0
  15. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.graphml +0 -0
  16. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_hooks.svg +0 -0
  17. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.graphml +0 -0
  18. data/docs/{setup_server_assets → howtos/trigger_generation_im}/deploy_with_jenkins.svg +0 -0
  19. data/docs/howtos/trigger_generation_im/docgen_github.puml +51 -0
  20. data/docs/{setup_server_assets → howtos/trigger_generation_im}/giblish_deployment.graphml +0 -0
  21. data/docs/howtos/trigger_generation_im/post-receive-example.sh +50 -0
  22. data/docs/reference/box_flow_spec.adoc +22 -0
  23. data/docs/reference/search_spec.adoc +185 -0
  24. data/giblish.gemspec +47 -29
  25. data/lib/giblish/adocsrc_providers.rb +23 -0
  26. data/lib/giblish/application.rb +214 -41
  27. data/lib/giblish/cmdline.rb +273 -259
  28. data/lib/giblish/config_utils.rb +41 -0
  29. data/lib/giblish/configurator.rb +163 -0
  30. data/lib/giblish/conversion_info.rb +120 -0
  31. data/lib/giblish/docattr_providers.rb +125 -0
  32. data/lib/giblish/docid/docid.rb +181 -0
  33. data/lib/giblish/github_trigger/webhook_manager.rb +64 -0
  34. data/lib/giblish/gitrepos/checkoutmanager.rb +124 -0
  35. data/lib/giblish/{gititf.rb → gitrepos/gititf.rb} +30 -4
  36. data/lib/giblish/gitrepos/gitsummary.erb +61 -0
  37. data/lib/giblish/gitrepos/gitsummaryprovider.rb +78 -0
  38. data/lib/giblish/gitrepos/history_pb.rb +41 -0
  39. data/lib/giblish/indexbuilders/d3treegraph.rb +88 -0
  40. data/lib/giblish/indexbuilders/depgraphbuilder.rb +109 -0
  41. data/lib/giblish/indexbuilders/dotdigraphadoc.rb +174 -0
  42. data/lib/giblish/indexbuilders/standard_index.erb +10 -0
  43. data/lib/giblish/indexbuilders/subtree_indices.rb +132 -0
  44. data/lib/giblish/indexbuilders/templates/circles.html.erb +111 -0
  45. data/lib/giblish/indexbuilders/templates/flame.html.erb +61 -0
  46. data/lib/giblish/indexbuilders/templates/tree.html.erb +366 -0
  47. data/lib/giblish/indexbuilders/templates/treemap.html.erb +127 -0
  48. data/lib/giblish/indexbuilders/verbatimtree.rb +94 -0
  49. data/lib/giblish/pathtree.rb +473 -74
  50. data/lib/giblish/resourcepaths.rb +150 -0
  51. data/lib/giblish/search/expand_adoc.rb +55 -0
  52. data/lib/giblish/search/headingindexer.rb +312 -0
  53. data/lib/giblish/search/request_manager.rb +110 -0
  54. data/lib/giblish/search/searchquery.rb +68 -0
  55. data/lib/giblish/search/textsearcher.rb +349 -0
  56. data/lib/giblish/subtreeinfobuilder.rb +77 -0
  57. data/lib/giblish/treeconverter.rb +272 -0
  58. data/lib/giblish/utils.rb +142 -294
  59. data/lib/giblish/version.rb +1 -1
  60. data/lib/giblish.rb +10 -7
  61. data/scripts/hooks/post-receive.example +66 -0
  62. data/{docgen/scripts/githook_examples → scripts/hooks}/post-update.example +0 -0
  63. data/{docgen → scripts}/resources/css/adoc-colony.css +0 -0
  64. data/scripts/resources/css/giblish-serif.css +419 -0
  65. data/scripts/resources/css/giblish.css +1979 -419
  66. data/{docgen → scripts}/resources/fonts/Ubuntu-B.ttf +0 -0
  67. data/{docgen → scripts}/resources/fonts/Ubuntu-BI.ttf +0 -0
  68. data/{docgen → scripts}/resources/fonts/Ubuntu-R.ttf +0 -0
  69. data/{docgen → scripts}/resources/fonts/Ubuntu-RI.ttf +0 -0
  70. data/{docgen → scripts}/resources/fonts/mplus1p-regular-fallback.ttf +0 -0
  71. data/{docgen → scripts}/resources/images/giblish_logo.png +0 -0
  72. data/{docgen → scripts}/resources/images/giblish_logo.svg +0 -0
  73. data/{docgen → scripts}/resources/themes/giblish.yml +0 -0
  74. data/scripts/wserv_development.rb +32 -0
  75. data/web_apps/cgi_search/gibsearch.rb +43 -0
  76. data/web_apps/gh_webhook_trigger/config.ru +2 -0
  77. data/web_apps/gh_webhook_trigger/gh_webhook_trigger.rb +73 -0
  78. data/web_apps/gh_webhook_trigger/public/dummy.txt +3 -0
  79. data/web_apps/sinatra_search/config.ru +2 -0
  80. data/web_apps/sinatra_search/public/dummy.txt +3 -0
  81. data/web_apps/sinatra_search/sinatra_search.rb +34 -0
  82. data/web_apps/sinatra_search/tmp/restart.txt +0 -0
  83. metadata +168 -73
  84. data/.rubocop.yml +0 -7
  85. data/.travis.yml +0 -3
  86. data/Changelog +0 -16
  87. data/Gemfile +0 -4
  88. data/README.adoc +0 -1
  89. data/Rakefile +0 -41
  90. data/bin/console +0 -14
  91. data/bin/setup +0 -8
  92. data/data/testdocs/malformed/no_header.adoc +0 -5
  93. data/data/testdocs/toplevel.adoc +0 -19
  94. data/data/testdocs/wellformed/adorned_purpose.adoc +0 -17
  95. data/data/testdocs/wellformed/docidtest/docid_1.adoc +0 -24
  96. data/data/testdocs/wellformed/docidtest/docid_2.adoc +0 -8
  97. data/data/testdocs/wellformed/simple.adoc +0 -14
  98. data/data/testdocs/wellformed/source_highlighting/highlight_source.adoc +0 -38
  99. data/docgen/resources/css/giblish.css +0 -1979
  100. data/docgen/scripts/Jenkinsfile +0 -18
  101. data/docgen/scripts/gen_adoc_org.sh +0 -58
  102. data/docs/README.adoc +0 -387
  103. data/docs/setup_server.adoc +0 -202
  104. data/lib/giblish/buildgraph.rb +0 -216
  105. data/lib/giblish/buildindex.rb +0 -459
  106. data/lib/giblish/core.rb +0 -451
  107. data/lib/giblish/docconverter.rb +0 -308
  108. data/lib/giblish/docid.rb +0 -180
  109. data/lib/giblish/docinfo.rb +0 -75
  110. data/lib/giblish/indexheadings.rb +0 -251
  111. data/lib/giblish-search.cgi +0 -459
  112. data/scripts/hooks/post-receive +0 -57
  113. data/scripts/publish_html.sh +0 -99
@@ -0,0 +1,366 @@
1
+ <style type="text/css">
2
+ .node {
3
+ cursor: pointer;
4
+ }
5
+
6
+ .overlay {
7
+ background-color: white;
8
+ }
9
+
10
+ .node circle {
11
+ fill: lightblue;
12
+ stroke: steelblue;
13
+ stroke-width: 1.5px;
14
+ }
15
+
16
+ .node text {
17
+ font-size: 12px;
18
+ font-family: sans-serif;
19
+ }
20
+
21
+ .link {
22
+ fill: none;
23
+ stroke: #ccc;
24
+ stroke-width: 1.5px;
25
+ }
26
+ </style>
27
+
28
+ <div id="tree-container"></div>
29
+ <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
30
+ <script src="http://d3js.org/d3.v3.min.js"></script>
31
+ <script>
32
+ /*Copyright (c) 2013-2016, Rob Schmuecker
33
+ All rights reserved.
34
+
35
+ Redistribution and use in source and binary forms, with or without
36
+ modification, are permitted provided that the following conditions are met:
37
+
38
+ * Redistributions of source code must retain the above copyright notice, this
39
+ list of conditions and the following disclaimer.
40
+
41
+ * Redistributions in binary form must reproduce the above copyright notice,
42
+ this list of conditions and the following disclaimer in the documentation
43
+ and/or other materials provided with the distribution.
44
+
45
+ * The name Rob Schmuecker may not be used to endorse or promote products
46
+ derived from this software without specific prior written permission.
47
+
48
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
49
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51
+ DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
52
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
53
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
55
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
56
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
57
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
58
+
59
+
60
+ treeData = <%= @tree.to_json %>;
61
+
62
+ // Calculate total nodes, max label length
63
+ var maxLabelLength = 0;
64
+ // panning variables
65
+ var panSpeed = 200;
66
+ // Misc. variables
67
+ var i = 0;
68
+ var duration = 750;
69
+ var root;
70
+
71
+ // size of the diagram
72
+ var viewerWidth = $(document).width() / 2;
73
+ var viewerHeight = $(document).height() / 2;
74
+ // var viewerWidth = $(document).width();
75
+ // var viewerHeight = $(document).height();
76
+
77
+ var tree = d3.layout.tree()
78
+ .size([viewerHeight, viewerWidth])
79
+ .separation(function (a, b) {
80
+ // return (a.parent == b.parent ? 1 : 2);// * 3 * a.depth;
81
+ return 1;
82
+ });
83
+
84
+ // define a d3 diagonal projection for use by the node paths later on.
85
+ var diagonal = d3.svg.diagonal()
86
+ .projection(function (d) {
87
+ return [d.y, d.x];
88
+ // return [d.x, d.y];
89
+ });
90
+
91
+ // A recursive helper function for performing some setup by walking through all nodes
92
+ function visit(parent, visitFn, childrenFn) {
93
+ if (!parent) return;
94
+
95
+ visitFn(parent);
96
+
97
+ var children = childrenFn(parent);
98
+ if (children) {
99
+ var count = children.length;
100
+ for (var i = 0; i < count; i++) {
101
+ visit(children[i], visitFn, childrenFn);
102
+ }
103
+ }
104
+ }
105
+
106
+ // Call visit function to establish maxLabelLength
107
+ visit(treeData, function (d) {
108
+ maxLabelLength = Math.max(d.name.length, maxLabelLength);
109
+
110
+ }, function (d) {
111
+ return d.children && d.children.length > 0 ? d.children : null;
112
+ });
113
+
114
+ function pan(domNode, direction) {
115
+ var speed = panSpeed;
116
+ if (panTimer) {
117
+ clearTimeout(panTimer);
118
+ translateCoords = d3.transform(svgGroup.attr("transform"));
119
+ if (direction == 'left' || direction == 'right') {
120
+ translateX = direction == 'left' ? translateCoords.translate[0] + speed : translateCoords.translate[0] - speed;
121
+ translateY = translateCoords.translate[1];
122
+ } else if (direction == 'up' || direction == 'down') {
123
+ translateX = translateCoords.translate[0];
124
+ translateY = direction == 'up' ? translateCoords.translate[1] + speed : translateCoords.translate[1] - speed;
125
+ }
126
+ scaleX = translateCoords.scale[0];
127
+ scaleY = translateCoords.scale[1];
128
+ scale = zoomListener.scale();
129
+ svgGroup.transition().attr("transform", "translate(" + translateX + "," + translateY + ")scale(" + scale + ")");
130
+ d3.select(domNode).select('g.node').attr("transform", "translate(" + translateX + "," + translateY + ")");
131
+ zoomListener.scale(zoomListener.scale());
132
+ zoomListener.translate([translateX, translateY]);
133
+ panTimer = setTimeout(function () {
134
+ pan(domNode, speed, direction);
135
+ }, 50);
136
+ }
137
+ }
138
+
139
+ // Define the zoom function for the zoomable tree
140
+ function zoom() {
141
+ svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
142
+ }
143
+
144
+
145
+ // define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
146
+ var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);
147
+
148
+ // define the baseSvg, attaching a class for styling and the zoomListener
149
+ var baseSvg = d3.select("#tree-container").append("svg")
150
+ .attr("width", viewerWidth)
151
+ .attr("height", viewerHeight)
152
+ .attr("class", "overlay")
153
+ .call(zoomListener);
154
+
155
+ // Function to center node when clicked/dropped so node doesn't get lost when collapsing/moving with large amount of children.
156
+
157
+ function centerNode(source) {
158
+ scale = zoomListener.scale();
159
+ x = -source.y0;
160
+ y = -source.x0;
161
+ x = x * scale + viewerWidth / 2;
162
+ y = y * scale + viewerHeight / 2;
163
+ d3.select('g').transition()
164
+ .duration(duration)
165
+ .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
166
+ zoomListener.scale(scale);
167
+ zoomListener.translate([x, y]);
168
+ }
169
+
170
+ // Toggle children function
171
+
172
+ function toggleChildren(d) {
173
+ if (d.children) {
174
+ d._children = d.children;
175
+ d.children = null;
176
+ } else if (d._children) {
177
+ d.children = d._children;
178
+ d._children = null;
179
+ }
180
+ return d;
181
+ }
182
+
183
+ // Toggle children on click.
184
+ function click(d) {
185
+ if (d3.event.defaultPrevented) return; // click suppressed
186
+ d = toggleChildren(d);
187
+ update(d);
188
+ centerNode(d);
189
+ }
190
+
191
+ function update(source) {
192
+ // Compute the new height, function counts total children of root node and sets tree height accordingly.
193
+ // This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed
194
+ // This makes the layout more consistent.
195
+ var levelWidth = [1];
196
+ var childCount = function (level, n) {
197
+
198
+ if (n.children && n.children.length > 0) {
199
+ if (levelWidth.length <= level + 1) levelWidth.push(1);
200
+
201
+ levelWidth[level + 1] += n.children.length;
202
+ n.children.forEach(function (d) {
203
+ childCount(level + 1, d);
204
+ });
205
+ }
206
+ };
207
+ childCount(0, root);
208
+ var newHeight = d3.max(levelWidth) * 50; // 50 pixels per line
209
+ tree = tree.size([newHeight, viewerWidth]);
210
+
211
+ // Compute the new tree layout.
212
+ var nodes = tree.nodes(root).reverse(),
213
+ links = tree.links(nodes);
214
+
215
+ // Set widths between levels based on maxLabelLength.
216
+ nodes.forEach(function (d) {
217
+ d.y = (d.depth * (maxLabelLength * 5)); //maxLabelLength * 10px
218
+ // alternatively to keep a fixed scale one can set a fixed depth per level
219
+ // Normalize for fixed-depth by commenting out below line
220
+ // d.y = (d.depth * 500); //500px per level.
221
+ });
222
+
223
+ // Update the nodes…
224
+ node = svgGroup.selectAll("g.node")
225
+ .data(nodes, function (d) {
226
+ return d.id || (d.id = ++i);
227
+ });
228
+
229
+ // Enter any new nodes at the parent's previous position.
230
+ var nodeEnter = node.enter().append("g")
231
+ .attr("class", "node")
232
+ .attr("transform", function (d) {
233
+ return "translate(" + source.y0 + "," + source.x0 + ")";
234
+ })
235
+ .on('click', click);
236
+
237
+ nodeEnter.append("circle")
238
+ .attr('class', 'nodeCircle')
239
+ .attr("r", 0)
240
+ .style("fill", function (d) {
241
+ return d._children ? "lightsteelblue" : "#fff";
242
+ });
243
+
244
+ nodeEnter.append("svg:a").attr("xlink:href", function (d) { return d.dst_ref })
245
+ .append("text")
246
+ .attr("x", function (d) {
247
+ return d.children || d._children ? -20 : 20;
248
+ })
249
+ .attr("dy", ".35em")
250
+ .attr('class', 'nodeText')
251
+ .attr("text-anchor", function (d) {
252
+ return d.children || d._children ? "end" : "start";
253
+ })
254
+ .text(function (d) {
255
+ return d.name;
256
+ })
257
+ .style("fill-opacity", 50);
258
+
259
+ // Update the text to reflect whether node has children or not.
260
+ node.select('text')
261
+ .attr("x", function (d) {
262
+ return d.children || d._children ? -20 : 20;
263
+ })
264
+ .attr("text-anchor", function (d) {
265
+ return d.children || d._children ? "end" : "start";
266
+ })
267
+ .text(function (d) {
268
+ return d.name;
269
+ });
270
+
271
+ // Change the circle fill depending on whether it has children and is collapsed
272
+ node.select("circle.nodeCircle")
273
+ .attr("r", 7)
274
+ .style("fill", function (d) {
275
+ return d._children ? "lightsteelblue" : "#fff";
276
+ });
277
+
278
+ // Transition nodes to their new position.
279
+ var nodeUpdate = node.transition()
280
+ .duration(duration)
281
+ .attr("transform", function (d) {
282
+ // var x = d.x + (d.depth % 2 * 15)
283
+ // return "translate(" + d.y + "," + x + ")";
284
+ return "translate(" + d.y + "," + d.x + ")";
285
+ // return "translate(" + d.x + "," + d.y + ")";
286
+ });
287
+
288
+ // Fade the text in
289
+ nodeUpdate.select("text")
290
+ .style("fill-opacity", 1);
291
+
292
+ // Transition exiting nodes to the parent's new position.
293
+ var nodeExit = node.exit().transition()
294
+ .duration(duration)
295
+ .attr("transform", function (d) {
296
+ return "translate(" + source.y + "," + source.x + ")";
297
+ // return "translate(" + source.x + "," + source.y + ")";
298
+ })
299
+ .remove();
300
+
301
+ nodeExit.select("circle")
302
+ .attr("r", 0);
303
+
304
+ nodeExit.select("text")
305
+ .style("fill-opacity", 0);
306
+
307
+ // Update the links…
308
+ var link = svgGroup.selectAll("path.link")
309
+ .data(links, function (d) {
310
+ return d.target.id;
311
+ });
312
+
313
+ // Enter any new links at the parent's previous position.
314
+ link.enter().insert("path", "g")
315
+ .attr("class", "link")
316
+ .attr("d", function (d) {
317
+ var o = {
318
+ x: source.x0,
319
+ y: source.y0
320
+ };
321
+ return diagonal({
322
+ source: o,
323
+ target: o
324
+ });
325
+ });
326
+
327
+ // Transition links to their new position.
328
+ link.transition()
329
+ .duration(duration)
330
+ .attr("d", diagonal);
331
+
332
+ // Transition exiting nodes to the parent's new position.
333
+ link.exit().transition()
334
+ .duration(duration)
335
+ .attr("d", function (d) {
336
+ var o = {
337
+ x: source.x,
338
+ y: source.y
339
+ };
340
+ return diagonal({
341
+ source: o,
342
+ target: o
343
+ });
344
+ })
345
+ .remove();
346
+
347
+ // Stash the old positions for transition.
348
+ nodes.forEach(function (d) {
349
+ d.x0 = d.x;
350
+ d.y0 = d.y;
351
+ });
352
+ }
353
+
354
+ // Append a group which holds all nodes and which the zoom Listener can act upon.
355
+ var svgGroup = baseSvg.append("g");
356
+
357
+ // Define the root
358
+ root = treeData;
359
+ // root.x0 = viewerHeight / 2;
360
+ root.x0 = 0;
361
+ root.y0 = viewerWidth / 2;
362
+
363
+ // Layout the tree initially and center on the root node.
364
+ update(root);
365
+ // centerNode(root);
366
+ </script>
@@ -0,0 +1,127 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <style>
6
+ html, body {
7
+ padding: 0;
8
+ margin: 0;
9
+ width: 100%;
10
+ height: 100%;
11
+ overflow: hidden;
12
+ }
13
+
14
+ text {
15
+ font: 12px sans-serif;
16
+ }
17
+
18
+ tspan:last-child {
19
+ font-size: 12px;
20
+ fill-opacity: 0.8;
21
+ }
22
+
23
+ .node rect {
24
+ shape-rendering: crispEdges;
25
+ }
26
+
27
+ .node--hover rect {
28
+ stroke: #000;
29
+ }
30
+
31
+ </style>
32
+ <svg width="100%" height="100%"></svg>
33
+ <script src="http://d3js.org/d3.v4.0.0-alpha.35.min.js"></script>
34
+ <script>
35
+
36
+ var svg = d3.select("svg"),
37
+ width = window.innerWidth,
38
+ height = window.innerHeight;
39
+
40
+ svg.attr("width", width + "px");
41
+ svg.attr("height", height + "px");
42
+
43
+ var format = d3.format(",d");
44
+
45
+ var color = d3.scaleMagma()
46
+ .domain([-4, 4]);
47
+
48
+ var treemap = d3.treemap()
49
+ .size([width, height])
50
+ .paddingOuter(3)
51
+ .paddingTop(19)
52
+ .paddingInner(1)
53
+ .round(true);
54
+
55
+
56
+ var data = <%= tree.to_json %>
57
+ var root = d3.hierarchy(data)
58
+ .sum(function(d) {
59
+ var value = 1;
60
+ d.children.forEach(function(i){ value += i.value; })
61
+ return value;
62
+ })
63
+ .sort(function(a, b) { return b.height - a.height || b.value - a.value; })
64
+
65
+ var counter = 0;
66
+ root.each(function(d){ d.id = counter++; })
67
+ treemap(root)
68
+
69
+ var cell = svg
70
+ .selectAll(".node")
71
+ .data(root.descendants())
72
+ .enter().append("g")
73
+ .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; })
74
+ .attr("class", "node")
75
+ .each(function(d) { d.node = this; })
76
+ .on("mouseover", hovered(true))
77
+ .on("mouseout", hovered(false));
78
+
79
+ cell.append("rect")
80
+ .attr("id", function(d) { return "rect-" + d.id; })
81
+ .attr("width", function(d) { return d.x1 - d.x0; })
82
+ .attr("height", function(d) { return d.y1 - d.y0; })
83
+ .style("fill", function(d) { return color(d.depth); });
84
+
85
+ cell.append("clipPath")
86
+ .attr("id", function(d) { return "clip-" + d.id; })
87
+ .append("use")
88
+ .attr("xlink:href", function(d) { return "#rect-" + d.id + ""; });
89
+
90
+ var label = cell.append("text")
91
+ .attr("clip-path", function(d) { return "url(#clip-" + d.id + ")"; });
92
+
93
+ label
94
+ .filter(function(d) { return d.children; })
95
+ .selectAll("tspan")
96
+ .data(function(d) { return [d.data.name]; })
97
+ .enter().append("tspan")
98
+ .attr("x", function(d, i) { return i ? null : 4; })
99
+ .attr("y", 13)
100
+ .text(function(d) { return d; });
101
+
102
+ label
103
+ .filter(function(d) { return !d.children; })
104
+ .selectAll("tspan")
105
+ .data(function(d) { return [d.data.name]; })
106
+ .enter().append("tspan")
107
+ .attr("x", 4)
108
+ .attr("y", function(d, i) { return 13 + i * 10; })
109
+ .text(function(d) { return d; });
110
+
111
+ cell.append("title")
112
+ .text(function(d) { return d.data.name; });
113
+
114
+ function hovered(hover) {
115
+ return function(d) {
116
+ d3.selectAll(d.ancestors().map(function(d) { return d.node; }))
117
+ .classed("node--hover", hover)
118
+ .select("rect")
119
+ .attr("width", function(d) { return d.x1 - d.x0 - hover; })
120
+ .attr("height", function(d) { return d.y1 - d.y0 - hover; });
121
+ };
122
+ }
123
+
124
+ </script>
125
+ </head>
126
+ <body></body>
127
+ </head>
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Giblish
4
+ # Generate asciidoc that represents a given pathtree as a
5
+ # verbatim block with indented, clickable entries.
6
+ class VerbatimTree
7
+ # options:
8
+ # dir_index_base_name: String - the basename of the index file
9
+ # residing in each directory
10
+ def initialize(tree, options = {dir_index_base_name: "index"})
11
+ @tree = tree
12
+ @nof_missing_titles = 0
13
+ @options = options.dup
14
+ end
15
+
16
+ def source
17
+ # output tree intro
18
+ tree_string = +<<~DOC_HEADER
19
+ [subs=\"normal\"]
20
+ ----
21
+ DOC_HEADER
22
+
23
+ # generate each tree entry string
24
+ @tree.traverse_preorder do |level, node|
25
+ next if level == 0
26
+
27
+ tree_string << tree_entry_string(level, node)
28
+ end
29
+
30
+ # generate the tree footer
31
+ tree_string << "\n----\n"
32
+ end
33
+
34
+ private
35
+
36
+ def tree_entry_string(level, node)
37
+ # indent 2 * level
38
+ prefix_str = " " * (level + 1)
39
+
40
+ # return only name for directories
41
+ return directory_entry(prefix_str, node) unless node.leaf?
42
+
43
+ # return links to content and details for files
44
+ d = node.data
45
+ if d.converted
46
+ tree_entry_converted(prefix_str, node)
47
+ else
48
+ # no converted file exists, show what we know
49
+ "#{prefix_str} FAIL: #{d.src_basename} <<#{d.src_basename},details>>\n"
50
+ end
51
+ end
52
+
53
+ def directory_entry(prefix_str, node)
54
+ p = node.pathname.relative_path_from(@tree.pathname).join(@options[:dir_index_base_name])
55
+ "#{prefix_str} <<#{p}#,#{node.segment}>>\n"
56
+ end
57
+
58
+ # Generate an adoc string that will display as
59
+ # DocTitle (conv issues) details
60
+ # Where the DocTitle and details are links to the doc itself and a section
61
+ # identified with the doc's title respectively.
62
+ def tree_entry_converted(prefix_str, node)
63
+ # Get the elements of the entry
64
+ doc_title, doc_link, doc_details = format_title_and_ref(node)
65
+ warning_label = node.data.stderr.empty? ? "" : "(conv issues)"
66
+
67
+ # Calculate padding to get (conv issues) and details aligned in columns
68
+ padding = 70
69
+ [doc_title, prefix_str, warning_label].each { |p| padding -= p.length }
70
+ padding = 0 unless padding.positive?
71
+
72
+ "#{prefix_str} #{doc_link}#{" " * padding}#{warning_label} #{doc_details}"
73
+ end
74
+
75
+ # Private: Return adoc elements for displaying a clickable title
76
+ # and a 'details' ref that points to a section that uses the title as an id.
77
+ #
78
+ # Returns [ title, clickableTitleStr, clickableDetailsStr ]
79
+ def format_title_and_ref(node)
80
+ conv_info = node.data
81
+
82
+ # Use docid and title in title reference
83
+ title_ref = (conv_info.docid.nil? ? "" : "#{conv_info.docid} - ") + conv_info.title
84
+
85
+ # find relative source path from the file to this tree's root
86
+ p = node.pathname.relative_path_from(@tree.pathname).sub_ext(".adoc")
87
+
88
+ # remove html markup in the title for displaying in the tree
89
+ stripped_title = title_ref.gsub(/<.*?>/, "")
90
+ [stripped_title, "<<#{p}#,#{stripped_title}>>",
91
+ "<<#{Giblish.to_valid_id(node.pathname.to_s, "_", "_", true)},details>>\n"]
92
+ end
93
+ end
94
+ end