OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
Siggi Cherem (dart-lang)
2015/03/07 02:43:01
this is adapted from the code in polymer. Simplifi
| |
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. | |
4 | |
5 /// This library provides a single function called injectLogs which when called | |
6 /// will request a logs json file and build a small widget out of them which | |
7 /// groups the logs by level. | |
8 library polymer.build.log_injector; | |
9 | |
10 import 'dart:async'; | |
11 import 'dart:convert'; | |
12 import 'dart:html'; | |
13 | |
14 import 'package:path/path.dart' as path; | |
15 import 'package:source_span/source_span.dart'; | |
16 import 'package:dev_compiler/src/summary.dart'; | |
17 | |
18 main() async => displayMessages(await HttpRequest.getString('messages.json')); | |
19 | |
20 void displayMessages(String data) { | |
21 var summary = GlobalSummary.parse(JSON.decode(data)); | |
22 var messagesByLevel = _getMessagesByLevel(summary); | |
23 if (messagesByLevel.isEmpty) return; | |
24 | |
25 // Build the wrapper, menu, and content divs. | |
26 var menuWrapper = new DivElement()..classes.add('menu'); | |
27 var contentWrapper = new DivElement()..classes.add('content'); | |
28 var wrapperDiv = new DivElement() | |
29 ..classes.add('dev-compiler-messages') | |
30 ..append(menuWrapper) | |
31 ..append(contentWrapper); | |
32 | |
33 var selectedMenu = new _Selection(); | |
34 var selectedContent = new _Selection(); | |
35 | |
36 // Add a menu item, content section, and messages for each log level. | |
37 messagesByLevel.forEach((level, messages) { | |
38 var contentItem = new DivElement()..classes.add(level); | |
39 var menuItem = new Element.html('<div class="$level">' | |
40 '$level <span class="num">(${messages.length})</span>' | |
41 '</div>'); | |
42 menuWrapper.append(menuItem); | |
43 contentWrapper.append(contentItem); | |
44 menuItem.onClick.listen((_) { | |
45 selectedMenu.select(menuItem); | |
46 selectedContent.select(contentItem); | |
47 }); | |
48 | |
49 // TODO(sigmund): add permanent links to error messages like in polymer. | |
50 for (var m in messages) { | |
51 var message = _hyperlinkUrls(_escape(m.message)); | |
52 var span = m.span; | |
53 var sb = new StringBuffer(); | |
54 sb.write('<div class="message"><div class="text $level">$message</div>'); | |
55 if (span != null) { | |
56 sb.write('<div class="location">' | |
57 ' <span class="location">${span.start.toolString}</span></div>' | |
58 ' <span class="text">${_escape(span.text)}</span></div></div>'); | |
59 } | |
60 sb.write('</div>'); | |
61 | |
62 var logElement = new Element.html('$sb', | |
63 validator: new NodeValidatorBuilder.common() | |
64 ..allowNavigation(new _OpenUriPolicy())); | |
65 contentItem.append(logElement); | |
66 var messageElement = logElement.querySelector('div.text'); | |
67 messageElement.onClick.listen((e) { | |
68 if (e.target == messageElement) { | |
69 messageElement.classes.toggle('expanded'); | |
70 } | |
71 }); | |
72 } | |
73 }); | |
74 | |
75 document.body.append(wrapperDiv); | |
76 } | |
77 | |
78 /// Toggles classes to match which item of a list of items is selected. | |
79 class _Selection { | |
80 Element _selected; | |
81 | |
82 select(Element newItem) { | |
83 if (_selected == newItem) { | |
84 _selected = null; | |
85 } else { | |
86 if (_selected != null) { | |
87 _selected.classes.remove('active'); | |
88 } | |
89 _selected = newItem; | |
90 } | |
91 newItem.classes.toggle('active'); | |
92 } | |
93 } | |
94 | |
95 final _urlRegex = new RegExp('http://[^ ]*'); | |
96 final _escaper = new HtmlEscape(); | |
97 String _hyperlinkUrls(String text) => text.replaceAllMapped(_urlRegex, | |
98 (m) => '<a href="${m.group(0)}" target="blank">${m.group(0)}</a>'); | |
99 String _escape(String text) => _escaper.convert(text); | |
100 | |
101 class _OpenUriPolicy implements UriPolicy { | |
102 bool allowsUri(String uri) => true; | |
103 } | |
104 | |
105 Map<String, List<MessageSummary>> _getMessagesByLevel(GlobalSummary messages) { | |
106 var visitor = new _Visitor(); | |
107 messages.accept(visitor); | |
108 return visitor.messagesByLevel; | |
109 } | |
110 | |
111 class _Visitor extends RecursiveSummaryVisitor { | |
112 final Map<String, List<MessageSummary>> messagesByLevel = {}; | |
113 | |
114 @override | |
115 void visitMessage(MessageSummary message) { | |
116 var level = message.level.toLowerCase(); | |
117 messagesByLevel.putIfAbsent(level, () => []); | |
118 messagesByLevel[level].add(message); | |
119 } | |
120 } | |
OLD | NEW |