~james-w/ubuntu/lucid/psycopg2/precise-backport

« back to all changes in this revision

Viewing changes to doc/html/_static/searchtools.js

  • Committer: Mikhail Turov
  • Date: 2010-07-28 20:30:01 UTC
  • mfrom: (5.1.9 sid)
  • Revision ID: groldster@gmail.com-20100728203001-u1dv46tnd3s02ejg
Tags: 2.2.1-1ubuntu1
releasing version 2.2.1-1ubuntu1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * helper function to return a node containing the
 
3
 * search summary for a given text. keywords is a list
 
4
 * of stemmed words, hlwords is the list of normal, unstemmed
 
5
 * words. the first one is used to find the occurance, the
 
6
 * latter for highlighting it.
 
7
 */
 
8
 
 
9
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
 
10
  var textLower = text.toLowerCase();
 
11
  var start = 0;
 
12
  $.each(keywords, function() {
 
13
    var i = textLower.indexOf(this.toLowerCase());
 
14
    if (i > -1)
 
15
      start = i;
 
16
  });
 
17
  start = Math.max(start - 120, 0);
 
18
  var excerpt = ((start > 0) ? '...' : '') +
 
19
  $.trim(text.substr(start, 240)) +
 
20
  ((start + 240 - text.length) ? '...' : '');
 
21
  var rv = $('<div class="context"></div>').text(excerpt);
 
22
  $.each(hlwords, function() {
 
23
    rv = rv.highlightText(this, 'highlight');
 
24
  });
 
25
  return rv;
 
26
}
 
27
 
 
28
/**
 
29
 * Porter Stemmer
 
30
 */
 
