OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library trydart.htmlToText; | 5 library trydart.htmlToText; |
6 | 6 |
7 import 'dart:math' show | 7 import 'dart:math' show |
8 max; | 8 max; |
9 | 9 |
10 import 'dart:html' show | 10 import 'dart:html' show |
| 11 CharacterData, |
11 Element, | 12 Element, |
12 Node, | 13 Node, |
13 NodeFilter, | 14 NodeFilter, |
14 ShadowRoot, | 15 ShadowRoot, |
15 Text, | |
16 TreeWalker; | 16 TreeWalker; |
17 | 17 |
18 import 'selection.dart' show | 18 import 'selection.dart' show |
19 TrySelection; | 19 TrySelection; |
20 | 20 |
| 21 import 'shadow_root.dart' show |
| 22 WALKER_NEXT, |
| 23 WALKER_SKIP_NODE, |
| 24 walkNodes; |
| 25 |
21 /// Returns true if [node] is a block element, that is, not inline. | 26 /// Returns true if [node] is a block element, that is, not inline. |
22 bool isBlockElement(Node node) { | 27 bool isBlockElement(Node node) { |
23 if (node is! Element) return false; | 28 if (node is! Element) return false; |
24 Element element = node; | 29 Element element = node; |
25 | 30 |
26 // TODO(ahe): Remove this line by changing code completion to avoid using a | 31 // TODO(ahe): Remove this line by changing code completion to avoid using a |
27 // div element. | 32 // div element. |
28 if (element.classes.contains('dart-code-completion')) return false; | 33 if (element.classes.contains('dart-code-completion')) return false; |
29 | 34 |
30 return element.getComputedStyle().display != 'inline'; | 35 return element.getComputedStyle().display != 'inline'; |
31 } | 36 } |
32 | 37 |
33 /// Position [walker] at the last predecessor (that is, child of child of | |
34 /// child...) of [node]. The next call to walker.nextNode will return the first | |
35 /// node after [node]. | |
36 void skip(Node node, TreeWalker walker) { | |
37 if (walker.nextSibling() != null) { | |
38 walker.previousNode(); | |
39 return; | |
40 } | |
41 for (Node current = walker.nextNode(); | |
42 current != null; | |
43 current = walker.nextNode()) { | |
44 if (!node.contains(current)) { | |
45 walker.previousNode(); | |
46 return; | |
47 } | |
48 } | |
49 } | |
50 | |
51 /// Writes the text of [root] to [buffer]. Keeps track of [selection] and | 38 /// Writes the text of [root] to [buffer]. Keeps track of [selection] and |
52 /// returns the new anchorOffset from beginning of [buffer] or -1 if the | 39 /// returns the new anchorOffset from beginning of [buffer] or -1 if the |
53 /// selection isn't in [root]. | 40 /// selection isn't in [root]. |
54 int htmlToText(Node root, | 41 int htmlToText(Node root, |
55 StringBuffer buffer, | 42 StringBuffer buffer, |
56 TrySelection selection, | 43 TrySelection selection, |
57 {bool treatRootAsInline: false}) { | 44 {bool treatRootAsInline: false}) { |
58 int selectionOffset = -1; | 45 int selectionOffset = -1; |
59 TreeWalker walker = new TreeWalker(root, NodeFilter.SHOW_ALL); | 46 walkNodes(root, (Node node) { |
60 | 47 if (selection.anchorNode == node) { |
61 for (Node node = root; node != null; node = walker.nextNode()) { | 48 selectionOffset = selection.anchorOffset + buffer.length; |
| 49 } |
62 switch (node.nodeType) { | 50 switch (node.nodeType) { |
63 case Node.CDATA_SECTION_NODE: | 51 case Node.CDATA_SECTION_NODE: |
64 case Node.TEXT_NODE: | 52 case Node.TEXT_NODE: |
65 if (selection.anchorNode == node) { | 53 CharacterData text = node; |
66 selectionOffset = selection.anchorOffset + buffer.length; | |
67 } | |
68 Text text = node; | |
69 buffer.write(text.data.replaceAll('\xA0', ' ')); | 54 buffer.write(text.data.replaceAll('\xA0', ' ')); |
70 break; | 55 break; |
71 | 56 |
72 default: | 57 default: |
73 if (!ShadowRoot.supported && | 58 if (node.nodeName == 'BR') { |
74 node is Element && | |
75 node.getAttribute('try-dart-shadow-root') != null) { | |
76 skip(node, walker); | |
77 } else if (node.nodeName == 'BR') { | |
78 buffer.write('\n'); | 59 buffer.write('\n'); |
79 } else if (node != root && isBlockElement(node)) { | 60 } else if (node != root && isBlockElement(node)) { |
80 selectionOffset = | 61 selectionOffset = |
81 max(selectionOffset, htmlToText(node, buffer, selection)); | 62 max(selectionOffset, htmlToText(node, buffer, selection)); |
82 skip(node, walker); | 63 return WALKER_SKIP_NODE; |
83 } | 64 } |
84 break; | 65 break; |
85 } | 66 } |
86 } | 67 |
| 68 return WALKER_NEXT; |
| 69 }); |
87 | 70 |
88 if (!treatRootAsInline && isBlockElement(root)) { | 71 if (!treatRootAsInline && isBlockElement(root)) { |
89 buffer.write('\n'); | 72 buffer.write('\n'); |
90 } | 73 } |
91 | 74 |
92 return selectionOffset; | 75 return selectionOffset; |
93 } | 76 } |
OLD | NEW |