@harvard-lts/mirador-eda-plugin 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.github/pull_request_template.md +31 -0
  2. package/.github/workflows/publish-package.yml +34 -0
  3. package/.nvmrc +1 -0
  4. package/.parcelrc +9 -0
  5. package/.travis.yml +16 -0
  6. package/CONTRIBUTING.md +20 -0
  7. package/LICENSE +201 -0
  8. package/README.md +175 -0
  9. package/__mocks__/fileMock.js +1 -0
  10. package/babel.config.json +11 -0
  11. package/demo/data/manifest-3037.json +524 -0
  12. package/demo/data/manifest-5f3b.json +315 -0
  13. package/demo/data/manifest-609.json +500 -0
  14. package/demo/data/ms_am_1118_3_142_0001.jpg +0 -0
  15. package/demo/data/ms_am_1118_3_142_0002.jpg +0 -0
  16. package/demo/data/ms_am_1118_3_142_0003.jpg +0 -0
  17. package/demo/demoEntry.js +21 -0
  18. package/demo/index.html +23 -0
  19. package/dist/es/index.js +535 -0
  20. package/jest.config.js +23 -0
  21. package/nwb.config.js +20 -0
  22. package/package.json +73 -0
  23. package/rollup.config.mjs +12 -0
  24. package/setupTests.js +1 -0
  25. package/src/index.js +10 -0
  26. package/src/plugins/EdaSideBarButtonsWrapper.js +51 -0
  27. package/src/plugins/EdaTranscriptionButton.js +19 -0
  28. package/src/plugins/EdaTranscriptionPanel.js +245 -0
  29. package/src/plugins/__tests__/EdaSideBarButtonsWrapper.spec.js +183 -0
  30. package/src/plugins/__tests__/EdaTranscriptionButton.spec.js +17 -0
  31. package/src/plugins/__tests__/EdaTranscriptionPanel.spec.js +188 -0
  32. package/src/plugins/__tests__/edaManifest.spec.js +110 -0
  33. package/src/plugins/__tests__/nonEdaManifest.spec.js +64 -0
  34. package/src/plugins/__tests__/transcriptionUtils.spec.js +430 -0
  35. package/src/plugins/testFixtures/combinedEditionsTranscriptions.js +62 -0
  36. package/src/plugins/testFixtures/franklinVariorum1998Transcription.js +85 -0
  37. package/src/plugins/testFixtures/johnsonPoems1955Transcription.js +88 -0
  38. package/src/plugins/transcriptionUtils.js +114 -0
  39. package/src/plugins/utils/suppressWarnings.js +41 -0
  40. package/webpack.config.cjs +56 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Extract the edition name from a transcription HTML string
