From b972677e2a4a39b58b80f84677410650120ef5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Daoust?= Date: Fri, 22 Jun 2018 18:46:41 +0200 Subject: [PATCH] [Framework] New "See also" column in summary tables The framework can now render a "See also" column that contains useful links to resources related to the specification, notably: - a link to the Editor's Draft - a link to the repository that contains the Editor's Draft - specific links defined in the description of the spec. The "See also" column is only rendered in the (currently unused) `versions` type of summary table. The exact links that need to be rendered can be customized in the `toc.json` file. The README explains how to customize the summary tables. See related need expressed in https://github.com/w3c/web-roadmaps/issues/90 NB: The framework more or less already supported a `versions` column but that wasn't flexible enough, and name seemed badly chosen. --- README.md | 46 ++++++++++++++++++++++++++++ assets/css/theme.css | 4 +++ js/generate-utils.js | 61 ++++++++++++++++++++++++++++++++++---- js/translations.json | 2 +- js/translations.zh.json | 2 +- tools/extract-spec-data.js | 25 ++++++++++++++++ tools/spec.jsons | 31 +++++++++++++++++++ tools/tr.jsons | 31 +++++++++++++++++++ 8 files changed, 194 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c88777a1..02ad8d95 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ It aims at simplifying the creation and maintenance of such roadmaps by collecti * [Creating a new roadmap page or a new single-page roadmap](#creating-a-new-roadmap-page-or-a-new-single-page-roadmap) * [Creating the index of a new multi-page roadmap](#creating-the-index-of-a-new-multi-page-roadmap) * [Creating an About this document page](#creating-an-about-this-document-page) +* [Customizing summary tables](#customizing-summary-tables) * [Repository branches](#repository-branches) * [Generate content locally](#generate-content-locally) * [Translating a roadmap](#translating-a-roadmap) @@ -60,10 +61,12 @@ Depending on the advancement of the underlying specification, the JSON object ca * `feature`: in case the reference to the specification would benefit from being more specific than the specification as a whole, the `feature` property allows to add the name of the specific feature (see e.g. the [reference to the HTMLMediaElement interface in the HTML5 specification](data/htmlmediaelement.json)). * `title`: when the specification is unknown to the [W3C API](https://w3c.github.io/w3c-api/) and to [Specref](https://www.specref.org/), the `title` property should be set to the title of the specification. * `edDraft`: when the specification is unknown to the [W3C API](https://w3c.github.io/w3c-api/) and to [Specref](https://www.specref.org/), or when these APIs do not know the URL of the Editor's Draft for the specification, the `edDraft` property should contain the URL of the Editor's Draft of the specification. +* `repository`: when the repository of the specification cannot be determined automatically, the `repository` property should contain the URL of the repository that contains the source of the Editor's Draft of the specification * `wgs`: when the specification is unknown to the [W3C API](https://w3c.github.io/w3c-api/) and to [Specref](https://www.specref.org/), the `wgs` property should be an array of objects describing the groups that are producing the spec; each such object should have a `url` property with a link to the group's home page, and a `label` property with the name of the group. * `publisher`: the organization that published the specification. The framework automatically computes the publisher for W3C, WHATWG, and IETF specifications. * `informative`: when the specification is unknown to the [W3C API](https://w3c.github.io/w3c-api/), set the `informative` property to `true` to tell the framework that it only contains informative content or that it will be (or has been) published as a Group Note and not as a Recommendation. * `evergreen`: from time to time, specifications remain as drafts indefinitely but are continuously updated and can be considered stable whenever a new version is published. Set the `evergreen` property to `true` when the specification can always be used as a reference, no matter where it is on the Recommendation track. +* `seeAlso`: a list of other resources that could be worth looking at in relation with the specification. The `seeAlso` property should be an array of objects that have a `url` property set to the URL of the resource, a `label` property set to the title of the resource, and optionally a `kind` property that specifies the kind of resource as a string. The links are rendered in the "See also" column. The whole list is rendered by default, the `kind` value can be used to filter resources in some cases. See [Customizing summary tables](#customizing-summary-tables) for details. Here is an example of a JSON file that describes the "Intersection Observer" specification: ```json @@ -238,6 +241,7 @@ The following settings may be added to the `toc.json` file to generate the appro * `publishedVersion`: The URL of the latest published version. Generates a "Latest Published Version" link. * `previousVersion`: The URL of the previous published version. Generates a "Previous Version" link. * `publishDate`: The date of the publication, following a `YYYY-MM` format. Generates a subheading under the page's title with the date. +* `tables`: Custom summary tables, see [Customizing summary tables](#customizing-summary-tables)) The above settings may also be passed to the page as query string parameters, which can be useful to generate specific snapshots (in particular to pass the `publishDate` parameter). For instance, supposing the page can be served over a local HTTP server running at port 8080, you could use the following to view a "complete" Document Metadata section: @@ -311,6 +315,48 @@ Children of the `
` element in the about page are automatically appended to ``` + +## Customizing summary tables + +The framework automatically generates and renders summary tables at the end of sections that are flagged with a `featureset` class. Summary tables contain one entry per feature mentioned in the prose of the section. The columns rendered in the summary table are also determined by the `class` attribute of the `
` tag. Recognized values are: + +- `well-deployed`: Typically used to talk about well-deployed technologies. The summary table will be composed of the following columns: Feature, Specification / Group, Maturity, and Current Implementations. +- `in-progress`: Typically used to talk about technologies that are progressing along the Recommendation track. Same summary table as for well-deployed sections. +- `exploratory-work`: Typically used to talk about technologies that are being incubated somewhere without any official status. The summary table will be composed of the following columns: Feature, Specification / Group, Implementation intents. +- `versions`: Typically used to talk about specifications that convey guidelines, requirements, notes. The summary table will be composed of the following columns: Feature, Specification / Group, Maturity, and See also. + +Roadmap authors may customize the columns displayed and create new types of tables through the `tables` property of the `toc.json` file. That property must be set to an object indexed by the class identifier that will trigger the use of the table (e.g. `well-deployed` to override the default definition of the `well-deployed` table, or a new name to create a new type). For each type, the list of columns to render must be given in an array of objects that describe the column to render. + +That object must contain a `type` property that identifies the type of column. It may also contain a `title` property to override the default column's title, and other parameters (which depend on the type of column). + +The framework recognizes the following column types: + +- `feature` - Feature: Renders the name of the features that appear in `data-feature` attributes. A feature cell may span multiple rows. +- `spec` - Specification / Group: Renders the spec title and the name of the group that develops it. +- `maturity` - Maturity: Renders the maturity status of a spec as an icon. The list of icons is e.g. described in the [About page of the mobile roadmap](https://w3c.github.io/web-roadmaps/mobile/about.html#maturity-levels). +- `impl` - Implementation status: Renders the implementation status of the specification in main browsers. The icons and info that get represented are e.g. described in the [About page of the mobile rodmap](https://w3c.github.io/web-roadmaps/mobile/about.html#implementation) +- `seeAlso` - See also: Renders the list of related resources, including a link to the Editor's Draft, and a link to the repository. The exact kinds of resources to render can be specified in a `kinds` property. Default value is `all` to render all links, but the property can be set to an array of strings. Possible string values are: + - `edDraft`: renders a link to the Editor's Draft, when known + - `repository`: renders a link to the repository that contains the Editor's Draft, when known + - `seeAlso`: renders all resources in the `seeAlso` property of the specification + - some token: renders all resources in the `seeAlso` property of the specification whose `kind` property is equal to the token + +For instance, to add the `seeAlso` column with all possible links to the summary table rendered at the end of well-deployed sections, and to create a new type of section for reference documents that also renders a `seeAlso` column with only the Editor's Draft and links flagged as `ref` in the definition of specifications, you may add the following to your `toc.json` file: + +```json +"tables": { + "well-deployed": ["feature", "spec", "maturity", "impl", "seeAlso"], + "reference": ["spec", "maturity", { + "type": "seeAlso", + "title": "Reference documents", + "kinds": ["edDraft", "ref"] + }] +} +``` + +With these definitions, the `reference` table will be generated at the end of sections that have a `class` attribute set to `featureset reference`. + + ## Repository branches The source of the roadmaps is in the `master` branch. This is the default branch of the repository, and the branch against which you should be sending pull requests. Whenever content is pushed onto the `master` branch, a Travis script will run, fetch information and implementation data for all features listed in `data`, and eventually update the `gh-pages` branch accordingly. diff --git a/assets/css/theme.css b/assets/css/theme.css index 67770418..03103ad2 100644 --- a/assets/css/theme.css +++ b/assets/css/theme.css @@ -145,6 +145,10 @@ th.feature[rowspan] { td.maturity { text-align: center; } td.maturity img { vertical-align: middle; } td.impl { min-width: 220px; } +td.seeAlso { + min-width: 200px; + font-size: 90%; +} td img + img { margin-left: 0.25em; } td ul { list-style-type: none; diff --git a/js/generate-utils.js b/js/generate-utils.js index 66b238c3..62d7fda4 100644 --- a/js/generate-utils.js +++ b/js/generate-utils.js @@ -140,7 +140,7 @@ const tableColumnsPerType = { 'well-deployed': ['feature', 'spec', 'maturity', 'impl'], 'in-progress': ['feature', 'spec', 'maturity', 'impl'], 'exploratory-work': ['feature', 'spec', 'impl-intents'], - 'versions': ['feature', 'spec', 'maturity', 'versions'] + 'versions': ['feature', 'spec', 'maturity', 'seeAlso'] }; /** @@ -314,16 +314,65 @@ const createImplCell = function (column, featureId, featureName, specInfo, implI return cell; }; -const createVersionsCell = function (column, featureId, featureName, specInfo, implInfo, translate, lang, pos) { +const createSeeAlsoCell = function (column, featureId, featureName, specInfo, implInfo, translate, lang, pos) { let cell = document.createElement('td'); - (specInfo.versions || []).forEach((version, pos) => { - if (version.url && version.label) { + cell.classList.add('seeAlso'); + if (column.class) { + cell.classList.add(column.class); + } + let renderLink = (link, pos) => { + if (link.url && link.label) { if (pos > 0) { cell.appendChild(document.createElement('br')); } - fillCell(cell, version); + fillCell(cell, link); + } + }; + let links = specInfo.seeAlso || []; + let kinds = null; + if (!column.kinds || (column.kinds === 'all')) { + kinds = ['seeAlso', 'edDraft', 'repository']; + } + else if (isArray(column.kinds)) { + kinds = column.kinds; + } + else { + kinds = [column.kinds]; + } + let linkPos = 0; + kinds.forEach(kind => { + switch (kind) { + case 'repository': + if (specInfo.repository) { + renderLink({ + label: translate('metadata', 'Repository'), + url: specInfo.repository + }, linkPos); + linkPos += 1; + } + break; + + case 'edDraft': + if (specInfo.edDraft) { + renderLink({ + label: translate('metadata', 'Editor\'s Draft'), + url: specInfo.edDraft + }, linkPos); + linkPos += 1; + } + break; + + default: + links.forEach(link => { + if ((kind === 'seeAlso') || (link.kind === kind)) { + renderLink(link, linkPos); + linkPos += 1; + } + }); + break; } }); + return cell; }; @@ -333,7 +382,7 @@ const tableColumnCreators = { 'maturity': createMaturityCell, 'impl': createImplCell, 'impl-intents': createImplCell, - 'versions': createVersionsCell + 'seeAlso': createSeeAlsoCell }; diff --git a/js/translations.json b/js/translations.json index 0ecbbf5d..1dc986cc 100644 --- a/js/translations.json +++ b/js/translations.json @@ -12,7 +12,7 @@ "maturity": "Maturity", "impl": "Current implementations", "impl-intents": "Implementation intents", - "versions": "Development versions" + "seeAlso": "See also" }, "implstatus": { "shipped": "Shipped", diff --git a/js/translations.zh.json b/js/translations.zh.json index 2cbc3fe5..217653cd 100644 --- a/js/translations.zh.json +++ b/js/translations.zh.json @@ -12,7 +12,7 @@ "maturity": "成熟度", "impl": "现有实现", "impl-intents": "实现意向", - "versions": "Development versions" + "seeAlso": "See also" }, "browsers": { "chrome": "Chrome", diff --git a/tools/extract-spec-data.js b/tools/extract-spec-data.js index 8d1a03de..81049ff2 100644 --- a/tools/extract-spec-data.js +++ b/tools/extract-spec-data.js @@ -144,6 +144,29 @@ function getSpecUrl(spec) { } +/** + * Construct the URL of the repository from the Editor's Draft URL + * (only works for GitHub repositories for now) + * + * @function + * @param {Object} spec The spec object to parse + * @return {String} The URL of the repository + */ +function getRepositoryFromEdDraft(edDraft) { + edDraft = edDraft || ''; + let tokens = edDraft.match(/^https?:\/\/([^\.]+)\.github\.io\/([^\/$]+)/i); + if (tokens) { + return 'https://github.com/' + tokens[1] + '/' + tokens[2]; + } + else if (edDraft.match(/^https?:\/\/drafts\.csswg\.org\//)) { + return 'https://github.com/w3c/csswg-drafts'; + } + else { + return null; + } +} + + /** * Return the URL to use to search for additional info about the given spec in * Specref. @@ -260,6 +283,7 @@ async function extractSpecData(files, config) { trInfo = { url: latestInfo.shortlink, edDraft: latestInfo['editor-draft'], + repository: getRepositoryFromEdDraft(latestInfo['editor-draft']), title: latestInfo.title, status: latestInfo.status, publisher: 'W3C', @@ -281,6 +305,7 @@ async function extractSpecData(files, config) { let info = { url: getSpecUrl(spec) || trInfo.url || lookupInfo.href, edDraft: spec.data.edDraft || spec.data.editors || trInfo.edDraft || lookupInfo.edDraft, + repository: spec.data.repository || trInfo.repository || lookupInfo.repository, title: spec.data.title || trInfo.title || lookupInfo.title, status: spec.data.status || trInfo.status || lookupInfo.status || 'ED', deliveredBy: spec.data.wgs || trInfo.deliveredBy || lookupInfo.deliveredBy || [], diff --git a/tools/spec.jsons b/tools/spec.jsons index 5cbab811..aae89cdf 100644 --- a/tools/spec.jsons +++ b/tools/spec.jsons @@ -16,6 +16,12 @@ "type": "string", "format": "uri" }, + "repository": { + "title": "URL of the repository", + "description": "URL of the repository that contains the Editor’s Draft of the specification.", + "type": "string", + "format": "uri" + }, "impl": { "title": "Implementation info", "description": "For specifications for which browser implementations are expected, the impl property explains where to look for implementation info", @@ -149,6 +155,31 @@ "informative": { "description": "The spec contains only informative content or is/will be published as a Note.", "type": "boolean" + }, + "seeAlso": { + "title": "See also", + "description": "Other resources worth looking at in relation to this spec", + "type": "array", + "additionalItems": false, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["url", "label"], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "label": { + "type": "string", + "minLength": 1 + }, + "kind": { + "type": "string", + "minLength": 1 + } + } + } } } } diff --git a/tools/tr.jsons b/tools/tr.jsons index 3dff4ab4..ff1b23bf 100644 --- a/tools/tr.jsons +++ b/tools/tr.jsons @@ -19,6 +19,12 @@ "type": "string", "format": "uri" }, + "repository": { + "title": "URL of the repository", + "description": "URL of the repository that contains the Editor’s Draft of the specification.", + "type": "string", + "format": "uri" + }, "title": { "title": "Title of the specification", "description": "Title of the specification.", @@ -71,6 +77,31 @@ "informative": { "description": "The spec contains only informative content or is/will be published as a Note.", "type": "boolean" + }, + "seeAlso": { + "title": "See also", + "description": "Other resources worth looking at in relation to this spec", + "type": "array", + "additionalItems": false, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["url", "label"], + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "label": { + "type": "string", + "minLength": 1 + }, + "kind": { + "type": "string", + "minLength": 1 + } + } + } } } }