<!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>[183380] trunk/Websites/webkit.org</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/183380">183380</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-26 20:38:50 -0700 (Sun, 26 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Improve the status page
https://bugs.webkit.org/show_bug.cgi?id=144248

Reviewed by Darin Adler.

* status.html:
Lots of minor changes:
-Add a page title.
-Do not use sync XHR. That was nice for testing but that's eveil
 and it breaks Firefox.
-Start fetching the json files as soon as possible during page load,
 that server takes forever to respond.
-Remove some useless CSS.
-Get rid of mustache. That template thing was awesome but it took
 up to 600ms to fetch the file (plus it is not exactly efficient).
-Put both the specifications and the features in the list.
 They are referencing each other with links. That seems to work pretty well.
-Use the keywords for filtering.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsiteswebkitorgChangeLog">trunk/Websites/webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsiteswebkitorgstatushtml">trunk/Websites/webkit.org/status.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebsiteswebkitorgChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Websites/webkit.org/ChangeLog (183379 => 183380)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/webkit.org/ChangeLog        2015-04-27 02:30:18 UTC (rev 183379)
+++ trunk/Websites/webkit.org/ChangeLog        2015-04-27 03:38:50 UTC (rev 183380)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2015-04-26  Benjamin Poulain  &lt;benjamin@webkit.org&gt;
+
+        Improve the status page
+        https://bugs.webkit.org/show_bug.cgi?id=144248
+
+        Reviewed by Darin Adler.
+
+        * status.html:
+        Lots of minor changes:
+        -Add a page title.
+        -Do not use sync XHR. That was nice for testing but that's eveil
+         and it breaks Firefox.
+        -Start fetching the json files as soon as possible during page load,
+         that server takes forever to respond.
+        -Remove some useless CSS.
+        -Get rid of mustache. That template thing was awesome but it took
+         up to 600ms to fetch the file (plus it is not exactly efficient).
+        -Put both the specifications and the features in the list.
+         They are referencing each other with links. That seems to work pretty well.
+        -Use the keywords for filtering.
+
</ins><span class="cx"> 2015-04-26  Benjamin Poulain  &lt;benjamin@webkit.org&gt;, Chris Bateman  &lt;chrisb808@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Start a basic status page on webkit.org
</span></span></pre></div>
<a id="trunkWebsiteswebkitorgstatushtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/webkit.org/status.html (183379 => 183380)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/webkit.org/status.html        2015-04-27 02:30:18 UTC (rev 183379)
+++ trunk/Websites/webkit.org/status.html        2015-04-27 03:38:50 UTC (rev 183380)
</span><span class="lines">@@ -1,22 +1,52 @@
</span><span class="cx"> &lt;?php
</span><ins>+$title = &quot;Web Platform Status&quot;;
</ins><span class="cx"> $extra_head_content = &lt;&lt;&lt;EOF
</span><del>-&lt;style type=&quot;text/css&quot;&gt;
-p { margin: 0px 0px 4px 0px; }
-&lt;/style&gt;
</del><ins>+&lt;script&gt;
+function xhrPromise(url) {
+    return new Promise(function(resolve, reject) {
+        var xhrRequest = new XMLHttpRequest();
+        xhrRequest.open('GET', url, true);
+        xhrRequest.responseType = &quot;json&quot;;
+
+        xhrRequest.onload = function() {
+            if (xhrRequest.status == 200) {
+                if (xhrRequest.response) {
+                    resolve(xhrRequest.response);
+                } else {
+                    reject({ request: xhrRequest, url:url});
+                }
+            } else {
+                reject({ request: xhrRequest, url:url});
+            }
+        };
+        xhrRequest.onerror = function() {
+            reject({ request: xhrRequest, url:url});
+        };
+        xhrRequest.send();
+    });
+}
+var origin = new URL(&quot;https://svn.webkit.org/&quot;)
+var loadJavaScriptCoreFeatures = xhrPromise(new URL(&quot;/repository/webkit/trunk/Source/JavaScriptCore/features.json&quot;, origin));
+var loadWebCoreFeatures = xhrPromise(new URL(&quot;/repository/webkit/trunk/Source/WebCore/features.json&quot;, origin));
+&lt;/script&gt;
</ins><span class="cx"> EOF;
</span><span class="cx"> include(&quot;header.inc&quot;);
</span><span class="cx"> ?&gt;
</span><del>-
</del><span class="cx"> &lt;style&gt;
</span><span class="cx"> #feature-list {
</span><span class="cx">     margin-top: 2em;
</span><ins>+    word-wrap: break-word;
+    -webkit-text-size-adjust:135%;
</ins><span class="cx"> }
</span><del>-
</del><span class="cx"> #search {
</span><span class="cx">     width: 50%;
</span><span class="cx">     margin-top: 1em;
</span><span class="cx">     margin-bottom: 1em;
</span><span class="cx"> }
</span><ins>+/* Hide the internal links on search since they are unlikely to work. */
+#search:required:valid + *  .internal-reference {
+    display: none;
+}
</ins><span class="cx"> 
</span><span class="cx"> .feature-header {
</span><span class="cx">     display: -webkit-flex;
</span><span class="lines">@@ -24,16 +54,17 @@
</span><span class="cx">     -webkit-flex-direction: row;
</span><span class="cx">     flex-direction: row;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> .feature-header &gt; h3:first-of-type {
</span><span class="cx">     -webkit-flex-grow: 1;
</span><span class="cx">     flex-grow: 1;
</span><ins>+    margin: 0;
+    font-size: 16px;
+    line-height: 1.4em;
+    text-shadow: none;
</ins><span class="cx"> }
</span><del>-
</del><span class="cx"> ul.features {
</span><span class="cx">     padding: 0;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> .feature {
</span><span class="cx">     display: block;
</span><span class="cx">     background: linear-gradient(#fff, #f9f9f9);
</span><span class="lines">@@ -46,30 +77,12 @@
</span><span class="cx"> .feature.is-hidden {
</span><span class="cx">     display: none;
</span><span class="cx"> }
</span><del>-
-.feature-header {
-    display: inline-block;
-    width: 100%;
-    vertical-align: middle;
-}
-.feature-heading {
-    margin: 0;
-    float: left;
-    font-size: 16px;
-    line-height: 1.4em;
-    text-shadow: none;
-}
-.feature-status {
-    float:right;
-}
</del><span class="cx"> .feature-desc {
</span><span class="cx">     margin: 0.4em 0;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> ul.feature-details {
</span><span class="cx">     margin: 0;
</span><span class="cx"> }
</span><del>-
</del><span class="cx"> .feature-statusItem {
</span><span class="cx">     margin-right: .5em;
</span><span class="cx"> }
</span><span class="lines">@@ -80,8 +93,8 @@
</span><span class="cx"> &lt;/div&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;template id=&quot;success-template&quot;&gt;
</span><del>-    &lt;input type=&quot;search&quot; id=&quot;search&quot; placeholder=&quot;Filter&quot; title=&quot;Filter the feature list.&quot;&gt;
-    &lt;ul class=&quot;features&quot; id=&quot;featuresContainer&quot;&gt;&lt;/ul&gt;
</del><ins>+    &lt;input type=&quot;search&quot; id=&quot;search&quot; placeholder=&quot;Filter&quot; title=&quot;Filter the feature list.&quot; required&gt;
+    &lt;ul class=&quot;features&quot; id=&quot;features-container&quot;&gt;&lt;/ul&gt;
</ins><span class="cx">     &lt;p&gt;Cannot find something? You can contact &lt;a href=&quot;https://twitter.com/webkit&quot;&gt;@webkit&lt;/a&gt; on Twitter or contact the &lt;a href=&quot;https://lists.webkit.org/mailman/listinfo/webkit-help&quot;&gt;webkit-help&lt;/a&gt; mailing list for questions.&lt;/p&gt;
</span><span class="cx">     &lt;p&gt;You can also &lt;a href=&quot;http://127.0.0.1:8000/coding/contributing.html&quot;&gt;contribute to features&lt;/a&gt; directly, the entire project is Open Source. To report bugs on existing features or check existing bug reports, see &lt;a href=&quot;https://bugs.webkit.org&quot;&gt;https://bugs.webkit.org&lt;/a&gt;.&lt;/p&gt;
</span><span class="cx"> &lt;/template&gt;
</span><span class="lines">@@ -90,40 +103,6 @@
</span><span class="cx">     &lt;p&gt;If this is not resolved soon, please contact &lt;a href=&quot;https://twitter.com/webkit&quot;&gt;@webkit&lt;/a&gt; on Twitter or the &lt;a href=&quot;https://lists.webkit.org/mailman/listinfo/webkit-help&quot;&gt;webkit-help&lt;/a&gt; mailing list.&lt;/p&gt;
</span><span class="cx"> &lt;/template&gt;
</span><span class="cx"> 
</span><del>-&lt;script id=&quot;template&quot; type=&quot;x-tmpl-mustache&quot;&gt;
-{{#features}}
-    &lt;li class=&quot;feature&quot;&gt;
-        &lt;div class=&quot;feature-header&quot;&gt;
-            &lt;div class=&quot;feature-header&quot;&gt;
-                &lt;h3 class=&quot;feature-heading&quot;&gt;{{name}}&lt;/h3&gt;
-                &lt;strong class=&quot;feature-status&quot;&gt;Status: {{#webkit-url}}&lt;a href=&quot;{{webkit-url}}&quot;&gt;{{/webkit-url}}{{status.status}}{{#webkit-url}}&lt;/a&gt;{{/webkit-url}}&lt;/strong&gt;
-            &lt;/div&gt;
-            {{#description}}
-                &lt;p class=&quot;feature-desc&quot;&gt;{{description}}&lt;/p&gt;
-            {{/description}}
-            {{#comment}}
-            &lt;p&gt;Comment: {{comment}}&lt;/p&gt;
-            {{/comment}}
-        &lt;/div&gt;
-        &lt;ul class=&quot;feature-details&quot;&gt;
-            {{#documentation-url}}
-                 &lt;li&gt;Documentation: &lt;a href=&quot;{{documentation-url}}&quot;&gt;{{documentation-url}}&lt;/a&gt;&lt;/li&gt;
-            {{/documentation-url}}
-            {{#url}}
-                &lt;li&gt;More Info: &lt;a href=&quot;{{url}}&quot;&gt;{{url}}&lt;/a&gt;&lt;/li&gt;
-            {{/url}}
-            {{#contact}}
-                &lt;li&gt;Contact:
-                    {{#twitter}} &lt;a href=&quot;https://twitter.com/{{twitter}}&quot;&gt;{{twitter}}&lt;/a&gt;{{/twitter}}
-                    {{#email}}&lt;a href=&quot;mailto:{{email}}&quot;&gt;{{name}}&lt;/a&gt;{{/email}}
-                &lt;/li&gt;
-            {{/contact}}
-        &lt;/ul&gt;
-    &lt;/li&gt;
-{{/features}}
-&lt;/script&gt;
-
-&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js&quot;&gt;&lt;/script&gt;
</del><span class="cx"> &lt;script&gt;
</span><span class="cx"> function initializeStatusPage() {
</span><span class="cx">     function sortAlphabetically(array) {
</span><span class="lines">@@ -141,16 +120,149 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function renderFeatures(features) {
-        var template = document.getElementById('template').innerHTML;
-        
-        var rendered = Mustache.render(template, {
-            features: features
-        });
-        
-        document.getElementById('featuresContainer').innerHTML = rendered;
</del><ins>+    function createFeatureView(featureObject) {
+        function createLinkWithHeading(elementName, heading, linkText, linkUrl) {
+            var container = document.createElement(elementName);
+            if (heading) {
+                container.textContent = heading + &quot;: &quot;;
+            }
+            var link = document.createElement(&quot;a&quot;);
+            link.textContent = linkText;
+            link.href = linkUrl;
+            container.appendChild(link);
+            return container;
+        }
+
+        var container = document.createElement('li');
+        container.className = &quot;feature&quot;;
+
+        if (&quot;features&quot; in featureObject) {
+            container.setAttribute(&quot;id&quot;, &quot;specification-&quot; + featureObject.name);
+        } else {
+            container.setAttribute(&quot;id&quot;, &quot;feature-&quot; + featureObject.name);
+        }
+
+        var descriptionContainer = document.createElement('div');
+        descriptionContainer.className = &quot;feature-description&quot;;
+
+        var featureHeaderContainer = document.createElement('div');
+        featureHeaderContainer.className = &quot;feature-header&quot;;
+        descriptionContainer.appendChild(featureHeaderContainer);
+
+        var titleElement = document.createElement(&quot;h3&quot;);
+        titleElement.textContent = featureObject.name;
+        featureHeaderContainer.appendChild(titleElement);
+
+        if (&quot;status&quot; in featureObject) {
+            var statusContainer = document.createElement(&quot;span&quot;);
+            statusContainer.className = &quot;feature-status&quot;;
+            if (&quot;webkit-url&quot; in featureObject) {
+                statusContainer.textContent = &quot;Status: &quot;;
+                var statusLink = document.createElement(&quot;a&quot;);
+                statusLink.href = featureObject[&quot;webkit-url&quot;];
+                statusLink.textContent = featureObject.status.status;
+                statusContainer.appendChild(statusLink);
+            } else {
+                statusContainer.textContent = &quot;Status: &quot; + featureObject.status.status;
+            }
+
+            featureHeaderContainer.appendChild(statusContainer);
+        }
+
+        if (&quot;description&quot; in featureObject) {
+            var testDescription = document.createElement('p');
+            testDescription.className = &quot;feature-desc&quot;;
+            testDescription.innerHTML = featureObject.description;
+            descriptionContainer.appendChild(testDescription);
+        }
+
+        if (&quot;comment&quot; in featureObject) {
+            if (&quot;description&quot; in featureObject) {
+                descriptionContainer.appendChild(document.createElement(&quot;hr&quot;));
+            }
+            var comment = document.createElement('p');
+            comment.innerHTML = featureObject.comment;
+            descriptionContainer.appendChild(comment);
+        }
+
+        container.appendChild(descriptionContainer);
+
+        var hasDocumentationLink = &quot;documentation-url&quot; in featureObject;
+        var hasReferenceLink = &quot;url&quot; in featureObject;
+        var hasContactObject = &quot;contact&quot; in featureObject;
+        var hasSpecificationObject = &quot;specification&quot; in featureObject;
+        if (hasDocumentationLink || hasReferenceLink || hasContactObject) {
+            var moreInfoList = document.createElement(&quot;ul&quot;);
+            if (hasDocumentationLink) {
+                var url = featureObject[&quot;documentation-url&quot;];
+                moreInfoList.appendChild(createLinkWithHeading(&quot;li&quot;, &quot;Documentation&quot;, url, url));
+            }
+
+            if (hasReferenceLink) {
+                var url = featureObject.url;
+                moreInfoList.appendChild(createLinkWithHeading(&quot;li&quot;, &quot;Reference&quot;, url, url));
+            }
+
+            if (hasSpecificationObject) {
+                var specification = featureObject.specification;
+                var li = createLinkWithHeading(&quot;li&quot;, &quot;Parent feature&quot;, specification.name, (&quot;#specification-&quot; + specification.name));
+                li.className = &quot;internal-reference&quot;;
+                moreInfoList.appendChild(li);
+            }
+
+            if (hasContactObject) {
+                var li = document.createElement(&quot;li&quot;);
+                li.textContent = &quot;Contact: &quot;;
+                if (featureObject.contact.twitter) {
+                    li.appendChild(createLinkWithHeading(&quot;span&quot;, null, featureObject.contact.twitter, featureObject.contact.twitter));
+                }
+                if (featureObject.contact.email) {
+                    if (featureObject.contact.twitter) {
+                        li.appendChild(document.createTextNode(&quot; - &quot;));
+                    }
+                    var emailText = featureObject.contact.email;
+                    if (featureObject.contact.name) {
+                        emailText = featureObject.contact.name;
+                    }
+                    li.appendChild(createLinkWithHeading(&quot;span&quot;, null, emailText, featureObject.contact.email));
+                }
+                moreInfoList.appendChild(li);
+            }
+
+            container.appendChild(moreInfoList);
+        }
+
+        if (&quot;features&quot; in featureObject &amp;&amp; featureObject.features.length) {
+            var internalLinkContainer = document.createElement(&quot;div&quot;);
+            internalLinkContainer.className = &quot;internal-reference&quot;;
+            var trackedFeatures = document.createElement(&quot;p&quot;);
+            trackedFeatures.textContent = &quot;Subfeatures: &quot;;
+            internalLinkContainer.appendChild(trackedFeatures);
+
+            var list = document.createElement(&quot;ul&quot;);
+            for (var feature of featureObject.features) {
+                var link = document.createElement(&quot;a&quot;);
+                link.textContent = feature.name;
+                link.href = &quot;#feature-&quot; + feature.name;
+
+                var li = document.createElement(&quot;li&quot;);
+                li.appendChild(link);
+                list.appendChild(li);
+            }
+            internalLinkContainer.appendChild(list);
+            container.appendChild(internalLinkContainer);
+        }
+
+        return container;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    function renderFeaturesAndSpecifications(featureLikeObjects) {
+        var featureContainer = document.getElementById('features-container');
+        for (var featureLikeObject of featureLikeObjects) {
+            featureContainer.appendChild(createFeatureView(featureLikeObject));
+        }
+    }
+
</ins><span class="cx">     function initSearch(featuresArray) {
</span><span class="cx">         var inputField = document.getElementById('search');
</span><span class="cx">         var featuresEls = document.querySelectorAll('.features &gt; li');
</span><span class="lines">@@ -183,7 +295,15 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function isSearchMatch(feature, searchTerm) {
</span><del>-        return feature.name.toLowerCase().indexOf(searchTerm) !== -1;
</del><ins>+        if (feature.name.toLowerCase().indexOf(searchTerm) !== -1)
+            return true;
+        if (&quot;keywords&quot; in feature) {
+            for (var keyword of feature.keywords) {
+                if (keyword.toLowerCase().indexOf(searchTerm) !== -1)
+                    return true;
+            }
+        }
+        return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function displayFeatures(results)
</span><span class="lines">@@ -192,13 +312,36 @@
</span><span class="cx">         var successSubtree = document.importNode(document.getElementById(&quot;success-template&quot;).content, true);
</span><span class="cx">         mainContent.appendChild(successSubtree);
</span><span class="cx"> 
</span><ins>+        var allSpecifications = [];
+        for (var i in results) {
+            allSpecifications = allSpecifications.concat(results[i].specification);
+        }
+        var specificationsByName = {}
+        for (var specification of allSpecifications) {
+            specification.features = [];
+            specification.isSpecification = true;
+            specificationsByName[specification.name] = specification;
+        }
+
</ins><span class="cx">         var allFeatures = [];
</span><span class="cx">         for (var i in results) {
</span><span class="cx">             allFeatures = allFeatures.concat(results[i].features);
</span><span class="cx">         }
</span><del>-        sortAlphabetically(allFeatures);
-        renderFeatures(allFeatures);
-        initSearch(allFeatures);
</del><ins>+        var featuresByName = {};
+        for (var feature of allFeatures) {
+            if ('specification' in feature) {
+                var specificationObject = specificationsByName[feature.specification];
+                specificationObject.features.push(feature);
+                feature.specification = specificationObject;
+            }
+            feature.isSpecification = false;
+            featuresByName[feature.name] = feature;
+        }
+
+        var everythingToShow = allFeatures.concat(allSpecifications);
+        sortAlphabetically(everythingToShow);
+        renderFeaturesAndSpecifications(everythingToShow);
+        initSearch(everythingToShow);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function displayError(error)
</span><span class="lines">@@ -219,32 +362,6 @@
</span><span class="cx">         mainContent.appendChild(successSubtree);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function xhrPromise(url) {
-        return new Promise(function(resolve, reject) {
-            var xhrRequest = new XMLHttpRequest();
-            xhrRequest.responseType = &quot;json&quot;;
-            xhrRequest.open('GET', url);
-
-            xhrRequest.onload = function() {
-                if (xhrRequest.status == 200) {
-                    if (xhrRequest.response) {
-                        resolve(xhrRequest.response);
-                    } else {
-                        reject({ request: xhrRequest, url:url});
-                    }
-                } else {
-                    reject({ request: xhrRequest, url:url});
-                }
-            };
-            xhrRequest.onerror = function() {
-                reject({ request: xhrRequest, url:url});
-            };
-            xhrRequest.send();
-        });
-    }
-
-    var loadJavaScriptCoreFeatures = xhrPromise(&quot;https://svn.webkit.org/repository/webkit/trunk/Source/JavaScriptCore/features.json&quot;);
-    var loadWebCoreFeatures = xhrPromise(&quot;https://svn.webkit.org/repository/webkit/trunk/Source/WebCore/features.json&quot;);
</del><span class="cx">     Promise.all([loadJavaScriptCoreFeatures, loadWebCoreFeatures]).then(displayFeatures).catch(displayError);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>