• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"use strict";
6
7class TextView extends View {
8  constructor(id, broker, patterns, allowSpanSelection) {
9    super(id, broker);
10    let view = this;
11    view.hide();
12    view.textListNode = view.divNode.getElementsByTagName('ul')[0];
13    view.fillerSvgElement = view.divElement.append("svg").attr('version','1.1').attr("width", "0");
14    view.patterns = patterns;
15    view.allowSpanSelection = allowSpanSelection;
16    view.nodeToLineMap = [];
17    var selectionHandler = {
18      clear: function() {
19        broker.clear(selectionHandler);
20      },
21      select: function(items, selected) {
22        for (let i of items) {
23          if (selected) {
24            i.classList.add("selected");
25          } else {
26            i.classList.remove("selected");
27          }
28        }
29        broker.clear(selectionHandler);
30        broker.select(selectionHandler, view.getLocations(items), selected);
31      },
32      selectionDifference: function(span1, inclusive1, span2, inclusive2) {
33        return null;
34      },
35      brokeredSelect: function(locations, selected) {
36        view.selectLocations(locations, selected, true);
37      },
38      brokeredClear: function() {
39        view.selection.clear();
40      }
41    };
42    view.selection = new Selection(selectionHandler);
43    broker.addSelectionHandler(selectionHandler);
44  }
45
46  setPatterns(patterns) {
47    let view = this;
48    view.patterns = patterns;
49  }
50
51  clearText() {
52    let view = this;
53    while (view.textListNode.firstChild) {
54      view.textListNode.removeChild(view.textListNode.firstChild);
55    }
56  }
57
58  sameLocation(l1, l2) {
59    let view = this;
60    if (l1.block_id != undefined && l2.block_id != undefined &&
61      l1.block_id == l2.block_id && l1.node_id === undefined) {
62      return true;
63    }
64
65    if (l1.address != undefined && l1.address == l2.address) {
66      return true;
67    }
68
69    let node1 = l1.node_id;
70    let node2 = l2.node_id;
71
72    if (node1 === undefined || node2 == undefined) {
73      if (l1.pos_start === undefined || l2.pos_start == undefined) {
74        return false;
75      }
76      if (l1.pos_start == -1 || l2.pos_start == -1) {
77        return false;
78      }
79      if (l1.pos_start < l2.pos_start) {
80        return l1.pos_end > l2.pos_start;
81      } {
82        return l1.pos_start < l2.pos_end;
83      }
84    }
85
86    return l1.node_id == l2.node_id;
87  }
88
89  selectLocations(locations, selected, makeVisible) {
90    let view = this;
91    let s = new Set();
92    for (let l of locations) {
93      for (let i = 0; i < view.textListNode.children.length; ++i) {
94        let child = view.textListNode.children[i];
95        if (child.location != undefined && view.sameLocation(l, child.location)) {
96          s.add(child);
97        }
98      }
99    }
100    view.selectCommon(s, selected, makeVisible);
101  }
102
103  getLocations(items) {
104    let result = [];
105    let lastObject = null;
106    for (let i of items) {
107      if (i.location) {
108        result.push(i.location);
109      }
110    }
111    return result;
112  }
113
114  createFragment(text, style) {
115    let view = this;
116    let span = document.createElement("SPAN");
117    span.onmousedown = function(e) {
118      view.mouseDownSpan(span, e);
119    }
120    if (style != undefined) {
121      span.classList.add(style);
122    }
123    span.innerHTML = text;
124    return span;
125  }
126
127  appendFragment(li, fragment) {
128    li.appendChild(fragment);
129  }
130
131  processLine(line) {
132    let view = this;
133    let result = [];
134    let patternSet = 0;
135    while (true) {
136      let beforeLine = line;
137      for (let pattern of view.patterns[patternSet]) {
138        let matches = line.match(pattern[0]);
139        if (matches != null) {
140          if (matches[0] != '') {
141            let style = pattern[1] != null ? pattern[1] : {};
142            let text = matches[0];
143            if (text != '') {
144              let fragment = view.createFragment(matches[0], style.css);
145              if (style.link) {
146                fragment.classList.add('linkable-text');
147                fragment.link = style.link;
148              }
149              result.push(fragment);
150              if (style.location != undefined) {
151                let location = style.location(text);
152                if (location != undefined) {
153                  fragment.location = location;
154                }
155              }
156            }
157            line = line.substr(matches[0].length);
158          }
159          let nextPatternSet = patternSet;
160          if (pattern.length > 2) {
161            nextPatternSet = pattern[2];
162          }
163          if (line == "") {
164            if (nextPatternSet != -1) {
165              throw("illegal parsing state in text-view in patternSet" + patternSet);
166            }
167            return result;
168          }
169          patternSet = nextPatternSet;
170          break;
171        }
172      }
173      if (beforeLine == line) {
174        throw("input not consumed in text-view in patternSet" + patternSet);
175      }
176    }
177  }
178
179  select(s, selected, makeVisible) {
180    let view = this;
181    view.selection.clear();
182    view.selectCommon(s, selected, makeVisible);
183  }
184
185  selectCommon(s, selected, makeVisible) {
186    let view = this;
187    let firstSelect = makeVisible && view.selection.isEmpty();
188    if ((typeof s) === 'function') {
189      for (let i = 0; i < view.textListNode.children.length; ++i) {
190        let child = view.textListNode.children[i];
191        if (child.location && s(child.location)) {
192          if (firstSelect) {
193            makeContainerPosVisible(view.parentNode, child.offsetTop);
194            firstSelect = false;
195          }
196          view.selection.select(child, selected);
197        }
198      }
199    } else if (typeof s[Symbol.iterator] === 'function') {
200      if (firstSelect) {
201        for (let i of s) {
202          makeContainerPosVisible(view.parentNode, i.offsetTop);
203          break;
204        }
205      }
206      view.selection.select(s, selected);
207    } else {
208      if (firstSelect) {
209        makeContainerPosVisible(view.parentNode, s.offsetTop);
210      }
211      view.selection.select(s, selected);
212    }
213  }
214
215  mouseDownLine(li, e) {
216    let view = this;
217    e.stopPropagation();
218    if (!e.shiftKey) {
219      view.selection.clear();
220    }
221    if (li.location != undefined) {
222      view.selectLocations([li.location], true, false);
223    }
224  }
225
226  mouseDownSpan(span, e) {
227    let view = this;
228    if (view.allowSpanSelection) {
229      e.stopPropagation();
230      if (!e.shiftKey) {
231        view.selection.clear();
232      }
233      select(li, true);
234    } else if (span.link) {
235      span.link(span.textContent);
236      e.stopPropagation();
237    }
238  }
239
240  processText(text) {
241    let view = this;
242    let textLines = text.split(/[\n]/);
243    let lineNo = 0;
244    for (let line of textLines) {
245      let li = document.createElement("LI");
246      li.onmousedown = function(e) {
247        view.mouseDownLine(li, e);
248      }
249      li.className = "nolinenums";
250      li.lineNo = lineNo++;
251      let fragments = view.processLine(line);
252      for (let fragment of fragments) {
253        view.appendFragment(li, fragment);
254      }
255      let lineLocation = view.lineLocation(li);
256      if (lineLocation != undefined) {
257        li.location = lineLocation;
258      }
259      view.textListNode.appendChild(li);
260    }
261  }
262
263  initializeContent(data, rememberedSelection) {
264    let view = this;
265    view.selection.clear();
266    view.clearText();
267    view.processText(data);
268    var fillerSize = document.documentElement.clientHeight -
269        view.textListNode.clientHeight;
270    if (fillerSize < 0) {
271      fillerSize = 0;
272    }
273    view.fillerSvgElement.attr("height", fillerSize);
274  }
275
276  deleteContent() {
277  }
278
279  isScrollable() {
280    return true;
281  }
282
283  detachSelection() {
284    return null;
285  }
286
287  lineLocation(li) {
288    let view = this;
289    for (let i = 0; i < li.children.length; ++i) {
290      let fragment = li.children[i];
291      if (fragment.location != undefined && !view.allowSpanSelection) {
292        return fragment.location;
293      }
294    }
295  }
296}
297