Completed
Pull Request — master (#70)
by Ron
13:25
created

Search.performTermsSearch   F

Complexity

Conditions 21
Paths 24

Size

Total Lines 98
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 59
nc 24
nop 4
dl 0
loc 98
rs 0
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A 0 1 1
A 0 1 1
A 0 17 5
A 0 1 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like Search.performTermsSearch often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*
2
 * searchtools.js
3
 * ~~~~~~~~~~~~~~~~
4
 *
5
 * Sphinx JavaScript utilities for the full-text search.
6
 *
7
 * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
8
 * :license: BSD, see LICENSE for details.
9
 *
10
 */
11
12
if (!Scorer) {
0 ignored issues
show
Bug introduced by
The variable Scorer seems to be never initialized.
Loading history...
13
  /**
14
   * Simple result scoring code.
15
   */
16
  var Scorer = {
17
    // Implement the following function to further tweak the score for each result
18
    // The function takes a result array [filename, title, anchor, descr, score]
19
    // and returns the new score.
20
    /*
21
    score: function(result) {
22
      return result[4];
23
    },
24
    */
25
26
    // query matches the full name of an object
27
    objNameMatch: 11,
28
    // or matches in the last dotted part of the object name
29
    objPartialMatch: 6,
30
    // Additive scores depending on the priority of the object
31
    objPrio: {0:  15,   // used to be importantResults
32
              1:  5,   // used to be objectResults
33
              2: -5},  // used to be unimportantResults
34
    //  Used when the priority is not in the mapping.
35
    objPrioDefault: 0,
36
37
    // query found in title
38
    title: 15,
39
    partialTitle: 7,
40
    // query found in terms
41
    term: 5,
42
    partialTerm: 2
43
  };
44
}
45
46
if (!splitQuery) {
47
  function splitQuery(query) {
0 ignored issues
show
Bug introduced by
The function splitQuery is declared conditionally. This is not supported by all runtimes. Consider moving it to root scope or using var splitQuery = function() { /* ... */ }; instead.
Loading history...
48
    return query.split(/\s+/);
49
  }
50
}
51
52
/**
53
 * Search Module
54
 */
55
var Search = {
56
57
  _index : null,
58
  _queued_query : null,
59
  _pulse_status : -1,
60
61
  htmlToText : function(htmlString) {
62
      var htmlElement = document.createElement('span');
63
      htmlElement.innerHTML = htmlString;
64
      $(htmlElement).find('.headerlink').remove();
65
      docContent = $(htmlElement).find('[role=main]')[0];
0 ignored issues
show
Bug introduced by
The variable docContent seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.docContent.
Loading history...
66
      return docContent.textContent || docContent.innerText;
67
  },
68
69
  init : function() {
70
      var params = $.getQueryParameters();
71
      if (params.q) {
72
          var query = params.q[0];
73
          $('input[name="q"]')[0].value = query;
74
          this.performSearch(query);
75
      }
76
  },
77
78
  loadIndex : function(url) {
79
    $.ajax({type: "GET", url: url, data: null,
80
            dataType: "script", cache: true,
81
            complete: function(jqxhr, textstatus) {
82
              if (textstatus != "success") {
83
                document.getElementById("searchindexloader").src = url;
84
              }
85
            }});
86
  },
87
88
  setIndex : function(index) {
89
    var q;
90
    this._index = index;
91
    if ((q = this._queued_query) !== null) {
92
      this._queued_query = null;
93
      Search.query(q);
94
    }
95
  },
96
97
  hasIndex : function() {
98
      return this._index !== null;
99
  },
100
101
  deferQuery : function(query) {
102
      this._queued_query = query;
103
  },
104
105
  stopPulse : function() {
106
      this._pulse_status = 0;
107
  },
108
109
  startPulse : function() {
110
    if (this._pulse_status >= 0)
111
        return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
112
    function pulse() {
113
      var i;
114
      Search._pulse_status = (Search._pulse_status + 1) % 4;
115
      var dotString = '';
116
      for (i = 0; i < Search._pulse_status; i++)
117
        dotString += '.';
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
118
      Search.dots.text(dotString);
119
      if (Search._pulse_status > -1)
120
        window.setTimeout(pulse, 500);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
121
    }
122
    pulse();
123
  },
124
125
  /**
126
   * perform a search for something (or wait until index is loaded)
127
   */
128
  performSearch : function(query) {
129
    // create the required interface elements
130
    this.out = $('#search-results');
131
    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
132
    this.dots = $('<span></span>').appendTo(this.title);
133
    this.status = $('<p class="search-summary">&nbsp;</p>').appendTo(this.out);
134
    this.output = $('<ul class="search"/>').appendTo(this.out);
135
136
    $('#search-progress').text(_('Preparing search...'));
137
    this.startPulse();
138
139
    // index already loaded, the browser was quick!
140
    if (this.hasIndex())
141
      this.query(query);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
142
    else
143
      this.deferQuery(query);
144
  },
145
146
  /**
147
   * execute search (requires search index to be loaded)
148
   */
149
  query : function(query) {
150
    var i;
151
152
    // stem the searchterms and add them to the correct list
153
    var stemmer = new Stemmer();
0 ignored issues
show
Bug introduced by
The variable Stemmer seems to be never declared. If this is a global, consider adding a /** global: Stemmer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
154
    var searchterms = [];
155
    var excluded = [];
156
    var hlterms = [];
157
    var tmp = splitQuery(query);
158
    var objectterms = [];
159
    for (i = 0; i < tmp.length; i++) {
160
      if (tmp[i] !== "") {
161
          objectterms.push(tmp[i].toLowerCase());
162
      }
163
164
      if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
0 ignored issues
show
Bug introduced by
The variable $u seems to be never declared. If this is a global, consider adding a /** global: $u */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable stopwords seems to be never declared. If this is a global, consider adding a /** global: stopwords */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
165
          tmp[i] === "") {
166
        // skip this "word"
167
        continue;
168
      }
169
      // stem the word
170
      var word = stemmer.stemWord(tmp[i].toLowerCase());
171
      // prevent stemmer from cutting word smaller than two chars
172
      if(word.length < 3 && tmp[i].length >= 3) {
173
        word = tmp[i];
174
      }
175
      var toAppend;
176
      // select the correct list
177
      if (word[0] == '-') {
178
        toAppend = excluded;
179
        word = word.substr(1);
180
      }
181
      else {
182
        toAppend = searchterms;
183
        hlterms.push(tmp[i].toLowerCase());
184
      }
185
      // only add if not already in the list
186
      if (!$u.contains(toAppend, word))
187
        toAppend.push(word);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
188
    }
189
    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
190
191
    // console.debug('SEARCH: searching for:');
192
    // console.info('required: ', searchterms);
193
    // console.info('excluded: ', excluded);
194
195
    // prepare search
196
    var terms = this._index.terms;
197
    var titleterms = this._index.titleterms;
198
199
    // array of [filename, title, anchor, descr, score]
200
    var results = [];
201
    $('#search-progress').empty();
202
203
    // lookup as object
204
    for (i = 0; i < objectterms.length; i++) {
205
      var others = [].concat(objectterms.slice(0, i),
206
                             objectterms.slice(i+1, objectterms.length));
207
      results = results.concat(this.performObjectSearch(objectterms[i], others));
208
    }
209
210
    // lookup as search terms in fulltext
211
    results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
212
213
    // let the scorer override scores with a custom scoring function
214
    if (Scorer.score) {
215
      for (i = 0; i < results.length; i++)
216
        results[i][4] = Scorer.score(results[i]);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
217
    }
218
219
    // now sort the results by score (in opposite order of appearance, since the
220
    // display function below uses pop() to retrieve items) and then
221
    // alphabetically
222
    results.sort(function(a, b) {
223
      var left = a[4];
224
      var right = b[4];
225
      if (left > right) {
226
        return 1;
227
      } else if (left < right) {
228
        return -1;
229
      } else {
230
        // same score: sort alphabetically
231
        left = a[1].toLowerCase();
232
        right = b[1].toLowerCase();
233
        return (left > right) ? -1 : ((left < right) ? 1 : 0);
234
      }
235
    });
236
237
    // for debugging
238
    //Search.lastresults = results.slice();  // a copy
239
    //console.info('search results:', Search.lastresults);
240
241
    // print the results
242
    var resultCount = results.length;
243
    function displayNextItem() {
244
      // results left, load the summary and display it
245
      if (results.length) {
246
        var item = results.pop();
247
        var listItem = $('<li style="display:none"></li>');
248
        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
0 ignored issues
show
Bug introduced by
The variable DOCUMENTATION_OPTIONS seems to be never declared. If this is a global, consider adding a /** global: DOCUMENTATION_OPTIONS */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
249
          // dirhtml builder
250
          var dirname = item[0] + '/';
251
          if (dirname.match(/\/index\/$/)) {
252
            dirname = dirname.substring(0, dirname.length-6);
253
          } else if (dirname == 'index/') {
254
            dirname = '';
255
          }
256
          listItem.append($('<a/>').attr('href',
257
            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
258
            highlightstring + item[2]).html(item[1]));
259
        } else {
260
          // normal html builders
261
          listItem.append($('<a/>').attr('href',
262
            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
263
            highlightstring + item[2]).html(item[1]));
264
        }
265
        if (item[3]) {
266
          listItem.append($('<span> (' + item[3] + ')</span>'));
267
          Search.output.append(listItem);
268
          listItem.slideDown(5, function() {
269
            displayNextItem();
270
          });
271
        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
272
          $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX,
273
                  dataType: "text",
274
                  complete: function(jqxhr, textstatus) {
0 ignored issues
show
Unused Code introduced by
The parameter textstatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
275
                    var data = jqxhr.responseText;
276
                    if (data !== '' && data !== undefined) {
277
                      listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
278
                    }
279
                    Search.output.append(listItem);
280
                    listItem.slideDown(5, function() {
281
                      displayNextItem();
282
                    });
283
                  }});
284
        } else {
285
          // no source available, just display title
286
          Search.output.append(listItem);
287
          listItem.slideDown(5, function() {
288
            displayNextItem();
289
          });
290
        }
