Test Failed
Push — master ( 9811b7...5b4ca1 )
by Chad
16:14 queued 01:44
created

doc/build/_static/websupport.js   F

Complexity

Total Complexity 128
Complexity/F 1.58

Size

Lines of Code 797
Function Count 81

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 128
dl 0
loc 797
rs 2.1818
c 1
b 0
f 0
cc 0
nc 16777216
mnd 3
bc 106
fnc 81
bpm 1.3086
cpm 1.5802
noi 32

30 Functions

Rating   Name   Duplication   Size   Complexity  
A $.fn.autogrow.resize 0 11 1
B $.fn.comment 0 42 1
A websupport.js ➔ showProposeChange 0 8 1
A websupport.js ➔ init 0 4 1
A websupport.js ➔ closeReply 0 10 1
A $(document).ready 0 3 1
A websupport.js ➔ renderTemplate 0 15 1
C websupport.js ➔ createCommentDiv 0 32 14
A $.fn.autogrow 0 17 1
A websupport.js ➔ acceptComment 0 14 1
A websupport.js ➔ initEvents 0 50 1
B websupport.js ➔ getComments 0 31 1
B websupport.js ➔ insertComment 0 29 3
A websupport.js ➔ hide 0 8 1
C websupport.js ➔ handleVote 0 58 12
A websupport.js ➔ hideProposeChange 0 7 1
A websupport.js ➔ initComparator 0 16 4
A websupport.js ➔ handleReSort 0 19 3
A websupport.js ➔ showError 0 9 1
A websupport.js ➔ setComparator 0 15 2
A websupport.js ➔ hideProposal 0 5 1
A websupport.js ➔ toggleCommentMarkupBox 0 3 1
B websupport.js ➔ openReply 0 24 1
A websupport.js ➔ sortComments 0 7 1
A websupport.js ➔ getChildren 0 11 1
A websupport.js ➔ appendComments 0 10 1
A websupport.js ➔ addComment 0 54 2
A websupport.js ➔ showProposal 0 5 1
A websupport.js ➔ show 0 17 1
B websupport.js ➔ deleteComment 0 33 1

How to fix   Complexity   

Complexity

Complex classes like doc/build/_static/websupport.js 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
 * websupport.js
3
 * ~~~~~~~~~~~~~
4
 *
5
 * sphinx.websupport utilties for all documentation.
6
 *
7
 * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
8
 * :license: BSD, see LICENSE for details.
9
 *
10
 */
