| <?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"); ?> |