1 // 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 5 var 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 123 CodeView.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 172 CodeView.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 } 178