291
      }
292
      // search finished, update title and status message
293
      else {
294
        Search.stopPulse();
295
        Search.title.text(_('Search Results'));
296
        if (!resultCount)
297
          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.'));
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
298
        else
299
            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
300
        Search.status.fadeIn(500);
301
      }
302
    }
303
    displayNextItem();
304
  },
305
306
  /**
307
   * search for object names
308
   */
309
  performObjectSearch : function(object, otherterms) {
310
    var filenames = this._index.filenames;
311
    var docnames = this._index.docnames;
312
    var objects = this._index.objects;
313
    var objnames = this._index.objnames;
314
    var titles = this._index.titles;
315
316
    var i;
317
    var results = [];
318
319
    for (var prefix in objects) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
320
      for (var name in objects[prefix]) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
321
        var fullname = (prefix ? prefix + '.' : '') + name;
322
        if (fullname.toLowerCase().indexOf(object) > -1) {
323
          var score = 0;
324
          var parts = fullname.split('.');
325
          // check for different match types: exact matches of full name or
326
          // "last name" (i.e. last dotted part)
327
          if (fullname == object || parts[parts.length - 1] == object) {
328
            score += Scorer.objNameMatch;
329
          // matches in last name
330
          } else if (parts[parts.length - 1].indexOf(object) > -1) {
331
            score += Scorer.objPartialMatch;
332
          }
333
          var match = objects[prefix][name];
334
          var objname = objnames[match[1]][2];
335
          var title = titles[match[0]];
336
          // If more than one term searched for, we require other words to be
337
          // found in the name/title/description
338
          if (otherterms.length > 0) {
339
            var haystack = (prefix + ' ' + name + ' ' +
340
                            objname + ' ' + title).toLowerCase();
341
            var allfound = true;
342
            for (i = 0; i < otherterms.length; i++) {
343
              if (haystack.indexOf(otherterms[i]) == -1) {
344
                allfound = false;
345
                break;
346
              }
347
            }
348
            if (!allfound) {
349
              continue;
350
            }
351
          }
352
          var descr = objname + _(', in ') + title;
353
354
          var anchor = match[3];
355
          if (anchor === '')
356
            anchor = fullname;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
357
          else if (anchor == '-')
358
            anchor = objnames[match[1]][1] + '-' + fullname;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
359
          // add custom score for some objects according to scorer
360
          if (Scorer.objPrio.hasOwnProperty(match[2])) {
361
            score += Scorer.objPrio[match[2]];
362
          } else {
363
            score += Scorer.objPrioDefault;
364
          }
365
          results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
366
        }
367
      }
