<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[37288] trunk/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/37288">37288</a></dd>
<dt>Author</dt> <dd>timothy@apple.com</dd>
<dt>Date</dt> <dd>2008-10-04 01:09:52 -0700 (Sat, 04 Oct 2008)</dd>
</dl>

<h3>Log Message</h3>
<pre>        Adds support to the Web Inspector's Elements panel for fast tag name,
        class name, id and attribute name searching. The panel first tries
        using getElementById, getElementsByClassName and getElementsByTagName
        with the search query. Then does a slower search using XPath for partial
        matches, text and comment matches.

        Adds support for search queries like &quot;&lt;div&gt;&quot;, &quot;&lt;h&quot; and &quot;frame&gt;&quot;.
        These forms limit the search to tag names, text and comment matches.

        https://bugs.webkit.org/show_bug.cgi?id=21353

        Reviewed by Maciej Stachowiak.

        * page/inspector/ElementsPanel.js:
        (WebInspector.ElementsPanel.prototype.performSearch): Add tag syntax
        support. Add new search functions that try exact matches first.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebCoreChangeLog">trunk/WebCore/ChangeLog</a></li>
<li><a href="#trunkWebCorepageinspectorElementsPaneljs">trunk/WebCore/page/inspector/ElementsPanel.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/ChangeLog (37287 => 37288)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ChangeLog        2008-10-04 08:09:41 UTC (rev 37287)
+++ trunk/WebCore/ChangeLog        2008-10-04 08:09:52 UTC (rev 37288)
</span><span class="lines">@@ -1,5 +1,24 @@
</span><span class="cx"> 2008-10-03  Timothy Hatcher  &lt;timothy@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Adds support to the Web Inspector's Elements panel for fast tag name,
+        class name, id and attribute name searching. The panel first tries
+        using getElementById, getElementsByClassName and getElementsByTagName
+        with the search query. Then does a slower search using XPath for partial
+        matches, text and comment matches.
+
+        Adds support for search queries like &quot;&lt;div&gt;&quot;, &quot;&lt;h&quot; and &quot;frame&gt;&quot;.
+        These forms limit the search to tag names, text and comment matches.
+
+        https://bugs.webkit.org/show_bug.cgi?id=21353
+
+        Reviewed by Maciej Stachowiak.
+
+        * page/inspector/ElementsPanel.js:
+        (WebInspector.ElementsPanel.prototype.performSearch): Add tag syntax
+        support. Add new search functions that try exact matches first.
+
+2008-10-03  Timothy Hatcher  &lt;timothy@apple.com&gt;
+
</ins><span class="cx">         Changes how searching works in the Web Inspector's Elements
</span><span class="cx">         panel. The search tasks are divided into chunks that are small
</span><span class="cx">         units of work that are performed at a time interval. This
</span></span></pre></div>
<a id="trunkWebCorepageinspectorElementsPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/page/inspector/ElementsPanel.js (37287 => 37288)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/page/inspector/ElementsPanel.js        2008-10-04 08:09:41 UTC (rev 37287)
+++ trunk/WebCore/page/inspector/ElementsPanel.js        2008-10-04 08:09:52 UTC (rev 37288)
</span><span class="lines">@@ -255,7 +255,26 @@
</span><span class="cx">         if (!whitespaceTrimmedQuery.length)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><ins>+        var tagNameQuery = whitespaceTrimmedQuery;
+        var attributeNameQuery = whitespaceTrimmedQuery;
+        var startTagFound = (tagNameQuery.indexOf(&quot;&lt;&quot;) === 0);
+        var endTagFound = (tagNameQuery.lastIndexOf(&quot;&gt;&quot;) === (tagNameQuery.length - 1));
+
+        if (startTagFound || endTagFound) {
+            var tagNameQueryLength = tagNameQuery.length;
+            tagNameQuery = tagNameQuery.substring((startTagFound ? 1 : 0), (endTagFound ? (tagNameQueryLength - 1) : tagNameQueryLength));
+        }
+
+        // Check the tagNameQuery is it is a possibly valid tag name.
+        if (!/^[a-zA-Z0-9\-_:]+$/.test(tagNameQuery))
+            tagNameQuery = null;
+
+        // Check the attributeNameQuery is it is a possibly valid tag name.
+        if (!/^[a-zA-Z0-9\-_:]+$/.test(attributeNameQuery))
+            attributeNameQuery = null;
+
</ins><span class="cx">         const escapedQuery = query.escapeCharacters(&quot;'&quot;);
</span><ins>+        const escapedTagNameQuery = (tagNameQuery ? tagNameQuery.escapeCharacters(&quot;'&quot;) : null);
</ins><span class="cx">         const escapedWhitespaceTrimmedQuery = whitespaceTrimmedQuery.escapeCharacters(&quot;'&quot;);
</span><span class="cx">         const searchResultsProperty = this.includedInSearchResultsPropertyName;
</span><span class="cx"> 
</span><span class="lines">@@ -308,9 +327,66 @@
</span><span class="cx">             updateMatchesCountSoon.call(this);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        function matchExactItems(doc)
+        {
+            matchExactId.call(this, doc);
+            matchExactClassNames.call(this, doc);
+            matchExactTagNames.call(this, doc);
+            matchExactAttributeNames.call(this, doc);
+        }
+
+        function matchExactId(doc)
+        {
+            const result = doc.__proto__.getElementById.call(doc, whitespaceTrimmedQuery);
+            addNodesToResults.call(this, result, (result ? 1 : 0), function() { return this });
+        }
+
+        function matchExactClassNames(doc)
+        {
+            const result = doc.__proto__.getElementsByClassName.call(doc, whitespaceTrimmedQuery);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchExactTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.getElementsByTagName.call(doc, tagNameQuery);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchExactAttributeNames(doc)
+        {
+            if (!attributeNameQuery)
+                return;
+            const result = doc.__proto__.querySelectorAll.call(doc, &quot;[&quot; + attributeNameQuery + &quot;]&quot;);
+            addNodesToResults.call(this, result, result.length, result.item);
+        }
+
+        function matchPartialTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.evaluate.call(doc, &quot;//*[contains(name(), '&quot; + escapedTagNameQuery + &quot;')]&quot;, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
+        function matchStartOfTagNames(doc)
+        {
+            if (!tagNameQuery)
+                return;
+            const result = doc.__proto__.evaluate.call(doc, &quot;//*[starts-with(name(), '&quot; + escapedTagNameQuery + &quot;')]&quot;, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
+            addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
+        }
+
</ins><span class="cx">         function matchPartialTagNamesAndAttributeValues(doc)
</span><span class="cx">         {
</span><del>-            const result = doc.__proto__.evaluate.call(doc, &quot;//*[contains(name(), '&quot; + escapedWhitespaceTrimmedQuery + &quot;') or contains(@*, '&quot; + escapedQuery + &quot;')]&quot;, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
</del><ins>+            if (!tagNameQuery) {
+                matchPartialAttributeValues.call(this, doc);
+                return;
+            }
+
+            const result = doc.__proto__.evaluate.call(doc, &quot;//*[contains(name(), '&quot; + escapedTagNameQuery + &quot;') or contains(@*, '&quot; + escapedQuery + &quot;')]&quot;, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
</ins><span class="cx">             addNodesToResults.call(this, result, result.snapshotLength, result.snapshotItem);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -348,12 +424,20 @@
</span><span class="cx">         const mainFrameDocument = InspectorController.inspectedWindow().document;
</span><span class="cx">         const searchDocuments = [mainFrameDocument];
</span><span class="cx"> 
</span><del>-        if (whitespaceTrimmedQuery === &quot;//*&quot; || whitespaceTrimmedQuery === &quot;*&quot;) {
</del><ins>+        if (tagNameQuery &amp;&amp; startTagFound &amp;&amp; endTagFound)
+            const searchFunctions = [matchExactTagNames, matchPlainText];
+        else if (tagNameQuery &amp;&amp; startTagFound)
+            const searchFunctions = [matchStartOfTagNames, matchPlainText];
+        else if (tagNameQuery &amp;&amp; endTagFound) {
+            // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
+            // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
+            const searchFunctions = [matchPartialTagNames, matchPlainText];
+        } else if (whitespaceTrimmedQuery === &quot;//*&quot; || whitespaceTrimmedQuery === &quot;*&quot;) {
</ins><span class="cx">             // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
</span><span class="cx">             // so limit the search functions list to plain text and attribute matching.
</span><span class="cx">             const searchFunctions = [matchPartialAttributeValues, matchPlainText];
</span><span class="cx">         } else
</span><del>-            const searchFunctions = [matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery];
</del><ins>+            const searchFunctions = [matchExactItems, matchStyleSelector, matchPartialTagNamesAndAttributeValues, matchPlainText, matchXPathQuery];
</ins><span class="cx"> 
</span><span class="cx">         // Find all frames, iframes and object elements to search their documents.
</span><span class="cx">         const querySelectorAllFunction = InspectorController.inspectedWindow().Document.prototype.querySelectorAll;
</span></span></pre>
</div>
</div>

</body>
</html>