blob: 31a2281c007462f912fb4abf3f12a296297382bc [file] [log] [blame]
<?php
$title = "Web Platform Status";
$extra_head_content = <<<EOF
<script>
function xhrPromise(url) {
return new Promise(function(resolve, reject) {
var xhrRequest = new XMLHttpRequest();
xhrRequest.open('GET', url, true);
xhrRequest.responseType = "json";
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("https://svn.webkit.org/")
var loadJavaScriptCoreFeatures = xhrPromise(new URL("/repository/webkit/trunk/Source/JavaScriptCore/features.json", origin));
var loadWebCoreFeatures = xhrPromise(new URL("/repository/webkit/trunk/Source/WebCore/features.json", origin));
</script>
EOF;
include("header.inc");
?>
<style>
#feature-list {
margin-top: 2em;
word-wrap: break-word;
-webkit-text-size-adjust:135%;
}
#search {
width: 50%;
margin-top: 1em;
margin-bottom: 1em;
}
/* Hide the internal links on search since they are unlikely to work. */
#search:required:valid + * .internal-reference {
display: none;
}
.feature-header {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.feature-header > h3:first-of-type {
-webkit-flex-grow: 1;
flex-grow: 1;
margin: 0;
font-size: 16px;
line-height: 1.4em;
text-shadow: none;
}
ul.features {
padding: 0;
}
.feature {
display: block;
background: linear-gradient(#fff, #f9f9f9);
border: 1px solid #bbb;
border-radius: 5px;
padding: 1em;
margin: 1em 0 !important;
}
.feature.is-hidden {
display: none;
}
.feature-desc {
margin: 0.4em 0;
}
ul.feature-details {
margin: 0;
}
.feature-statusItem {
margin-right: .5em;
}
</style>
<h2>WebKit Web Platform Status</h2>
<div id="feature-list">
</div>
<template id="success-template">
<input type="search" id="search" placeholder="Filter" title="Filter the feature list." required>
<ul class="features" id="features-container"></ul>
<p>Cannot find something? You can contact <a href="https://twitter.com/webkit">@webkit</a> on Twitter or contact the <a href="https://lists.webkit.org/mailman/listinfo/webkit-help">webkit-help</a> mailing list for questions.</p>
<p>You can also <a href="coding/contributing.html">contribute to features</a> directly, the entire project is Open Source. To report bugs on existing features or check existing bug reports, see <a href="https://bugs.webkit.org">https://bugs.webkit.org</a>.</p>
</template>
<template id="error-template">
<p>Error: unable to load the features list (<span id="error-message"></span>).</p>
<p>If this is not resolved soon, please contact <a href="https://twitter.com/webkit">@webkit</a> on Twitter or the <a href="https://lists.webkit.org/mailman/listinfo/webkit-help">webkit-help</a> mailing list.</p>
</template>
<script>
function initializeStatusPage() {
function sortAlphabetically(array) {
array.sort(function(a, b){
var aName = a.name.toLocaleLowerCase();
var bName = b.name.toLocaleLowerCase();
if (aName < bName) {
return -1;
}
if (aName > bName) {
return 1;
}
return 0;
});
}
function createFeatureView(featureObject) {
function createLinkWithHeading(elementName, heading, linkText, linkUrl) {
var container = document.createElement(elementName);
if (heading) {
container.textContent = heading + ": ";
}
var link = document.createElement("a");
link.textContent = linkText;
link.href = linkUrl;
container.appendChild(link);
return container;
}
var container = document.createElement('li');
container.className = "feature";
if ("features" in featureObject) {
container.setAttribute("id", "specification-" + featureObject.name);
} else {
container.setAttribute("id", "feature-" + featureObject.name);
}
var descriptionContainer = document.createElement('div');
descriptionContainer.className = "feature-description";
var featureHeaderContainer = document.createElement('div');
featureHeaderContainer.className = "feature-header";
descriptionContainer.appendChild(featureHeaderContainer);
var titleElement = document.createElement("h3");
titleElement.textContent = featureObject.name;
featureHeaderContainer.appendChild(titleElement);
if ("status" in featureObject) {
var statusContainer = document.createElement("span");
statusContainer.className = "feature-status";
if ("webkit-url" in featureObject) {
statusContainer.textContent = "Status: ";
var statusLink = document.createElement("a");
statusLink.href = featureObject["webkit-url"];
statusLink.textContent = featureObject.status.status;
statusContainer.appendChild(statusLink);
} else {
statusContainer.textContent = "Status: " + featureObject.status.status;
}
featureHeaderContainer.appendChild(statusContainer);
}
if ("description" in featureObject) {
var testDescription = document.createElement('p');
testDescription.className = "feature-desc";
testDescription.innerHTML = featureObject.description;
descriptionContainer.appendChild(testDescription);
}
if ("comment" in featureObject) {
if ("description" in featureObject) {
descriptionContainer.appendChild(document.createElement("hr"));
}
var comment = document.createElement('p');
comment.innerHTML = featureObject.comment;
descriptionContainer.appendChild(comment);
}
container.appendChild(descriptionContainer);
var hasDocumentationLink = "documentation-url" in featureObject;
var hasReferenceLink = "url" in featureObject;
var hasContactObject = "contact" in featureObject;
var hasSpecificationObject = "specification" in featureObject;
if (hasDocumentationLink || hasReferenceLink || hasContactObject) {
var moreInfoList = document.createElement("ul");
if (hasDocumentationLink) {
var url = featureObject["documentation-url"];
moreInfoList.appendChild(createLinkWithHeading("li", "Documentation", url, url));
}
if (hasReferenceLink) {
var url = featureObject.url;
moreInfoList.appendChild(createLinkWithHeading("li", "Reference", url, url));
}
if (hasSpecificationObject) {
var specification = featureObject.specification;
var li = createLinkWithHeading("li", "Parent feature", specification.name, ("#specification-" + specification.name));
li.className = "internal-reference";
moreInfoList.appendChild(li);
}
if (hasContactObject) {
var li = document.createElement("li");
li.textContent = "Contact: ";
if (featureObject.contact.twitter) {
li.appendChild(createLinkWithHeading("span", null, featureObject.contact.twitter, featureObject.contact.twitter));
}
if (featureObject.contact.email) {
if (featureObject.contact.twitter) {
li.appendChild(document.createTextNode(" - "));
}
var emailText = featureObject.contact.email;
if (featureObject.contact.name) {
emailText = featureObject.contact.name;
}
li.appendChild(createLinkWithHeading("span", null, emailText, "mailto:" + featureObject.contact.email));
}
moreInfoList.appendChild(li);
}
container.appendChild(moreInfoList);
}
if ("features" in featureObject && featureObject.features.length) {
var internalLinkContainer = document.createElement("div");
internalLinkContainer.className = "internal-reference";
var trackedFeatures = document.createElement("p");
trackedFeatures.textContent = "Subfeatures: ";
internalLinkContainer.appendChild(trackedFeatures);
var list = document.createElement("ul");
for (var feature of featureObject.features) {
var link = document.createElement("a");
link.textContent = feature.name;
link.href = "#feature-" + feature.name;
var li = document.createElement("li");
li.appendChild(link);
list.appendChild(li);
}
internalLinkContainer.appendChild(list);
container.appendChild(internalLinkContainer);
}
return container;
}
function renderFeaturesAndSpecifications(featureLikeObjects) {
var featureContainer = document.getElementById('features-container');
for (var featureLikeObject of featureLikeObjects) {
featureContainer.appendChild(createFeatureView(featureLikeObject));
}
}
function initSearch(featuresArray) {
var inputField = document.getElementById('search');
var featuresEls = document.querySelectorAll('.features > li');
featuresArray.forEach(function(feature, i) {
feature.el = featuresEls[i];
feature.visible = true;
});
inputField.addEventListener('input', search);
function search(ev) {
var searchTerm = inputField.value.trim().toLowerCase();
searchFeatures(featuresArray, searchTerm);
}
}
function searchFeatures(featuresArray, searchTerm) {
featuresArray.forEach(function(feature) {
var visible = isSearchMatch(feature, searchTerm);
if (visible && !feature.visible) {
feature.el.className = 'feature';
} else if (!visible && feature.visible) {
feature.el.className = 'feature is-hidden';
}
feature.visible = visible;
});
}
function isSearchMatch(feature, searchTerm) {
if (feature.name.toLowerCase().indexOf(searchTerm) !== -1)
return true;
if ("keywords" in feature) {
for (var keyword of feature.keywords) {
if (keyword.toLowerCase().indexOf(searchTerm) !== -1)
return true;
}
}
return false;
}
function displayFeatures(results)
{
var mainContent = document.getElementById("feature-list");
var successSubtree = document.importNode(document.getElementById("success-template").content, true);
mainContent.appendChild(successSubtree);
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;
}
var allFeatures = [];
for (var i in results) {
allFeatures = allFeatures.concat(results[i].features);
}
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);
}
function displayError(error)
{
var mainContent = document.getElementById("feature-list");
var successSubtree = document.importNode(document.getElementById("error-template").content, true);
var errorMessage = "Unable to load " + error.url;
if (error.request.status !== 200) {
errorMessage += ", status: " + error.request.status + " - " + error.request.statusText;
} else if (!error.response) {
errorMessage += ", the JSON file cannot be processed.";
}
successSubtree.querySelector("#error-message").textContent = errorMessage;
mainContent.appendChild(successSubtree);
}
Promise.all([loadJavaScriptCoreFeatures, loadWebCoreFeatures]).then(displayFeatures).catch(displayError);
}
document.addEventListener("DOMContentLoaded", initializeStatusPage);
</script>
<?php include("footer.inc"); ?>