368
    }
369
370
    return results;
371
  },
372
373
  /**
374
   * search for full-text terms in the index
375
   */
376
  performTermsSearch : function(searchterms, excluded, terms, titleterms) {
377
    var docnames = this._index.docnames;
378
    var filenames = this._index.filenames;
379
    var titles = this._index.titles;
380
381
    var i, j, file;
382
    var fileMap = {};
383
    var scoreMap = {};
384
    var results = [];
385
386
    // perform the search on the required terms
387
    for (i = 0; i < searchterms.length; i++) {
388
      var word = searchterms[i];
389
      var files = [];
390
      var _o = [
391
        {files: terms[word], score: Scorer.term},
392
        {files: titleterms[word], score: Scorer.title}
393
      ];
394
      // add support for partial matches
395
      if (word.length > 2) {
396
        for (var w in terms) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
397
          if (w.match(word) && !terms[word]) {
398
            _o.push({files: terms[w], score: Scorer.partialTerm})
399
          }
400
        }
401
        for (var w in titleterms) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable w already seems to be declared on line 396. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
402
          if (w.match(word) && !titleterms[word]) {
403
              _o.push({files: titleterms[w], score: Scorer.partialTitle})
404
          }
405
        }
406
      }
407
408
      // no match but word was a required one
409
      if ($u.every(_o, function(o){return o.files === undefined;})) {
0 ignored issues
show
Bug introduced by
The variable $u seems to be never declared. If this is a global, consider adding a /** global: $u */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
410
        break;
411
      }