11
12
(function($) {
13
  $.fn.autogrow = function() {
14
    return this.each(function() {
15
    var textarea = this;
16
17
    $.fn.autogrow.resize(textarea);
18
19
    $(textarea)
20
      .focus(function() {
21
        textarea.interval = setInterval(function() {
22
          $.fn.autogrow.resize(textarea);
23
        }, 500);
24
      })
25
      .blur(function() {
26
        clearInterval(textarea.interval);
27
      });
28
    });
29
  };
30
31
  $.fn.autogrow.resize = function(textarea) {
32
    var lineHeight = parseInt($(textarea).css('line-height'), 10);
33
    var lines = textarea.value.split('\n');
34
    var columns = textarea.cols;
35
    var lineCount = 0;
36
    $.each(lines, function() {
37
      lineCount += Math.ceil(this.length / columns) || 1;
38
    });
39
    var height = lineHeight * (lineCount + 1);
40
    $(textarea).css('height', height);
41
  };
42
})(jQuery);
43
44
(function($) {
45
  var comp, by;
46
47
  function init() {
48
    initEvents();
49
    initComparator();
50
  }
51
52
  function initEvents() {
53
    $(document).on("click", 'a.comment-close', function(event) {
54
      event.preventDefault();
55
      hide($(this).attr('id').substring(2));
56
    });
57
    $(document).on("click", 'a.vote', function(event) {
58
      event.preventDefault();
59
      handleVote($(this));
60
    });
61
    $(document).on("click", 'a.reply', function(event) {
62
      event.preventDefault();
63
      openReply($(this).attr('id').substring(2));
64
    });
65
    $(document).on("click", 'a.close-reply', function(event) {
66
      event.preventDefault();
67
      closeReply($(this).attr('id').substring(2));
68
    });
69
    $(document).on("click", 'a.sort-option', function(event) {
70
      event.preventDefault();
71
      handleReSort($(this));
72
    });
73
    $(document).on("click", 'a.show-proposal', function(event) {
74
      event.preventDefault();
75
      showProposal($(this).attr('id').substring(2));
76
    });
77
    $(document).on("click", 'a.hide-proposal', function(event) {
78
      event.preventDefault();
79
      hideProposal($(this).attr('id').substring(2));
80
    });
81
    $(document).on("click", 'a.show-propose-change', function(event) {
82
      event.preventDefault();
83
      showProposeChange($(this).attr('id').substring(2));
84
    });
85
    $(document).on("click", 'a.hide-propose-change', function(event) {
86
      event.preventDefault();
87
      hideProposeChange($(this).attr('id').substring(2));
88
    });
89
    $(document).on("click", 'a.accept-comment', function(event) {
90
      event.preventDefault();
91
      acceptComment($(this).attr('id').substring(2));
92
    });
93
    $(document).on("click", 'a.delete-comment', function(event) {
94
      event.preventDefault();
95
      deleteComment($(this).attr('id').substring(2));
96
    });
97
    $(document).on("click", 'a.comment-markup', function(event) {
98
      event.preventDefault();
99
      toggleCommentMarkupBox($(this).attr('id').substring(2));
100
    });
101
  }
102
103
  /**
104
   * Set comp, which is a comparator function used for sorting and
105
   * inserting comments into the list.
106
   */
107
  function setComparator() {
108
    // If the first three letters are "asc", sort in ascending order
109
    // and remove the prefix.
110
    if (by.substring(0,3) == 'asc') {
111
      var i = by.substring(3);
112
      comp = function(a, b) { return a[i] - b[i]; };
113
    } else {
114
      // Otherwise sort in descending order.
115
      comp = function(a, b) { return b[by] - a[by]; };
116
    }
117
118
    // Reset link styles and format the selected sort option.
119
    $('a.sel').attr('href', '#').removeClass('sel');
120
    $('a.by' + by).removeAttr('href').addClass('sel');
121
  }
122
123
  /**
124
   * Create a comp function. If the user has preferences stored in
125
   * the sortBy cookie, use those, otherwise use the default.
126
   */
127
  function initComparator() {
128
    by = 'rating'; // Default to sort by rating.
129
    // If the sortBy cookie is set, use that instead.
130
    if (document.cookie.length > 0) {
131
      var start = document.cookie.indexOf('sortBy=');
132
      if (start != -1) {
133
        start = start + 7;
134
        var end = document.cookie.indexOf(";", start);
135
        if (end == -1) {
136
          end = document.cookie.length;
137
          by = unescape(document.cookie.substring(start, end));
138
        }
139
      }
140
    }
141
    setComparator();
142
  }
143
144
  /**
145
   * Show a comment div.
146
   */
147
  function show(id) {
148
    $('#ao' + id).hide();
149
    $('#ah' + id).show();
150
    var context = $.extend({id: id}, opts);
151
    var popup = $(renderTemplate(popupTemplate, context)).hide();
152
    popup.find('textarea[name="proposal"]').hide();
153
    popup.find('a.by' + by).addClass('sel');
154
    var form = popup.find('#cf' + id);
155
    form.submit(function(event) {
156
      event.preventDefault();
157
      addComment(form);
158
    });
159
    $('#s' + id).after(popup);
160
    popup.slideDown('fast', function() {
161
      getComments(id);
162
    });
163
  }
164
165
  /**
166
   * Hide a comment div.
167
   */
168
  function hide(id) {
169
    $('#ah' + id).hide();
170
    $('#ao' + id).show();
171
    var div = $('#sc' + id);
172
    div.slideUp('fast', function() {
173
      div.remove();
174
    });
175
  }
176
177
  /**
178
   * Perform an ajax request to get comments for a node
179
   * and insert the comments into the comments tree.
180
   */
181
  function getComments(id) {
182
    $.ajax({
183
     type: 'GET',
184
     url: opts.getCommentsURL,
185
     data: {node: id},
186
     success: function(data, textStatus, request) {
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...
Unused Code introduced by
The parameter request 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...
187
       var ul = $('#cl' + id);
188
       var speed = 100;
189
       $('#cf' + id)
190
         .find('textarea[name="proposal"]')
191
         .data('source', data.source);
192
193
       if (data.comments.length === 0) {
194
         ul.html('<li>No comments yet.</li>');
195
         ul.data('empty', true);
196
       } else {
197
         // If there are comments, sort them and put them in the list.
198
         var comments = sortComments(data.comments);
199
         speed = data.comments.length * 100;
200
         appendComments(comments, ul);
201
         ul.data('empty', false);
202
       }
203
       $('#cn' + id).slideUp(speed + 200);
204
       ul.slideDown(speed);
205
     },
206
     error: function(request, textStatus, error) {
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...
Unused Code introduced by
The parameter error 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...
Unused Code introduced by
The parameter request 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...
207
       showError('Oops, there was a problem retrieving the comments.');
208
     },
209
     dataType: 'json'
210
    });
211
  }
212
213
  /**
214
   * Add a comment via ajax and insert the comment into the comment tree.
215
   */
216
  function addComment(form) {
217
    var node_id = form.find('input[name="node"]').val();
218
    var parent_id = form.find('input[name="parent"]').val();
219
    var text = form.find('textarea[name="comment"]').val();
220
    var proposal = form.find('textarea[name="proposal"]').val();
221
222
    if (text == '') {
223
      showError('Please enter a comment.');
224
      return;
225
    }
226
227
    // Disable the form that is being submitted.
228
    form.find('textarea,input').attr('disabled', 'disabled');
229
230
    // Send the comment to the server.
231
    $.ajax({
232
      type: "POST",
233
      url: opts.addCommentURL,
234
      dataType: 'json',
235
      data: {
236
        node: node_id,
237
        parent: parent_id,
238
        text: text,
239
        proposal: proposal
240
      },
241
      success: function(data, textStatus, error) {
0 ignored issues
show
Unused Code introduced by
The parameter error 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...
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...
242
        // Reset the form.
243
        if (node_id) {
244
          hideProposeChange(node_id);
245
        }
246
        form.find('textarea')
247
          .val('')
248
          .add(form.find('input'))
249
          .removeAttr('disabled');
250
	var ul = $('#cl' + (node_id || parent_id));
251
        if (ul.data('empty')) {
252
          $(ul).empty();
253
          ul.data('empty', false);
254
        }
255
        insertComment(data.comment);
256
        var ao = $('#ao' + node_id);
257
        ao.find('img').attr({'src': opts.commentBrightImage});
258
        if (node_id) {
259
          // if this was a "root" comment, remove the commenting box
260
          // (the user can get it back by reopening the comment popup)
261
          $('#ca' + node_id).slideUp();
262
        }
263
      },
264
      error: function(request, textStatus, error) {
0 ignored issues
show
Unused Code introduced by
The parameter request 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...
Unused Code introduced by
The parameter error 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...
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...
265
        form.find('textarea,input').removeAttr('disabled');
266
        showError('Oops, there was a problem adding the comment.');
267
      }
268
    });
269
  }
270
271
  /**
272
   * Recursively append comments to the main comment list and children
273
   * lists, creating the comment tree.
274
   */
275
  function appendComments(comments, ul) {
276
    $.each(comments, function() {
277
      var div = createCommentDiv(this);
278
      ul.append($(document.createElement('li')).html(div));
279
      appendComments(this.children, div.find('ul.comment-children'));
280
      // To avoid stagnating data, don't store the comments children in data.
281
      this.children = null;
282
      div.data('comment', this);
283
    });
284
  }
285
286
  /**
287
   * After adding a new comment, it must be inserted in the correct
288
   * location in the comment tree.
289
   */
290
  function insertComment(comment) {
291
    var div = createCommentDiv(comment);
292
293
    // To avoid stagnating data, don't store the comments children in data.
294
    comment.children = null;
295
    div.data('comment', comment);
296
297
    var ul = $('#cl' + (comment.node || comment.parent));
298
    var siblings = getChildren(ul);
299
300
    var li = $(document.createElement('li'));
301
    li.hide();
302
303
    // Determine where in the parents children list to insert this comment.
304
    for(i=0; i < siblings.length; i++) {
0 ignored issues
show
Bug introduced by
The variable i 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.i.
Loading history...
305
      if (comp(comment, siblings[i]) <= 0) {
306
        $('#cd' + siblings[i].id)
307
          .parent()
308
          .before(li.html(div));
309
        li.slideDown('fast');
310
        return;
311
      }
312
    }
313
314
    // If we get here, this comment rates lower than all the others,
315
    // or it is the only comment in the list.
316
    ul.append(li.html(div));
317
    li.slideDown('fast');
318
  }
319
320
  function acceptComment(id) {
321
    $.ajax({
322
      type: 'POST',
323
      url: opts.acceptCommentURL,
324
      data: {id: id},
325
      success: function(data, textStatus, request) {
0 ignored issues
show
Unused Code introduced by
The parameter request 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...
Unused Code introduced by
The parameter data 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...
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...
326
        $('#cm' + id).fadeOut('fast');
327
        $('#cd' + id).removeClass('moderate');
328
      },
329
      error: function(request, textStatus, error) {
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...
Unused Code introduced by
The parameter request 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...
Unused Code introduced by
The parameter error 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...
330
        showError('Oops, there was a problem accepting the comment.');
331
      }
332
    });
333
  }
334
335
  function deleteComment(id) {
336
    $.ajax({
337
      type: 'POST',
338
      url: opts.deleteCommentURL,
339
      data: {id: id},
340
      success: function(data, textStatus, request) {
0 ignored issues
show
Unused Code introduced by
The parameter request 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...
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...
341
        var div = $('#cd' + id);
342
        if (data == 'delete') {
343
          // Moderator mode: remove the comment and all children immediately
344
          div.slideUp('fast', function() {
345
            div.remove();
346
          });
347
          return;
348
        }
349
        // User mode: only mark the comment as deleted
350
        div
351
          .find('span.user-id:first')
352
          .text('[deleted]').end()
353
          .find('div.comment-text:first')
354
          .text('[deleted]').end()
355
          .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
356
                ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
357
          .remove();
358
        var comment = div.data('comment');
359
        comment.username = '[deleted]';
360
        comment.text = '[deleted]';
361
        div.data('comment', comment);
362
      },
363
      error: function(request, textStatus, error) {
0 ignored issues
show
Unused Code introduced by
The parameter request 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...
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...
Unused Code introduced by
The parameter error 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...
364
        showError('Oops, there was a problem deleting the comment.');
365
      }
366
    });
367
  }
368
369
  function showProposal(id) {
370
    $('#sp' + id).hide();
371
    $('#hp' + id).show();
372
    $('#pr' + id).slideDown('fast');
373
  }
374
375
  function hideProposal(id) {
376
    $('#hp' + id).hide();
377
    $('#sp' + id).show();
378
    $('#pr' + id).slideUp('fast');
379
  }
380
381
  function showProposeChange(id) {
382
    $('#pc' + id).hide();
383
    $('#hc' + id).show();
384
    var textarea = $('#pt' + id);
385
    textarea.val(textarea.data('source'));
386
    $.fn.autogrow.resize(textarea[0]);
387
    textarea.slideDown('fast');
388
  }
389
390
  function hideProposeChange(id) {
391
    $('#hc' + id).hide();
392
    $('#pc' + id).show();
393
    var textarea = $('#pt' + id);
394
    textarea.val('').removeAttr('disabled');
395
    textarea.slideUp('fast');
396
  }
397
398
  function toggleCommentMarkupBox(id) {
399
    $('#mb' + id).toggle();
400
  }
401
402
  /** Handle when the user clicks on a sort by link. */
403
  function handleReSort(link) {
404
    var classes = link.attr('class').split(/\s+/);
405
    for (var i=0; i<classes.length; i++) {
406
      if (classes[i] != 'sort-option') {
407
	by = classes[i].substring(2);
408
      }
409
    }
410
    setComparator();
411
    // Save/update the sortBy cookie.
412
    var expiration = new Date();
413
    expiration.setDate(expiration.getDate() + 365);
414
    document.cookie= 'sortBy=' + escape(by) +
0 ignored issues
show
Bug introduced by
The variable by seems to not be initialized for all possible execution paths. Are you sure escape handles undefined variables?
Loading history...
415
                     ';expires=' + expiration.toUTCString();
416
    $('ul.comment-ul').each(function(index, ul) {
417
      var comments = getChildren($(ul), true);
418
      comments = sortComments(comments);
419
      appendComments(comments, $(ul).empty());
420
    });
421
  }
422
423
  /**
424
   * Function to process a vote when a user clicks an arrow.
425
   */
426
  function handleVote(link) {
427
    if (!opts.voting) {
428
      showError("You'll need to login to vote.");
429
      return;
430
    }
431
432
    var id = link.attr('id');
433
    if (!id) {
434
      // Didn't click on one of the voting arrows.
435
      return;
436
    }
437
    // If it is an unvote, the new vote value is 0,
438
    // Otherwise it's 1 for an upvote, or -1 for a downvote.
439
    var value = 0;
440
    if (id.charAt(1) != 'u') {
441
      value = id.charAt(0) == 'u' ? 1 : -1;
442
    }
443
    // The data to be sent to the server.
444
    var d = {
445
      comment_id: id.substring(2),
446
      value: value
447
    };
448
449
    // Swap the vote and unvote links.
450
    link.hide();
451
    $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
452
      .show();
453
454
    // The div the comment is displayed in.
455
    var div = $('div#cd' + d.comment_id);
456
    var data = div.data('comment');
457
458
    // If this is not an unvote, and the other vote arrow has
459
    // already been pressed, unpress it.
460
    if ((d.value !== 0) && (data.vote === d.value * -1)) {
461
      $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
462
      $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
463
    }
464
465
    // Update the comments rating in the local data.
466
    data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
467
    data.vote = d.value;
468
    div.data('comment', data);
469
470
    // Change the rating text.
471
    div.find('.rating:first')
472
      .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
473
474
    // Send the vote information to the server.
475
    $.ajax({
476
      type: "POST",
477
      url: opts.processVoteURL,
478
      data: d,
479
      error: function(request, textStatus, error) {
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...
Unused Code introduced by
The parameter error 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...
Unused Code introduced by
The parameter request 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...
480
        showError('Oops, there was a problem casting that vote.');
481
      }
482
    });
483
  }
484
485
  /**
486
   * Open a reply form used to reply to an existing comment.
487
   */
488
  function openReply(id) {
489
    // Swap out the reply link for the hide link
490
    $('#rl' + id).hide();
491
    $('#cr' + id).show();
492
493
    // Add the reply li to the children ul.
494
    var div = $(renderTemplate(replyTemplate, {id: id})).hide();
495
    $('#cl' + id)
496
      .prepend(div)
497
      // Setup the submit handler for the reply form.
498
      .find('#rf' + id)
499
      .submit(function(event) {
500
        event.preventDefault();
501
        addComment($('#rf' + id));
502
        closeReply(id);
503
      })
504
      .find('input[type=button]')
505
      .click(function() {
506
        closeReply(id);
507
      });
508
    div.slideDown('fast', function() {
509
      $('#rf' + id).find('textarea').focus();
510
    });
511
  }
512
513
  /**
514
   * Close the reply form opened with openReply.
515
   */
516
  function closeReply(id) {
517
    // Remove the reply div from the DOM.
518
    $('#rd' + id).slideUp('fast', function() {
519
      $(this).remove();
520
    });
521
522
    // Swap out the hide link for the reply link
523
    $('#cr' + id).hide();
524
    $('#rl' + id).show();
525
  }
526
527
  /**
528
   * Recursively sort a tree of comments using the comp comparator.
529
   */
530
  function sortComments(comments) {
531
    comments.sort(comp);
532
    $.each(comments, function() {
533
      this.children = sortComments(this.children);
534
    });
535
    return comments;
536
  }
537
538
  /**
539
   * Get the children comments from a ul. If recursive is true,
540
   * recursively include childrens' children.
541
   */
542
  function getChildren(ul, recursive) {
543
    var children = [];
544
    ul.children().children("[id^='cd']")
545
      .each(function() {
546
        var comment = $(this).data('comment');
547
        if (recursive)
548
          comment.children = getChildren($(this).find('#cl' + comment.id), true);
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...
549
        children.push(comment);
550
      });
551
    return children;
552
  }
553
554
  /** Create a div to display a comment in. */
555
  function createCommentDiv(comment) {
556
    if (!comment.displayed && !opts.moderator) {
557
      return $('<div class="moderate">Thank you!  Your comment will show up '
558
               + 'once it is has been approved by a moderator.</div>');
559
    }
560
    // Prettify the comment rating.
561
    comment.pretty_rating = comment.rating + ' point' +
562
      (comment.rating == 1 ? '' : 's');
563
    // Make a class (for displaying not yet moderated comments differently)
564
    comment.css_class = comment.displayed ? '' : ' moderate';
565
    // Create a div for this comment.
566
    var context = $.extend({}, opts, comment);
567
    var div = $(renderTemplate(commentTemplate, context));
568
569
    // If the user has voted on this comment, highlight the correct arrow.
570
    if (comment.vote) {
571
      var direction = (comment.vote == 1) ? 'u' : 'd';
572
      div.find('#' + direction + 'v' + comment.id).hide();
573
      div.find('#' + direction + 'u' + comment.id).show();
574
    }
575
576
    if (opts.moderator || comment.text != '[deleted]') {
577
      div.find('a.reply').show();
578
      if (comment.proposal_diff)
579
        div.find('#sp' + comment.id).show();
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...
580
      if (opts.moderator && !comment.displayed)
581
        div.find('#cm' + comment.id).show();
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...
582
      if (opts.moderator || (opts.username == comment.username))
583
        div.find('#dc' + comment.id).show();
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...
584
    }
585
    return div;
586
  }
587
588
  /**
589
   * A simple template renderer. Placeholders such as <%id%> are replaced
590
   * by context['id'] with items being escaped. Placeholders such as <#id#>
591
   * are not escaped.
592
   */
593
  function renderTemplate(template, context) {
594
    var esc = $(document.createElement('div'));
595
596
    function handle(ph, escape) {
597
      var cur = context;
598
      $.each(ph.split('.'), function() {
599
        cur = cur[this];
600
      });
601
      return escape ? esc.text(cur || "").html() : cur;
602
    }
603
604
    return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
605
      return handle(arguments[2], arguments[1] == '%' ? true : false);
606
    });
607
  }