31
var PorterStemmer = function() {
 
32
 
 
33
  var step2list = {
 
34
    ational: 'ate',
 
35
    tional: 'tion',
 
36
    enci: 'ence',
 
37
    anci: 'ance',
 
38
    izer: 'ize',
 
39
    bli: 'ble',
 
40
    alli: 'al',
 
41
    entli: 'ent',
 
42
    eli: 'e',
 
43
    ousli: 'ous',
 
44
    ization: 'ize',
 
45
    ation: 'ate',
 
46
    ator: 'ate',
 
47
    alism: 'al',
 
48
    iveness: 'ive',
 
49
    fulness: 'ful',
 
50
    ousness: 'ous',
 
51
    aliti: 'al',
 
52
    iviti: 'ive',
 
53
    biliti: 'ble',
 
54
    logi: 'log'
 
55
  };
 
56
 
 
57
  var step3list = {
 
58
    icate: 'ic',
 
59
    ative: '',
 
60
    alize: 'al',
 
61
    iciti: 'ic',
 
62
    ical: 'ic',
 
63
    ful: '',
 
64
    ness: ''
 
65
  };
 
66
 
 
67
  var c = "[^aeiou]";          // consonant
 
68
  var v = "[aeiouy]";          // vowel
 
69
  var C = c + "[^aeiouy]*";    // consonant sequence
 
70
  var V = v + "[aeiou]*";      // vowel sequence
 
71
 
 
72
  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
 
73
  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
 
74
  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
 
75
  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
 
76
 
 
77
  this.stemWord = function (w) {
 
78
    var stem;
 
79
    var suffix;
 
80
    var firstch;
 
81
    var origword = w;
 
82
 
 
83
    if (w.length < 3)
 
84
      return w;
 
85
 
 
86
    var re;
 
87
    var re2;
 
88
    var re3;
 
89
    var re4;
 
90
 
 
91
    firstch = w.substr(0,1);
 
92
    if (firstch == "y")
 
93
      w = firstch.toUpperCase() + w.substr(1);
 
94
 
 
95
    // Step 1a
 
96
    re = /^(.+?)(ss|i)es$/;
 
97
    re2 = /^(.+?)([^s])s$/;
 
98
 
 
99
    if (re.test(w))
 
100
      w = w.replace(re,"$1$2");
 
101
    else if (re2.test(w))
 
102
      w = w.replace(re2,"$1$2");
 
103
 
 
104
    // Step 1b
 
105
    re = /^(.+?)eed$/;
 
106
    re2 = /^(.+?)(ed|ing)$/;
 
107
    if (re.test(w)) {
 
108
      var fp = re.exec(w);
 
109
      re = new RegExp(mgr0);
 
110
      if (re.test(fp[1])) {
 
111
        re = /.$/;
 
112
        w = w.replace(re,"");
 
113
      }
 
114
    }
 
115
    else if (re2.test(w)) {
 
116
      var fp = re2.exec(w);
 
117
      stem = fp[1];
 
118
      re2 = new RegExp(s_v);
 
119
      if (re2.test(stem)) {
 
120
        w = stem;
 
121
        re2 = /(at|bl|iz)$/;
 
122
        re3 = new RegExp("([^aeiouylsz])\\1$");
 
123
        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
 
124
        if (re2.test(w))
 
125
          w = w + "e";
 
126
        else if (re3.test(w)) {
 
127
          re = /.$/;
 
128
          w = w.replace(re,"");
 
129
        }
 
130
        else if (re4.test(w))
 
131
          w = w + "e";
 
132
      }
 
133
    }
 
134
 
 
135
    // Step 1c
 
136
    re = /^(.+?)y$/;
 
137
    if (re.test(w)) {
 
138
      var fp = re.exec(w);
 
139
      stem = fp[1];
 
140
      re = new RegExp(s_v);
 
141
      if (re.test(stem))
 
142
        w = stem + "i";
 
143
    }
 
144
 
 
145
    // Step 2
 
146
    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
 
147
    if (re.test(w)) {
 
148
      var fp = re.exec(w);
 
149
      stem = fp[1];
 
150
      suffix = fp[2];
 
151
      re = new RegExp(mgr0);
 
152
      if (re.test(stem))
 
153
        w = stem + step2list[suffix];
 
154
    }
 
155
 
 
156
    // Step 3
 
157
    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
 
158
    if (re.test(w)) {
 
159
      var fp = re.exec(w);
 
160
      stem = fp[1];
 
161
      suffix = fp[2];
 
162
      re = new RegExp(mgr0);
 
163
      if (re.test(stem))
 
164
        w = stem + step3list[suffix];
 
165
    }
 
166
 
 
167
    // Step 4
 
168
    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
 
169
    re2 = /^(.+?)(s|t)(ion)$/;
 
170
    if (re.test(w)) {
 
171
      var fp = re.exec(w);
 
172
      stem = fp[1];
 
173
      re = new RegExp(mgr1);
 
174
      if (re.test(stem))
 
175
        w = stem;
 
176
    }
 
177
    else if (re2.test(w)) {
 
178
      var fp = re2.exec(w);
 
179
      stem = fp[1] + fp[2];
 
180
      re2 = new RegExp(mgr1);
 
181
      if (re2.test(stem))
 
182
        w = stem;
 
183
    }
 
184
 
 
185
    // Step 5
 
186
    re = /^(.+?)e$/;
 
187
    if (re.test(w)) {
 
188
      var fp = re.exec(w);
 
189
      stem = fp[1];
 
190
      re = new RegExp(mgr1);
 
191
      re2 = new RegExp(meq1);
 
192
      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
 
193
      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
 
194
        w = stem;
 
195
    }
 
196
    re = /ll$/;
 
197
    re2 = new RegExp(mgr1);
 
198
    if (re.test(w) && re2.test(w)) {
 
199
      re = /.$/;
 
200
      w = w.replace(re,"");
 
201
    }
 
202
 
 
203
    // and turn initial Y back to y
 
204
    if (firstch == "y")
 
205
      w = firstch.toLowerCase() + w.substr(1);
 
206
    return w;
 
207
  }
 
208
}
 
209
 
 
210
 
 
211
/**
 
212
 * Search Module
 
213
 */
 