412
      // found search word in contents
413
      $u.each(_o, function(o) {
414
        var _files = o.files;
415
        if (_files === undefined)
416
          return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
417
418
        if (_files.length === undefined)
419
          _files = [_files];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
420
        files = files.concat(_files);
0 ignored issues
show
Bug introduced by
The variable files is changed as part of the for loop for example by [] on line 389. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
421
422
        // set score for the word in each file to Scorer.term
423
        for (j = 0; j < _files.length; j++) {
0 ignored issues
show
Bug introduced by
The variable j is changed as part of the for loop for example by j++ on line 423. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
424
          file = _files[j];
425
          if (!(file in scoreMap))
0 ignored issues
show
Bug introduced by
The variable file is changed as part of the for loop for example by _files.j on line 424. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
426
            scoreMap[file] = {}
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
427
          scoreMap[file][word] = o.score;
428
        }
429
      });
430
431
      // create the mapping
432
      for (j = 0; j < files.length; j++) {
433
        file = files[j];
434
        if (file in fileMap)
435
          fileMap[file].push(word);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
436
        else
437
          fileMap[file] = [word];
438
      }
439
    }
440
441
    // now check if the files don't contain excluded terms
442
    for (file in fileMap) {
443
      var valid = true;
444
445
      // check if all requirements are matched
446
      var filteredTermCount = // as search terms with length < 3 are discarded: ignore
447
        searchterms.filter(function(term){return term.length > 2}).length
448
      if (
449
        fileMap[file].length != searchterms.length &&
450
        fileMap[file].length != filteredTermCount
451
      ) continue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
452
453
      // ensure that none of the excluded terms is in the search result
454
      for (i = 0; i < excluded.length; i++) {
455
        if (terms[excluded[i]] == file ||
456
            titleterms[excluded[i]] == file ||
457
            $u.contains(terms[excluded[i]] || [], file) ||
458
            $u.contains(titleterms[excluded[i]] || [], file)) {
459
          valid = false;
460
          break;
461
        }
462
      }
463
464
      // if we have still a valid result we can add it to the result list
465
      if (valid) {
466
        // select one (max) score for the file.
467
        // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
468
        var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
0 ignored issues
show
introduced by
The variable file is changed by the for-each loop on line 442. Only the value of the last iteration will be visible in this function if it is called outside of the loop.
Loading history...
469
        results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
470
      }
471
    }
472
    return results;
473
  },
474
475
  /**
476
   * helper function to return a node containing the
477
   * search summary for a given text. keywords is a list
478
   * of stemmed words, hlwords is the list of normal, unstemmed
479
   * words. the first one is used to find the occurrence, the
480
   * latter for highlighting it.
481
   */
482
  makeSearchSummary : function(htmlText, keywords, hlwords) {
483
    var text = Search.htmlToText(htmlText);
484
    var textLower = text.toLowerCase();
485
    var start = 0;
486
    $.each(keywords, function() {
487
      var i = textLower.indexOf(this.toLowerCase());
488
      if (i > -1)
489
        start = i;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
490
    });
491
    start = Math.max(start - 120, 0);
492
    var excerpt = ((start > 0) ? '...' : '') +
493
      $.trim(text.substr(start, 240)) +
494
      ((start + 240 - text.length) ? '...' : '');
495
    var rv = $('<div class="context"></div>').text(excerpt);
496
    $.each(hlwords, function() {
497
      rv = rv.highlightText(this, 'highlighted');
498
    });
499
    return rv;
500
  }
501
};
502
503
$(document).ready(function() {
504
  Search.init();
505
});
506