xref: /dokuwiki/lib/scripts/qsearch.js (revision f9328d30809630f0fe49373facd9f8e1d47f38ba)
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_id: '#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_id);
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) {
112                    return l.offsetLeft < 0;
113                };
114            } else {
115                max -= parseInt(dw_qsearch.$outObj.css('padding-right'));
116                too_big = function (l) {
117                    return l.offsetWidth + l.offsetLeft > max;
118                };
119            }
120
121            $links.each(function () {
122                var start, length, replace, nsL, nsR, eli, runaway;
123
124                if (!too_big(this)) {
125                    return;
126                }
127
128                // make IE's innerText available to W3C conform browsers
129                if (this.textContent) {
130                    this.__defineGetter__('innerText', function () {
131                        return this.textContent
132                    });
133                    this.__defineSetter__('innerText', function (val) {
134                        this.textContent = val
135                    });
136                }
137
138                nsL = this.innerText.indexOf('(');
139                nsR = this.innerText.indexOf(')');
140                eli = 0;
141                runaway = 0;
142
143                while ((nsR - nsL > 3) && too_big(this) && runaway++ < 500) {
144                    if (eli !== 0) {
145                        // elipsis already inserted
146                        if ((eli - nsL) > (nsR - eli)) {
147                            // cut left
148                            start = eli - 2;
149                            length = 2;
150                        } else {
151                            // cut right
152                            start = eli + 1;
153                            length = 1;
154                        }
155                        replace = '';
156                    } else {
157                        // replace middle with ellipsis
158                        start = Math.floor(nsL + ((nsR - nsL) / 2));
159                        length = 1;
160                        replace = '…';
161                    }
162                    this.innerText = substr_replace(this.innerText,
163                        replace, start, length);
164
165                    eli = this.innerText.indexOf('…');
166                    nsL = this.innerText.indexOf('(');
167                    nsR = this.innerText.indexOf(')');
168                }
169            });
170
171            // reenable overflow
172            dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow', 'ellipsis');
173        }
174
175
176    };
177
178    jQuery.extend(dw_qsearch, overrides);
179
180    if (!overrides.deferInit) {
181        dw_qsearch.init();
182    }
183
184    return dw_qsearch;
185};
186
187jQuery(function () {
188    jQuery('#qsearch__in').dw_qsearch({
189        output_id: '#qsearch__out'
190    });
191});
192