Almirah 0.2.4 → 0.2.6

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/almirah +4 -4
  3. data/lib/almirah/doc_fabric.rb +65 -65
  4. data/lib/almirah/doc_items/blockquote.rb +21 -21
  5. data/lib/almirah/doc_items/code_block.rb +26 -26
  6. data/lib/almirah/doc_items/controlled_paragraph.rb +112 -112
  7. data/lib/almirah/doc_items/controlled_table.rb +224 -224
  8. data/lib/almirah/doc_items/controlled_table_row.rb +22 -22
  9. data/lib/almirah/doc_items/doc_footer.rb +16 -16
  10. data/lib/almirah/doc_items/doc_item.rb +22 -20
  11. data/lib/almirah/doc_items/frontmatter.rb +9 -0
  12. data/lib/almirah/doc_items/heading.rb +93 -93
  13. data/lib/almirah/doc_items/image.rb +27 -27
  14. data/lib/almirah/doc_items/markdown_list.rb +156 -158
  15. data/lib/almirah/doc_items/markdown_table.rb +61 -63
  16. data/lib/almirah/doc_items/paragraph.rb +25 -27
  17. data/lib/almirah/doc_items/text_line.rb +296 -296
  18. data/lib/almirah/doc_items/todo_block.rb +21 -21
  19. data/lib/almirah/doc_parser.rb +378 -330
  20. data/lib/almirah/doc_types/base_document.rb +64 -70
  21. data/lib/almirah/doc_types/coverage.rb +95 -81
  22. data/lib/almirah/doc_types/index.rb +173 -169
  23. data/lib/almirah/doc_types/persistent_document.rb +17 -20
  24. data/lib/almirah/doc_types/protocol.rb +24 -24
  25. data/lib/almirah/doc_types/specification.rb +67 -67
  26. data/lib/almirah/doc_types/traceability.rb +142 -142
  27. data/lib/almirah/dom/doc_section.rb +25 -25
  28. data/lib/almirah/dom/document.rb +78 -72
  29. data/lib/almirah/navigation_pane.rb +16 -16
  30. data/lib/almirah/project.rb +287 -306
  31. data/lib/almirah/project_configuration.rb +41 -41
  32. data/lib/almirah/project_template.rb +298 -0
  33. data/lib/almirah/project_utility.rb +52 -0
  34. data/lib/almirah/search/specifications_db.rb +79 -83
  35. data/lib/almirah/templates/css/main.css +300 -300
  36. data/lib/almirah/templates/css/search.css +40 -40
  37. data/lib/almirah/templates/page.html +42 -42
  38. data/lib/almirah/templates/scripts/main.js +111 -111
  39. data/lib/almirah/templates/scripts/orama_search.js +138 -138
  40. data/lib/almirah.rb +93 -49
  41. metadata +28 -5