608
609
  /** Flash an error message briefly. */
610
  function showError(message) {
611
    $(document.createElement('div')).attr({'class': 'popup-error'})
612
      .append($(document.createElement('div'))
613
               .attr({'class': 'error-message'}).text(message))
614
      .appendTo('body')
615
      .fadeIn("slow")
616
      .delay(2000)
617
      .fadeOut("slow");
618
  }
619
620
  /** Add a link the user uses to open the comments popup. */
621
  $.fn.comment = function() {
622
    return this.each(function() {
623
      var id = $(this).attr('id').substring(1);
624
      var count = COMMENT_METADATA[id];
0 ignored issues
show
Bug introduced by
The variable COMMENT_METADATA seems to be never declared. If this is a global, consider adding a /** global: COMMENT_METADATA */ 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...
625
      var title = count + ' comment' + (count == 1 ? '' : 's');
626
      var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
627
      var addcls = count == 0 ? ' nocomment' : '';
628
      $(this)
629
        .append(
630
          $(document.createElement('a')).attr({
631
            href: '#',
632
            'class': 'sphinx-comment-open' + addcls,
633
            id: 'ao' + id
634
          })
635
            .append($(document.createElement('img')).attr({
636
              src: image,
637
              alt: 'comment',
638
              title: title
639
            }))
640
            .click(function(event) {
641
              event.preventDefault();
642
              show($(this).attr('id').substring(2));
643
            })
644
        )
645
        .append(
646
          $(document.createElement('a')).attr({
647
            href: '#',
648
            'class': 'sphinx-comment-close hidden',
649
            id: 'ah' + id
650
          })
651
            .append($(document.createElement('img')).attr({
652
              src: opts.closeCommentImage,
653
              alt: 'close',
654
              title: 'close'
655
            }))
656
            .click(function(event) {
657
              event.preventDefault();
658
              hide($(this).attr('id').substring(2));
659
            })
660
        );
661
    });
662
  };