3
+ * @param {string} html
4
+ * @returns {string} "Unknown Edition" if no name is found
5
+ */
6
+
7
+ const getEditionName = (html) => {
8
+ const parser = new DOMParser()
9
+ const doc = parser.parseFromString(html, "text/html")
10
+ const workBody = doc.querySelector(".work-body")
11
+ return workBody?.dataset?.edition || "Unknown Edition"
12
+ }
13
+
14
+ /**
15
+ * Returns an array of EDA transcriptions from the manifest
16
+ * Transcriptions with the same edition name will be combined into a single transcription
17
+ * @param {Object} state
18
+ * @param {string} windowId
19
+ * @returns {array} - empty if EDA no transcriptions exist
20
+ */
21
+
22
+ export const getEdaTranscription = (state, windowId) => {
23
+ const windows = state?.windows || {}
24
+
25
+ let targetWindow
26
+ if (windowId && windows[windowId]) {
27
+ targetWindow = windows[windowId]
28
+ } else {
29
+ const windowIds = Object.keys(windows)
30
+ targetWindow = windowIds.length > 0 ? windows[windowIds[0]] : null
31
+ }
32
+
33
+ const canvasId = targetWindow?.canvasId
34
+ const manifestId = targetWindow?.manifestId
35
+ const manifest = manifestId ? state.manifests[manifestId] : null
36
+ if (!manifest?.json || !canvasId) {
37
+ return []
38
+ }
39
+
40
+ const canvas = manifest.json.items?.find(item => item.id === canvasId)
41
+ if (!canvas?.annotations) {
42
+ return []
43
+ }
44
+
45
+ const allTranscriptions = canvas.annotations
46
+ .flatMap(page => page.items || [])
47
+ .filter(annotation => {
48
+ if (annotation?.body?.format !== "text/html") return false
49
+
50
+ const value = annotation?.body?.value
51
+ if (!value) return false
52
+
53
+ return value.includes('data-exhibit="emily-dickinson-archive"')
54
+ })
55
+ .map(annotation => annotation.body.value)
56
+
57
+ // Group transcriptions by edition name
58
+ const transcriptionsByEdition = allTranscriptions.reduce((acc, html) => {
59
+ const editionName = getEditionName(html)
60
+ if (!acc[editionName]) {
61
+ acc[editionName] = []
62
+ }
63
+ acc[editionName].push(html)
64
+ return acc
65
+ }, {})
66
+
67
+ // Combine HTML for editions with multiple transcriptions
68
+ const combinedTranscriptions = Object.entries(transcriptionsByEdition).map(([editionName, htmlArray]) => {
69
+ if (htmlArray.length === 1) {
70
+ return htmlArray[0]
71
+ }
72
+
73
+ const parser = new DOMParser()
74
+ const firstDoc = parser.parseFromString(htmlArray[0], "text/html")
75
+ const firstWorkBody = firstDoc.querySelector(".work-body")
76
+ const combinedDoc = parser.parseFromString('<div class="work-body"></div>', "text/html")
77
+ const combinedWorkBody = combinedDoc.querySelector(".work-body")
78
+
79
+ if (firstWorkBody.dataset.edition) {
80
+ combinedWorkBody.dataset.edition = firstWorkBody.dataset.edition
81
+ }
82
+ if (firstWorkBody.dataset.exhibit) {
83
+ combinedWorkBody.dataset.exhibit = firstWorkBody.dataset.exhibit
84
+ }
85
+
86
+ htmlArray.forEach(html => {
87
+ const doc = parser.parseFromString(html, "text/html")
88
+ const workBody = doc.querySelector(".work-body")
89
+
90
+ const title = workBody.querySelector("h3")
91
+ const stanzas = workBody.querySelectorAll(".stanza")
92
+
93
+ if (title) {
94
+ const titleClone = title.cloneNode(true)
95
+ combinedWorkBody.appendChild(titleClone)
96
+ }
97
+
98
+ stanzas.forEach(stanza => {
99
+ const clone = stanza.cloneNode(true)
100
+ combinedWorkBody.appendChild(clone)
101
+ })
102
+
103
+ if (html !== htmlArray[htmlArray.length - 1]) {
104
+ const spacer = combinedDoc.createElement("div")
105
+ spacer.style.height = "2em"
106
+ combinedWorkBody.appendChild(spacer)
107
+ }
108
+ })
109
+
110
+ return combinedWorkBody.outerHTML
111
+ })
112
+
113
+ return combinedTranscriptions
114
+ }
@@ -0,0 +1,41 @@
1
+ import { version as miradorVersion } from "mirador/package.json"
2
+
3
+ // In Mirador version 3x there is a deprecation console warning:
4
+ // Warning: Failed prop type: Material-UI: `overlap="rectangle"` was deprecated. Use `overlap="rectangular"` instead.
5
+ // This was fixed in Mirador version 4.0.0
6
+ // https://github.com/ProjectMirador/mirador/commit/90e695e0df5df44174a023cfae367a76e5697760
7
+
8
+ // Suppressing this error to improve developer experience
9
+
10
+ const FIXED_VERSION = "4.0.0"
11
+
12
+ const parsedCurrentVersion = parseInt(miradorVersion.replace(/\./g, ""))
13
+ const parsedFixedVersion = parseInt(FIXED_VERSION.replace(/\./g, ""))
14
+
15
+ // Once the version is greater than or equal to the fixed version, we can remove this suppression
16
+ if (parsedCurrentVersion >= parsedFixedVersion) {
17
+ console.log(
18
+ "⚠️ Warning suppression for Material-UI Badge overlap prop may no longer be needed.\n" +
19
+ " Current Mirador version: " + miradorVersion + "\n" +
20
+ " Fixed in version: " + FIXED_VERSION + "\n" +
21
+ " Consider removing src/plugins/utils/suppressWarnings.js"
22
+ )
23
+ } else {
24
+ const originalConsoleError = console.error
25
+
26
+ console.error = (...args) => {
27
+ const suppressedWarnings = [
28
+ "Material-UI: `overlap=\"rectangle\"` was deprecated. Use `overlap=\"rectangular\"` instead.",
29
+ ]
30
+
31
+ const shouldSuppress = suppressedWarnings.some(warning =>
32
+ args[0]?.includes && args[0].includes(warning)
33
+ )
34
+
35
+ if (!shouldSuppress) {
36
+ originalConsoleError.apply(console, args)
37
+ }
38
+ }
39
+ }
40
+
41
+
@@ -0,0 +1,56 @@
1
+ const path = require("path");
2
+ const webpack = require("webpack");
3
+
4
+ module.exports = (env, options) => {
5
+ return {
6
+ mode: options.mode,
7
+ entry: "./demo/demoEntry.js",
8
+ output: {
9
+ path: path.resolve(__dirname, "demo", "dist"),
10
+ filename: "demo.js",
11
+ publicPath: "/",
12
+ },
13
+ resolve: {
14
+ extensions: [".js", ".jsx"],
15
+ },
16
+ plugins: [
17
+ new webpack.IgnorePlugin({
18
+ resourceRegExp: /@blueprintjs\/(core|icons)/, // ignore optional UI framework dependencies
19
+ }),
20
+ ],
21
+ module: {
22
+ rules: [
23
+ {
24
+ test: /\.(js|jsx)$/,
25
+ exclude: /node_modules/,
26
+ use: {
27
+ loader: "babel-loader",
28
+ },
29
+ resolve: {
30
+ fullySpecified: false,
31
+ },
32
+ },
33
+ {
34
+ test: /\.(png|jpe?g|gif|svg)$/i,
35
+ type: 'asset/resource',
36
+ },
37
+ ],
38
+ },
39
+ devServer: {
40
+ static: [
41
+ {
42
+ directory: path.join(__dirname, "demo"),
43
+ },
44
+ {
45
+ directory: path.join(__dirname, "demo", "dist"),
46
+ },
47
+ ],
48
+ compress: true,
49
+ port: 9000,
50
+ historyApiFallback: true,
51
+ client: {
52
+ overlay: false,
53
+ },
54
+ },
55
+ };
56
+ };