@@ -1,42 +1,42 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>{{DOCUMENT_TITLE}}</title>
6
- <!-- CSS -->
7
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
8
- {{STYLES_AND_SCRIPTS}}
9
- </head>
10
- <body>
11
- <div id="top_nav">
12
- <a id="home_menu_item" href="javascript:void(0)" onclick="navigate_to_home()"><span><i class="fa fa-home" aria-hidden="true"></i></span>&nbsp;Home</a>
13
- <a id="index_menu_item" href="javascript:void(0)" onclick="navigate_to_home()" style="display: none;"><span><i class="fa fa-info" aria-hidden="true"></i></span>&nbsp;Index</a>
14
- <a id="document_tree_menu_item" href="javascript:void(0)" onclick="openNav()" style="display: none;" title="Navigation Pane"><span><i class="fa fa-folder-open-o" aria-hidden="true"></i></span></a>
15
- <input type="text" id="searchInput" placeholder="Search.." style="display: none;">
16
- <a class="split">{{DOCUMENT_TITLE}}</a>
17
- </div>
18
- <div id="search_dropdown" class="search-results-content" style="display: none;"></div>
19
- <div id="main">
20
- <div id="closed_nav_pane" href="javascript:void(0)" onclick="openNav()">
21
- </div>
22
- <div id="nav_pane">
23
- {{NAV_PANE}}
24
- </div>
25
- <div id="content" href="javascript:void(0)" onclick="closeNav()">
26
- {{CONTENT}}
27
- </div><!-- content -->
28
- </div><!-- main -->
29
- <div id="footer">
30
- Powered by <a target="_blank" rel="noopener" href="https://www.almirah.site/">
31
- Almirah Framework
32
- {{GEM_VERSION}}
33
- </a>
34
- </div><!-- footer -->
35
- <!-- The modal window for image zoom -->
36
- <div id="image_modal_div" class="modal">
37
- <span class="modal_close_btn" href="javascript:void(0)" onclick="modal_close_OnClick(this)">&times;</span>
38
- <img class="modal_image" id="modal_image_id">
39
- <div id="modal_image_caption"></div>
40
- </div>
41
- </body>
42
-
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>{{DOCUMENT_TITLE}}</title>
6
+ <!-- CSS -->
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
8
+ {{STYLES_AND_SCRIPTS}}
9
+ </head>
10
+ <body>
11
+ <div id="top_nav">
12
+ <a id="home_menu_item" href="javascript:void(0)" onclick="navigate_to_home()"><span><i class="fa fa-home" aria-hidden="true"></i></span>&nbsp;Home</a>
13
+ <a id="index_menu_item" href="javascript:void(0)" onclick="navigate_to_home()" style="display: none;"><span><i class="fa fa-info" aria-hidden="true"></i></span>&nbsp;Index</a>
14
+ <a id="document_tree_menu_item" href="javascript:void(0)" onclick="openNav()" style="display: none;" title="Navigation Pane"><span><i class="fa fa-folder-open-o" aria-hidden="true"></i></span></a>
15
+ <input type="text" id="searchInput" placeholder="Search.." style="display: none;">
16
+ <a class="split">{{DOCUMENT_TITLE}}</a>
17
+ </div>
18
+ <div id="search_dropdown" class="search-results-content" style="display: none;"></div>
19
+ <div id="main">
20
+ <div id="closed_nav_pane" href="javascript:void(0)" onclick="openNav()">
21
+ </div>
22
+ <div id="nav_pane">
23
+ {{NAV_PANE}}
24
+ </div>
25
+ <div id="content" href="javascript:void(0)" onclick="closeNav()">
26
+ {{CONTENT}}
27
+ </div><!-- content -->
28
+ </div><!-- main -->
29
+ <div id="footer">
30
+ Powered by <a target="_blank" rel="noopener" href="https://www.almirah.site/">
31
+ Almirah Framework
32
+ {{GEM_VERSION}}
33
+ </a>
34
+ </div><!-- footer -->
35
+ <!-- The modal window for image zoom -->
36
+ <div id="image_modal_div" class="modal">
37
+ <span class="modal_close_btn" href="javascript:void(0)" onclick="modal_close_OnClick(this)">&times;</span>
38
+ <img class="modal_image" id="modal_image_id">
39
+ <div id="modal_image_caption"></div>
40
+ </div>
41
+ </body>
42
+
@@ -1,112 +1,112 @@
1
- function openNav() {
2
- if (document.getElementById("nav_pane").style.visibility == "visible"){
3
- document.getElementById("nav_pane").style.visibility = "hidden";
4
- }else{
5
- document.getElementById("nav_pane").style.visibility = "visible";
6
- }
7
- }
8
-
9
- function closeNav() {
10
- document.getElementById("nav_pane").style.visibility = "hidden";
11
- }
12
-
13
- window.onload = (event) => {
14
- for (var i = 0, n = document.images.length; i < n; i++)
15
- {
16
- elem = document.images[i];
17
- if (elem.width > 640)
18
- {
19
- elem.style.width = "640px";
20
- }
21
- }
22
- if (document.title == "Document Index"){
23
- document.getElementById('document_tree_menu_item').style.display = "none";
24
- document.getElementById('home_menu_item').style.display = "block";
25
- document.getElementById('index_menu_item').style.display = "none";
26
- if (document.URL.includes('http')){
27
- document.getElementById("searchInput").style.display = "block";
28
- }
29
- }else{
30
- document.getElementById('home_menu_item').style.display = "none";
31
- document.getElementById('index_menu_item').style.display = "block";
32
- if (document.title.includes("Traceability Matrix:")){
33
- document.getElementById('document_tree_menu_item').style.display = "none";
34
- } else {
35
- document.getElementById('document_tree_menu_item').style.display = "block";
36
- }
37
- }
38
- // Scroll a bit to make navigated anchor visible
39
- //setTimeout(function() {
40
- // window.scrollBy({
41
- // top: -40,
42
- // behavior: "smooth"
43
- // });
44
- // }, 200);
45
- };
46
-
47
- function downlink_OnClick(clicked){
48
- clicked.style.display = 'none';
49
- id_parts = clicked.id.split("_");
50
- required_id = "DLS_" + id_parts[1];
51
- document.getElementById(required_id).style.display = 'block';
52
- }
53
- function coverageLink_OnClick(clicked){
54
- clicked.style.display = 'none';
55
- id_parts = clicked.id.split("_");
56
- required_id = "COVS_" + id_parts[1];
57
- document.getElementById(required_id).style.display = 'block';
58
- }
59
- function upLink_OnClick(clicked){
60
- clicked.style.display = 'none';
61
- id_parts = clicked.id.split("_");
62
- required_id = "ULS_" + id_parts[1];
63
- document.getElementById(required_id).style.display = 'block';
64
- }
65
-
66
- function navigate_to_home(){
67
- if (document.title != "Document Index")
68
- {
69
- if (document.URL.includes('protocols')){
70
- window.location.href = "./../../../index.html";
71
- }else{
72
- window.location.href = "./../../index.html";
73
- }
74
- }else{
75
- window.location.href = "./index.html";
76
- }
77
- }
78
-
79
- // Modal window for image zoom
80
- function image_OnClick(clicked){
81
-
82
- var modal = document.getElementById('image_modal_div');
83
- var modalImg = document.getElementById("modal_image_id");
84
- var captionText = document.getElementById("modal_image_caption");
85
-
86
- modal.style.display = "block";
87
- modalImg.src = clicked.src;
88
- captionText.innerHTML = clicked.alt;
89
- }
90
-
91
- function modal_close_OnClick(clicked){
92
- var modal = document.getElementById('image_modal_div');
93
- modal.style.display = "none";
94
- }
95
-
96
- // Navigation Pane Expand/Collapse
97
- function nav_toggle_expand_list(el, e){
98
- var children = el.children;
99
- e.stopPropagation();
100
- for (var i = 0; i < children.length; i++) {
101
- var list_item = children[i];
102
- if (list_item.tagName == "UL"){
103
- if (list_item.style.display != "none"){
104
- list_item.style.display = "none";
105
- }else{
106
- list_item.style.display = "block";
107
- }
108
- }else if (list_item.tagName == "SPAN"){
109
- list_item.firstChild.classList.toggle("fa-plus-square-o");
110
- }
111
- }
1
+ function openNav() {
2
+ if (document.getElementById("nav_pane").style.visibility == "visible"){
3
+ document.getElementById("nav_pane").style.visibility = "hidden";
4
+ }else{
5
+ document.getElementById("nav_pane").style.visibility = "visible";
6
+ }
7
+ }
8
+
9
+ function closeNav() {
10
+ document.getElementById("nav_pane").style.visibility = "hidden";
11
+ }
12
+
13
+ window.onload = (event) => {
14
+ for (var i = 0, n = document.images.length; i < n; i++)
15
+ {
16
+ elem = document.images[i];
17
+ if (elem.width > 640)
18
+ {
19
+ elem.style.width = "640px";
20
+ }
21
+ }
22
+ if (document.title == "Document Index"){
23
+ document.getElementById('document_tree_menu_item').style.display = "none";
24
+ document.getElementById('home_menu_item').style.display = "block";
25
+ document.getElementById('index_menu_item').style.display = "none";
26
+ if (document.URL.includes('http')){
27
+ document.getElementById("searchInput").style.display = "block";
28
+ }
29
+ }else{
30
+ document.getElementById('home_menu_item').style.display = "none";
31
+ document.getElementById('index_menu_item').style.display = "block";
32
+ if (document.title.includes("Traceability Matrix:")){
33
+ document.getElementById('document_tree_menu_item').style.display = "none";
34
+ } else {
35
+ document.getElementById('document_tree_menu_item').style.display = "block";
36
+ }
37
+ }
38
+ // Scroll a bit to make navigated anchor visible
39
+ //setTimeout(function() {
40
+ // window.scrollBy({
41
+ // top: -40,
42
+ // behavior: "smooth"
43
+ // });
44
+ // }, 200);
45
+ };
46
+
47
+ function downlink_OnClick(clicked){
48
+ clicked.style.display = 'none';
49
+ id_parts = clicked.id.split("_");
50
+ required_id = "DLS_" + id_parts[1];
51
+ document.getElementById(required_id).style.display = 'block';
52
+ }
53
+ function coverageLink_OnClick(clicked){
54
+ clicked.style.display = 'none';
55
+ id_parts = clicked.id.split("_");
56
+ required_id = "COVS_" + id_parts[1];
57
+ document.getElementById(required_id).style.display = 'block';
58
+ }
59
+ function upLink_OnClick(clicked){
60
+ clicked.style.display = 'none';
61
+ id_parts = clicked.id.split("_");
62
+ required_id = "ULS_" + id_parts[1];
63
+ document.getElementById(required_id).style.display = 'block';
64
+ }
65
+
66
+ function navigate_to_home(){
67
+ if (document.title != "Document Index")
68
+ {
69
+ if (document.URL.includes('protocols')){
70
+ window.location.href = "./../../../index.html";
71
+ }else{
72
+ window.location.href = "./../../index.html";
73
+ }
74
+ }else{
75
+ window.location.href = "./index.html";
76
+ }
77
+ }
78
+
79
+ // Modal window for image zoom
80
+ function image_OnClick(clicked){
81
+
82
+ var modal = document.getElementById('image_modal_div');
83
+ var modalImg = document.getElementById("modal_image_id");
84
+ var captionText = document.getElementById("modal_image_caption");
85
+
86
+ modal.style.display = "block";
87
+ modalImg.src = clicked.src;
88
+ captionText.innerHTML = clicked.alt;
89
+ }
90
+
91
+ function modal_close_OnClick(clicked){
92
+ var modal = document.getElementById('image_modal_div');
93
+ modal.style.display = "none";
94
+ }
95
+
96
+ // Navigation Pane Expand/Collapse
97
+ function nav_toggle_expand_list(el, e){
98
+ var children = el.children;
99
+ e.stopPropagation();
100
+ for (var i = 0; i < children.length; i++) {
101
+ var list_item = children[i];
102
+ if (list_item.tagName == "UL"){
103
+ if (list_item.style.display != "none"){
104
+ list_item.style.display = "none";
105
+ }else{
106
+ list_item.style.display = "block";
107
+ }
108
+ }else if (list_item.tagName == "SPAN"){
109
+ list_item.firstChild.classList.toggle("fa-plus-square-o");
110
+ }
111
+ }
112
112
  }
@@ -1,138 +1,138 @@
1
- // Do search only on the Index Page
2
- import { create, search, insert } from 'https://unpkg.com/@orama/orama@latest/dist/index.js'
3
-
4
- // Create DB
5
- const db = await create({
6
- schema: {
7
- doc_title: 'string',
8
- doc_color: 'string',
9
- text: 'string',
10
- heading_url: 'string',
11
- heading_text: 'string'
12
- }
13
- })
14
- // Load JSON DB
15
- const rel_location = window.location.href.split('/').slice(0,-1).join('/');
16
- const json_location = rel_location + "/data/specifications_db.json";
17
- const response = await fetch(json_location);
18
- const data_rows = await response.json();
19
- let i = 0;
20
- while (i < data_rows.length) {
21
- await insert(db, {
22
- document: data_rows[i]["document"],
23
- doc_color: data_rows[i]["doc_color"],
24
- text: data_rows[i]["text"],
25
- heading_url: data_rows[i]["heading_url"],
26
- heading_text: data_rows[i]["heading_text"]
27
- })
28
- i++;
29
- }
30
-
31
- // Main db search function
32
- async function search_onKeyUp(){
33
-
34
- const search_input_text = document.getElementById("searchInput").value;
35
- // Close drop down when empty
36
- if ( search_input_text == ''){
37
- document.getElementById("search_dropdown").style.display = "none";
38
- }else{
39
- document.getElementById("search_dropdown").style.display = "block";
40
- }
41
-
42
- const searchResult = await search(db, {
43
- term: search_input_text,
44
- properties: ['text', 'heading_text'],
45
- exact: true,
46
- });
47
- if (searchResult == null){
48
- return;
49
- }
50
- //console.log(searchResult.hits.map((hit) => hit.document));
51
-
52
- // clear previous search
53
- const myNode = document.getElementById("search_dropdown");
54
- while (myNode.firstChild) {
55
- myNode.removeChild(myNode.lastChild);
56
- }
57
-
58
- if (searchResult.count == 0){
59
-
60
- const node = document.createElement("div");
61
- node.classList.add('search-item');
62
- const textnode = document.createTextNode("There are no matches found");
63
- node.appendChild(textnode);
64
- myNode.appendChild(node);
65
-
66
- }else{
67
-
68
- searchResult.hits.forEach ((value, index, array) =>{
69
- const doc_title = value.document["document"]
70
- const doc_color = value.document["doc_color"]
71
- const heading_url = value.document["heading_url"]
72
- const heading_text = value.document["heading_text"]
73
- const search_text = value.document["text"]
74
-
75
- const node_div = document.createElement("div");
76
- node_div.classList.add('search-item');
77
-
78
- const table = document.createElement("table");
79
- table.classList.add('search-result-table');
80
- node_div.appendChild(table);
81
-
82
- const tbody = document.createElement("tbody");
83
- table.appendChild(tbody);
84
-
85
- // Row 1
86
- let row = document.createElement("tr");
87
- let cell = document.createElement("td");
88
- let i = document.createElement("i");
89
- i.classList.add("fa","fa-file-text-o");
90
- i.style.backgroundColor = "#" + doc_color;
91
- cell.appendChild(i);
92
- let textnode = document.createTextNode("\xa0" + doc_title);
93
- cell.appendChild(textnode);
94
- row.appendChild(cell)
95
- cell = document.createElement("td");
96
-
97
- const a = document.createElement('a');
98
- const link = document.createTextNode(heading_text)
99
- a.appendChild(link);
100
- a.title = heading_text;
101
- a.href = heading_url;
102
- document.body.appendChild(a);
103
-
104
- cell.appendChild(a);
105
- row.appendChild(cell)
106
- tbody.appendChild(row)
107
-
108
- // Row 2
109
- row = document.createElement("tr");
110
- cell = document.createElement("td");
111
- cell.colSpan = 2;
112
- let show_text_parts = search_text.split(" ", 10).join(" ");
113
- textnode = document.createTextNode(show_text_parts);
114
- cell.appendChild(textnode)
115
- row.appendChild(cell)
116
- tbody.appendChild(row)
117
-
118
- myNode.appendChild(node_div);
119
- })
120
- }
121
- }
122
-
123
-
124
- document.getElementById("searchInput").addEventListener("keyup", search_onKeyUp);
125
-
126
- // Show when focus in
127
- document.getElementById("searchInput").addEventListener("focusin", (event) => {
128
- // clear previous search
129
- const element = document.getElementById("search_dropdown");
130
- while (element.firstChild) {
131
- element.removeChild(element.lastChild);
132
- }
133
- // show
134
- const rect = document.getElementById("searchInput").getBoundingClientRect();
135
- element.style.left = rect.left +'px';
136
- element.style.top = rect.top + rect.height + 4 +'px';
137
- element.style.display = "block";
138
- });
1
+ // Do search only on the Index Page
2
+ import { create, search, insert } from 'https://unpkg.com/@orama/orama@latest/dist/index.js'
3
+
4
+ // Create DB
5
+ const db = await create({
6
+ schema: {
7
+ doc_title: 'string',
8
+ doc_color: 'string',
9
+ text: 'string',
10
+ heading_url: 'string',
11
+ heading_text: 'string'
12
+ }
13
+ })
14
+ // Load JSON DB
15
+ const rel_location = window.location.href.split('/').slice(0,-1).join('/');
16
+ const json_location = rel_location + "/data/specifications_db.json";
17
+ const response = await fetch(json_location);
18
+ const data_rows = await response.json();
19
+ let i = 0;
20
+ while (i < data_rows.length) {
21
+ await insert(db, {
22
+ document: data_rows[i]["document"],
23
+ doc_color: data_rows[i]["doc_color"],
24
+ text: data_rows[i]["text"],
25
+ heading_url: data_rows[i]["heading_url"],
26
+ heading_text: data_rows[i]["heading_text"]
27
+ })
28
+ i++;
29
+ }
30
+
31
+ // Main db search function
32
+ async function search_onKeyUp(){
33
+
34
+ const search_input_text = document.getElementById("searchInput").value;
35
+ // Close drop down when empty
36
+ if ( search_input_text == ''){
37
+ document.getElementById("search_dropdown").style.display = "none";
38
+ }else{
39
+ document.getElementById("search_dropdown").style.display = "block";
40
+ }
41
+
42
+ const searchResult = await search(db, {
43
+ term: search_input_text,
44
+ properties: ['text', 'heading_text'],
45
+ exact: true,
46
+ });
47
+ if (searchResult == null){
48
+ return;
49
+ }
50
+ //console.log(searchResult.hits.map((hit) => hit.document));
51
+
52
+ // clear previous search
53
+ const myNode = document.getElementById("search_dropdown");
54
+ while (myNode.firstChild) {
55
+ myNode.removeChild(myNode.lastChild);
56
+ }
57
+
58
+ if (searchResult.count == 0){
59
+
60
+ const node = document.createElement("div");
61
+ node.classList.add('search-item');
62
+ const textnode = document.createTextNode("There are no matches found");
63
+ node.appendChild(textnode);
64
+ myNode.appendChild(node);
65
+
66
+ }else{
67
+
68
+ searchResult.hits.forEach ((value, index, array) =>{
69
+ const doc_title = value.document["document"]
70
+ const doc_color = value.document["doc_color"]
71
+ const heading_url = value.document["heading_url"]
72
+ const heading_text = value.document["heading_text"]
73
+ const search_text = value.document["text"]
74
+
75
+ const node_div = document.createElement("div");
76
+ node_div.classList.add('search-item');
77
+
78
+ const table = document.createElement("table");
79
+ table.classList.add('search-result-table');
80
+ node_div.appendChild(table);
81
+
82
+ const tbody = document.createElement("tbody");
83
+ table.appendChild(tbody);
84
+
85
+ // Row 1
86
+ let row = document.createElement("tr");
87
+ let cell = document.createElement("td");
88
+ let i = document.createElement("i");
89
+ i.classList.add("fa","fa-file-text-o");
90
+ i.style.backgroundColor = "#" + doc_color;
91
+ cell.appendChild(i);
92
+ let textnode = document.createTextNode("\xa0" + doc_title);
93
+ cell.appendChild(textnode);
94
+ row.appendChild(cell)
95
+ cell = document.createElement("td");
96
+
97
+ const a = document.createElement('a');
98
+ const link = document.createTextNode(heading_text)
99
+ a.appendChild(link);
100
+ a.title = heading_text;
101
+ a.href = heading_url;
102
+ document.body.appendChild(a);
103
+
104
+ cell.appendChild(a);
105
+ row.appendChild(cell)
106
+ tbody.appendChild(row)
107
+
108
+ // Row 2
109
+ row = document.createElement("tr");
110
+ cell = document.createElement("td");
111
+ cell.colSpan = 2;
112
+ let show_text_parts = search_text.split(" ", 10).join(" ");
113
+ textnode = document.createTextNode(show_text_parts);
114
+ cell.appendChild(textnode)
115
+ row.appendChild(cell)
116
+ tbody.appendChild(row)
117
+
118
+ myNode.appendChild(node_div);
119
+ })
120
+ }
121
+ }
122
+
123
+
124
+ document.getElementById("searchInput").addEventListener("keyup", search_onKeyUp);
125
+
126
+ // Show when focus in
127
+ document.getElementById("searchInput").addEventListener("focusin", (event) => {
128
+ // clear previous search
129
+ const element = document.getElementById("search_dropdown");
130
+ while (element.firstChild) {
131
+ element.removeChild(element.lastChild);
132
+ }
133
+ // show
134
+ const rect = document.getElementById("searchInput").getBoundingClientRect();
135
+ element.style.left = rect.left +'px';
136
+ element.style.top = rect.top + rect.height + 4 +'px';
137
+ element.style.display = "block";
138
+ });