// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var CodeView = function(divID, PR, sourceText, sourcePosition, broker) {
"use strict";
var view = this;
view.divElement = document.getElementById(divID);
view.broker = broker;
view.codeSelection = null;
view.allSpans = [];
var selectionHandler = {
clear: function() {
broker.clear(selectionHandler);
},
select: function(items, selected) {
var handler = this;
var divElement = view.divElement;
var broker = view.broker;
for (let span of items) {
if (selected) {
span.classList.add("selected");
} else {
span.classList.remove("selected");
}
}
var ranges = [];
for (var span of items) {
ranges.push([span.start, span.end, null]);
}
broker.select(selectionHandler, ranges, selected);
},
selectionDifference: function(span1, inclusive1, span2, inclusive2) {
var pos1 = span1.start;
var pos2 = span2.start;
var result = [];
var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
for (var i=0; i < lineListDiv.length; i++) {
var currentLineElement = lineListDiv[i];
var spans = currentLineElement.childNodes;
for (var j=0; j < spans.length; ++j) {
var currentSpan = spans[j];
if (currentSpan.start > pos1 || (inclusive1 && currentSpan.start == pos1)) {
if (currentSpan.start < pos2 || (inclusive2 && currentSpan.start == pos2)) {
result.push(currentSpan);
}
}
}
}
return result;
},
brokeredSelect: function(ranges, selected) {
var firstSelect = view.codeSelection.isEmpty();
for (var range of ranges) {
var start = range[0];
var end = range[1];
var lower = 0;
var upper = view.allSpans.length;
if (upper > 0) {
while ((upper - lower) > 1) {
var middle = Math.floor((upper + lower) / 2);
var lineStart = view.allSpans[middle].start;
if (lineStart < start) {
lower = middle;
} else if (lineStart > start) {
upper = middle;
} else {
lower = middle;
break;
}
}
var currentSpan = view.allSpans[lower];
var currentLineElement = currentSpan.parentNode;
if ((currentSpan.start <= start && start < currentSpan.end) ||
(currentSpan.start <= end && end < currentSpan.end)) {
if (firstSelect) {
makeContainerPosVisible(view.divElement, currentLineElement.offsetTop);
firstSelect = false;
}
view.codeSelection.select(currentSpan, selected);
}
}
}
},
brokeredClear: function() {
view.codeSelection.clear();
},
};
view.codeSelection = new Selection(selectionHandler);
broker.addSelectionHandler(selectionHandler);
var mouseDown = false;
this.handleSpanMouseDown = function(e) {
e.stopPropagation();
if (!e.shiftKey) {
view.codeSelection.clear();
}
view.codeSelection.select(this, true);
mouseDown = true;
}
this.handleSpanMouseMove = function(e) {
if (mouseDown) {
view.codeSelection.extendTo(this);
}
}
this.handleCodeMouseDown = function(e) {
view.codeSelection.clear();
}
document.addEventListener('mouseup', function(e){
mouseDown = false;
}, false);
this.initializeCode(sourceText, sourcePosition);
}
CodeView.prototype.initializeCode = function(sourceText, sourcePosition) {
var view = this;
if (sourceText == "") {
var newHtml = "<pre class=\"prettyprint\"</pre>";
view.divElement.innerHTML = newHtml;
} else {
var newHtml = "<pre class=\"prettyprint linenums\">"
+ sourceText + "</pre>";
view.divElement.innerHTML = newHtml;
try {
// Wrap in try to work when offline.
PR.prettyPrint();
} catch (e) {
}
view.divElement.onmousedown = this.handleCodeMouseDown;
var base = sourcePosition;
var current = 0;
var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
for (i=0; i < lineListDiv.length; i++) {
var currentLineElement = lineListDiv[i];
currentLineElement.id = "li" + i;
var pos = base + current;
currentLineElement.pos = pos;
var spans = currentLineElement.childNodes;
for (j=0; j < spans.length; ++j) {
var currentSpan = spans[j];
if (currentSpan.nodeType == 1) {
currentSpan.start = pos;
currentSpan.end = pos + currentSpan.textContent.length;
currentSpan.onmousedown = this.handleSpanMouseDown;
currentSpan.onmousemove = this.handleSpanMouseMove;
view.allSpans.push(currentSpan);
}
current += currentSpan.textContent.length;
pos = base + current;
}
while ((current < sourceText.length) && (
sourceText[current] == '\n' ||
sourceText[current] == '\r')) {
++current;
}
}
}
this.resizeToParent();
}
CodeView.prototype.resizeToParent = function() {
var view = this;
var documentElement = document.documentElement;
var y = view.divElement.parentNode.clientHeight || documentElement.clientHeight;
view.divElement.style.height = y + "px";
}