Wiki source code of Linkding + SingleFile Archief

Version 13.1 by XWikiGuest on 2026/03/11 21:02

Show last authors
1 = Linkding + SingleFile Archief =
2
3 Bookmarks uit Linkding met inline archief-viewer. Klik op 📄 om de opgeslagen versie te bekijken.
4
5 {{html clean="false"}}
6 <style>
7 #ldsf-container {
8 display: flex;
9 height: 75vh;
10 border: 1px solid #4e5d6c;
11 border-radius: 4px;
12 overflow: hidden;
13 }
14 #ldsf-left {
15 width: 35%;
16 min-width: 200px;
17 max-width: 60%;
18 overflow-y: auto;
19 background: #2b3e50;
20 display: flex;
21 flex-direction: column;
22 }
23 #ldsf-divider {
24 width: 6px;
25 background: #4e5d6c;
26 cursor: col-resize;
27 flex-shrink: 0;
28 transition: background 0.2s;
29 }
30 #ldsf-divider:hover, #ldsf-divider.dragging { background: #df691a; }
31 #ldsf-right {
32 flex: 1;
33 min-width: 200px;
34 display: flex;
35 flex-direction: column;
36 }
37 #ldsf-status {
38 color: #6b7c8d;
39 font-size: 13px;
40 padding: 8px 12px;
41 flex-shrink: 0;
42 }
43 #ldsf-bookmarks {
44 overflow-y: auto;
45 flex: 1;
46 }
47 #ldsf-bookmarks ul {
48 list-style: none;
49 padding: 0;
50 margin: 0;
51 }
52 #ldsf-bookmarks li {
53 padding: 6px 12px;
54 border-bottom: 1px solid rgba(78,93,108,0.3);
55 display: flex;
56 align-items: center;
57 gap: 8px;
58 }
59 #ldsf-bookmarks li:hover { background: #3b4e60; }
60 #ldsf-bookmarks a {
61 color: #5bc0de;
62 text-decoration: none;
63 overflow: hidden;
64 text-overflow: ellipsis;
65 white-space: nowrap;
66 font-size: 13px;
67 }
68 #ldsf-bookmarks a:hover { color: #df691a; }
69 .sf-btn {
70 cursor: pointer;
71 background: #4e5d6c;
72 border: none;
73 color: #5bc0de;
74 padding: 2px 6px;
75 border-radius: 3px;
76 font-size: 13px;
77 flex-shrink: 0;
78 }
79 .sf-btn:hover { background: #df691a; color: #fff; }
80 #ldsf-viewer-bar {
81 display: none;
82 justify-content: space-between;
83 align-items: center;
84 padding: 4px 12px;
85 background: #2b3e50;
86 color: #ebebeb;
87 font-size: 12px;
88 flex-shrink: 0;
89 border-bottom: 1px solid #4e5d6c;
90 }
91 #ldsf-viewer-bar .close-btn {
92 cursor: pointer;
93 color: #d9534f;
94 font-size: 18px;
95 padding: 0 4px;
96 }
97 #ldsf-viewer-bar .close-btn:hover { color: #ff6b6b; }
98 #ldsf-viewer-frame {
99 width: 100%;
100 flex: 1;
101 border: none;
102 background: #fff;
103 display: none;
104 }
105 #ldsf-placeholder {
106 display: flex;
107 align-items: center;
108 justify-content: center;
109 flex: 1;
110 color: #6b7c8d;
111 font-size: 15px;
112 background: #2b3e50;
113 }
114 </style>
115
116 <div id="ldsf-container">
117 <div id="ldsf-left">
118 <div id="ldsf-status">Laden...</div>
119 <div id="ldsf-bookmarks"></div>
120 </div>
121 <div id="ldsf-divider"></div>
122 <div id="ldsf-right">
123 <div id="ldsf-viewer-bar">
124 <span id="ldsf-viewer-title"></span>
125 <span class="close-btn" data-sfclose="1">&times;</span>
126 </div>
127 <div id="ldsf-placeholder">Klik op &#128196; om een archief te bekijken</div>
128 <iframe id="ldsf-viewer-frame" sandbox="allow-same-origin"></iframe>
129 </div>
130 </div>
131
132 <script>
133 /* --- Configuration --- */
134 var LDSF = {
135 linkding: 'https://bookmarks.rhebergen.org/api/bookmarks/',
136 token: '3b7443e0f84e2b2b269adebb96d7475e4a5e653e',
137 tag: 'Nuclear-&-Energy',
138 count: 20,
139 share: 'eT2X9ttBHK5GoEY',
140 webdav: 'https://cloud.rhebergen.org/public.php/webdav/'
141 };
142 LDSF.auth = 'Basic ' + btoa(LDSF.share + ':');
143
144 /* --- State --- */
145 var ldsf_urlToFile = {};
146 var ldsf_fileMap = {};
147
148 /* --- URL matching (exact, with/without slash, without query string) --- */
149 function ldsfMatch(url) {
150 var tries = [url, url.replace(/\/$/, ''), url + '/', url.replace(/\?.*$/, '')];
151 for (var i = 0; i < tries.length; i++) {
152 if (ldsf_urlToFile[tries[i]]) return ldsf_urlToFile[tries[i]];
153 }
154 return null;
155 }
156
157 /* --- Show archived page in viewer --- */
158 function ldsfShow(filename) {
159 document.getElementById('ldsf-viewer-title').textContent = filename.replace(/\.html?$/i, '');
160 document.getElementById('ldsf-viewer-bar').style.display = 'flex';
161 document.getElementById('ldsf-placeholder').style.display = 'none';
162 var frame = document.getElementById('ldsf-viewer-frame');
163 frame.style.display = 'block';
164 frame.srcdoc = '<p style="padding:20px;color:#888">Laden...</p>';
165 fetch(LDSF.webdav + encodeURIComponent(filename), { headers: { 'Authorization': LDSF.auth } })
166 .then(function(r) { return r.text(); })
167 .then(function(html) { frame.srcdoc = html; })
168 .catch(function(e) { frame.srcdoc = '<p style="padding:20px;color:#d9534f">Fout: ' + e.message + '</p>'; });
169 }
170
171 /* --- Close viewer --- */
172 function ldsfClose() {
173 document.getElementById('ldsf-viewer-bar').style.display = 'none';
174 document.getElementById('ldsf-viewer-frame').style.display = 'none';
175 document.getElementById('ldsf-placeholder').style.display = 'flex';
176 }
177
178 /* --- Render bookmark list --- */
179 function ldsfRender(data) {
180 var total = data.count || 0, archived = 0;
181 var container = document.getElementById('ldsf-bookmarks');
182 var html = '<ul>';
183 (data.results || []).forEach(function(bm, i) {
184 var title = bm.title || bm.website_title || bm.url;
185 var file = ldsfMatch(bm.url);
186 if (file) { archived++; ldsf_fileMap[i] = file; }
187 html += '<li>';
188 if (file) html += '<span class="sf-btn" data-sf="' + i + '" title="Archief bekijken">&#128196;</span>';
189 html += '<a href="' + bm.url + '" target="_blank">' + title + '</a></li>';
190 });
191 container.innerHTML = html + '</ul>';
192 document.getElementById('ldsf-status').textContent = total + ' bookmarks, ' + archived + ' met archief';
193 }
194
195 /* --- Click handler (event delegation, works in XWiki html macro) --- */
196 document.addEventListener('click', function(e) {
197 var t = e.target;
198 if (!t || !t.getAttribute) return;
199 var sf = t.getAttribute('data-sf');
200 if (sf !== null && ldsf_fileMap[sf]) ldsfShow(ldsf_fileMap[sf]);
201 if (t.getAttribute('data-sfclose') !== null) ldsfClose();
202 }, true);
203
204 /* --- Draggable divider --- */
205 var ldsf_drag = false;
206 document.getElementById('ldsf-divider').addEventListener('mousedown', function(e) {
207 ldsf_drag = true;
208 this.classList.add('dragging');
209 e.preventDefault();
210 });
211 document.addEventListener('mousemove', function(e) {
212 if (!ldsf_drag) return;
213 var box = document.getElementById('ldsf-container').getBoundingClientRect();
214 var w = e.clientX - box.left;
215 if (w >= 200 && w <= box.width * 0.6)
216 document.getElementById('ldsf-left').style.width = w + 'px';
217 });
218 document.addEventListener('mouseup', function() {
219 if (ldsf_drag) {
220 ldsf_drag = false;
221 document.getElementById('ldsf-divider').classList.remove('dragging');
222 }
223 });
224
225 /* --- Load index, then bookmarks --- */
226 fetch(LDSF.webdav + 'index.json', { headers: { 'Authorization': LDSF.auth } })
227 .then(function(r) { return r.ok ? r.json() : {}; })
228 .then(function(idx) {
229 for (var f in idx) { if (idx.hasOwnProperty(f)) ldsf_urlToFile[idx[f]] = f; }
230 })
231 .catch(function() {})
232 .then(function() {
233 return fetch(LDSF.linkding + '?limit=' + LDSF.count + '&q=%23' + encodeURIComponent(LDSF.tag),
234 { headers: { 'Authorization': 'Token ' + LDSF.token } });
235 })
236 .then(function(r) { return r.json(); })
237 .then(ldsfRender)
238 .catch(function(e) {
239 document.getElementById('ldsf-status').textContent = 'Fout: ' + e.message;
240 });
241 </script>
242 {{/html}}