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