ixbrl-viewer 1.4.21__py3-none-any.whl → 1.4.50__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 +210 -137
- 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 +30 -3
- 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 +28 -2
- iXBRLViewerPlugin/viewer/src/js/summary.test.js +52 -14
- 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.50.dist-info}/METADATA +41 -14
- ixbrl_viewer-1.4.50.dist-info/RECORD +197 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.50.dist-info}/WHEEL +1 -1
- tests/puppeteer/framework/page_objects/doc_frame.js +3 -3
- tests/puppeteer/framework/page_objects/fact_details_panel.js +29 -1
- 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.50.dist-info}/LICENSE +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.50.dist-info}/NOTICE +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.50.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.21.dist-info → ixbrl_viewer-1.4.50.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,8 @@ import { DocumentSummary } from "./summary.js";
|
|
|
6
6
|
function testConcept(typedDomainElement) {
|
|
7
7
|
return {
|
|
8
8
|
isTypedDimension: () => typedDomainElement !== undefined,
|
|
9
|
-
typedDomainElement: () => typedDomainElement
|
|
9
|
+
typedDomainElement: () => typedDomainElement,
|
|
10
|
+
hasDefinition: true,
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -17,16 +18,17 @@ function testFact(conceptName, dimensions) {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
function testReportSet(concepts, facts, documents) {
|
|
21
|
+
function testReportSet(concepts, facts, documents, softwareCredits) {
|
|
21
22
|
const report = {
|
|
22
23
|
getConcept: conceptName => concepts[conceptName],
|
|
23
|
-
localDocuments: () => documents
|
|
24
|
+
localDocuments: () => documents,
|
|
24
25
|
}
|
|
25
26
|
for (const f of facts) {
|
|
26
27
|
f.report = report;
|
|
27
28
|
}
|
|
28
29
|
return {
|
|
29
30
|
facts: () => facts,
|
|
31
|
+
getSoftwareCredits: () => softwareCredits,
|
|
30
32
|
reports: [ report ]
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -34,7 +36,7 @@ function testReportSet(concepts, facts, documents) {
|
|
|
34
36
|
describe("Facts summary", () => {
|
|
35
37
|
|
|
36
38
|
test("no facts", () => {
|
|
37
|
-
const reportSet = testReportSet({}, [], {});
|
|
39
|
+
const reportSet = testReportSet({}, [], {}, []);
|
|
38
40
|
const summary = new DocumentSummary(reportSet);
|
|
39
41
|
|
|
40
42
|
expect(summary.totalFacts()).toBe(0);
|
|
@@ -43,9 +45,9 @@ describe("Facts summary", () => {
|
|
|
43
45
|
test("multiple facts", () => {
|
|
44
46
|
const facts = [];
|
|
45
47
|
for (let i = 0; i < 10; i++) {
|
|
46
|
-
facts.push(testFact("eg:Concept1", {}));
|
|
48
|
+
facts.push(testFact("eg:Concept1", {}, []));
|
|
47
49
|
}
|
|
48
|
-
const reportSet = testReportSet({}, facts, {});
|
|
50
|
+
const reportSet = testReportSet({}, facts, {}, []);
|
|
49
51
|
const summary = new DocumentSummary(reportSet);
|
|
50
52
|
|
|
51
53
|
expect(summary.totalFacts()).toBe(10);
|
|
@@ -55,7 +57,7 @@ describe("Facts summary", () => {
|
|
|
55
57
|
const conceptName = "eg:Concept1";
|
|
56
58
|
const fact1 = testFact(conceptName, {});
|
|
57
59
|
const fact2 = testFact(conceptName, {});
|
|
58
|
-
const reportSet = testReportSet({}, [fact1, fact2], {});
|
|
60
|
+
const reportSet = testReportSet({}, [fact1, fact2], {}, []);
|
|
59
61
|
const summary = new DocumentSummary(reportSet);
|
|
60
62
|
|
|
61
63
|
expect(summary.totalFacts()).toBe(2);
|
|
@@ -66,7 +68,7 @@ describe("Facts summary", () => {
|
|
|
66
68
|
describe("Tags summary", () => {
|
|
67
69
|
|
|
68
70
|
test("no tags", () => {
|
|
69
|
-
const reportSet = testReportSet({}, [], {})
|
|
71
|
+
const reportSet = testReportSet({}, [], {}, [])
|
|
70
72
|
const summary = new DocumentSummary(reportSet);
|
|
71
73
|
|
|
72
74
|
expect(summary.tagCounts()).toEqual(new Map());
|
|
@@ -76,7 +78,7 @@ describe("Tags summary", () => {
|
|
|
76
78
|
const fact1 = testFact("eg:Concept1", {});
|
|
77
79
|
const fact2 = testFact("eg:Concept2", {});
|
|
78
80
|
const fact3 = testFact("xz:Concept1", {});
|
|
79
|
-
const reportSet = testReportSet({}, [fact1, fact2, fact3], {})
|
|
81
|
+
const reportSet = testReportSet({}, [fact1, fact2, fact3], {}, [])
|
|
80
82
|
const summary = new DocumentSummary(reportSet);
|
|
81
83
|
|
|
82
84
|
expect(Object.fromEntries(summary.tagCounts())).toEqual({
|
|
@@ -105,7 +107,7 @@ describe("Tags summary", () => {
|
|
|
105
107
|
const concepts = {
|
|
106
108
|
[dimension]: testConcept(),
|
|
107
109
|
}
|
|
108
|
-
const reportSet = testReportSet(concepts, [fact], {})
|
|
110
|
+
const reportSet = testReportSet(concepts, [fact], {}, [])
|
|
109
111
|
const summary = new DocumentSummary(reportSet);
|
|
110
112
|
|
|
111
113
|
expect(Object.fromEntries(summary.tagCounts())).toEqual({
|
|
@@ -135,7 +137,7 @@ describe("Tags summary", () => {
|
|
|
135
137
|
[dimension2]: testConcept(),
|
|
136
138
|
[dimension3]: testConcept(),
|
|
137
139
|
}
|
|
138
|
-
const reportSet = testReportSet(concepts, [fact], {})
|
|
140
|
+
const reportSet = testReportSet(concepts, [fact], {}, [])
|
|
139
141
|
const summary = new DocumentSummary(reportSet);
|
|
140
142
|
|
|
141
143
|
expect(Object.fromEntries(summary.tagCounts())).toEqual({
|
|
@@ -176,7 +178,7 @@ describe("Tags summary", () => {
|
|
|
176
178
|
const concepts = {
|
|
177
179
|
[dimension]: testConcept(typedDomain),
|
|
178
180
|
}
|
|
179
|
-
const reportSet = testReportSet(concepts, [fact], {})
|
|
181
|
+
const reportSet = testReportSet(concepts, [fact], {}, [])
|
|
180
182
|
const summary = new DocumentSummary(reportSet);
|
|
181
183
|
|
|
182
184
|
expect(Object.fromEntries(summary.tagCounts())).toEqual({
|
|
@@ -200,7 +202,7 @@ describe("Files summary", () => {
|
|
|
200
202
|
|
|
201
203
|
test("no files", () => {
|
|
202
204
|
const documentData = {}
|
|
203
|
-
const reportSet = testReportSet({}, [], documentData);
|
|
205
|
+
const reportSet = testReportSet({}, [], documentData, []);
|
|
204
206
|
const summary = new DocumentSummary(reportSet);
|
|
205
207
|
|
|
206
208
|
expect(summary.getLocalDocuments()).toEqual({
|
|
@@ -228,7 +230,7 @@ describe("Files summary", () => {
|
|
|
228
230
|
'labelLinkbase.xml': ['labelLinkbase'],
|
|
229
231
|
'unrecognizedLinkbase.xml': ['unrecognizedLinkbase'],
|
|
230
232
|
}
|
|
231
|
-
const reportSet = testReportSet({}, [], documentData);
|
|
233
|
+
const reportSet = testReportSet({}, [], documentData, []);
|
|
232
234
|
const summary = new DocumentSummary(reportSet);
|
|
233
235
|
|
|
234
236
|
expect(summary.getLocalDocuments()).toEqual({
|
|
@@ -243,3 +245,39 @@ describe("Files summary", () => {
|
|
|
243
245
|
});
|
|
244
246
|
});
|
|
245
247
|
});
|
|
248
|
+
|
|
249
|
+
describe("Software credit", () => {
|
|
250
|
+
|
|
251
|
+
test("no credits", () => {
|
|
252
|
+
const softwareCredits = []
|
|
253
|
+
const documentData = {}
|
|
254
|
+
const reportSet = testReportSet({}, [], documentData, softwareCredits);
|
|
255
|
+
const summary = new DocumentSummary(reportSet);
|
|
256
|
+
|
|
257
|
+
expect(summary.getSoftwareCredits()).toEqual([]);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("one credit", () => {
|
|
261
|
+
const softwareCredits = ["Example credit text"]
|
|
262
|
+
const documentData = {}
|
|
263
|
+
const reportSet = testReportSet({}, [], documentData, softwareCredits);
|
|
264
|
+
const summary = new DocumentSummary(reportSet);
|
|
265
|
+
|
|
266
|
+
expect(summary.getSoftwareCredits()).toEqual(["Example credit text"]);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("multiple credits", () => {
|
|
270
|
+
const softwareCredits = [
|
|
271
|
+
"Example credit text A",
|
|
272
|
+
"Example credit text B",
|
|
273
|
+
]
|
|
274
|
+
const documentData = {}
|
|
275
|
+
const reportSet = testReportSet({}, [], documentData, softwareCredits);
|
|
276
|
+
const summary = new DocumentSummary(reportSet);
|
|
277
|
+
|
|
278
|
+
expect(summary.getSoftwareCredits()).toEqual([
|
|
279
|
+
"Example credit text A",
|
|
280
|
+
"Example credit text B",
|
|
281
|
+
]);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
3
|
import $ from 'jquery'
|
|
4
|
-
import FileSaver from 'file-saver'
|
|
5
4
|
import writeXlsxFile from 'write-excel-file'
|
|
6
5
|
import { Fact } from './fact.js';
|
|
7
6
|
|
|
@@ -15,12 +14,13 @@ export class TableExport {
|
|
|
15
14
|
static addHandles(iframe, reportSet) {
|
|
16
15
|
$('table', iframe).each(function () {
|
|
17
16
|
const table = $(this);
|
|
18
|
-
|
|
17
|
+
// Require at least two facts on different rows.
|
|
18
|
+
if (table.find("tr").filter((i, row) => $(row).find(".ixbrl-element").length > 0).length > 1) {
|
|
19
19
|
table.css("position", "relative");
|
|
20
20
|
const exporter = new TableExport(table, reportSet);
|
|
21
21
|
$('<div class="ixbrl-table-handle"><span>Export table</span></div>')
|
|
22
22
|
.appendTo(table)
|
|
23
|
-
.click(
|
|
23
|
+
.on("click", () => exporter.exportTable());
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// See COPYRIGHT.md for copyright information
|
|
2
|
+
|
|
3
|
+
export class TaxonomyNamer {
|
|
4
|
+
constructor(map) {
|
|
5
|
+
this.map = new Map(Array.from(map.entries()).map(([k,v]) => [new RegExp(k), new TaxonomyName(v[0], v[1])]));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
getName(prefix, uri) {
|
|
10
|
+
for (const [re, name] of this.map.entries()) {
|
|
11
|
+
const m = uri.match(re);
|
|
12
|
+
if (m !== null) {
|
|
13
|
+
return name;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return new TaxonomyName(prefix, prefix);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fromQName(qname) {
|
|
20
|
+
return this.getName(qname.prefix, qname.namespace);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
convertQName(qname) {
|
|
24
|
+
const name = this.fromQName(qname)
|
|
25
|
+
return name.prefix + ':' + qname.localname;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class TaxonomyName {
|
|
30
|
+
constructor(prefix, name) {
|
|
31
|
+
this.prefix = prefix;
|
|
32
|
+
this.name = name;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// See COPYRIGHT.md for copyright information
|
|
2
|
+
|
|
3
|
+
import { TaxonomyNamer } from './taxonomynamer.js';
|
|
4
|
+
import { QName } from './qname.js';
|
|
5
|
+
|
|
6
|
+
const prefixMap = {
|
|
7
|
+
"e": "http://example.com/",
|
|
8
|
+
"g": "http://eggsample.com/",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const preferredPrefixMap = new Map([
|
|
12
|
+
[ "http://ex.*\.com/", ["prefix1", "My Example"] ]
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function qname(s) {
|
|
16
|
+
return new QName(prefixMap, s);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("readableName", () => {
|
|
20
|
+
const namer = new TaxonomyNamer(preferredPrefixMap);
|
|
21
|
+
test("Taxonomy name match", () => {
|
|
22
|
+
expect(namer.fromQName(qname("e:1234")).prefix).toBe("prefix1");
|
|
23
|
+
expect(namer.fromQName(qname("e:1234")).name).toBe("My Example");
|
|
24
|
+
expect(namer.convertQName(qname("e:1234"))).toBe("prefix1:1234");
|
|
25
|
+
});
|
|
26
|
+
test("Unknown taxonomy", () => {
|
|
27
|
+
expect(namer.fromQName(qname("g:1234")).prefix).toBe("g");
|
|
28
|
+
expect(namer.fromQName(qname("g:1234")).name).toBe("g");
|
|
29
|
+
expect(namer.convertQName(qname("g:1234"))).toBe("g:1234");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// See COPYRIGHT.md for copyright information
|
|
2
|
+
|
|
3
|
+
import { STORAGE_THEME } from "./util";
|
|
4
|
+
|
|
5
|
+
const DARK_THEME = 'dark';
|
|
6
|
+
const LIGHT_THEME = 'light';
|
|
7
|
+
|
|
8
|
+
function getHtmlElement() {
|
|
9
|
+
return document.querySelector('html');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getVariable(name) {
|
|
13
|
+
const html = getHtmlElement();
|
|
14
|
+
return getComputedStyle(html).getPropertyValue(name);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function setTheme(theme) {
|
|
18
|
+
const html = getHtmlElement();
|
|
19
|
+
html.dataset.theme = `theme-${theme}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getStoredTheme() {
|
|
23
|
+
return localStorage.getItem(STORAGE_THEME);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function storeTheme(theme) {
|
|
27
|
+
localStorage.setItem(STORAGE_THEME, theme);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getTheme() {
|
|
31
|
+
const html = getHtmlElement();
|
|
32
|
+
return html.dataset.theme.replace('theme-','');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function initializeTheme() {
|
|
36
|
+
const storedTheme = getStoredTheme();
|
|
37
|
+
if (storedTheme !== null) {
|
|
38
|
+
setTheme(storedTheme);
|
|
39
|
+
} else {
|
|
40
|
+
setTheme(window.matchMedia(`(prefers-color-scheme: ${DARK_THEME})`).matches ? DARK_THEME : LIGHT_THEME);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function toggleTheme() {
|
|
45
|
+
const currentTheme = getTheme();
|
|
46
|
+
const newTheme = currentTheme === LIGHT_THEME ? DARK_THEME : LIGHT_THEME;
|
|
47
|
+
setTheme(newTheme);
|
|
48
|
+
storeTheme(newTheme);
|
|
49
|
+
}
|
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { NAMESPACE_ISO4217 } from "./util";
|
|
4
|
+
import i18next from "i18next";
|
|
5
|
+
import { utr } from "./utr";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Transforms measure qname into title case label (or currency symbol, if applicable).
|
|
9
|
+
* @return {String} Measure Label
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function measureLabel(report, measure) {
|
|
13
|
+
const qname = report.qname(measure);
|
|
14
|
+
if (qname.namespace === NAMESPACE_ISO4217) {
|
|
15
|
+
// Prefer a name from our own i18n resources
|
|
16
|
+
const keyi18n = `currencies:unitFormat${qname.localname}`;
|
|
17
|
+
if (i18next.exists(keyi18n)) {
|
|
18
|
+
return i18next.t(keyi18n);
|
|
19
|
+
}
|
|
20
|
+
// Fall back on symbol from UTR ...
|
|
21
|
+
const utrEntry = utr.get(qname);
|
|
22
|
+
if (utrEntry !== undefined) {
|
|
23
|
+
// ... but disambiguate "$" symbol
|
|
24
|
+
return utrEntry.symbol == '$' ? `${qname.localname} $` : utrEntry.symbol;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (measure.includes(':')) {
|
|
28
|
+
return measure.split(':')[1];
|
|
29
|
+
}
|
|
30
|
+
return measure;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function measureName(report, measure) {
|
|
34
|
+
const qname = report.qname(measure);
|
|
35
|
+
const utrEntry = utr.get(qname);
|
|
36
|
+
return utrEntry?.name;
|
|
37
|
+
}
|
|
4
38
|
|
|
5
39
|
export class Unit {
|
|
6
|
-
|
|
7
40
|
constructor(reportSet, unitKey) {
|
|
8
41
|
this._reportSet = reportSet;
|
|
9
42
|
this._value = unitKey;
|
|
@@ -50,5 +83,43 @@ export class Unit {
|
|
|
50
83
|
value() {
|
|
51
84
|
return this._value;
|
|
52
85
|
}
|
|
86
|
+
|
|
87
|
+
measureHTML(m) {
|
|
88
|
+
const span = document.createElement("span");
|
|
89
|
+
const name = measureName(this._reportSet, m);
|
|
90
|
+
if (name !== undefined) {
|
|
91
|
+
span.setAttribute("title", name);
|
|
92
|
+
span.classList.add("measure");
|
|
93
|
+
}
|
|
94
|
+
span.append(document.createTextNode(measureLabel(this._reportSet, m)));
|
|
95
|
+
return span;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
partsHTML(parts) {
|
|
99
|
+
const span = document.createElement("span");
|
|
100
|
+
if (parts.length > 1) {
|
|
101
|
+
span.appendChild(document.createTextNode("("));
|
|
102
|
+
}
|
|
103
|
+
for (const [i, m] of parts.entries()) {
|
|
104
|
+
span.appendChild(this.measureHTML(m));
|
|
105
|
+
if (i < parts.length - 1) {
|
|
106
|
+
span.appendChild(document.createTextNode(" * "))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (parts.length > 1) {
|
|
110
|
+
span.appendChild(document.createTextNode(")"));
|
|
111
|
+
}
|
|
112
|
+
return span;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
html() {
|
|
116
|
+
const span = document.createElement("span");
|
|
117
|
+
span.append(this.partsHTML(this._numerators));
|
|
118
|
+
if (this._denominators.length > 0) {
|
|
119
|
+
span.append(document.createTextNode(" / "));
|
|
120
|
+
span.append(this.partsHTML(this._denominators));
|
|
121
|
+
}
|
|
122
|
+
return span;
|
|
123
|
+
}
|
|
53
124
|
}
|
|
54
125
|
|
|
@@ -11,7 +11,7 @@ var testReportData = {
|
|
|
11
11
|
"iso4217": NAMESPACE_ISO4217,
|
|
12
12
|
"e": "http://example.com/entity",
|
|
13
13
|
},
|
|
14
|
-
"facts": {}
|
|
14
|
+
"facts": {},
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
function testReport() {
|
|
@@ -57,12 +57,23 @@ describe("Unit label", () => {
|
|
|
57
57
|
|
|
58
58
|
test("Unit label - known currency", () => {
|
|
59
59
|
var unit = new Unit(testReport(), 'iso4217:USD');
|
|
60
|
+
// Note "US $" from i18n takes precedence over "USD $" generated from UTR
|
|
60
61
|
expect(unit.label()).toEqual('US $');
|
|
61
62
|
});
|
|
62
63
|
|
|
64
|
+
test("Unit label - UTR currency", () => {
|
|
65
|
+
var unit = new Unit(testReport(), 'iso4217:THB');
|
|
66
|
+
expect(unit.label()).toEqual('฿');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("Unit label - UTR currency with '$' symbol", () => {
|
|
70
|
+
var unit = new Unit(testReport(), 'iso4217:SGD');
|
|
71
|
+
expect(unit.label()).toEqual('SGD $');
|
|
72
|
+
});
|
|
73
|
+
|
|
63
74
|
test("Unit label - unknown", () => {
|
|
64
|
-
var unit = new Unit(testReport(), 'iso4217:
|
|
65
|
-
expect(unit.label()).toEqual('
|
|
75
|
+
var unit = new Unit(testReport(), 'iso4217:ZZZZ');
|
|
76
|
+
expect(unit.label()).toEqual('ZZZZ');
|
|
66
77
|
});
|
|
67
78
|
});
|
|
68
79
|
|
|
@@ -2,16 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
import moment from "moment";
|
|
4
4
|
import Decimal from "decimal.js";
|
|
5
|
-
import i18next from "i18next";
|
|
6
|
-
|
|
7
5
|
|
|
8
6
|
export const SHOW_FACT = 'SHOW_FACT';
|
|
9
7
|
|
|
10
8
|
export const NAMESPACE_ISO4217 = 'http://www.xbrl.org/2003/iso4217';
|
|
9
|
+
export const NAMESPACE_XBRLI = 'http://www.xbrl.org/2003/instance';
|
|
10
|
+
|
|
11
|
+
export const CALC_ARCROLE = "calc";
|
|
12
|
+
export const CALC11_ARCROLE = "calc11";
|
|
13
|
+
|
|
14
|
+
export const GLOSSARY_URL = "https://xbrl.org/glossary/";
|
|
11
15
|
|
|
12
16
|
// The number of distinct highlight colors defined in inspector.less
|
|
13
17
|
export const HIGHLIGHT_COLORS = 3;
|
|
14
18
|
|
|
19
|
+
// Feature names
|
|
20
|
+
export const FEATURE_GUIDE_LINK = 'guide_link';
|
|
21
|
+
export const FEATURE_HOME_LINK_LABEL = 'home_link_label';
|
|
22
|
+
export const FEATURE_HOME_LINK_URL = 'home_link_url';
|
|
23
|
+
export const FEATURE_REVIEW = 'review';
|
|
24
|
+
export const FEATURE_SUPPORT_LINK = 'support_link';
|
|
25
|
+
export const FEATURE_SURVEY_LINK = 'survey_link';
|
|
26
|
+
export const FEATURE_SEARCH_ON_STARTUP = 'search_on_startup';
|
|
27
|
+
export const FEATURE_HIGHLIGHT_FACTS_ON_STARTUP = 'highlight_facts_on_startup';
|
|
28
|
+
|
|
29
|
+
export const STORAGE_THEME = "ixbrl-viewer-theme";
|
|
30
|
+
export const STORAGE_HIGHLIGHT_FACTS = "ixbrl-viewer-highlight-all-facts";
|
|
31
|
+
export const STORAGE_HOME_LINK_QUERY = "ixbrl-viewer-home-link-query";
|
|
32
|
+
|
|
15
33
|
/*
|
|
16
34
|
* Takes a moment.js oject and converts it to a human readable date, or date
|
|
17
35
|
* and time if the time component is not midnight. Adjust specifies that a
|
|
@@ -205,7 +223,7 @@ export function localId(viewerUniqueId) {
|
|
|
205
223
|
|
|
206
224
|
export function getIXHiddenLinkStyle(domNode) {
|
|
207
225
|
if (domNode.hasAttribute('style')) {
|
|
208
|
-
const re = /(?:^|\s|;)
|
|
226
|
+
const re = /(?:^|\s|;)(?:-sec|-esef)?-ix-hidden:\s*([^\s;]+)/;
|
|
209
227
|
const m = domNode.getAttribute('style').match(re);
|
|
210
228
|
if (m) {
|
|
211
229
|
return m[1];
|
|
@@ -213,18 +231,3 @@ export function getIXHiddenLinkStyle(domNode) {
|
|
|
213
231
|
}
|
|
214
232
|
return null;
|
|
215
233
|
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Transforms measure qname into title case label (or currency symbol, if applicable).
|
|
219
|
-
* @return {String} Measure Label
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
|
-
export function measureLabel(report, measure) {
|
|
223
|
-
const qname = report.qname(measure);
|
|
224
|
-
if (qname.namespace === NAMESPACE_ISO4217) {
|
|
225
|
-
measure = i18next.t(`currencies:unitFormat${qname.localname}`, {defaultValue: qname.localname});
|
|
226
|
-
} else if (measure.includes(':')) {
|
|
227
|
-
measure = measure.split(':')[1];
|
|
228
|
-
}
|
|
229
|
-
return measure;
|
|
230
|
-
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// See COPYRIGHT.md for copyright information
|
|
2
|
+
|
|
3
|
+
// Class to expose properties of Unit Type Registry entries from viewer data
|
|
4
|
+
|
|
5
|
+
export class UTREntry {
|
|
6
|
+
|
|
7
|
+
constructor(symbol, name) {
|
|
8
|
+
this.symbol = symbol;
|
|
9
|
+
this.name = name;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class UTR {
|
|
14
|
+
constructor() {
|
|
15
|
+
self.entries = require("../data/utr.json");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get(qname) {
|
|
19
|
+
const u = self.entries[qname.namespace]?.[qname.localname]
|
|
20
|
+
if (u === undefined) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return new UTREntry(u.s ?? u.n, u.n)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const utr = new UTR();
|