xref: /dokuwiki/lib/scripts/qsearch.js (revision db9faf025cf129d15a086a803e8056e977975d76)
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 */
9jQuery.fn.dw_qsearch = function (overrides) {
10
11    var dw_qsearch = {
12
13        output: '#qsearch__out',
14
15        $inObj: this,
16        $outObj: null,
17        timer: null,
18        curRequest: null,
19
20        /**
21         * initialize the quick search
22         *
23         * Attaches the event handlers
24         *
25         */
26        init: function () {
27            var do_qsearch;
28
29            dw_qsearch.$outObj = jQuery(dw_qsearch.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.getSearchterm();
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         * Read search term from input
75         */
76        getSearchterm: function() {
77            return dw_qsearch.$inObj.val();
78        },
79
80        /**
81         * Empty and hide the output div
82         */
83        clear_results: function () {
84            dw_qsearch.$outObj.hide();
85            dw_qsearch.$outObj.text('');
86        },
87
88        /**
89         * Callback. Reformat and display the results.
90         *
91         * Namespaces are shortened here to keep the results from overflowing
92         * or wrapping
93         *
94         * @param data The result HTML
95         */
96        onCompletion: function (data) {
97            var max, $links, too_big;
98
99            dw_qsearch.curRequest = null;
100
101            if (data === '') {
102                dw_qsearch.clear_results();
103                return;
104            }
105
106            dw_qsearch.$outObj
107                .html(data)
108                .show()
109                .css('white-space', 'nowrap');
110
111            // disable overflow during shortening
112            dw_qsearch.$outObj.find('li').css('overflow', 'visible');
113
114            $links = dw_qsearch.$outObj.find('a');
115            max = dw_qsearch.$outObj[0].clientWidth; // maximum width allowed (but take away paddings below)
116            if (document.documentElement.dir === 'rtl') {
117                max -= parseInt(dw_qsearch.$outObj.css('padding-left'));
118                too_big = function (l) {
119                    return l.offsetLeft < 0;
120                };
121            } else {
122                max -= parseInt(dw_qsearch.$outObj.css('padding-right'));
123                too_big = function (l) {
124                    return l.offsetWidth + l.offsetLeft > max;
125                };
126            }
127
128            $links.each(function () {
129                var start, length, replace, nsL, nsR, eli, runaway;
130
131                if (!too_big(this)) {
132                    return;
133                }
134
135                // make IE's innerText available to W3C conform browsers
136                if (this.textContent) {
137                    this.__defineGetter__('innerText', function () {
138                        return this.textContent
139                    });
140                    this.__defineSetter__('innerText', function (val) {
141                        this.textContent = val
142                    });
143                }
144
145                nsL = this.innerText.indexOf('(');
146                nsR = this.innerText.indexOf(')');
147                eli = 0;
148                runaway = 0;
149
150                while ((nsR - nsL > 3) && too_big(this) && runaway++ < 500) {
151                    if (eli !== 0) {
152                        // elipsis already inserted
153                        if ((eli - nsL) > (nsR - eli)) {
154                            // cut left
155                            start = eli - 2;
156                            length = 2;
157                        } else {
158                            // cut right
159                            start = eli + 1;
160                            length = 1;
161                        }
162                        replace = '';
163                    } else {
164                        // replace middle with ellipsis
165                        start = Math.floor(nsL + ((nsR - nsL) / 2));
166                        length = 1;
167                        replace = '…';
168                    }
169                    this.innerText = substr_replace(this.innerText,
170                        replace, start, length);
171
172                    eli = this.innerText.indexOf('…');
173                    nsL = this.innerText.indexOf('(');
174                    nsR = this.innerText.indexOf(')');
175                }
176            });
177
178            // reenable overflow
179            dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow', 'ellipsis');
180        }
181
182
183    };
184
185    jQuery.extend(dw_qsearch, overrides);
186
187    if (!overrides.deferInit) {
188        dw_qsearch.init();
189    }
190
191    return dw_qsearch;
192};
193
194jQuery(function () {
195    jQuery('#qsearch__in').dw_qsearch({
196        output: '#qsearch__out'
197    });
198});
199