fw4spl
Apps/VRRender/doc/source/_static/searchtools.js
1 
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 
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 
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 
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 
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  if (name.toLowerCase().indexOf(object) > -1) {
345  match = descrefs[prefix][name];
346  fullname = (prefix ? 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 });
The namespace console contains no service. It is only used to launch a main loop for console applicat...