ixbrl-viewer 1.4.21__py3-none-any.whl → 1.4.49__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/__init__.py +77 -49
- iXBRLViewerPlugin/_version.py +2 -2
- iXBRLViewerPlugin/constants.py +86 -1
- iXBRLViewerPlugin/featureConfig.py +4 -1
- iXBRLViewerPlugin/iXBRLViewer.py +202 -131
- iXBRLViewerPlugin/plugin.py +7 -0
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +9 -2
- iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
- iXBRLViewerPlugin/viewer/src/data/utr.json +1 -0
- iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
- iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
- iXBRLViewerPlugin/viewer/src/html/footnote-details.html +1 -1
- iXBRLViewerPlugin/viewer/src/html/inspector.html +324 -211
- iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +56 -24
- iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +70 -37
- iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
- iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
- iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
- iXBRLViewerPlugin/viewer/src/js/accordian.js +3 -2
- iXBRLViewerPlugin/viewer/src/js/aspect.js +18 -10
- iXBRLViewerPlugin/viewer/src/js/aspect.test.js +2 -2
- iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
- iXBRLViewerPlugin/viewer/src/js/calculation.js +45 -34
- iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +4 -7
- iXBRLViewerPlugin/viewer/src/js/chart.js +23 -21
- iXBRLViewerPlugin/viewer/src/js/concept.js +27 -2
- iXBRLViewerPlugin/viewer/src/js/concept.test.js +23 -2
- iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
- iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
- iXBRLViewerPlugin/viewer/src/js/dialog.js +6 -4
- iXBRLViewerPlugin/viewer/src/js/fact.js +40 -7
- iXBRLViewerPlugin/viewer/src/js/fact.test.js +3 -0
- iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
- iXBRLViewerPlugin/viewer/src/js/inspector.js +560 -160
- iXBRLViewerPlugin/viewer/src/js/inspector.test.js +1 -2
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +129 -31
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +133 -20
- iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
- iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
- iXBRLViewerPlugin/viewer/src/js/number-matcher.js +2 -2
- iXBRLViewerPlugin/viewer/src/js/outline.js +2 -4
- iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
- iXBRLViewerPlugin/viewer/src/js/report.js +68 -13
- iXBRLViewerPlugin/viewer/src/js/report.test.js +77 -6
- iXBRLViewerPlugin/viewer/src/js/reportset.js +33 -3
- iXBRLViewerPlugin/viewer/src/js/reportset.test.js +32 -6
- iXBRLViewerPlugin/viewer/src/js/search.js +61 -35
- iXBRLViewerPlugin/viewer/src/js/search.test.js +8 -5
- iXBRLViewerPlugin/viewer/src/js/summary.js +22 -0
- iXBRLViewerPlugin/viewer/src/js/summary.test.js +50 -13
- iXBRLViewerPlugin/viewer/src/js/tableExport.js +3 -3
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
- iXBRLViewerPlugin/viewer/src/js/theme.js +49 -0
- iXBRLViewerPlugin/viewer/src/js/unit.js +73 -2
- iXBRLViewerPlugin/viewer/src/js/unit.test.js +14 -3
- iXBRLViewerPlugin/viewer/src/js/util.js +21 -18
- iXBRLViewerPlugin/viewer/src/js/util.test.js +1 -0
- iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
- iXBRLViewerPlugin/viewer/src/js/viewer.js +40 -29
- iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
- iXBRLViewerPlugin/viewer/src/less/accordian.less +8 -4
- iXBRLViewerPlugin/viewer/src/less/block-list.less +12 -6
- iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +2 -2
- iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
- iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
- iXBRLViewerPlugin/viewer/src/less/colours.less +28 -21
- iXBRLViewerPlugin/viewer/src/less/common.less +1 -1
- iXBRLViewerPlugin/viewer/src/less/components.less +3 -3
- iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
- iXBRLViewerPlugin/viewer/src/less/dialog.less +13 -10
- iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
- iXBRLViewerPlugin/viewer/src/less/inspector.less +556 -300
- iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
- iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
- iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
- iXBRLViewerPlugin/viewer/src/less/tabs.less +5 -5
- iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
- iXBRLViewerPlugin/viewer/src/less/validation-report.less +1 -1
- iXBRLViewerPlugin/viewer/src/less/viewer.less +30 -18
- iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/METADATA +41 -14
- ixbrl_viewer-1.4.49.dist-info/RECORD +197 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/WHEEL +1 -1
- tests/puppeteer/framework/page_objects/doc_frame.js +3 -3
- tests/puppeteer/framework/page_objects/fact_details_panel.js +28 -0
- tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
- tests/puppeteer/tests/fact_properties.test.js +10 -4
- tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +117 -51
- iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
- ixbrl_viewer-1.4.21.dist-info/RECORD +0 -166
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/LICENSE +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/NOTICE +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.49.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
|
-
import { Fact } from "./fact.js"
|
|
4
|
-
import { Footnote } from "./footnote.js"
|
|
5
|
-
import { QName } from "./qname.js"
|
|
6
3
|
import { Concept } from "./concept.js";
|
|
7
|
-
import { setDefault
|
|
8
|
-
import $ from 'jquery'
|
|
4
|
+
import { setDefault } from "./util.js";
|
|
9
5
|
import i18next from "i18next";
|
|
10
6
|
|
|
11
7
|
// Class to represent the XBRL data from a single target document in a single
|
|
@@ -169,7 +165,39 @@ export class XBRLReport {
|
|
|
169
165
|
return label;
|
|
170
166
|
}
|
|
171
167
|
}
|
|
172
|
-
return
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
getRoleLabelOrURI(rolePrefix) {
|
|
172
|
+
return this.getRoleLabel(rolePrefix) ?? this.reportSet.roleMap()[rolePrefix];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
getLabelRoleLabel(rolePrefix) {
|
|
176
|
+
const roleURI = this.reportSet.roleMap()[rolePrefix];
|
|
177
|
+
if (roleURI === undefined) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Built-in label roles don't have a definition in the taxonomy. Do an
|
|
182
|
+
// i18n look-up on the last part of the URI. For "en" the camel-case
|
|
183
|
+
// splitter will do what we want for everything except standard label
|
|
184
|
+
// and documentation label
|
|
185
|
+
const suffix = roleURI.split("/").pop();
|
|
186
|
+
if (roleURI.startsWith("http://www.xbrl.org/2003/role/") && i18next.exists(`labelRoles:${suffix}`)) {
|
|
187
|
+
return i18next.t(`labelRoles:${suffix}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Attempt to get a label from the role definition
|
|
191
|
+
const label = this.getRoleLabel(rolePrefix);
|
|
192
|
+
if (label !== undefined) {
|
|
193
|
+
return label;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Fall back on de-camel-casing the last part of the URI
|
|
197
|
+
return suffix
|
|
198
|
+
.replaceAll(/([A-Z][a-z]+)/g, ' $1')
|
|
199
|
+
.trim()
|
|
200
|
+
.replace(/^./, s => s.toUpperCase());
|
|
173
201
|
}
|
|
174
202
|
|
|
175
203
|
localDocuments() {
|
|
@@ -184,7 +212,7 @@ export class XBRLReport {
|
|
|
184
212
|
}
|
|
185
213
|
|
|
186
214
|
getScaleLabel(scale, unit) {
|
|
187
|
-
let label = i18next.t(`scale
|
|
215
|
+
let label = i18next.t(`scale:${scale}`, {defaultValue:"noName"});
|
|
188
216
|
if (unit && unit.isMonetary() && scale === -2) {
|
|
189
217
|
let measure = unit.value() ?? '';
|
|
190
218
|
if (measure) {
|
|
@@ -203,35 +231,47 @@ export class XBRLReport {
|
|
|
203
231
|
}
|
|
204
232
|
|
|
205
233
|
getLabel(c, rolePrefix, showPrefix) {
|
|
234
|
+
return this.getLabelAndLang(c, rolePrefix, showPrefix).label;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
getLabelAndLang(c, rolePrefix, showPrefix) {
|
|
206
238
|
rolePrefix = rolePrefix || 'std';
|
|
207
239
|
const lang = this.reportSet.viewerOptions.language;
|
|
208
240
|
const concept = this._reportData.concepts[c];
|
|
209
241
|
if (concept === undefined) {
|
|
210
242
|
console.log("Attempt to get label for undefined concept: " + c);
|
|
211
|
-
return "<no label>";
|
|
243
|
+
return { label: "<no label>" };
|
|
212
244
|
}
|
|
213
245
|
const labels = concept.labels[rolePrefix]
|
|
214
246
|
if (labels === undefined || Object.keys(labels).length == 0) {
|
|
215
|
-
return undefined;
|
|
247
|
+
return { label: undefined };
|
|
216
248
|
}
|
|
217
249
|
else {
|
|
218
250
|
let label;
|
|
251
|
+
let actualLang;
|
|
219
252
|
if (lang && labels[lang]) {
|
|
220
253
|
label = labels[lang];
|
|
254
|
+
actualLang = lang;
|
|
221
255
|
}
|
|
222
256
|
else {
|
|
223
257
|
// Fall back on English, then any label deterministically.
|
|
224
|
-
|
|
258
|
+
for (const l of ["en", "en-us", Object.keys(labels).sort()[0]]) {
|
|
259
|
+
if (labels[l] !== undefined) {
|
|
260
|
+
label = labels[l];
|
|
261
|
+
actualLang = l;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
225
265
|
}
|
|
226
266
|
if (label === undefined) {
|
|
227
|
-
return undefined;
|
|
267
|
+
return {label: undefined};
|
|
228
268
|
}
|
|
229
269
|
let s = '';
|
|
230
270
|
if (showPrefix && this.reportSet.viewerOptions.showPrefixes) {
|
|
231
|
-
s = "(" + this.qname(c).prefix + ") ";
|
|
271
|
+
s = "(" + this.reportSet.taxonomyNamer.fromQName(this.qname(c)).prefix + ") ";
|
|
232
272
|
}
|
|
233
273
|
s += label;
|
|
234
|
-
return s;
|
|
274
|
+
return { label: s, lang: actualLang };
|
|
235
275
|
}
|
|
236
276
|
}
|
|
237
277
|
|
|
@@ -243,6 +283,14 @@ export class XBRLReport {
|
|
|
243
283
|
return label;
|
|
244
284
|
}
|
|
245
285
|
|
|
286
|
+
getLabelOrNameAndLang(c, rolePrefix, showPrefix) {
|
|
287
|
+
const labelLang = this.getLabelAndLang(c, rolePrefix, showPrefix);
|
|
288
|
+
if (labelLang.label === undefined) {
|
|
289
|
+
return { label: c };
|
|
290
|
+
}
|
|
291
|
+
return labelLang;
|
|
292
|
+
}
|
|
293
|
+
|
|
246
294
|
isCalculationContributor(c) {
|
|
247
295
|
if (this._calculationContributors === undefined) {
|
|
248
296
|
if (this._reportData.rels?.calc) {
|
|
@@ -270,4 +318,11 @@ export class XBRLReport {
|
|
|
270
318
|
}
|
|
271
319
|
return this._calculationSummations.has(c);
|
|
272
320
|
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @return {Array[String]} Software credit text labels provided with this report for display purposes.
|
|
324
|
+
*/
|
|
325
|
+
softwareCredits() {
|
|
326
|
+
return this._reportData.softwareCredits ?? [];
|
|
327
|
+
}
|
|
273
328
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ReportSet } from "./reportset.js";
|
|
4
4
|
import { ViewerOptions } from "./viewerOptions.js";
|
|
5
|
+
import { TestInspector } from "./test-utils.js";
|
|
5
6
|
import { NAMESPACE_ISO4217 } from "./util";
|
|
6
7
|
|
|
7
8
|
var testReportData = {
|
|
@@ -17,7 +18,11 @@ var testReportData = {
|
|
|
17
18
|
"role1": "https://www.example.com/role1",
|
|
18
19
|
"role2": "https://www.example.com/role2",
|
|
19
20
|
"role3": "https://www.example.com/role3",
|
|
20
|
-
"role4": "https://www.example.com/
|
|
21
|
+
"role4": "https://www.example.com/role4MoreWords",
|
|
22
|
+
"std": "http://www.xbrl.org/2003/role/label",
|
|
23
|
+
"doc": "http://www.xbrl.org/2003/role/documentation",
|
|
24
|
+
"verbose": "http://www.xbrl.org/2003/role/verboseLabel",
|
|
25
|
+
"total": "http://www.xbrl.org/2003/role/totalLabel",
|
|
21
26
|
},
|
|
22
27
|
"roleDefs": {
|
|
23
28
|
"role1": { "en": "Role 1 Label" },
|
|
@@ -62,9 +67,15 @@ var testReportData = {
|
|
|
62
67
|
"p": "2018-01-01/2019-01-01",
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
|
-
}
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
"softwareCredits": ["Example credit text A", "Example credit text B"],
|
|
66
73
|
};
|
|
67
74
|
|
|
75
|
+
var insp = new TestInspector();
|
|
76
|
+
beforeAll(() => {
|
|
77
|
+
return insp.i18nInit();
|
|
78
|
+
});
|
|
68
79
|
|
|
69
80
|
describe("Language options", () => {
|
|
70
81
|
const testReportSet = new ReportSet(testReportData);
|
|
@@ -101,23 +112,33 @@ describe("Concept labels", () => {
|
|
|
101
112
|
test("Label fallback", () => {
|
|
102
113
|
vo.language = 'fr';
|
|
103
114
|
expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept trois");
|
|
115
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept trois");
|
|
116
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("fr");
|
|
104
117
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept trois");
|
|
105
118
|
vo.language = 'es';
|
|
106
119
|
expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept cuatro");
|
|
120
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept cuatro");
|
|
121
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("es");
|
|
107
122
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept cuatro");
|
|
108
123
|
// No English label, so fall back on German (de is first alphabetically)
|
|
109
124
|
vo.language = 'en';
|
|
110
125
|
expect(testReport.getLabel('eg:Concept3', 'std')).toBe("Concept vier");
|
|
126
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').label).toBe("Concept vier");
|
|
127
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std').lang).toBe("de");
|
|
111
128
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept vier");
|
|
112
129
|
|
|
113
130
|
// Attempt to get an undefined label type
|
|
114
131
|
expect(testReport.getLabel('eg:Concept3', 'doc')).toBeUndefined();
|
|
132
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'doc').label).toBeUndefined();
|
|
133
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'doc').lang).toBeUndefined();
|
|
115
134
|
expect(testReport.getLabelOrName('eg:Concept3', 'doc')).toBe('eg:Concept3');
|
|
116
135
|
});
|
|
117
136
|
|
|
118
137
|
test("With prefix", () => {
|
|
119
138
|
vo.language = 'fr';
|
|
120
139
|
expect(testReport.getLabel('eg:Concept3', 'std', true)).toBe("(eg) Concept trois");
|
|
140
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std', true).label).toBe("(eg) Concept trois");
|
|
141
|
+
expect(testReport.getLabelAndLang('eg:Concept3', 'std', true).lang).toBe("fr");
|
|
121
142
|
expect(testReport.getLabelOrName('eg:Concept3', 'std', true)).toBe("(eg) Concept trois");
|
|
122
143
|
|
|
123
144
|
expect(testReport.getLabel('eg:Concept3', 'doc', true)).toBeUndefined();
|
|
@@ -131,16 +152,66 @@ describe("ELR labels", () => {
|
|
|
131
152
|
testReportSet._initialize();
|
|
132
153
|
const testReport = testReportSet.reports[0];
|
|
133
154
|
test("Present", () => {
|
|
134
|
-
expect(testReport.
|
|
155
|
+
expect(testReport.getRoleLabelOrURI("role1")).toBe("Role 1 Label");
|
|
156
|
+
});
|
|
157
|
+
test("Null", () => {
|
|
158
|
+
expect(testReport.getRoleLabelOrURI("role2")).toBe("https://www.example.com/role2");
|
|
159
|
+
});
|
|
160
|
+
test("No label", () => {
|
|
161
|
+
expect(testReport.getRoleLabelOrURI("role3")).toBe("https://www.example.com/role3");
|
|
162
|
+
});
|
|
163
|
+
test("Not present in roleDef", () => {
|
|
164
|
+
expect(testReport.getRoleLabelOrURI("role4")).toBe("https://www.example.com/role4MoreWords");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("Label role labels", () => {
|
|
169
|
+
const testReportSet = new ReportSet(testReportData);
|
|
170
|
+
testReportSet._initialize();
|
|
171
|
+
const testReport = testReportSet.reports[0];
|
|
172
|
+
test("Built-in (via i18n)", () => {
|
|
173
|
+
expect(testReport.getLabelRoleLabel("std")).toBe("Standard Label");
|
|
174
|
+
});
|
|
175
|
+
test("Built-in (via i18n)", () => {
|
|
176
|
+
expect(testReport.getLabelRoleLabel("doc")).toBe("Documentation Label");
|
|
177
|
+
});
|
|
178
|
+
test("Built-in (via de-camelcase)", () => {
|
|
179
|
+
expect(testReport.getLabelRoleLabel("verbose")).toBe("Verbose Label");
|
|
180
|
+
});
|
|
181
|
+
test("Present", () => {
|
|
182
|
+
expect(testReport.getLabelRoleLabel("role1")).toBe("Role 1 Label");
|
|
135
183
|
});
|
|
136
184
|
test("Null", () => {
|
|
137
|
-
expect(testReport.
|
|
185
|
+
expect(testReport.getLabelRoleLabel("role2")).toBe("Role2");
|
|
138
186
|
});
|
|
139
187
|
test("No label", () => {
|
|
140
|
-
expect(testReport.
|
|
188
|
+
expect(testReport.getLabelRoleLabel("role3")).toBe("Role3");
|
|
141
189
|
});
|
|
142
190
|
test("Not present in roleDef", () => {
|
|
143
|
-
expect(testReport.
|
|
191
|
+
expect(testReport.getLabelRoleLabel("role4")).toBe("Role4 More Words");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("Fetching software credit", () => {
|
|
197
|
+
|
|
198
|
+
test("Successful", () => {
|
|
199
|
+
const testReportSet = new ReportSet(testReportData);
|
|
200
|
+
testReportSet._initialize();
|
|
201
|
+
const report = testReportSet.reports[0];
|
|
202
|
+
|
|
203
|
+
const softwareCredits = report.softwareCredits();
|
|
204
|
+
expect(softwareCredits).toEqual(["Example credit text A", "Example credit text B"]);
|
|
144
205
|
});
|
|
145
206
|
|
|
207
|
+
test("Unset", () => {
|
|
208
|
+
let alternateData = JSON.parse(JSON.stringify(testReportData));
|
|
209
|
+
delete alternateData.softwareCredits;
|
|
210
|
+
const testReportSet = new ReportSet(alternateData);
|
|
211
|
+
testReportSet._initialize();
|
|
212
|
+
const report = testReportSet.reports[0];
|
|
213
|
+
|
|
214
|
+
const softwareCredits = report.softwareCredits();
|
|
215
|
+
expect(softwareCredits).toEqual([]);
|
|
216
|
+
});
|
|
146
217
|
});
|
|
@@ -7,8 +7,7 @@ import { Unit } from "./unit";
|
|
|
7
7
|
import { titleCase, viewerUniqueId } from "./util.js";
|
|
8
8
|
import { QName } from "./qname.js";
|
|
9
9
|
import { ViewerOptions } from './viewerOptions.js';
|
|
10
|
-
import
|
|
11
|
-
|
|
10
|
+
import { TaxonomyNamer } from './taxonomynamer.js';
|
|
12
11
|
|
|
13
12
|
// Class represents the set of XBRL "target" reports shown in the viewer.
|
|
14
13
|
// Each contained report represents the data from a single target document in a
|
|
@@ -19,6 +18,7 @@ export class ReportSet {
|
|
|
19
18
|
this._data = data;
|
|
20
19
|
this._ixNodeMap = {};
|
|
21
20
|
this.viewerOptions = new ViewerOptions()
|
|
21
|
+
this.taxonomyNamer = new TaxonomyNamer(new Map());
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/*
|
|
@@ -99,6 +99,10 @@ export class ReportSet {
|
|
|
99
99
|
return this._data.prefixes;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
preferredPrefix(prefix) {
|
|
103
|
+
return this.taxonomyNamer.getName(prefix, this._data.prefixes[prefix]).prefix;
|
|
104
|
+
}
|
|
105
|
+
|
|
102
106
|
namespaceGroups() {
|
|
103
107
|
const counts = {};
|
|
104
108
|
for (const f of this.facts()) {
|
|
@@ -118,6 +122,28 @@ export class ReportSet {
|
|
|
118
122
|
return this._usedPrefixes;
|
|
119
123
|
}
|
|
120
124
|
|
|
125
|
+
getUsedConceptDataTypes() {
|
|
126
|
+
if (this._usedDataTypes === undefined) {
|
|
127
|
+
const map = new Map()
|
|
128
|
+
for (const dt of Object.values(this._items)
|
|
129
|
+
.filter(f => f instanceof Fact)
|
|
130
|
+
.map(f => ({ dataType: f.concept().dataType(), isNumeric: f.isNumeric() }))
|
|
131
|
+
.filter(t => t.dataType !== undefined)) {
|
|
132
|
+
map.set(dt.dataType.name, dt);
|
|
133
|
+
}
|
|
134
|
+
this._usedDataTypes = map.values().toArray();
|
|
135
|
+
}
|
|
136
|
+
return this._usedDataTypes;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @return {Array[String]} Sorted list of unique software credit text values
|
|
141
|
+
*/
|
|
142
|
+
getSoftwareCredits() {
|
|
143
|
+
let softwareCredits = new Set(this.reports.flatMap(r => r.softwareCredits()));
|
|
144
|
+
return Array.from(softwareCredits).sort();
|
|
145
|
+
}
|
|
146
|
+
|
|
121
147
|
getTargetDocuments() {
|
|
122
148
|
if (this._targetDocuments === undefined) {
|
|
123
149
|
this._targetDocuments = new Set(Object.values(this._items)
|
|
@@ -219,6 +245,10 @@ export class ReportSet {
|
|
|
219
245
|
return this.reportsData().some(r => r.rels?.["w-n"] !== undefined);
|
|
220
246
|
}
|
|
221
247
|
|
|
248
|
+
usesCalculations() {
|
|
249
|
+
return this.reportsData().some(r => Object.keys(r.rels?.calc ?? {}).length > 0);
|
|
250
|
+
}
|
|
251
|
+
|
|
222
252
|
hasValidationErrors() {
|
|
223
253
|
return this._data.validation !== undefined && this._data.validation.length > 0;
|
|
224
254
|
}
|
|
@@ -230,5 +260,5 @@ export class ReportSet {
|
|
|
230
260
|
factsForReport(report) {
|
|
231
261
|
return Object.values(this._items).filter(i => i instanceof Fact && i.report == report);
|
|
232
262
|
}
|
|
233
|
-
|
|
263
|
+
|
|
234
264
|
}
|
|
@@ -73,7 +73,10 @@ function multiReportTestData(withAnchoring) {
|
|
|
73
73
|
"facts": {
|
|
74
74
|
...createNumericFact("f1", "eg:Concept1", "iso2417:USD", "2018-01-01/2019-01-01", 1000, -3),
|
|
75
75
|
...createNumericFact("f2", "eg:Concept2", "iso2417:USD", "2018-01-01/2019-01-01", 1000, -3),
|
|
76
|
-
}
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
"softwareCredits": ["Example credit text C", "Example credit text B"],
|
|
77
80
|
},
|
|
78
81
|
]
|
|
79
82
|
},
|
|
@@ -112,7 +115,9 @@ function multiReportTestData(withAnchoring) {
|
|
|
112
115
|
|
|
113
116
|
"rels": {
|
|
114
117
|
...anchoringRelationShips(withAnchoring)
|
|
115
|
-
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
"softwareCredits": ["Example credit text A"],
|
|
116
121
|
}
|
|
117
122
|
]
|
|
118
123
|
}
|
|
@@ -165,7 +170,9 @@ function singleReportTestData() {
|
|
|
165
170
|
"facts": {
|
|
166
171
|
...createNumericFact("f1", "eg:Concept1", "iso2417:USD", "2018-01-01/2019-01-01", 1000, -3),
|
|
167
172
|
...createNumericFact("f2", "eg:Concept2", "iso2417:USD", "2018-01-01/2019-01-01", 1000, -3),
|
|
168
|
-
}
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
"softwareCredits": ["Example credit text"],
|
|
169
176
|
};
|
|
170
177
|
}
|
|
171
178
|
|
|
@@ -233,8 +240,8 @@ describe("Multi report - ELR labels", () => {
|
|
|
233
240
|
|
|
234
241
|
test("Present", () => {
|
|
235
242
|
// Role 1 only has a label in report 1
|
|
236
|
-
expect(testReportSet.reports[0].
|
|
237
|
-
expect(testReportSet.reports[1].
|
|
243
|
+
expect(testReportSet.reports[0].getRoleLabelOrURI("role1")).toBe("Role 1 Label");
|
|
244
|
+
expect(testReportSet.reports[1].getRoleLabelOrURI("role1")).toBe("https://www.example.com/role1");
|
|
238
245
|
});
|
|
239
246
|
});
|
|
240
247
|
|
|
@@ -326,6 +333,25 @@ describe("ELR labels", () => {
|
|
|
326
333
|
testReportSet._initialize();
|
|
327
334
|
|
|
328
335
|
test("Present", () => {
|
|
329
|
-
expect(testReportSet.reports[0].
|
|
336
|
+
expect(testReportSet.reports[0].getRoleLabelOrURI("role1")).toBe("Role 1 Label");
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe("Fetching software credit", () => {
|
|
341
|
+
|
|
342
|
+
test("Single", () => {
|
|
343
|
+
const testReportSet = new ReportSet(singleReportTestData());
|
|
344
|
+
testReportSet._initialize();
|
|
345
|
+
|
|
346
|
+
const softwareCredits = testReportSet.getSoftwareCredits();
|
|
347
|
+
expect(softwareCredits).toEqual(["Example credit text"]);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test("Multiple", () => {
|
|
351
|
+
const testReportSet = new ReportSet(multiReportTestData(true));
|
|
352
|
+
testReportSet._initialize();
|
|
353
|
+
|
|
354
|
+
const softwareCredits = testReportSet.getSoftwareCredits();
|
|
355
|
+
expect(softwareCredits).toEqual(["Example credit text A", "Example credit text B", "Example credit text C"]);
|
|
330
356
|
});
|
|
331
357
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
3
|
import lunr from 'lunr'
|
|
4
|
-
import $ from 'jquery'
|
|
5
|
-
import Decimal from "decimal.js";
|
|
6
4
|
|
|
7
5
|
export class ReportSearch {
|
|
8
6
|
constructor(reportSet) {
|
|
@@ -15,42 +13,49 @@ export class ReportSearch {
|
|
|
15
13
|
var dims = {};
|
|
16
14
|
var facts = this._reportSet.facts();
|
|
17
15
|
this.periods = {};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
// Add hidden facts to index later, so that they appear later in the
|
|
17
|
+
// default search
|
|
18
|
+
for (const hidden of [false, true]) {
|
|
19
|
+
for (var i = 0; i < facts.length; i++) {
|
|
20
|
+
var f = facts[i];
|
|
21
|
+
if (f.isHidden() !== hidden) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
var doc = { "id": f.vuid };
|
|
25
|
+
var l = f.getLabel("std");
|
|
26
|
+
doc.concept = f.conceptQName().localname;
|
|
27
|
+
doc.doc = f.getLabel("doc");
|
|
28
|
+
doc.date = f.periodTo();
|
|
29
|
+
doc.startDate = f.periodFrom();
|
|
30
|
+
var dims = f.dimensions();
|
|
31
|
+
for (var d in dims) {
|
|
32
|
+
if (f.report.getConcept(d).isTypedDimension()) {
|
|
33
|
+
if (dims[d] !== null) {
|
|
34
|
+
l += " " + dims[d];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
l += " " + f.report.getLabel(dims[d], "std");
|
|
31
39
|
}
|
|
32
40
|
}
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
doc.label = l;
|
|
42
|
+
doc.ref = f.concept().referenceValuesAsString();
|
|
43
|
+
const wider = f.widerConcepts();
|
|
44
|
+
if (wider.length > 0) {
|
|
45
|
+
doc.widerConcept = f.report.qname(wider[0]).localname;
|
|
46
|
+
doc.widerLabel = f.report.getLabel(wider[0], "std");
|
|
47
|
+
doc.widerDoc = f.report.getLabel(wider[0], "doc");
|
|
35
48
|
}
|
|
36
|
-
|
|
37
|
-
doc.label = l;
|
|
38
|
-
doc.ref = f.concept().referenceValuesAsString();
|
|
39
|
-
const wider = f.widerConcepts();
|
|
40
|
-
if (wider.length > 0) {
|
|
41
|
-
doc.widerConcept = f.report.qname(wider[0]).localname;
|
|
42
|
-
doc.widerLabel = f.report.getLabel(wider[0], "std");
|
|
43
|
-
doc.widerDoc = f.report.getLabel(wider[0], "doc");
|
|
44
|
-
}
|
|
45
|
-
docs.push(doc);
|
|
49
|
+
docs.push(doc);
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
var p = f.period();
|
|
52
|
+
if (p) {
|
|
53
|
+
this.periods[p.key()] = p.toString();
|
|
54
|
+
}
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
if (i % 100 === 0) {
|
|
57
|
+
yield;
|
|
58
|
+
}
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
const builder = new lunr.Builder();
|
|
@@ -88,7 +93,11 @@ export class ReportSearch {
|
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
visibilityFilter(s, item) {
|
|
91
|
-
return
|
|
96
|
+
return (
|
|
97
|
+
s.visibilityFilter === '*' ||
|
|
98
|
+
s.visibilityFilter === 'visible' && !item.isHidden() ||
|
|
99
|
+
s.visibilityFilter === 'hidden' && item.isHidden()
|
|
100
|
+
)
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
periodFilter(s, item) {
|
|
@@ -140,6 +149,14 @@ export class ReportSearch {
|
|
|
140
149
|
);
|
|
141
150
|
}
|
|
142
151
|
|
|
152
|
+
dataTypesFilter(s, item) {
|
|
153
|
+
return (
|
|
154
|
+
s.dataTypesFilter == null ||
|
|
155
|
+
s.dataTypesFilter.length === 0 ||
|
|
156
|
+
s.dataTypesFilter.some(p => item.concept().dataType()?.name === p)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
143
160
|
unitsFilter(s, item) {
|
|
144
161
|
return (
|
|
145
162
|
s.unitsFilter.length === 0 ||
|
|
@@ -161,6 +178,13 @@ export class ReportSearch {
|
|
|
161
178
|
);
|
|
162
179
|
}
|
|
163
180
|
|
|
181
|
+
mandatoryFactFilter(s, item) {
|
|
182
|
+
if(!s.showMandatoryFacts) {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
return item.isMandatory();
|
|
186
|
+
}
|
|
187
|
+
|
|
164
188
|
search(s) {
|
|
165
189
|
if (!this.ready) {
|
|
166
190
|
return;
|
|
@@ -177,9 +201,11 @@ export class ReportSearch {
|
|
|
177
201
|
this.factValueFilter,
|
|
178
202
|
this.calculationsFilter,
|
|
179
203
|
this.namespacesFilter,
|
|
204
|
+
this.dataTypesFilter,
|
|
180
205
|
this.unitsFilter,
|
|
181
206
|
this.scalesFilter,
|
|
182
|
-
this.targetDocumentFilter
|
|
207
|
+
this.targetDocumentFilter,
|
|
208
|
+
this.mandatoryFactFilter
|
|
183
209
|
];
|
|
184
210
|
|
|
185
211
|
rr.forEach((r,_) => {
|
|
@@ -55,7 +55,7 @@ function createDimensionalizedFact(id, concept, options=null, dimensions= {}) {
|
|
|
55
55
|
|
|
56
56
|
// Returns a report set with a single report
|
|
57
57
|
function testReport(testData, sourceIXData) {
|
|
58
|
-
return testReportSet([ {data: testData, ixData: sourceIXData ?? {} } ])
|
|
58
|
+
return testReportSet([ {data: testData, ixData: sourceIXData ?? { } } ])
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function mergeDicts(a, b) {
|
|
@@ -71,7 +71,7 @@ function testReportSet(reports) {
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
const ixData = {};
|
|
74
|
-
for (const
|
|
74
|
+
for (const report of reports.values()) {
|
|
75
75
|
const targetReport = {};
|
|
76
76
|
for (const key of ["languages", "prefixes", "roles"]) {
|
|
77
77
|
reportSetData[key] = mergeDicts(reportSetData[key], report.data[key]);
|
|
@@ -83,12 +83,15 @@ function testReportSet(reports) {
|
|
|
83
83
|
|
|
84
84
|
for (const id of Object.keys(targetReport.facts)) {
|
|
85
85
|
if (!(id in ixData)) {
|
|
86
|
-
ixData[viewerUniqueId(
|
|
86
|
+
ixData[viewerUniqueId(0, id)] = report.ixData?.[id] ?? {};
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
targetReports.push(targetReport);
|
|
90
90
|
}
|
|
91
91
|
const reportSet = new ReportSet(reportSetData);
|
|
92
|
+
for (const [id, data] of Object.entries(ixData)) {
|
|
93
|
+
ixData[id].isHidden ??= false;
|
|
94
|
+
}
|
|
92
95
|
reportSet.setIXNodeMap(ixData);
|
|
93
96
|
return reportSet;
|
|
94
97
|
}
|
|
@@ -96,13 +99,13 @@ function testReportSet(reports) {
|
|
|
96
99
|
function testSearchSpec(searchString='') {
|
|
97
100
|
const spec = {};
|
|
98
101
|
spec.searchString = searchString;
|
|
99
|
-
spec.
|
|
100
|
-
spec.showHiddenFacts = true;
|
|
102
|
+
spec.visibilityFilter = '*';
|
|
101
103
|
spec.namespacesFilter = [];
|
|
102
104
|
spec.unitsFilter = [];
|
|
103
105
|
spec.scalesFilter = [];
|
|
104
106
|
spec.periodFilter = [];
|
|
105
107
|
spec.conceptTypeFilter = '*';
|
|
108
|
+
spec.dataTypesFilter = [];
|
|
106
109
|
spec.dimensionTypeFilter = [];
|
|
107
110
|
spec.factValueFilter = '*';
|
|
108
111
|
spec.calculationsFilter = [];
|
|
@@ -125,6 +125,20 @@ export class DocumentSummary {
|
|
|
125
125
|
return this._totalFacts;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
hiddenFacts() {
|
|
129
|
+
if (this._hiddenFacts === undefined) {
|
|
130
|
+
this._hiddenFacts = this._reportSet.facts().filter(f => f.isHidden()).length;
|
|
131
|
+
}
|
|
132
|
+
return this._hiddenFacts;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
mandatoryFacts() {
|
|
136
|
+
if (this._mandatoryFacts === undefined) {
|
|
137
|
+
this._mandatoryFacts = this._reportSet.facts().filter(f => f.isMandatory()).length;
|
|
138
|
+
}
|
|
139
|
+
return this._mandatoryFacts;
|
|
140
|
+
}
|
|
141
|
+
|
|
128
142
|
tagCounts() {
|
|
129
143
|
if (this._tagCounts === undefined) {
|
|
130
144
|
this._buildTagCounts();
|
|
@@ -138,4 +152,12 @@ export class DocumentSummary {
|
|
|
138
152
|
}
|
|
139
153
|
return this._localFileSummary.getDocuments()
|
|
140
154
|
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @return {Array[String]} Report set's list of software credit text values.
|
|
159
|
+
*/
|
|
160
|
+
getSoftwareCredits() {
|
|
161
|
+
return this._reportSet.getSoftwareCredits();
|
|
162
|
+
}
|
|
141
163
|
}
|