feat: better htmlization views (#4825)

* feat: Use bs5 for htmlized doc (#4082)

Co-authored-by: Martin Thomson <mt@lowentropy.net>

* fix: Various fixes to HTMLized document view (#4501)

* fix: Pref labels were switched

* fix: Fix ToC for htmlized docs

* Replace datatracker button with document name link to datatracker

* ui: Make fonts even larger on larger window widths

* fix: Document format buttons open new tabs

* fix: Various suggestions from Jay

* fix: Don't show "htmlized" self-link under formats

* ui: Font size fix for iOS

* ui: More little tweaks

* feat/htmlize fixes and improvements (#4506)

* fix: Don't open htmlized view in new tab

* fix: Tests were failing

* feat: Add pref settings to cap max font size

* feat: Add ability to hide side panel

* fix: And more `feat/htmlize` fixes (#4511)

* fix: Remove superfluous scrollbars

* fix: Show email links for authors

* fix: Only show "email authors" button for latest reversion

* fix: Remove duplicate code, fix nav scrolling

* feat: Add RFCs to revision lists

* feat: Add pref option to control dependency inlining

* fix: Add analytical tags

* feat: Notify user of rendering inconsistencies

* feat: Split out bootstrap-icons when not inlining dependencies

* fix: Revision list and minor other fixes

* feat: Show stream logo when possible (#4516)

* fix: Remove superfluous scrollbars

* fix: Show email links for authors

* fix: Only show "email authors" button for latest reversion

* fix: Remove duplicate code, fix nav scrolling

* feat: Add RFCs to revision lists

* feat: Add pref option to control dependency inlining

* fix: Add analytical tags

* feat: Notify user of rendering inconsistencies

* feat: Split out bootstrap-icons when not inlining dependencies

* fix: Revision list and minor other fixes

* feat: Show stream logos when possible

* fix: Pick up CSS changes from https://github.com/martinthomson/rfc-txt-html (#4520)

* fix: Remove superfluous scrollbars

* fix: Show email links for authors

* fix: Only show "email authors" button for latest reversion

* fix: Remove duplicate code, fix nav scrolling

* feat: Add RFCs to revision lists

* feat: Add pref option to control dependency inlining

* fix: Add analytical tags

* feat: Notify user of rendering inconsistencies

* feat: Split out bootstrap-icons when not inlining dependencies

* fix: Revision list and minor other fixes

* feat: Show stream logos when possible

* fix: Pick up CSS changes from https://github.com/martinthomson/rfc-txt-html

* chore: add debug script to replicate GitHub Actions test environment

* chore: cleanup from merge of main

* fix: Fix PDFixation crash due to referencing renamed CSS asset (#4665)

* fix: Rename some CSS classes to handle recent xml2rfc changes (#4791)

* Merge main

* fix: Rename some CSS classes to handle recent xml2rfc changes

Fixes #4784.

* chore: repair merge damage

* chore: more merge corrections

* chore: one more merge correction

* fix: npm dependencies

* fix: Change default font size (#4817)

* Fix dependency issues

* Cap fontsize at 12pt by default

Co-authored-by: Nicolas Giard <github@ngpixel.com>

Co-authored-by: Lars Eggert <lars@eggert.org>
Co-authored-by: Martin Thomson <mt@lowentropy.net>
Co-authored-by: Nicolas Giard <github@ngpixel.com>
This commit is contained in:
Robert Sparks 2022-12-02 15:17:14 -06:00 committed by GitHub
parent d8db6e7102
commit 9457e2b1e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 2074 additions and 937 deletions

103
.pnp.cjs generated
View file

@ -42,6 +42,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/timegrid", "npm:5.11.3"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@parcel/optimizer-data-url", "npm:2.8.0"],\
["@parcel/transformer-inline-string", "npm:2.8.0"],\
["@parcel/transformer-sass", "npm:2.8.0"],\
["@popperjs/core", "npm:2.11.6"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
@ -52,7 +54,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["browser-fs-access", "npm:0.31.1"],\
["browserlist", "npm:1.0.1"],\
["c8", "npm:7.12.0"],\
["caniuse-lite", "npm:1.0.30001434"],\
["caniuse-lite", "npm:1.0.30001435"],\
["d3", "npm:7.6.1"],\
["eslint", "npm:8.28.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.0"],\
@ -63,7 +65,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
["file-saver", "npm:2.0.5"],\
["highcharts", "npm:10.3.1"],\
["highcharts", "npm:10.3.2"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
["jquery", "npm:3.6.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
@ -72,14 +74,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\
["lodash-es", "npm:4.17.21"],\
["luxon", "npm:3.1.0"],\
["luxon", "npm:3.1.1"],\
["moment", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.39"],\
["ms", "npm:2.1.3"],\
["murmurhash-js", "npm:1.0.0"],\
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\
["sass", "npm:1.56.1"],\
@ -337,7 +339,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/common", "npm:5.11.3"],\
["@types/luxon", null],\
["luxon", "npm:3.1.0"],\
["luxon", "npm:3.1.1"],\
["tslib", "npm:2.4.0"]\
],\
"packagePeers": [\
@ -1136,6 +1138,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["@parcel/optimizer-data-url", [\
["npm:2.8.0", {\
"packageLocation": "./.yarn/cache/@parcel-optimizer-data-url-npm-2.8.0-89a39d906e-998fb94cee.zip/node_modules/@parcel/optimizer-data-url/",\
"packageDependencies": [\
["@parcel/optimizer-data-url", "npm:2.8.0"],\
["@parcel/plugin", "npm:2.8.0"],\
["@parcel/utils", "npm:2.8.0"],\
["isbinaryfile", "npm:4.0.10"],\
["mime", "npm:2.6.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["@parcel/optimizer-htmlnano", [\
["npm:2.8.0", {\
"packageLocation": "./.yarn/cache/@parcel-optimizer-htmlnano-npm-2.8.0-d2ead43d0c-68010e586b.zip/node_modules/@parcel/optimizer-htmlnano/",\
@ -1529,6 +1544,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["@parcel/transformer-inline-string", [\
["npm:2.8.0", {\
"packageLocation": "./.yarn/cache/@parcel-transformer-inline-string-npm-2.8.0-5fce2c90b8-e40616c55b.zip/node_modules/@parcel/transformer-inline-string/",\
"packageDependencies": [\
["@parcel/transformer-inline-string", "npm:2.8.0"],\
["@parcel/plugin", "npm:2.8.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["@parcel/transformer-js", [\
["npm:2.8.0", {\
"packageLocation": "./.yarn/unplugged/@parcel-transformer-js-virtual-0a5c0b53bd/node_modules/@parcel/transformer-js/",\
@ -2690,10 +2715,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\
"linkType": "HARD"\
}],\
["npm:1.0.30001434", {\
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001434-9c6ea57daf-7c9d2641e8.zip/node_modules/caniuse-lite/",\
["npm:1.0.30001435", {\
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001435-7cebb35f0a-ec88b9c37f.zip/node_modules/caniuse-lite/",\
"packageDependencies": [\
["caniuse-lite", "npm:1.0.30001434"]\
["caniuse-lite", "npm:1.0.30001435"]\
],\
"linkType": "HARD"\
}]\
@ -4910,10 +4935,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["highcharts", [\
["npm:10.3.1", {\
"packageLocation": "./.yarn/cache/highcharts-npm-10.3.1-e67a887ff6-8a1cf9a363.zip/node_modules/highcharts/",\
["npm:10.3.2", {\
"packageLocation": "./.yarn/cache/highcharts-npm-10.3.2-1672942f09-43cb42b24c.zip/node_modules/highcharts/",\
"packageDependencies": [\
["highcharts", "npm:10.3.1"]\
["highcharts", "npm:10.3.2"]\
],\
"linkType": "HARD"\
}]\
@ -5456,6 +5481,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["isbinaryfile", [\
["npm:4.0.10", {\
"packageLocation": "./.yarn/cache/isbinaryfile-npm-4.0.10-91d1251522-a6b28db7e2.zip/node_modules/isbinaryfile/",\
"packageDependencies": [\
["isbinaryfile", "npm:4.0.10"]\
],\
"linkType": "HARD"\
}]\
]],\
["isexe", [\
["npm:2.0.0", {\
"packageLocation": "./.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip/node_modules/isexe/",\
@ -5918,10 +5952,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["luxon", [\
["npm:3.1.0", {\
"packageLocation": "./.yarn/cache/luxon-npm-3.1.0-16e2508500-f8a850b759.zip/node_modules/luxon/",\
["npm:3.1.1", {\
"packageLocation": "./.yarn/cache/luxon-npm-3.1.1-64fe977c1d-388fb35d3c.zip/node_modules/luxon/",\
"packageDependencies": [\
["luxon", "npm:3.1.0"]\
["luxon", "npm:3.1.1"]\
],\
"linkType": "HARD"\
}]\
@ -5987,6 +6021,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["mime", "npm:1.6.0"]\
],\
"linkType": "HARD"\
}],\
["npm:2.6.0", {\
"packageLocation": "./.yarn/cache/mime-npm-2.6.0-88b89d8de0-1497ba7b9f.zip/node_modules/mime/",\
"packageDependencies": [\
["mime", "npm:2.6.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["minimatch", [\
@ -6659,17 +6700,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["pinia", [\
["npm:2.0.26", {\
"packageLocation": "./.yarn/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\
["npm:2.0.27", {\
"packageLocation": "./.yarn/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
"packageDependencies": [\
["pinia", "npm:2.0.26"]\
["pinia", "npm:2.0.27"]\
],\
"linkType": "SOFT"\
}],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26", {\
"packageLocation": "./.yarn/__virtual__/pinia-virtual-3c74e5a139/0/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27", {\
"packageLocation": "./.yarn/__virtual__/pinia-virtual-0b7bfddb52/0/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
"packageDependencies": [\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
["@types/typescript", null],\
["@types/vue", null],\
["@types/vue__composition-api", null],\
@ -6677,7 +6718,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@vue/devtools-api", "npm:6.4.5"],\
["typescript", null],\
["vue", "npm:3.2.45"],\
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"]\
["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"]\
],\
"packagePeers": [\
"@types/typescript",\
@ -6706,7 +6747,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/vue", null],\
["@types/vue__composition-api", null],\
["@vue/composition-api", null],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
["vue", "npm:3.2.45"],\
["vue-demi", "virtual:f56fcf19bbebc2ada1b28955da8cc216b1e9a569a1a7337d2d1926c1ebd1bc7a5bd91aedae1d05c15c8562f33caf7c59bd3020a667340f6bdc6a7b13fc2ba847#npm:0.12.5"]\
],\
@ -7232,6 +7273,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/timegrid", "npm:5.11.3"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@parcel/optimizer-data-url", "npm:2.8.0"],\
["@parcel/transformer-inline-string", "npm:2.8.0"],\
["@parcel/transformer-sass", "npm:2.8.0"],\
["@popperjs/core", "npm:2.11.6"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
@ -7242,7 +7285,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["browser-fs-access", "npm:0.31.1"],\
["browserlist", "npm:1.0.1"],\
["c8", "npm:7.12.0"],\
["caniuse-lite", "npm:1.0.30001434"],\
["caniuse-lite", "npm:1.0.30001435"],\
["d3", "npm:7.6.1"],\
["eslint", "npm:8.28.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.0"],\
@ -7253,7 +7296,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
["file-saver", "npm:2.0.5"],\
["highcharts", "npm:10.3.1"],\
["highcharts", "npm:10.3.2"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
["jquery", "npm:3.6.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
@ -7262,14 +7305,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\
["lodash-es", "npm:4.17.21"],\
["luxon", "npm:3.1.0"],\
["luxon", "npm:3.1.1"],\
["moment", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.39"],\
["ms", "npm:2.1.3"],\
["murmurhash-js", "npm:1.0.0"],\
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\
["sass", "npm:1.56.1"],\
@ -8159,16 +8202,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "SOFT"\
}],\
["npm:0.13.1", {\
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-cfef5ecd67/node_modules/vue-demi/",\
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-615072ef29/node_modules/vue-demi/",\
"packageDependencies": [\
["vue-demi", "npm:0.13.1"]\
],\
"linkType": "SOFT"\
}],\
["virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1", {\
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-cfef5ecd67/node_modules/vue-demi/",\
["virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1", {\
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-615072ef29/node_modules/vue-demi/",\
"packageDependencies": [\
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"],\
["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"],\
["@types/vue", null],\
["@types/vue__composition-api", null],\
["@vue/composition-api", null],\

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

26
dev/tests/debug.sh Normal file
View file

@ -0,0 +1,26 @@
#!/bin/bash
# This script recreate the same environment used during tests on GitHub Actions
# and drops you into a terminal at the point where the actual tests would be run.
#
# Refer to https://github.com/ietf-tools/datatracker/blob/main/.github/workflows/build.yml#L141-L155
# for the commands to run next.
#
# Simply type "exit" + ENTER to exit and shutdown this test environment.
echo "Fetching latest images..."
docker pull ghcr.io/ietf-tools/datatracker-app-base:latest
docker pull ghcr.io/ietf-tools/datatracker-db:latest
echo "Starting containers..."
docker compose -f docker-compose.debug.yml -p dtdebug up -d
echo "Copying working directory into container..."
docker compose -p dtdebug cp ../../. app:/__w/datatracker/datatracker/
echo "Run prepare script..."
docker compose -p dtdebug exec app chmod +x ./dev/tests/prepare.sh
docker compose -p dtdebug exec app sh ./dev/tests/prepare.sh
docker compose -p dtdebug exec app /usr/local/bin/wait-for db:3306 -- echo "DB ready"
echo "================================================================="
echo "Launching zsh terminal:"
docker compose -p dtdebug exec app /bin/zsh
echo "Shutting down containers..."
docker compose -p dtdebug down -v

View file

@ -0,0 +1,33 @@
# This docker-compose replicates the test workflow happening on GitHub during a PR / build check.
# To be used from the debug.sh script.
version: '3.8'
services:
app:
image: ghcr.io/ietf-tools/datatracker-app-base:latest
command: -f /dev/null
working_dir: /__w/datatracker/datatracker
entrypoint: tail
hostname: app
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
CI: 'true'
GITHUB_ACTIONS: 'true'
HOME: /github/home
db:
image: ghcr.io/ietf-tools/datatracker-db:latest
restart: unless-stopped
volumes:
- mariadb-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: RkTkDPFnKpko
MYSQL_DATABASE: ietf_utf8
MYSQL_USER: django
MYSQL_PASSWORD: RkTkDPFnKpko
CI: 'true'
GITHUB_ACTIONS: 'true'
volumes:
mariadb-data:

View file

@ -8,6 +8,8 @@ import io
import os
import rfc2html
from pathlib import Path
from lxml import etree
from typing import Optional, TYPE_CHECKING
from weasyprint import HTML as wpHTML
@ -21,6 +23,7 @@ from django.conf import settings
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.html import mark_safe # type:ignore
from django.contrib.staticfiles import finders
import debug # pyflakes:ignore
@ -541,6 +544,46 @@ class DocumentInfo(models.Model):
def text_or_error(self):
return self.text() or "Error; cannot read '%s'"%self.get_base_name()
def html_body(self, classes=""):
if self.get_state_slug() == "rfc":
try:
html = Path(
os.path.join(settings.RFC_PATH, self.canonical_name() + ".html")
).read_text()
except IOError:
return None
else:
try:
html = Path(
os.path.join(
settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR,
self.name + "-" + self.rev + ".html",
)
).read_text()
except IOError:
return None
# If HTML was generated by rfc2html, do not return it. Caller
# will use htmlize() to use a more current rfc2html to
# generate an HTMLized version. TODO: There should be a
# better way to determine how an HTML format was generated.
if html.startswith("<pre>"):
return None
# get body
body = etree.HTML(html).xpath("//body")[0]
body.tag = "div"
if classes:
body.attrib["class"] = classes
# remove things
for tag in ["script"]:
for t in body.xpath(f"//{tag}"):
t.getparent().remove(t)
html = etree.tostring(body, encoding=str, method="html")
return html
def htmlized(self):
name = self.get_base_name()
text = self.text()
@ -566,17 +609,29 @@ class DocumentInfo(models.Model):
def pdfized(self):
name = self.get_base_name()
text = self.text()
cache = caches['pdfized']
cache_key = name.split('.')[0]
text = self.html_body(classes="rfchtml")
stylesheets = [finders.find("ietf/css/document_html_referenced.css")]
if text:
stylesheets.append(finders.find("ietf/css/document_html_txt.css"))
else:
text = self.htmlized()
stylesheets.append(io.BytesIO(b"body { font-size: 9.2pt; }"))
cache = caches["pdfized"]
cache_key = name.split(".")[0]
try:
pdf = cache.get(cache_key)
except EOFError:
pdf = None
if not pdf:
html = rfc2html.markup(text, path=settings.PDFIZER_URL_PREFIX)
try:
pdf = wpHTML(string=html.replace('\xad','')).write_pdf(stylesheets=[io.BytesIO(b'html { font-size: 94%;}')])
pdf = wpHTML(
string=text, base_url=settings.IDTRACKER_BASE_URL
).write_pdf(
stylesheets=stylesheets,
presentational_hints=True,
optimize_size=("fonts", "images"),
)
except AssertionError:
pdf = None
if pdf:

View file

@ -260,8 +260,8 @@ def urlize_ietf_docs(string, autoescape=None):
urlize_ietf_docs = stringfilter(urlize_ietf_docs)
@register.filter(name='urlize_related_source_list', is_safe=True, needs_autoescape=True)
def urlize_related_source_list(related, autoescape=None):
@register.filter(name='urlize_related_source_list', is_safe=True, document_html=False)
def urlize_related_source_list(related, document_html=False):
"""Convert a list of RelatedDocuments into list of links using the source document's canonical name"""
links = []
names = set()
@ -273,8 +273,7 @@ def urlize_related_source_list(related, autoescape=None):
continue
names.add(name)
titles.add(title)
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name))
if autoescape:
url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
name = escape(name)
title = escape(title)
links.append(mark_safe(
@ -284,15 +283,14 @@ def urlize_related_source_list(related, autoescape=None):
))
return links
@register.filter(name='urlize_related_target_list', is_safe=True, needs_autoescape=True)
def urlize_related_target_list(related, autoescape=None):
@register.filter(name='urlize_related_target_list', is_safe=True, document_html=False)
def urlize_related_target_list(related, document_html=False):
"""Convert a list of RelatedDocuments into list of links using the target document's canonical name"""
links = []
for rel in related:
name=rel.target.document.canonical_name()
title = rel.target.document.title
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name))
if autoescape:
url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
name = escape(name)
title = escape(title)
links.append(mark_safe(
@ -554,6 +552,19 @@ def consensus(doc):
else:
return "Unknown"
@register.filter
def std_level_to_label_format(doc):
"""Returns valid Bootstrap classes to label a status level badge."""
if doc.is_rfc():
if doc.related_that("obs"):
return "obs"
else:
return doc.std_level_id
else:
return "draft"
@register.filter
def pos_to_label_format(text):
"""Returns valid Bootstrap classes to label a ballot position."""

View file

@ -730,13 +730,13 @@ Man Expires September 22, 2015 [Page 3]
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name)))
self.assertEqual(r.status_code, 200)
self.assertContains(r, "Versions:")
self.assertContains(r, "Select version")
self.assertContains(r, "Deimos street")
q = PyQuery(r.content)
self.assertEqual(q('title').text(), 'draft-ietf-mars-test-01')
self.assertEqual(len(q('.rfcmarkup pre')), 4)
self.assertEqual(len(q('.rfcmarkup span.h1')), 2)
self.assertEqual(len(q('.rfcmarkup a[href]')), 41)
self.assertEqual(len(q('.rfcmarkup pre')), 3)
self.assertEqual(len(q('.rfcmarkup span.h1, .rfcmarkup h1')), 2)
self.assertEqual(len(q('.rfcmarkup a[href]')), 28)
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name, rev=draft.rev)))
self.assertEqual(r.status_code, 200)

View file

@ -995,41 +995,6 @@ def get_search_cache_key(params):
key = "doc:document:search:" + hashlib.sha512(json.dumps(kwargs, sort_keys=True).encode('utf-8')).hexdigest()
return key
def label_wrap(label, items, joiner=',', max=50):
lines = []
if not items:
return lines
line = '%s: %s' % (label, items[0])
for item in items[1:]:
if len(line)+len(joiner+' ')+len(item) > max:
lines.append(line+joiner)
line = ' '*(len(label)+len(': ')) + item
else:
line += joiner+' '+item
if line:
lines.append(line)
return lines
def join_justified(left, right, width=72):
count = max(len(left), len(right))
left = left + ['']*(count-len(left))
right = right + ['']*(count-len(right))
lines = []
i = 0
while True:
l = left[i]
r = right[i]
if len(l)+1+len(r) > width:
left = left + ['']
right = right[:i] + [''] + right[i:]
r = right[i]
count += 1
lines.append( l + ' ' + r.rjust(width-len(l)-1) )
i += 1
if i >= count:
break
return lines
def build_file_urls(doc):
if isinstance(doc,Document) and doc.get_state_slug() == "rfc":
name = doc.canonical_name()
@ -1069,135 +1034,6 @@ def build_file_urls(doc):
return file_urls, found_types
def build_doc_supermeta_block(doc):
items = []
items.append(f'[<a href="{ settings.IDTRACKER_BASE_URL }" title="Document search and retrieval page">Search</a>]')
file_urls, found_types = build_file_urls(doc)
file_urls = [('txt',url) if label=='plain text' else (label,url) for label,url in file_urls]
if file_urls:
file_labels = {
'txt' : 'Plaintext version of this document',
'xml' : 'XML source for this document',
'pdf' : 'PDF version of this document',
'html' : 'HTML version of this document, from XML2RFC',
'bibtex' : 'BibTex entry for this document',
}
parts=[]
for label,url in file_urls:
if 'htmlized' not in label:
file_label=file_labels.get(label,'')
title_attribute = f' title="{file_label}"' if file_label else ''
partstring = f'<a href="{url}"{title_attribute}>{label}</a>'
parts.append(partstring)
items.append('[' + '|'.join(parts) + ']')
items.append(f'[<a href="{ urlreverse("ietf.doc.views_doc.document_main",kwargs=dict(name=doc.canonical_name())) }" title="Datatracker information for this document">Tracker</a>]')
if doc.group.acronym != 'none':
items.append(f'[<a href="{urlreverse("ietf.group.views.group_home",kwargs=dict(acronym=doc.group.acronym))}" title="The working group handling this document">WG</a>]')
items.append(f'[<a href="mailto:{doc.name}@ietf.org?subject={doc.name}" title="Send email to the document authors">Email</a>]')
if doc.rev != "00":
items.append(f'[<a href="{settings.RFCDIFF_BASE_URL}?difftype=--hwdiff&amp;url2={doc.name}-{doc.rev}.txt" title="Inline diff (wdiff)">Diff1</a>]')
items.append(f'[<a href="{settings.RFCDIFF_BASE_URL}?url2={doc.name}-{doc.rev}.txt" title="Side-by-side diff">Diff2</a>]')
items.append(f'[<a href="{settings.IDNITS_BASE_URL}?url={settings.IETF_ID_ARCHIVE_URL}{doc.name}-{doc.rev}.txt" title="Run an idnits check of this document">Nits</a>]')
return ' '.join(items)
def build_doc_meta_block(doc, path):
def add_markup(path, doc, lines):
is_hst = doc.is_dochistory()
rev = doc.rev
if is_hst:
doc = doc.doc
name = doc.name
rfcnum = doc.rfc_number()
errata_url = settings.RFC_EDITOR_ERRATA_URL.format(rfc_number=rfcnum) if not is_hst else ""
ipr_url = "%s?submit=draft&amp;id=%s" % (urlreverse('ietf.ipr.views.search'), name)
for i, line in enumerate(lines):
# add draft links
line = re.sub(r'\b(draft-[-a-z0-9]+)\b', r'<a href="%s/\g<1>">\g<1></a>'%(path, ), line)
# add rfcXXXX to RFC links
line = re.sub(r' (rfc[0-9]+)\b', r' <a href="%s/\g<1>">\g<1></a>'%(path, ), line)
# add XXXX to RFC links
line = re.sub(r' ([0-9]{3,5})\b', r' <a href="%s/rfc\g<1>">\g<1></a>'%(path, ), line)
# add draft revision links
line = re.sub(r' ([0-9]{2})\b', r' <a href="%s/%s-\g<1>">\g<1></a>'%(path, name, ), line)
if rfcnum:
# add errata link
line = re.sub(r'Errata exist', r'<a class="text-warning" href="%s">Errata exist</a>'%(errata_url, ), line)
if is_hst or not rfcnum:
# make current draft rev bold
line = re.sub(r'>(%s)<'%rev, r'><b>\g<1></b><', line)
line = re.sub(r'IPR declarations', r'<a class="text-warning" href="%s">IPR declarations</a>'%(ipr_url, ), line)
line = line.replace(r'[txt]', r'[<a href="%s">txt</a>]' % doc.get_href())
lines[i] = line
return lines
#
now = timezone.now()
draft_state = doc.get_state('draft')
block = ''
meta = {}
if doc.type_id == 'draft':
revisions = []
ipr = doc.related_ipr()
if ipr:
meta['ipr'] = [ "IPR declarations" ]
if doc.is_rfc() and not doc.is_dochistory():
if not doc.name.startswith('rfc'):
meta['from'] = [ "%s-%s"%(doc.name, doc.rev) ]
meta['errata'] = [ "Errata exist" ] if doc.tags.filter(slug='errata').exists() else []
meta['obsoletedby'] = [ document.rfc_number() for alias in doc.related_that('obs') for document in alias.docs.all() ]
meta['obsoletedby'].sort()
meta['updatedby'] = [ document.rfc_number() for alias in doc.related_that('updates') for document in alias.docs.all() ]
meta['updatedby'].sort()
meta['stdstatus'] = [ doc.std_level.name ]
else:
dd = doc.doc if doc.is_dochistory() else doc
revisions += [ '(%s)%s'%(d.name, ' '*(2-((len(d.name)-1)%3))) for d in dd.replaces() ]
revisions += doc.revisions()
if doc.is_dochistory() and doc.doc.is_rfc():
revisions += [ doc.doc.canonical_name() ]
else:
revisions += [ d.name for d in doc.replaced_by() ]
meta['versions'] = revisions
if not doc.is_dochistory and draft_state.slug == 'active' and now > doc.expires:
# Active past expiration date
meta['active'] = [ 'Document is active' ]
meta['state' ] = [ doc.friendly_state() ]
intended_std = doc.intended_std_level if doc.intended_std_level else None
if intended_std:
if intended_std.slug in ['ps', 'ds', 'std']:
meta['stdstatus'] = [ "Standards Track" ]
else:
meta['stdstatus'] = [ intended_std.name ]
elif doc.type_id == 'charter':
meta['versions'] = doc.revisions()
#
# Add markup to items that needs it.
if 'versions' in meta:
meta['versions'] = label_wrap('Versions', meta['versions'], joiner="")
for label in ['Obsoleted by', 'Updated by', 'From' ]:
item = label.replace(' ','').lower()
if item in meta and meta[item]:
meta[item] = label_wrap(label, meta[item])
#
left = []
right = []
#right = [ '[txt]']
for item in [ 'from', 'versions', 'obsoletedby', 'updatedby', ]:
if item in meta and meta[item]:
left += meta[item]
for item in ['stdstatus', 'active', 'state', 'ipr', 'errata', ]:
if item in meta and meta[item]:
right += meta[item]
lines = join_justified(left, right)
block = '\n'.join(add_markup(path, doc, lines))
#
return block
def augment_docs_and_user_with_user_info(docs, user):
"""Add attribute to each document with whether the document is tracked
or has a review wish by the user or not, and the review teams the user is on."""

View file

@ -49,6 +49,7 @@ from django.template.loader import render_to_string
from django.urls import reverse as urlreverse
from django.conf import settings
from django import forms
from django.contrib.staticfiles import finders
import debug # pyflakes:ignore
@ -61,9 +62,9 @@ from ietf.doc.utils import (add_links_in_new_revision_events, augment_events_wit
can_adopt_draft, can_unadopt_draft, get_chartering_type, get_tags_for_stream_id,
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot,
get_initial_notify, make_notify_changed_event, make_rev_history, default_consensus,
add_events_message_info, get_unicode_document_content, build_doc_meta_block,
add_events_message_info, get_unicode_document_content,
augment_docs_and_user_with_user_info, irsg_needed_ballot_positions, add_action_holder_change_event,
build_doc_supermeta_block, build_file_urls, update_documentauthors, fuzzy_find_documents,
build_file_urls, update_documentauthors, fuzzy_find_documents,
bibxml_for_draft)
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
from ietf.group.models import Role, Group
@ -140,12 +141,12 @@ def interesting_doc_relations(doc):
return interesting_relations_that, interesting_relations_that_doc
def document_main(request, name, rev=None):
def document_main(request, name, rev=None, document_html=False):
doc = get_object_or_404(Document.objects.select_related(), docalias__name=name)
# take care of possible redirections
aliases = DocAlias.objects.filter(docs=doc).values_list("name", flat=True)
if rev==None and doc.type_id == "draft" and not name.startswith("rfc"):
if document_html is False and rev==None and doc.type_id == "draft" and not name.startswith("rfc"):
for a in aliases:
if a.startswith("rfc"):
return redirect("ietf.doc.views_doc.document_main", name=a)
@ -169,7 +170,7 @@ def document_main(request, name, rev=None):
doc = h
break
if not snapshot:
if not snapshot and document_html is False:
return redirect('ietf.doc.views_doc.document_main', name=name)
if doc.type_id == "charter":
@ -184,7 +185,6 @@ def document_main(request, name, rev=None):
top = render_document_top(request, doc, "status", name)
telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)):
telechat = None
@ -446,8 +446,22 @@ def document_main(request, name, rev=None):
else:
stream_desc = "(None)"
return render(request, "doc/document_draft.html",
html = None
js = None
css = None
if document_html:
html = doc.html_body()
if request.COOKIES.get("pagedeps") == "inline":
js = Path(finders.find("ietf/js/document_html.js")).read_text()
css = Path(finders.find("ietf/css/document_html_inline.css")).read_text()
if html:
css += Path(finders.find("ietf/css/document_html_txt.css")).read_text()
return render(request, "doc/document_draft.html" if document_html is False else "doc/document_html.html",
dict(doc=doc,
document_html=document_html,
css=css,
js=js,
html=html,
group=group,
top=top,
name=name,
@ -787,7 +801,6 @@ def document_raw_id(request, name, rev=None, ext=None):
except:
raise Http404
def document_html(request, name, rev=None):
found = fuzzy_find_documents(name, rev)
num_found = found.documents.count()
@ -811,30 +824,7 @@ def document_html(request, name, rev=None):
if not os.path.exists(doc.get_file_name()):
raise Http404("File not found: %s" % doc.get_file_name())
if doc.type_id in ['draft',]:
doc.supermeta = build_doc_supermeta_block(doc)
doc.meta = build_doc_meta_block(doc, settings.HTMLIZER_URL_PREFIX)
doccolor = 'bgwhite' # Unknown
if doc.type_id=='draft':
if doc.is_rfc():
if doc.related_that('obs'):
doccolor = 'bgbrown'
else:
doccolor = {
'ps' : 'bgblue',
'exp' : 'bgyellow',
'inf' : 'bgorange',
'ds' : 'bgcyan',
'hist' : 'bggrey',
'std' : 'bggreen',
'bcp' : 'bgmagenta',
'unkn' : 'bgwhite',
}.get(doc.std_level_id, 'bgwhite')
else:
doccolor = 'bgred' # Draft
return render(request, "doc/document_html.html", {"doc":doc, "doccolor":doccolor })
return document_main(request, name, rev=rev, document_html=True)
def document_pdfized(request, name, rev=None, ext=None):

View file

@ -0,0 +1,316 @@
@use "sass:map";
// FIXME: It's not clear why these three variables remain unset by bs5, but just
// set them to placeholder values so the CSS embedded in the HTML validates.
$btn-font-family: inherit !default;
$nav-link-font-weight: inherit !default;
$tooltip-margin: inherit !default;
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/root";
// Layout & components
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
// @import "bootstrap/scss/images";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
// @import "bootstrap/scss/tables";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/transitions";
// @import "bootstrap/scss/dropdown";
@import "bootstrap/scss/button-group";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
// @import "bootstrap/scss/card";
// @import "bootstrap/scss/accordion";
// @import "bootstrap/scss/breadcrumb";
@import "bootstrap/scss/pagination";
@import "bootstrap/scss/badge";
@import "bootstrap/scss/alert";
// @import "bootstrap/scss/progress";
// @import "bootstrap/scss/list-group";
// @import "bootstrap/scss/close";
// @import "bootstrap/scss/toasts";
// @import "bootstrap/scss/modal";
@import "bootstrap/scss/tooltip";
// @import "bootstrap/scss/popover";
// @import "bootstrap/scss/carousel";
// @import "bootstrap/scss/spinners";
// @import "bootstrap/scss/offcanvas";
// @import "bootstrap/scss/placeholders";
// Helpers
@import "bootstrap/scss/helpers";
// Utilities
@import "bootstrap/scss/utilities/api";
:root {
--doc-ptsize-max: 16pt;
}
.overscroll-none {
overscroll-behavior: none;
}
.no-scrollbar {
scrollbar-width: none;
}
.sidebar-toggle[aria-expanded="true"] {
display: none;
}
.sidebar-toggle[aria-expanded="false"] {
display: inherit;
}
@media screen {
@include media-breakpoint-down(md) {
body {
padding-top: 60px;
}
html {
scroll-padding-top: 60px;
}
}
@include media-breakpoint-down(sm) {
body {
padding-top: 70px;
}
html {
scroll-padding-top: 70px;
}
}
}
.rfcmarkup,
.rfchtml {
font-family: var(--bs-font-monospace);
caption {
padding: 0;
color: var(--bs-body-color);
}
code {
font-size: 1em;
color: var(--bs-body-color);
}
@media screen {
@include media-breakpoint-only(xs) {
font-size: min(7pt, var(--doc-ptsize-max));
}
@include media-breakpoint-up(sm) {
font-size: min(9.5pt, var(--doc-ptsize-max));
}
@include media-breakpoint-up(md) {
font-size: min(9.5pt, var(--doc-ptsize-max));
}
@include media-breakpoint-up(lg) {
font-size: min(11pt, var(--doc-ptsize-max));
}
@include media-breakpoint-up(xl) {
font-size: min(13pt, var(--doc-ptsize-max));
}
@include media-breakpoint-up(xxl) {
font-size: min(16pt, var(--doc-ptsize-max));
}
.grey,
hr {
opacity: $hr-opacity;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: bold;
font-size: 1em;
}
pre,
code {
font-size: 1em;
}
pre {
width: 72ch;
margin: 0;
padding: 0;
}
.bcp14 {
font-weight: bold;
// color: $gray-700;
}
}
.rfcmarkup {
h1,
h2,
h3,
h4,
h5,
h6 {
white-space: pre;
display: inline;
}
}
tbody.meta tr {
td:first-child,
th:first-child,
td.edit {
display: none;
}
}
.sidebar {
height: 100vh;
.toplink,
#name-table-of-contents {
display: none;
}
th,
td {
display: block;
padding: 0;
}
td {
margin-bottom: map.get($spacers, 3);
}
}
// Add some padding when there are multiple buttons in a line that can wrap
.buttonlist .btn {
margin-bottom: map.get($spacers, 1);
}
// Make revision numbers pagination items fixed-width
.revision-list {
.page-item {
width: 2.2rem;
}
.page-item.rfc {
width: 6.6rem;
}
}
#docinfo {
max-height: 70vh;
z-index: -1;
}
.badge-obs {
color: white;
background-color: $orange-800;
}
.badge-ps {
color: black;
background-color: $blue-300;
}
.badge-exp {
color: black;
background-color: $yellow-200;
}
.badge-inf {
color: white;
background-color: $orange;
}
.badge-ds {
color: black;
background-color: $cyan-200;
}
.badge-hist {
color: white;
background-color: $gray-700;
}
.badge-std {
color: black;
background-color: $teal-200;
}
.badge-bcp {
color: white;
background-color: $pink-500;
}
.badge-unkn {
color: black;
background-color: $gray-300;
}
.badge-draft {
color: white;
background-color: $danger;
}
#toc-nav {
width: inherit;
overscroll-behavior-y: none; // Prevent overscrolling from scrolling the main content
}
@media print {
@page {
size: letter;
margin: .75in;
}
body {
margin: 0;
padding: 0;
font-size: 10pt;
}
pre {
page-break-inside: avoid;
}
a:link,
a:visited {
// color: inherit;
// text-decoration: none;
}
.newpage {
page-break-before: always !important;
}
.noprint {
display: none;
}
}

View file

@ -0,0 +1,6 @@
@import "document_html";
// Make the bootstrap icons available via data-url.
$bootstrap-icons-font-src: url(data-url:npm:bootstrap-icons/font/fonts/bootstrap-icons.woff2) format("woff2"),
url(data-url:npm:bootstrap-icons/font/fonts/bootstrap-icons.woff) format("woff");
@import "bootstrap-icons/font/bootstrap-icons";

View file

@ -0,0 +1,6 @@
@import "document_html";
// Make the bootstrap icons available.
$bootstrap-icons-font-src: url("npm:bootstrap-icons/font/fonts/bootstrap-icons.woff2") format("woff2"),
url("npm:bootstrap-icons/font/fonts/bootstrap-icons.woff") format("woff");
@import "bootstrap-icons/font/bootstrap-icons";

View file

@ -0,0 +1,376 @@
:root {
--line: 1.2em;
--block: 0 0 0 3ch;
--paragraph: var(--line) 0 var(--line) 3ch;
}
// WeasyPrint can't handle CSS variables in multi-attribute properties, so work
// around that
// https://github.com/Kozea/WeasyPrint/issues/1219
@mixin margin-paragraph {
margin-top: var(--line);
margin-right: 0;
margin-bottom: var(--line);
margin-left: 3ch;
}
@mixin margin-line {
margin-top: var(--line);
margin-right: 0;
margin-bottom: var(--line);
margin-left: 0;
}
@mixin margin-block {
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 3ch;
}
.rfchtml {
// body {
// color: black;
// font-family: monospace;
// font-size: 1em;
line-height: var(--line);
width: 72ch;
// margin: var(--line) 3ch;
margin-top: var(--line);
margin-right: 3ch;
margin-bottom: var(--line);
margin-left: 3ch;
h1, h2, h3, h4, h5 {
font-weight: bold;
font-size: inherit;
line-height: inherit;
// margin: var(--line) 0;
@include margin-line;
}
.section-number {
margin-right: 1ch;
}
p {
// margin: var(--paragraph);
@include margin-paragraph;
}
aside, ol, dl {
// margin: var(--block);
@include margin-block;
}
figure {
margin: 0;
}
blockquote {
// margin: var(--paragraph);
@include margin-paragraph;
border-left: 2px solid darkgrey;
}
/* Header junk */
#external-metadata {
display: none !important; /* metadata.min.js is evil because it produces unstyleable goop */
}
#identifiers dt:is(.label-stream, .label-rfc, .label-std, .label-bcp, .label-internet-draft,
.label-workgroup, .label-intended-status, .label-obsoletes, .label-updates,
.label-published, .label-expires, .label-category, .label-issn,
.label-authors), .ears {
display: none;
}
#identifiers {
margin: 0;
display: grid;
grid-template-columns: 47ch 24ch;
grid-auto-rows: auto;
gap: 0 1ch;
}
#identifiers dt {
margin: 0 1ch 0 0;
float: revert;
display: inline-block;
}
#identifiers dd {
grid-column: 1;
margin: 0;
width: 47ch;
/* HAXX: this gets around the lack of text-content-trim support */
display: flex;
flex-wrap: wrap;
}
#identifiers dd::before {
margin: 0 1ch 0 0;
}
#identifiers dd.rfc::before {
content: "Request for Comments:";
}
#identifiers dd.std::before {
content: "STD:";
}
#identifiers dd.bcp::before {
content: "BCP:";
}
#identifiers dd.internet-draft::before {
content: "Internet-Draft:";
}
#identifiers dd.workgroup::before {
content: "Workgroup:";
}
#identifiers dd.intended-status::before {
content: "Intended Status:";
}
#identifiers dd.obsoletes::before {
content: "Obsoletes:";
margin: 0 0 0 -10ch;
}
#identifiers dd.obsoletes {
padding-left: 10ch;
width: 37ch;
}
#identifiers dd.updates::before {
content: "Updates:";
margin: 0 0 0 -8ch;
}
#identifiers dd.updates {
padding-left: 8ch;
width: 39ch;
}
#identifiers dd:is(.updates, .obsoletes) a {
margin: 0 0 0 1ch;
}
#identifiers dd:is(.updates, .obsoletes) a:last-of-type {
margin: 0 1ch;
}
#identifiers dd.published::before {
content: "Published:";
}
#identifiers dd.expires::before {
content: "Expires:";
}
#identifiers dd.category::before {
content: "Category:";
}
#identifiers dd.issn::before {
content: "ISSN:";
}
#identifiers dd.authors {
grid-area: 1 / 2 / 100 / 3;
width: 24ch;
text-align: right;
display: block;
}
#title {
clear: left;
text-align: center;
margin-top: 2em;
}
#rfcnum {
display: none;
}
.toplink {
display: none;
}
nav.toc ul {
list-style: none;
margin: 0;
padding: 0;
}
nav.toc ul > li {
padding-left: 2ch;
}
nav.toc > ul > li {
padding-left: 3ch;
}
nav.toc ul > li > p {
margin: 0;
}
/* Lists */
ol, ul {
padding: 0;
}
ol {
margin: 0 0 0 6ch; /* todo: deal with lists that have >= 10 items */
}
ol ol, ul ol {
margin: 0 0 0 3ch;
}
ul {
margin: 0 0 0 4ch;
list-style-type: '*';
}
ul ul {
list-style-type: '-';
}
ul ul, ol ul {
margin-left: 1ch;
}
ul ul ul {
list-style-type: 'o';
}
li {
// margin: var(--line) 0;
@include margin-line;
padding: 0 0 0 2ch;
}
.compact li {
margin: 0;
}
li p:first-child, dd p:first-child {
margin: 0;
}
dt {
float: left;
clear: left;
margin: 0 2ch 0 0;
break-after: avoid;
}
dd {
// margin: var(--paragraph);
@include margin-paragraph;
break-before: avoid;
}
dl.compact dt, dl.compact dd {
margin-top: 0;
margin-bottom: 0;
}
dl.references dt {
margin-right: 1ch;
}
dl.references dd {
margin-left: 11ch;
}
dd.break {
display: none;
}
/* Figures, tables */
pre {
// margin: var(--line) 0;
@include margin-line;
}
div.artwork, div.sourcecode {
display: flex;
flex-wrap: nowrap;
align-items: end;
}
div.artwork.alignCenter, div.sourcecode.alignCenter {
justify-content: center;
}
div.artwork.alignRight, div.sourcecode.alignRight {
justify-content: end;
}
div.artwork::before, div.sourcecode::before {
flex: 0 1 3ch;
content: "";
}
div.artwork.alignRight::before, div.sourcecode.alignRight::before {
flex-grow: 1;
}
div.artwork pre, div.sourcecode pre {
flex: 0 0 content;
margin: 0;
max-width: 72ch;
overflow: auto;
}
div.artwork .pilcrow, div.sourcecode .pilcrow {
flex: 0 0 1ch;
}
figcaption, table caption {
text-align: center;
margin-top: var(--line);
}
table {
--half-line: calc(var(--line) / 2 - 1px);
caption-side: bottom;
// margin: var(--line) 0 var(--half-line) 3ch;
margin-top: var(--line);
margin-right: 0;
margin-bottom: var(--half-line);
margin-left: 3ch;
border-collapse: collapse;
}
table.center {
margin-left: auto; /* todo: add 3ch */
margin-right: auto;
}
table caption {
margin-top: calc(var(--half-line) + var(--line));
}
thead, tfoot {
border-top-style: double;
border-bottom-style: double;
}
td, th {
border: 1px solid black;
// padding: var(--half-line) 1ch;
padding-top: var(--half-line);
padding-right: 1ch;
padding-bottom: var(--half-line);
padding-left: 1ch;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
/* Links */
a.selfRef, a.pilcrow {
color: black;
text-decoration: none;
}
a.relref, a.xref {
hyphens: none;
}
a.relref, a.xref.cite {
white-space: nowrap;
}
.pilcrow {
display: inline-block;
margin-right: -1ch;
opacity: 0.01;
text-decoration: none;
}
:hover > .pilcrow {
opacity: 0.2;
}
* > .pilcrow[href]:hover {
opacity: 0.6;
}
/* sup, sub */
sup, sub {
line-height: 1.1;
}
/* Authors */
address {
font-style: normal;
// margin: 2em 0 var(--line) 3ch;
margin-top: 2em;
margin-right: 0;
margin-bottom: var(--line);
margin-left: 3ch;
}
h2 + address {
margin-top: 1em;
}
address .tel, address .email {
// margin: var(--line) 0 0;
margin-top: var(--line);
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
}
address .tel + .email {
margin: 0;
}
}

View file

@ -168,8 +168,9 @@ table tbody.meta {
}
}
// Try and hyphenate table headings
th {
// Try and hyphenate table headings and other things
th,
.hyphenate {
hyphens: auto;
}
@ -208,6 +209,17 @@ th {
max-width: 300px;
}
// Make revision numbers pagination items fixed-width
.revision-list {
.page-item {
width: 2.2rem;
}
.page-item.rfc {
width: 6.6rem;
}
}
// Style the photo cards
.photo {
width: 12em;

View file

@ -1 +1,76 @@
<svg width="765" height="990" style="display:inline" xmlns="http://www.w3.org/2000/svg"><g style="display:inline"><text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:0%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black,';text-align:start;letter-spacing:0;word-spacing:0;writing-mode:lr-tb;text-anchor:start;fill:#fff;fill-opacity:1;stroke:#000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" x="250.217" y="565.473" transform="translate(0 -62.362)"><tspan x="250.217" y="565.473" style="font-size:102.5px;line-height:1.25">R</tspan></text><path style="fill:#bdbcbc;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m134.869 273.355-44.033 44.031 44.033 44.034 44.032-44.034-44.032-44.03m519.185-.001-44.032 44.031 44.032 44.034 44.031-44.034-44.03-44.03m-311.778-.001-44.032 44.031 44.032 44.034 44.032-44.034-44.032-44.03m103.693-.001-44.032 44.031 44.032 44.034 44.032-44.034-44.032-44.03m103.693-.001-44.032 44.031 44.032 44.034 44.033-44.034-44.033-44.03M290.8 325.407l-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032m-52.217-52.052-44.033 44.031 44.033 44.034 44.033-44.034-44.033-44.03m155.911 52.051-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032m103.693 0-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032M290.8 221.827l-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031m103.694 0-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031m103.693 0-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031" transform="translate(0 -62.362)"/><path style="fill:#fccf34;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M98.431 312.254h90.633l49.886 49.886 51.52-51.52 51.807 51.807 104.12-104.12 52.06 52.059 51.52-51.52 53.948 53.949H692.4v10.248h-92.79l-49.903-49.901-51.79 51.79-51.79-51.79-103.58 103.581-51.79-51.792-51.52 51.522-54.22-54.22H97.89l.54-9.98" transform="translate(0 -62.362)"/><path style="fill:none;stroke:#0c0a08;stroke-width:1.90799999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="M98.431 312.254h90.633l49.886 49.886 51.52-51.52 51.807 51.807 104.12-104.12 52.06 52.059 51.52-51.52 53.948 53.949H692.4v10.248h-92.79l-49.903-49.901-51.79 51.79-51.79-51.79-103.58 103.581-51.79-51.792-51.52 51.522-54.22-54.22H97.89l.54-9.98z" transform="translate(0 -62.362)"/><path style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M79.997 327.492h21.04v-19.421h-21.04v19.421zm606.244 0h21.04v-19.421h-21.04v19.421zM98.468 565.473h25.715v-73.378H98.468v73.378zm341.277-54.979v-18.399h71.55v18.399h-22.919v54.979h-25.714v-54.98h-22.917m200.334-18.398h53.58v15.494h-27.867v13.34h26.145v15.495h-26.145v29.049H640.08v-73.378" transform="translate(0 -62.362)"/><path style="fill:#fff;fill-opacity:1;stroke:#000;stroke-width:1.90800011;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" d="m446.283 169.434-29.062 29.06 29.062 29.062 29.06-29.062-29.06-29.06m-111.179 7.485-29.061 29.06 29.06 29.062 29.062-29.062-29.061-29.06m-148.231 44.032-29.061 29.06 29.061 29.063 29.061-29.062-29.061-29.06m37.408 171.686-29.061 29.06 29.061 29.063 29.061-29.062-29.06-29.06m222.358-14.971-29.061 29.06 29.06 29.062 29.062-29.062-29.061-29.06m155.211-22.201-29.061 29.06 29.061 29.062 29.061-29.062-29.061-29.06M224.145 184.184l-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m52.217-22.027-14.53 14.53 14.53 14.531 14.53-14.531-14.53-14.53m14.751-44.252-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m74.192 29.501-14.531 14.53 14.531 14.53 14.53-14.53-14.53-14.53m118.444-14.751-14.531 14.53 14.53 14.531 14.532-14.53-14.531-14.53m29.501 29.501-14.53 14.53 14.53 14.531 14.53-14.531-14.53-14.53m51.477 22.027-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531M201.855 369.897l-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m89.615 59.823-14.531 14.53 14.531 14.53L306 444.25l-14.53-14.53m103.693 0-14.53 14.53 14.53 14.53 14.53-14.53-14.53-14.53m140.42-37.302-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.53m-36.726 37.301-14.531 14.53 14.53 14.53 14.531-14.53-14.53-14.53m-140.94-37.082-29.06 29.06 29.06 29.063 29.062-29.062-29.062-29.06m243.488-171.688-14.531 14.53 14.53 14.532 14.531-14.531-14.53-14.53m-28.713-73.546-14.531 14.53 14.53 14.53 14.531-14.53-14.53-14.53" transform="translate(0 -62.362)"/></g></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="627.284"
height="449.19662"
style="display:inline"
version="1.1"
id="svg303"
sodipodi:docname="irtf-logo.svg"
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs307" />
<sodipodi:namedview
id="namedview305"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.0373737"
inkscape:cx="304.1334"
inkscape:cy="446.80136"
inkscape:window-width="1797"
inkscape:window-height="1083"
inkscape:window-x="951"
inkscape:window-y="445"
inkscape:window-maximized="0"
inkscape:current-layer="svg303" />
<g
style="display:inline"
id="g301"
transform="translate(-79.997,-54.868397)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:0%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black,';text-align:start;letter-spacing:0;word-spacing:0;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="250.217"
y="565.47302"
transform="translate(0,-62.362)"
id="text289"><tspan
x="250.217"
y="565.47302"
style="font-size:102.5px;line-height:1.25"
id="tspan287">R</tspan></text>
<path
style="fill:#bdbcbc;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 134.869,273.355 -44.033,44.031 44.033,44.034 44.032,-44.034 -44.032,-44.03 m 519.185,-10e-4 -44.032,44.031 44.032,44.034 44.031,-44.034 -44.03,-44.03 m -311.778,-10e-4 -44.032,44.031 44.032,44.034 44.032,-44.034 -44.032,-44.03 m 103.693,-10e-4 -44.032,44.031 44.032,44.034 44.032,-44.034 -44.032,-44.03 m 103.693,-10e-4 -44.032,44.031 44.032,44.034 44.033,-44.034 -44.033,-44.03 M 290.8,325.407 246.768,369.439 290.8,413.471 334.832,369.439 290.8,325.407 m -52.217,-52.052 -44.033,44.031 44.033,44.034 44.033,-44.034 -44.033,-44.03 m 155.911,52.051 -44.032,44.032 44.032,44.032 44.032,-44.032 -44.032,-44.032 m 103.693,0 -44.032,44.032 44.032,44.032 44.032,-44.032 -44.032,-44.032 M 290.8,221.827 246.768,265.857 290.8,309.891 334.832,265.858 290.8,221.827 m 103.694,0 -44.032,44.03 44.032,44.034 44.032,-44.033 -44.032,-44.031 m 103.693,0 -44.032,44.03 44.032,44.034 44.032,-44.033 -44.032,-44.031"
transform="translate(0,-62.362)"
id="path291" />
<path
style="fill:#fccf34;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 98.431,312.254 h 90.633 l 49.886,49.886 51.52,-51.52 51.807,51.807 104.12,-104.12 52.06,52.059 51.52,-51.52 53.948,53.949 H 692.4 v 10.248 h -92.79 l -49.903,-49.901 -51.79,51.79 -51.79,-51.79 -103.58,103.581 -51.79,-51.792 -51.52,51.522 -54.22,-54.22 H 97.89 l 0.54,-9.98"
transform="translate(0,-62.362)"
id="path293" />
<path
style="fill:none;stroke:#0c0a08;stroke-width:1.908;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 98.431,312.254 h 90.633 l 49.886,49.886 51.52,-51.52 51.807,51.807 104.12,-104.12 52.06,52.059 51.52,-51.52 53.948,53.949 H 692.4 v 10.248 h -92.79 l -49.903,-49.901 -51.79,51.79 -51.79,-51.79 -103.58,103.581 -51.79,-51.792 -51.52,51.522 -54.22,-54.22 H 97.89 l 0.54,-9.98 z"
transform="translate(0,-62.362)"
id="path295" />
<path
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 79.997,327.492 h 21.04 v -19.421 h -21.04 z m 606.244,0 h 21.04 v -19.421 h -21.04 z M 98.468,565.473 h 25.715 V 492.095 H 98.468 Z m 341.277,-54.979 v -18.399 h 71.55 v 18.399 h -22.919 v 54.979 h -25.714 v -54.98 h -22.917 m 200.334,-18.398 h 53.58 v 15.494 h -27.867 v 13.34 h 26.145 v 15.495 h -26.145 v 29.049 H 640.08 v -73.378"
transform="translate(0,-62.362)"
id="path297" />
<path
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 446.283,169.434 -29.062,29.06 29.062,29.062 29.06,-29.062 -29.06,-29.06 m -111.179,7.485 -29.061,29.06 29.06,29.062 29.062,-29.062 -29.061,-29.06 m -148.231,44.032 -29.061,29.06 29.061,29.063 29.061,-29.062 -29.061,-29.06 m 37.408,171.686 -29.061,29.06 29.061,29.063 29.061,-29.062 -29.06,-29.06 m 222.358,-14.971 -29.061,29.06 29.06,29.062 29.062,-29.062 -29.061,-29.06 m 155.211,-22.201 -29.061,29.06 29.061,29.062 29.061,-29.062 -29.061,-29.06 m -377.706,-171.283 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 52.217,-22.027 -14.53,14.53 14.53,14.531 14.53,-14.531 -14.53,-14.53 m 14.751,-44.252 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 74.192,29.501 -14.531,14.53 14.531,14.53 14.53,-14.53 -14.53,-14.53 m 118.444,-14.751 -14.531,14.53 14.53,14.531 14.532,-14.53 -14.531,-14.53 m 29.501,29.501 -14.53,14.53 14.53,14.531 14.53,-14.531 -14.53,-14.53 m 51.477,22.027 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m -362.872,185.713 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 89.615,59.823 -14.531,14.53 14.531,14.53 14.53,-14.53 -14.53,-14.53 m 103.693,0 -14.53,14.53 14.53,14.53 14.53,-14.53 -14.53,-14.53 m 140.42,-37.302 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.53 m -36.726,37.301 -14.531,14.53 14.53,14.53 14.531,-14.53 -14.53,-14.53 m -140.94,-37.082 -29.06,29.06 29.06,29.063 29.062,-29.062 -29.062,-29.06 m 243.488,-171.688 -14.531,14.53 14.53,14.532 14.531,-14.531 -14.53,-14.53 m -28.713,-73.546 -14.531,14.53 14.53,14.53 14.531,-14.53 -14.53,-14.53"
transform="translate(0,-62.362)"
id="path299" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1,86 @@
import {
Tooltip as Tooltip,
// Button as Button,
// Collapse as Collapse,
// ScrollSpy as ScrollSpy,
Tab as Tab
} from "bootstrap";
import Cookies from "js-cookie";
import { populate_nav } from "./nav.js";
const cookies = Cookies.withAttributes({ sameSite: "strict" });
document.addEventListener("DOMContentLoaded", function (event) {
// handle point size slider
const cookie = "doc-ptsize-max";
function change_ptsize(ptsize) {
document.documentElement.style.setProperty(`--${cookie}`,
`${ptsize}pt`);
cookies.set(cookie, ptsize);
}
document.getElementById("ptsize")
.oninput = function () { change_ptsize(this.value) };
const ptsize = cookies.get(cookie);
change_ptsize(ptsize ? Math.min(Math.max(7, ptsize), 16) : 12);
// Use the Bootstrap tooltip plugin for all elements with a title attribute
const tt_triggers = document.querySelectorAll(
"[title]:not([title=''])");
[...tt_triggers].map(tt_el => {
const tooltip = Tooltip.getOrCreateInstance(tt_el);
tt_el.addEventListener("click", el => {
tooltip.hide();
tt_el.blur();
});
});
// Rewrite ids and hrefs to not contains dots (bug in bs5.2 scrollspy)
// See https://github.com/twbs/bootstrap/issues/34381
// TODO: check if this can be removed when bs5 is updated
const ids = document.querySelectorAll(
"#content [id^=section-], #content [id^=appendix-]");
[...ids].map(id_el => id_el.id = id_el.id.replaceAll(/\./g, "-"));
const hrefs = document.querySelectorAll(
"#content [href*='#section-'], #content [href*='#appendix-']"
);
[...hrefs].map(id_el => {
const href = new URL(id_el.href);
href.hash = href.hash.replaceAll(/\./g, "-");
id_el.href = href.href;
});
// Set up a nav pane
const toc_pane = document.getElementById("toc-nav");
populate_nav(toc_pane,
`#content h2, #content h3, #content h4, #content h5, #content h6
#content .h1, #content .h2, #content .h3, #content .h4, #content .h5, #content .h6`,
["py-0"]);
// activate pref buttons selected by pref cookies
document.querySelectorAll(".btn-check")
.forEach(btn => {
const id = btn.id.replace("-radio", "");
if (cookies.get(btn.name) == id) {
btn.checked = true;
}
btn.addEventListener("click", el => {
cookies.set(btn.name, id);
window.location.reload();
});
});
// activate tab selected in prefs
let defpane;
try {
defpane = Tab.getOrCreateInstance(
`#${cookies.get("deftab")}-tab`);
} catch (err) {
defpane = Tab.getOrCreateInstance("#docinfo-tab");
};
defpane.show();
document.activeElement.blur();
});

View file

@ -24,7 +24,7 @@ if (!process.env.BUILD_DEPLOY) {
import Cookies from "js-cookie";
import debounce from "lodash/debounce";
import { populate_nav } from "./nav.js";
// setup CSRF protection using jQuery
function csrfSafeMethod(method) {
@ -154,9 +154,9 @@ $(document)
$(function () {
const contentElement = $('#content.ietf-auto-nav');
if (contentElement.length > 0) {
const heading_selector = "h2:not([style='display:none']):not(.navskip), h3:not([style='display:none']):not(.navskip), h4:not([style='display:none']):not(.navskip), h5:not([style='display:none']):not(.navskip), h6:not([style='display:none']):not(.navskip), .nav-heading:not([style='display:none']):not(.navskip)";
const headings = contentElement
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible, .nav-heading:visible")
.not(".navskip");
.find(heading_selector);
const contents = (headings.length > 0) &&
($(headings)
@ -178,8 +178,6 @@ $(function () {
if (pageTooTall || haveExtraNav) {
// console.log("Enabling nav.");
let n = 0;
let last_level;
contentElement
.attr("data-bs-offset", 0)
@ -197,48 +195,7 @@ $(function () {
.children()
.last();
contentElement
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible, .nav-heading:visible")
.not(".navskip")
.each(function () {
// Some headings have line breaks in them - only use first line in that case.
const frag = $(this)
.html()
.split("<br")
.shift();
const text = $.parseHTML(frag)
.map(x => $(x)
.text())
.join(" ");
if (text === undefined || text === "") {
// Nothing to do for empty headings.
return;
}
let id = $(this)
.attr("id");
if (id === undefined) {
id = `autoid-${++n}`;
$(this)
.attr("id", id);
}
const level = parseInt(this.nodeName.substring(1)) - 1;
if (!last_level) {
last_level = level;
}
if (level > last_level) {
last_level = level;
} else
while (level < last_level) {
last_level--;
}
$(nav)
.append(`<a class="nav-link" href="#${id}">${text}</a>`);
});
populate_nav(nav[0], heading_selector);
if (haveExtraNav) {
$('#righthand-panel').append('<div id="righthand-extra" class="w-100 py-3"></div>');
@ -246,18 +203,6 @@ $(function () {
extraNav.remove();
}
$(document)
// Chrome apparently wants this debounced to something >10ms,
// otherwise the main view doesn't scroll?
.on("scroll", debounce(function () {
const item = $('#righthand-nav')
.find(".active")
.last();
if (item.length) {
item[0].scrollIntoView({ block: "center", behavior: "smooth" });
}
}, 100));
// offset the scrollspy to account for the menu bar
const contentOffset = contentElement ? contentElement.offset().top : 0;

100
ietf/static/js/nav.js Normal file
View file

@ -0,0 +1,100 @@
import debounce from "lodash/debounce";
function make_nav() {
const nav = document.createElement("nav");
nav.classList.add("nav-pills", "ps-3", "flex-column");
return nav;
}
function get_level(el) {
let h;
if (el.tagName.match(/^h\d/i)) {
h = el.tagName
} else {
el.classList.forEach(cl => {
if (cl.match(/^h\d/i)) {
h = cl;
return;
}
});
}
return h.charAt(h.length - 1);
}
export function populate_nav(nav, heading_selector, classes) {
// Extract section headings from document
const headings = document.querySelectorAll(heading_selector);
const min_level = Math.min(...Array.from(headings)
.map(get_level));
let nav_stack = [nav];
let cur_level = 0;
let n = 0;
headings.forEach(el => {
const level = get_level(el) - min_level;
if (level < cur_level) {
while (level < cur_level) {
let nav = nav_stack.pop();
cur_level--;
nav_stack[level].appendChild(nav);
}
} else {
while (level > cur_level) {
nav_stack.push(make_nav());
cur_level++;
}
}
const link = document.createElement("a");
link.classList.add("nav-link", "ps-1", "d-flex", "hyphenate",
classes);
if (!el.id) {
el.id = `autoid-${++n}`;
}
link.href = `#${el.id}`;
const words = el.innerText.split(/\s+/);
let nr = "";
if (words[0].includes(".")) {
nr = words.shift();
} else if (words.length > 1 && words[1].includes(".")) {
nr = words.shift() + " " + words.shift();
nr = nr.replace(/\s*Appendix\s*/, "");
}
if (nr) {
const number = document.createElement("div");
number.classList.add("pe-1");
number.textContent = nr;
link.appendChild(number);
}
const text = document.createElement("div");
text.classList.add("text-break");
text.textContent = words.join(" ");
link.appendChild(text);
nav_stack[level].appendChild(link);
});
for (var i = nav_stack.length - 1; i > 0; i--) {
nav_stack[i - 1].appendChild(nav_stack[i]);
}
// Chrome apparently wants this debounced to something >10ms,
// otherwise the main view doesn't scroll?
document.addEventListener("scroll", debounce(function () {
const items = nav.querySelectorAll(".active");
const item = [...items].pop();
console.log(item);
if (item) {
item.scrollIntoView({
block: "center",
behavior: "smooth"
});
}
}, 100));
}

View file

@ -26,7 +26,7 @@
{% block content %}
{% origin %}
{{ top|safe }}
{% include "doc/revisions_list.html" %}
{% include "doc/revisions_list.html" with document_html=document_html %}
<div id="timeline"></div>
{% if doc.rev != latest_rev %}
<div class="alert alert-warning my-3">The information below is for an old version of the document.</div>
@ -38,363 +38,7 @@
{% endif %}
{% endif %}
<table class="table table-sm table-borderless">
<tbody class="meta border-top">
<tr>
<th scope="row">Document</th>
<th scope="row">Type</th>
<td class="edit"></td>
<td>
{% if doc.get_state_slug == "rfc" and not snapshot %}
<span class="text-success">RFC - {{ doc.std_level }}</span>
{% if published %}
({{ doc.pub_date|date:"F Y" }})
{% else %}
(Publication date unknown)
{% endif %}
{% if has_verified_errata %}
<a class="badge rounded-pill bg-danger text-decoration-none text-light"
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
Errata
</a>
{% elif has_errata %}
<a class="badge rounded-pill bg-warning text-decoration-none text-light"
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
Errata
</a>
{% endif %}
{% if obsoleted_by %}<div>Obsoleted by {{ obsoleted_by|urlize_related_source_list|join:", " }}</div>{% endif %}
{% if updated_by %}<div>Updated by {{ updated_by|urlize_related_source_list|join:", " }}</div>{% endif %}
{% if obsoletes %}<div>Obsoletes {{ obsoletes|urlize_related_target_list|join:", " }}</div>{% endif %}
{% if updates %}<div>Updates {{ updates|urlize_related_target_list|join:", " }}</div>{% endif %}
{% if status_changes %}
<div>Status changed by {{ status_changes|urlize_related_source_list|join:", " }}</div>
{% endif %}
{% if proposed_status_changes %}
<div>Proposed status changed by {{ proposed_status_changes|urlize_related_source_list|join:", " }}</div>
{% endif %}
{% if rfc_aliases %}<div>Also known as {{ rfc_aliases|join:", "|urlize_ietf_docs }}</div>{% endif %}
{% if draft_name %}
<div>
Was
<a href="{% url 'ietf.doc.views_doc.document_main' name=draft_name %}">{{ draft_name }}</a>
{% if submission %}({{ submission|safe }}){% endif %}
</div>
{% endif %}
{% else %}
{% if snapshot and doc.doc.get_state_slug == 'rfc' %}
<span>This is an older version of an Internet-Draft that was ultimately published as an RFC.</span>
{% elif snapshot and doc.rev != latest_rev %}
<span>This is an older version of an Internet-Draft whose latest revision is {{ doc.doc.get_state }}</span>
{% else %}
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
{% if submission %}({{ submission|safe }}){% endif %}
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
<tr>
<td></td>
<th scope="row">Author{{ doc.authors|pluralize }}</th>
<td class="edit">
{% if can_edit_authors %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_doc.edit_authors' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{# Implementation that uses the current primary email for each author #}
{% for author in doc.authors %}
{% person_link author %}{% if not forloop.last %},{% endif %}
{% endfor %}
</td>
</tr>
<tr>
<td></td>
<th scope="row">Last updated</th>
<td class="edit"></td>
<td>
{{ doc.time|date:"Y-m-d" }}
{% if latest_revision and latest_revision.time|date:"Y-m-d" != doc.time|date:"Y-m-d" %}
<span class="text-muted">(Latest revision {{ latest_revision.time|date:"Y-m-d" }})</span>
{% endif %}
</td>
</tr>
{% if replaces or can_edit_stream_info %}
<tr>
<td></td>
<th scope="row">Replaces</th>
<td class="edit">
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{% if replaces %}
{{ replaces|urlize_related_target_list|join:", " }}
{% else %}
<span class="text-muted">(None)</span>
{% endif %}
</td>
</tr>
{% endif %}
{% if replaced_by %}
<tr>
<td></td>
<th scope="row">
Replaced by
</th>
<td class="edit">
</td>
<td>
{{ replaced_by|urlize_related_source_list|join:", " }}
</td>
</tr>
{% endif %}
{% if can_view_possibly_replaces %}
{% if possibly_replaces %}
<tr>
<td></td>
<th scope="row">
Possibly Replaces
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{{ possibly_replaces|urlize_related_target_list|join:", " }}
</td>
</tr>
{% endif %}
{% if possibly_replaced_by %}
<tr>
<td></td>
<th scope="row">
Possibly Replaced By
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
{% comment %}<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
{% endif %}
</td>
<td>
{{ possibly_replaced_by|urlize_related_source_list|join:", " }}
</td>
</tr>
{% endif %}
{% endif %}
<tr>
<td></td>
<th scope="row">
Stream
</th>
<td class="edit">
{% if can_change_stream and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.change_stream' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td {% if stream_desc == "(None)" %}class="text-muted"{%endif%}>
{{ stream_desc }}
</td>
</tr>
{% if doc.get_state_slug != "rfc" and not snapshot %}
<tr>
<td></td>
<th scope="row">
Intended RFC status
</th>
<td class="edit">
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.change_intention' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if doc.intended_std_level %}
{{ doc.intended_std_level }}
{% else %}
<span class="text-muted">
(None)
</span>
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<td></td>
<th scope="row">
Formats
</th>
<td class="edit">
</td>
<td>
{% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" %}
<div class="badge rounded-pill bg-warning float-end">
Expired &amp; archived
</div>
{% endif %}
{% include "doc/document_format_buttons.html" %}
</td>
</tr>
{% for check in doc.submission.latest_checks %}
{% if check.passed != None and check.symbol.strip %}
<tr>
<td></td>
<th scope="row">
{{ check.checker|title }}
</th>
<td class="edit">
</td>
<td>
{% if check.errors or check.warnings %}
<span class="checker-warning"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}"
title="{{ check.checker|title }} returned warnings or errors.">
{{ check.symbol|safe }}
</span>
{% else %}
<span class="checker-success"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}"
title="{{ check.checker|title }} passed">
{{ check.symbol|safe }}
</span>
{% endif %}
<a href="#"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}">
{{ check.errors }} errors, {{ check.warnings }} warnings
</a>
{% include "doc/yang-check-modal-overlay.html" %}
</td>
</tr>
{% endif %}
{% endfor %}
{% if review_assignments or can_request_review %}
<tr>
<td></td>
<th scope="row">
Reviews
</th>
<td class="edit">
</td>
<td>
{% for review_assignment in review_assignments %}
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
{% endfor %}
{% if no_review_from_teams %}
{% for team in no_review_from_teams %}
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
{% endfor %}
will not review this version
{% endif %}
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
<div {% if review_assignments or no_review_from_teams %} class="mt-3"{% endif %}>
{% if can_request_review %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
<i class="bi bi-check-circle">
</i>
Request review
</a>
{% endif %}
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% elif can_submit_unsolicited_review_for_teams %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% endif %}
</div>
{% endif %}
</td>
</tr>
{% endif %}
{% if conflict_reviews %}
<tr>
<td></td>
<th scope="row">
IETF conflict review
</th>
<td class="edit">
</td>
<td>
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
</td>
</tr>
{% endif %}
{% with doc.docextresource_set.all as resources %}
{% if resources or can_edit_stream_info or can_edit_individual %}
<tr>
<td>
</td>
<th scope="row">
Additional resources
</th>
<td class="edit">
{% if can_edit_stream_info or can_edit_individual %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.edit_doc_extresources' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if resources or doc.group and doc.group.list_archive %}
{% for resource in resources|dictsort:"display_name" %}
{% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %}
<a href="{{ resource.value }}" title="{{ resource.name.name }}">
{% firstof resource.display_name resource.name.name %}
</a>
<br>
{# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #}
{% else %}
<span title="{{ resource.name.name }}">
{% firstof resource.display_name resource.name.name %}: {{ resource.value|escape }}
</span>
<br>
{% endif %}
{% endfor %}
{% if doc.group and doc.group.list_archive %}
{% if doc.group.list_archive|startswith:settings.MAILING_LIST_ARCHIVE_URL %}
<a href="{{ doc.group.list_archive }}?q={{ doc.name }}">
Mailing list discussion
</a>
{% elif doc.group.list_archive|is_valid_url %}
<a href="{{ doc.group.list_archive }}">
Mailing list discussion
</a>
{% else %}
{{ doc.group.list_archive|urlencode }}
{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
{% endif %}
{% endwith %}
</tbody>
{% include "doc/document_info.html" %}
<tbody class="meta border-top">
<tr>
<th scope="row">

View file

@ -1,7 +1,18 @@
{% if file_urls %}
<div class="buttonlist">
{% for label, url in file_urls %}
<a class="btn btn-primary btn-sm" href="{{ url }}">
{% if label != skip_format %}
<a class="btn btn-primary btn-sm"
{% if label == 'pdf' or label == 'pdfized' %}
download="{% if not snapshot and doc.get_state_slug == 'rfc' %}rfc{{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}.pdf"
{% comment %}
TODO: determine if we want bibtex to jiust download
{% elif label == 'bibtex' %}
download="{% if not snapshot and doc.get_state_slug == 'rfc' %}rfc{{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}.bib"
{% endcomment %}
{% endif %}
{% if label != 'htmlized' %}target="_blank"{% endif %}
href="{{ url }}">
{% if label == 'pdf' or label == 'pdfized' %}
<i class="bi bi-file-pdf"></i> pdf
{% elif label == 'xml' or label == 'html' %}
@ -16,6 +27,7 @@
<i class="bi bi-file-diff"></i> w/errata
{% endif %}
</a>
{% endif %}
{% endfor %}
</div>
{% else %}

View file

@ -1,92 +1,276 @@
{% extends "doc/htmlized_base.html" %}
{# Copyright The IETF Trust 2016, All Rights Reserved #}
<!DOCTYPE html>
{% load analytical %}
{% load origin %}
{% load static %}
{% load ietf_filters %}
{% block pagehead %}
{% load ietf_filters textfilters %}
{% origin %}
<html lang="en">
<head>
{% analytical_head_top %}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>
{% if not snapshot and doc.get_state_slug == "rfc" %}
RFC {{ doc.rfc_number }} - {{ doc.title }}
{% else %}
{{ doc.name }}-{{ doc.rev }}
{% endif %}
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
{% if request.COOKIES.pagedeps == 'inline' %}
<script>{{ js|safe }}</script>
<style>{{ css|safe }}</style>
{% else %}
<link rel="stylesheet" href="{% static 'ietf/css/document_html_referenced.css' %}">
{% if html %}
<link rel="stylesheet" href="{% static 'ietf/css/document_html_txt.css' %}">
{% endif %}
<script src="{% static 'ietf/js/document_html.js' %}"></script>
{% endif %}
<link rel="alternate"
type="application/atom+xml"
title="Document changes"
href="/feed/document-changes/{{ doc.name }}/">
<meta name="description"
{% if doc.get_state_slug == "rfc" %}
content="{{ doc.title }} (RFC {{ doc.rfc_number }}{% if published %}, {{ published.time|date:"F Y" }}{% endif %}{% if obsoleted_by %}; obsoleted by {{ obsoleted_by|join:", " }}{% endif %})"
{% if not snapshot and doc.get_state_slug == 'rfc' %}
content="{{ doc.title }} (RFC {{ doc.rfc_number }}{% if published %}, {{ published.time|date:'F Y' }}{% endif %}{% if obsoleted_by %}; obsoleted by {{ obsoleted_by|join:', ' }}{% endif %}"
{% else %}
content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:"Y" }})"
content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:'Y' }})"
{% endif %}>
{% endblock %}
{% block morecss %}
.bgwhite { background-color: white; }
.bgred { background-color: #F44; }
.bggrey { background-color: #666; }
.bgbrown { background-color: #840; }
.bgorange { background-color: #FA0; }
.bgyellow { background-color: #EE0; }
.bgmagenta{ background-color: #F4F; }
.bgblue { background-color: #66F; }
.bgcyan { background-color: #4DD; }
.bggreen { background-color: #4F4; }
.draftcontent { margin-top:1em;}
{% endblock %}
{% block title %}
{% if doc.get_state_slug == "rfc" %}
RFC {{ doc.rfc_number }} - {{ doc.title }}
{% include "base/icons.html" %}
{% include "doc/opengraph.html" %}
{% analytical_head_bottom %}
</head>
<body>
{% analytical_body_top %}
<button class="btn btn-outline-secondary position-fixed top-0 end-0 m-2 sidebar-toggle"
type="button"
id="sidebar-on"
data-bs-toggle="collapse"
data-bs-target="#sidebar"
aria-expanded="{% if request.COOKIES.sidebar != 'off'%}true{% else %}false{% endif %}"
aria-controls="sidebar"
aria-label="Show metadata sidebar"
title="Show metadata sidebar">
<i class="bi bi-layout-sidebar-reverse"></i>
</button>
<nav class="navbar navbar-light bg-light px-1 fixed-top d-print-none d-md-none">
<a class="nav-link ps-1"
href="{% url 'ietf.doc.views_doc.document_main' name=doc.canonical_name %}">
{% if not snapshot and doc.get_state_slug == "rfc" %}
RFC {{ doc.rfc_number }}
{% else %}
{{ doc.name }}-{{ doc.rev }}
{% endif %}
{% endblock %}
{% block content %}
<!-- [html-validate-disable-block no-inline-style, attr-quotes, void-style -- FIXME: it's everywhere in this old code] -->
{% origin %}
<br class="d-sm-none">
<span class="ms-sm-3 badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
{% if not snapshot %}
{{ doc.std_level }}
{% else %}
Internet-Draft
{% endif %}
</span>
</a>
<button class="navbar-toggler p-1"
type="button"
data-bs-toggle="collapse"
data-bs-target="#docinfo-collapse"
aria-controls="docinfo-collapse"
aria-expanded="false"
aria-label="Show document information">
<span class="navbar-toggler-icon small"></span>
</button>
<div class="navbar-nav navbar-nav-scroll overscroll-none collapse pt-1" id="docinfo-collapse">
<div class="bg-light p-0">
<table class="table table-sm table-borderless small">
<tbody class="meta align-top">
<tr>
<th scope="row"></th>
<th scope="row">Title</th>
<td class="edit"></td>
<td>{{ doc.title }}</td>
</tr>
</tbody>
{% include "doc/document_info.html" with sidebar=False %}
</table>
</div>
</div>
</nav>
<div class="row g-0">
<div class="col d-flex justify-content-center lh-sm"
data-bs-spy="scroll"
data-bs-target="#toc-nav"
data-bs-smooth-scroll="true"
tabindex="0"
id="content">
{% if html and request.COOKIES.htmlconf != 'txt' %}
<div class="rfchtml">
<br class="noprint">
{{ html|safe }}
</div>
{% else %}
<div class="rfcmarkup">
<div class="noprint" style="height: .5em;">
<div onmouseover="this.style.cursor='pointer';"
onclick="showLegend();"
onmouseout="hideLegend()"
style="height: .5em; min-height: .5em; width: 96ex; "
class="meta-info {{ doccolor }}"
title="Click for color legend.">
</div>
<div id="legend"
class="meta-info noprint pre legend"
style="position:absolute; top: 4px; left: 4ex; visibility:hidden; background-color: white; padding: 4px 9px 5px 7px; border: solid #345 1px; "
onmouseover="showLegend();"
onmouseout="hideLegend();">
</div>
</div>
{% if doc.meta %}
<div class="noprint">
<pre class="pre meta-info">{{ doc.supermeta|safe }}
{{ doc.meta|safe }}</pre>
<br class="noprint">
<!-- [html-validate-disable-block attr-quotes, void-style, element-permitted-content, heading-level -- FIXME: rfcmarkup/rfc2html generates HTML with issues] -->
{{ doc.htmlized|default:"Generation of htmlized text failed"|linkify|safe }}
</div>
{% endif %}
<div class="draftcontent">{{ doc.htmlized|default:"Generation of htmlized text failed"|safe }}</div>
</div>
{% endblock %}
{% block js %}
<script>
var legend_html = 'Color legend:<br> \
<table> \
<tr><td>Unknown:</td> <td><span class="bgwhite">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Draft:</td> <td><span class="bgred">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Informational:</td> <td><span class="bgorange">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Experimental:</td> <td><span class="bgyellow">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Best Common Practice:</td> <td><span class="bgmagenta">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Proposed Standard:</td> <td><span class="bgblue">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Draft Standard (old designation):</td> <td><span class="bgcyan">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Internet Standard:</td> <td><span class="bggreen">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Historic:</td> <td><span class="bggrey">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
<tr><td>Obsolete:</td> <td><span class="bgbrown">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr> \
</table>';
function showLegend() {
var elem = document.getElementById('legend');
elem.innerHTML = legend_html
elem.style.visibility='visible';
}
function hideLegend() {
var elem = document.getElementById('legend');
elem.style.visibility='hidden';
elem.innerHTML = "";
}
</script>
{% endblock %}
<div class="d-print-none col-3 bg-light collapse{% if request.COOKIES.sidebar != 'off'%} show{% endif %}" id="sidebar">
<div class="position-fixed col-3 border-start sidebar overflow-scroll overscroll-none no-scrollbar">
<button class="btn btn-outline-secondary float-end m-2"
type="button"
id="sidebar-off"
data-bs-toggle="collapse"
data-bs-target="#sidebar"
aria-expanded="{% if request.COOKIES.sidebar != 'off'%}true{% else %}false{% endif %}"
aria-controls="sidebar"
aria-label="Hide metadata sidebar"
title="Hide metadata sidebar">
<i class="bi bi-arrow-bar-up"></i>
</button>
<div class="pt-2 pt-lg-3 px-md-2 px-lg-3">
<p>
<a href="{% url 'ietf.doc.views_doc.document_main' name=doc.canonical_name %}">
{% if not snapshot and doc.get_state_slug == "rfc" %}
RFC {{ doc.rfc_number }}
{% else %}
{{ doc.name }}-{{ doc.rev }}
{% endif %}
<br>
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
{% if not snapshot %}
{{ doc.std_level }}
{% else %}
Internet-Draft
{% endif %}
</span>
</a>
</p>
{% if request.COOKIES.htmlconf != 'html' and html %}
<div class="alert alert-info small">
You are viewing the legacy <code>rfc2html</code>
rendering of this document. Change the
preferences for a modern <code>xml2rfc</code>-based
HTMLization.
</div>
{% elif request.COOKIES.htmlconf == 'html' and not html %}
<div class="alert alert-info small">
You are viewing the legacy <code>rfc2html</code>
rendering, because no <code>xml2rfc</code>-generated
HTML is available for this document.
</div>
{% endif %}
<ul class="nav nav-tabs nav-fill small" role="tablist">
<li class="nav-item" role="presentation" title="Document information">
<button class="nav-link px-2"
id="docinfo-tab"
data-bs-toggle="tab"
data-bs-target="#docinfo-tab-pane"
type="button"
role="tab"
aria-controls="docinfo-tab-pane"
aria-selected="true">
<i class="bi bi-info-circle"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Info</span>
</button>
</li>
<li class="nav-item" role="presentation" title="Table of contents">
<button class="nav-link px-2"
id="toc-tab"
data-bs-toggle="tab"
data-bs-target="#toc-tab-pane"
type="button"
role="tab"
aria-controls="toc-tab-pane"
aria-selected="false">
<i class="bi bi-list-ol"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Contents</span>
</button>
</li>
<li class="nav-item" role="presentation" title="Preferences">
<button class="nav-link px-2"
id="pref-tab"
data-bs-toggle="tab"
data-bs-target="#pref-tab-pane"
type="button"
role="tab"
aria-controls="pref-tab-pane"
aria-selected="false">
<i class="bi bi-gear"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Prefs</span>
</button>
</li>
</ul>
<div class="tab-content pt-2">
<div class="tab-pane"
id="docinfo-tab-pane"
role="tabpanel"
aria-labelledby="docinfo-tab"
tabindex="0">
<table class="table table-sm table-borderless">
{% include "doc/document_info.html" with sidebar=True %}
</table>
</div>
<div class="tab-pane mb-5"
id="toc-tab-pane"
role="tabpanel"
aria-labelledby="toc-tab"
tabindex="0">
<nav class="nav nav-pills flex-column small" id="toc-nav">
</nav>
</div>
<div class="tab-pane mb-5 small"
id="pref-tab-pane"
role="tabpanel"
aria-labelledby="pref-tab"
tabindex="0">
<label class="form-label fw-bold mb-2">Show sidebar by default</label>
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
<input type="radio" class="btn-check" name="sidebar" id="on-radio">
<label class="btn btn-outline-primary" for="on-radio">Yes</label>
<input type="radio" class="btn-check" name="sidebar" id="off-radio">
<label class="btn btn-outline-primary" for="off-radio">No</label>
</div>
<label class="form-label fw-bold mt-4 mb-2">Tab to show by default</label>
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
<input type="radio" class="btn-check" name="deftab" id="docinfo-radio">
<label class="btn btn-outline-primary" for="docinfo-radio">
<i class="bi bi-info-circle me-1"></i>Info
</label>
<input type="radio" class="btn-check" name="deftab" id="toc-radio">
<label class="btn btn-outline-primary" for="toc-radio">
<i class="bi bi-list-ol me-1"></i>Contents
</label>
</div>
<label class="form-label fw-bold mt-4 mb-2">HTMLization configuration</label>
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
<input type="radio" class="btn-check" name="htmlconf" id="txt-radio">
<label class="btn btn-outline-primary" for="txt-radio" title="This is the traditional HTMLization method.">
<i class="bi bi-badge-sd me-1"></i>HTMLize the plaintext
</label>
<input type="radio" class="btn-check" name="htmlconf" id="html-radio">
<label class="btn btn-outline-primary" for="html-radio" title="This is the modern HTMLization method.">
<i class="bi bi-badge-hd me-1"></i>Plaintextify the HTML
</label>
</div>
<label class="form-label fw-bold mt-4 mb-2" for="ptsize">Maximum font size</label>
<input type="range" class="form-range" min="7" max="16" id="ptsize" oninput="ptdemo.value = ptsize.value">
<label class="form-label fw-bold mt-4 mb-2">Page dependencies</label>
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
<input type="radio" class="btn-check" name="pagedeps" id="inline-radio">
<label class="btn btn-outline-primary" for="inline-radio" title="Generate larger, standalone web pages that do not require network access to render.">
<i class="bi bi-box me-1"></i>Inline
</label>
<input type="radio" class="btn-check" name="pagedeps" id="reference-radio">
<label class="btn btn-outline-primary" for="reference-radio" title="Generate regular web pages that require network access to render.">
<i class="bi bi-link-45deg me-1"></i>Reference
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% analytical_body_bottom %}
</body>
</html>

View file

@ -0,0 +1,449 @@
{# Copyright The IETF Trust 2016-2020, All Rights Reserved #}
{% load origin %}
{% load static %}
{% load ietf_filters %}
{% load person_filters %}
{% origin %}
<tbody class="meta align-top {% if not document_html %} border-top{% endif %}">
<tr>
<th scope="row">Document</th>
<th scope="row">{% if document_html %}Document type{% else %}Type{% endif %}</th>
<td class="edit"></td>
<td>
{% if doc.get_state_slug == "rfc" and not snapshot %}
<span class="text-success">RFC
{% if not document_html %}
- {{ doc.std_level }}
{% else %}
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">{{ doc.std_level }}</span>
{% endif %}
</span>
{% if published %}
{% if document_html %}<br>{% else %}({% endif %}{{ doc.pub_date|date:"F Y" }}{% if not document_html %}){% endif %}
{% else %}
<span class="text-muted">(Publication date unknown)</span>
{% endif %}
{% if document_html %}<br>{% endif %}
{% if has_verified_errata or has_errata %}
<a class="{% if document_html %}btn btn-danger btn-sm my-1{% else %}badge rounded-pill bg-danger text-decoration-none text-light{% endif %}"
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
Errata
</a>
{% endif %}
{% if doc.related_ipr %}
<a title="Click to view IPR declarations." class="{% if document_html %}btn btn-warning btn-sm my-1{% else %}badge rounded-pill bg-warning text-decoration-none text-light{% endif %}" href="{% url 'ietf.ipr.views.search' %}?submit=draft&amp;id={{ doc.name }}">IPR</a>
{% endif %}
{% if obsoleted_by %}<div>Obsoleted by {{ obsoleted_by|urlize_related_source_list:document_html|join:", " }}</div>{% endif %}
{% if updated_by %}<div>Updated by {{ updated_by|urlize_related_source_list:document_html|join:", " }}</div>{% endif %}
{% if obsoletes %}<div>Obsoletes {{ obsoletes|urlize_related_target_list:document_html|join:", " }}</div>{% endif %}
{% if updates %}<div>Updates {{ updates|urlize_related_target_list:document_html|join:", " }}</div>{% endif %}
{% if status_changes %}
<div>Status changed by {{ status_changes|urlize_related_source_list|join:", " }}</div>
{% endif %}
{% if proposed_status_changes %}
<div>Proposed status changed by {{ proposed_status_changes|urlize_related_source_list|join:", " }}</div>
{% endif %}
{% if rfc_aliases %}<div>Also known as {{ rfc_aliases|join:", "|urlize_ietf_docs }}</div>{% endif %}
{% if draft_name %}
<div>
Was
<a href="{% url 'ietf.doc.views_doc.document_main' name=draft_name %}">{{ draft_name }}</a>
{% if submission %}({{ submission|safe }}){% endif %}
</div>
{% endif %}
{% else %}
{% if snapshot and doc.doc.get_state_slug == 'rfc' %}
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft that was ultimately published as <a href="{% url 'ietf.doc.views_doc.document_html' name=doc.doc.canonical_name %}">{{doc.doc.canonical_name|prettystdname}}</a>.</div>
{% elif snapshot and doc.rev != latest_rev %}
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft whose latest revision state is "{{ doc.doc.get_state }}".</div>
{% else %}
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' or doc.get_state_slug == 'repl' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
{% if submission %}({{ submission|safe }}){% endif %}
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
{% endif %}
{% endif %}
{% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" %}
<div class="badge rounded-pill bg-warning{% if not document_html %} float-end{% endif %}">
Expired &amp; archived
</div>
{% endif %}
</td>
</tr>
{% if document_html %}
<tr>
<td></td>
<th scope="row">Select version</th>
<td class="edit"></td>
<td>
{% include "doc/revisions_list.html" with document_html=document_html %}
</td>
</tr>
{% if doc.rev != "00" %}
<tr>
<td></td>
<th scope="row">Compare versions</th>
<td class="edit"></td>
<td>
<a class="btn btn-primary btn-sm" href="{{ settings.RFCDIFF_BASE_URL }}?difftype=--hwdiff&amp;url2={{ doc.name }}-{{ doc.rev }}.txt" title="Inline diff (wdiff)">Inline</a>
<a class="btn btn-primary btn-sm" href="{{ settings.RFCDIFF_BASE_URL }}?url2={{ doc.name }}-{{ doc.rev }}.txt" title="Side-by-side diff">Side-by-side</a>
</td>
</tr>
{% endif %}
{% endif %}
<tr>
<td></td>
<th scope="row">Author{{ doc.authors|pluralize }}</th>
<td class="edit">
{% if can_edit_authors %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_doc.edit_authors' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{# Implementation that uses the current primary email for each author #}
{% for author in doc.authors %}
{% person_link author %}{% if not forloop.last %},{% endif %}
{% endfor %}
{% if document_html and not snapshot or document_html and doc.rev == latest_rev%}
<br>
<a class="btn btn-primary btn-sm mt-1" href="mailto:{{ doc.name }}@ietf.org?subject={{ doc.name}}" title="Send email to the document authors">Email authors</a>
{% endif %}
</td>
</tr>
{% if not document_html %}
{# FIXME: This shows the date of the last history event, which is not what participants necessarily expect here. #}
<tr>
<td></td>
<th scope="row">Last updated</th>
<td class="edit"></td>
<td>
{{ doc.time|date:"Y-m-d" }}
{% if latest_revision and latest_revision.time|date:"Y-m-d" != doc.time|date:"Y-m-d" %}
<span class="text-muted">(Latest revision {{ latest_revision.time|date:"Y-m-d" }})</span>
{% endif %}
</td>
</tr>
{% endif %}
{% if replaces or not document_html and can_edit_stream_info %}
<tr>
<td></td>
<th scope="row">Replaces</th>
<td class="edit">
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
{% endif %}
</td>
<td>
{% if replaces %}
{% if document_html %}
{{ replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% else %}
{{ replaces|urlize_related_target_list:document_html|join:", " }}
{% endif %}
{% else %}
<span class="text-muted">(None)</span>
{% endif %}
</td>
</tr>
{% endif %}
{% if replaced_by %}
<tr>
<td></td>
<th scope="row">
Replaced by
</th>
<td class="edit">
</td>
<td>
{% if document_html %}
{{ replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{% else %}
{{ replaced_by|urlize_related_source_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% if can_view_possibly_replaces %}
{% if possibly_replaces %}
<tr>
<td></td>
<th scope="row">
Possibly Replaces
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:"<br>" }}
{% else %}
{{ possibly_replaces|urlize_related_target_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% if possibly_replaced_by %}
<tr>
<td></td>
<th scope="row">
Possibly Replaced By
</th>
<td class="edit">
{% if can_edit_replaces and not snapshot %}
{% comment %}<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
{% endif %}
</td>
<td>
{% if document_html %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
{% else %}
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:", " }}
{% endif %}
</td>
</tr>
{% endif %}
{% endif %}
<tr>
<td></td>
<th scope="row">
RFC stream
</th>
<td class="edit">
{% if can_change_stream and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.change_stream' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td {% if stream_desc == "(None)" %}class="text-muted"{%endif%}>
{% if stream_desc != "(None)" %}
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
<a href="{% url 'ietf.group.views.stream_documents' acronym=doc.stream.name|lower %}">
{% endif %}
{% if document_html %}
{% if doc.stream.name|lower in 'iab,ietf,irtf' %}
<img alt="{{ doc.stream.name|upper }} Logo"
title="{{ stream_desc }}"
class="w-25 mt-1"
{% if doc.stream.name|lower == 'iab' %}
src="{% static 'ietf/images/iab-logo.svg' %}"
{% elif doc.stream.name|lower == 'ietf' %}
src="{% static 'ietf/images/ietf-logo.svg' %}"
{% elif doc.stream.name|lower == 'irtf' %}
src="{% static 'ietf/images/irtf-logo.svg' %}"
{% endif %}
>
{% else %}
{{ stream_desc }}
{% endif %}
{% else %}
{{ stream_desc }}
{% endif %}
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
</a>
{% endif %}
{% else %}
{{ stream_desc }}
{% endif %}
</td>
</tr>
{% if doc.get_state_slug != "rfc" and not snapshot %}
<tr>
<td></td>
<th scope="row">
Intended RFC status
</th>
<td class="edit">
{% if can_edit_stream_info and not snapshot %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.change_intention' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if doc.intended_std_level %}
{{ doc.intended_std_level }}
{% else %}
<span class="text-muted">
(None)
</span>
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<td></td>
<th scope="row">
{% if document_html %}Other formats{% else %}Formats{% endif %}
</th>
<td class="edit">
</td>
<td>
{% if document_html %}
{% include "doc/document_format_buttons.html" with skip_format="htmlized" %}
{% else %}
{% include "doc/document_format_buttons.html" %}
{% endif %}
</td>
</tr>
{% for check in doc.submission.latest_checks %}
{% if check.passed != None and check.symbol.strip %}
<tr>
<td></td>
<th scope="row">
{{ check.checker|title }}
</th>
<td class="edit">
</td>
<td>
{% if check.errors or check.warnings %}
<span class="checker-warning"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}"
title="{{ check.checker|title }} returned warnings or errors.">
{{ check.symbol|safe }}
</span>
{% else %}
<span class="checker-success"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}"
title="{{ check.checker|title }} passed">
{{ check.symbol|safe }}
</span>
{% endif %}
<a href="#"
data-bs-toggle="modal"
data-bs-target="#check-{{ check.pk }}">
{{ check.errors }} errors, {{ check.warnings }} warnings
</a>
{% include "doc/yang-check-modal-overlay.html" %}
</td>
</tr>
{% endif %}
{% endfor %}
{% if not document_html %}
{% if review_assignments or can_request_review %}
<tr>
<td></td>
<th scope="row">
Reviews
</th>
<td class="edit">
</td>
<td>
{% for review_assignment in review_assignments %}
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
{% endfor %}
{% if no_review_from_teams %}
{% for team in no_review_from_teams %}
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
{% endfor %}
will not review this version
{% endif %}
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
<div {% if review_assignments or no_review_from_teams %}class="mt-3"{% endif %}>
{% if can_request_review %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
<i class="bi bi-check-circle">
</i>
Request review
</a>
{% endif %}
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% elif can_submit_unsolicited_review_for_teams %}
<a class="btn btn-primary btn-sm"
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
<i class="bi bi-pencil-square">
</i>
Submit unsolicited review
</a>
{% endif %}
</div>
{% endif %}
</td>
</tr>
{% endif %}
{% if conflict_reviews %}
<tr>
<td></td>
<th scope="row">
IETF conflict review
</th>
<td class="edit">
</td>
<td>
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
</td>
</tr>
{% endif %}
{% endif %}
{% with doc.docextresource_set.all as resources %}
{% if document_html and resources or document_html and doc.group and doc.group.list_archive %}
{% if resources or doc.group and doc.group.list_archive or can_edit_stream_info or can_edit_individual %}
<tr>
<td>
</td>
<th scope="row">
Additional resources
</th>
<td class="edit">
{% if can_edit_stream_info or can_edit_individual %}
<a class="btn btn-primary btn-sm"
href="{% url 'ietf.doc.views_draft.edit_doc_extresources' name=doc.name %}">
Edit
</a>
{% endif %}
</td>
<td>
{% if resources or doc.group and doc.group.list_archive %}
{% for resource in resources|dictsort:"display_name" %}
{% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %}
<a href="{{ resource.value }}" title="{{ resource.name.name }}">
{% firstof resource.display_name resource.name.name %}
</a>
<br>
{# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #}
{% else %}
<span title="{{ resource.name.name }}">
{% firstof resource.display_name resource.name.name %}: {{ resource.value|escape }}
</span>
<br>
{% endif %}
{% endfor %}
{% if doc.group and doc.group.list_archive %}
{% if doc.group.list_archive|startswith:settings.MAILING_LIST_ARCHIVE_URL %}
<a href="{{ doc.group.list_archive }}?q={{ doc.name }}">
Mailing list discussion
</a>
{% elif doc.group.list_archive|is_valid_url %}
<a href="{{ doc.group.list_archive }}">
Mailing list discussion
</a>
{% else %}
{{ doc.group.list_archive|urlencode }}
{% endif %}
{% endif %}
{% endif %}
</td>
</tr>
{% endif %}
{% endif %}
{% endwith %}
</tbody>

View file

@ -1,139 +0,0 @@
<!DOCTYPE html>
{% load ietf_filters static %}
{# Copyright The IETF Trust 2021, All Rights Reserved #}
{% load origin %}
{% origin %}
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>
{% block title %}No title{% endblock %}
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
@media only screen
and (min-width: 992px)
and (max-width: 1199px) {
body { font-size: 14pt; }
div.content { width: 96ex; margin: 0 auto; }
}
@media only screen
and (min-width: 768px)
and (max-width: 991px) {
body { font-size: 14pt; }
div.content { width: 96ex; margin: 0 auto; }
}
@media only screen
and (min-width: 480px)
and (max-width: 767px) {
body { font-size: 11pt; }
div.content { width: 96ex; margin: 0 auto; }
}
@media only screen
and (max-width: 479px) {
body { font-size: 8pt; }
div.content { width: 96ex; margin: 0 auto; }
}
@media only screen
and (min-width : 375px)
and (max-width : 667px) {
body { font-size: 9.5pt; }
div.content { width: 96ex; margin: 0; }
}
@media only screen
and (min-width: 1200px) {
body { font-size: 10pt; margin: 0 4em; }
div.content { width: 96ex; margin: 0; }
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
font-weight: bold;
/* line-height: 0pt; */
display: inline;
white-space: pre;
font-family: monospace;
font-size: 1em;
font-weight: bold;
}
pre {
font-size: 1em;
margin-top: 0px;
margin-bottom: 0px;
}
.pre {
white-space: pre;
font-family: monospace;
}
.header{
font-weight: bold;
}
.newpage {
page-break-before: always;
}
.invisible {
text-decoration: none;
color: white;
}
@media print {
body {
margin-top: 5em;
font-family: monospace;
font-size: 10.5pt;
}
h1, h2, h3, h4, h5, h6 {
font-size: 1em;
}
a:link, a:visited {
color: inherit;
text-decoration: none;
}
.noprint {
display: none;
}
}
@media screen {
.grey, .grey a:link, .grey a:visited {
color: #777;
}
.meta-info {
background-color: #EEE;
width: 96ex;
}
.top {
border-top: 7px solid #EEE;
}
.pad {
padding-top: 7px;
line-height: 24px;
padding-bottom: 4px;
}
.bgwhite { background-color: white; }
.bgred { background-color: #F44; }
.bggrey { background-color: #666; }
.bgbrown { background-color: #840; }
.bgorange { background-color: #FA0; }
.bgyellow { background-color: #EE0; }
.bgmagenta{ background-color: #F4F; }
.bgblue { background-color: #66F; }
.bgcyan { background-color: #4DD; }
.bggreen { background-color: #4F4; }
.legend { font-size: 90%; }
.cplate { font-size: 70%; border: solid grey 1px; }
}
{% block morecss %}{% endblock %}
</style>
{% block pagehead %}{% endblock %}
{% include "base/icons.html" %}
</head>
<body {% block bodyAttrs %}{% endblock %}>
<div class="content" id="content">
{% block content %}{{ content|safe }}{% endblock %}
{% block content_end %}{% endblock %}
</div>
{% block footer %}{% endblock %}
{% block js %}{% endblock %}
</body>
</html>

View file

@ -1,21 +1,38 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% origin %}
<label class="my-1 fw-bold">Versions:</label>
<nav class="mb-3">
<ul class="pagination pagination-sm flex-wrap">
{% if not document_html %}
<label class="my-1 fw-bold">Versions:</label>
<nav class="mb-3">
{% endif %}
<ul class="revision-list pagination pagination-sm text-center flex-wrap{% if document_html %} my-0{% endif %}">
{% for rev in revisions %}
{% if rev %}
<li class="page-item {% if rev == doc.rev %}{% if snapshot or doc.get_state_slug != 'rfc' %}active{% endif %}{% endif %}">
<a class="page-link"
href="{% if snapshot and doc.get_state_slug == 'rfc' %}{% url 'ietf.doc.views_doc.document_main' name=doc.doc.name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.name %}{% endif %}{% if rev %}{{ rev }}/{% endif %}"
href="{% if snapshot and doc.get_state_slug == 'rfc' %}{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.doc.name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.doc.name %}{% endif %}{% else %}{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.name rev=rev %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.name rev=rev %}{% endif %}{% endif %}"
{% if rev != '00' and rev != latest_rev %}rel="nofollow"{% endif %}>
{% if rev %}
{{ rev }}
{% else %}
{{ doc.name }}
{% endif %}
</a>
</li>
{% endif %}
{% endfor %}
{% if doc.get_state_slug == 'rfc' %}
<li class="page-item rfc{% if not snapshot %} active{% endif %}">
<a class="page-link"
href="{% if doc.doc %}{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.doc.canonical_name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.doc.canonical_name %}{% endif %}{% else %}{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.canonical_name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.canonical_name %}{% endif %}{% endif %}">
RFC {{ doc.rfc_number }}
</a>
</li>
{% elif doc.doc.get_state_slug == 'rfc' %}
<li class="page-item rfc">
<a class="page-link"
href="{% if document_html %}{% url 'ietf.doc.views_doc.document_html' name=doc.doc.canonical_name %}{% else %}{% url 'ietf.doc.views_doc.document_main' name=doc.doc.canonical_name %}{% endif %}">
RFC {{ doc.doc.rfc_number }}
</a>
</li>
{% endif %}
</ul>
</nav>
{% if not document_html %}
</nav>
{% endif %}

View file

@ -174,14 +174,21 @@ def vnu_fmt_message(file, msg, content):
def vnu_filter_message(msg, filter_db_issues, filter_test_issues):
"True if the vnu message is a known false positive"
if filter_db_issues and re.search(
r"""^Forbidden\ code\ point\ U\+|
Illegal\ character\ in\ query:\ '\['|
'href'\ on\ element\ 'a':\ Percentage\ \("%"\)\ is\ not\ followed|
^Saw\ U\+\d+\ in\ stream|
^Document\ uses\ the\ Unicode\ Private\ Use\ Area""",
if re.search(
r"""^Document\ uses\ the\ Unicode\ Private\ Use\ Area|
^Element\ 'h.'\ not\ allowed\ as\ child\ of\ element\ 'pre'""",
msg["message"],
flags=re.VERBOSE,
) or (
filter_db_issues
and re.search(
r"""^Forbidden\ code\ point\ U\+|
Illegal\ character\ in\ query:\ '\['|
'href'\ on\ element\ 'a':\ Percentage\ \("%"\)\ is\ not|
^Saw\ U\+\d+\ in\ stream""",
msg["message"],
flags=re.VERBOSE,
)
):
return True

View file

@ -20,23 +20,23 @@
"bootstrap": "5.2.3",
"bootstrap-icons": "1.10.2",
"browser-fs-access": "0.31.1",
"caniuse-lite": "1.0.30001434",
"caniuse-lite": "1.0.30001435",
"d3": "7.6.1",
"file-saver": "2.0.5",
"highcharts": "10.3.1",
"highcharts": "10.3.2",
"jquery": "3.6.1",
"jquery-ui-dist": "1.13.2",
"js-cookie": "3.0.1",
"list.js": "2.3.1",
"lodash": "4.17.21",
"lodash-es": "4.17.21",
"luxon": "3.1.0",
"luxon": "3.1.1",
"moment": "2.29.4",
"moment-timezone": "0.5.39",
"ms": "2.1.3",
"murmurhash-js": "1.0.0",
"naive-ui": "2.34.2",
"pinia": "2.0.26",
"pinia": "2.0.27",
"pinia-plugin-persist": "1.0.0",
"select2": "4.1.0-rc.0",
"select2-bootstrap-5-theme": "1.3.0",
@ -50,6 +50,8 @@
},
"devDependencies": {
"@faker-js/faker": "7.6.0",
"@parcel/optimizer-data-url": "2.8.0",
"@parcel/transformer-inline-string": "2.8.0",
"@parcel/transformer-sass": "2.8.0",
"@rollup/pluginutils": "5.0.2",
"@vitejs/plugin-vue": "3.2.0",
@ -76,6 +78,9 @@
"distDir": "ietf/static/dist/ietf",
"source": [
"ietf/static/css/datepicker.scss",
"ietf/static/css/document_html_inline.scss",
"ietf/static/css/document_html_referenced.scss",
"ietf/static/css/document_html_txt.scss",
"ietf/static/css/ietf.scss",
"ietf/static/css/jquery-ui.scss",
"ietf/static/css/liaisons.css",
@ -83,6 +88,7 @@
"ietf/static/css/select2.scss",
"ietf/static/images/arrow-ani.webp",
"ietf/static/images/iab-logo-card.png",
"ietf/static/images/iab-logo.svg",
"ietf/static/images/iesg-draft-state-diagram.png",
"ietf/static/images/ietf-logo-card.png",
"ietf/static/images/ietf-logo-nor-16-dev.png",
@ -100,6 +106,7 @@
"ietf/static/images/ietf-logo-nor.svg",
"ietf/static/images/ietf-logo.svg",
"ietf/static/images/irtf-logo-card.png",
"ietf/static/images/irtf-logo.svg",
"ietf/static/js/agenda_filter.js",
"ietf/static/js/agenda_materials.js",
"ietf/static/js/agenda_personalize.js",
@ -110,6 +117,7 @@
"ietf/static/js/d3.js",
"ietf/static/js/datepicker.js",
"ietf/static/js/doc-search.js",
"ietf/static/js/document_html.js",
"ietf/static/js/document_relations.js",
"ietf/static/js/document_timeline.js",
"ietf/static/js/draft-submit.js",

View file

@ -63,6 +63,6 @@ tblib>=1.7.0 # So that the django test runner provides tracebacks
tlds>=2022042700 # Used to teach bleach about which TLDs currently exist
tqdm>=4.64.0
Unidecode>=1.3.4
weasyprint>=52.5,<53 # Datatracker tests past on 54, but xml2rfc tests do not.
weasyprint>=53
xml2rfc>=3.12.4
xym>=0.6,<1.0

View file

@ -824,6 +824,18 @@ __metadata:
languageName: node
linkType: hard
"@parcel/optimizer-data-url@npm:2.8.0":
version: 2.8.0
resolution: "@parcel/optimizer-data-url@npm:2.8.0"
dependencies:
"@parcel/plugin": 2.8.0
"@parcel/utils": 2.8.0
isbinaryfile: ^4.0.2
mime: ^2.4.4
checksum: 998fb94ceea6c385c47a2337e6c911884f6580720609fd8e95b8036b8ce5860733a3028e3b7cff62e5f1b0aed2d86fda587cce8232d5e54514898fcb8e9e76ce
languageName: node
linkType: hard
"@parcel/optimizer-htmlnano@npm:2.8.0":
version: 2.8.0
resolution: "@parcel/optimizer-htmlnano@npm:2.8.0"
@ -1145,6 +1157,15 @@ __metadata:
languageName: node
linkType: hard
"@parcel/transformer-inline-string@npm:2.8.0":
version: 2.8.0
resolution: "@parcel/transformer-inline-string@npm:2.8.0"
dependencies:
"@parcel/plugin": 2.8.0
checksum: e40616c55bbebfacc38a572d44028f79dab95abbe57dd27175bdce267894c7885fe1aab38012b1ce2c652f03d0d91ce5dbdc64c2625a12ae83cfff603558c259
languageName: node
linkType: hard
"@parcel/transformer-js@npm:2.8.0":
version: 2.8.0
resolution: "@parcel/transformer-js@npm:2.8.0"
@ -2075,10 +2096,10 @@ browserlist@latest:
languageName: node
linkType: hard
"caniuse-lite@npm:1.0.30001434":
version: 1.0.30001434
resolution: "caniuse-lite@npm:1.0.30001434"
checksum: 7c9d2641e8e8f3ddf9af14c4ce47266a9d8fd1fc0243626049ff1b2eca4bf02938ff440813cc3feae3fa8d851ec8d1b9718044340c8d09bb4372d92d4f6b519c
"caniuse-lite@npm:1.0.30001435":
version: 1.0.30001435
resolution: "caniuse-lite@npm:1.0.30001435"
checksum: ec88b9c37f66095e26ddb8b43110e9564ebccb6de77e495b8e8b9d64fdbfe37f7762be8fd2578c3ecc181a183a159578c9bd8e9b90eb15b44b78e8a6d0e92530
languageName: node
linkType: hard
@ -3944,10 +3965,10 @@ browserlist@latest:
languageName: node
linkType: hard
"highcharts@npm:10.3.1":
version: 10.3.1
resolution: "highcharts@npm:10.3.1"
checksum: 8a1cf9a363cfcd30b7ea64f6baba5c23c06998367b36eb9bee8b3903d49820df9de8251e3a6434f88a153d537243c2b41a55dc44e841c486f49e20bfe41a42d2
"highcharts@npm:10.3.2":
version: 10.3.2
resolution: "highcharts@npm:10.3.2"
checksum: 43cb42b24c3d6effc03d021f410a760322092ebd7012b60c2c475aa48a426af6c2a0a2937707bfc1c7aab089f0cc968c9aec3a9a1147e87ffc463b0adfb61ad4
languageName: node
linkType: hard
@ -4402,6 +4423,13 @@ browserlist@latest:
languageName: node
linkType: hard
"isbinaryfile@npm:^4.0.2":
version: 4.0.10
resolution: "isbinaryfile@npm:4.0.10"
checksum: a6b28db7e23ac7a77d3707567cac81356ea18bd602a4f21f424f862a31d0e7ab4f250759c98a559ece35ffe4d99f0d339f1ab884ffa9795172f632ab8f88e686
languageName: node
linkType: hard
"isexe@npm:^2.0.0":
version: 2.0.0
resolution: "isexe@npm:2.0.0"
@ -4823,10 +4851,10 @@ browserlist@latest:
languageName: node
linkType: hard
"luxon@npm:3.1.0":
version: 3.1.0
resolution: "luxon@npm:3.1.0"
checksum: f8a850b759ba7a2e009d904c522ed7bc264bf4add57578f8948e52a0ed96b627b025b5aad8032295b570ae19fac41f0ffab91bdb128715fb0cc020798a7ba886
"luxon@npm:3.1.1":
version: 3.1.1
resolution: "luxon@npm:3.1.1"
checksum: 388fb35d3c51a19d8b305a3338e7e74634b08562e7d2f9ed5c05a7f4bc9ee1c1ab6a2546b6d9c4c104516b24043757d65f5f3fe3d78b206fbf55a9586ab62230
languageName: node
linkType: hard
@ -4888,6 +4916,15 @@ browserlist@latest:
languageName: node
linkType: hard
"mime@npm:^2.4.4":
version: 2.6.0
resolution: "mime@npm:2.6.0"
bin:
mime: cli.js
checksum: 1497ba7b9f6960694268a557eae24b743fd2923da46ec392b042469f4b901721ba0adcf8b0d3c2677839d0e243b209d76e5edcbd09cfdeffa2dfb6bb4df4b862
languageName: node
linkType: hard
"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
@ -5520,9 +5557,9 @@ browserlist@latest:
languageName: node
linkType: hard
"pinia@npm:2.0.26":
version: 2.0.26
resolution: "pinia@npm:2.0.26"
"pinia@npm:2.0.27":
version: 2.0.27
resolution: "pinia@npm:2.0.27"
dependencies:
"@vue/devtools-api": ^6.4.5
vue-demi: "*"
@ -5535,7 +5572,7 @@ browserlist@latest:
optional: true
typescript:
optional: true
checksum: 0d38cc0efc6572436c439491491df0e989182bad342fc3828d8865a42db6c6580c8f86663fcc47955bfeca5baf6e7f95e61b9b3f795ba161c19ef86fdc9b2841
checksum: 29c862ea4304cdfeae385cbd2ab08100809aa9a79c147c4cb4085215601c0323e0ca664cea6abcaa0298e7ea53865117b6950ebb59224347fbc1683dbe956ac8
languageName: node
linkType: hard
@ -6011,6 +6048,8 @@ browserlist@latest:
"@fullcalendar/luxon2": 5.11.3
"@fullcalendar/timegrid": 5.11.3
"@fullcalendar/vue3": 5.11.3
"@parcel/optimizer-data-url": 2.8.0
"@parcel/transformer-inline-string": 2.8.0
"@parcel/transformer-sass": 2.8.0
"@popperjs/core": 2.11.6
"@rollup/pluginutils": 5.0.2
@ -6021,7 +6060,7 @@ browserlist@latest:
browser-fs-access: 0.31.1
browserlist: latest
c8: 7.12.0
caniuse-lite: 1.0.30001434
caniuse-lite: 1.0.30001435
d3: 7.6.1
eslint: 8.28.0
eslint-config-standard: 17.0.0
@ -6032,7 +6071,7 @@ browserlist@latest:
eslint-plugin-promise: 6.1.1
eslint-plugin-vue: 9.8.0
file-saver: 2.0.5
highcharts: 10.3.1
highcharts: 10.3.2
html-validate: 7.10.0
jquery: 3.6.1
jquery-migrate: 3.4.0
@ -6041,14 +6080,14 @@ browserlist@latest:
list.js: 2.3.1
lodash: 4.17.21
lodash-es: 4.17.21
luxon: 3.1.0
luxon: 3.1.1
moment: 2.29.4
moment-timezone: 0.5.39
ms: 2.1.3
murmurhash-js: 1.0.0
naive-ui: 2.34.2
parcel: 2.8.0
pinia: 2.0.26
pinia: 2.0.27
pinia-plugin-persist: 1.0.0
pug: 3.0.2
sass: 1.56.1