ixbrl-viewer 1.4.4__py3-none-any.whl → 1.4.6__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.

Potentially problematic release.


This version of ixbrl-viewer might be problematic. Click here for more details.

@@ -6,313 +6,328 @@ import { ReportSet } from "./reportset.js";
6
6
  import { Viewer, DocumentTooLargeError } from "./viewer.js";
7
7
  import { Inspector } from "./inspector.js";
8
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,
9
+ export class iXBRLViewer {
10
+
11
+ constructor(options) {
12
+ this._features = new Set();
13
+ this._plugins = [];
14
+ this.inspector = new Inspector(this);
15
+ this.viewer = null;
16
+ options = options || {};
17
+ const defaults = {
18
+ continuationElementLimit: 10000,
19
+ showValidationWarningOnStart: false,
20
+ }
21
+ this.options = {...defaults, ...options};
18
22
  }
19
- this.options = {...defaults, ...options};
20
- }
21
23
 
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
- }
24
+ /*
25
+ * Adds a plugin to the viewer. The plugin should be an object with one or
26
+ * more of the methods listed below, which will be called by the viewer.
27
+ *
28
+ * preProcessiXBRL(bodyElement, docIndex)
29
+ *
30
+ * Called upon viewer intialisation, once for each iXBRL document. bodyElement
31
+ * is a DOM object for the body element. docIndex is the index of the document
32
+ * within the document set.
33
+ *
34
+ * updateViewerStyleElement(styleElts)
35
+ *
36
+ * styleElts is a JQuery object consisting of the viewer style elements for
37
+ * each document in the document set. Additional CSS can be appended to the
38
+ * contents, or additional header elements inserted relative to the provided
39
+ * style element.
40
+ *
41
+ * extendDisplayOptionsMenu(menu)
42
+ *
43
+ * Called when the display options menu is created or recreated. menu is a
44
+ * Menu object, and can be modified to add additional menu items.
45
+ *
46
+ * extendHighlightKey(key)
47
+ *
48
+ * Called when the highlight color key is created. key is an array of labels,
49
+ * which can be modified or extended.
50
+ *
51
+ */
52
+ registerPlugin(plugin) {
53
+ this._plugins.push(plugin);
54
+ }
53
55
 
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);
56
+ callPluginMethod(methodName, ...args) {
57
+ for (const p of this._plugins) {
58
+ if (typeof p[methodName] === 'function') {
59
+ p[methodName](...args);
60
+ }
59
61
  }
60
- });
61
- }
62
+ }
62
63
 
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);
64
+ pluginPromise(methodName, ...args) {
65
+ return new Promise((resolve, reject) => {
66
+ /* Call promises in turn */
67
+ (async () => {
68
+ for (const p of this._plugins) {
69
+ if (typeof p[methodName] === 'function') {
70
+ await p[methodName](...args);
71
+ }
72
72
  }
73
+ })().then(() => {
74
+ resolve();
75
+ });
76
+ });
77
+ }
78
+
79
+ setFeatures(featureNames, queryString) {
80
+ const featureMap = {}
81
+ // Enable given features initially
82
+ featureNames.forEach(f => {
83
+ featureMap[f] = true;
84
+ });
85
+
86
+ // Enable/disable features based on query string
87
+ const urlParams = new URLSearchParams(queryString);
88
+ urlParams.forEach((value, key) => {
89
+ // Do nothing if feature has already been disabled by query
90
+ if (featureMap[key] !== false) {
91
+ // Disable feature if value is exactly 'false', anything else enables the feature
92
+ featureMap[key] = value !== 'false';
73
93
  }
74
- })().then(() => {
75
- resolve();
76
94
  });
77
- });
78
- }
79
95
 
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';
96
+ // Gather results in _features set
97
+ if (this._features.size > 0) {
98
+ this._features = new Set();
95
99
  }
96
- });
97
-
98
- // Gather results in _features set
99
- if (iv._features.size > 0) {
100
- iv._features = new Set();
101
- }
102
- for (const [feature, enabled] of Object.entries(featureMap)) {
103
- if (enabled) {
104
- iv._features.add(feature);
100
+ for (const [feature, enabled] of Object.entries(featureMap)) {
101
+ if (enabled) {
102
+ this._features.add(feature);
103
+ }
105
104
  }
106
105
  }
107
- }
108
106
 
