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

Unified Diff: chrome/browser/resources/options/search_page.js

Issue 6141002: dom-ui settings: display bubbles for sub-page search results.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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 | « chrome/browser/resources/options/search_page.css ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/options/search_page.js
===================================================================
--- chrome/browser/resources/options/search_page.js (revision 72214)
+++ chrome/browser/resources/options/search_page.js (working copy)
@@ -6,6 +6,77 @@
const OptionsPage = options.OptionsPage;
/**
+ * Encapsulated handling of a search bubble.
+ * @constructor
+ */
+ function SearchBubble(text) {
+ var el = cr.doc.createElement('div');
+ SearchBubble.decorate(el);
+ el.textContent = text;
+ return el;
+ }
+
+ SearchBubble.decorate = function(el) {
+ el.__proto__ = SearchBubble.prototype;
+ el.decorate();
+ };
+
+ SearchBubble.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ decorate: function() {
+ this.className = 'search-bubble';
+
+ // We create a timer to periodically update the position of the bubbles.
+ // While this isn't all that desirable, it's the only sure-fire way of
+ // making sure the bubbles stay in the correct location as sections
+ // may dynamically change size at any time.
+ var self = this;
+ this.intervalId = setInterval(this.updatePosition.bind(this), 250);
+ },
+
+ /**
+ * Clear the interval timer and remove the element from the page.
+ */
+ dispose: function() {
+ clearInterval(this.intervalId);
+
+ var parent = this.parentNode;
+ if (parent)
+ parent.removeChild(this);
+ },
+
+ /**
+ * Update the position of the bubble. Called at creation time and then
+ * periodically while the bubble remains visible.
+ */
+ updatePosition: function() {
+ // This bubble is 'owned' by the next sibling.
+ var owner = this.nextSibling;
+
+ // If there isn't an offset parent, we have nothing to do.
+ if (!owner.offsetParent)
+ return;
+
+ // Position the bubble below the location of the owner.
+ var left = owner.offsetLeft + owner.offsetWidth / 2 -
+ this.offsetWidth / 2;
+ var top = owner.offsetTop + owner.offsetHeight;
+
+ // Update the position in the CSS. Cache the last values for
+ // best performance.
+ if (left != this.lastLeft) {
+ this.style.left = left + 'px';
+ this.lastLeft = left;
+ }
+ if (top != this.lastTop) {
+ this.style.top = top + 'px';
+ this.lastTop = top;
+ }
+ }
+ }
+
+ /**
* Encapsulated handling of the search page.
* @constructor
*/
@@ -108,17 +179,12 @@
// Update the visible state of all top-level elements that are not
// sections (ie titles, button strips). We do this before changing
// the page visibility to avoid excessive re-draw.
- var length = page.pageDiv.childNodes.length;
- var childDiv;
- for (var i = 0; i < length; i++) {
- childDiv = page.pageDiv.childNodes[i];
- if (childDiv.nodeType == document.ELEMENT_NODE) {
- if (active) {
- if (childDiv.nodeName.toLowerCase() != 'section')
- childDiv.classList.add('search-hidden');
- } else {
- childDiv.classList.remove('search-hidden');
- }
+ for (var i = 0, childDiv; childDiv = page.pageDiv.children[i]; i++) {
+ if (active) {
+ if (childDiv.tagName != 'SECTION')
+ childDiv.classList.add('search-hidden');
+ } else {
+ childDiv.classList.remove('search-hidden');
}
}
@@ -129,9 +195,11 @@
}
}
- // After hiding all page content, remove any highlighted matches.
- if (!active)
+ // After hiding all page content, remove any search results.
+ if (!active) {
this.unhighlightMatches_();
+ this.removeSearchBubbles_();
+ }
},
/**
@@ -141,9 +209,11 @@
*/
setSearchText_: function(text) {
var foundMatches = false;
+ var bubbleControls = [];
- // Remove any highlighted matches.
+ // Remove any prior search results.
this.unhighlightMatches_();
+ this.removeSearchBubbles_();
// Generate search text by applying lowercase and escaping any characters
// that would be problematic for regular expressions.
@@ -157,7 +227,7 @@
// Initialize all sections. If the search string matches a title page,
// show sections for that page.
- var page, pageMatch, childDiv;
+ var page, pageMatch, childDiv, length;
var pagesToSearch = this.getSearchablePages_();
for (var key in pagesToSearch) {
page = pagesToSearch[key];
@@ -167,10 +237,8 @@
}
if (pageMatch)
foundMatches = true;
- for (var i = 0; i < page.pageDiv.childNodes.length; i++) {
- childDiv = page.pageDiv.childNodes[i];
- if (childDiv.nodeType == document.ELEMENT_NODE &&
- childDiv.nodeName == 'SECTION') {
+ for (var i = 0, childDiv; childDiv = page.pageDiv.children[i]; i++) {
+ if (childDiv.tagName == 'SECTION') {
if (pageMatch) {
childDiv.classList.remove('search-hidden');
} else {
@@ -181,6 +249,18 @@
}
if (searchText.length) {
+ // Search all top-level sections for anchored string matches.
+ for (var key in pagesToSearch) {
+ page = pagesToSearch[key];
+ for (var i = 0, childDiv; childDiv = page.pageDiv.children[i]; i++) {
+ if (childDiv.tagName == 'SECTION' &&
+ this.performReplace_(regEx, replaceString, childDiv)) {
+ childDiv.classList.remove('search-hidden');
+ foundMatches = true;
+ }
+ }
+ }
+
// Search all sub-pages, generating an array of top-level sections that
// we need to make visible.
var subPagesToSearch = this.getSearchableSubPages_();
@@ -188,31 +268,22 @@
for (var key in subPagesToSearch) {
page = subPagesToSearch[key];
if (this.performReplace_(regEx, replaceString, page.pageDiv)) {
+ // Reveal the section for this search result.
section = page.associatedSection;
if (section)
section.classList.remove('search-hidden');
- controls = page.associatedControls;
+
+ // Identify any controls that should have bubbles.
+ var controls = page.associatedControls;
if (controls) {
- // TODO(csilv): highlight each control.
+ length = controls.length;
+ for (var i = 0; i < length; i++)
+ bubbleControls.push(controls[i]);
}
foundMatches = true;
}
}
-
- // Search all top-level sections for anchored string matches.
- for (var key in pagesToSearch) {
- page = pagesToSearch[key];
- for (var i = 0; i < page.pageDiv.childNodes.length; i++) {
- childDiv = page.pageDiv.childNodes[i];
- if (childDiv.nodeType == document.ELEMENT_NODE &&
- childDiv.nodeName == 'SECTION' &&
- this.performReplace_(regEx, replaceString, childDiv)) {
- childDiv.classList.remove('search-hidden');
- foundMatches = true;
- }
- }
- }
}
// Configure elements on the search results page based on search results.
@@ -226,6 +297,11 @@
$('searchPageInfo').classList.add('search-hidden');
$('searchPageNoMatches').classList.remove('search-hidden');
}
+
+ // Create search balloons for sub-page results.
+ length = bubbleControls.length;
+ for (var i = 0; i < length; i++)
+ this.createSearchBubble_(bubbleControls[i], text);
},
/**
@@ -288,9 +364,8 @@
var elements = document.querySelectorAll('.search-highlighted');
// For each element, remove the highlighting.
- var node, parent, i, length = elements.length;
- for (i = 0; i < length; i++) {
- node = elements[i];
+ var parent, i;
+ for (var i = 0, node; node = elements[i]; i++) {
parent = node.parentNode;
// Replace the highlight element with the first child (the text node).
@@ -302,6 +377,37 @@
},
/**
+ * Creates a search result bubble attached to an element.
+ * @param {Element} element An HTML element, usually a button.
+ * @param {string} text A string to show in the bubble.
+ * @private
+ */
+ createSearchBubble_: function(element, text) {
+ // avoid appending multiple ballons to a button.
+ var sibling = element.previousElementSibling;
+ if (sibling && sibling.classList.contains('search-bubble'))
+ return;
+
+ var parent = element.parentElement;
+ if (parent) {
+ var bubble = new SearchBubble(text);
+ parent.insertBefore(bubble, element);
+ bubble.updatePosition();
+ }
+ },
+
+ /**
+ * Removes all search match bubbles.
+ * @private
+ */
+ removeSearchBubbles_: function() {
+ var elements = document.querySelectorAll('.search-bubble');
+ var length = elements.length;
+ for (var i = 0; i < length; i++)
+ elements[i].dispose();
+ },
+
+ /**
* Builds a list of top-level pages to search. Omits the search page and
* all sub-pages.
* @returns {Array} An array of pages to search.
« no previous file with comments | « chrome/browser/resources/options/search_page.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698