xref: /dokuwiki/lib/scripts/qsearch.js (revision 21606750a4ae0a46937a589ca323c250f26a2e58)
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            var value = dw_qsearch.$inObj.val();
39            if (value === '') {
40                dw_qsearch.clear_results();
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.timer = window.setTimeout(do_qsearch, 500);
61            }
62        );
63
64        // attach eventhandler to output field
65        dw_qsearch.$outObj.click(dw_qsearch.clear_results);
66    },
67
68    /**
69     * Empty and hide the output div
70     */
71    clear_results: function(){
72        dw_qsearch.$outObj.hide();
73        dw_qsearch.$outObj.text('');
74    },
75
76    /**
77     * Callback. Reformat and display the results.
78     *
79     * Namespaces are shortened here to keep the results from overflowing
80     * or wrapping
81     *
82     * @param data The result HTML
83     */
84    onCompletion: function(data) {
85        var max, $links, too_big;
86
87        if (data === '') {
88            dw_qsearch.clear_results();
89            return;
90        }
91
92        dw_qsearch.$outObj
93            .html(data)
94            .show()
95            .css('white-space', 'nowrap');
96
97        // disable overflow during shortening
98        dw_qsearch.$outObj.find('li').css('overflow', 'visible');
99
100        $links = dw_qsearch.$outObj.find('a');
101        max    = dw_qsearch.$outObj[0].clientWidth; // maximum width allowed (but take away paddings below)
102        if(document.documentElement.dir === 'rtl'){
103            max -= parseInt(dw_qsearch.$outObj.css('padding-left'));
104            too_big = function (l) { return l.offsetLeft < 0; };
105        }else{
106            max -= parseInt(dw_qsearch.$outObj.css('padding-right'));
107            too_big = function (l) { return l.offsetWidth + l.offsetLeft > max; };
108        }
109
110        $links.each(function () {
111            var start, length, replace, nsL, nsR, eli, runaway;
112
113            if (!too_big(this)) {
114                return;
115            }
116
117            // make IE's innerText available to W3C conform browsers
118            if(this.textContent){
119                this.__defineGetter__('innerText', function(){ return this.textContent });
120                this.__defineSetter__('innerText', function(val){ this.textContent = val });
121            }
122
123            nsL = this.innerText.indexOf('(');
124            nsR = this.innerText.indexOf(')');
125            eli = 0;
126            runaway = 0;
127
128            while((nsR - nsL > 3) && too_big(this) && runaway++ < 500) {
129                if(eli !== 0){
130                    // elipsis already inserted
131                    if( (eli - nsL) > (nsR - eli) ){
132                        // cut left
133                        start = eli - 2;
134                        length = 2;
135                    }else{
136                        // cut right
137                        start = eli + 1;
138                        length = 1;
139                    }
140                    replace = '';
141                }else{
142                    // replace middle with ellipsis
143                    start = Math.floor( nsL + ((nsR-nsL)/2) );
144                    length = 1;
145                    replace = '…';
146                }
147                this.innerText = substr_replace(this.innerText,
148                                                replace, start, length);
149
150                eli = this.innerText.indexOf('…');
151                nsL = this.innerText.indexOf('(');
152                nsR = this.innerText.indexOf(')');
153            }
154        });
155
156        // reenable overflow
157        dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow','ellipsis');
158    }
159};
160
161jQuery(function () {
162    dw_qsearch.init('#qsearch__in','#qsearch__out');
163});
164