PageSourceSearch

https://www.akrehamn.vgs.no/script/vanilla/autosuggest/autosuggest.vanilla.js?v=20250710

js akrehamn.vgs.no collected 2026-10-06 00:06:40 UTC 15,708 bytes, 381 lines download raw bytes

1(function () {
2    "use strict";
3    var requests = [];
4
5    var AutoSuggest = {
6        init: function (element, options) {
7            if (!element || !element.nodeType) {
8                console.error('AutoSuggest.init: Invalid element provided');
9                return;
10            }
11            
12            const settings = Object.assign({
13                'PortalID': -1,
14                'SpakID': -1,
15                'Token': '',
16                'AutoSuggestWordsURL': '',
17                'DidYouMeanURL': '',
18                'btnSearch': null,
19                Container: null,
20                oSeResultatFor: 'Se resultat for:',
21                MinimumWordLength: 3
22            }, options || {});
23
24            var inputSearch = null;
25            var container = null;
26
27            inputSearch = element;
28            container = settings.Container || element;
29
30            var timeout = null;
31            var previousLi = null;
32
33            inputSearch.addEventListener("keydown", function (e) {
34                var autoSuggestEl = document.getElementById("SokAutoSuggest");
35                if (e.keyCode == 13 && autoSuggestEl) {
36                    var hoverLi = autoSuggestEl.querySelector("li.hover");
37                    if (hoverLi) {
38                        e.preventDefault();
39                        inputSearch.value = hoverLi.textContent;
40                        hoverLi.click();
41                    }
42                }
43            });
44
45            inputSearch.addEventListener("keyup", function (e) {
46                if (timeout != null) {
47                    clearTimeout(timeout);
48                }
49                
50                var autoSuggestEl = document.getElementById("SokAutoSuggest");
51                
52                // Arrow key navigation
53                if ((e.keyCode == 40 || e.keyCode == 38) && autoSuggestEl) {
54                    var hoverLi = autoSuggestEl.querySelector("li.hover");
55                    var allLis = autoSuggestEl.querySelectorAll("li");
56                    
57                    if (hoverLi) {
58                        var currentIndex = Array.prototype.indexOf.call(allLis, hoverLi);
59                        
60                        if (currentIndex == allLis.length - 1 && e.keyCode == 40) {
61                            // At bottom and pressing down, jump to first
62                            if (previousLi) {
63                                AutoSuggest.triggerMouseOut(previousLi);
64                            }
65                            AutoSuggest.triggerMouseOver(allLis[0]);
66                            previousLi = allLis[0];
67                        }
68                        else if (currentIndex == 0 && e.keyCode == 38) {
69                            // At top and pressing up, jump to last
70                            if (previousLi) {
71                                AutoSuggest.triggerMouseOut(previousLi);
72                            }
73                            AutoSuggest.triggerMouseOver(allLis[allLis.length - 1]);
74                            previousLi = allLis[allLis.length - 1];
75                        }
76                        else {
77                            // Normal navigation
78                            if (previousLi) {
79                                AutoSuggest.triggerMouseOut(previousLi);
80                            }
81                            if (e.keyCode == 38) {
82                                AutoSuggest.triggerMouseOver(allLis[currentIndex - 1]);
83                                previousLi = allLis[currentIndex - 1];
84                            } else {
85                                AutoSuggest.triggerMouseOver(allLis[currentIndex + 1]);
86                                previousLi = allLis[currentIndex + 1];
87                            }
88                        }
89                    } else {
90                        // First time user presses arrow in navigation
91                        if (allLis.length > 0) {
92                            AutoSuggest.triggerMouseOver(allLis[0]);
93                            previousLi = allLis[0];
94                        }
95                    }
96                } else {
97                    previousLi = null;
98                    timeout = setTimeout(function () {
99                        if (inputSearch.value.length < settings.MinimumWordLength) {
100                            var autoSuggestEl = document.getElementById("SokAutoSuggest");
101                            if (autoSuggestEl) {
102                                autoSuggestEl.remove();
103                            }
104                        }
105
106                        if (inputSearch.value.length >= settings.MinimumWordLength) {
107                            AutoSuggest.Query(inputSearch, container, settings);
108                        }
109                    }, 250);
110                }
111            });
112        },
113
114        triggerMouseOver: function(element) {
115            element.style.backgroundColor = "#EDEDED";
116            element.classList.add("hover");
117        },
118
119        triggerMouseOut: function(element) {
120            element.style.backgroundColor = "";
121            element.classList.remove("hover");
122        },
123
124        Query: function (inputSearch, container, settings) {
125            if (requests.length > 0) {
126                requests.pop().abort();
127            }
128            
129            var xhr = new XMLHttpRequest();
130            xhr.open("POST", settings.AutoSuggestWordsURL, true);
131            xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
132            xhr.setRequestHeader("PortalId", settings.PortalID);
133            xhr.setRequestHeader("SprakId", settings.SprakID);
134            xhr.setRequestHeader("RequestVerificationToken", settings.Token);
135            
136            xhr.onreadystatechange = function() {
137                if (xhr.readyState === XMLHttpRequest.DONE) {
138                    if (xhr.status === 200) {
139                        var resultat = JSON.parse(xhr.responseText);
140                        AutoSuggest.CreateBox(resultat, inputSearch.value, inputSearch, container, settings);
141                    }
142                }
143            };
144            
145            xhr.send(JSON.stringify(inputSearch.value));
146            requests.push(xhr);
147        },
148
149        CreateBox: function (resultat, query, inputSearch, container, settings) {
150            var existingBox = document.getElementById("SokAutoSuggest");
151            if (existingBox) {
152                existingBox.remove();
153            }
154
155            if (resultat.length == 0) {
156                AutoSuggest.DidYouMean(inputSearch, container, settings);
157                return false;
158            }
159
160            var offset = AutoSuggest.getOffset(container);
161            var offsetInput = AutoSuggest.getOffset(inputSearch);
162            var width = container.offsetWidth;
163            
164            if (offsetInput.left - 25 > offset.left) {
165                // Container is not styled, use inputsearch box
166                container = inputSearch;
167                offset = offsetInput;
168                width = inputSearch.offsetWidth + 3;
169            }
170            else if(!container.offsetHeight){
171                container = inputSearch;
172            }
173
174            var wrapper = document.createElement("div");
175            wrapper.id = "SokAutoSuggest";
176            wrapper.style.width = width + "px";
177            wrapper.style.position = "absolute";
178            wrapper.style.top = (offset.top + container.offsetHeight) + "px";
179            wrapper.style.left = offset.left + "px";
180            wrapper.style.backgroundColor = "white";
181            wrapper.style.border = "1px solid #ccc";
182            wrapper.style.boxShadow = "0 2px 4px rgba(0,0,0,0.1)";
183            
184            var hoverTimeout;
185            wrapper.addEventListener("mouseenter", function () {
186                if (hoverTimeout) {
187                    clearTimeout(hoverTimeout);
188                }
189            });
190            
191            wrapper.addEventListener("mouseleave", function () {
192                var that = this;
193                hoverTimeout = setTimeout(function () {
194                    that.remove();
195                }, 1500);
196            });
197
198            var ul = document.createElement("ul");
199            ul.style.listStyle = "none";
200            ul.style.margin = "0";
201            ul.style.padding = "0";
202
203            var finnesIListe = false;
204            for (var i = 0; i < resultat.length; i++) {
205                if (resultat[i].toLowerCase() == query.toLowerCase()) {
206                    finnesIListe = true;
207                }
208                ul.appendChild(AutoSuggest.LagLi(resultat[i], query, inputSearch, settings));
209            }
210            if (!finnesIListe) {
211                ul.insertBefore(AutoSuggest.LagLi(query, query, inputSearch, settings), ul.firstChild);
212            }
213            wrapper.appendChild(ul);
214            document.body.appendChild(wrapper);
215        },
216
217        getOffset: function(element) {
218            if (!element || !element.getBoundingClientRect) {
219                return { top: 0, left: 0 };
220            }
221            var rect = element.getBoundingClientRect();
222            var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
223            var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
224            return {
225                top: rect.top + scrollTop,
226                left: rect.left + scrollLeft
227            };
228        },
229
230        LagLi: function (resultat, query, inputSearch, settings) {
231            var activeElement = document.activeElement;
232            var computedStyle = window.getComputedStyle(activeElement);
233            var padding = computedStyle.padding;
234            var text = AutoSuggest.MarkBold(resultat, query);
235            
236            var li = document.createElement("li");
237            li.className = "resultat";
238            li.style.padding = padding;
239            li.style.cursor = "pointer";
240            li.innerHTML = text;
241            
242            li.addEventListener("click", function () {
243                inputSearch.value = this.textContent;
244                if (settings.btnSearch) {
245                    settings.btnSearch.click();
246                }
247                var autoSuggestEl = document.getElementById("SokAutoSuggest");
248                if (autoSuggestEl) {
249                    autoSuggestEl.remove();
250                }
251            });
252            
253            li.addEventListener("mouseenter", function () {
254                this.style.backgroundColor = "#EDEDED";
255                this.classList.add("hover");
256            });
257            
258            li.addEventListener("mouseleave", function () {
259                this.style.backgroundColor = "";
260                this.classList.remove("hover");
261            });
262            
263            return li;
264        },
265
266        MarkBold: function (text, val) {
267            // Security: HTML-escape the suggestion text before applying <strong> highlighting,
268            text = AutoSuggest.escapeHtml(text);
269
270            if (val.split(' ').length > 1) {
271                var liste = val.split(' ');
272                for (var i = 0; i < liste.length; i++) {
273                    var regex = new RegExp("(" + AutoSuggest.escapeRegExp(liste[i]) + ")", "gi");
274                    text = text.replace(regex, "<strong>$1</strong>");
275                }
276            } else {
277                var regex = new RegExp("(" + AutoSuggest.escapeRegExp(val) + ")", "gi");
278                text = text.replace(regex, "<strong>$1</strong>");
279            }
280            return text;
281        },
282
283        escapeRegExp: function(string) {
284            return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
285        },
286
287        escapeHtml: function (string) {
288            if (string == null) {
289                return '';
290            }
291            return String(string)
292                .replace(/&/g, '&amp;')
293                .replace(/</g, '&lt;')
294                .replace(/>/g, '&gt;')
295                .replace(/"/g, '&quot;')
296                .replace(/'/g, '&#39;');
297        },
298
299        DidYouMean: function (inputSearch, container, settings) {
300            if (requests.length > 0) {
301                requests.pop().abort();
302            }
303            
304            if (inputSearch.value.length > settings.MinimumWordLength) {
305                var xhr = new XMLHttpRequest();
306                xhr.open("POST", settings.DidYouMeanURL, true);
307                xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
308                xhr.setRequestHeader("PortalId", settings.PortalID);
309                xhr.setRequestHeader("SprakId", settings.SprakID);
310                xhr.setRequestHeader("RequestVerificationToken", settings.Token);
311                
312                xhr.onreadystatechange = function() {
313                    if (xhr.readyState === XMLHttpRequest.DONE) {
314                        if (xhr.status === 200) {
315                            var resultat = JSON.parse(xhr.responseText);
316                            var forslag = resultat;
317                            if(forslag != null) {
318                                AutoSuggest.CreateBox(forslag.Ord, forslag.KorrektOrd, inputSearch, container, settings);
319                            }
320                        }
321                    }
322                };
323                
324                xhr.send(JSON.stringify(inputSearch.value));
325                requests.push(xhr);
326            }
327        }
328    };
329
330    // Public API
331    window.AutoSuggest = {
332        init: function(selector, options) {
333            var elements = [];
334            
335            if (!selector) {
336                console.error('AutoSuggest: No selector provided');
337                return;
338            }
339            
340            if (typeof selector === 'string') {
341                elements = document.querySelectorAll(selector);
342                if (elements.length === 0) {
343                    console.warn('AutoSuggest: No elements found for selector "' + selector + '"');
344                    return;
345                }
346            } else if (selector && selector.nodeType) {
347                elements = [selector];
348            } else if (selector && selector.length !== undefined) {
349                // Array-like object (NodeList, HTMLCollection, Array)
350                elements = selector;
351            } else {
352                console.error('AutoSuggest: Invalid selector type');
353                return;
354            }
355            
356            Array.prototype.forEach.call(elements, function(element) {
357                if (element && element.nodeType === 1) { // Ensure it's an element node
358                    AutoSuggest.init(element, options);
359                }
360            });
361        }
362    };
363
364    // Alternative usage pattern similar to jQuery
365    window.autosuggest = function(selector, options) {
366        if (!selector) {
367            console.error('autosuggest: No selector provided');
368            return;
369        }
370        return window.AutoSuggest.init(selector, options);
371    };
372
373    // For backward compatibility - wait for DOM to be ready if needed
374    if (typeof document !== 'undefined') {
375        if (document.readyState === 'loading') {
376            document.addEventListener('DOMContentLoaded', function() {
377                // DOM is ready
378            });
379        }
380    }
381})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.