Chromium Code Reviews| Index: dart/site/try/src/editor.dart |
| diff --git a/dart/site/try/src/editor.dart b/dart/site/try/src/editor.dart |
| index 885295de9c167a69860620832964cdb048f71f0c..f360e76bcca15b5edf1e66f9747407ccb8e3f1ab 100644 |
| --- a/dart/site/try/src/editor.dart |
| +++ b/dart/site/try/src/editor.dart |
| @@ -6,18 +6,12 @@ library trydart.editor; |
| import 'dart:html'; |
| -import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' |
| +import 'package:compiler/implementation/scanner/scannerlib.dart' |
| show |
| EOF_TOKEN, |
| StringScanner, |
| Token; |
| -import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart' show |
| - StringSourceFile; |
| - |
| -import 'compilation.dart' show |
| - scheduleCompilation; |
| - |
| import 'ui.dart' show |
| currentTheme, |
| hackDiv, |
| @@ -26,6 +20,7 @@ import 'ui.dart' show |
| outputDiv; |
| import 'decoration.dart' show |
| + CodeCompletionDecoration, |
| Decoration, |
| DiagnosticDecoration, |
| error, |
| @@ -34,189 +29,99 @@ import 'decoration.dart' show |
| const String INDENT = '\u{a0}\u{a0}'; |
| -onKeyUp(KeyboardEvent e) { |
| - if (e.keyCode == 13) { |
| - e.preventDefault(); |
| - Selection selection = window.getSelection(); |
| - if (selection.isCollapsed && selection.anchorNode is Text) { |
| - Text text = selection.anchorNode; |
| - int offset = selection.anchorOffset; |
| - text.insertData(offset, '\n'); |
| - selection.collapse(text, offset + 1); |
| - } |
| - } |
| - // This is a hack to get Safari to send mutation events on contenteditable. |
| - var newDiv = new DivElement(); |
| - hackDiv.replaceWith(newDiv); |
| - hackDiv = newDiv; |
| -} |
| - |
| -bool isMalformedInput = false; |
| -String currentSource = ""; |
| - |
| -// TODO(ahe): This method should be cleaned up. It is too large. |
| -onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
| - scheduleCompilation(); |
| - |
| - for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) { |
| - element.remove(); |
| - } |
| - // Discard clean-up mutations. |
| - observer.takeRecords(); |
| - |
| - Selection selection = window.getSelection(); |
| - |
| - while (!mutations.isEmpty) { |
| - for (MutationRecord record in mutations) { |
| - String type = record.type; |
| - switch (type) { |
| - |
| - case 'characterData': |
| +Set<String> seenIdentifiers; |
| - bool hasSelection = false; |
| - int offset = selection.anchorOffset; |
| - if (selection.isCollapsed && selection.anchorNode == record.target) { |
| - hasSelection = true; |
| - } |
| - var parent = record.target.parentNode; |
| - if (parent != inputPre) { |
| - inlineChildren(parent); |
| - } |
| - if (hasSelection) { |
| - selection.collapse(record.target, offset); |
| - } |
| - break; |
| - |
| - default: |
| - if (!record.addedNodes.isEmpty) { |
| - for (var node in record.addedNodes) { |
| - |
| - if (node.nodeType != Node.ELEMENT_NODE) continue; |
| - |
| - if (node is BRElement) { |
| - if (selection.anchorNode != node) { |
| - node.replaceWith(new Text('\n')); |
| - } |
| - } else { |
| - var parent = node.parentNode; |
| - if (parent == null) continue; |
| - var nodes = new List.from(node.nodes); |
| - var style = node.getComputedStyle(); |
| - if (style.display != 'inline') { |
| - var previous = node.previousNode; |
| - if (previous is Text) { |
| - previous.appendData('\n'); |
| - } else { |
| - parent.insertBefore(new Text('\n'), node); |
| - } |
| - } |
| - for (Node child in nodes) { |
| - child.remove(); |
| - parent.insertBefore(child, node); |
| - } |
| - node.remove(); |
| - } |
| - } |
| - } |
| - } |
| +Element moveActive(int distance) { |
| + List<Element> entries = document.querySelectorAll('.dart-static>.dart-entry'); |
| + int activeIndex = -1; |
| + for (var i = 0; i < entries.length; i++) { |
| + if (entries[i].classes.contains('activeEntry')) { |
| + activeIndex = i; |
| + break; |
| } |
| - mutations = observer.takeRecords(); |
| } |
| - |
| - if (!inputPre.nodes.isEmpty && inputPre.nodes.last is Text) { |
| - Text text = inputPre.nodes.last; |
| - if (!text.text.endsWith('\n')) { |
| - text.appendData('\n'); |
| - } |
| + int newIndex = activeIndex + distance; |
| + Element currentEntry; |
| + if (0 <= newIndex && newIndex < entries.length) { |
| + currentEntry = entries[newIndex]; |
| } |
| - |
| - int offset = 0; |
| - int anchorOffset = 0; |
| - bool hasSelection = false; |
| - Node anchorNode = selection.anchorNode; |
| - // TODO(ahe): Try to share walk4 methods. |
| - void walk4(Node node) { |
| - // TODO(ahe): Use TreeWalker when that is exposed. |
| - // function textNodesUnder(root){ |
| - // var n, a=[], walk=document.createTreeWalker( |
| - // root,NodeFilter.SHOW_TEXT,null,false); |
| - // while(n=walk.nextNode()) a.push(n); |
| - // return a; |
| - // } |
| - int type = node.nodeType; |
| - if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) { |
| - CharacterData text = node; |
| - if (anchorNode == node) { |
| - hasSelection = true; |
| - anchorOffset = selection.anchorOffset + offset; |
| - return; |
| + if (currentEntry == null) return null; |
| + if (0 <= newIndex && activeIndex != -1) { |
| + entries[activeIndex].classes.remove('activeEntry'); |
| + } |
| + Element staticNode = document.querySelector('.dart-static'); |
| + String visibility = computeVisibility(currentEntry, staticNode); |
| + print(visibility); |
| + var serverResults = document.querySelectorAll('.dart-server>.dart-entry'); |
| + var serverResultCount = serverResults.length; |
| + if (serverResultCount > 0) { |
| + switch (visibility) { |
| + case obscured: |
| + case hidden: { |
|
kasperl
2014/03/24 10:32:51
No need for { } in a case.
ahe
2014/03/24 15:20:23
I like {} in this case.
|
| + Rectangle cr = currentEntry.getBoundingClientRect(); |
| + Rectangle sr = staticNode.getBoundingClientRect(); |
| + Element entry = serverResults[0]; |
| + entry.remove(); |
| + currentEntry.parentNode.insertBefore(entry, currentEntry); |
| + currentEntry = entry; |
| + serverResultCount--; |
| + |
| + staticNode.style.maxHeight = '${sr.boundingBox(cr).height}px'; |
| } |
| - offset += text.length; |
| - } |
| - |
| - var child = node.firstChild; |
| - while (child != null) { |
| - walk4(child); |
| - if (hasSelection) return; |
| - child = child.nextNode; |
| } |
| + } else { |
| + currentEntry.scrollIntoView(ScrollAlignment.BOTTOM); |
| } |
| - if (selection.isCollapsed) { |
| - walk4(inputPre); |
| + if (serverResultCount == 0) { |
| + document.querySelector('.dart-server').style.display = 'none'; |
| } |
| - |
| - currentSource = inputPre.text; |
| - inputPre.nodes.clear(); |
| - inputPre.appendText(currentSource); |
| - if (hasSelection) { |
| - selection.collapse(inputPre.firstChild, anchorOffset); |
| + if (currentEntry != null) { |
| + currentEntry.classes.add('activeEntry'); |
| } |
| + // Discard mutations. |
| + observer.takeRecords(); |
| + return currentEntry; |
| +} |
| - isMalformedInput = false; |
| - for (var n in new List.from(inputPre.nodes)) { |
| - if (n is! Text) continue; |
| - Text node = n; |
| - String text = node.text; |
| +const visible = 'visible'; |
| +const obscured = 'obscured'; |
| +const hidden = 'hidden'; |
| - Token token = new StringScanner( |
| - new StringSourceFile('', text), includeComments: true).tokenize(); |
| - int offset = 0; |
| - for (;token.kind != EOF_TOKEN; token = token.next) { |
| - Decoration decoration = getDecoration(token); |
| - if (decoration == null) continue; |
| - bool hasSelection = false; |
| - int selectionOffset = selection.anchorOffset; |
| +String computeVisibility(Element node, [Element parent]) { |
| + Rectangle nr = node.getBoundingClientRect(); |
| + if (parent == null) parent = node.parentNode; |
| + Rectangle pr = parent.getBoundingClientRect(); |
| - if (selection.isCollapsed && selection.anchorNode == node) { |
| - hasSelection = true; |
| - selectionOffset = selection.anchorOffset; |
| - } |
| - int splitPoint = token.charOffset - offset; |
| - Text str = node.splitText(splitPoint); |
| - Text after = str.splitText(token.charCount); |
| - offset += splitPoint + token.charCount; |
| - inputPre.insertBefore(after, node.nextNode); |
| - inputPre.insertBefore(decoration.applyTo(str), after); |
| + if (pr.containsRectangle(nr)) return visible; |
| - if (hasSelection && selectionOffset > node.length) { |
| - selectionOffset -= node.length; |
| - if (selectionOffset > str.length) { |
| - selectionOffset -= str.length; |
| - selection.collapse(after, selectionOffset); |
| - } else { |
| - selection.collapse(str, selectionOffset); |
| - } |
| - } |
| - node = after; |
| - } |
| - } |
| + if (pr.intersects(nr)) return obscured; |
| + |
| + return hidden; |
| +} |
| - window.localStorage['currentSource'] = currentSource; |
| +var activeCompletion; |
| +num minSuggestionWidth = 0; |
| - // Discard highlighting mutations. |
| - observer.takeRecords(); |
| +/// Returns the [Element] which encloses the current collapsed selection, if it |
| +/// exists. |
| +Element getElementAtSelection() { |
| + Selection selection = window.getSelection(); |
| + if (!selection.isCollapsed) return null; |
| + var anchorNode = selection.anchorNode; |
| + if (!inputPre.contains(anchorNode)) return null; |
| + if (inputPre == anchorNode) return null; |
| + int type = anchorNode.nodeType; |
| + if (type != Node.TEXT_NODE) return null; |
| + Text text = anchorNode; |
| + var parent = text.parent; |
| + if (parent is! Element) return null; |
| + if (inputPre == parent) return null; |
| + return parent; |
| } |
| +bool isMalformedInput = false; |
| +String currentSource = ""; |
| + |
| addDiagnostic(String kind, String message, int begin, int end) { |
| observer.disconnect(); |
| Selection selection = window.getSelection(); |
| @@ -260,7 +165,11 @@ addDiagnostic(String kind, String message, int begin, int end) { |
| offset = newOffset; |
| } else if (type == Node.ELEMENT_NODE) { |
| Element element = node; |
| - if (element.classes.contains('alert')) return; |
| + CssClassSet classes = element.classes; |
| + if (classes.contains('alert') || |
| + classes.contains('dart-code-completion')) { |
| + return; |
| + } |
| } |
| var child = node.firstChild; |
| @@ -295,7 +204,10 @@ Decoration getDecoration(Token token) { |
| String tokenValue = token.value; |
| String tokenInfo = token.info.value; |
| if (tokenInfo == 'string') return currentTheme.string; |
| - // if (tokenInfo == 'identifier') return identifier; |
| + if (tokenInfo == 'identifier') { |
| + seenIdentifiers.add(tokenValue); |
| + return CodeCompletionDecoration.from(currentTheme.foreground); |
| + } |
| if (tokenInfo == 'keyword') return currentTheme.keyword; |
| if (tokenInfo == 'comment') return currentTheme.singleLineComment; |
| if (tokenInfo == 'malformed input') { |