-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapplication.js
109 lines (90 loc) · 3.8 KB
/
application.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import scrollIntoView from 'scroll-into-view-if-needed'
function forestFromText(data) {
let res = [], levels = [res];
for (let line of data.split('\n')) {
let
level = line.search(/\S/) >> 1 // (index of first non whitespace char) / 2, assuming indentation is 2 spaces
, trimmed = line.trim()
, children = []
;
if (!trimmed) continue;
const i = trimmed.indexOf(':');
let name = trimmed;
let href = null;
if (i !== -1) {
name = trimmed.slice(0, i).trim();
href = trimmed.slice(i + 1).trim();
}
levels[level].push({ name: name, href: href, children: children });
levels[++level] = children;
}
return res;
}
function treePaths(tree) {
if (tree.children.length === 0) {
return [{ names: [tree.name], label: tree.name, href: tree.href }];
} else {
return tree.children
.map((child) => treePaths(child))
.flat()
.map((flattenedTree) => {
return { names: [tree.name, ...flattenedTree.names], label: `${tree.name} / ${flattenedTree.label}`, href: flattenedTree.href }
});
}
}
function forestPaths(forest) {
return forest.map((tree) => treePaths(tree)).flat().sort((a, b) => a.label.toLowerCase() > b.label.toLowerCase() ? 1 : -1);
}
function forestFromPreElement() {
const forestText = document.getElementById('bookmarks').innerText.trim();
return forestFromText(forestText);
}
function xHtmlForTree(tree) {
if (tree.children.length === 0) {
return `<li><a href="${tree.href}">${tree.name}</a></li>`;
} else {
const xHtmlForChildrenArray = tree.children.map((child) => xHtmlForTree(child));
const xHtmlForChildren = xHtmlForChildrenArray.map((xHtmlForChild) => `<ul>${xHtmlForChild}</ul>`).join('\n');
return `<li><span class="font-medium text-gray-500">${tree.name}</span>\n${xHtmlForChildren}</li>`;
}
}
document.addEventListener('alpine:init', () => {
const forest = forestFromPreElement();
const paths = forestPaths(forest);
Alpine.data('bookmarks', () => ({
version: '0.0.2',
xHtmlForForest: forest.map((tree) => `<ul>${xHtmlForTree(tree)}</ul>`),
searchString: '',
activeSearchResultIndex: 0,
search() {
if (this.searchString.trim() === "")
return [];
const normalisedSearchString = this.searchString.trim().toLowerCase();
const searchStringParts = normalisedSearchString.split(/\s+/);
return paths.filter((path) =>
searchStringParts.every((searchStringPart) => path.names.some((name) => name.toLowerCase().includes(searchStringPart))) ||
path.href.toLowerCase().includes(normalisedSearchString)
);
},
makeNextSearchResultActive() {
this.activeSearchResultIndex = Math.min(this.activeSearchResultIndex + 1, this.search().length - 1);
const searchResultElem = document.getElementById('search-result-' + this.activeSearchResultIndex);
if (searchResultElem)
scrollIntoView(searchResultElem, {
scrollMode: 'if-needed',
block: 'nearest',
inline: 'nearest',
});
},
makePreviousSearchResultActive() {
this.activeSearchResultIndex = Math.max(this.activeSearchResultIndex - 1, 0);
const searchResultElem = document.getElementById('search-result-' + this.activeSearchResultIndex);
if (searchResultElem)
scrollIntoView(searchResultElem, {
scrollMode: 'if-needed',
block: 'nearest',
inline: 'nearest',
});
}
}))
})