xref: /dokuwiki/lib/scripts/qsearch.js (revision 38479cbba628ee76a92ff5f3c974cfa8e6ce9e61)
1/**
2 * AJAX functions for the pagename quicksearch
3 *
4 * @license  GPL2 (http://www.gnu.org/licenses/gpl.html)
5 * @author   Andreas Gohr <andi@splitbrain.org>
6 * @author   Adrian Lang <lang@cosmocode.de>
7 * @author   Michal Rezler <m.rezler@centrum.cz>
8 */
9
10var dw_qsearch = {
11
12    $inObj: null,
13    $outObj: null,
14    timer: null,
15
16    /**
17     * initialize the quick search
18     *
19     * Attaches the event handlers
20     *
21     * @param input element (jQuery selector/DOM obj)
22     * @param output element (jQuery selector/DOM obj)
23     */
24    init: function (input, output) {
25        var do_qsearch;
26
27        dw_qsearch.$inObj  = jQuery(input);
28        dw_qsearch.$outObj = jQuery(output);
29
30        // objects found?
31        if (dw_qsearch.$inObj.length === 0 ||
32            dw_qsearch.$outObj.length === 0) {
33            return;
34        }
35
36        // attach eventhandler to search field
37        do_qsearch = function () {
38            dw_qsearch.clear_results();
39            var value = dw_qsearch.$inObj.val();
40            if (value === '') {
41                return;
42            }
43            jQuery.post(
44                DOKU_BASE + 'lib/exe/ajax.php',
45                {
46                    call: 'qsearch',
47                    q: encodeURI(value)
48                },
49                dw_qsearch.onCompletion,
50                'html'
51            );
52        };
53
54        dw_qsearch.$inObj.keyup(
55            function() {
56                if(dw_qsearch.timer){
57                    window.clearTimeout(dw_qsearch.timer);
58                    dw_qsearch.timer = null;
59                }
60                dw_qsearch.clear_results();
61                dw_qsearch.timer = window.setTimeout(do_qsearch, 500);
62            }
63        );
64
65        // attach eventhandler to output field
66        dw_qsearch.$outObj.click(dw_qsearch.clear_results);
67    },
68
69    /**
70     * Empty and hide the output div
71     */
72    clear_results: function(){
73        dw_qsearch.$outObj.hide();
74        dw_qsearch.$outObj.text('');
75    },
76
77    /**
78     * Callback. Reformat and display the results.
79     *
80     * Namespaces are shortened here to keep the results from overflowing
81     * or wrapping
82     *
83     * @param data The result HTML
84     */
85    onCompletion: function(data) {
86        var max, $links, too_big;
87
88        if (data === '') { return; }
89
90        dw_qsearch.$outObj
91            .html(data)
92            .show()
93            .css('white-space', 'nowrap');
94
95        // disable overflow during shortening
96        dw_qsearch.$outObj.find('li').css('overflow', 'visible');
97
98        $links = dw_qsearch.$outObj.find('a');
99        max    = dw_qsearch.$outObj[0].clientWidth; // maximum width allowed (but take away paddings below)
100        if(document.documentElement.dir === 'rtl'){
101            max -= parseInt(dw_qsearch.$outObj.css('padding-left'));
102            too_big = function (l) { return l.offsetLeft < 0; };
103        }else{
104            max -= parseInt(dw_qsearch.$outObj.css('padding-right'));
105            too_big = function (l) { return l.offsetWidth + l.offsetLeft > max; };
106        }
107
108        $links.each(function () {
109            var start, length, replace, nsL, nsR, eli, runaway;
110
111            if (!too_big(this)) {
112                return;
113            }
114
115            // make IE's innerText available to W3C conform browsers
116            if(this.textContent){
117                this.__defineGetter__('innerText', function(){ return this.textContent });
118                this.__defineSetter__('innerText', function(val){ this.textContent = val });
119            }
120
121            nsL = this.innerText.indexOf('(');
122            nsR = this.innerText.indexOf(')');
123            eli = 0;
124            runaway = 0;
125
126            while((nsR - nsL > 3) && too_big(this) && runaway++ < 500) {
127                if(eli !== 0){
128                    // elipsis already inserted
129                    if( (eli - nsL) > (nsR - eli) ){
130                        // cut left
131                        start = eli - 2;
132                        length = 2;
133                    }else{
134                        // cut right
135                        start = eli + 1;
136                        length = 1;
137                    }
138                    replace = '';
139                }else{
140                    // replace middle with ellipsis
141                    start = Math.floor( nsL + ((nsR-nsL)/2) );
142                    length = 1;
143                    replace = '…';
144                }
145                this.innerText = substr_replace(this.innerText,
146                                                replace, start, length);
147
148                eli = this.innerText.indexOf('…');
149                nsL = this.innerText.indexOf('(');
150                nsR = this.innerText.indexOf(')');
151            }
152        });
153
154        // reenable overflow
155        dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow','ellipsis');
156    }
157};
158
159jQuery(function () {
160    dw_qsearch.init('#qsearch__in','#qsearch__out');
161});
162