Skip to content

Commit 0b605f6

Browse files
authored
New CustomScript addon (#431)
This is a new addon that allow users to inject a specific JavaScript file to all the versions to all the documentation pages to allow them to fix issues in old "frozen" (not able to re-build) versions. Requires readthedocs/readthedocs.org#11758
1 parent 4d210bb commit 0b605f6

10 files changed

+159
-9
lines changed

dist/readthedocs-addons.js

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/readthedocs-addons.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/_/readthedocs-addons.json

+4
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@
149149
],
150150
"default_filter": "subprojects:example/latest"
151151
},
152+
"customscript": {
153+
"enabled": true,
154+
"src": "customscript.js"
155+
},
152156
"hotkeys": {
153157
"enabled": true,
154158
"doc_diff": {

public/customscript.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const section = document.querySelector("#customscript + p");
2+
section.innerHTML = "This was injected by the customscript addon";

public/index.html

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ <h2 id="ethicalads">Ethical Ad</h2>
3434
data-ea-type="readthedocs-sidebar">
3535
</div>
3636

37+
<h2 id="customscript">CustomScript</h2>
38+
<p>Content of the section</p>
39+
3740
<h2 id="search">Search</h2>
3841
<p>Hit <code>/</code> to trigger the search modal, or click on the input from the flyout.</p>
3942
<readthedocs-search></readthedocs-search>

src/customscript.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { default as objectPath } from "object-path";
2+
import { AddonBase } from "./utils";
3+
4+
const SCRIPT_ID = "readthedocs-addons-custom-script";
5+
6+
/**
7+
* User JavaScript file.
8+
*
9+
* Allow a user to inject a custom JavaScript file in all the pages.
10+
*/
11+
export class CustomScriptAddon extends AddonBase {
12+
static jsonValidationURI =
13+
"http://v1.schemas.readthedocs.org/addons.customscript.json";
14+
static addonEnabledPath = "addons.customscript.enabled";
15+
static addonName = "CustomScript";
16+
static enabledOnHttpStatus = [200, 403, 404, 500];
17+
18+
constructor(config) {
19+
super();
20+
this.config = config;
21+
22+
if (objectPath.get(this.config, "addons.customscript.src")) {
23+
this.injectJavaScriptFile();
24+
}
25+
}
26+
27+
injectJavaScriptFile() {
28+
const script = document.createElement("script");
29+
script.id = SCRIPT_ID;
30+
script.src = objectPath.get(this.config, "addons.customscript.src");
31+
script.async = true;
32+
33+
document.body.appendChild(script);
34+
}
35+
}

src/data-validation.js

+24
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,29 @@ const addons_linkpreviews = {
493493
},
494494
};
495495

496+
// Validator for CustomScript Addon
497+
const addons_customscript = {
498+
$id: "http://v1.schemas.readthedocs.org/addons.customscript.json",
499+
type: "object",
500+
required: ["addons"],
501+
properties: {
502+
addons: {
503+
type: "object",
504+
required: ["customscript"],
505+
properties: {
506+
customscript: {
507+
type: "object",
508+
required: ["enabled"],
509+
properties: {
510+
enabled: { type: "boolean" },
511+
src: { type: ["string", "null"] },
512+
},
513+
},
514+
},
515+
},
516+
},
517+
};
518+
496519
export const ajv = new Ajv({
497520
allErrors: true,
498521
schemas: [
@@ -505,6 +528,7 @@ export const ajv = new Ajv({
505528
addons_search,
506529
addons_linkpreviews,
507530
addons_filetreediff,
531+
addons_customscript,
508532
],
509533
});
510534

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as ethicalads from "./ethicalads";
88
import * as hotkeys from "./hotkeys";
99
import * as linkpreviews from "./linkpreviews";
1010
import * as filetreediff from "./filetreediff";
11+
import * as customscript from "./customscript";
1112
import {
1213
domReady,
1314
IS_PRODUCTION,
@@ -26,6 +27,7 @@ export function setup() {
2627
hotkeys.HotKeysAddon,
2728
linkpreviews.LinkPreviewsAddon,
2829
filetreediff.FileTreeDiffAddon,
30+
customscript.CustomScriptAddon,
2931
];
3032

3133
return new Promise((resolve) => {

tests/customscript.test.html

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<html>
2+
<body>
3+
<script type="module">
4+
import { expect, elementUpdated } from "@open-wc/testing";
5+
import { runTests } from "@web/test-runner-mocha";
6+
import * as customscript from "../src/customscript";
7+
8+
let config;
9+
10+
runTests(async () => {
11+
beforeEach(() => {
12+
config = {
13+
addons: {
14+
customscript: {
15+
enabled: true,
16+
src: "https://myproject.readthedocs.io/en/latest/_static/readthedocs.js",
17+
},
18+
},
19+
};
20+
});
21+
22+
describe("CustomScript addon", () => {
23+
it("script element is added", async () => {
24+
const addon = new customscript.CustomScriptAddon(config);
25+
const element = document.querySelector(
26+
"#readthedocs-addons-custom-script",
27+
);
28+
29+
expect(element.src).to.equal(
30+
"https://myproject.readthedocs.io/en/latest/_static/readthedocs.js",
31+
);
32+
expect(element.async).to.equal(true);
33+
});
34+
});
35+
});
36+
</script>
37+
</body>
38+
</html>

tests/customscript.test.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { expect, assert, fixture, html } from "@open-wc/testing";
2+
import { CustomScriptAddon } from "../src/customscript";
3+
4+
describe("CustomScript addon", () => {
5+
it("invalid configuration disables the addon", () => {
6+
expect(
7+
CustomScriptAddon.isEnabled({
8+
addons: {
9+
customscript: {
10+
invalid: true,
11+
},
12+
},
13+
}),
14+
).to.be.false;
15+
});
16+
17+
it("is disabled", () => {
18+
expect(
19+
CustomScriptAddon.isEnabled({
20+
addons: {
21+
customscript: {
22+
enabled: false,
23+
src: "/en/latest/_static/readthedocs.js",
24+
},
25+
},
26+
}),
27+
).to.be.false;
28+
});
29+
30+
it("valid data and enabled", () => {
31+
expect(
32+
CustomScriptAddon.isEnabled({
33+
addons: {
34+
customscript: {
35+
enabled: true,
36+
src: "/en/latest/_static/readthedocs.js",
37+
},
38+
},
39+
}),
40+
).to.be.true;
41+
});
42+
});

0 commit comments

Comments
 (0)