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.
- iXBRLViewerPlugin/_version.py +2 -2
- iXBRLViewerPlugin/iXBRLViewer.py +3 -2
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +282 -267
- iXBRLViewerPlugin/viewer/src/js/report.js +197 -195
- iXBRLViewerPlugin/viewer/src/js/reportset.js +4 -5
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/METADATA +52 -14
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/RECORD +14 -14
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/WHEEL +1 -1
- tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +1 -0
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/LICENSE +0 -0
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/NOTICE +0 -0
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.4.dist-info → ixbrl_viewer-1.4.6.dist-info}/top_level.txt +0 -0
|
@@ -11,253 +11,255 @@ import i18next from "i18next";
|
|
|
11
11
|
// Class to represent the XBRL data from a single target document in a single
|
|
12
12
|
// Inline XBRL Document or Document Set.
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
export class XBRLReport {
|
|
15
|
+
|
|
16
|
+
constructor(reportSet, reportData) {
|
|
17
|
+
this.reportSet = reportSet;
|
|
18
|
+
this._reportData = reportData;
|
|
19
|
+
// A map of IDs to Fact and Footnote objects
|
|
20
|
+
this._reverseRelationshipCache = {};
|
|
21
|
+
}
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
availableLanguages() {
|
|
24
|
+
if (!this._availableLanguages) {
|
|
25
|
+
this._availableLanguages = new Set()
|
|
26
|
+
for (const c of Object.values(this._reportData.concepts)) {
|
|
27
|
+
for (const ll of Object.values(c.labels)) {
|
|
28
|
+
for (const lang of Object.keys(ll)) {
|
|
29
|
+
this._availableLanguages.add(lang);
|
|
30
|
+
}
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
}
|
|
34
|
+
return this._availableLanguages;
|
|
31
35
|
}
|
|
32
|
-
return this._availableLanguages;
|
|
33
|
-
}
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
37
|
+
facts() {
|
|
38
|
+
return this.reportSet.factsForReport(this);
|
|
39
|
+
}
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
getChildRelationships(conceptName, arcrole) {
|
|
42
|
+
const rels = {}
|
|
43
|
+
const elrs = this._reportData.rels[arcrole] || {};
|
|
44
|
+
for (const elr in elrs) {
|
|
45
|
+
if (conceptName in elrs[elr]) {
|
|
46
|
+
rels[elr] = elrs[elr][conceptName];
|
|
47
|
+
}
|
|
45
48
|
}
|
|
49
|
+
return rels;
|
|
46
50
|
}
|
|
47
|
-
return rels;
|
|
48
|
-
}
|
|
49
51
|
|
|
50
|
-
/*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
/*
|
|
53
|
+
* Build and cache an inverse map of relationships for a given arcrole for
|
|
54
|
+
* efficient lookup of parents concept from a child.
|
|
55
|
+
*
|
|
56
|
+
* Map is arcrole => elr => target => [ rel, ... ]
|
|
57
|
+
*
|
|
58
|
+
* "rel" is modified to have a "src" property with the source concept.
|
|
59
|
+
*/
|
|
60
|
+
_reverseRelationships(arcrole) {
|
|
61
|
+
if (!(arcrole in this._reverseRelationshipCache)) {
|
|
62
|
+
const rrc = {};
|
|
63
|
+
const elrs = this._reportData.rels[arcrole] || {};
|
|
64
|
+
for (const [elr, relSet] of Object.entries(elrs)) {
|
|
65
|
+
for (const [src, rels] of Object.entries(relSet)) {
|
|
66
|
+
for (const r of rels) {
|
|
67
|
+
r.src = src;
|
|
68
|
+
setDefault(setDefault(rrc, elr, {}), r.t, []).push(r);
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
71
|
}
|
|
72
|
+
this._reverseRelationshipCache[arcrole] = rrc;
|
|
69
73
|
}
|
|
70
|
-
this._reverseRelationshipCache[arcrole]
|
|
74
|
+
return this._reverseRelationshipCache[arcrole];
|
|
71
75
|
}
|
|
72
|
-
return this._reverseRelationshipCache[arcrole];
|
|
73
|
-
}
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
getParentRelationships(conceptName, arcrole) {
|
|
78
|
+
const rels = {}
|
|
79
|
+
for (const [elr, relSet] of Object.entries(this._reverseRelationships(arcrole))) {
|
|
80
|
+
if (conceptName in relSet) {
|
|
81
|
+
rels[elr] = relSet[conceptName];
|
|
82
|
+
}
|
|
80
83
|
}
|
|
84
|
+
return rels;
|
|
81
85
|
}
|
|
82
|
-
return rels;
|
|
83
|
-
}
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
87
|
+
getParentRelationshipsInGroup(conceptName, arcrole, elr) {
|
|
88
|
+
const relSet = this._reverseRelationships(arcrole)[elr] || {};
|
|
89
|
+
return relSet[conceptName] || [];
|
|
90
|
+
}
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
dimensionDefault(dimensionName) {
|
|
93
|
+
// ELR is irrelevant for dimension-default relationships, so check all of
|
|
94
|
+
// them, and return the first (illegal for there to be more than one
|
|
95
|
+
for (const rel of Object.values(this._reportData.rels["d-d"] || {})) {
|
|
96
|
+
if (dimensionName in rel) {
|
|
97
|
+
return rel[dimensionName][0].t;
|
|
98
|
+
}
|
|
96
99
|
}
|
|
100
|
+
return undefined;
|
|
97
101
|
}
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
103
|
+
relationshipGroups(arcrole) {
|
|
104
|
+
return Object.keys(this._reportData.rels[arcrole] || {});
|
|
105
|
+
}
|
|
104
106
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
relationshipGroupRoots(arcrole, elr) {
|
|
108
|
+
const roots = [];
|
|
109
|
+
for (const conceptName in this._reportData.rels[arcrole][elr]) {
|
|
110
|
+
if (!(elr in this.getParentRelationships(conceptName, arcrole))) {
|
|
111
|
+
roots.push(conceptName);
|
|
112
|
+
}
|
|
110
113
|
}
|
|
114
|
+
return roots;
|
|
111
115
|
}
|
|
112
|
-
return roots;
|
|
113
|
-
}
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
$.each(all, function (i, ff) {
|
|
123
|
-
if (ff.isAligned(f, coveredAspects)) {
|
|
124
|
-
aligned.push(ff);
|
|
117
|
+
getAlignedFacts(f, coveredAspects) {
|
|
118
|
+
// XXX should filter to current report facts?
|
|
119
|
+
const all = this.reportSet.facts();
|
|
120
|
+
const aligned = [];
|
|
121
|
+
if (!coveredAspects) {
|
|
122
|
+
coveredAspects = {};
|
|
125
123
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
XBRLReport.prototype.deduplicate = function (facts) {
|
|
131
|
-
const ff = [];
|
|
132
|
-
$.each(facts, function (i, f) {
|
|
133
|
-
var dupe = false;
|
|
134
|
-
$.each(ff, function (j, of) {
|
|
135
|
-
if (of.isAligned(f,{})) {
|
|
136
|
-
dupe = true;
|
|
124
|
+
for (const ff of all) {
|
|
125
|
+
if (ff.isAligned(f, coveredAspects)) {
|
|
126
|
+
aligned.push(ff);
|
|
137
127
|
}
|
|
138
|
-
});
|
|
139
|
-
if (!dupe){
|
|
140
|
-
ff.push(f);
|
|
141
128
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
XBRLReport.prototype.getConcept = function(name) {
|
|
148
|
-
return new Concept(this, name);
|
|
149
|
-
}
|
|
129
|
+
return aligned;
|
|
130
|
+
}
|
|
150
131
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (label !== undefined && label !== null) {
|
|
164
|
-
return label;
|
|
132
|
+
deduplicate(facts) {
|
|
133
|
+
const ff = [];
|
|
134
|
+
for (const f of facts) {
|
|
135
|
+
let dupe = false;
|
|
136
|
+
for (const other of ff) {
|
|
137
|
+
if (other.isAligned(f,{})) {
|
|
138
|
+
dupe = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!dupe) {
|
|
142
|
+
ff.push(f);
|
|
143
|
+
}
|
|
165
144
|
}
|
|
145
|
+
return ff;
|
|
166
146
|
}
|
|
167
|
-
return this.reportSet.roleMap()[rolePrefix];
|
|
168
|
-
}
|
|
169
147
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return {}
|
|
148
|
+
getConcept(name) {
|
|
149
|
+
return new Concept(this, name);
|
|
173
150
|
}
|
|
174
|
-
return this._reportData.localDocs;
|
|
175
|
-
}
|
|
176
151
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
152
|
+
getRoleLabel(rolePrefix) {
|
|
153
|
+
/* This is currently hard-coded to "en" as the generator does not yet
|
|
154
|
+
* support generic labels, and instead provides the (non-localisable) role
|
|
155
|
+
* definition as a single "en" label.
|
|
156
|
+
*
|
|
157
|
+
* Returns the ELR URI if there is no label
|
|
158
|
+
*/
|
|
159
|
+
const labels = this._reportData.roleDefs[rolePrefix];
|
|
160
|
+
if (labels !== undefined) {
|
|
161
|
+
const label = labels["en"];
|
|
162
|
+
// Earlier versions of the generator added a "null" label if no labels
|
|
163
|
+
// were available.
|
|
164
|
+
if (label !== undefined && label !== null) {
|
|
165
|
+
return label;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return this.reportSet.roleMap()[rolePrefix];
|
|
185
169
|
}
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
|
|
171
|
+
localDocuments() {
|
|
172
|
+
if (this._reportData.localDocs === undefined) {
|
|
173
|
+
return {}
|
|
174
|
+
}
|
|
175
|
+
return this._reportData.localDocs;
|
|
188
176
|
}
|
|
189
|
-
return label;
|
|
190
|
-
}
|
|
191
177
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
178
|
+
qname(v) {
|
|
179
|
+
return this.reportSet.qname(v);
|
|
180
|
+
}
|
|
195
181
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
182
|
+
getScaleLabel(scale, isMonetaryValue, currency=null) {
|
|
183
|
+
let label = i18next.t(`scale.${scale}`, {defaultValue:"noName"});
|
|
184
|
+
if (isMonetaryValue && scale === -2) {
|
|
185
|
+
label = i18next.t(`currencies:cents${currency}`, {defaultValue: label});
|
|
186
|
+
}
|
|
187
|
+
if (label === "noName") {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return label;
|
|
203
191
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
return
|
|
192
|
+
|
|
193
|
+
concepts() {
|
|
194
|
+
return this._reportData.concepts;
|
|
207
195
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
196
|
+
|
|
197
|
+
getLabel(c, rolePrefix, showPrefix) {
|
|
198
|
+
rolePrefix = rolePrefix || 'std';
|
|
199
|
+
const lang = this.reportSet.viewerOptions.language;
|
|
200
|
+
const concept = this._reportData.concepts[c];
|
|
201
|
+
if (concept === undefined) {
|
|
202
|
+
console.log("Attempt to get label for undefined concept: " + c);
|
|
203
|
+
return "<no label>";
|
|
216
204
|
}
|
|
217
|
-
|
|
205
|
+
const labels = concept.labels[rolePrefix]
|
|
206
|
+
if (labels === undefined || Object.keys(labels).length == 0) {
|
|
218
207
|
return undefined;
|
|
219
208
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
else {
|
|
210
|
+
let label;
|
|
211
|
+
if (lang && labels[lang]) {
|
|
212
|
+
label = labels[lang];
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Fall back on English, then any label deterministically.
|
|
216
|
+
label = labels["en"] || labels["en-us"] || labels[Object.keys(labels).sort()[0]];
|
|
217
|
+
}
|
|
218
|
+
if (label === undefined) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
let s = '';
|
|
222
|
+
if (showPrefix && this.reportSet.viewerOptions.showPrefixes) {
|
|
223
|
+
s = "(" + this.qname(c).prefix + ") ";
|
|
224
|
+
}
|
|
225
|
+
s += label;
|
|
226
|
+
return s;
|
|
223
227
|
}
|
|
224
|
-
s += label;
|
|
225
|
-
return s;
|
|
226
228
|
}
|
|
227
|
-
}
|
|
228
229
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
getLabelOrName(c, rolePrefix, showPrefix) {
|
|
231
|
+
const label = this.getLabel(c, rolePrefix, showPrefix);
|
|
232
|
+
if (label === undefined) {
|
|
233
|
+
return c;
|
|
234
|
+
}
|
|
235
|
+
return label;
|
|
233
236
|
}
|
|
234
|
-
return label;
|
|
235
|
-
}
|
|
236
237
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
238
|
+
isCalculationContributor(c) {
|
|
239
|
+
if (this._calculationContributors === undefined) {
|
|
240
|
+
if (this._reportData.rels?.calc) {
|
|
241
|
+
this._calculationContributors = new Set(Object.values(this._reportData.rels.calc).flatMap(calculations => {
|
|
242
|
+
return Object.values(calculations).flatMap(contributors => {
|
|
243
|
+
return contributors.map(c => c.t);
|
|
244
|
+
});
|
|
245
|
+
}));
|
|
246
|
+
} else {
|
|
247
|
+
this._calculationContributors = new Set();
|
|
248
|
+
}
|
|
247
249
|
}
|
|
250
|
+
return this._calculationContributors.has(c);
|
|
248
251
|
}
|
|
249
|
-
return this._calculationContributors.has(c);
|
|
250
|
-
}
|
|
251
252
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
253
|
+
isCalculationSummation(c) {
|
|
254
|
+
if (this._calculationSummations === undefined) {
|
|
255
|
+
if (this._reportData.rels?.calc) {
|
|
256
|
+
this._calculationSummations = new Set(Object.values(this._reportData.rels.calc).flatMap(calculations => {
|
|
257
|
+
return Object.keys(calculations);
|
|
258
|
+
}));
|
|
259
|
+
} else {
|
|
260
|
+
this._calculationSummations = new Set();
|
|
261
|
+
}
|
|
260
262
|
}
|
|
263
|
+
return this._calculationSummations.has(c);
|
|
261
264
|
}
|
|
262
|
-
return this._calculationSummations.has(c);
|
|
263
265
|
}
|
|
@@ -101,12 +101,11 @@ export class ReportSet {
|
|
|
101
101
|
|
|
102
102
|
namespaceGroups() {
|
|
103
103
|
const counts = {};
|
|
104
|
-
|
|
105
|
-
counts[f.conceptQName().prefix] = counts[f.conceptQName().prefix] || 0;
|
|
106
|
-
|
|
107
|
-
});
|
|
104
|
+
for (const f of this.facts()) {
|
|
105
|
+
counts[f.conceptQName().prefix] = (counts[f.conceptQName().prefix] || 0) + 1;
|
|
106
|
+
}
|
|
108
107
|
const prefixes = Object.keys(counts);
|
|
109
|
-
prefixes.sort(
|
|
108
|
+
prefixes.sort((a, b) => counts[b] - counts[a]);
|
|
110
109
|
return prefixes;
|
|
111
110
|
}
|
|
112
111
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ixbrl-viewer
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.6
|
|
4
4
|
Summary: The Arelle iXBRL Viewer allows iXBRL reports to be viewed interactively in a web browser.
|
|
5
5
|
Author-email: "arelle.org" <support@arelle.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -60,20 +60,23 @@ The viewer project consists of two components:
|
|
|
60
60
|
In order to view an iXBRL report in the viewer, it must first be prepared using
|
|
61
61
|
the Arelle plugin. The preparation process updates the iXBRL file to include:
|
|
62
62
|
|
|
63
|
-
1. A link to the
|
|
63
|
+
1. A link to the JavaScript viewer
|
|
64
64
|
2. A block of JSON data that contains the results of processing the XBRL data and associated taxonomy
|
|
65
65
|
|
|
66
|
-
Once prepared, the resulting file provides an entirely standalone viewer
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
Once prepared, the resulting file provides an entirely standalone viewer, and
|
|
67
|
+
does not require access to the taxonomy, or to any online services. The only
|
|
68
|
+
dependency is on the JavaScript viewer application, which is a single file
|
|
69
|
+
which can be accessed directly online, downloaded or built locally.
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
It is also possible to place the link to the viewer, and the block of JSON data
|
|
72
|
+
in a separate file. See Stub Viewer Mode below.
|
|
73
|
+
|
|
74
|
+
The JavaScript viewer application is a single JavaScript file called ixbrlviewer.js. It
|
|
75
|
+
contains all of the JavaScript that runs the viewer functionality.
|
|
73
76
|
|
|
74
77
|
## Installation
|
|
75
78
|
|
|
76
|
-
The
|
|
79
|
+
The Python portion of this repo is developed using Python 3.11.
|
|
77
80
|
|
|
78
81
|
1. Clone the [iXBRL Viewer git repository][ixbrlviewer-github].
|
|
79
82
|
2. Download and install [Arelle][arelle-download]
|
|
@@ -113,11 +116,15 @@ the ixbrl-viewer.
|
|
|
113
116
|
|
|
114
117
|
## JavaScript Versioning
|
|
115
118
|
|
|
116
|
-
The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a
|
|
117
|
-
by the JavaScript. The metadata produced
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a
|
|
120
|
+
specific format read by the JavaScript. The metadata produced will work with a
|
|
121
|
+
viewer application that has the same major version, and the same or later minor
|
|
122
|
+
version as the plugin used to create it.
|
|
123
|
+
|
|
124
|
+
This means that once an XBRL report has been prepared by the plugin, the
|
|
125
|
+
associated JavaScript viewer application can be upgraded within the same major
|
|
126
|
+
version. Any features introduced in newer versions of the viewer that rely on
|
|
127
|
+
additional metadata will degrade gracefully if that metadata is not present.
|
|
121
128
|
|
|
122
129
|
## Producing an ixbrl-viewer via the Arelle GUI
|
|
123
130
|
|
|
@@ -206,6 +213,9 @@ Notes:
|
|
|
206
213
|
2. A relative url to the downloaded ixviewer.js from github
|
|
207
214
|
3. A relative url to the locally built ixviewer.js
|
|
208
215
|
|
|
216
|
+
* Due to browser security restrictions, the resulting viewer cannot be loaded
|
|
217
|
+
directly from `file:` URLs; it must be served by a web server.
|
|
218
|
+
|
|
209
219
|
### Using build-viewer.py
|
|
210
220
|
|
|
211
221
|
As an alternative to the standard Arelle command line, the
|
|
@@ -229,7 +239,29 @@ e.g.
|
|
|
229
239
|
```shell
|
|
230
240
|
PYTHONPATH=/path/to/Arelle:/path/to/ixbrl-viewer ./samples/build-viewer.py --out out-dir --package-dir /my/packages/ ixds-dir
|
|
231
241
|
```
|
|
242
|
+
|
|
243
|
+
## Stub viewer mode
|
|
244
|
+
|
|
245
|
+
By default, the link to the JavaScript viewer and the JSON data block are added
|
|
246
|
+
to the iXBRL report file (or to the first file, in the case of a document set).
|
|
247
|
+
|
|
248
|
+
Stub viewer mode is an optional generation mode that creates an additional,
|
|
249
|
+
minimal HTML file containing the JSON data block, and the link to the
|
|
250
|
+
JavaScript viewer. This mode has two advantages over the default approach of
|
|
251
|
+
embedding the JSON data and JavaScript link in the iXBRL report:
|
|
252
|
+
|
|
253
|
+
1. Provided that all facts and footnotes in the iXBRL report already have ID
|
|
254
|
+
attributes, no modification of the iXBRL report is required.
|
|
255
|
+
2. The iXBRL viewer loading mask will be displayed much more quickly. This is
|
|
256
|
+
helpful for very large iXBRL reports which can otherwise result in a long
|
|
257
|
+
delay before there is any sign of the iXBRL Viewer loading.
|
|
258
|
+
|
|
259
|
+
The downside of this mode is that due to browser security restrictions, the
|
|
260
|
+
viewer cannot be loaded directly from files (using `file:` URLs); they must be
|
|
261
|
+
served by a web server.
|
|
262
|
+
|
|
232
263
|
# Optional Features
|
|
264
|
+
|
|
233
265
|
Some features are disabled by default but can be enabled at generation time or with query parameters.
|
|
234
266
|
|
|
235
267
|
To enable features:
|
|
@@ -261,6 +293,12 @@ This mode replaces the namespace-based highlighting with optional highlighting b
|
|
|
261
293
|
|---------------------------|----------------|
|
|
262
294
|
| `--viewer-feature-review` | `?review=true` |
|
|
263
295
|
|
|
296
|
+
# Disable viewer loading
|
|
297
|
+
|
|
298
|
+
Loading of the viewer can be disabled by specifying `?disable-viewer` as a
|
|
299
|
+
query parameter. This will leave the iXBRL document loaded in the browser, but
|
|
300
|
+
without any viewer functionality. In the case of an iXBRL document set, or
|
|
301
|
+
multi-document viewer, the first document will be shown.
|
|
264
302
|
|
|
265
303
|
## Running tests
|
|
266
304
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
iXBRLViewerPlugin/__init__.py,sha256=uicpgRNpgHnYdyIVIhLpVqO3kC3pv5BHusutY5lSHKM,13921
|
|
2
|
-
iXBRLViewerPlugin/_version.py,sha256=
|
|
2
|
+
iXBRLViewerPlugin/_version.py,sha256=rcHU37_iyVNYVuSTTj5Shc-mUDPpQw2cyeznRUHdnOc,160
|
|
3
3
|
iXBRLViewerPlugin/constants.py,sha256=kJ-kjt6rGhwBvk8HNbIiXt31b5qe6Lb6qPOXQF6rH_8,833
|
|
4
4
|
iXBRLViewerPlugin/featureConfig.py,sha256=tOViPYmN32i2uIf_T9HGgbkkv41VoTpTjqhn4w9rTgw,194
|
|
5
|
-
iXBRLViewerPlugin/iXBRLViewer.py,sha256=
|
|
5
|
+
iXBRLViewerPlugin/iXBRLViewer.py,sha256=aHcBcnGBu2X4dhdJmALBehJ9jUi29N5Ne_cuHIMmImk,28138
|
|
6
6
|
iXBRLViewerPlugin/stubviewer.html,sha256=hc5BeIR7y3ojGRux_Hy5oqEAHdlQ34kk3lL5eH-B4AU,158
|
|
7
7
|
iXBRLViewerPlugin/ui.py,sha256=G2TsBoBLfpmyYQxB01d_7r8IsMEnemayU__fKvSQeLE,9713
|
|
8
8
|
iXBRLViewerPlugin/xhtmlserialize.py,sha256=XG6HRR6qDclSwbrpywFC0v8Ktb4-YZj-9IV_gqroCOY,6766
|
|
@@ -11,7 +11,7 @@ iXBRLViewerPlugin/viewer/version.js,sha256=7b5si8UmaS7QqALQIP-wJ0I8onKFox8VyaAiU
|
|
|
11
11
|
iXBRLViewerPlugin/viewer/webpack.common.js,sha256=AsiOVAW2XbmSNjv6Kl6LC4VUM2rA9UyQ8vwhz_1jb1Y,1320
|
|
12
12
|
iXBRLViewerPlugin/viewer/webpack.dev.js,sha256=R9AwY_TBrg9otvXpDxT1UsGg5eMqi4aXW7C7EIsHzZk,551
|
|
13
13
|
iXBRLViewerPlugin/viewer/webpack.prod.js,sha256=vfLowWC1EOty0zbq9P-usGaJ3w-JoERpJrYaE9MfoSE,499
|
|
14
|
-
iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js,sha256=
|
|
14
|
+
iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js,sha256=tbZncQHSEFAXd1nasN4f6j25eAD2rlZVMosatDMIMaY,860669
|
|
15
15
|
iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt,sha256=eA5xbvB65RVR5QmweqeHe4sYtW3dzEmgLhUDFOGr9m4,1697
|
|
16
16
|
iXBRLViewerPlugin/viewer/src/html/fact-details.html,sha256=P9BJw1OK4nIYfoT4KPwW1WP94ZeD7v1nisvSKMeSnU8,1495
|
|
17
17
|
iXBRLViewerPlugin/viewer/src/html/footnote-details.html,sha256=9I7y0KM7xsPzbiZheuHkm1k4nHNXD8S9qxvD_Y0I1Us,278
|
|
@@ -74,7 +74,7 @@ iXBRLViewerPlugin/viewer/src/js/index.js,sha256=SdxunWx8kNw0-vwwnr58-ac1-eQIE1__
|
|
|
74
74
|
iXBRLViewerPlugin/viewer/src/js/inspector.js,sha256=vSHr-pVjtviT72fzwAeJm7hbQw8iTQgQ1AzHje0odm8,45017
|
|
75
75
|
iXBRLViewerPlugin/viewer/src/js/inspector.test.js,sha256=kKoYhBLjnFn3eJ8q1de3irK6tDgUVxcDKugIIURgp60,7814
|
|
76
76
|
iXBRLViewerPlugin/viewer/src/js/interact.min.js,sha256=Yk0ZkCU3IZ0heGijAgUiNVkZ1Djq-MjvbS32DBSrdIs,85048
|
|
77
|
-
iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js,sha256=
|
|
77
|
+
iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js,sha256=3bQpJ_fUJzSQNjFizz6_7jJ5bKctwQq8Bb1sJB-HE2Y,13211
|
|
78
78
|
iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js,sha256=ey61xTRZkP0Kf3W8DVQtZE-PeXwK4OOx51iLySMSBsY,2712
|
|
79
79
|
iXBRLViewerPlugin/viewer/src/js/ixnode.js,sha256=C_9exfjf6BnARnHYeNY3RW0-RhxhCjsnn9woFLCjQPk,1575
|
|
80
80
|
iXBRLViewerPlugin/viewer/src/js/menu.js,sha256=uUpL-zmgqGZZJPQwdFBYoPxSixyCRNFZBoAjyeMbPsA,3198
|
|
@@ -88,9 +88,9 @@ iXBRLViewerPlugin/viewer/src/js/outline.test.js,sha256=GJtAB_1Yj-sxoiNQJOZUjSuVJ
|
|
|
88
88
|
iXBRLViewerPlugin/viewer/src/js/period.js,sha256=D9zXSOr19trWCmHizgCe5DQ612HB6IlAWmI5Rh4I8ZM,2267
|
|
89
89
|
iXBRLViewerPlugin/viewer/src/js/period.test.js,sha256=nMamproI2VukUnO0wm3SKQA_rnjwNkwkzyn4uhke0kc,5417
|
|
90
90
|
iXBRLViewerPlugin/viewer/src/js/qname.js,sha256=6MqMBbgziuPPNHKS3UUGyYIgHWygaAIf0mcpK95hwT8,282
|
|
91
|
-
iXBRLViewerPlugin/viewer/src/js/report.js,sha256=
|
|
91
|
+
iXBRLViewerPlugin/viewer/src/js/report.js,sha256=6A9it4-1mIIGBgwDdVLRG0BUyS8OljodHuXhBqmchF8,8567
|
|
92
92
|
iXBRLViewerPlugin/viewer/src/js/report.test.js,sha256=tedkrEUoUrFv9_zfU3ekJT-HQNEOVH8PftxgJof0saQ,5041
|
|
93
|
-
iXBRLViewerPlugin/viewer/src/js/reportset.js,sha256=
|
|
93
|
+
iXBRLViewerPlugin/viewer/src/js/reportset.js,sha256=CyxZvUrNxFY3lXzHCioWcIbEfUe2IxnFF-SHiM77MDM,7824
|
|
94
94
|
iXBRLViewerPlugin/viewer/src/js/reportset.test.js,sha256=ZSXsojqB_aWpNq5XUoMlfKG5KsUtZTb7UtaGX1_-Hrs,12573
|
|
95
95
|
iXBRLViewerPlugin/viewer/src/js/search.js,sha256=M7rZ7IVqzUbsLusgbu2ohhLnaRRigAVYJ2Bb8jmjKPQ,5490
|
|
96
96
|
iXBRLViewerPlugin/viewer/src/js/search.test.js,sha256=YGUrgxKjNC0CoY9CJm5FbpBi5tepqMcGriIv7fw19aQ,20925
|
|
@@ -145,13 +145,13 @@ tests/puppeteer/tests/search.test.js,sha256=N6EDeok_PQct4C8fIFfUeZi-9Wdnc1c1D3Yr
|
|
|
145
145
|
tests/puppeteer/tools/generate.sh,sha256=A-SUACwIh_OLlV6nPh2HH21grYhPLIqwm0PpygRXTPQ,500
|
|
146
146
|
tests/unit_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
147
147
|
tests/unit_tests/iXBRLViewerPlugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
148
|
-
tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py,sha256=
|
|
148
|
+
tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py,sha256=Dm11pBwEqDmcCc4mkxNciFEEM_DbgtzQ2QYNP1y_ImE,1307
|
|
149
149
|
tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py,sha256=arjJXU5jWkh_JmEuZIGXVJ0Ory6_uGUvPcQLM9o6TZA,31583
|
|
150
150
|
tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py,sha256=BQNN1sC899sZzV1RN3wuFj9uwi8ioaRJcONxTiTdfZM,12570
|
|
151
|
-
ixbrl_viewer-1.4.
|
|
152
|
-
ixbrl_viewer-1.4.
|
|
153
|
-
ixbrl_viewer-1.4.
|
|
154
|
-
ixbrl_viewer-1.4.
|
|
155
|
-
ixbrl_viewer-1.4.
|
|
156
|
-
ixbrl_viewer-1.4.
|
|
157
|
-
ixbrl_viewer-1.4.
|
|
151
|
+
ixbrl_viewer-1.4.6.dist-info/LICENSE,sha256=TZJhu77S_2-WQcPAkuIAlQiuuiNqVcuHBjd7z3Y5S08,16645
|
|
152
|
+
ixbrl_viewer-1.4.6.dist-info/METADATA,sha256=Fq1s4E-n7YRO497GKFztwi_V23VAJInsyRr4tzr7HAo,14496
|
|
153
|
+
ixbrl_viewer-1.4.6.dist-info/NOTICE,sha256=-SHDY0OY7s4gm4Rdk5AB3nbnUsrdHEHPdJuGFR_vuM4,566
|
|
154
|
+
ixbrl_viewer-1.4.6.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
155
|
+
ixbrl_viewer-1.4.6.dist-info/entry_points.txt,sha256=2XUzP20WGwxdvnugdBybUBwAB3xf_zvrOR5W_smFz_4,65
|
|
156
|
+
ixbrl_viewer-1.4.6.dist-info/top_level.txt,sha256=h8MkrMhC_t2-KbfS1oxJVnFAbn5NZJH8END_BL40mv8,24
|
|
157
|
+
ixbrl_viewer-1.4.6.dist-info/RECORD,,
|