xref: /dokuwiki/lib/scripts/qsearch.js (revision 7647d87743e49e1c775040271cf5c9f60cd25eb4)
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) { 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
168    };
169
170    jQuery.extend(dw_qsearch, overrides);
171
172    if (!overrides.deferInit) {
173        dw_qsearch.init();
174    }
175
176    return dw_qsearch;
177};
178
179jQuery(function () {
180    jQuery('#qsearch__in').dw_qsearch({
181        output_id: '#qsearch__out'
182    });
183});
184