summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/extensions/extension_code.js
blob: c22376b834dfb5f709087e369c918664e917c56f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('extensions', function() {
  'use strict';

  /**
   * ExtensionCode is an element which displays code in a styled div, and is
   * designed to highlight errors.
   */
  function ExtensionCode(div) {
    div.__proto__ = ExtensionCode.prototype;
    return div;
  }

  ExtensionCode.prototype = {
    __proto__: HTMLDivElement.prototype,

    /**
     * Populate the content area of the code div with the given code. This will
     * highlight the erroneous section (if any).
     * @param {Object} code An object with four strings: beforeHighlight,
     *     afterHighlight, highlight, and the message. The 'highlight' strings
     *     represent the three portions of the file's content to display - the
     *     portion which is most relevant and should be emphasized (highlight),
     *     and the parts both before and after this portion. The message is the
     *     error message, which will be the mouseover hint for the highlighted
     *     region. These may be empty.
     *  @param {string} emptyMessage The message to display if the code
     *     object is empty (e.g., 'could not load code').
     */
    populate: function(code, emptyMessage) {
      // Clear any remnant content, so we don't have multiple code listed.
      this.clear();

      var sourceDiv = document.createElement('div');
      sourceDiv.classList.add('extension-code-source');
      this.appendChild(sourceDiv);

      // If there's no code, then display an appropriate message.
      if (!code ||
          (!code.highlight && !code.beforeHighlight && !code.afterHighlight)) {
        var span = document.createElement('span');
        span.textContent = emptyMessage;
        sourceDiv.appendChild(span);
        return;
      }

      var lineCount = 0;
      var createSpan = function(source, isHighlighted) {
        lineCount += source.split('\n').length - 1;
        var span = document.createElement('span');
        span.className = isHighlighted ? 'extension-code-highlighted-source' :
                                         'extension-code-normal-source';
        span.textContent = source;
        return span;
      };

      if (code.beforeHighlight)
        sourceDiv.appendChild(createSpan(code.beforeHighlight, false));

      if (code.highlight) {
        var highlightSpan = createSpan(code.highlight, true);
        highlightSpan.title = code.message;
        sourceDiv.appendChild(highlightSpan);
      }

      if (code.afterHighlight)
        sourceDiv.appendChild(createSpan(code.afterHighlight, false));

      // Make the line numbers. This should be the number of line breaks + 1
      // (the last line doesn't break, but should still be numbered).
      var content = '';
      for (var i = 1; i < lineCount + 1; ++i)
        content += i + '\n';
      var span = document.createElement('span');
      span.textContent = content;

      var linesDiv = document.createElement('div');
      linesDiv.classList.add('extension-code-line-numbers');
      linesDiv.appendChild(span);
      this.insertBefore(linesDiv, this.firstChild);
    },

    /**
     * Clears the content of the element.
     */
    clear: function() {
      while (this.firstChild)
        this.removeChild(this.firstChild);
    },

    /**
     * Scrolls to the error, if there is one. This cannot be called when the
     * div is hidden.
     */
    scrollToError: function() {
      var errorSpan = this.querySelector('.extension-code-highlighted-source');
      if (errorSpan)
        this.scrollTop = errorSpan.offsetTop - this.clientHeight / 2;
    }
  };

  // Export
  return {
    ExtensionCode: ExtensionCode
  };
});