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/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/timegrid", "npm:5.11.3"],\ ["@fullcalendar/timegrid", "npm:5.11.3"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#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"],\ ["@parcel/transformer-sass", "npm:2.8.0"],\
["@popperjs/core", "npm:2.11.6"],\ ["@popperjs/core", "npm:2.11.6"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\ ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
@ -52,7 +54,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["browser-fs-access", "npm:0.31.1"],\ ["browser-fs-access", "npm:0.31.1"],\
["browserlist", "npm:1.0.1"],\ ["browserlist", "npm:1.0.1"],\
["c8", "npm:7.12.0"],\ ["c8", "npm:7.12.0"],\
["caniuse-lite", "npm:1.0.30001434"],\ ["caniuse-lite", "npm:1.0.30001435"],\
["d3", "npm:7.6.1"],\ ["d3", "npm:7.6.1"],\
["eslint", "npm:8.28.0"],\ ["eslint", "npm:8.28.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.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-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\ ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
["file-saver", "npm:2.0.5"],\ ["file-saver", "npm:2.0.5"],\
["highcharts", "npm:10.3.1"],\ ["highcharts", "npm:10.3.2"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\ ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
["jquery", "npm:3.6.1"],\ ["jquery", "npm:3.6.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
@ -72,14 +74,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\ ["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\ ["lodash", "npm:4.17.21"],\
["lodash-es", "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", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.39"],\ ["moment-timezone", "npm:0.5.39"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
["murmurhash-js", "npm:1.0.0"],\ ["murmurhash-js", "npm:1.0.0"],\
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\ ["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\ ["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"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\ ["pug", "npm:3.0.2"],\
["sass", "npm:1.56.1"],\ ["sass", "npm:1.56.1"],\
@ -337,7 +339,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\ ["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/common", "npm:5.11.3"],\ ["@fullcalendar/common", "npm:5.11.3"],\
["@types/luxon", null],\ ["@types/luxon", null],\
["luxon", "npm:3.1.0"],\ ["luxon", "npm:3.1.1"],\
["tslib", "npm:2.4.0"]\ ["tslib", "npm:2.4.0"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
@ -1136,6 +1138,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "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", [\ ["@parcel/optimizer-htmlnano", [\
["npm:2.8.0", {\ ["npm:2.8.0", {\
"packageLocation": "./.yarn/cache/@parcel-optimizer-htmlnano-npm-2.8.0-d2ead43d0c-68010e586b.zip/node_modules/@parcel/optimizer-htmlnano/",\ "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"\ "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", [\ ["@parcel/transformer-js", [\
["npm:2.8.0", {\ ["npm:2.8.0", {\
"packageLocation": "./.yarn/unplugged/@parcel-transformer-js-virtual-0a5c0b53bd/node_modules/@parcel/transformer-js/",\ "packageLocation": "./.yarn/unplugged/@parcel-transformer-js-virtual-0a5c0b53bd/node_modules/@parcel/transformer-js/",\
@ -2690,10 +2715,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\ }],\
["npm:1.0.30001434", {\ ["npm:1.0.30001435", {\
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001434-9c6ea57daf-7c9d2641e8.zip/node_modules/caniuse-lite/",\ "packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001435-7cebb35f0a-ec88b9c37f.zip/node_modules/caniuse-lite/",\
"packageDependencies": [\ "packageDependencies": [\
["caniuse-lite", "npm:1.0.30001434"]\ ["caniuse-lite", "npm:1.0.30001435"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -4910,10 +4935,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["highcharts", [\ ["highcharts", [\
["npm:10.3.1", {\ ["npm:10.3.2", {\
"packageLocation": "./.yarn/cache/highcharts-npm-10.3.1-e67a887ff6-8a1cf9a363.zip/node_modules/highcharts/",\ "packageLocation": "./.yarn/cache/highcharts-npm-10.3.2-1672942f09-43cb42b24c.zip/node_modules/highcharts/",\
"packageDependencies": [\ "packageDependencies": [\
["highcharts", "npm:10.3.1"]\ ["highcharts", "npm:10.3.2"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -5456,6 +5481,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "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", [\ ["isexe", [\
["npm:2.0.0", {\ ["npm:2.0.0", {\
"packageLocation": "./.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip/node_modules/isexe/",\ "packageLocation": "./.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip/node_modules/isexe/",\
@ -5918,10 +5952,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["luxon", [\ ["luxon", [\
["npm:3.1.0", {\ ["npm:3.1.1", {\
"packageLocation": "./.yarn/cache/luxon-npm-3.1.0-16e2508500-f8a850b759.zip/node_modules/luxon/",\ "packageLocation": "./.yarn/cache/luxon-npm-3.1.1-64fe977c1d-388fb35d3c.zip/node_modules/luxon/",\
"packageDependencies": [\ "packageDependencies": [\
["luxon", "npm:3.1.0"]\ ["luxon", "npm:3.1.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -5987,6 +6021,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["mime", "npm:1.6.0"]\ ["mime", "npm:1.6.0"]\
],\ ],\
"linkType": "HARD"\ "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", [\ ["minimatch", [\
@ -6659,17 +6700,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["pinia", [\ ["pinia", [\
["npm:2.0.26", {\ ["npm:2.0.27", {\
"packageLocation": "./.yarn/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\ "packageLocation": "./.yarn/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
"packageDependencies": [\ "packageDependencies": [\
["pinia", "npm:2.0.26"]\ ["pinia", "npm:2.0.27"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27", {\
"packageLocation": "./.yarn/__virtual__/pinia-virtual-3c74e5a139/0/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\ "packageLocation": "./.yarn/__virtual__/pinia-virtual-0b7bfddb52/0/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
"packageDependencies": [\ "packageDependencies": [\
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\ ["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
["@types/typescript", null],\ ["@types/typescript", null],\
["@types/vue", null],\ ["@types/vue", null],\
["@types/vue__composition-api", null],\ ["@types/vue__composition-api", null],\
@ -6677,7 +6718,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@vue/devtools-api", "npm:6.4.5"],\ ["@vue/devtools-api", "npm:6.4.5"],\
["typescript", null],\ ["typescript", null],\
["vue", "npm:3.2.45"],\ ["vue", "npm:3.2.45"],\
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"]\ ["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
"@types/typescript",\ "@types/typescript",\
@ -6706,7 +6747,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/vue", null],\ ["@types/vue", null],\
["@types/vue__composition-api", null],\ ["@types/vue__composition-api", null],\
["@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", "npm:3.2.45"],\
["vue-demi", "virtual:f56fcf19bbebc2ada1b28955da8cc216b1e9a569a1a7337d2d1926c1ebd1bc7a5bd91aedae1d05c15c8562f33caf7c59bd3020a667340f6bdc6a7b13fc2ba847#npm:0.12.5"]\ ["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/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
["@fullcalendar/timegrid", "npm:5.11.3"],\ ["@fullcalendar/timegrid", "npm:5.11.3"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#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"],\ ["@parcel/transformer-sass", "npm:2.8.0"],\
["@popperjs/core", "npm:2.11.6"],\ ["@popperjs/core", "npm:2.11.6"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\ ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
@ -7242,7 +7285,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["browser-fs-access", "npm:0.31.1"],\ ["browser-fs-access", "npm:0.31.1"],\
["browserlist", "npm:1.0.1"],\ ["browserlist", "npm:1.0.1"],\
["c8", "npm:7.12.0"],\ ["c8", "npm:7.12.0"],\
["caniuse-lite", "npm:1.0.30001434"],\ ["caniuse-lite", "npm:1.0.30001435"],\
["d3", "npm:7.6.1"],\ ["d3", "npm:7.6.1"],\
["eslint", "npm:8.28.0"],\ ["eslint", "npm:8.28.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.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-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\ ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
["file-saver", "npm:2.0.5"],\ ["file-saver", "npm:2.0.5"],\
["highcharts", "npm:10.3.1"],\ ["highcharts", "npm:10.3.2"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\ ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
["jquery", "npm:3.6.1"],\ ["jquery", "npm:3.6.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
@ -7262,14 +7305,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\ ["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\ ["lodash", "npm:4.17.21"],\
["lodash-es", "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", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.39"],\ ["moment-timezone", "npm:0.5.39"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
["murmurhash-js", "npm:1.0.0"],\ ["murmurhash-js", "npm:1.0.0"],\
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\ ["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\ ["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"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\ ["pug", "npm:3.0.2"],\
["sass", "npm:1.56.1"],\ ["sass", "npm:1.56.1"],\
@ -8159,16 +8202,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["npm:0.13.1", {\ ["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": [\ "packageDependencies": [\
["vue-demi", "npm:0.13.1"]\ ["vue-demi", "npm:0.13.1"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1", {\ ["virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#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": [\ "packageDependencies": [\
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"],\ ["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"],\
["@types/vue", null],\ ["@types/vue", null],\
["@types/vue__composition-api", null],\ ["@types/vue__composition-api", null],\
["@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 os
import rfc2html import rfc2html
from pathlib import Path
from lxml import etree
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from weasyprint import HTML as wpHTML from weasyprint import HTML as wpHTML
@ -21,6 +23,7 @@ from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import mark_safe # type:ignore from django.utils.html import mark_safe # type:ignore
from django.contrib.staticfiles import finders
import debug # pyflakes:ignore import debug # pyflakes:ignore
@ -541,6 +544,46 @@ class DocumentInfo(models.Model):
def text_or_error(self): def text_or_error(self):
return self.text() or "Error; cannot read '%s'"%self.get_base_name() 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): def htmlized(self):
name = self.get_base_name() name = self.get_base_name()
text = self.text() text = self.text()
@ -566,17 +609,29 @@ class DocumentInfo(models.Model):
def pdfized(self): def pdfized(self):
name = self.get_base_name() name = self.get_base_name()
text = self.text() text = self.html_body(classes="rfchtml")
cache = caches['pdfized'] stylesheets = [finders.find("ietf/css/document_html_referenced.css")]
cache_key = name.split('.')[0] 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: try:
pdf = cache.get(cache_key) pdf = cache.get(cache_key)
except EOFError: except EOFError:
pdf = None pdf = None
if not pdf: if not pdf:
html = rfc2html.markup(text, path=settings.PDFIZER_URL_PREFIX)
try: 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: except AssertionError:
pdf = None pdf = None
if pdf: if pdf:

View file

@ -260,8 +260,8 @@ def urlize_ietf_docs(string, autoescape=None):
urlize_ietf_docs = stringfilter(urlize_ietf_docs) urlize_ietf_docs = stringfilter(urlize_ietf_docs)
@register.filter(name='urlize_related_source_list', is_safe=True, needs_autoescape=True) @register.filter(name='urlize_related_source_list', is_safe=True, document_html=False)
def urlize_related_source_list(related, autoescape=None): 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""" """Convert a list of RelatedDocuments into list of links using the source document's canonical name"""
links = [] links = []
names = set() names = set()
@ -273,10 +273,9 @@ def urlize_related_source_list(related, autoescape=None):
continue continue
names.add(name) names.add(name)
titles.add(title) titles.add(title)
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name)) url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
if autoescape: name = escape(name)
name = escape(name) title = escape(title)
title = escape(title)
links.append(mark_safe( links.append(mark_safe(
'<a href="%(url)s" title="%(title)s">%(name)s</a>' % dict(name=prettify_std_name(name), '<a href="%(url)s" title="%(title)s">%(name)s</a>' % dict(name=prettify_std_name(name),
title=title, title=title,
@ -284,17 +283,16 @@ def urlize_related_source_list(related, autoescape=None):
)) ))
return links return links
@register.filter(name='urlize_related_target_list', is_safe=True, needs_autoescape=True) @register.filter(name='urlize_related_target_list', is_safe=True, document_html=False)
def urlize_related_target_list(related, autoescape=None): 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""" """Convert a list of RelatedDocuments into list of links using the target document's canonical name"""
links = [] links = []
for rel in related: for rel in related:
name=rel.target.document.canonical_name() name=rel.target.document.canonical_name()
title = rel.target.document.title title = rel.target.document.title
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name)) url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
if autoescape: name = escape(name)
name = escape(name) title = escape(title)
title = escape(title)
links.append(mark_safe( links.append(mark_safe(
'<a href="%(url)s" title="%(title)s">%(name)s</a>' % dict(name=prettify_std_name(name), '<a href="%(url)s" title="%(title)s">%(name)s</a>' % dict(name=prettify_std_name(name),
title=title, title=title,
@ -554,6 +552,19 @@ def consensus(doc):
else: else:
return "Unknown" 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 @register.filter
def pos_to_label_format(text): def pos_to_label_format(text):
"""Returns valid Bootstrap classes to label a ballot position.""" """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))) r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name)))
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r, "Versions:") self.assertContains(r, "Select version")
self.assertContains(r, "Deimos street") self.assertContains(r, "Deimos street")
q = PyQuery(r.content) q = PyQuery(r.content)
self.assertEqual(q('title').text(), 'draft-ietf-mars-test-01') self.assertEqual(q('title').text(), 'draft-ietf-mars-test-01')
self.assertEqual(len(q('.rfcmarkup pre')), 4) self.assertEqual(len(q('.rfcmarkup pre')), 3)
self.assertEqual(len(q('.rfcmarkup span.h1')), 2) self.assertEqual(len(q('.rfcmarkup span.h1, .rfcmarkup h1')), 2)
self.assertEqual(len(q('.rfcmarkup a[href]')), 41) 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))) 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) 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() key = "doc:document:search:" + hashlib.sha512(json.dumps(kwargs, sort_keys=True).encode('utf-8')).hexdigest()
return key 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): def build_file_urls(doc):
if isinstance(doc,Document) and doc.get_state_slug() == "rfc": if isinstance(doc,Document) and doc.get_state_slug() == "rfc":
name = doc.canonical_name() name = doc.canonical_name()
@ -1069,135 +1034,6 @@ def build_file_urls(doc):
return file_urls, found_types 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): def augment_docs_and_user_with_user_info(docs, user):
"""Add attribute to each document with whether the document is tracked """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.""" 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.urls import reverse as urlreverse
from django.conf import settings from django.conf import settings
from django import forms from django import forms
from django.contrib.staticfiles import finders
import debug # pyflakes:ignore 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, 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, 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, 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, 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) bibxml_for_draft)
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
from ietf.group.models import Role, Group from ietf.group.models import Role, Group
@ -140,12 +141,12 @@ def interesting_doc_relations(doc):
return interesting_relations_that, interesting_relations_that_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) doc = get_object_or_404(Document.objects.select_related(), docalias__name=name)
# take care of possible redirections # take care of possible redirections
aliases = DocAlias.objects.filter(docs=doc).values_list("name", flat=True) 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: for a in aliases:
if a.startswith("rfc"): if a.startswith("rfc"):
return redirect("ietf.doc.views_doc.document_main", name=a) return redirect("ietf.doc.views_doc.document_main", name=a)
@ -169,7 +170,7 @@ def document_main(request, name, rev=None):
doc = h doc = h
break break
if not snapshot: if not snapshot and document_html is False:
return redirect('ietf.doc.views_doc.document_main', name=name) return redirect('ietf.doc.views_doc.document_main', name=name)
if doc.type_id == "charter": if doc.type_id == "charter":
@ -184,7 +185,6 @@ def document_main(request, name, rev=None):
top = render_document_top(request, doc, "status", name) top = render_document_top(request, doc, "status", name)
telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat") 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)): if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)):
telechat = None telechat = None
@ -446,8 +446,22 @@ def document_main(request, name, rev=None):
else: else:
stream_desc = "(None)" 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, dict(doc=doc,
document_html=document_html,
css=css,
js=js,
html=html,
group=group, group=group,
top=top, top=top,
name=name, name=name,
@ -787,7 +801,6 @@ def document_raw_id(request, name, rev=None, ext=None):
except: except:
raise Http404 raise Http404
def document_html(request, name, rev=None): def document_html(request, name, rev=None):
found = fuzzy_find_documents(name, rev) found = fuzzy_find_documents(name, rev)
num_found = found.documents.count() 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()): if not os.path.exists(doc.get_file_name()):
raise Http404("File not found: %s" % doc.get_file_name()) raise Http404("File not found: %s" % doc.get_file_name())
if doc.type_id in ['draft',]: return document_main(request, name, rev=rev, document_html=True)
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 })
def document_pdfized(request, name, rev=None, ext=None): 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 // Try and hyphenate table headings and other things
th { th,
.hyphenate {
hyphens: auto; hyphens: auto;
} }
@ -208,6 +209,17 @@ th {
max-width: 300px; 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 // Style the photo cards
.photo { .photo {
width: 12em; 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 Cookies from "js-cookie";
import debounce from "lodash/debounce"; import { populate_nav } from "./nav.js";
// setup CSRF protection using jQuery // setup CSRF protection using jQuery
function csrfSafeMethod(method) { function csrfSafeMethod(method) {
@ -154,9 +154,9 @@ $(document)
$(function () { $(function () {
const contentElement = $('#content.ietf-auto-nav'); const contentElement = $('#content.ietf-auto-nav');
if (contentElement.length > 0) { 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 const headings = contentElement
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible, .nav-heading:visible") .find(heading_selector);
.not(".navskip");
const contents = (headings.length > 0) && const contents = (headings.length > 0) &&
($(headings) ($(headings)
@ -178,8 +178,6 @@ $(function () {
if (pageTooTall || haveExtraNav) { if (pageTooTall || haveExtraNav) {
// console.log("Enabling nav."); // console.log("Enabling nav.");
let n = 0;
let last_level;
contentElement contentElement
.attr("data-bs-offset", 0) .attr("data-bs-offset", 0)
@ -197,48 +195,7 @@ $(function () {
.children() .children()
.last(); .last();
contentElement populate_nav(nav[0], heading_selector);
.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>`);
});
if (haveExtraNav) { if (haveExtraNav) {
$('#righthand-panel').append('<div id="righthand-extra" class="w-100 py-3"></div>'); $('#righthand-panel').append('<div id="righthand-extra" class="w-100 py-3"></div>');
@ -246,18 +203,6 @@ $(function () {
extraNav.remove(); 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 // offset the scrollspy to account for the menu bar
const contentOffset = contentElement ? contentElement.offset().top : 0; 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 %} {% block content %}
{% origin %} {% origin %}
{{ top|safe }} {{ top|safe }}
{% include "doc/revisions_list.html" %} {% include "doc/revisions_list.html" with document_html=document_html %}
<div id="timeline"></div> <div id="timeline"></div>
{% if doc.rev != latest_rev %} {% if doc.rev != latest_rev %}
<div class="alert alert-warning my-3">The information below is for an old version of the document.</div> <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 %}
{% endif %} {% endif %}
<table class="table table-sm table-borderless"> <table class="table table-sm table-borderless">
<tbody class="meta border-top"> {% include "doc/document_info.html" %}
<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>
<tbody class="meta border-top"> <tbody class="meta border-top">
<tr> <tr>
<th scope="row"> <th scope="row">

View file

@ -1,7 +1,18 @@
{% if file_urls %} {% if file_urls %}
<div class="buttonlist"> <div class="buttonlist">
{% for label, url in file_urls %} {% 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' %} {% if label == 'pdf' or label == 'pdfized' %}
<i class="bi bi-file-pdf"></i> pdf <i class="bi bi-file-pdf"></i> pdf
{% elif label == 'xml' or label == 'html' %} {% elif label == 'xml' or label == 'html' %}
@ -16,6 +27,7 @@
<i class="bi bi-file-diff"></i> w/errata <i class="bi bi-file-diff"></i> w/errata
{% endif %} {% endif %}
</a> </a>
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% else %} {% else %}

View file

@ -1,92 +1,276 @@
{% extends "doc/htmlized_base.html" %}
{# Copyright The IETF Trust 2016, All Rights Reserved #} {# Copyright The IETF Trust 2016, All Rights Reserved #}
<!DOCTYPE html>
{% load analytical %}
{% load origin %} {% load origin %}
{% load static %} {% load static %}
{% load ietf_filters %} {% load ietf_filters textfilters %}
{% block pagehead %} {% origin %}
<link rel="alternate" <html lang="en">
type="application/atom+xml" <head>
title="Document changes" {% analytical_head_top %}
href="/feed/document-changes/{{ doc.name }}/"> <meta charset="utf-8">
<meta name="description" <meta http-equiv="X-UA-Compatible" content="IE=edge">
{% if doc.get_state_slug == "rfc" %} <title>
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" %}
{% else %} RFC {{ doc.rfc_number }} - {{ doc.title }}
content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:"Y" }})" {% else %}
{% endif %}> {{ doc.name }}-{{ doc.rev }}
{% endblock %} {% endif %}
{% block morecss %} </title>
.bgwhite { background-color: white; } <meta name="viewport" content="width=device-width, initial-scale=1">
.bgred { background-color: #F44; } {% if request.COOKIES.pagedeps == 'inline' %}
.bggrey { background-color: #666; } <script>{{ js|safe }}</script>
.bgbrown { background-color: #840; } <style>{{ css|safe }}</style>
.bgorange { background-color: #FA0; } {% else %}
.bgyellow { background-color: #EE0; } <link rel="stylesheet" href="{% static 'ietf/css/document_html_referenced.css' %}">
.bgmagenta{ background-color: #F4F; } {% if html %}
.bgblue { background-color: #66F; } <link rel="stylesheet" href="{% static 'ietf/css/document_html_txt.css' %}">
.bgcyan { background-color: #4DD; } {% endif %}
.bggreen { background-color: #4F4; } <script src="{% static 'ietf/js/document_html.js' %}"></script>
.draftcontent { margin-top:1em;} {% endif %}
{% endblock %} <link rel="alternate"
{% block title %} type="application/atom+xml"
{% if doc.get_state_slug == "rfc" %} title="Document changes"
RFC {{ doc.rfc_number }} - {{ doc.title }} href="/feed/document-changes/{{ doc.name }}/">
{% else %} <meta name="description"
{{ doc.name }}-{{ doc.rev }} {% if not snapshot and doc.get_state_slug == 'rfc' %}
{% endif %} content="{{ doc.title }} (RFC {{ doc.rfc_number }}{% if published %}, {{ published.time|date:'F Y' }}{% endif %}{% if obsoleted_by %}; obsoleted by {{ obsoleted_by|join:', ' }}{% endif %}"
{% endblock %} {% else %}
{% block content %} content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:'Y' }})"
<!-- [html-validate-disable-block no-inline-style, attr-quotes, void-style -- FIXME: it's everywhere in this old code] --> {% endif %}>
{% origin %} {% include "base/icons.html" %}
<div class="rfcmarkup"> {% include "doc/opengraph.html" %}
<div class="noprint" style="height: .5em;"> {% analytical_head_bottom %}
<div onmouseover="this.style.cursor='pointer';" </head>
onclick="showLegend();" <body>
onmouseout="hideLegend()" {% analytical_body_top %}
style="height: .5em; min-height: .5em; width: 96ex; " <button class="btn btn-outline-secondary position-fixed top-0 end-0 m-2 sidebar-toggle"
class="meta-info {{ doccolor }}" type="button"
title="Click for color legend."> 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 %}
<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> </div>
<div id="legend" </nav>
class="meta-info noprint pre legend" <div class="row g-0">
style="position:absolute; top: 4px; left: 4ex; visibility:hidden; background-color: white; padding: 4px 9px 5px 7px; border: solid #345 1px; " <div class="col d-flex justify-content-center lh-sm"
onmouseover="showLegend();" data-bs-spy="scroll"
onmouseout="hideLegend();"> 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">
<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>
<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>
</div> </div>
{% if doc.meta %} {% analytical_body_bottom %}
<div class="noprint"> </body>
<pre class="pre meta-info">{{ doc.supermeta|safe }} </html>
{{ doc.meta|safe }}</pre>
</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 %}

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 #} {# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %} {% load origin %}
{% origin %} {% origin %}
<label class="my-1 fw-bold">Versions:</label> {% if not document_html %}
<nav class="mb-3"> <label class="my-1 fw-bold">Versions:</label>
<ul class="pagination pagination-sm flex-wrap"> <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 %} {% for rev in revisions %}
<li class="page-item {% if rev == doc.rev %}{% if snapshot or doc.get_state_slug != 'rfc' %}active{% endif %}{% endif %}"> {% if rev %}
<a class="page-link" <li class="page-item {% if rev == doc.rev %}{% if snapshot or doc.get_state_slug != 'rfc' %}active{% endif %}{% endif %}">
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 %}" <a class="page-link"
{% if rev != '00' and rev != latest_rev %}rel="nofollow"{% 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 %} {% if rev != '00' and rev != latest_rev %}rel="nofollow"{% endif %}>
{{ rev }} {{ rev }}
{% else %} </a>
{{ doc.name }} </li>
{% endif %} {% 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> </a>
</li> </li>
{% endfor %} {% 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> </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): def vnu_filter_message(msg, filter_db_issues, filter_test_issues):
"True if the vnu message is a known false positive" "True if the vnu message is a known false positive"
if filter_db_issues and re.search( if re.search(
r"""^Forbidden\ code\ point\ U\+| r"""^Document\ uses\ the\ Unicode\ Private\ Use\ Area|
Illegal\ character\ in\ query:\ '\['| ^Element\ 'h.'\ not\ allowed\ as\ child\ of\ element\ 'pre'""",
'href'\ on\ element\ 'a':\ Percentage\ \("%"\)\ is\ not\ followed|
^Saw\ U\+\d+\ in\ stream|
^Document\ uses\ the\ Unicode\ Private\ Use\ Area""",
msg["message"], msg["message"],
flags=re.VERBOSE, 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 return True

View file

@ -20,23 +20,23 @@
"bootstrap": "5.2.3", "bootstrap": "5.2.3",
"bootstrap-icons": "1.10.2", "bootstrap-icons": "1.10.2",
"browser-fs-access": "0.31.1", "browser-fs-access": "0.31.1",
"caniuse-lite": "1.0.30001434", "caniuse-lite": "1.0.30001435",
"d3": "7.6.1", "d3": "7.6.1",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"highcharts": "10.3.1", "highcharts": "10.3.2",
"jquery": "3.6.1", "jquery": "3.6.1",
"jquery-ui-dist": "1.13.2", "jquery-ui-dist": "1.13.2",
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"list.js": "2.3.1", "list.js": "2.3.1",
"lodash": "4.17.21", "lodash": "4.17.21",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"luxon": "3.1.0", "luxon": "3.1.1",
"moment": "2.29.4", "moment": "2.29.4",
"moment-timezone": "0.5.39", "moment-timezone": "0.5.39",
"ms": "2.1.3", "ms": "2.1.3",
"murmurhash-js": "1.0.0", "murmurhash-js": "1.0.0",
"naive-ui": "2.34.2", "naive-ui": "2.34.2",
"pinia": "2.0.26", "pinia": "2.0.27",
"pinia-plugin-persist": "1.0.0", "pinia-plugin-persist": "1.0.0",
"select2": "4.1.0-rc.0", "select2": "4.1.0-rc.0",
"select2-bootstrap-5-theme": "1.3.0", "select2-bootstrap-5-theme": "1.3.0",
@ -50,6 +50,8 @@
}, },
"devDependencies": { "devDependencies": {
"@faker-js/faker": "7.6.0", "@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", "@parcel/transformer-sass": "2.8.0",
"@rollup/pluginutils": "5.0.2", "@rollup/pluginutils": "5.0.2",
"@vitejs/plugin-vue": "3.2.0", "@vitejs/plugin-vue": "3.2.0",
@ -76,6 +78,9 @@
"distDir": "ietf/static/dist/ietf", "distDir": "ietf/static/dist/ietf",
"source": [ "source": [
"ietf/static/css/datepicker.scss", "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/ietf.scss",
"ietf/static/css/jquery-ui.scss", "ietf/static/css/jquery-ui.scss",
"ietf/static/css/liaisons.css", "ietf/static/css/liaisons.css",
@ -83,6 +88,7 @@
"ietf/static/css/select2.scss", "ietf/static/css/select2.scss",
"ietf/static/images/arrow-ani.webp", "ietf/static/images/arrow-ani.webp",
"ietf/static/images/iab-logo-card.png", "ietf/static/images/iab-logo-card.png",
"ietf/static/images/iab-logo.svg",
"ietf/static/images/iesg-draft-state-diagram.png", "ietf/static/images/iesg-draft-state-diagram.png",
"ietf/static/images/ietf-logo-card.png", "ietf/static/images/ietf-logo-card.png",
"ietf/static/images/ietf-logo-nor-16-dev.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-nor.svg",
"ietf/static/images/ietf-logo.svg", "ietf/static/images/ietf-logo.svg",
"ietf/static/images/irtf-logo-card.png", "ietf/static/images/irtf-logo-card.png",
"ietf/static/images/irtf-logo.svg",
"ietf/static/js/agenda_filter.js", "ietf/static/js/agenda_filter.js",
"ietf/static/js/agenda_materials.js", "ietf/static/js/agenda_materials.js",
"ietf/static/js/agenda_personalize.js", "ietf/static/js/agenda_personalize.js",
@ -110,6 +117,7 @@
"ietf/static/js/d3.js", "ietf/static/js/d3.js",
"ietf/static/js/datepicker.js", "ietf/static/js/datepicker.js",
"ietf/static/js/doc-search.js", "ietf/static/js/doc-search.js",
"ietf/static/js/document_html.js",
"ietf/static/js/document_relations.js", "ietf/static/js/document_relations.js",
"ietf/static/js/document_timeline.js", "ietf/static/js/document_timeline.js",
"ietf/static/js/draft-submit.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 tlds>=2022042700 # Used to teach bleach about which TLDs currently exist
tqdm>=4.64.0 tqdm>=4.64.0
Unidecode>=1.3.4 Unidecode>=1.3.4
weasyprint>=52.5,<53 # Datatracker tests past on 54, but xml2rfc tests do not. weasyprint>=53
xml2rfc>=3.12.4 xml2rfc>=3.12.4
xym>=0.6,<1.0 xym>=0.6,<1.0

View file

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