source: sasview/park_integration/docs/sphinx/html/_static/searchtools.js @ 8d27cac

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 8d27cac was f696e2a, checked in by Gervaise Alina <gervyh@…>, 13 years ago

edit doc

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/*
2 * searchtools.js_t
3 * ~~~~~~~~~~~~~~~~
4 *
5 * Sphinx JavaScript utilties for the full-text search.
6 *
7 * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
8 * :license: BSD, see LICENSE for details.
9 *
10 */
11
12/**
13 * helper function to return a node containing the
14 * search summary for a given text. keywords is a list
15 * of stemmed words, hlwords is the list of normal, unstemmed
16 * words. the first one is used to find the occurance, the
17 * latter for highlighting it.
18 */
19
20jQuery.makeSearchSummary = function(text, keywords, hlwords) {
21  var textLower = text.toLowerCase();
22  var start = 0;
23  $.each(keywords, function() {
24    var i = textLower.indexOf(this.toLowerCase());
25    if (i > -1)
26      start = i;
27  });
28  start = Math.max(start - 120, 0);
29  var excerpt = ((start > 0) ? '...' : '') +
30  $.trim(text.substr(start, 240)) +
31  ((start + 240 - text.length) ? '...' : '');
32  var rv = $('<div class="context"></div>').text(excerpt);
33  $.each(hlwords, function() {
34    rv = rv.highlightText(this, 'highlighted');
35  });
36  return rv;
37}
38
39
40/**
41 * Porter Stemmer
42 */
43var Stemmer = function() {
44
45  var step2list = {
46    ational: 'ate',
47    tional: 'tion',
48    enci: 'ence',
49    anci: 'ance',
50    izer: 'ize',
51    bli: 'ble',
52    alli: 'al',
53    entli: 'ent',
54    eli: 'e',
55    ousli: 'ous',
56    ization: 'ize',
57    ation: 'ate',
58    ator: 'ate',
59    alism: 'al',
60    iveness: 'ive',
61    fulness: 'ful',
62    ousness: 'ous',
63    aliti: 'al',
64    iviti: 'ive',
65    biliti: 'ble',
66    logi: 'log'
67  };
68
69  var step3list = {
70    icate: 'ic',
71    ative: '',
72    alize: 'al',
73    iciti: 'ic',
74    ical: 'ic',
75    ful: '',
76    ness: ''
77  };
78
79  var c = "[^aeiou]";          // consonant
80  var v = "[aeiouy]";          // vowel
81  var C = c + "[^aeiouy]*";    // consonant sequence
82  var V = v + "[aeiou]*";      // vowel sequence
83
84  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
85  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
86  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
87  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
88
89  this.stemWord = function (w) {
90    var stem;
91    var suffix;
92    var firstch;
93    var origword = w;
94
95    if (w.length < 3)
96      return w;
97
98    var re;
99    var re2;
100    var re3;
101    var re4;
102
103    firstch = w.substr(0,1);
104    if (firstch == "y")
105      w = firstch.toUpperCase() + w.substr(1);
106
107    // Step 1a
108    re = /^(.+?)(ss|i)es$/;
109    re2 = /^(.+?)([^s])s$/;
110
111    if (re.test(w))
112      w = w.replace(re,"$1$2");
113    else if (re2.test(w))
114      w = w.replace(re2,"$1$2");
115
116    // Step 1b
117    re = /^(.+?)eed$/;
118    re2 = /^(.+?)(ed|ing)$/;
119    if (re.test(w)) {
120      var fp = re.exec(w);
121      re = new RegExp(mgr0);
122      if (re.test(fp[1])) {
123        re = /.$/;
124        w = w.replace(re,"");
125      }
126    }
127    else if (re2.test(w)) {
128      var fp = re2.exec(w);
129      stem = fp[1];
130      re2 = new RegExp(s_v);
131      if (re2.test(stem)) {
132        w = stem;
133        re2 = /(at|bl|iz)$/;
134        re3 = new RegExp("([^aeiouylsz])\\1$");
135        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
136        if (re2.test(w))
137          w = w + "e";
138        else if (re3.test(w)) {
139          re = /.$/;
140          w = w.replace(re,"");
141        }
142        else if (re4.test(w))
143          w = w + "e";
144      }
145    }
146
147    // Step 1c
148    re = /^(.+?)y$/;
149    if (re.test(w)) {
150      var fp = re.exec(w);
151      stem = fp[1];
152      re = new RegExp(s_v);
153      if (re.test(stem))
154        w = stem + "i";
155    }
156
157    // Step 2
158    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
159    if (re.test(w)) {
160      var fp = re.exec(w);
161      stem = fp[1];
162      suffix = fp[2];
163      re = new RegExp(mgr0);
164      if (re.test(stem))
165        w = stem + step2list[suffix];
166    }
167
168    // Step 3
169    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
170    if (re.test(w)) {
171      var fp = re.exec(w);
172      stem = fp[1];
173      suffix = fp[2];
174      re = new RegExp(mgr0);
175      if (re.test(stem))
176        w = stem + step3list[suffix];
177    }
178
179    // Step 4
180    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
181    re2 = /^(.+?)(s|t)(ion)$/;
182    if (re.test(w)) {
183      var fp = re.exec(w);
184      stem = fp[1];
185      re = new RegExp(mgr1);
186      if (re.test(stem))
187        w = stem;
188    }
189    else if (re2.test(w)) {
190      var fp = re2.exec(w);
191      stem = fp[1] + fp[2];
192      re2 = new RegExp(mgr1);
193      if (re2.test(stem))
194        w = stem;
195    }
196
197    // Step 5
198    re = /^(.+?)e$/;
199    if (re.test(w)) {
200      var fp = re.exec(w);
201      stem = fp[1];
202      re = new RegExp(mgr1);
203      re2 = new RegExp(meq1);
204      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
205      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
206        w = stem;
207    }
208    re = /ll$/;
209    re2 = new RegExp(mgr1);
210    if (re.test(w) && re2.test(w)) {
211      re = /.$/;
212      w = w.replace(re,"");
213    }
214
215    // and turn initial Y back to y
216    if (firstch == "y")
217      w = firstch.toLowerCase() + w.substr(1);
218    return w;
219  }
220}
221
222
223/**
224 * Search Module
225 */
226var Search = {
227
228  _index : null,
229  _queued_query : null,
230  _pulse_status : -1,
231
232  init : function() {
233      var params = $.getQueryParameters();
234      if (params.q) {
235          var query = params.q[0];
236          $('input[name="q"]')[0].value = query;
237          this.performSearch(query);
238      }
239  },
240
241  loadIndex : function(url) {
242    $.ajax({type: "GET", url: url, data: null, success: null,
243            dataType: "script", cache: true});
244  },
245
246  setIndex : function(index) {
247    var q;
248    this._index = index;
249    if ((q = this._queued_query) !== null) {
250      this._queued_query = null;
251      Search.query(q);
252    }
253  },
254
255  hasIndex : function() {
256      return this._index !== null;
257  },
258
259  deferQuery : function(query) {
260      this._queued_query = query;
261  },
262
263  stopPulse : function() {
264      this._pulse_status = 0;
265  },
266
267  startPulse : function() {
268    if (this._pulse_status >= 0)
269        return;
270    function pulse() {
271      Search._pulse_status = (Search._pulse_status + 1) % 4;
272      var dotString = '';
273      for (var i = 0; i < Search._pulse_status; i++)
274        dotString += '.';
275      Search.dots.text(dotString);
276      if (Search._pulse_status > -1)
277        window.setTimeout(pulse, 500);
278    };
279    pulse();
280  },
281
282  /**
283   * perform a search for something
284   */
285  performSearch : function(query) {
286    // create the required interface elements
287    this.out = $('#search-results');
288    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
289    this.dots = $('<span></span>').appendTo(this.title);
290    this.status = $('<p style="display: none"></p>').appendTo(this.out);
291    this.output = $('<ul class="search"/>').appendTo(this.out);
292
293    $('#search-progress').text(_('Preparing search...'));
294    this.startPulse();
295
296    // index already loaded, the browser was quick!
297    if (this.hasIndex())
298      this.query(query);
299    else
300      this.deferQuery(query);
301  },
302
303  query : function(query) {
304    var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
305
306    // Stem the searchterms and add them to the correct list
307    var stemmer = new Stemmer();
308    var searchterms = [];
309    var excluded = [];
310    var hlterms = [];
311    var tmp = query.split(/\s+/);
312    var objectterms = [];
313    for (var i = 0; i < tmp.length; i++) {
314      if (tmp[i] != "") {
315          objectterms.push(tmp[i].toLowerCase());
316      }
317
318      if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
319          tmp[i] == "") {
320        // skip this "word"
321        continue;
322      }
323      // stem the word
324      var word = stemmer.stemWord(tmp[i]).toLowerCase();
325      // select the correct list
326      if (word[0] == '-') {
327        var toAppend = excluded;
328        word = word.substr(1);
329      }
330      else {
331        var toAppend = searchterms;
332        hlterms.push(tmp[i].toLowerCase());
333      }
334      // only add if not already in the list
335      if (!$.contains(toAppend, word))
336        toAppend.push(word);
337    };
338    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
339
340    // console.debug('SEARCH: searching for:');
341    // console.info('required: ', searchterms);
342    // console.info('excluded: ', excluded);
343
344    // prepare search
345    var filenames = this._index.filenames;
346    var titles = this._index.titles;
347    var terms = this._index.terms;
348    var fileMap = {};
349    var files = null;
350    // different result priorities
351    var importantResults = [];
352    var objectResults = [];
353    var regularResults = [];
354    var unimportantResults = [];
355    $('#search-progress').empty();
356
357    // lookup as object
358    for (var i = 0; i < objectterms.length; i++) {
359      var others = [].concat(objectterms.slice(0,i),
360                             objectterms.slice(i+1, objectterms.length))
361      var results = this.performObjectSearch(objectterms[i], others);
362      // Assume first word is most likely to be the object,
363      // other words more likely to be in description.
364      // Therefore put matches for earlier words first.
365      // (Results are eventually used in reverse order).
366      objectResults = results[0].concat(objectResults);
367      importantResults = results[1].concat(importantResults);
368      unimportantResults = results[2].concat(unimportantResults);
369    }
370
371    // perform the search on the required terms
372    for (var i = 0; i < searchterms.length; i++) {
373      var word = searchterms[i];
374      // no match but word was a required one
375      if ((files = terms[word]) == null)
376        break;
377      if (files.length == undefined) {
378        files = [files];
379      }
380      // create the mapping
381      for (var j = 0; j < files.length; j++) {
382        var file = files[j];
383        if (file in fileMap)
384          fileMap[file].push(word);
385        else
386          fileMap[file] = [word];
387      }
388    }
389
390    // now check if the files don't contain excluded terms
391    for (var file in fileMap) {
392      var valid = true;
393
394      // check if all requirements are matched
395      if (fileMap[file].length != searchterms.length)
396        continue;
397
398      // ensure that none of the excluded terms is in the
399      // search result.
400      for (var i = 0; i < excluded.length; i++) {
401        if (terms[excluded[i]] == file ||
402            $.contains(terms[excluded[i]] || [], file)) {
403          valid = false;
404          break;
405        }
406      }
407
408      // if we have still a valid result we can add it
409      // to the result list
410      if (valid)
411        regularResults.push([filenames[file], titles[file], '', null]);
412    }
413
414    // delete unused variables in order to not waste
415    // memory until list is retrieved completely
416    delete filenames, titles, terms;
417
418    // now sort the regular results descending by title
419    regularResults.sort(function(a, b) {
420      var left = a[1].toLowerCase();
421      var right = b[1].toLowerCase();
422      return (left > right) ? -1 : ((left < right) ? 1 : 0);
423    });
424
425    // combine all results
426    var results = unimportantResults.concat(regularResults)
427      .concat(objectResults).concat(importantResults);
428
429    // print the results
430    var resultCount = results.length;
431    function displayNextItem() {
432      // results left, load the summary and display it
433      if (results.length) {
434        var item = results.pop();
435        var listItem = $('<li style="display:none"></li>');
436        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
437          // dirhtml builder
438          var dirname = item[0] + '/';
439          if (dirname.match(/\/index\/$/)) {
440            dirname = dirname.substring(0, dirname.length-6);
441          } else if (dirname == 'index/') {
442            dirname = '';
443          }
444          listItem.append($('<a/>').attr('href',
445            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
446            highlightstring + item[2]).html(item[1]));
447        } else {
448          // normal html builders
449          listItem.append($('<a/>').attr('href',
450            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
451            highlightstring + item[2]).html(item[1]));
452        }
453        if (item[3]) {
454          listItem.append($('<span> (' + item[3] + ')</span>'));
455          Search.output.append(listItem);
456          listItem.slideDown(5, function() {
457            displayNextItem();
458          });
459        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
460          $.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
461                item[0] + '.txt', function(data) {
462            if (data != '') {
463              listItem.append($.makeSearchSummary(data, searchterms, hlterms));
464              Search.output.append(listItem);
465            }
466            listItem.slideDown(5, function() {
467              displayNextItem();
468            });
469          }, "text");
470        } else {
471          // no source available, just display title
472          Search.output.append(listItem);
473          listItem.slideDown(5, function() {
474            displayNextItem();
475          });
476        }
477      }
478      // search finished, update title and status message
479      else {
480        Search.stopPulse();
481        Search.title.text(_('Search Results'));
482        if (!resultCount)
483          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.'));
484        else
485            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
486        Search.status.fadeIn(500);
487      }
488    }
489    displayNextItem();
490  },
491
492  performObjectSearch : function(object, otherterms) {
493    var filenames = this._index.filenames;
494    var objects = this._index.objects;
495    var objnames = this._index.objnames;
496    var titles = this._index.titles;
497
498    var importantResults = [];
499    var objectResults = [];
500    var unimportantResults = [];
501
502    for (var prefix in objects) {
503      for (var name in objects[prefix]) {
504        var fullname = (prefix ? prefix + '.' : '') + name;
505        if (fullname.toLowerCase().indexOf(object) > -1) {
506          var match = objects[prefix][name];
507          var objname = objnames[match[1]][2];
508          var title = titles[match[0]];
509          // If more than one term searched for, we require other words to be
510          // found in the name/title/description
511          if (otherterms.length > 0) {
512            var haystack = (prefix + ' ' + name + ' ' +
513                            objname + ' ' + title).toLowerCase();
514            var allfound = true;
515            for (var i = 0; i < otherterms.length; i++) {
516              if (haystack.indexOf(otherterms[i]) == -1) {
517                allfound = false;
518                break;
519              }
520            }
521            if (!allfound) {
522              continue;
523            }
524          }
525          var descr = objname + _(', in ') + title;
526          anchor = match[3];
527          if (anchor == '')
528            anchor = fullname;
529          else if (anchor == '-')
530            anchor = objnames[match[1]][1] + '-' + fullname;
531          result = [filenames[match[0]], fullname, '#'+anchor, descr];
532          switch (match[2]) {
533          case 1: objectResults.push(result); break;
534          case 0: importantResults.push(result); break;
535          case 2: unimportantResults.push(result); break;
536          }
537        }
538      }
539    }
540
541    // sort results descending
542    objectResults.sort(function(a, b) {
543      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
544    });
545
546    importantResults.sort(function(a, b) {
547      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
548    });
549
550    unimportantResults.sort(function(a, b) {
551      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
552    });
553
554    return [importantResults, objectResults, unimportantResults]
555  }
556}
557
558$(document).ready(function() {
559  Search.init();
560});
Note: See TracBrowser for help on using the repository browser.