PageSourceSearch

https://gogs.waldemar-brodkorb.de/js/gogs.js?v=3ba8aca90e17e5410b7e8b227c9f29256ac3e875

js waldemar-brodkorb.de collected 2026-09-28 06:53:40 UTC 47,885 bytes, 1,790 lines download raw bytes

1"use strict";
2
3var csrf;
4var suburl;
5
6function initCommentPreviewTab($form) {
7  var $tabMenu = $form.find(".tabular.menu");
8  $tabMenu.find(".item").tab();
9  $tabMenu
10    .find('.item[data-tab="' + $tabMenu.data("preview") + '"]')
11    .click(function() {
12      var $this = $(this);
13      $.post(
14        $this.data("url"),
15        {
16          _csrf: csrf,
17          mode: "gfm",
18          context: $this.data("context"),
19          text: $form
20            .find(
21              '.tab.segment[data-tab="' + $tabMenu.data("write") + '"] textarea'
22            )
23            .val()
24        },
25        function(data) {
26          var $previewPanel = $form.find(
27            '.tab.segment[data-tab="' + $tabMenu.data("preview") + '"]'
28          );
29          $previewPanel.html(data);
30          emojify.run($previewPanel[0]);
31          $("pre code", $previewPanel[0]).each(function(i, block) {
32            hljs.highlightBlock(block);
33          });
34        }
35      );
36    });
37
38  buttonsClickOnEnter();
39}
40
41var previewFileModes;
42
43function initEditPreviewTab($form) {
44  var $tabMenu = $form.find(".tabular.menu");
45  $tabMenu.find(".item").tab();
46  var $previewTab = $tabMenu.find(
47    '.item[data-tab="' + $tabMenu.data("preview") + '"]'
48  );
49  if ($previewTab.length) {
50    previewFileModes = $previewTab.data("preview-file-modes").split(",");
51    $previewTab.click(function() {
52      var $this = $(this);
53      $.post(
54        $this.data("url"),
55        {
56          _csrf: csrf,
57          context: $this.data("context"),
58          text: $form
59            .find(
60              '.tab.segment[data-tab="' + $tabMenu.data("write") + '"] textarea'
61            )
62            .val()
63        },
64        function(data) {
65          var $previewPanel = $form.find(
66            '.tab.segment[data-tab="' + $tabMenu.data("preview") + '"]'
67          );
68          $previewPanel.html(data);
69          emojify.run($previewPanel[0]);
70          $("pre code", $previewPanel[0]).each(function(i, block) {
71            hljs.highlightBlock(block);
72          });
73        }
74      );
75    });
76  }
77}
78
79function initEditDiffTab($form) {
80  var $tabMenu = $form.find(".tabular.menu");
81  $tabMenu.find(".item").tab();
82  $tabMenu
83    .find('.item[data-tab="' + $tabMenu.data("diff") + '"]')
84    .click(function() {
85      var $this = $(this);
86      $.post(
87        $this.data("url"),
88        {
89          _csrf: csrf,
90          content: $form
91            .find(
92              '.tab.segment[data-tab="' + $tabMenu.data("write") + '"] textarea'
93            )
94            .val()
95        },
96        function(data) {
97          var $diffPreviewPanel = $form.find(
98            '.tab.segment[data-tab="' + $tabMenu.data("diff") + '"]'
99          );
100          $diffPreviewPanel.html(data);
101          emojify.run($diffPreviewPanel[0]);
102        }
103      );
104    });
105}
106
107function initEditForm() {
108  if ($(".edit.form").length == 0) {
109    return;
110  }
111
112  initEditPreviewTab($(".edit.form"));
113  initEditDiffTab($(".edit.form"));
114}
115
116function initCommentForm() {
117  if ($(".comment.form").length == 0) {
118    return;
119  }
120
121  initCommentPreviewTab($(".comment.form"));
122
123  // Labels
124  var $list = $(".ui.labels.list");
125  var $noSelect = $list.find(".no-select");
126  var $labelMenu = $(".select-label .menu");
127  var hasLabelUpdateAction = $labelMenu.data("action") == "update";
128
129  function updateIssueMeta(url, action, id) {
130    $.post(url, {
131      _csrf: csrf,
132      action: action,
133      id: id
134    });
135  }
136
137  // Add   to each unselected label to keep UI looks good.
138  // This should be added directly to HTML but somehow just get empty <span> on this page.
139  $labelMenu
140    .find(".item:not(.no-select) .octicon:not(.octicon-check)")
141    .each(function() {
142      $(this).html("&nbsp;");
143    });
144  $labelMenu.find(".item:not(.no-select)").click(function() {
145    if ($(this).hasClass("checked")) {
146      $(this).removeClass("checked");
147      $(this)
148        .find(".octicon")
149        .removeClass("octicon-check")
150        .html("&nbsp;");
151      if (hasLabelUpdateAction) {
152        updateIssueMeta(
153          $labelMenu.data("update-url"),
154          "detach",
155          $(this).data("id")
156        );
157      }
158    } else {
159      $(this).addClass("checked");
160      $(this)
161        .find(".octicon")
162        .addClass("octicon-check")
163        .html("");
164      if (hasLabelUpdateAction) {
165        updateIssueMeta(
166          $labelMenu.data("update-url"),
167          "attach",
168          $(this).data("id")
169        );
170      }
171    }
172
173    var labelIds = "";
174    $(this)
175      .parent()
176      .find(".item")
177      .each(function() {
178        if ($(this).hasClass("checked")) {
179          labelIds += $(this).data("id") + ",";
180          $($(this).data("id-selector")).removeClass("hide");
181        } else {
182          $($(this).data("id-selector")).addClass("hide");
183        }
184      });
185    if (labelIds.length == 0) {
186      $noSelect.removeClass("hide");
187    } else {
188      $noSelect.addClass("hide");
189    }
190    $(
191      $(this)
192        .parent()
193        .data("id")
194    ).val(labelIds);
195    return false;
196  });
197  $labelMenu.find(".no-select.item").click(function() {
198    if (hasLabelUpdateAction) {
199      updateIssueMeta($labelMenu.data("update-url"), "clear", "");
200    }
201
202    $(this)
203      .parent()
204      .find(".item")
205      .each(function() {
206        $(this).removeClass("checked");
207        $(this)
208          .find(".octicon")
209          .removeClass("octicon-check")
210          .html("&nbsp;");
211      });
212
213    $list.find(".item").each(function() {
214      $(this).addClass("hide");
215    });
216    $noSelect.removeClass("hide");
217    $(
218      $(this)
219        .parent()
220        .data("id")
221    ).val("");
222  });
223
224  function selectItem(select_id, input_id) {
225    var $menu = $(select_id + " .menu");
226    var $list = $(".ui" + select_id + ".list");
227    var hasUpdateAction = $menu.data("action") == "update";
228
229    $menu.find(".item:not(.no-select)").click(function() {
230      $(this)
231        .parent()
232        .find(".item")
233        .each(function() {
234          $(this).removeClass("selected active");
235        });
236
237      $(this).addClass("selected active");
238      if (hasUpdateAction) {
239        updateIssueMeta($menu.data("update-url"), "", $(this).data("id"));
240      }
241      switch (input_id) {
242        case "#milestone_id":
243          var $milestoneAnchor = $('<a class="item"></a>');
244          $milestoneAnchor.attr("href", $(this).data("href"));
245          $milestoneAnchor.text($(this).text());
246          $list.find(".selected").empty().append($milestoneAnchor);
247          break;
248        case "#assignee_id":
249          var $assigneeAnchor = $('<a class="item"></a>');
250          $assigneeAnchor.attr("href", $(this).data("href"));
251          $assigneeAnchor.append(
252            $('<img class="ui avatar image">').attr("src", $(this).data("avatar"))
253          );
254          $assigneeAnchor.append($("<span></span>").text($(this).text()));
255          $list.find(".selected").empty().append($assigneeAnchor);
256      }
257      $(".ui" + select_id + ".list .no-select").addClass("hide");
258      $(input_id).val($(this).data("id"));
259    });
260    $menu.find(".no-select.item").click(function() {
261      $(this)
262        .parent()
263        .find(".item:not(.no-select)")
264        .each(function() {
265          $(this).removeClass("selected active");
266        });
267
268      if (hasUpdateAction) {
269        updateIssueMeta($menu.data("update-url"), "", "");
270      }
271
272      $list.find(".selected").html("");
273      $list.find(".no-select").removeClass("hide");
274      $(input_id).val("");
275    });
276  }
277
278  // Milestone and assignee
279  selectItem(".select-milestone", "#milestone_id");
280  selectItem(".select-assignee", "#assignee_id");
281}
282
283function initRepository() {
284  if ($(".repository").length == 0) {
285    return;
286  }
287
288  function initFilterSearchDropdown(selector) {
289    var $dropdown = $(selector);
290    $dropdown.dropdown({
291      fullTextSearch: true,
292      onChange: function(text, value, $choice) {
293        window.location.href = $choice.data("url");
294        console.log($choice.data("url"));
295      },
296      message: { noResults: $dropdown.data("no-results") }
297    });
298  }
299
300  // File list and commits
301  if (
302    $(".repository.file.list").length > 0 ||
303    ".repository.commits".length > 0
304  ) {
305    initFilterSearchDropdown(".choose.reference .dropdown");
306
307    $(".reference.column").click(function() {
308      $(".choose.reference .scrolling.menu").css("display", "none");
309      $(".choose.reference .text").removeClass("black");
310      $($(this).data("target")).css("display", "block");
311      $(this)
312        .find(".text")
313        .addClass("black");
314      return false;
315    });
316  }
317
318  // Wiki
319  if ($(".repository.wiki.view").length > 0) {
320    initFilterSearchDropdown(".choose.page .dropdown");
321  }
322
323  // Options
324  if ($(".repository.settings.options").length > 0) {
325    $("#repo_name").keyup(function() {
326      var $prompt = $("#repo-name-change-prompt");
327      if (
328        $(this)
329          .val()
330          .toString()
331          .toLowerCase() !=
332        $(this)
333          .data("repo-name")
334          .toString()
335          .toLowerCase()
336      ) {
337        $prompt.show();
338      } else {
339        $prompt.hide();
340      }
341    });
342  }
343
344  // Branches
345  if ($(".repository.settings.branches").length > 0) {
346    initFilterSearchDropdown(".protected-branches .dropdown");
347    $(".enable-protection, .enable-whitelist").change(function() {
348      if (this.checked) {
349        $($(this).data("target")).removeClass("disabled");
350      } else {
351        $($(this).data("target")).addClass("disabled");
352      }
353    });
354  }
355
356  // Labels
357  if ($(".repository.labels").length > 0) {
358    // Create label
359    var $newLabelPanel = $(".new-label.segment");
360    $(".new-label.button").click(function() {
361      $newLabelPanel.show();
362    });
363    $(".new-label.segment .cancel").click(function() {
364      $newLabelPanel.hide();
365    });
366
367    $(".color-picker").each(function() {
368      $(this).minicolors();
369    });
370    $(".precolors .color").click(function() {
371      var color_hex = $(this).data("color-hex");
372      $(".color-picker").val(color_hex);
373      $(".minicolors-swatch-color").css("background-color", color_hex);
374    });
375    $(".edit-label-button").click(function() {
376      $("#label-modal-id").val($(this).data("id"));
377      $(".edit-label .new-label-input").val($(this).data("title"));
378      $(".edit-label .color-picker").val($(this).data("color"));
379      $(".minicolors-swatch-color").css(
380        "background-color",
381        $(this).data("color")
382      );
383      $(".edit-label.modal")
384        .modal({
385          onApprove: function() {
386            $(".edit-label.form").submit();
387          }
388        })
389        .modal("show");
390      return false;
391    });
392  }
393
394  // Milestones
395  if ($(".repository.milestones").length > 0) {
396  }
397  if ($(".repository.new.milestone").length > 0) {
398    var $datepicker = $(".milestone.datepicker");
399    $datepicker.datetimepicker({
400      lang: $datepicker.data("lang"),
401      inline: true,
402      timepicker: false,
403      startDate: $datepicker.data("start-date"),
404      formatDate: "Y-m-d",
405      onSelectDate: function(ct) {
406        $("#deadline").val(ct.dateFormat("Y-m-d"));
407      }
408    });
409    $("#clear-date").click(function() {
410      $("#deadline").val("");
411      return false;
412    });
413  }
414
415  // Issues
416  if ($(".repository.view.issue").length > 0) {
417    // Edit issue title
418    var $issueTitle = $("#issue-title");
419    var $editInput = $("#edit-title-input").find("input");
420    var editTitleToggle = function() {
421      $issueTitle.toggle();
422      $(".not-in-edit").toggle();
423      $("#edit-title-input").toggle();
424      $(".in-edit").toggle();
425      $editInput.focus();
426      return false;
427    };
428    $("#edit-title").click(editTitleToggle);
429    $("#cancel-edit-title").click(editTitleToggle);
430    $("#save-edit-title")
431      .click(editTitleToggle)
432      .click(function() {
433        if (
434          $editInput.val().length == 0 ||
435          $editInput.val() == $issueTitle.text()
436        ) {
437          $editInput.val($issueTitle.text());
438          return false;
439        }
440
441        $.post(
442          $(this).data("update-url"),
443          {
444            _csrf: csrf,
445            title: $editInput.val()
446          },
447          function(data) {
448            $editInput.val(data.title);
449            $issueTitle.text(data.title);
450          }
451        );
452        return false;
453      });
454
455    // Edit issue or comment content
456    $(".edit-content").click(function() {
457      var $segment = $(this)
458        .parent()
459        .parent()
460        .parent()
461        .next();
462      var $editContentZone = $segment.find(".edit-content-zone");
463      var $renderContent = $segment.find(".render-content");
464      var $rawContent = $segment.find(".raw-content");
465      var $textarea;
466
467      // Setup new form
468      if ($editContentZone.html().length == 0) {
469        $editContentZone.html($("#edit-content-form").html());
470        $textarea = $segment.find("textarea");
471
472        // Give new write/preview data-tab name to distinguish from others
473        var $editContentForm = $editContentZone.find(".ui.comment.form");
474        var $tabMenu = $editContentForm.find(".tabular.menu");
475        $tabMenu.attr("data-write", $editContentZone.data("write"));
476        $tabMenu.attr("data-preview", $editContentZone.data("preview"));
477        $tabMenu
478          .find(".write.item")
479          .attr("data-tab", $editContentZone.data("write"));
480        $tabMenu
481          .find(".preview.item")
482          .attr("data-tab", $editContentZone.data("preview"));
483        $editContentForm
484          .find(".write.segment")
485          .attr("data-tab", $editContentZone.data("write"));
486        $editContentForm
487          .find(".preview.segment")
488          .attr("data-tab", $editContentZone.data("preview"));
489
490        initCommentPreviewTab($editContentForm);
491
492        $editContentZone.find(".cancel.button").click(function() {
493          $renderContent.show();
494          $editContentZone.hide();
495        });
496        $editContentZone.find(".save.button").click(function() {
497          $renderContent.show();
498          $editContentZone.hide();
499
500          $.post(
501            $editContentZone.data("update-url"),
502            {
503              _csrf: csrf,
504              content: $textarea.val(),
505              context: $editContentZone.data("context")
506            },
507            function(data) {
508              if (data.length == 0) {
509                $renderContent.html($("#no-content").html());
510              } else {
511                $renderContent.html(data.content);
512                emojify.run($renderContent[0]);
513                $("pre code", $renderContent[0]).each(function(i, block) {
514                  hljs.highlightBlock(block);
515                });
516              }
517            }
518          );
519        });
520      } else {
521        $textarea = $segment.find("textarea");
522      }
523
524      // Show write/preview tab and copy raw content as needed
525      $editContentZone.show();
526      $renderContent.hide();
527      if ($textarea.val().length == 0) {
528        $textarea.val($rawContent.text());
529      }
530      $textarea.focus();
531      return false;
532    });
533
534    // Delete comment
535    $(".delete-comment").click(function() {
536      var $this = $(this);
537      if (confirm($this.data("locale"))) {
538        $.post($this.data("url"), {
539          _csrf: csrf
540        }).done(function() {
541          $("#" + $this.data("comment-id")).remove();
542        });
543      }
544      return false;
545    });
546
547    // Change status
548    var $statusButton = $("#status-button");
549    $("#comment-form .edit_area").keyup(function() {
550      if ($(this).val().length == 0) {
551        $statusButton.text($statusButton.data("status"));
552      } else {
553        $statusButton.text($statusButton.data("status-and-comment"));
554      }
555    });
556    $statusButton.click(function() {
557      $("#status").val($statusButton.data("status-val"));
558      $("#comment-form").submit();
559    });
560  }
561
562  // Diff
563  if ($(".repository.diff").length > 0) {
564    var $counter = $(".diff-counter");
565    if ($counter.length >= 1) {
566      $counter.each(function(i, item) {
567        var $item = $(item);
568        var addLine = $item.find("span[data-line].add").data("line");
569        var delLine = $item.find("span[data-line].del").data("line");
570        var addPercent =
571          (parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine))) *
572          100;
573        $item.find(".bar .add").css("width", addPercent + "%");
574      });
575    }
576
577    $(".diff-file-box .lines-num").click(function() {
578      if ($(this).attr("id")) {
579        window.location.href = "#" + $(this).attr("id");
580      }
581    });
582
583    $(window)
584      .on("hashchange", function(e) {
585        $(".diff-file-box .lines-code.active").removeClass("active");
586        var m = window.location.hash.match(/^#diff-.+$/);
587        if (m) {
588          $(m[0])
589            .siblings(".lines-code")
590            .addClass("active");
591        }
592      })
593      .trigger("hashchange");
594  }
595
596  // Quick start and repository home
597  $("#repo-clone-ssh").click(function() {
598    $(".clone-url").text($(this).data("link"));
599    $("#repo-clone-url").val($(this).data("link"));
600    $(this).addClass("blue");
601    $("#repo-clone-https").removeClass("blue");
602    localStorage.setItem("repo-clone-protocol", "ssh");
603  });
604  $("#repo-clone-https").click(function() {
605    $(".clone-url").text($(this).data("link"));
606    $("#repo-clone-url").val($(this).data("link"));
607    $(this).addClass("blue");
608    $("#repo-clone-ssh").removeClass("blue");
609    localStorage.setItem("repo-clone-protocol", "https");
610  });
611  $("#repo-clone-url").click(function() {
612    $(this).select();
613  });
614
615  // Pull request
616  if ($(".repository.compare.pull").length > 0) {
617    initFilterSearchDropdown(".choose.branch .dropdown");
618  }
619  if ($(".repository.view.pull").length > 0) {
620    $(".comment.merge.box input[name=merge_style]").change(function() {
621      if ($(this).val() === "create_merge_commit") {
622        $(".commit.description.field").show();
623      } else {
624        $(".commit.description.field").hide();
625      }
626    });
627  }
628}
629
630function initWikiForm() {
631  var $editArea = $(".repository.wiki textarea#edit_area");
632  if ($editArea.length > 0) {
633    new SimpleMDE({
634      autoDownloadFontAwesome: false,
635      element: $editArea[0],
636      forceSync: true,
637      previewRender: function(plainText, preview) {
638        // Async method
639        setTimeout(function() {
640          // FIXME: still send render request when return back to edit mode
641          $.post(
642            $editArea.data("url"),
643            {
644              _csrf: csrf,
645              mode: "gfm",
646              context: $editArea.data("context"),
647              text: plainText
648            },
649            function(data) {
650              preview.innerHTML = '<div class="markdown">' + data + "</div>";
651              emojify.run($(".editor-preview")[0]);
652            }
653          );
654        }, 0);
655
656        return "Loading...";
657      },
658      renderingConfig: {
659        singleLineBreaks: false
660      },
661      indentWithTabs: false,
662      tabSize: 4,
663      spellChecker: false,
664      toolbar: [
665        "bold",
666        "italic",
667        "strikethrough",
668        "|",
669        "heading-1",
670        "heading-2",
671        "heading-3",
672        "heading-bigger",
673        "heading-smaller",
674        "|",
675        "code",
676        "quote",
677        "|",
678        "unordered-list",
679        "ordered-list",
680        "|",
681        "link",
682        "image",
683        "table",
684        "horizontal-rule",
685        "|",
686        "clean-block",
687        "preview",
688        "fullscreen"
689      ]
690    });
691  }
692}
693
694var simpleMDEditor;
695var codeMirrorEditor;
696
697// For IE
698String.prototype.endsWith = function(pattern) {
699  var d = this.length - pattern.length;
700  return d >= 0 && this.lastIndexOf(pattern) === d;
701};
702
703// Adding function to get the cursor position in a text field to jQuery object.
704(function($, undefined) {
705  $.fn.getCursorPosition = function() {
706    var el = $(this).get(0);
707    var pos = 0;
708    if ("selectionStart" in el) {
709      pos = el.selectionStart;
710    } else if ("selection" in document) {
711      el.focus();
712      var Sel = document.selection.createRange();
713      var SelLength = document.selection.createRange().text.length;
714      Sel.moveStart("character", -el.value.length);
715      pos = Sel.text.length - SelLength;
716    }
717    return pos;
718  };
719})(jQuery);
720
721function setSimpleMDE($editArea) {
722  if (codeMirrorEditor) {
723    codeMirrorEditor.toTextArea();
724    codeMirrorEditor = null;
725  }
726
727  if (simpleMDEditor) {
728    return true;
729  }
730
731  simpleMDEditor = new SimpleMDE({
732    autoDownloadFontAwesome: false,
733    element: $editArea[0],
734    forceSync: true,
735    renderingConfig: {
736      singleLineBreaks: false
737    },
738    indentWithTabs: false,
739    tabSize: 4,
740    spellChecker: false,
741    previewRender: function(plainText, preview) {
742      // Async method
743      setTimeout(function() {
744        // FIXME: still send render request when return back to edit mode
745        $.post(
746          $editArea.data("url"),
747          {
748            _csrf: csrf,
749            mode: "gfm",
750            context: $editArea.data("context"),
751            text: plainText
752          },
753          function(data) {
754            preview.innerHTML = '<div class="markdown">' + data + "</div>";
755            emojify.run($(".editor-preview")[0]);
756          }
757        );
758      }, 0);
759
760      return "Loading...";
761    },
762    toolbar: [
763      "bold",
764      "italic",
765      "strikethrough",
766      "|",
767      "heading-1",
768      "heading-2",
769      "heading-3",
770      "heading-bigger",
771      "heading-smaller",
772      "|",
773      "code",
774      "quote",
775      "|",
776      "unordered-list",
777      "ordered-list",
778      "|",
779      "link",
780      "image",
781      "table",
782      "horizontal-rule",
783      "|",
784      "clean-block"
785    ]
786  });
787
788  return true;
789}
790
791function setCodeMirror($editArea) {
792  if (simpleMDEditor) {
793    simpleMDEditor.toTextArea();
794    simpleMDEditor = null;
795  }
796
797  if (codeMirrorEditor) {
798    return true;
799  }
800
801  codeMirrorEditor = CodeMirror.fromTextArea($editArea[0], {
802    lineNumbers: true
803  });
804  codeMirrorEditor.on("change", function(cm, change) {
805    $editArea.val(cm.getValue());
806  });
807
808  return true;
809}
810
811function initEditor() {
812  $(".js-quick-pull-choice-option").change(function() {
813    if ($(this).val() == "commit-to-new-branch") {
814      $(".quick-pull-branch-name").show();
815      $(".quick-pull-branch-name input").prop("required", true);
816    } else {
817      $(".quick-pull-branch-name").hide();
818      $(".quick-pull-branch-name input").prop("required", false);
819    }
820  });
821
822  var $editFilename = $("#file-name");
823  $editFilename
824    .keyup(function(e) {
825      var $section = $(".breadcrumb span.section");
826      var $divider = $(".breadcrumb div.divider");
827      if (e.keyCode == 8) {
828        if ($(this).getCursorPosition() == 0) {
829          if ($section.length > 0) {
830            var value = $section
831              .last()
832              .find("a")
833              .text();
834            $(this).val(value + $(this).val());
835            $(this)[0].setSelectionRange(value.length, value.length);
836            $section.last().remove();
837            $divider.last().remove();
838          }
839        }
840      }
841      if (e.keyCode == 191) {
842        var parts = $(this)
843          .val()
844          .split("/");
845        for (var i = 0; i < parts.length; ++i) {
846          var value = parts[i];
847          if (i < parts.length - 1) {
848            if (value.length) {
849              $(
850                '<span class="section"><a href="#">' + value + "</a></span>"
851              ).insertBefore($(this));
852              $('<div class="divider"> / </div>').insertBefore($(this));
853            }
854          } else {
855            $(this).val(value);
856          }
857          $(this)[0].setSelectionRange(0, 0);
858        }
859      }
860      var parts = [];
861      $(".breadcrumb span.section").each(function(i, element) {
862        element = $(element);
863        if (element.find("a").length) {
864          parts.push(element.find("a").text());
865        } else {
866          parts.push(element.text());
867        }
868      });
869      if ($(this).val()) {
870        parts.push($(this).val());
871      }
872
873      var tree_path = parts.join("/");
874      $("#tree_path").val(tree_path);
875      $("#preview-tab").data(
876        "context",
877        $("#preview-tab").data("root-context") +
878          tree_path.substring(0, tree_path.lastIndexOf("/") + 1)
879      );
880    })
881    .trigger("keyup");
882
883  var $editArea = $(".repository.editor textarea#edit_area");
884  if (!$editArea.length) return;
885
886  var markdownFileExts = $editArea.data("markdown-file-exts").split(",");
887  var lineWrapExtensions = $editArea.data("line-wrap-extensions").split(",");
888
889  $editFilename
890    .on("keyup", function(e) {
891      var val = $editFilename.val(),
892        m,
893        mode,
894        spec,
895        extension,
896        extWithDot,
897        previewLink,
898        dataUrl,
899        apiCall;
900      extension = extWithDot = "";
901      if ((m = /.+\.([^.]+)$/.exec(val))) {
902        extension = m[1].toLowerCase();
903        extWithDot = "." + extension;
904      }
905
906      var info = CodeMirror.findModeByExtension(extension);
907      previewLink = $("a[data-tab=preview]");
908      if (info) {
909        mode = info.mode;
910        spec = info.mime;
911        apiCall = mode;
912      } else {
913        apiCall = extension;
914      }
915
916      if (
917        previewLink.length &&
918        apiCall &&
919        previewFileModes &&
920        previewFileModes.length &&
921        previewFileModes.indexOf(apiCall) >= 0
922      ) {
923        dataUrl = previewLink.data("url");
924        previewLink.data("url", dataUrl.replace(/(.*)\/.*/i, "$1/" + mode));
925        previewLink.show();
926      } else {
927        previewLink.hide();
928      }
929
930      // If this file is a Markdown extensions, we will load that editor and return
931      if (markdownFileExts.indexOf(extWithDot) >= 0) {
932        if (setSimpleMDE($editArea)) {
933          return;
934        }
935      }
936
937      // Else we are going to use CodeMirror
938      if (!codeMirrorEditor && !setCodeMirror($editArea)) {
939        return;
940      }
941
942      if (mode) {
943        codeMirrorEditor.setOption("mode", spec);
944        CodeMirror.autoLoadMode(codeMirrorEditor, mode);
945      }
946
947      if (lineWrapExtensions.indexOf(extWithDot) >= 0) {
948        codeMirrorEditor.setOption("lineWrapping", true);
949      } else {
950        codeMirrorEditor.setOption("lineWrapping", false);
951      }
952
953      // get the filename without any folder
954      var value = $editFilename.val();
955      if (value.length === 0) {
956        return;
957      }
958      value = value.split("/");
959      value = value[value.length - 1];
960
961      $.getJSON($editFilename.data("ec-url-prefix") + value, function(
962        editorconfig
963      ) {
964        if (editorconfig.indent_style === "tab") {
965          codeMirrorEditor.setOption("indentWithTabs", true);
966          codeMirrorEditor.setOption("extraKeys", {});
967        } else {
968          codeMirrorEditor.setOption("indentWithTabs", false);
969          // required because CodeMirror doesn't seems to use spaces correctly for {"indentWithTabs": false}:
970          // - https://github.com/codemirror/CodeMirror/issues/988
971          // - https://codemirror.net/doc/manual.html#keymaps
972          codeMirrorEditor.setOption("extraKeys", {
973            Tab: function(cm) {
974              var spaces = Array(parseInt(cm.getOption("indentUnit")) + 1).join(
975                " "
976              );
977              cm.replaceSelection(spaces);
978            }
979          });
980        }
981        codeMirrorEditor.setOption("indentUnit", editorconfig.indent_size || 4);
982        codeMirrorEditor.setOption("tabSize", editorconfig.tab_width || 4);
983      });
984    })
985    .trigger("keyup");
986}
987
988function initOrganization() {
989  if ($(".organization").length == 0) {
990    return;
991  }
992
993  // Options
994  if ($(".organization.settings.options").length > 0) {
995    $("#org_name").keyup(function() {
996      var $prompt = $("#org-name-change-prompt");
997      if (
998        $(this)
999          .val()
1000          .toString()
1001          .toLowerCase() !=
1002        $(this)
1003          .data("org-name")
1004          .toString()
1005          .toLowerCase()
1006      ) {
1007        $prompt.show();
1008      } else {
1009        $prompt.hide();
1010      }
1011    });
1012  }
1013}
1014
1015function initAdmin() {
1016  if ($(".admin").length == 0) {
1017    return;
1018  }
1019
1020  // New user
1021  if ($(".admin.new.user").length > 0 || $(".admin.edit.user").length > 0) {
1022    $("#login_type").change(function() {
1023      if (
1024        $(this)
1025          .val()
1026          .substring(0, 1) == "0"
1027      ) {
1028        $("#login_name").removeAttr("required");
1029        $(".non-local").hide();
1030        $(".local").show();
1031        $("#user_name").focus();
1032
1033        if ($(this).data("password") == "required") {
1034          $("#password").attr("required", "required");
1035        }
1036      } else {
1037        $("#login_name").attr("required", "required");
1038        $(".non-local").show();
1039        $(".local").hide();
1040        $("#login_name").focus();
1041
1042        $("#password").removeAttr("required");
1043      }
1044    });
1045  }
1046
1047  function onSecurityProtocolChange() {
1048    if ($("#security_protocol").val() > 0) {
1049      $(".has-tls").show();
1050    } else {
1051      $(".has-tls").hide();
1052    }
1053  }
1054
1055  // New authentication
1056  if ($(".admin.new.authentication").length > 0) {
1057    $("#auth_type").change(function() {
1058      $(".ldap").hide();
1059      $(".dldap").hide();
1060      $(".smtp").hide();
1061      $(".pam").hide();
1062      $(".github").hide();
1063      $(".has-tls").hide();
1064
1065      var authType = $(this).val();
1066      switch (authType) {
1067        case "2": // LDAP
1068          $(".ldap").show();
1069          break;
1070        case "3": // SMTP
1071          $(".smtp").show();
1072          $(".has-tls").show();
1073          break;
1074        case "4": // PAM
1075          $(".pam").show();
1076          break;
1077        case "5": // LDAP
1078          $(".dldap").show();
1079          break;
1080        case "6": //GITHUB
1081          $(".github").show();
1082          $(".has-tls").show();
1083          break;
1084      }
1085
1086      if (authType == "2" || authType == "5") {
1087        onSecurityProtocolChange();
1088      }
1089    });
1090    $("#security_protocol").change(onSecurityProtocolChange);
1091  }
1092  // Edit authentication
1093  if ($(".admin.edit.authentication").length > 0) {
1094    var authType = $("#auth_type").val();
1095    if (authType == "2" || authType == "5") {
1096      $("#security_protocol").change(onSecurityProtocolChange);
1097    }
1098  }
1099
1100  // Notice
1101  if ($(".admin.notice")) {
1102    var $detailModal = $("#detail-modal");
1103
1104    // Attach view detail modals
1105    $(".view-detail").click(function() {
1106      $detailModal.find(".content p").text($(this).data("content"));
1107      $detailModal.modal("show");
1108      return false;
1109    });
1110
1111    // Select actions
1112    var $checkboxes = $(".select.table .ui.checkbox");
1113    $(".select.action").click(function() {
1114      switch ($(this).data("action")) {
1115        case "select-all":
1116          $checkboxes.checkbox("check");
1117          break;
1118        case "deselect-all":
1119          $checkboxes.checkbox("uncheck");
1120          break;
1121        case "inverse":
1122          $checkboxes.checkbox("toggle");
1123          break;
1124      }
1125    });
1126    $("#delete-selection").click(function() {
1127      var $this = $(this);
1128      $this.addClass("loading disabled");
1129      var ids = [];
1130      $checkboxes.each(function() {
1131        if ($(this).checkbox("is checked")) {
1132          ids.push($(this).data("id"));
1133        }
1134      });
1135      $.post($this.data("link"), {
1136        _csrf: csrf,
1137        ids: ids
1138      }).done(function() {
1139        window.location.href = $this.data("redirect");
1140      });
1141    });
1142  }
1143}
1144
1145function buttonsClickOnEnter() {
1146  $(".ui.button").keypress(function(e) {
1147    if (e.keyCode == 13 || e.keyCode == 32)
1148      // enter key or space bar
1149      $(this).click();
1150  });
1151}
1152
1153function hideWhenLostFocus(body, parent) {
1154  $(document).click(function(e) {
1155    var target = e.target;
1156    if (
1157      !$(target).is(body) &&
1158      !$(target)
1159        .parents()
1160        .is(parent)
1161    ) {
1162      $(body).hide();
1163    }
1164  });
1165}
1166
1167function searchUsers() {
1168  if (!$("#search-user-box .results").length) {
1169    return;
1170  }
1171
1172  var $searchUserBox = $("#search-user-box");
1173  var $results = $searchUserBox.find(".results");
1174  $searchUserBox.keyup(function() {
1175    var $this = $(this);
1176    var keyword = $this.find("input").val();
1177    if (keyword.length < 2) {
1178      $results.hide();
1179      return;
1180    }
1181
1182    $.ajax({
1183      url: suburl + "/api/v1/users/search?q=" + keyword,
1184      dataType: "json",
1185      success: function(response) {
1186        var notEmpty = function(str) {
1187          return str && str.length > 0;
1188        };
1189
1190        $results.html("");
1191
1192        if (response.ok && response.data.length) {
1193          var html = "";
1194          $.each(response.data, function(i, item) {
1195            html +=
1196              '<div class="item"><img class="ui avatar image" src="' +
1197              item.avatar_url +
1198              '"><span class="username">' +
1199              item.username +
1200              "</span>";
1201            if (notEmpty(item.full_name)) {
1202              html += " (" + item.full_name + ")";
1203            }
1204            html += "</div>";
1205          });
1206          $results.html(html);
1207          $this.find(".results .item").click(function() {
1208            $this.find("input").val(
1209              $(this)
1210                .find(".username")
1211                .text()
1212            );
1213            $results.hide();
1214          });
1215          $results.show();
1216        } else {
1217          $results.hide();
1218        }
1219      }
1220    });
1221  });
1222  $searchUserBox.find("input").focus(function() {
1223    $searchUserBox.keyup();
1224  });
1225  hideWhenLostFocus("#search-user-box .results", "#search-user-box");
1226}
1227
1228// FIXME: merge common parts in two functions
1229function searchRepositories() {
1230  if (!$("#search-repo-box .results").length) {
1231    return;
1232  }
1233
1234  var $searchRepoBox = $("#search-repo-box");
1235  var $results = $searchRepoBox.find(".results");
1236  $searchRepoBox.keyup(function() {
1237    var $this = $(this);
1238    var keyword = $this.find("input").val();
1239    if (keyword.length < 2) {
1240      $results.hide();
1241      return;
1242    }
1243
1244    $.ajax({
1245      url:
1246        suburl +
1247        "/api/v1/repos/search?q=" +
1248        keyword +
1249        "&uid=" +
1250        $searchRepoBox.data("uid"),
1251      dataType: "json",
1252      success: function(response) {
1253        var notEmpty = function(str) {
1254          return str && str.length > 0;
1255        };
1256
1257        $results.html("");
1258
1259        if (response.ok && response.data.length) {
1260          var html = "";
1261          $.each(response.data, function(i, item) {
1262            html +=
1263              '<div class="item"><i class="octicon octicon-repo"></i> <span class="fullname">' +
1264              item.full_name +
1265              "</span></div>";
1266          });
1267          $results.html(html);
1268          $this.find(".results .item").click(function() {
1269            $this.find("input").val(
1270              $(this)
1271                .find(".fullname")
1272                .text()
1273                .split("/")[1]
1274            );
1275            $results.hide();
1276          });
1277          $results.show();
1278        } else {
1279          $results.hide();
1280        }
1281      }
1282    });
1283  });
1284  $searchRepoBox.find("input").focus(function() {
1285    $searchRepoBox.keyup();
1286  });
1287  hideWhenLostFocus("#search-repo-box .results", "#search-repo-box");
1288}
1289
1290function initCodeView() {
1291  if ($(".code-view .linenums").length > 0) {
1292    $(document).on("click", ".lines-num span", function(e) {
1293      var $select = $(this);
1294      var $list = $select
1295        .parent()
1296        .siblings(".lines-code")
1297        .find("ol.linenums > li");
1298      selectRange(
1299        $list,
1300        $list.filter("[rel=" + $select.attr("id") + "]"),
1301        e.shiftKey ? $list.filter(".active").eq(0) : null
1302      );
1303      deSelect();
1304    });
1305
1306    $(window)
1307      .on("hashchange", function(e) {
1308        var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/);
1309        var $list = $(".code-view ol.linenums > li");
1310        var $first;
1311        if (m) {
1312          $first = $list.filter("." + m[1]);
1313          selectRange($list, $first, $list.filter("." + m[2]));
1314          $("html, body").scrollTop($first.offset().top - 200);
1315          return;
1316        }
1317        m = window.location.hash.match(/^#(L\d+)$/);
1318        if (m) {
1319          $first = $list.filter("." + m[1]);
1320          selectRange($list, $first);
1321          $("html, body").scrollTop($first.offset().top - 200);
1322        }
1323      })
1324      .trigger("hashchange");
1325  }
1326}
1327
1328function initUserSettings() {
1329  console.log("initUserSettings");
1330
1331  // Options
1332  if ($(".user.settings.profile").length > 0) {
1333    $("#username").keyup(function() {
1334      var $prompt = $("#name-change-prompt");
1335      if (
1336        $(this)
1337          .val()
1338          .toString()
1339          .toLowerCase() !=
1340        $(this)
1341          .data("name")
1342          .toString()
1343          .toLowerCase()
1344      ) {
1345        $prompt.show();
1346      } else {
1347        $prompt.hide();
1348      }
1349    });
1350  }
1351}
1352
1353function initRepositoryCollaboration() {
1354  console.log("initRepositoryCollaboration");
1355
1356  // Change collaborator access mode
1357  $(".access-mode.menu .item").click(function() {
1358    var $menu = $(this).parent();
1359    $.post($menu.data("url"), {
1360      _csrf: csrf,
1361      uid: $menu.data("uid"),
1362      mode: $(this).data("value")
1363    });
1364  });
1365}
1366
1367function initWebhookSettings() {
1368  $(".events.checkbox input").change(function() {
1369    if ($(this).is(":checked")) {
1370      $(".events.fields").show();
1371    }
1372  });
1373  $(".non-events.checkbox input").change(function() {
1374    if ($(this).is(":checked")) {
1375      $(".events.fields").hide();
1376    }
1377  });
1378
1379  // Highlight payload on first click
1380  $(".hook.history.list .toggle.button").click(function() {
1381    $($(this).data("target") + " .nohighlight").each(function() {
1382      var $this = $(this);
1383      $this.removeClass("nohighlight");
1384      setTimeout(function() {
1385        hljs.highlightBlock($this[0]);
1386      }, 500);
1387    });
1388  });
1389
1390  // Trigger delivery
1391  $(".delivery.button, .redelivery.button").click(function() {
1392    var $this = $(this);
1393    $this.addClass("loading disabled");
1394    $.post($this.data("link"), {
1395      _csrf: csrf
1396    }).done(
1397      setTimeout(function() {
1398        window.location.href = $this.data("redirect");
1399      }, 5000)
1400    );
1401  });
1402}
1403
1404$(document).ready(function() {
1405  csrf = $("meta[name=_csrf]").attr("content");
1406  suburl = $("meta[name=_suburl]").attr("content");
1407
1408  // Set cursor to the end of autofocus input string
1409  $("input[autofocus]").each(function() {
1410    $(this).val($(this).val());
1411  });
1412
1413  // Show exact time
1414  $(".time-since").each(function() {
1415    $(this)
1416      .addClass("poping up")
1417      .attr("data-content", $(this).attr("title"))
1418      .attr("data-variation", "inverted tiny")
1419      .attr("title", "");
1420  });
1421
1422  // Semantic UI modules.
1423  $(".ui.dropdown").dropdown({
1424    forceSelection: false
1425  });
1426  $(".jump.dropdown").dropdown({
1427    action: "select",
1428    onShow: function() {
1429      $(".poping.up").popup("hide");
1430    }
1431  });
1432  $(".slide.up.dropdown").dropdown({
1433    transition: "slide up"
1434  });
1435  $(".upward.dropdown").dropdown({
1436    direction: "upward"
1437  });
1438  $(".ui.accordion").accordion();
1439  $(".ui.checkbox").checkbox();
1440  $(".ui.progress").progress({
1441    showActivity: false
1442  });
1443  $(".poping.up").popup();
1444  $(".top.menu .poping.up").popup({
1445    onShow: function() {
1446      if ($(".top.menu .menu.transition").hasClass("visible")) {
1447        return false;
1448      }
1449    }
1450  });
1451  $(".tabular.menu .item").tab();
1452  $(".tabable.menu .item").tab();
1453
1454  $(".toggle.button").click(function() {
1455    $($(this).data("target")).slideToggle(100);
1456  });
1457
1458  // Dropzone
1459  var $dropzone = $("#dropzone");
1460  if ($dropzone.length > 0) {
1461    var filenameDict = {};
1462    $dropzone.dropzone({
1463      url: $dropzone.data("upload-url"),
1464      headers: { "X-CSRF-Token": csrf },
1465      maxFiles: $dropzone.data("max-file"),
1466      maxFilesize: $dropzone.data("max-size"),
1467      timeout: 0,
1468      acceptedFiles:
1469        $dropzone.data("accepts") === "*/*" ? null : $dropzone.data("accepts"),
1470      addRemoveLinks: true,
1471      dictDefaultMessage: $dropzone.data("default-message"),
1472      dictInvalidFileType: $dropzone.data("invalid-input-type"),
1473      dictFileTooBig: $dropzone.data("file-too-big"),
1474      dictRemoveFile: $dropzone.data("remove-file"),
1475      init: function() {
1476        this.on("success", function(file, data) {
1477          filenameDict[file.name] = data.uuid;
1478          var input = $(
1479            '<input id="' + data.uuid + '" name="files" type="hidden">'
1480          ).val(data.uuid);
1481          $(".files").append(input);
1482        });
1483        this.on("removedfile", function(file) {
1484          if (file.name in filenameDict) {
1485            $("#" + filenameDict[file.name]).remove();
1486          }
1487          if ($dropzone.data("remove-url") && $dropzone.data("csrf")) {
1488            $.post($dropzone.data("remove-url"), {
1489              file: filenameDict[file.name],
1490              _csrf: $dropzone.data("csrf")
1491            });
1492          }
1493        });
1494      }
1495    });
1496  }
1497
1498  // Emojify
1499  emojify.setConfig({
1500    img_dir: suburl + "/img/emoji",
1501    ignore_emoticons: true
1502  });
1503  var hasEmoji = document.getElementsByClassName("has-emoji");
1504  for (var i = 0; i < hasEmoji.length; i++) {
1505    emojify.run(hasEmoji[i]);
1506  }
1507
1508  // Clipboard JS
1509  var clipboard = new ClipboardJS(".clipboard");
1510  clipboard.on("success", function(e) {
1511    e.clearSelection();
1512
1513    $("#" + e.trigger.getAttribute("id")).popup("destroy");
1514    e.trigger.setAttribute(
1515      "data-content",
1516      e.trigger.getAttribute("data-success")
1517    );
1518    $("#" + e.trigger.getAttribute("id")).popup("show");
1519    e.trigger.setAttribute(
1520      "data-content",
1521      e.trigger.getAttribute("data-original")
1522    );
1523  });
1524
1525  clipboard.on("error", function(e) {
1526    $("#" + e.trigger.getAttribute("id")).popup("destroy");
1527    e.trigger.setAttribute(
1528      "data-content",
1529      e.trigger.getAttribute("data-error")
1530    );
1531    $("#" + e.trigger.getAttribute("id")).popup("show");
1532    e.trigger.setAttribute(
1533      "data-content",
1534      e.trigger.getAttribute("data-original")
1535    );
1536  });
1537
1538  // Autosize
1539  if ($("#description.autosize").length > 0) {
1540    autosize($("#description"));
1541    showMessageMaxLength(512, "description", "descLength");
1542  }
1543
1544  // AJAX load buttons
1545  $(".ajax-load-button").click(function() {
1546    var $this = $(this);
1547    $this.addClass("disabled");
1548
1549    $.ajax({
1550      url: $this.data("url"),
1551      headers: {
1552        "X-AJAX": "true"
1553      }
1554    }).done(function(data, status, request) {
1555      $(data).insertBefore($this);
1556
1557      // Update new URL or remove self if no more feeds
1558      var url = request.getResponseHeader("X-AJAX-URL");
1559      if (url) {
1560        $this.data("url", url);
1561        $this.removeClass("disabled");
1562      } else {
1563        $this.remove();
1564      }
1565    });
1566  });
1567
1568  // Helpers
1569  $(".delete-button").click(function() {
1570    var $this = $(this);
1571    $(".delete.modal")
1572      .modal({
1573        closable: false,
1574        onApprove: function() {
1575          if ($this.data("type") == "form") {
1576            $($this.data("form")).submit();
1577            return;
1578          }
1579
1580          $.post($this.data("url"), {
1581            _csrf: csrf,
1582            id: $this.data("id")
1583          }).done(function(data) {
1584            window.location.href = data.redirect;
1585          });
1586        }
1587      })
1588      .modal("show");
1589    return false;
1590  });
1591  $(".show-panel.button").click(function() {
1592    $($(this).data("panel")).show();
1593  });
1594  $(".show-modal.button").click(function() {
1595    $($(this).data("modal")).modal("show");
1596  });
1597  $(".delete-post.button").click(function() {
1598    var $this = $(this);
1599    $.post($this.data("request-url"), {
1600      _csrf: csrf
1601    }).done(function() {
1602      window.location.href = $this.data("done-url");
1603    });
1604  });
1605  // To make arbitrary form element to behave like a submit button
1606  $(".submit-button").click(function() {
1607    $($(this).data("form")).submit();
1608  });
1609
1610  // Check or select on option to enable/disable target region
1611  $(".enable-system").change(function() {
1612    if (this.checked) {
1613      $($(this).data("target")).removeClass("disabled");
1614    } else {
1615      $($(this).data("target")).addClass("disabled");
1616      $($(this).data("uncheck")).prop("checked", false);
1617    }
1618  });
1619  $(".enable-system-radio").change(function() {
1620    $($(this).data("enable")).removeClass("disabled");
1621    $($(this).data("disable")).addClass("disabled");
1622    $($(this).data("uncheck")).prop("checked", false);
1623  });
1624
1625  // Set anchor.
1626  $(".markdown").each(function() {
1627    var headers = {};
1628    $(this)
1629      .find("h1, h2, h3, h4, h5, h6")
1630      .each(function() {
1631        var node = $(this);
1632        var val = encodeURIComponent(
1633          node
1634            .text()
1635            .toLowerCase()
1636            .replace(/[^\u00C0-\u1FFF\u2C00-\uD7FF\w\- ]/g, "")
1637            .replace(/[ ]/g, "-")
1638        );
1639        var name = val;
1640        if (headers[val] > 0) {
1641          name = val + "-" + headers[val];
1642        }
1643        if (headers[val] == undefined) {
1644          headers[val] = 1;
1645        } else {
1646          headers[val] += 1;
1647        }
1648        node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>');
1649        node.append(
1650          '<a class="anchor" href="#' +
1651            name +
1652            '"><span class="octicon octicon-link"></span></a>'
1653        );
1654      });
1655  });
1656
1657  buttonsClickOnEnter();
1658  searchUsers();
1659  searchRepositories();
1660
1661  initCommentForm();
1662  initRepository();
1663  initWikiForm();
1664  initEditForm();
1665  initEditor();
1666  initOrganization();
1667  initAdmin();
1668  initCodeView();
1669
1670  // Repo clone url.
1671  if ($("#repo-clone-url").length > 0) {
1672    switch (localStorage.getItem("repo-clone-protocol")) {
1673      case "ssh":
1674        if ($("#repo-clone-ssh").click().length === 0) {
1675          $("#repo-clone-https").click();
1676        }
1677        break;
1678      default:
1679        $("#repo-clone-https").click();
1680        break;
1681    }
1682  }
1683
1684  var routes = {
1685    "div.user.settings": initUserSettings,
1686    "div.repository.settings.collaboration": initRepositoryCollaboration,
1687    "div.webhook.settings": initWebhookSettings
1688  };
1689
1690  var selector;
1691  for (selector in routes) {
1692    if ($(selector).length > 0) {
1693      routes[selector]();
1694      break;
1695    }
1696  }
1697});
1698
1699function changeHash(hash) {
1700  if (history.pushState) {
1701    history.pushState(null, null, hash);
1702  } else {
1703    location.hash = hash;
1704  }
1705}
1706
1707function deSelect() {
1708  if (window.getSelection) {
1709    window.getSelection().removeAllRanges();
1710  } else {
1711    document.selection.empty();
1712  }
1713}
1714
1715function selectRange($list, $select, $from) {
1716  $list.removeClass("active");
1717  if ($from) {
1718    var a = parseInt($select.attr("rel").substr(1));
1719    var b = parseInt($from.attr("rel").substr(1));
1720    var c;
1721    if (a != b) {
1722      if (a > b) {
1723        c = a;
1724        a = b;
1725        b = c;
1726      }
1727      var classes = [];
1728      for (var i = a; i <= b; i++) {
1729        classes.push(".L" + i);
1730      }
1731      $list.filter(classes.join(",")).addClass("active");
1732      changeHash("#L" + a + "-" + "L" + b);
1733      return;
1734    }
1735  }
1736  $select.addClass("active");
1737  changeHash("#" + $select.attr("rel"));
1738}
1739
1740$(function() {
1741  if ($(".user.signin").length > 0) return;
1742  $("form").areYouSure();
1743});
1744
1745// getByteLen counts bytes in a string's UTF-8 representation.
1746function getByteLen(normalVal) {
1747  // Force string type
1748  normalVal = String(normalVal);
1749
1750  var byteLen = 0;
1751  for (var i = 0; i < normalVal.length; i++) {
1752    var c = normalVal.charCodeAt(i);
1753    byteLen +=
1754      c < 1 << 7
1755        ? 1
1756        : c < 1 << 11
1757        ? 2
1758        : c < 1 << 16
1759        ? 3
1760        : c < 1 << 21
1761        ? 4
1762        : c < 1 << 26
1763        ? 5
1764        : c < 1 << 31
1765        ? 6
1766        : Number.NaN;
1767  }
1768  return byteLen;
1769}
1770
1771function showMessageMaxLength(maxLen, textElemId, counterId) {
1772  var $msg = $("#" + textElemId);
1773  $("#" + counterId).html(maxLen - getByteLen($msg.val()));
1774
1775  var onMessageKey = function(e) {
1776    var $msg = $(this);
1777    var text = $msg.val();
1778    var len = getByteLen(text);
1779    var remainder = maxLen - len;
1780
1781    if (len >= maxLen) {
1782      $msg.val($msg.val().substr(0, maxLen));
1783      remainder = 0;
1784    }
1785
1786    $("#" + counterId).html(remainder);
1787  };
1788
1789  $msg.keyup(onMessageKey).keydown(onMessageKey);
1790}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.