109
- iXBRLViewer.prototype.isFeatureEnabled = function (featureName) {
110
- return this._features.has(featureName);
111
- }
107
+ isFeatureEnabled(featureName) {
108
+ return this._features.has(featureName);
109
+ }
112
110
 
113
- iXBRLViewer.prototype.isReviewModeEnabled = function () {
114
- return this.isFeatureEnabled('review');
115
- }
111
+ isReviewModeEnabled() {
112
+ return this.isFeatureEnabled('review');
113
+ }
116
114
 
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__);
115
+ isViewerEnabled() {
116
+ const urlParams = new URLSearchParams(window.location.search);
117
+ return (urlParams.get('disable-viewer') ?? 'false') === 'false';
131
118
  }
132
- catch (e) {
133
- // ReferenceError if __VERSION__ not defined
119
+
120
+ _loadInspectorHTML() {
121
+ /* Insert HTML and CSS styles into body */
122
+ $(require('../html/inspector.html')).prependTo('body');
123
+ const inspector_css = require('css-loader!../less/inspector.less').toString();
124
+ $('<style id="ixv-style"></style>')
125
+ .prop("type", "text/css")
126
+ .text(inspector_css)
127
+ .appendTo('head');
128
+ $('<link id="ixv-favicon" type="image/x-icon" rel="shortcut icon" />')
129
+ .attr('href', require('../img/favicon.ico'))
130
+ .appendTo('head');
131
+
132
+ try {
133
+ $('.inspector-foot .version').text(__VERSION__);
134
+ }
135
+ catch (e) {
136
+ // ReferenceError if __VERSION__ not defined
137
+ }
134
138
  }
135
- }
136
139
 
137
- iXBRLViewer.prototype._reparentDocument = function () {
138
- var iframeContainer = $('#ixv #iframe-container');
140
+ _reparentDocument() {
141
+ const iframeContainer = $('#ixv #iframe-container');
139
142
 
140
- var iframe = $('<iframe title="iXBRL document view"/>')
141
- .data("report-index", 0)
142
- .appendTo(iframeContainer)[0];
143
+ const iframe = $('<iframe title="iXBRL document view"/>')
144
+ .data("report-index", 0)
145
+ .appendTo(iframeContainer)[0];
143
146
 
144
- var doc = iframe.contentDocument || iframe.contentWindow.document;
145
- doc.open();
146
- doc.write("<!DOCTYPE html><html><head><title></title></head><body></body></html>");
147
- doc.close();
147
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
148
+ doc.open();
149
+ doc.write("<!DOCTYPE html><html><head><title></title></head><body></body></html>");
150
+ doc.close();
148
151
 
149
- var docTitle = $('title').text();
150
- if (docTitle != "") {
151
- docTitle = "Inline Viewer - " + docTitle;
152
- }
153
- else {
154
- docTitle = "Inline Viewer";
155
- }
156
- if ($('html').attr("lang") === undefined) {
157
- $('html').attr("lang", "en-US");
158
- }
152
+ let docTitle = $('title').text();
153
+ if (docTitle != "") {
154
+ docTitle = "Inline Viewer - " + docTitle;
155
+ }
156
+ else {
157
+ docTitle = "Inline Viewer";
158
+ }
159
+ if ($('html').attr("lang") === undefined) {
160
+ $('html').attr("lang", "en-US");
161
+ }
159
162
 
160
- $('head').children().not("script").not("style#ixv-style").not("link#ixv-favicon").appendTo($(iframe).contents().find('head'));
163
+ $('head').children().not("script").not("style#ixv-style").not("link#ixv-favicon").appendTo($(iframe).contents().find('head'));
161
164
 
162
- $('<title>').text(docTitle).appendTo($('head'));
165
+ $('<title>').text(docTitle).appendTo($('head'));
163
166
 
164
- /* Due to self-closing tags, our script tags may not be a direct child of
165
- * the body tag in an HTML DOM, so move them so that they are */
166
- $('body script').appendTo($('body'));
167
- const iframeBody = $(iframe).contents().find('body');
168
- $('body').children().not("script").not('#ixv').not(iframeContainer).appendTo(iframeBody);
167
+ /* Due to self-closing tags, our script tags may not be a direct child of
168
+ * the body tag in an HTML DOM, so move them so that they are */
169
+ $('body script').appendTo($('body'));
170
+ const iframeBody = $(iframe).contents().find('body');
171
+ $('body').children().not("script").not('#ixv').not(iframeContainer).appendTo(iframeBody);
169
172
 
170
- /* Move all attributes on the body tag to the new body */
171
- for (const bodyAttr of [...$('body').prop("attributes")]) {
172
- iframeBody.attr(bodyAttr.name, bodyAttr.value);
173
- $('body').removeAttr(bodyAttr.name);
174
- }
173
+ /* Move all attributes on the body tag to the new body */
174
+ for (const bodyAttr of [...$('body').prop("attributes")]) {
175
+ iframeBody.attr(bodyAttr.name, bodyAttr.value);
176
+ $('body').removeAttr(bodyAttr.name);
177
+ }
175
178
 
176
- /* Avoid any inline styles on the old body interfering with the inspector */
177
- $('body').removeAttr('style');
178
- return iframe;
179
- }
179
+ /* Avoid any inline styles on the old body interfering with the inspector */
180
+ $('body').removeAttr('style');
181
+ return iframe;
182
+ }
180
183
 
