ixbrl-viewer 1.4.1__py3-none-any.whl → 1.4.86__py3-none-any.whl

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 (190) hide show
  1. iXBRLViewerPlugin/__init__.py +231 -127
  2. iXBRLViewerPlugin/_version.py +33 -3
  3. iXBRLViewerPlugin/constants.py +96 -2
  4. iXBRLViewerPlugin/featureConfig.py +8 -1
  5. iXBRLViewerPlugin/iXBRLViewer.py +356 -214
  6. iXBRLViewerPlugin/plugin.py +12 -0
  7. iXBRLViewerPlugin/ui.py +81 -50
  8. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  9. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
  10. iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
  11. iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -0
  12. iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
  13. iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
  14. iXBRLViewerPlugin/viewer/src/html/footnote-details.html +2 -2
  15. iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
  16. iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
  17. iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
  18. iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
  19. iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
  20. iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
  21. iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
  22. iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
  23. iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
  24. iXBRLViewerPlugin/viewer/src/i18n/da/balancetypes.json +4 -0
  25. iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
  26. iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
  27. iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
  28. iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
  29. iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
  30. iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
  31. iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
  32. iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
  33. iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
  34. iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
  35. iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
  36. iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
  37. iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
  38. iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
  39. iXBRLViewerPlugin/viewer/src/i18n/de/translation.json +179 -0
  40. iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
  41. iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
  42. iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
  43. iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
  44. iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
  45. iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +73 -23
  46. iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
  47. iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
  48. iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
  49. iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
  50. iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
  51. iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +87 -37
  52. iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
  53. iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
  54. iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
  55. iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
  56. iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
  57. iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
  58. iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
  59. iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
  60. iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
  61. iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
  62. iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
  63. iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
  64. iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
  65. iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
  66. iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
  67. iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
  68. iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
  69. iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
  70. iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
  71. iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
  72. iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
  73. iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
  74. iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
  75. iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
  76. iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
  77. iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
  78. iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
  79. iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
  80. iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
  81. iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
  82. iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -0
  83. iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
  84. iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
  85. iXBRLViewerPlugin/viewer/src/js/accordian.js +5 -4
  86. iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
  87. iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
  88. iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
  89. iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
  90. iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
  91. iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
  92. iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
  93. iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
  94. iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
  95. iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
  96. iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
  97. iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
  98. iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
  99. iXBRLViewerPlugin/viewer/src/js/docOrderIndex.js +7 -7
  100. iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
  101. iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
  102. iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
  103. iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
  104. iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
  105. iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
  106. iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
  107. iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
  108. iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
  109. iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
  110. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
  111. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
  112. iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
  113. iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
  114. iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
  115. iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
  116. iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
  117. iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
  118. iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
  119. iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
  120. iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
  121. iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
  122. iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
  123. iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
  124. iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
  125. iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
  126. iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
  127. iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
  128. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
  129. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
  130. iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
  131. iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
  132. iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
  133. iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
  134. iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
  135. iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
  136. iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
  137. iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
  138. iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
  139. iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
  140. iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
  141. iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
  142. iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
  143. iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
  144. iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
  145. iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
  146. iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
  147. iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
  148. iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
  149. iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
  150. iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
  151. iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
  152. iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
  153. iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
  154. iXBRLViewerPlugin/viewer/src/less/tabs.less +9 -9
  155. iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
  156. iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
  157. iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
  158. iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
  159. iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
  160. iXBRLViewerPlugin/xhtmlserialize.py +59 -45
  161. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
  162. ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
  163. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
  164. ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
  165. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
  166. iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
  167. iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
  168. ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
  169. tests/__init__.py +0 -0
  170. tests/puppeteer/framework/core_elements.js +0 -117
  171. tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
  172. tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
  173. tests/puppeteer/framework/page_objects/search_panel.js +0 -76
  174. tests/puppeteer/framework/page_objects/toolbar.js +0 -18
  175. tests/puppeteer/framework/utils.js +0 -3
  176. tests/puppeteer/framework/viewer_page.js +0 -103
  177. tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
  178. tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
  179. tests/puppeteer/test_filings/highlights.zip +0 -0
  180. tests/puppeteer/tests/fact_properties.test.js +0 -78
  181. tests/puppeteer/tests/highlight.test.js +0 -186
  182. tests/puppeteer/tests/search.test.js +0 -86
  183. tests/puppeteer/tools/generate.sh +0 -15
  184. tests/unit_tests/__init__.py +0 -0
  185. tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
  186. tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
  187. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
  188. tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
  189. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
  190. {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
@@ -2,315 +2,444 @@
2
2
 
3
3
  import interact from 'interactjs'
4
4
  import $ from 'jquery'
5
- import { iXBRLReport } from "./report.js";
5
+ import { ReportSet } from "./reportset.js";
6
6
  import { Viewer, DocumentTooLargeError } from "./viewer.js";
7
7
  import { Inspector } from "./inspector.js";
8
-
9
- export function iXBRLViewer(options) {
10
- this._features = new Set();
11
- this._plugins = [];
12
- this.inspector = new Inspector(this);
13
- this.viewer = null;
14
- options = options || {};
15
- const defaults = {
16
- continuationElementLimit: 10000,
17
- showValidationWarningOnStart: false,
8
+ import { initializeTheme } from './theme.js';
9
+ import { TaxonomyNamer } from './taxonomynamer.js';
10
+ import { FEATURE_GUIDE_LINK, FEATURE_REVIEW, FEATURE_SUPPORT_LINK, FEATURE_SURVEY_LINK, USER_GUIDE_URL, moveNonAppAttributes } from "./util";
11
+
12
+ const featureFalsyValues = new Set([undefined, null, '', 'false', false]);
13
+
14
+ export class iXBRLViewer {
15
+
16
+ constructor(options) {
17
+ this._staticFeatures = {};
18
+ this._dynamicFeatures = {};
19
+ this._plugins = [];
20
+ this.inspector = new Inspector(this);
21
+ this.viewer = null;
22
+ options = options || {};
23
+ const defaults = {
24
+ continuationElementLimit: 10000,
25
+ showValidationWarningOnStart: false,
26
+ }
27
+ this.options = {...defaults, ...options};
18
28
  }
19
- this.options = {...defaults, ...options};
20
- }
21
29
 
22
- /*
23
- * Adds a plugin to the viewer. The plugin should be an object with one or
24
- * more of the methods listed below, which will be called by the viewer.
25
- *
26
- * preProcessiXBRL(bodyElement, docIndex)
27
- *
28
- * Called upon viewer intialisation, once for each iXBRL document. bodyElement
29
- * is a DOM object for the body element. docIndex is the index of the document
30
- * within the document set.
31
- *
32
- * updateViewerStyleElement(styleElts)
33
- *
34
- * styleElts is a JQuery object consisting of the viewer style elements for
35
- * each document in the document set. Additional CSS can be appended to the
36
- * contents, or additional header elements inserted relative to the provided
37
- * style element.
38
- *
39
- * extendDisplayOptionsMenu(menu)
40
- *
41
- * Called when the display options menu is created or recreated. menu is a
42
- * Menu object, and can be modified to add additional menu items.
43
- *
44
- * extendHighlightKey(key)
45
- *
46
- * Called when the highlight color key is created. key is an array of labels,
47
- * which can be modified or extended.
48
- *
49
- */
50
- iXBRLViewer.prototype.registerPlugin = function (plugin) {
51
- this._plugins.push(plugin);
52
- }
30
+ /*
31
+ * Adds a plugin to the viewer. The plugin should be an object with one or
32
+ * more of the methods listed below, which will be called by the viewer.
33
+ *
34
+ * preProcessiXBRL(bodyElement, docIndex)
35
+ *
36
+ * Called upon viewer intialisation, once for each iXBRL document. bodyElement
37
+ * is a DOM object for the body element. docIndex is the index of the document
38
+ * within the document set.
39
+ *
40
+ * updateViewerStyleElement(styleElts)
41
+ *
42
+ * styleElts is a JQuery object consisting of the viewer style elements for
43
+ * each document in the document set. Additional CSS can be appended to the
44
+ * contents, or additional header elements inserted relative to the provided
45
+ * style element.
46
+ *
47
+ * extendDisplayOptionsMenu(menu)
48
+ *
49
+ * Called when the display options menu is created or recreated. menu is a
50
+ * Menu object, and can be modified to add additional menu items.
51
+ *
52
+ * extendHighlightKey(key)
53
+ *
54
+ * Called when the highlight color key is created. key is an array of labels,
55
+ * which can be modified or extended.
56
+ *
57
+ */
58
+ registerPlugin(plugin) {
59
+ this._plugins.push(plugin);
60
+ }
53
61
 
54
- iXBRLViewer.prototype.callPluginMethod = function (methodName, ...args) {
55
- var iv = this;
56
- $.each(iv._plugins, function (n, p) {
57
- if (typeof p[methodName] === 'function') {
58
- p[methodName](...args);
62
+ callPluginMethod(methodName, ...args) {
63
+ for (const p of this._plugins) {
64
+ if (typeof p[methodName] === 'function') {
65
+ p[methodName](...args);
66
+ }
59
67
  }
60
- });
61
- }
68
+ }
62
69
 
63
- iXBRLViewer.prototype.pluginPromise = function (methodName, ...args) {
64
- var iv = this;
65
- return new Promise(function (resolve, reject) {
66
- /* Call promises in turn */
67
- (async function () {
68
- for (var n = 0; n < iv._plugins.length; n++) {
69
- var p = iv._plugins[n];
70
- if (typeof p[methodName] === 'function') {
71
- await p[methodName](...args);
70
+ pluginPromise(methodName, ...args) {
71
+ return new Promise((resolve, reject) => {
72
+ /* Call promises in turn */
73
+ (async () => {
74
+ for (const p of this._plugins) {
75
+ if (typeof p[methodName] === 'function') {
76
+ await p[methodName](...args);
77
+ }
72
78
  }
73
- }
74
- })().then(() => {
75
- resolve();
79
+ })().then(() => {
80
+ resolve();
81
+ });
76
82
  });
77
- });
78
- }
83
+ }
79
84
 
80
- iXBRLViewer.prototype.setFeatures = function(featureNames, queryString) {
81
- const iv = this;
82
- const featureMap = {}
83
- // Enable given features initially
84
- featureNames.forEach(f => {
85
- featureMap[f] = true;
86
- });
87
-
88
- // Enable/disable features based on query string
89
- const urlParams = new URLSearchParams(queryString);
90
- urlParams.forEach((value, key) => {
91
- // Do nothing if feature has already been disabled by query
92
- if (featureMap[key] !== false) {
93
- // Disable feature if value is exactly 'false', anything else enables the feature
94
- featureMap[key] = value !== 'false';
85
+ setFeatures(features, queryString) {
86
+ this._staticFeatures = {}
87
+ for (const [key, value] of Object.entries(features)) {
88
+ this._staticFeatures[key] = value;
95
89
  }
96
- });
97
90
 
98
- // Gather results in _features set
99
- if (iv._features.size > 0) {
100
- iv._features = new Set();
91
+ const urlParams = new URLSearchParams(queryString);
92
+ this._dynamicFeatures = {}
93
+ urlParams.forEach((value, key) => {
94
+ if (value === '') {
95
+ if (this._dynamicFeatures[key] === undefined) {
96
+ value = 'true'
97
+ } else {
98
+ return;
99
+ }
100
+ }
101
+ this._dynamicFeatures[key] = value;
102
+ });
101
103
  }
102
- for (const [feature, enabled] of Object.entries(featureMap)) {
103
- if (enabled) {
104
- iv._features.add(feature);
105
- }
104
+
105
+ getStaticFeatureValue(featureName) {
106
+ return this._staticFeatures[featureName];
106
107
  }
107
- }
108
108
 
109
- iXBRLViewer.prototype.isFeatureEnabled = function (featureName) {
110
- return this._features.has(featureName);
111
- }
109
+ getFeatureValue(featureName) {
110
+ if (this._dynamicFeatures[featureName]) {
111
+ return this._dynamicFeatures[featureName];
112
+ }
113
+ return this.getStaticFeatureValue(featureName);
114
+ }
112
115
 
113
- iXBRLViewer.prototype.isReviewModeEnabled = function () {
114
- return this.isFeatureEnabled('review');
115
- }
116
+ isFeatureEnabled(featureName) {
117
+ return !featureFalsyValues.has(this.getFeatureValue(featureName));
118
+ }
116
119
 
117
- iXBRLViewer.prototype._loadInspectorHTML = function () {
118
- /* Insert HTML and CSS styles into body */
119
- $(require('../html/inspector.html')).prependTo('body');
120
- var inspector_css = require('css-loader!../less/inspector.less').toString();
121
- $('<style id="ixv-style"></style>')
122
- .prop("type", "text/css")
123
- .text(inspector_css)
124
- .appendTo('head');
125
- $('<link id="ixv-favicon" type="image/x-icon" rel="shortcut icon" />')
126
- .attr('href', require('../img/favicon.ico'))
127
- .appendTo('head');
128
-
129
- try {
130
- $('.inspector-foot .version').text(__VERSION__);
120
+ isStaticFeatureEnabled(featureName) {
121
+ return !featureFalsyValues.has(this.getStaticFeatureValue(featureName));
131
122
  }
132
- catch (e) {
133
- // ReferenceError if __VERSION__ not defined
123
+
124
+ isReviewModeEnabled() {
125
+ return this.isFeatureEnabled(FEATURE_REVIEW);
134
126
  }
135
- }
136
127
 
137
- iXBRLViewer.prototype._reparentDocument = function () {
138
- var iframeContainer = $('#ixv #iframe-container');
128
+ getGuideLinkUrl() {
129
+ if (!this.isStaticFeatureEnabled(FEATURE_GUIDE_LINK)) {
130
+ return USER_GUIDE_URL;
131
+ }
132
+ return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_GUIDE_LINK));
133
+ }
139
134
 
140
- var iframe = $('<iframe title="iXBRL document view"/>').appendTo(iframeContainer)[0];
135
+ getSupportLinkUrl() {
136
+ if (!this.isStaticFeatureEnabled(FEATURE_SUPPORT_LINK)) {
137
+ return null;
138
+ }
139
+ return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_SUPPORT_LINK));
140
+ }
141
141
 
142
- var doc = iframe.contentDocument || iframe.contentWindow.document;
143
- doc.open();
144
- doc.write("<!DOCTYPE html><html><head><title></title></head><body></body></html>");
145
- doc.close();
142
+ getSurveyLinkUrl() {
143
+ if (!this.isStaticFeatureEnabled(FEATURE_SURVEY_LINK)) {
144
+ return null;
145
+ }
146
+ return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_SURVEY_LINK));
147
+ }
146
148
 
147
- var docTitle = $('title').text();
148
- if (docTitle != "") {
149
- docTitle = "Inline Viewer - " + docTitle;
149
+ isViewerEnabled() {
150
+ const urlParams = new URLSearchParams(window.location.search);
151
+ return (urlParams.get('disable-viewer') ?? 'false') === 'false';
150
152
  }
151
- else {
152
- docTitle = "Inline Viewer";
153
+
154
+ // Resolves URL relative to the config file
155
+ resolveRelativeUrl(url) {
156
+ if (this.options.configUrl === undefined) {
157
+ return url;
158
+ }
159
+ const resolvedUrl = new URL(url, this.options.configUrl.href);
160
+ return resolvedUrl.href;
153
161
  }
154
- if ($('html').attr("lang") === undefined) {
155
- $('html').attr("lang", "en-US");
162
+
163
+ _loadInspectorHTML() {
164
+ /* Insert HTML and CSS styles into body */
165
+ const footerLogoHtml = this.runtimeConfig.skin?.footerLogoHtml ?? require("../html/footer-logo.html");
166
+ $(require('../html/inspector.html'))
167
+ .prependTo('body')
168
+ .find("#footer-logo").html(footerLogoHtml);
169
+ const inspector_css = require('../less/inspector.less').toString();
170
+ $('<style id="ixv-style"></style>')
171
+ .prop("type", "text/css")
172
+ .text(inspector_css)
173
+ .appendTo('head');
174
+ if (this.runtimeConfig.skin?.stylesheetUrl !== undefined) {
175
+ $('<link rel="stylesheet" id="ixv-style-skin" />')
176
+ .attr("href", this.resolveRelativeUrl(this.runtimeConfig.skin.stylesheetUrl))
177
+ .appendTo('head');
178
+ }
179
+ const favIconUrl = this.runtimeConfig.skin?.faviconUrl !== undefined ? this.resolveRelativeUrl(this.runtimeConfig.skin.faviconUrl) : require("../img/favicon.ico");
180
+ $('<link id="ixv-favicon" type="image/x-icon" rel="shortcut icon" />')
181
+ .attr('href', favIconUrl)
182
+ .appendTo('head');
183
+
184
+ try {
185
+ $('.inspector-foot .version').text(__VERSION__);
186
+ }
187
+ catch (e) {
188
+ // ReferenceError if __VERSION__ not defined
189
+ }
156
190
  }
157
191
 
158
- $('head').children().not("script").not("style#ixv-style").not("link#ixv-favicon").appendTo($(iframe).contents().find('head'));
192
+ _reparentDocument() {
193
+ const iframeContainer = $('#ixv #iframe-container');
194
+
195
+ const iframe = $('<iframe title="iXBRL document view" tabindex="0"/>')
196
+ .data("report-index", 0)
197
+ .appendTo(iframeContainer)[0];
198
+
199
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
200
+ doc.open();
201
+ doc.write("<!DOCTYPE html><html><head><title></title></head><body></body></html>");
202
+ doc.close();
203
+
204
+ let docTitle = $('title').text();
205
+ if (docTitle !== "") {
206
+ docTitle = `Inline Viewer - ${docTitle}`;
207
+ }
208
+ else {
209
+ docTitle = "Inline Viewer";
210
+ }
211
+
212
+
213
+ $('head')
214
+ .children().not("script, style#ixv-style, link#ixv-style-skin, link#ixv-favicon").appendTo($(iframe).contents().find('head'));
215
+
216
+ $('<title>').text(docTitle).appendTo($('head'));
159
217
 
160
- $('<title>').text(docTitle).appendTo($('head'));
218
+ /* Due to self-closing tags, our script tags may not be a direct child of
219
+ * the body tag in an HTML DOM, so move them so that they are */
220
+ $('body script').appendTo($('body'));
161
221
 
162
- /* Due to self-closing tags, our script tags may not be a direct child of
163
- * the body tag in an HTML DOM, so move them so that they are */
164
- $('body script').appendTo($('body'));
165
- const iframeBody = $(iframe).contents().find('body');
166
- $('body').children().not("script").not('#ixv').not(iframeContainer).appendTo(iframeBody);
222
+ const html = $('html');
223
+ const body = $('body');
224
+ const iframeHtml = $(iframe).contents().find('html');
225
+ const iframeBody = $(iframe).contents().find('body');
226
+ moveNonAppAttributes(html.get(0), iframeHtml.get(0));
227
+ moveNonAppAttributes(body.get(0), iframeBody.get(0));
228
+ html.attr('xmlns', 'http://www.w3.org/1999/xhtml');
167
229
 
168
- /* Move all attributes on the body tag to the new body */
169
- for (const bodyAttr of [...$('body').prop("attributes")]) {
170
- iframeBody.attr(bodyAttr.name, bodyAttr.value);
171
- $('body').removeAttr(bodyAttr.name);
230
+ body.children().not("script").not('#ixv').not(iframeContainer).appendTo(iframeBody);
231
+
232
+ /* Avoid any inline styles on the old body interfering with the inspector */
233
+ body.removeAttr('style');
234
+ return iframe;
172
235
  }
173
236
 
174
- /* Avoid any inline styles on the old body interfering with the inspector */
175
- $('body').removeAttr('style');
176
- return iframe;
177
- }
237
+ _getTaxonomyData() {
238
+ for (let i = document.body.children.length - 1; i >= 0; i--) {
239
+ const elt = document.body.children[i];
240
+ if (elt.tagName.toUpperCase() === 'SCRIPT' && elt.getAttribute("type") === 'application/x.ixbrl-viewer+json') {
241
+ return elt.innerHTML;
242
+ }
243
+ }
244
+ return null;
245
+ }
178
246
 
179
- iXBRLViewer.prototype._getTaxonomyData = function () {
180
- for (var i = document.body.children.length - 1; i >= 0; i--) {
181
- var elt = document.body.children[i];
182
- if (elt.tagName.toUpperCase() == 'SCRIPT' && elt.getAttribute("type") == 'application/x.ixbrl-viewer+json') {
183
- return elt.innerHTML;
247
+ _checkDocumentSetBrowserSupport() {
248
+ if (document.location.protocol === 'file:') {
249
+ alert("Displaying iXBRL document sets from local files is not supported. Please view the viewer files using a web server.");
184
250
  }
185
251
  }
186
- return null;
187
- }
188
252
 
189
- iXBRLViewer.prototype._checkDocumentSetBrowserSupport = function () {
190
- if (document.location.protocol == 'file:') {
191
- alert("Displaying iXBRL document sets from local files is not supported. Please view the viewer files using a web server.");
253
+ _loadRuntimeConfig() {
254
+ return new Promise((resolve, reject) => {
255
+ if (this.options.configUrl === undefined) {
256
+ resolve({});
257
+ }
258
+ else {
259
+ fetch(this.options.configUrl)
260
+ .then((resp) => {
261
+ switch (resp.status) {
262
+ case 200:
263
+ return resp.json();
264
+ case 404:
265
+ return Promise.resolve({});
266
+ default:
267
+ return Promise.reject(`Fetch of ${this.options.configUrl} failed: ${resp.status}`);
268
+ };
269
+ })
270
+ .then((data) => {
271
+ resolve(data);
272
+ })
273
+ .catch((err) => {
274
+ console.log(err);
275
+ resolve({});
276
+ });
277
+ }
278
+ });
192
279
  }
193
- }
194
280
 
195
- iXBRLViewer.prototype.load = function () {
196
- var iv = this;
197
- var inspector = this.inspector;
281
+ load() {
282
+ const iv = this;
283
+ const inspector = this.inspector;
284
+
285
+ this._loadRuntimeConfig().then((runtimeConfig) => {
286
+ this.runtimeConfig = runtimeConfig;
287
+ initializeTheme();
198
288
 
199
- setTimeout(function () {
289
+ const stubViewer = $('body').hasClass('ixv-stub-viewer');
200
290
 
201
- // We need to parse JSON first so that we can determine feature enablement before loading begins.
202
- const taxonomyData = iv._getTaxonomyData();
203
- const parsedTaxonomyData = taxonomyData && JSON.parse(taxonomyData);
204
- iv.setFeatures((parsedTaxonomyData && parsedTaxonomyData["features"]) || [], window.location.search);
291
+ // If viewer is disabled, but not in stub viewer mode, just abort
292
+ // loading to leave the iXBRL file as-is
293
+ if (!iv.isViewerEnabled() && !stubViewer) {
294
+ return;
295
+ }
205
296
 
206
- iv._loadInspectorHTML();
207
- var iframes;
208
- const stubViewer = $('body').hasClass('ixv-stub-viewer');
209
- if (!stubViewer) {
210
- iframes = $(iv._reparentDocument());
211
- }
212
- else {
213
- iframes = $();
214
- }
215
- if (parsedTaxonomyData === null) {
216
- $('#ixv .loader .text').text("Error: Could not find viewer data");
217
- $('#ixv .loader').removeClass("loading");
218
- return;
219
- }
220
- const report = new iXBRLReport(parsedTaxonomyData);
221
- const ds = report.documentSetFiles();
222
- var hasExternalIframe = false;
223
- for (var i = stubViewer ? 0 : 1; i < ds.length; i++) {
224
- const iframe = $("<iframe />").attr("src", ds[i]).appendTo("#ixv #iframe-container");
225
- iframes = iframes.add(iframe);
226
- hasExternalIframe = true;
227
- }
228
- if (hasExternalIframe) {
229
- iv._checkDocumentSetBrowserSupport();
230
- }
297
+ // Loading mask starts here
298
+ iv._loadInspectorHTML();
299
+ let iframes = $();
231
300
 
232
- const progress = stubViewer ? 'Loading iXBRL Report' : 'Loading iXBRL Viewer';
233
- iv.setProgress(progress).then(() => {
234
- /* Poll for iframe load completing - there doesn't seem to be a reliable event that we can use */
235
- var timer = setInterval(function () {
236
- var complete = true;
237
- iframes.each(function (n) {
238
- var iframe = this;
239
- var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
240
- if ((iframeDoc.readyState != 'complete' && iframeDoc.readyState != 'interactive') || $(iframe).contents().find("body").children().length == 0) {
241
- complete = false;
242
- }
243
- });
244
- if (complete) {
245
- clearInterval(timer);
246
-
247
- var viewer = iv.viewer = new Viewer(iv, iframes, report);
248
-
249
- viewer.initialize()
250
- .then(() => inspector.initialize(report, viewer))
251
- .then(() => {
252
- interact('#viewer-pane').resizable({
253
- edges: { left: false, right: ".resize", bottom: false, top: false},
254
- restrictEdges: {
255
- outer: 'parent',
256
- endOnly: true,
257
- },
258
- restrictSize: {
259
- min: { width: 100 }
260
- },
261
- })
262
- .on('resizestart', function (event) {
263
- $('#ixv').css("pointer-events", "none");
264
- })
265
- .on('resizemove', function (event) {
266
- var target = event.target;
267
- var w = 100 * event.rect.width / $(target).parent().width();
268
- target.style.width = w + '%';
269
- $('#inspector').css('width', (100 - w) + '%');
270
- })
271
- .on('resizeend', function (event) {
272
- $('#ixv').css("pointer-events", "auto");
273
- });
274
- $('#ixv .loader').remove();
301
+ // We need to parse JSON first so that we can determine feature enablement before loading begins.
302
+ const taxonomyData = iv._getTaxonomyData();
303
+ const parsedTaxonomyData = taxonomyData && JSON.parse(taxonomyData);
304
+ let features = parsedTaxonomyData?.features;
305
+ if (!features) {
306
+ features = {};
307
+ }
308
+ // `features` was previously an array of flag values
309
+ // Support this for backwards compatability
310
+ else if (Array.isArray(features)) {
311
+ features = features.reduce((obj, val) => {
312
+ obj[val] = true;
313
+ return obj;
314
+ }, {});
315
+ }
316
+ if (this.runtimeConfig.features !== undefined) {
317
+ features = {...this.runtimeConfig.features, features};
318
+ }
319
+ iv.setFeatures(features, window.location.search);
275
320
 
276
- /* Focus on fact specified in URL fragment, if any */
277
- inspector.handleFactDeepLink();
278
- if (iv.options.showValidationWarningOnStart) {
279
- inspector.showValidationWarning();
321
+ const reportSet = new ReportSet(parsedTaxonomyData);
322
+ reportSet.taxonomyNamer = new TaxonomyNamer(new Map(Object.entries(this.runtimeConfig.taxonomyNames ?? {})));
323
+
324
+ // Viewer disabled in stub viewer mode => redirect to first iXBRL document
325
+ if (!iv.isViewerEnabled()) {
326
+ window.location.replace(reportSet.reportFiles()[0].file);
327
+ return;
328
+ }
329
+
330
+ if (parsedTaxonomyData === null) {
331
+ $('#ixv .loader .text').text("Error: Could not find viewer data");
332
+ $('#ixv .loader').removeClass("loading");
333
+ return;
334
+ }
335
+
336
+ if (!stubViewer) {
337
+ iframes = $(iv._reparentDocument());
338
+ }
339
+ const ds = reportSet.reportFiles();
340
+ let hasExternalIframe = false;
341
+ for (let i = stubViewer ? 0 : 1; i < ds.length; i++) {
342
+ const iframe = $('<iframe tabindex="0" />').attr("src", ds[i].file).data("report-index", ds[i].index).appendTo("#ixv #iframe-container");
343
+ iframes = iframes.add(iframe);
344
+ hasExternalIframe = true;
345
+ }
346
+ if (hasExternalIframe) {
347
+ iv._checkDocumentSetBrowserSupport();
348
+ }
349
+
350
+ const progress = stubViewer ? 'Loading iXBRL Report' : 'Loading iXBRL Viewer';
351
+ iv.setProgress(progress).then(() => {
352
+ /* Poll for iframe load completing - there doesn't seem to be a reliable event that we can use */
353
+ const timer = setInterval(() => {
354
+ let complete = true;
355
+ iframes.each((n, iframe) => {
356
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
357
+ if ((iframeDoc.readyState !== 'complete' && iframeDoc.readyState !== 'interactive') || $(iframe).contents().find("body").children().length === 0) {
358
+ complete = false;
359
+ }
360
+ });
361
+ if (complete) {
362
+ clearInterval(timer);
363
+
364
+ iframes.each((n, iframe) => {
365
+ const htmlNode = $(iframe).contents().find('html');
366
+ // A schema valid report should not have a lang attribute on the html element.
367
+ // However, if the report is not schema valid, we shouldn't override it.
368
+ if (htmlNode.attr('lang') === undefined) {
369
+ // If the report has an XML lang attribute, use it as the HTML lang for screen readers.
370
+ // If the language of the report can't be detected, set it to an empty string to avoid
371
+ // inheriting the lang of the application HTML node (which is set to the UI language).
372
+ const docLang = htmlNode.attr('xml:lang') || '';
373
+ htmlNode.attr('lang', docLang);
280
374
  }
281
- viewer.postLoadAsync();
282
- inspector.postLoadAsync();
283
- })
284
- .catch(err => {
285
- if (err instanceof DocumentTooLargeError) {
375
+ });
376
+
377
+ const viewer = new Viewer(iv, iframes, reportSet);
378
+ iv.viewer = viewer
379
+
380
+ viewer.initialize()
381
+ .then(() => inspector.initialize(reportSet, viewer))
382
+ .then(() => {
383
+ interact('#viewer-pane').resizable({
384
+ edges: { left: false, right: ".resize", bottom: false, top: false},
385
+ restrictEdges: {
386
+ outer: 'parent',
387
+ endOnly: true,
388
+ },
389
+ restrictSize: {
390
+ min: { width: 100 }
391
+ },
392
+ })
393
+ .on('resizestart', () =>
394
+ $('#ixv').css("pointer-events", "none")
395
+ )
396
+ .on('resizemove', (event) => {
397
+ const target = event.target;
398
+ const w = 100 * event.rect.width / $(target).parent().width();
399
+ target.style.width = `${w}%`;
400
+ $('#inspector').css('width', `${100 - w}%`);
401
+ })
402
+ .on('resizeend', (event) =>
403
+ $('#ixv').css("pointer-events", "auto")
404
+ );
286
405
  $('#ixv .loader').remove();
287
- $('#inspector').addClass('failed-to-load');
288
- }
289
- else {
290
- throw err;
291
- }
292
406
 
293
- });
294
- }
295
- }, 250);
296
- });
297
- }, 0);
298
- }
407
+ /* Focus on fact specified in URL fragment, if any */
408
+ if (iv.options.showValidationWarningOnStart) {
409
+ inspector.showValidationWarning();
410
+ }
411
+ viewer.postLoadAsync();
412
+ inspector.postLoadAsync();
413
+ })
414
+ .catch(err => {
415
+ if (err instanceof DocumentTooLargeError) {
416
+ $('#ixv .loader').remove();
417
+ $('#inspector').addClass('failed-to-load');
418
+ }
419
+ else {
420
+ throw err;
421
+ }
299
422
 
300
- /* Update the progress message during initial load. Returns a Promise which
301
- * resolves once the message is actually displayed */
302
- iXBRLViewer.prototype.setProgress = function (msg) {
303
- return new Promise((resolve, reject) => {
304
- /* We need to do a double requestAnimationFrame, as we need to get the
305
- * message up before the ensuing thread-blocking work
306
- * https://bugs.chromium.org/p/chromium/issues/detail?id=675795
307
- */
308
- window.requestAnimationFrame(function () {
309
- console.log(`%c [Progress] ${msg} `, 'background: #77d1c8; color: black;');
310
- $('#ixv .loader .text').text(msg);
311
- window.requestAnimationFrame(function () {
312
- resolve();
423
+ });
424
+ }
425
+ }, 250);
426
+ });
427
+ }, 0);
428
+ }
429
+
430
+ /* Update the progress message during initial load. Returns a Promise which
431
+ * resolves once the message is actually displayed */
432
+ setProgress(msg) {
433
+ return new Promise((resolve, reject) => {
434
+ /* We need to do a double requestAnimationFrame, as we need to get the
435
+ * message up before the ensuing thread-blocking work
436
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=675795
437
+ */
438
+ window.requestAnimationFrame(() => {
439
+ console.log(`%c [Progress] ${msg} `, 'background: #77d1c8; color: black;');
440
+ $('#ixv .loader .text').text(msg);
441
+ window.requestAnimationFrame(() => resolve());
313
442
  });
314
443
  });
315
- });
444
+ }
316
445
  }