Suche

Von $1

    Inhaltsverzeichnis
    keine Gliederung

    Version seit 19:05, 11 Aug 2026

    zu dieser Version.

    Zurück zu Versionshistorie.

    Zeige aktuelle Version

    (function() {
    
        /* ============================================================
           HELIKON - MINDTOUCH SEARCH ADD-ON v1.0
           ============================================================
           Paste AFTER the main Helikon chat template.
           
           What it does:
           - Watches the chat for new user messages
           - Searches MindTouch API: Pages + Tags + Files (JSON)
           - Shows grouped, collapsible results IN the chat
           - Results appear while LLM is thinking
           - No modification to existing template needed
           ============================================================ */
    
        var PF = '"Press Start 2P","Courier New",Courier,monospace';
        var Q = String.fromCharCode(34);
        var SQ = String.fromCharCode(39);
        var T = String.fromCharCode(60);
        var TC = String.fromCharCode(60, 47);
        var G = String.fromCharCode(62);
        var AMP = String.fromCharCode(38);
    
        /* === INJECT CSS === */
        var css = ''
        + '.mtSearchBlock { margin:0 0 14px 0; border:2px solid #0077aa; border-radius:8px; background:#f0f8ff; overflow:hidden; font-family:' + PF + '; }'
        + '.mtSearchHeader { background:linear-gradient(135deg, #005580, #0077aa); color:#fff; padding:10px 14px; font-size:12px; line-height:1.6; display:flex; justify-content:space-between; align-items:center; }'
        + '.mtSearchHeader .mtHdrLeft { display:flex; align-items:center; gap:6px; }'
        + '.mtSearchHeader .mtHdrBadge { background:rgba(255,255,255,0.2); padding:2px 8px; border-radius:10px; font-size:11px; }'
        + '.mtSearchGroup { border-top:1px solid #cce0ee; }'
        + '.mtGroupHead { padding:10px 14px; font-size:12px; line-height:1.6; color:#0077aa; cursor:pointer; background:#e8f4fd; transition:background 0.15s; display:flex; justify-content:space-between; align-items:center; user-select:none; }'
        + '.mtGroupHead:hover { background:#d0e8f7; }'
        + '.mtGroupHead .mtGrpLeft { display:flex; align-items:center; gap:6px; }'
        + '.mtGroupHead .mtCount { background:#0077aa; color:#fff; padding:2px 8px; border-radius:10px; font-size:10px; min-width:16px; text-align:center; }'
        + '.mtGroupHead .mtArrow { transition:transform 0.2s; display:inline-block; font-size:10px; }'
        + '.mtGroupHead.open .mtArrow { transform:rotate(90deg); }'
        + '.mtGroupBody { max-height:0; overflow:hidden; transition:max-height 0.3s ease; }'
        + '.mtGroupBody.open { max-height:800px; }'
        + '.mtResultItem { padding:8px 14px; border-top:1px solid #e0ecf4; font-size:11px; line-height:1.8; transition:background 0.1s; }'
        + '.mtResultItem:first-child { border-top:none; }'
        + '.mtResultItem:hover { background:#e8f4fd; }'
        + '.mtResultItem a { color:#0077aa; text-decoration:none; font-size:12px; font-weight:bold; }'
        + '.mtResultItem a:hover { text-decoration:underline; color:#005580; }'
        + '.mtResultItem .mtPath { color:#999; font-size:10px; display:block; margin-top:2px; word-break:break-all; }'
        + '.mtResultItem .mtSnippet { color:#666; font-size:10px; display:block; margin-top:3px; font-family:Courier,monospace; }'
        + '.mtResultItem .mtMeta { color:#999; font-size:10px; }'
        + '.mtResultItem .mtTagBadge { display:inline-block; background:#0077aa; color:#fff; padding:2px 8px; border-radius:10px; font-size:10px; margin:2px 4px 2px 0; }'
        + '.mtNoHits { padding:12px 14px; color:#999; font-size:12px; text-align:center; line-height:1.6; }'
        + '.mtSearchBlock .mtLoading { padding:12px 14px; color:#0077aa; font-size:11px; text-align:center; }'
        + '@keyframes mtPulse { 0%,100% { opacity:1; } 50% { opacity:0.4; } }'
        + '.mtLoading { animation: mtPulse 1.2s ease-in-out infinite; }';
    
        var styleEl = document.createElement('style');
        styleEl.type = 'text/css';
        if (styleEl.styleSheet) { styleEl.styleSheet.cssText = css; }
        else { styleEl.appendChild(document.createTextNode(css)); }
        document.head.appendChild(styleEl);
    
        /* === CONFIG === */
        var MT_BASE = '/@api/deki';
        var SEARCH_LIMIT = 10;
        var TAG_MIN_WORD = 3;
    
        /* === MT API (JSON) === */
        function mtJson(path, callback) {
            var url = MT_BASE + path;
            var sep = (url.indexOf('?') === -1) ? '?' : AMP;
            url += sep + 'dream.out.format=json';
    
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onload = function() {
                if (xhr.status >= 200 && xhr.status < 300) {
                    try { callback(null, JSON.parse(xhr.responseText)); }
                    catch(e) { callback('JSON parse error'); }
                } else { callback('HTTP ' + xhr.status); }
            };
            xhr.onerror = function() { callback('Netzwerkfehler'); };
            xhr.send();
        }
    
        /* === SEARCH: Content (Pages + Files) === */
        function searchContent(query, callback) {
            mtJson('/site/search?q=' + encodeURIComponent(query) + AMP + 'limit=' + SEARCH_LIMIT, function(err, data) {
                if (err) { callback(err, null); return; }
    
                var result = new Object();
                result.pages = new Array();
                result.files = new Array();
    
                /* Pages */
                if (data.page) {
                    var pages = data.page;
                    if (!pages.length && pages['@id']) {
                        var tmp1 = new Array();
                        tmp1.push(data.page);
                        pages = tmp1;
                    }
                    var pi;
                    for (pi = 0; pi < pages.length && pi < SEARCH_LIMIT; pi++) {
                        var p = new Object();
                        p.id = pages[pi]['@id'] || '';
                        p.title = pages[pi].title || '';
                        p.path = pages[pi].path || '';
                        p.score = pages[pi]['@score'] || '0';
                        p.uri = '';
                        if (pages[pi]['uri.ui']) { p.uri = pages[pi]['uri.ui']; }
                        result.pages.push(p);
                    }
                }
    
                /* Files */
                if (data.file) {
                    var files = data.file;
                    if (!files.length && files['@id']) {
                        var tmp2 = new Array();
                        tmp2.push(data.file);
                        files = tmp2;
                    }
                    var fi;
                    for (fi = 0; fi < files.length && fi < SEARCH_LIMIT; fi++) {
                        var f = new Object();
                        f.id = files[fi]['@id'] || '';
                        f.filename = files[fi].filename || '';
                        f.type = (files[fi].contents && files[fi].contents['@type']) ? files[fi].contents['@type'] : '';
                        f.size = (files[fi].contents && files[fi].contents['@size']) ? files[fi].contents['@size'] : '';
                        f.href = (files[fi].contents && files[fi].contents['@href']) ? files[fi].contents['@href'] : '';
                        f.parentTitle = (files[fi]['page.parent'] && files[fi]['page.parent'].title) ? files[fi]['page.parent'].title : '';
                        result.files.push(f);
                    }
                }
    
                callback(null, result);
            });
        }
    
        /* === SEARCH: Tags === */
        function searchTags(query, callback) {
            mtJson('/site/tags', function(err, data) {
                if (err) { callback(err, null); return; }
                var matched = new Array();
                var q = query.toLowerCase();
                var words = q.split(' ');
    
                if (data.tag) {
                    var tags = data.tag;
                    if (!tags.length && tags['@value']) {
                        var tmp3 = new Array();
                        tmp3.push(data.tag);
                        tags = tmp3;
                    }
                    var ti;
                    for (ti = 0; ti < tags.length; ti++) {
                        var tagVal = (tags[ti]['@value'] || '').toLowerCase();
                        var tagTitle = (tags[ti].title || '').toLowerCase();
                        var wi;
                        for (wi = 0; wi < words.length; wi++) {
                            if (words[wi].length >= TAG_MIN_WORD && (tagVal.indexOf(words[wi]) !== -1 || tagTitle.indexOf(words[wi]) !== -1)) {
                                var t = new Object();
                                t.value = tags[ti]['@value'] || '';
                                t.title = tags[ti].title || '';
                                t.count = tags[ti]['@count'] || '0';
                                t.uri = tags[ti].uri || '';
                                matched.push(t);
                                break;
                            }
                        }
                    }
                }
    
                callback(null, matched);
            });
        }
    
        /* === RENDER: Grouped results HTML === */
        function renderResults(query, pages, tags, files) {
            var total = pages.length + tags.length + files.length;
    
            var html = '';
            html += T + 'div class=' + Q + 'mtSearchBlock' + Q + G;
    
            /* Header */
            html += T + 'div class=' + Q + 'mtSearchHeader' + Q + G;
            html += T + 'span class=' + Q + 'mtHdrLeft' + Q + G;
            html += String.fromCharCode(128269) + ' MindTouch: ' + Q;
            html += escHtml(query) + Q;
            html += TC + 'span' + G;
            html += T + 'span class=' + Q + 'mtHdrBadge' + Q + G + total + ' Treffer' + TC + 'span' + G;
            html += TC + 'div' + G;
    
            if (total === 0) {
                html += T + 'div class=' + Q + 'mtNoHits' + Q + G;
                html += 'Keine internen Treffer gefunden.';
                html += TC + 'div' + G;
                html += TC + 'div' + G;
                return html;
            }
    
            /* Group: Seiten */
            if (pages.length > 0) {
                html += renderGroup('mtGP' + Date.now(), String.fromCharCode(128196) + ' Seiten', pages.length, function() {
                    var inner = '';
                    var i;
                    for (i = 0; i < pages.length; i++) {
                        var pg = pages[i];
                        var url = pg.uri || ('/' + pg.path);
                        inner += T + 'div class=' + Q + 'mtResultItem' + Q + G;
                        inner += T + 'a href=' + Q + escAttr(url) + Q + ' target=' + Q + '_blank' + Q + G;
                        inner += escHtml(pg.title || pg.path);
                        inner += TC + 'a' + G;
                        if (pg.path) {
                            inner += T + 'span class=' + Q + 'mtPath' + Q + G + escHtml(pg.path) + TC + 'span' + G;
                        }
                        inner += TC + 'div' + G;
                    }
                    return inner;
                });
            }
    
            /* Group: Tags */
            if (tags.length > 0) {
                html += renderGroup('mtGT' + Date.now(), String.fromCharCode(127991) + ' Tags', tags.length, function() {
                    var inner = '';
                    var i;
                    for (i = 0; i < tags.length; i++) {
                        var tg = tags[i];
                        inner += T + 'div class=' + Q + 'mtResultItem' + Q + G;
                        inner += T + 'span class=' + Q + 'mtTagBadge' + Q + G + escHtml(tg.title) + TC + 'span' + G;
                        inner += ' ' + T + 'span class=' + Q + 'mtMeta' + Q + G + tg.count + ' Seiten' + TC + 'span' + G;
                        if (tg.uri) {
                            inner += ' ' + T + 'a href=' + Q + escAttr(tg.uri) + Q + ' target=' + Q + '_blank' + Q + ' style=' + Q + 'font-size:10px;font-weight:normal' + Q + G + 'anzeigen' + TC + 'a' + G;
                        }
                        inner += TC + 'div' + G;
                    }
                    return inner;
                });
            }
    
            /* Group: Dateien */
            if (files.length > 0) {
                html += renderGroup('mtGF' + Date.now(), String.fromCharCode(128190) + ' Dateien', files.length, function() {
                    var inner = '';
                    var i;
                    for (i = 0; i < files.length; i++) {
                        var fl = files[i];
                        var sizeStr = fl.size ? (Math.round(parseInt(fl.size, 10) / 1024)) + ' KB' : '';
                        inner += T + 'div class=' + Q + 'mtResultItem' + Q + G;
                        if (fl.href) {
                            inner += T + 'a href=' + Q + escAttr(fl.href) + Q + ' target=' + Q + '_blank' + Q + G;
                            inner += escHtml(fl.filename);
                            inner += TC + 'a' + G;
                        } else {
                            inner += escHtml(fl.filename);
                        }
                        inner += ' ' + T + 'span class=' + Q + 'mtMeta' + Q + G;
                        if (fl.type) inner += fl.type;
                        if (sizeStr) inner += ' | ' + sizeStr;
                        inner += TC + 'span' + G;
                        if (fl.parentTitle) {
                            inner += T + 'span class=' + Q + 'mtPath' + Q + G + 'auf: ' + escHtml(fl.parentTitle) + TC + 'span' + G;
                        }
                        inner += TC + 'div' + G;
                    }
                    return inner;
                });
            }
    
            html += TC + 'div' + G;
            return html;
        }
    
        /* === RENDER: Single collapsible group === */
        function renderGroup(gid, label, count, contentFn) {
            var html = '';
            html += T + 'div class=' + Q + 'mtSearchGroup' + Q + G;
    
            /* Group header with toggle */
            html += T + 'div class=' + Q + 'mtGroupHead' + Q;
            html += ' onclick=' + Q;
            html += 'var b=document.getElementById(' + SQ + gid + SQ + ');';
            html += 'if(b){b.classList.toggle(' + SQ + 'open' + SQ + ');this.classList.toggle(' + SQ + 'open' + SQ + ');}';
            html += Q + G;
    
            html += T + 'span class=' + Q + 'mtGrpLeft' + Q + G + label + TC + 'span' + G;
            html += T + 'span style=' + Q + 'display:flex;align-items:center;gap:8px' + Q + G;
            html += T + 'span class=' + Q + 'mtCount' + Q + G + count + TC + 'span' + G;
            html += T + 'span class=' + Q + 'mtArrow' + Q + G + String.fromCharCode(9654) + TC + 'span' + G;
            html += TC + 'span' + G;
            html += TC + 'div' + G;
    
            /* Group body (collapsed by default) */
            html += T + 'div class=' + Q + 'mtGroupBody' + Q + ' id=' + Q + gid + Q + G;
            html += contentFn();
            html += TC + 'div' + G;
    
            html += TC + 'div' + G;
            return html;
        }
    
        /* === HELPERS === */
        function escHtml(s) {
            if (!s) return '';
            return s.replace(/&/g, AMP + 'amp;').replace(/g, AMP + 'gt;');
        }
    
        function escAttr(s) {
            if (!s) return '';
            return s.replace(/&/g, AMP + 'amp;').replace(/"/g, AMP + 'quot;').replace(/ 0; ci--) {
                if (children[ci].className && children[ci].className.indexOf('typing') !== -1) {
                    typingEl = children[ci];
                    break;
                }
            }
    
            if (typingEl) {
                chatLog.insertBefore(placeholder, typingEl);
            } else {
                chatLog.appendChild(placeholder);
            }
            chatLog.scrollTop = chatLog.scrollHeight;
    
            /* Parallel search */
            var pending = 2;
            var contentResult = null;
            var tagResult = null;
    
            function onDone() {
                pending--;
                if (pending > 0) return;
    
                var pages = (contentResult && contentResult.pages) ? contentResult.pages : new Array();
                var files = (contentResult && contentResult.files) ? contentResult.files : new Array();
                var tags = tagResult || new Array();
    
                var html = renderResults(query, pages, tags, files);
                placeholder.outerHTML = html;
                chatLog.scrollTop = chatLog.scrollHeight;
            }
    
            searchContent(query, function(err, data) {
                if (!err) contentResult = data;
                onDone();
            });
    
            searchTags(query, function(err, data) {
                if (!err) tagResult = data;
                onDone();
            });
        }
    
        /* === START === */
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            setTimeout(init, 500);
        } else {
            document.addEventListener('DOMContentLoaded', function() { setTimeout(init, 500); });
        }
    
    })();
    

     
    Use the language selection below for English Utilise le sélecteur de langue ci-dessous pour français Per l'italiano, utilizzare la selezione della lingua qui sotto Schön sprichst du deutsch :-)