663
664
  var opts = {
665
    processVoteURL: '/_process_vote',
666
    addCommentURL: '/_add_comment',
667
    getCommentsURL: '/_get_comments',
668
    acceptCommentURL: '/_accept_comment',
669
    deleteCommentURL: '/_delete_comment',
670
    commentImage: '/static/_static/comment.png',
671
    closeCommentImage: '/static/_static/comment-close.png',
672
    loadingImage: '/static/_static/ajax-loader.gif',
673
    commentBrightImage: '/static/_static/comment-bright.png',
674
    upArrow: '/static/_static/up.png',
675
    downArrow: '/static/_static/down.png',
676
    upArrowPressed: '/static/_static/up-pressed.png',
677
    downArrowPressed: '/static/_static/down-pressed.png',
678
    voting: false,
679
    moderator: false
680
  };
681
682
  if (typeof COMMENT_OPTIONS != "undefined") {
0 ignored issues
show
Bug introduced by
The variable COMMENT_OPTIONS seems to be never declared. If this is a global, consider adding a /** global: COMMENT_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...
683
    opts = jQuery.extend(opts, COMMENT_OPTIONS);
684
  }
685
686
  var popupTemplate = '\
687
    <div class="sphinx-comments" id="sc<%id%>">\
688
      <p class="sort-options">\
689
        Sort by:\
690
        <a href="#" class="sort-option byrating">best rated</a>\
691
        <a href="#" class="sort-option byascage">newest</a>\
692
        <a href="#" class="sort-option byage">oldest</a>\
693
      </p>\
694
      <div class="comment-header">Comments</div>\
695
      <div class="comment-loading" id="cn<%id%>">\
696
        loading comments... <img src="<%loadingImage%>" alt="" /></div>\
697
      <ul id="cl<%id%>" class="comment-ul"></ul>\
698
      <div id="ca<%id%>">\
699
      <p class="add-a-comment">Add a comment\
700
        (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
701
      <div class="comment-markup-box" id="mb<%id%>">\
702
        reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
703
        <code>``code``</code>, \
704
        code blocks: <code>::</code> and an indented block after blank line</div>\
705
      <form method="post" id="cf<%id%>" class="comment-form" action="">\
706
        <textarea name="comment" cols="80"></textarea>\
707
        <p class="propose-button">\
708
          <a href="#" id="pc<%id%>" class="show-propose-change">\
709
            Propose a change &#9657;\
710
          </a>\
711
          <a href="#" id="hc<%id%>" class="hide-propose-change">\
712
            Propose a change &#9663;\
713
          </a>\
714
        </p>\
715
        <textarea name="proposal" id="pt<%id%>" cols="80"\
716
                  spellcheck="false"></textarea>\
717
        <input type="submit" value="Add comment" />\
718
        <input type="hidden" name="node" value="<%id%>" />\
719
        <input type="hidden" name="parent" value="" />\
720
      </form>\
721
      </div>\
722
    </div>';
723
724
  var commentTemplate = '\
725
    <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
726
      <div class="vote">\
727
        <div class="arrow">\
728
          <a href="#" id="uv<%id%>" class="vote" title="vote up">\
729
            <img src="<%upArrow%>" />\
730
          </a>\
731
          <a href="#" id="uu<%id%>" class="un vote" title="vote up">\
732
            <img src="<%upArrowPressed%>" />\
733
          </a>\
734
        </div>\
735
        <div class="arrow">\
736
          <a href="#" id="dv<%id%>" class="vote" title="vote down">\
737
            <img src="<%downArrow%>" id="da<%id%>" />\
738
          </a>\
739
          <a href="#" id="du<%id%>" class="un vote" title="vote down">\
740
            <img src="<%downArrowPressed%>" />\
741
          </a>\
742
        </div>\
743
      </div>\
744
      <div class="comment-content">\
745
        <p class="tagline comment">\
746
          <span class="user-id"><%username%></span>\
747
          <span class="rating"><%pretty_rating%></span>\
748
          <span class="delta"><%time.delta%></span>\
749
        </p>\
750
        <div class="comment-text comment"><#text#></div>\
751
        <p class="comment-opts comment">\
752
          <a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
753
          <a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
754
          <a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
755
          <a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
756
          <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
757
          <span id="cm<%id%>" class="moderation hidden">\
758
            <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
759
          </span>\
760
        </p>\
761
        <pre class="proposal" id="pr<%id%>">\
762
<#proposal_diff#>\
763
        </pre>\
764
          <ul class="comment-children" id="cl<%id%>"></ul>\
765
        </div>\
766
        <div class="clearleft"></div>\
767
      </div>\
768
    </div>';
769
770
  var replyTemplate = '\
771
    <li>\
772
      <div class="reply-div" id="rd<%id%>">\
773
        <form id="rf<%id%>">\
774
          <textarea name="comment" cols="80"></textarea>\
775
          <input type="submit" value="Add reply" />\
776
          <input type="button" value="Cancel" />\
777
          <input type="hidden" name="parent" value="<%id%>" />\
778
          <input type="hidden" name="node" value="" />\
779
        </form>\
780
      </div>\
781
    </li>';
782
783
  $(document).ready(function() {
784
    init();
785
  });
786
})(jQuery);
787
788
$(document).ready(function() {
789
  // add comment anchors for all paragraphs that are commentable
790
  $('.sphinx-has-comment').comment();
791
792
  // highlight search words in search results
793
  $("div.context").each(function() {
794
    var params = $.getQueryParameters();
795
    var terms = (params.q) ? params.q[0].split(/\s+/) : [];
796
    var result = $(this);
797
    $.each(terms, function() {
798
      result.highlightText(this.toLowerCase(), 'highlighted');
799
    });
800
  });
801
802
  // directly open comment window if requested
803
  var anchor = document.location.hash;
804
  if (anchor.substring(0, 9) == '#comment-') {
805
    $('#ao' + anchor.substring(9)).click();
806
    document.location.hash = '#s' + anchor.substring(9);
807
  }
808
});
809