181
- iXBRLViewer.prototype._getTaxonomyData = function () {
182
- for (var i = document.body.children.length - 1; i >= 0; i--) {
183
- var elt = document.body.children[i];
184
- if (elt.tagName.toUpperCase() == 'SCRIPT' && elt.getAttribute("type") == 'application/x.ixbrl-viewer+json') {
185
- return elt.innerHTML;
184
+ _getTaxonomyData() {
185
+ for (let i = document.body.children.length - 1; i >= 0; i--) {
186
+ const elt = document.body.children[i];
187
+ if (elt.tagName.toUpperCase() == 'SCRIPT' && elt.getAttribute("type") == 'application/x.ixbrl-viewer+json') {
188
+ return elt.innerHTML;
189
+ }
186
190
  }
191
+ return null;
187
192
  }
188
- return null;
189
- }
190
193
 
191
- iXBRLViewer.prototype._checkDocumentSetBrowserSupport = function () {
192
- if (document.location.protocol == 'file:') {
193
- alert("Displaying iXBRL document sets from local files is not supported. Please view the viewer files using a web server.");
194
+ _checkDocumentSetBrowserSupport() {
195
+ if (document.location.protocol == 'file:') {
196
+ alert("Displaying iXBRL document sets from local files is not supported. Please view the viewer files using a web server.");
197
+ }
194
198
  }
195
- }
196
199
 
197
- iXBRLViewer.prototype.load = function () {
198
- var iv = this;
199
- var inspector = this.inspector;
200
+ load() {
201
+ const iv = this;
202
+ const inspector = this.inspector;
200
203
 
201
- setTimeout(function () {
204
+ setTimeout(function () {
205
+ const stubViewer = $('body').hasClass('ixv-stub-viewer');
202
206
 
203
- // We need to parse JSON first so that we can determine feature enablement before loading begins.
204
- const taxonomyData = iv._getTaxonomyData();
205
- const parsedTaxonomyData = taxonomyData && JSON.parse(taxonomyData);
206
- iv.setFeatures((parsedTaxonomyData && parsedTaxonomyData["features"]) || [], window.location.search);
207
+ // If viewer is disabled, but not in stub viewer mode, just abort
208
+ // loading to leave the iXBRL file as-is
209
+ if (!iv.isViewerEnabled() && !stubViewer) {
210
+ return;
211
+ }
207
212
 
208
- iv._loadInspectorHTML();
209
- var iframes;
210
- const stubViewer = $('body').hasClass('ixv-stub-viewer');
211
- if (!stubViewer) {
212
- iframes = $(iv._reparentDocument());
213
- }
214
- else {
215
- iframes = $();
216
- }
217
- if (parsedTaxonomyData === null) {
218
- $('#ixv .loader .text').text("Error: Could not find viewer data");
219
- $('#ixv .loader').removeClass("loading");
220
- return;
221
- }
222
- const reportSet = new ReportSet(parsedTaxonomyData);
223
- const ds = reportSet.reportFiles();
224
- var hasExternalIframe = false;
225
- for (var i = stubViewer ? 0 : 1; i < ds.length; i++) {
226
- const iframe = $("<iframe />").attr("src", ds[i].file).data("report-index", ds[i].index).appendTo("#ixv #iframe-container");
227
- iframes = iframes.add(iframe);
228
- hasExternalIframe = true;
229
- }
230
- if (hasExternalIframe) {
231
- iv._checkDocumentSetBrowserSupport();
232
- }
213
+ // Loading mask starts here
214
+ iv._loadInspectorHTML();
215
+ let iframes = $();
233
216
 
234
- const progress = stubViewer ? 'Loading iXBRL Report' : 'Loading iXBRL Viewer';
235
- iv.setProgress(progress).then(() => {
236
- /* Poll for iframe load completing - there doesn't seem to be a reliable event that we can use */
237
- var timer = setInterval(function () {
238
- var complete = true;
239
- iframes.each(function (n) {
240
- var iframe = this;
241
- var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
242
- if ((iframeDoc.readyState != 'complete' && iframeDoc.readyState != 'interactive') || $(iframe).contents().find("body").children().length == 0) {
243
- complete = false;
244
- }
245
- });
246
- if (complete) {
247
- clearInterval(timer);
248
-
249
- var viewer = iv.viewer = new Viewer(iv, iframes, reportSet);
250
-
251
- viewer.initialize()
252
- .then(() => inspector.initialize(reportSet, viewer))
253
- .then(() => {
254
- interact('#viewer-pane').resizable({
255
- edges: { left: false, right: ".resize", bottom: false, top: false},
256
- restrictEdges: {
257
- outer: 'parent',
258
- endOnly: true,
259
- },
260
- restrictSize: {
261
- min: { width: 100 }
262
- },
263
- })
264
- .on('resizestart', function (event) {
265
- $('#ixv').css("pointer-events", "none");
266
- })
267
- .on('resizemove', function (event) {
268
- var target = event.target;
269
- var w = 100 * event.rect.width / $(target).parent().width();
270
- target.style.width = w + '%';
271
- $('#inspector').css('width', (100 - w) + '%');
272
- })
273
- .on('resizeend', function (event) {
274
- $('#ixv').css("pointer-events", "auto");
275
- });
276
- $('#ixv .loader').remove();
277
-
278
- /* Focus on fact specified in URL fragment, if any */
279
- inspector.handleFactDeepLink();
280
- if (iv.options.showValidationWarningOnStart) {
281
- inspector.showValidationWarning();
282
- }
283
- viewer.postLoadAsync();
284
- inspector.postLoadAsync();
285
- })
286
- .catch(err => {
287
- if (err instanceof DocumentTooLargeError) {
217
+ // We need to parse JSON first so that we can determine feature enablement before loading begins.
218
+ const taxonomyData = iv._getTaxonomyData();
219
+ const parsedTaxonomyData = taxonomyData && JSON.parse(taxonomyData);
220
+ iv.setFeatures((parsedTaxonomyData && parsedTaxonomyData["features"]) || [], window.location.search);
221
+
222
+ const reportSet = new ReportSet(parsedTaxonomyData);
223
+
224
+ // Viewer disabled in stub viewer mode => redirect to first iXBRL document
225
+ if (!iv.isViewerEnabled()) {
226
+ window.location.replace(reportSet.reportFiles()[0].file);
227
+ return;
228
+ }
229
+
230
+ if (parsedTaxonomyData === null) {
231
+ $('#ixv .loader .text').text("Error: Could not find viewer data");
232
+ $('#ixv .loader').removeClass("loading");
233
+ return;
234
+ }
235
+
236
+ if (!stubViewer) {
237
+ iframes = $(iv._reparentDocument());
238
+ }
239
+ const ds = reportSet.reportFiles();
240
+ let hasExternalIframe = false;
241
+ for (let i = stubViewer ? 0 : 1; i < ds.length; i++) {
242
+ const iframe = $("<iframe />").attr("src", ds[i].file).data("report-index", ds[i].index).appendTo("#ixv #iframe-container");
243
+ iframes = iframes.add(iframe);
244
+ hasExternalIframe = true;
245
+ }
246
+ if (hasExternalIframe) {
247
+ iv._checkDocumentSetBrowserSupport();
248
+ }
249
+
250
+ const progress = stubViewer ? 'Loading iXBRL Report' : 'Loading iXBRL Viewer';
251
+ iv.setProgress(progress).then(() => {
252
+ /* Poll for iframe load completing - there doesn't seem to be a reliable event that we can use */
253
+ let timer = setInterval(function () {
254
+ let complete = true;
255
+ iframes.each(function (n) {
256
+ const iframe = this;
257
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
258
+ if ((iframeDoc.readyState != 'complete' && iframeDoc.readyState != 'interactive') || $(iframe).contents().find("body").children().length == 0) {
259
+ complete = false;
260
+ }
261
+ });
262
+ if (complete) {
263
+ clearInterval(timer);
264
+
265
+ const viewer = iv.viewer = new Viewer(iv, iframes, reportSet);
266
+
267
+ viewer.initialize()
268
+ .then(() => inspector.initialize(reportSet, viewer))
269
+ .then(() => {
270
+ interact('#viewer-pane').resizable({
271
+ edges: { left: false, right: ".resize", bottom: false, top: false},
272
+ restrictEdges: {
273
+ outer: 'parent',
274
+ endOnly: true,
275
+ },
276
+ restrictSize: {
277
+ min: { width: 100 }
278
+ },
279
+ })
280
+ .on('resizestart', () =>
281
+ $('#ixv').css("pointer-events", "none")
282
+ )
283
+ .on('resizemove', (event) => {
284
+ const target = event.target;
285
+ const w = 100 * event.rect.width / $(target).parent().width();
286
+ target.style.width = w + '%';
287
+ $('#inspector').css('width', (100 - w) + '%');
288
+ })
289
+ .on('resizeend', (event) =>
290
+ $('#ixv').css("pointer-events", "auto")
291
+ );
288
292
  $('#ixv .loader').remove();
289
- $('#inspector').addClass('failed-to-load');
290
- }
291
- else {
292
- throw err;
293
- }
294
293
 
295
- });
296
- }
297
- }, 250);
298
- });
299
- }, 0);
300
- }
294
+ /* Focus on fact specified in URL fragment, if any */
295
+ inspector.handleFactDeepLink();
296
+ if (iv.options.showValidationWarningOnStart) {
297
+ inspector.showValidationWarning();
298
+ }
299
+ viewer.postLoadAsync();
300
+ inspector.postLoadAsync();
301
+ })
302
+ .catch(err => {
303
+ if (err instanceof DocumentTooLargeError) {
304
+ $('#ixv .loader').remove();
305
+ $('#inspector').addClass('failed-to-load');
306
+ }
307
+ else {
308
+ throw err;
309
+ }
301
310
 
302
- /* Update the progress message during initial load. Returns a Promise which
303
- * resolves once the message is actually displayed */
304
- iXBRLViewer.prototype.setProgress = function (msg) {
305
- return new Promise((resolve, reject) => {
306
- /* We need to do a double requestAnimationFrame, as we need to get the
307
- * message up before the ensuing thread-blocking work
308
- * https://bugs.chromium.org/p/chromium/issues/detail?id=675795
309
- */
310
- window.requestAnimationFrame(function () {
311
- console.log(`%c [Progress] ${msg} `, 'background: #77d1c8; color: black;');
312
- $('#ixv .loader .text').text(msg);
311
+ });
312
+ }
313
+ }, 250);
314
+ });
315
+ }, 0);
316
+ }
317
+
318
+ /* Update the progress message during initial load. Returns a Promise which
319
+ * resolves once the message is actually displayed */
320
+ setProgress(msg) {
321
+ return new Promise((resolve, reject) => {
322
+ /* We need to do a double requestAnimationFrame, as we need to get the
323
+ * message up before the ensuing thread-blocking work
324
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=675795
325
+ */
313
326
  window.requestAnimationFrame(function () {
314
- resolve();
327
+ console.log(`%c [Progress] ${msg} `, 'background: #77d1c8; color: black;');
328
+ $('#ixv .loader .text').text(msg);
329
+ window.requestAnimationFrame(() => resolve());
315
330
  });
316
331
  });
317
- });
332
+ }
318
333
  }