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

Unified Diff: pkg/dartdoc/dropdown.dart

Issue 10829361: 'Find-as-you-type'-search in dartdoc/apidoc. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 8 years, 4 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/dartdoc/dartdoc.dart ('k') | pkg/dartdoc/mirrors/dart2js_mirror.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/dartdoc/dropdown.dart
diff --git a/pkg/dartdoc/dropdown.dart b/pkg/dartdoc/dropdown.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fad4a2f99a4d9ff26f1f2bc2a048ef119d91a65b
--- /dev/null
+++ b/pkg/dartdoc/dropdown.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+List libraryList;
+InputElement searchInput;
+DivElement dropdown;
+
+/**
+ * Update the search drop down based on the current search text.
+ */
+updateDropDown(Event event) {
+ if (libraryList == null) return;
+ if (searchInput == null) return;
+ if (dropdown == null) return;
+
+ var results = <Result>[];
+ String text = searchInput.value;
+ if (text == currentSearchText) {
+ return;
+ }
+ if (text.isEmpty()) {
+ updateResults(text, results);
+ hideDropDown();
+ return;
+ }
+ if (text.contains('.')) {
+ // Search type members.
+ String typeText = text.substring(0, text.indexOf('.'));
+ String memberText = text.substring(text.indexOf('.') + 1);
+
+ if (typeText.isEmpty() && memberText.isEmpty()) {
+ // Don't search on '.'.
+ } else if (typeText.isEmpty()) {
+ // Search text is of the form '.id' => Look up members.
+ matchAllMembers(results, memberText);
+ } else if (memberText.isEmpty()) {
+ // Search text is of the form 'Type.' => Look up members in 'Type'.
+ matchAllMembersInType(results, typeText, memberText);
+ } else {
+ // Search text is of the form 'Type.id' => Look up member 'id' in 'Type'.
+ matchMembersInType(results, text, typeText, memberText);
+ }
+ } else {
+ // Search all entities.
+ var searchText = new SearchText(text);
+ for (Map<String,Dynamic> library in libraryList) {
+ matchLibrary(results, searchText, library);
+ matchLibraryMembers(results, searchText, library);
+ matchTypes(results, searchText, library);
+ }
+ }
+ var elements = <Element>[];
+ var table = new TableElement();
+ table.classes.add('drop-down-table');
+ elements.add(table);
+
+ if (results.isEmpty()) {
+ var row = table.insertRow(0);
+ row.innerHTML = "<tr><td>No matches found for '$text'.</td></tr>";
+ } else {
+ results.sort(resultComparator);
+
+ var count = 0;
+ for (Result result in results) {
+ result.addRow(table);
+ if (++count >= 10) {
+ break;
+ }
+ }
+ if (results.length >= 10) {
+ var row = table.insertRow(table.rows.length);
+ row.innerHTML = '<tr><td>+ ${results.length-10} more.</td></tr>';
+ results = results.getRange(0, 10);
+ }
+ }
+ dropdown.elements = elements;
+ updateResults(text, results);
+ showDropDown();
+}
+
+void matchAllMembers(List<Result> results, String memberText) {
+ var searchText = new SearchText(memberText);
+ for (Map<String,Dynamic> library in libraryList) {
+ String libraryName = library[NAME];
+ if (library.containsKey(TYPES)) {
+ for (Map<String,Dynamic> type in library[TYPES]) {
+ String typeName = type[NAME];
+ if (type.containsKey(MEMBERS)) {
+ for (Map<String,Dynamic> member in type[MEMBERS]) {
+ StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
+ if (memberMatch != null) {
+ results.add(new Result(memberMatch, member[KIND],
+ getTypeMemberUrl(libraryName, typeName, member),
+ library: libraryName, type: typeName, args: type[ARGS]));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void matchAllMembersInType(List<Result> results,
+ String typeText, String memberText) {
+ var searchText = new SearchText(typeText);
+ var emptyText = new SearchText(memberText);
+ for (Map<String,Dynamic> library in libraryList) {
+ String libraryName = library[NAME];
+ if (library.containsKey(TYPES)) {
+ for (Map<String,Dynamic> type in library[TYPES]) {
+ String typeName = type[NAME];
+ StringMatch typeMatch = obtainMatch(searchText, typeName);
+ if (typeMatch != null) {
+ if (type.containsKey(MEMBERS)) {
+ for (Map<String,Dynamic> member in type[MEMBERS]) {
+ StringMatch memberMatch = obtainMatch(emptyText,
+ member[NAME]);
+ results.add(new Result(memberMatch, member[KIND],
+ getTypeMemberUrl(libraryName, typeName, member),
+ library: libraryName, prefix: typeMatch));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void matchMembersInType(List<Result> results,
+ String text, String typeText, String memberText) {
+ var searchText = new SearchText(text);
+ var typeSearchText = new SearchText(typeText);
+ var memberSearchText = new SearchText(memberText);
+ for (Map<String,Dynamic> library in libraryList) {
+ String libraryName = library[NAME];
+ if (library.containsKey(TYPES)) {
+ for (Map<String,Dynamic> type in library[TYPES]) {
+ String typeName = type[NAME];
+ StringMatch typeMatch = obtainMatch(typeSearchText, typeName);
+ if (typeMatch != null) {
+ if (type.containsKey(MEMBERS)) {
+ for (Map<String,Dynamic> member in type[MEMBERS]) {
+ // Check for constructor match.
+ StringMatch constructorMatch = obtainMatch(searchText,
+ member[NAME]);
+ if (constructorMatch != null) {
+ results.add(new Result(constructorMatch, member[KIND],
+ getTypeMemberUrl(libraryName, typeName, member),
+ library: libraryName));
+ } else {
+ // Try member match.
+ StringMatch memberMatch = obtainMatch(memberSearchText,
+ member[NAME]);
+ if (memberMatch != null) {
+ results.add(new Result(memberMatch, member[KIND],
+ getTypeMemberUrl(libraryName, typeName, member),
+ library: libraryName, prefix: typeMatch,
+ args: type[ARGS]));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void matchLibrary(List<Result> results, SearchText searchText, Map library) {
+ String libraryName = library[NAME];
+ StringMatch libraryMatch = obtainMatch(searchText, libraryName);
+ if (libraryMatch != null) {
+ results.add(new Result(libraryMatch, LIBRARY,
+ getLibraryUrl(libraryName)));
+ }
+}
+
+void matchLibraryMembers(List<Result> results, SearchText searchText,
+ Map library) {
+ if (library.containsKey(MEMBERS)) {
+ String libraryName = library[NAME];
+ for (Map<String,Dynamic> member in library[MEMBERS]) {
+ StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
+ if (memberMatch != null) {
+ results.add(new Result(memberMatch, member[KIND],
+ getLibraryMemberUrl(libraryName, member),
+ library: libraryName));
+ }
+ }
+ }
+}
+
+void matchTypes(List<Result> results, SearchText searchText,
+ Map library) {
+ if (library.containsKey(TYPES)) {
+ String libraryName = library[NAME];
+ for (Map<String,Dynamic> type in library[TYPES]) {
+ String typeName = type[NAME];
+ matchType(results, searchText, libraryName, type);
+ matchTypeMembers(results, searchText, libraryName, type);
+ }
+ }
+}
+
+void matchType(List<Result> results, SearchText searchText,
+ String libraryName, Map type) {
+ String typeName = type[NAME];
+ StringMatch typeMatch = obtainMatch(searchText, typeName);
+ if (typeMatch != null) {
+ results.add(new Result(typeMatch, type[KIND],
+ getTypeUrl(libraryName, type),
+ library: libraryName, args: type[ARGS]));
+ }
+}
+
+void matchTypeMembers(List<Result> results, SearchText searchText,
+ String libraryName, Map type) {
+ if (type.containsKey(MEMBERS)) {
+ String typeName = type[NAME];
+ for (Map<String,Dynamic> member in type[MEMBERS]) {
+ StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
+ if (memberMatch != null) {
+ results.add(new Result(memberMatch, member[KIND],
+ getTypeMemberUrl(libraryName, typeName, member),
+ library: libraryName, type: typeName, args: type[ARGS]));
+ }
+ }
+ }
+}
+
+String currentSearchText;
+Result _currentResult;
+List<Result> currentResults = const <Result>[];
+
+void updateResults(String searchText, List<Result> results) {
+ currentSearchText = searchText;
+ currentResults = results;
+ if (currentResults.isEmpty()) {
+ _currentResultIndex = -1;
+ currentResult = null;
+ } else {
+ _currentResultIndex = 0;
+ currentResult = currentResults[0];
+ }
+}
+
+int _currentResultIndex;
+
+void set currentResultIndex(int index) {
+ if (index < -1) {
+ return;
+ }
+ if (index >= currentResults.length) {
+ return;
+ }
+ if (index != _currentResultIndex) {
+ _currentResultIndex = index;
+ if (index >= 0) {
+ currentResult = currentResults[_currentResultIndex];
+ } else {
+ currentResult = null;
+ }
+ }
+}
+
+int get currentResultIndex() => _currentResultIndex;
+
+void set currentResult(Result result) {
+ if (_currentResult != result) {
+ if (_currentResult != null) {
+ _currentResult.row.classes.remove('drop-down-link-select');
+ }
+ _currentResult = result;
+ if (_currentResult != null) {
+ _currentResult.row.classes.add('drop-down-link-select');
+ }
+ }
+}
+
+Result get currentResult() => _currentResult;
+
+/**
+ * Navigate the search drop down using up/down inside the search field. Follow
+ * the result link on enter.
+ */
+void handleUpDown(KeyboardEvent event) {
+ if (event.keyIdentifier == KeyName.UP) {
+ currentResultIndex--;
+ event.preventDefault();
+ } else if (event.keyIdentifier == KeyName.DOWN) {
+ currentResultIndex++;
+ event.preventDefault();
+ } else if (event.keyIdentifier == KeyName.ENTER) {
+ if (currentResult != null) {
+ window.location.href = currentResult.url;
+ event.preventDefault();
+ hideDropDown();
+ }
+ }
+}
+
+/** Show the search drop down unless there are no current results. */
+void showDropDown() {
+ if (currentResults.isEmpty()) {
+ hideDropDown();
+ } else {
+ dropdown.style.visibility = 'visible';
+ }
+}
+
+/** Used to prevent hiding the drop down when it is clicked. */
+bool hideDropDownSuspend = false;
+
+/** Hide the search drop down unless suspended. */
+void hideDropDown() {
+ if (hideDropDownSuspend) return;
+
+ dropdown.style.visibility = 'hidden';
+}
+
+/** Activate search on Ctrl+F and F3. */
+void shortcutHandler(KeyboardEvent event) {
+ if (event.keyCode == 0x46/*F*/ && event.ctrlKey ||
+ event.keyIdentifier == KeyName.F3) {
+ searchInput.focus();
+ event.preventDefault();
+ }
+}
+
+/** Setup search hooks. */
+void setupSearch(var libraries) {
+ libraryList = libraries;
+ searchInput = query('#q');
+ dropdown = query('#drop-down');
+
+ searchInput.on.keyDown.add(handleUpDown);
+ searchInput.on.keyUp.add(updateDropDown);
+ searchInput.on.change.add(updateDropDown);
+ searchInput.on.reset.add(updateDropDown);
+ searchInput.on.focus.add((event) => showDropDown());
+ searchInput.on.blur.add((event) => hideDropDown());
+ window.on.keyDown.add(shortcutHandler);
+}
« no previous file with comments | « pkg/dartdoc/dartdoc.dart ('k') | pkg/dartdoc/mirrors/dart2js_mirror.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698