Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(692)

Side by Side Diff: client/web/model.dart

Issue 11636011: Web components based app to view dart docs. Still has rough edges. (Closed) Base URL: https://github.com/dart-lang/dart-api-app.git@master
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 library apidoc_model; 1 library apidoc_model;
2 2
3 import 'package:web_ui/watcher.dart' as watchers; 3 import 'package:web_ui/watcher.dart' as watchers;
4 import 'package:web_ui/safe_html.dart'; 4 import 'package:web_ui/safe_html.dart';
5 import 'markdown.dart' as md; 5 import 'markdown.dart' as md;
6 import 'dart:html' as html; 6 import 'dart:html' as html;
7 import 'dart:json'; 7 import 'dart:json';
8 import 'ast.dart'; 8 import 'ast.dart';
9 9
10 // TODO(jacobr): specify the version # in the JSON file.
Siggi Cherem (dart-lang) 2012/12/19 19:47:33 +1 :)
Jacob 2013/01/02 19:54:58 acknowledged :)
10 String svnRevisionNumber = "15605"; 11 String svnRevisionNumber = "15605";
11 12
12 String _activeReferenceId; 13 /**
14 * Reference id of [currentElement].
15 * *
Siggi Cherem (dart-lang) 2012/12/19 19:47:33 remove extra *
Jacob 2013/01/02 19:54:58 rm * :)
16 * Stored in addition to [currentElement] as [currentElement] may
17 * not yet be available if the data model for the library it is part of has
18 * not yet been loaded.
19 */
20 String _currentReferenceId;
13 21
14 /// Current state of the application. 22 /**
23 * Current library the user is browsing if any.
24 */
15 LibraryElement currentLibrary; 25 LibraryElement currentLibrary;
26
27 /**
28 * Current type the user is viewing if any.
29 * Should be either a [ClassElement] or a [TypedefElement].
30 */
16 Element currentType; 31 Element currentType;
32 /**
33 * Current member of either [currentLibrary] or [currentType] that the user is
34 * viewing.
35 */
17 Element currentMember; 36 Element currentMember;
37
38 /**
39 * Element corresponding to [_currentReferenceId].
40 * The most specific element of [currentLibrary]. [currentType], and
41 * [currentMember].
42 */
18 Element currentElement; 43 Element currentElement;
19 44
45 /**
46 * Recomputes the Elements part of the current active state from the data model.
47 *
48 * This method should be invoked after additional libraries are loaded from the
49 * server or after the user navigates to a different element in the UI.
50 */
20 void _recomputeActiveState() { 51 void _recomputeActiveState() {
21 currentLibrary = null; 52 currentLibrary = null;
22 currentType = null; 53 currentType = null;
23 currentMember = null; 54 currentMember = null;
24 currentElement = null; 55 currentElement = null;
25 if (_activeReferenceId != null) { 56 if (_currentReferenceId != null) {
26 var path = lookupReferenceId(_activeReferenceId).path; 57 var referenceElement = lookupReferenceId(_currentReferenceId);
27 58 if (referenceElement != null) {
28 if (path.length > 0) { 59 var path = referenceElement.path;
29 currentLibrary = path[0]; 60 if (path.length > 0) {
30 } 61 currentLibrary = path[0];
31 if (path.length > 1) { 62 }
32 if (path[1] is ClassElement || path[1] is TypedefElement) { 63 if (path.length > 1) {
33 currentType = path[1]; 64 if (path[1] is ClassElement || path[1] is TypedefElement) {
34 if (path.length > 2) { 65 currentType = path[1];
35 currentMember = path[2]; 66 if (path.length > 2) {
67 currentMember = path[2];
68 }
69 } else {
70 currentMember = path[1];
36 } 71 }
72 }
73 if (currentMember != null) {
74 currentElement = currentMember;
75 } else if (currentType != null) {
76 currentElement = currentType;
37 } else { 77 } else {
38 currentMember = path[1]; 78 currentElement = currentLibrary;
39 } 79 }
40 } 80 }
41 if (currentMember != null) {
42 currentElement = currentMember;
43 } else if (currentType != null) {
44 currentElement = currentType;
45 } else {
46 currentElement = currentLibrary;
47 }
48 } 81 }
49 } 82 }
50 83
84 /**
85 * Scrolls the [currentElement] into view.
86 */
51 void scrollIntoView() { 87 void scrollIntoView() {
52 // TODO(jacobr): there should be a cleaner way to run code that executes 88 // TODO(jacobr): there should be a cleaner way to run code that executes
53 // after the UI updates. 89 // after the UI updates.
Siggi Cherem (dart-lang) 2012/12/19 19:47:33 let's add an issue for this in web-ui.
Jacob 2013/01/02 19:54:58 Referenced https://github.com/dart-lang/web-ui/iss
Siggi Cherem (dart-lang) 2013/01/02 21:40:55 Thanks! Sorry that I asked you to filed it and the
54 html.window.setTimeout(() { 90 html.window.setTimeout(() {
55 if (currentElement != null) { 91 if (currentElement != null) {
56 for (var e in html.queryAll('[data-id="${currentElement.id}"]')) { 92 for (var e in html.queryAll('[data-id="${currentElement.id}"]')) {
57 e.scrollIntoView(false); 93 e.scrollIntoView(false);
58 } 94 }
59 } 95 }
60 }, 0); 96 }, 0);
61 } 97 }
62 98
63 onDataModelChanged() { 99 /**
100 * Invoke every time the data model changes.
101 */
102 void _onDataModelChanged() {
64 _recomputeActiveState(); 103 _recomputeActiveState();
65 scrollIntoView(); 104 scrollIntoView();
66 } 105 }
67 106
68 /** 107 /**
69 * Generate a CSS class given an element that may be a class, member, method, 108 * Generate a CSS class given an element that may be a class, member, method,
70 * etc. 109 * etc.
71 */ 110 */
72 String kindCssClass(Element element) { 111 String kindCssClass(Element element) {
73 String classes = 'kind kind-${normalizedKind(element)}'; 112 String classes = 'kind kind-${_normalizedKind(element)}';
74 if (element.isPrivate == true) { 113 if (element.isPrivate == true) {
75 classes = '$classes private'; 114 classes = '$classes private';
76 } else if (element is MethodElementBase && element.isStatic) { 115 } else if (element is MethodElementBase && element.isStatic) {
77 classes = '$classes static'; 116 classes = '$classes static';
78 } 117 }
79 118
80 // Setters are viewed as methods by the AST. 119 // Setters are viewed as methods by the AST.
81 if (element is PropertyElement) { 120 if (element is PropertyElement) {
82 classes = '$classes getter'; 121 classes = '$classes getter';
83 } 122 }
84 123
85 if (element is MethodElementBase && element.isSetter) { 124 if (element is MethodElementBase && element.isSetter) {
86 classes = '$classes setter'; 125 classes = '$classes setter';
87 } 126 }
88 127
89 return classes; 128 return classes;
90 } 129 }
91 130
92 String normalizedKind(obj) { 131 String _normalizedKind(Element element) {
93 if (obj is Element) return normalizedKindFromElement(obj);
94 return obj;
95 }
96
97 String normalizedKindFromElement(Element element) {
98 var kind = element.kind; 132 var kind = element.kind;
99 var name = element.name; 133 var name = element.name;
100 if (kind == 'method' && element.isOperator) { 134 if (kind == 'method' && element.isOperator) {
101 kind = 'operator'; 135 kind = 'operator';
102 } 136 }
103 // TODO(jacobr): this is horrible but matches what DartDoc does 137 // TODO(jacobr): this is horrible but matches what DartDoc does
104 if (kind == 'class' && name.endsWith('Exception')) { 138 if (kind == 'class' && name.endsWith('Exception')) {
105 kind = 'exception'; 139 kind = 'exception';
106 } 140 }
107 return kind; 141 return kind;
108 } 142 }
109 143
110 String toUserVisibleKind(Element element) { 144 String toUserVisibleKind(Element element) {
111 return KIND_TITLES[normalizedKind(element)]; 145 return KIND_TITLES[_normalizedKind(element)];
112 } 146 }
113 147
114 /** 148 /**
115 * [obj] shoudl be a [Reference] or [Element]. 149 * [obj] shoudl be a [Reference] or [Element].
116 */ 150 */
117 String permalink(var obj) { 151 String permalink(var obj) {
118 var data = {'id': obj.refId}; 152 var data = {'id': obj.refId};
153 // TODO(jacobr): evaluate whether the persistent UI state will stay just a
154 // single reference ID in which case this is overkill.
119 return "#!${JSON.stringify(data)}"; 155 return "#!${JSON.stringify(data)}";
120 } 156 }
121 157
122 void loadStateFromUrl() { 158 void loadStateFromUrl() {
123 String link = html.window.location.hash; 159 String link = html.window.location.hash;
124 var data = {}; 160 var data = {};
125 if (link.length > 2) { 161 if (link.length > 2) {
126 try { 162 try {
127 // strip #! and parse json. 163 // strip #! and parse json.
128 data = JSON.parse(link.substring(2)); 164 data = JSON.parse(link.substring(2));
129 } catch (e) { 165 } catch (e) {
130 html.window.console.error("Invalid link url"); 166 html.window.console.error("Invalid link url");
131 // TODO(jacobr): redirect to default page or better yet attempt to fixup. 167 // TODO(jacobr): redirect to default page or better yet attempt to fixup.
132 } 168 }
133 } 169 }
134 _activeReferenceId = data['id']; 170 _currentReferenceId = data['id'];
135 _recomputeActiveState(); 171 _recomputeActiveState();
136 scrollIntoView(); 172 scrollIntoView();
137 } 173 }
138 174
139 Future loadModel() { 175 Future loadModel() {
140 html.window.on.popState.add((e) { 176 html.window.on.popState.add((e) {
Siggi Cherem (dart-lang) 2012/12/19 19:47:33 in our todomvc sample we had to listen for both po
Siggi Cherem (dart-lang) 2013/01/02 21:40:55 you might have missed this comment...
Jacob 2013/01/03 00:09:33 I did... done :)
141 loadStateFromUrl(); 177 loadStateFromUrl();
142 watchers.dispatch(); 178 watchers.dispatch();
143 }); 179 });
144 180
145 // Patch in support for [:...:]-style code to the markdown parser. 181 // Patch in support for [:...:]-style code to the markdown parser.
146 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? 182 // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
147 md.InlineParser.syntaxes.insertRange(0, 1, 183 md.InlineParser.syntaxes.insertRange(0, 1,
148 new md.CodeSyntax(r'\[\:((?:.|\n)*?)\:\]')); 184 new md.CodeSyntax(r'\[\:((?:.|\n)*?)\:\]'));
149 185
150 md.setImplicitLinkResolver(_resolveNameReference); 186 md.setImplicitLinkResolver(_resolveNameReference);
151 var completer = new Completer(); 187 var completer = new Completer();
152 // TODO(jacobr): shouldn't have to get this from the parent directory. 188 // TODO(jacobr): shouldn't have to get this from the parent directory.
153 new html.HttpRequest.get('../static/apidoc.json', onSuccess(html.HttpRequest r eq) { 189 new html.HttpRequest.get('../static/apidoc.json', (req) {
154 for (var libraryJson in JSON.parse(req.responseText)) { 190 for (var libraryJson in JSON.parse(req.responseText)) {
155 var library = new LibraryElement(libraryJson, null); 191 var library = new LibraryElement(libraryJson, null);
156 libraries[library.id] = library; 192 libraries[library.id] = library;
157 } 193 }
158 onDataModelChanged(); 194 _onDataModelChanged();
159 completer.complete(true); 195 completer.complete(true);
160 }); 196 });
161 return completer.future; 197 return completer.future;
162 } 198 }
163 199
164 /** XXX NOT USED TODO(jacobr) remove. 200 // TODO(jacobr): remove this method and resolve refences to types in the json
165 class DocComment { 201 // generation. That way the existing correct logic in Dart2Js can be used rather
166 final String text; 202 // than this rather busted logic.
167
168 /**
169 * Non-null if the comment is inherited from another declaration.
170 */
171 final inheritedFrom; // InterfaceMirror?
172
173 DocComment(this.text, [this.inheritedFrom = null]) {
174 assert(text != null && !text.trim().isEmpty);
175 }
176
177 SafeHtml get html => new SafeHtml.unsafe(md.markdownToHtml(text));
178
179 String toString() => text;
180 }
181
182 */
183
184 /** 203 /**
185 * This will be called whenever a doc comment hits a `[name]` in square 204 * This will be called whenever a doc comment hits a `[name]` in square
186 * brackets. It will try to figure out what the name refers to and link or 205 * brackets. It will try to figure out what the name refers to and link or
187 * style it appropriately. 206 * style it appropriately.
188 */ 207 */
189 md.Node _resolveNameReference(String name) { 208 md.Node _resolveNameReference(String name) {
190 // TODO(jacobr): this isn't right yet and we have made this code quite ugly 209 // TODO(jacobr): this isn't right yet and we have made this code quite ugly
191 // by using the verbose universal permalink member even though library is 210 // by using the verbose universal permalink member even though library is
192 // always currentLibrary. 211 // always currentLibrary.
193 makeLink(String href) { 212 makeLink(String href) {
194 return new md.Element.text('a', name) 213 return new md.Element.text('a', name)
195 ..attributes['href'] = href 214 ..attributes['href'] = href
196 ..attributes['class'] = 'crossref'; 215 ..attributes['class'] = 'crossref';
197 } 216 }
198 217
199 // See if it's a parameter of the current method. 218 // See if it's a parameter of the current method.
200 if (currentMember != null && currentMember.kind == 'method') { 219 if (currentMember != null && currentMember.kind == 'method') {
201 var parameters = currentMember.children; 220 var parameters = currentMember.children;
202 for (final parameter in parameters) { 221 for (final parameter in parameters) {
203 if (parameter.name == name) { 222 if (parameter.name == name) {
204 final element = new md.Element.text('span', name); 223 final element = new md.Element.text('span', name);
205 element.attributes['class'] = 'param'; 224 element.attributes['class'] = 'param';
206 return element; 225 return element;
207 } 226 }
208 } 227 }
209 } 228 }
210 229
211 // See if it's another member of the current type. 230 // See if it's another member of the current type.
212 // TODO(jacobr): fixme. this is wrong... members are by id now not simple stri ng name... 231 // TODO(jacobr): fixme. this is wrong... members are by id now not simple
232 // string name...
213 if (currentType != null) { 233 if (currentType != null) {
214 final foundMember = currentType.members[name]; 234 final foundMember = currentType.members[name];
215 if (foundMember != null) { 235 if (foundMember != null) {
216 return makeLink(permalink(foundMember)); 236 return makeLink(permalink(foundMember));
217 } 237 }
218 } 238 }
219 239
220 // See if it's another type or a member of another type in the current 240 // See if it's another type or a member of another type in the current
221 // library. 241 // library.
222 if (currentLibrary != null) { 242 if (currentLibrary != null) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 } 281 }
262 } 282 }
263 283
264 // TODO(jacobr): Should also consider: 284 // TODO(jacobr): Should also consider:
265 // * Names imported by libraries this library imports. Don't think we even 285 // * Names imported by libraries this library imports. Don't think we even
266 // store this in the AST. 286 // store this in the AST.
267 // * Type parameters of the enclosing type. 287 // * Type parameters of the enclosing type.
268 288
269 return new md.Element.text('code', name); 289 return new md.Element.text('code', name);
270 } 290 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698