blob: aa106d3ab0f3412e64aded66db9156f61d62feeb [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5var CodeView = function(divID, PR, sourceText, sourcePosition, broker) {
6 "use strict";
7 var view = this;
8
9 view.divElement = document.getElementById(divID);
10 view.broker = broker;
11 view.codeSelection = null;
12 view.allSpans = [];
13
14 var selectionHandler = {
15 clear: function() {
16 broker.clear(selectionHandler);
17 },
18 select: function(items, selected) {
19 var handler = this;
20 var divElement = view.divElement;
21 var broker = view.broker;
22 for (let span of items) {
23 if (selected) {
24 span.classList.add("selected");
25 } else {
26 span.classList.remove("selected");
27 }
28 }
29 var ranges = [];
30 for (var span of items) {
31 ranges.push([span.start, span.end, null]);
32 }
33 broker.select(selectionHandler, ranges, selected);
34 },
35 selectionDifference: function(span1, inclusive1, span2, inclusive2) {
36 var pos1 = span1.start;
37 var pos2 = span2.start;
38 var result = [];
39 var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
40 for (var i=0; i < lineListDiv.length; i++) {
41 var currentLineElement = lineListDiv[i];
42 var spans = currentLineElement.childNodes;
43 for (var j=0; j < spans.length; ++j) {
44 var currentSpan = spans[j];
45 if (currentSpan.start > pos1 || (inclusive1 && currentSpan.start == pos1)) {
46 if (currentSpan.start < pos2 || (inclusive2 && currentSpan.start == pos2)) {
47 result.push(currentSpan);
48 }
49 }
50 }
51 }
52 return result;
53 },
54 brokeredSelect: function(ranges, selected) {
55 var firstSelect = view.codeSelection.isEmpty();
56 for (var range of ranges) {
57 var start = range[0];
58 var end = range[1];
59 var lower = 0;
60 var upper = view.allSpans.length;
61 if (upper > 0) {
62 while ((upper - lower) > 1) {
63 var middle = Math.floor((upper + lower) / 2);
64 var lineStart = view.allSpans[middle].start;
65 if (lineStart < start) {
66 lower = middle;
67 } else if (lineStart > start) {
68 upper = middle;
69 } else {
70 lower = middle;
71 break;
72 }
73 }
74 var currentSpan = view.allSpans[lower];
75 var currentLineElement = currentSpan.parentNode;
76 if ((currentSpan.start <= start && start < currentSpan.end) ||
77 (currentSpan.start <= end && end < currentSpan.end)) {
78 if (firstSelect) {
79 makeContainerPosVisible(view.divElement, currentLineElement.offsetTop);
80 firstSelect = false;
81 }
82 view.codeSelection.select(currentSpan, selected);
83 }
84 }
85 }
86 },
87 brokeredClear: function() {
88 view.codeSelection.clear();
89 },
90 };
91
92 view.codeSelection = new Selection(selectionHandler);
93 broker.addSelectionHandler(selectionHandler);
94
95 var mouseDown = false;
96
97 this.handleSpanMouseDown = function(e) {
98 e.stopPropagation();
99 if (!e.shiftKey) {
100 view.codeSelection.clear();
101 }
102 view.codeSelection.select(this, true);
103 mouseDown = true;
104 }
105
106 this.handleSpanMouseMove = function(e) {
107 if (mouseDown) {
108 view.codeSelection.extendTo(this);
109 }
110 }
111
112 this.handleCodeMouseDown = function(e) {
113 view.codeSelection.clear();
114 }
115
116 document.addEventListener('mouseup', function(e){
117 mouseDown = false;
118 }, false);
119
120 this.initializeCode(sourceText, sourcePosition);
121}
122
123CodeView.prototype.initializeCode = function(sourceText, sourcePosition) {
124 var view = this;
125 if (sourceText == "") {
126 var newHtml = "<pre class=\"prettyprint\"</pre>";
127 view.divElement.innerHTML = newHtml;
128 } else {
129 var newHtml = "<pre class=\"prettyprint linenums\">"
130 + sourceText + "</pre>";
131 view.divElement.innerHTML = newHtml;
132 try {
133 // Wrap in try to work when offline.
134 PR.prettyPrint();
135 } catch (e) {
136 }
137
138 view.divElement.onmousedown = this.handleCodeMouseDown;
139
140 var base = sourcePosition;
141 var current = 0;
142 var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
143 for (i=0; i < lineListDiv.length; i++) {
144 var currentLineElement = lineListDiv[i];
145 currentLineElement.id = "li" + i;
146 var pos = base + current;
147 currentLineElement.pos = pos;
148 var spans = currentLineElement.childNodes;
149 for (j=0; j < spans.length; ++j) {
150 var currentSpan = spans[j];
151 if (currentSpan.nodeType == 1) {
152 currentSpan.start = pos;
153 currentSpan.end = pos + currentSpan.textContent.length;
154 currentSpan.onmousedown = this.handleSpanMouseDown;
155 currentSpan.onmousemove = this.handleSpanMouseMove;
156 view.allSpans.push(currentSpan);
157 }
158 current += currentSpan.textContent.length;
159 pos = base + current;
160 }
161 while ((current < sourceText.length) && (
162 sourceText[current] == '\n' ||
163 sourceText[current] == '\r')) {
164 ++current;
165 }
166 }
167 }
168
169 this.resizeToParent();
170}
171
172CodeView.prototype.resizeToParent = function() {
173 var view = this;
174 var documentElement = document.documentElement;
175 var y = view.divElement.parentNode.clientHeight || documentElement.clientHeight;
176 view.divElement.style.height = y + "px";
177}