214
var Search = {
 
215
 
 
216
  _index : null,
 
217
  _queued_query : null,
 
218
  _pulse_status : -1,
 
219
 
 
220
  init : function() {
 
221
      var params = $.getQueryParameters();
 
222
      if (params.q) {
 
223
          var query = params.q[0];
 
224
          $('input[name="q"]')[0].value = query;
 
225
          this.performSearch(query);
 
226
      }
 
227
  },
 
228
 
 
229
  /**
 
230
   * Sets the index
 
231
   */
 
232
  setIndex : function(index) {
 
233
    var q;
 
234
    this._index = index;
 
235
    if ((q = this._queued_query) !== null) {
 
236
      this._queued_query = null;
 
237
      Search.query(q);
 
238
    }
 
239
  },
 
240
 
 
241
  hasIndex : function() {
 
242
      return this._index !== null;
 
243
  },
 
244
 
 
245
  deferQuery : function(query) {
 
246
      this._queued_query = query;
 
247
  },
 
248
 
 
249
  stopPulse : function() {
 
250
      this._pulse_status = 0;
 
251
  },
 
252
 
 
253
  startPulse : function() {
 
254
    if (this._pulse_status >= 0)
 
255
        return;
 
256
    function pulse() {
 
257
      Search._pulse_status = (Search._pulse_status + 1) % 4;
 
258
      var dotString = '';
 
259
      for (var i = 0; i < Search._pulse_status; i++)
 
260
        dotString += '.';
 
261
      Search.dots.text(dotString);
 
262
      if (Search._pulse_status > -1)
 
263
        window.setTimeout(pulse, 500);
 
264
    };
 
265
    pulse();
 
266
  },
 
267
 
 
268
  /**
 
269
   * perform a search for something
 
270
   */
 
271
  performSearch : function(query) {
 
272
    // create the required interface elements
 
273
    this.out = $('#search-results');
 
274
    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
 
275
    this.dots = $('<span></span>').appendTo(this.title);
 
276
    this.status = $('<p style="display: none"></p>').appendTo(this.out);
 
277
    this.output = $('<ul class="search"/>').appendTo(this.out);
 
278
 
 
279
    $('#search-progress').text(_('Preparing search...'));
 
280
    this.startPulse();
 
281
 
 
282
    // index already loaded, the browser was quick!
 
283
    if (this.hasIndex())
 
284
      this.query(query);
 
285
    else
 
286
      this.deferQuery(query);
 
287
  },
 
288
 
 
289
  query : function(query) {
 
290
    // stem the searchterms and add them to the
 
291
    // correct list
 
292
    var stemmer = new PorterStemmer();
 
293
    var searchterms = [];
 
294
    var excluded = [];
 
295
    var hlterms = [];
 
296
    var tmp = query.split(/\s+/);
 
297
    var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
 
298
    for (var i = 0; i < tmp.length; i++) {
 
299
      // stem the word
 
300
      var word = stemmer.stemWord(tmp[i]).toLowerCase();
 
301
      // select the correct list
 
302
      if (word[0] == '-') {
 
303
        var toAppend = excluded;
 
304
        word = word.substr(1);
 
305
      }
 
306
      else {
 
307
        var toAppend = searchterms;
 
308
        hlterms.push(tmp[i].toLowerCase());
 
309
      }
 
310
      // only add if not already in the list
 
311
      if (!$.contains(toAppend, word))
 
312
        toAppend.push(word);
 
313
    };
 
314
    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
 
315
 
 
316
    console.debug('SEARCH: searching for:');
 
317
    console.info('required: ', searchterms);
 
318
    console.info('excluded: ', excluded);
 
319
 
 
320
    // prepare search
 
321
    var filenames = this._index.filenames;
 
322
    var titles = this._index.titles;
 
323
    var terms = this._index.terms;
 
324
    var descrefs = this._index.descrefs;
 
325
    var modules = this._index.modules;
 
326
    var desctypes = this._index.desctypes;
 
327
    var fileMap = {};
 
328
    var files = null;
 
329
    var objectResults = [];
 
330
    var regularResults = [];
 
331
    $('#search-progress').empty();
 
332
 
 
333
    // lookup as object
 
334
    if (object != null) {
 
335
      for (var module in modules) {
 
336
        if (module.indexOf(object) > -1) {
 
337
          fn = modules[module];
 
338
          descr = _('module, in ') + titles[fn];
 
339
          objectResults.push([filenames[fn], module, '#module-'+module, descr]);
 
340
        }
 
341
      }
 
342
      for (var prefix in descrefs) {
 
343
        for (var name in descrefs[prefix]) {
 
344
          var fullname = (prefix ? prefix + '.' : '') + name;
 
345
          if (fullname.toLowerCase().indexOf(object) > -1) {
 
346
            match = descrefs[prefix][name];
 
347
            descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
 
348
            objectResults.push([filenames[match[0]], fullname, '#'+fullname, descr]);
 
349
          }
 
350
        }
 
351
      }
 
352
    }
 
353
 
 
354
    // sort results descending
 
355
    objectResults.sort(function(a, b) {
 
356
      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
 
357
    });
 
358
 
 
359
 
 
360
    // perform the search on the required terms
 
361
    for (var i = 0; i < searchterms.length; i++) {
 
362
      var word = searchterms[i];
 
363
      // no match but word was a required one
 
364
      if ((files = terms[word]) == null)
 
365
        break;
 
366
      if (files.length == undefined) {
 
367
        files = [files];
 
368
      }
 
369
      // create the mapping
 
370
      for (var j = 0; j < files.length; j++) {
 
371
        var file = files[j];
 
372
        if (file in fileMap)
 
373
          fileMap[file].push(word);
 
374
        else
 
375
          fileMap[file] = [word];
 
376
      }
 
377
    }
 
378
 
 
379
    // now check if the files don't contain excluded terms
 
380
    for (var file in fileMap) {
 
381
      var valid = true;
 
382
 
 
383
      // check if all requirements are matched
 
384
      if (fileMap[file].length != searchterms.length)
 
385
        continue;
 
386
 
 
387
      // ensure that none of the excluded terms is in the
 
388
      // search result.
 
389
      for (var i = 0; i < excluded.length; i++) {
 
390
        if (terms[excluded[i]] == file ||
 
391
            $.contains(terms[excluded[i]] || [], file)) {
 
392
          valid = false;
 
393
          break;
 
394
        }
 
395
      }
 
396
 
 
397
      // if we have still a valid result we can add it
 
398
      // to the result list
 
399
      if (valid)
 
400
        regularResults.push([filenames[file], titles[file], '', null]);
 
401
    }
 
402
 
 
403
    // delete unused variables in order to not waste
 
404
    // memory until list is retrieved completely
 
405
    delete filenames, titles, terms;
 
406
 
 
407
    // now sort the regular results descending by title
 
408
    regularResults.sort(function(a, b) {
 
409
      var left = a[1].toLowerCase();
 
410
      var right = b[1].toLowerCase();
 
411
      return (left > right) ? -1 : ((left < right) ? 1 : 0);
 
412
    });
 
413
 
 
414
    // combine both
 
415
    var results = regularResults.concat(objectResults);
 
416
 
 
417
    // print the results
 
418
    var resultCount = results.length;
 
419
    function displayNextItem() {
 
420
      // results left, load the summary and display it
 
421
      if (results.length) {
 
422
        var item = results.pop();
 
423
        var listItem = $('<li style="display:none"></li>');
 
424
        listItem.append($('<a/>').attr(
 
425
          'href',
 
426
          item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
 
427
          highlightstring + item[2]).html(item[1]));
 
428
        if (item[3]) {
 
429
          listItem.append($('<span> (' + item[3] + ')</span>'));
 
430
          Search.output.append(listItem);
 
431
          listItem.slideDown(5, function() {
 
432
            displayNextItem();
 
433
          });
 
434
        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
 
435
          $.get('_sources/' + item[0] + '.txt', function(data) {
 
436
            listItem.append($.makeSearchSummary(data, searchterms, hlterms));
 
437
            Search.output.append(listItem);
 
438
            listItem.slideDown(5, function() {
 
439
              displayNextItem();
 
440
            });
 
441
          });
 
442
        } else {
 
443
          // no source available, just display title
 
444
          Search.output.append(listItem);
 
445
          listItem.slideDown(5, function() {
 
446
            displayNextItem();
 
447
          });
 
448
        }
 
449
      }
 
450
      // search finished, update title and status message
 
451
      else {
 
452
        Search.stopPulse();
 
453
        Search.title.text(_('Search Results'));
 
454
        if (!resultCount)
 
455
          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
 
456
        else
 
457
            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
 
458
        Search.status.fadeIn(500);
 
459
      }
 
460
    }
 
461
    displayNextItem();
 
462
  }
 
463
}
 
464
 
 
465
$(document).ready(function() {
 
466
  Search.init();
 
467
});