ixbrl-viewer 1.4.38__py3-none-any.whl → 1.4.40__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 +25 -22
- iXBRLViewerPlugin/_version.py +2 -2
- iXBRLViewerPlugin/constants.py +86 -1
- iXBRLViewerPlugin/featureConfig.py +4 -1
- iXBRLViewerPlugin/iXBRLViewer.py +28 -14
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
- iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
- 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 +318 -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 +50 -25
- 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 +66 -40
- 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 +2 -1
- iXBRLViewerPlugin/viewer/src/js/aspect.js +18 -7
- iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
- iXBRLViewerPlugin/viewer/src/js/chart.js +10 -6
- iXBRLViewerPlugin/viewer/src/js/concept.js +28 -1
- 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 +3 -1
- iXBRLViewerPlugin/viewer/src/js/fact.js +16 -0
- iXBRLViewerPlugin/viewer/src/js/fact.test.js +3 -0
- iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
- iXBRLViewerPlugin/viewer/src/js/inspector.js +498 -120
- iXBRLViewerPlugin/viewer/src/js/inspector.test.js +1 -1
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +128 -30
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +133 -20
- iXBRLViewerPlugin/viewer/src/js/menu.js +21 -3
- iXBRLViewerPlugin/viewer/src/js/outline.js +2 -2
- iXBRLViewerPlugin/viewer/src/js/report.js +60 -8
- iXBRLViewerPlugin/viewer/src/js/report.test.js +51 -5
- iXBRLViewerPlugin/viewer/src/js/reportset.js +20 -0
- iXBRLViewerPlugin/viewer/src/js/reportset.test.js +3 -3
- iXBRLViewerPlugin/viewer/src/js/search.js +23 -2
- iXBRLViewerPlugin/viewer/src/js/search.test.js +2 -2
- iXBRLViewerPlugin/viewer/src/js/summary.js +14 -0
- iXBRLViewerPlugin/viewer/src/js/tableExport.js +2 -1
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
- iXBRLViewerPlugin/viewer/src/js/theme.js +36 -0
- iXBRLViewerPlugin/viewer/src/js/unit.js +17 -2
- iXBRLViewerPlugin/viewer/src/js/util.js +16 -16
- iXBRLViewerPlugin/viewer/src/js/viewer.js +26 -15
- 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 +538 -299
- 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
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/METADATA +33 -5
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/RECORD +95 -66
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/WHEEL +1 -1
- tests/puppeteer/framework/page_objects/doc_frame.js +1 -1
- tests/puppeteer/tests/fact_properties.test.js +4 -4
- tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +69 -28
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/LICENSE +0 -0
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/NOTICE +0 -0
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/top_level.txt +0 -0
|
@@ -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" },
|
|
@@ -67,6 +72,10 @@ var testReportData = {
|
|
|
67
72
|
"softwareCredits": ["Example credit text A", "Example credit text B"],
|
|
68
73
|
};
|
|
69
74
|
|
|
75
|
+
var insp = new TestInspector();
|
|
76
|
+
beforeAll(() => {
|
|
77
|
+
return insp.i18nInit();
|
|
78
|
+
});
|
|
70
79
|
|
|
71
80
|
describe("Language options", () => {
|
|
72
81
|
const testReportSet = new ReportSet(testReportData);
|
|
@@ -103,23 +112,33 @@ describe("Concept labels", () => {
|
|
|
103
112
|
test("Label fallback", () => {
|
|
104
113
|
vo.language = 'fr';
|
|
105
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");
|
|
106
117
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept trois");
|
|
107
118
|
vo.language = 'es';
|
|
108
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");
|
|
109
122
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept cuatro");
|
|
110
123
|
// No English label, so fall back on German (de is first alphabetically)
|
|
111
124
|
vo.language = 'en';
|
|
112
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");
|
|
113
128
|
expect(testReport.getLabelOrName('eg:Concept3', 'std')).toBe("Concept vier");
|
|
114
129
|
|
|
115
130
|
// Attempt to get an undefined label type
|
|
116
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();
|
|
117
134
|
expect(testReport.getLabelOrName('eg:Concept3', 'doc')).toBe('eg:Concept3');
|
|
118
135
|
});
|
|
119
136
|
|
|
120
137
|
test("With prefix", () => {
|
|
121
138
|
vo.language = 'fr';
|
|
122
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");
|
|
123
142
|
expect(testReport.getLabelOrName('eg:Concept3', 'std', true)).toBe("(eg) Concept trois");
|
|
124
143
|
|
|
125
144
|
expect(testReport.getLabel('eg:Concept3', 'doc', true)).toBeUndefined();
|
|
@@ -133,16 +152,43 @@ describe("ELR labels", () => {
|
|
|
133
152
|
testReportSet._initialize();
|
|
134
153
|
const testReport = testReportSet.reports[0];
|
|
135
154
|
test("Present", () => {
|
|
136
|
-
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");
|
|
137
183
|
});
|
|
138
184
|
test("Null", () => {
|
|
139
|
-
expect(testReport.
|
|
185
|
+
expect(testReport.getLabelRoleLabel("role2")).toBe("Role2");
|
|
140
186
|
});
|
|
141
187
|
test("No label", () => {
|
|
142
|
-
expect(testReport.
|
|
188
|
+
expect(testReport.getLabelRoleLabel("role3")).toBe("Role3");
|
|
143
189
|
});
|
|
144
190
|
test("Not present in roleDef", () => {
|
|
145
|
-
expect(testReport.
|
|
191
|
+
expect(testReport.getLabelRoleLabel("role4")).toBe("Role4 More Words");
|
|
146
192
|
});
|
|
147
193
|
|
|
148
194
|
});
|
|
@@ -7,6 +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 { TaxonomyNamer } from './taxonomynamer.js';
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
// Class represents the set of XBRL "target" reports shown in the viewer.
|
|
@@ -18,6 +19,7 @@ export class ReportSet {
|
|
|
18
19
|
this._data = data;
|
|
19
20
|
this._ixNodeMap = {};
|
|
20
21
|
this.viewerOptions = new ViewerOptions()
|
|
22
|
+
this.taxonomyNamer = new TaxonomyNamer(new Map());
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/*
|
|
@@ -98,6 +100,10 @@ export class ReportSet {
|
|
|
98
100
|
return this._data.prefixes;
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
preferredPrefix(prefix) {
|
|
104
|
+
return this.taxonomyNamer.getName(prefix, this._data.prefixes[prefix]).prefix;
|
|
105
|
+
}
|
|
106
|
+
|
|
101
107
|
namespaceGroups() {
|
|
102
108
|
const counts = {};
|
|
103
109
|
for (const f of this.facts()) {
|
|
@@ -117,6 +123,20 @@ export class ReportSet {
|
|
|
117
123
|
return this._usedPrefixes;
|
|
118
124
|
}
|
|
119
125
|
|
|
126
|
+
getUsedConceptDataTypes() {
|
|
127
|
+
if (this._usedDataTypes === undefined) {
|
|
128
|
+
const map = new Map()
|
|
129
|
+
for (const dt of Object.values(this._items)
|
|
130
|
+
.filter(f => f instanceof Fact)
|
|
131
|
+
.map(f => ({ dataType: f.concept().dataType(), isNumeric: f.isNumeric() }))
|
|
132
|
+
.filter(t => t.dataType !== undefined)) {
|
|
133
|
+
map.set(dt.dataType.name, dt);
|
|
134
|
+
}
|
|
135
|
+
this._usedDataTypes = map.values().toArray();
|
|
136
|
+
}
|
|
137
|
+
return this._usedDataTypes;
|
|
138
|
+
}
|
|
139
|
+
|
|
120
140
|
/**
|
|
121
141
|
* @return {Array[String]} Sorted list of unique software credit text values
|
|
122
142
|
*/
|
|
@@ -240,8 +240,8 @@ describe("Multi report - ELR labels", () => {
|
|
|
240
240
|
|
|
241
241
|
test("Present", () => {
|
|
242
242
|
// Role 1 only has a label in report 1
|
|
243
|
-
expect(testReportSet.reports[0].
|
|
244
|
-
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");
|
|
245
245
|
});
|
|
246
246
|
});
|
|
247
247
|
|
|
@@ -333,7 +333,7 @@ describe("ELR labels", () => {
|
|
|
333
333
|
testReportSet._initialize();
|
|
334
334
|
|
|
335
335
|
test("Present", () => {
|
|
336
|
-
expect(testReportSet.reports[0].
|
|
336
|
+
expect(testReportSet.reports[0].getRoleLabelOrURI("role1")).toBe("Role 1 Label");
|
|
337
337
|
});
|
|
338
338
|
});
|
|
339
339
|
|
|
@@ -86,7 +86,11 @@ export class ReportSearch {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
visibilityFilter(s, item) {
|
|
89
|
-
return
|
|
89
|
+
return (
|
|
90
|
+
s.visibilityFilter === '*' ||
|
|
91
|
+
s.visibilityFilter === 'visible' && !item.isHidden() ||
|
|
92
|
+
s.visibilityFilter === 'hidden' && item.isHidden()
|
|
93
|
+
)
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
periodFilter(s, item) {
|
|
@@ -138,6 +142,14 @@ export class ReportSearch {
|
|
|
138
142
|
);
|
|
139
143
|
}
|
|
140
144
|
|
|
145
|
+
dataTypesFilter(s, item) {
|
|
146
|
+
return (
|
|
147
|
+
s.dataTypesFilter == null ||
|
|
148
|
+
s.dataTypesFilter.length === 0 ||
|
|
149
|
+
s.dataTypesFilter.some(p => item.concept().dataType()?.name === p)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
141
153
|
unitsFilter(s, item) {
|
|
142
154
|
return (
|
|
143
155
|
s.unitsFilter.length === 0 ||
|
|
@@ -159,6 +171,13 @@ export class ReportSearch {
|
|
|
159
171
|
);
|
|
160
172
|
}
|
|
161
173
|
|
|
174
|
+
mandatoryFactFilter(s, item) {
|
|
175
|
+
if(!s.showMandatoryFacts) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return item.isMandatory();
|
|
179
|
+
}
|
|
180
|
+
|
|
162
181
|
search(s) {
|
|
163
182
|
if (!this.ready) {
|
|
164
183
|
return;
|
|
@@ -175,9 +194,11 @@ export class ReportSearch {
|
|
|
175
194
|
this.factValueFilter,
|
|
176
195
|
this.calculationsFilter,
|
|
177
196
|
this.namespacesFilter,
|
|
197
|
+
this.dataTypesFilter,
|
|
178
198
|
this.unitsFilter,
|
|
179
199
|
this.scalesFilter,
|
|
180
|
-
this.targetDocumentFilter
|
|
200
|
+
this.targetDocumentFilter,
|
|
201
|
+
this.mandatoryFactFilter
|
|
181
202
|
];
|
|
182
203
|
|
|
183
204
|
rr.forEach((r,_) => {
|
|
@@ -96,13 +96,13 @@ function testReportSet(reports) {
|
|
|
96
96
|
function testSearchSpec(searchString='') {
|
|
97
97
|
const spec = {};
|
|
98
98
|
spec.searchString = searchString;
|
|
99
|
-
spec.
|
|
100
|
-
spec.showHiddenFacts = true;
|
|
99
|
+
spec.visibilityFilter = '*';
|
|
101
100
|
spec.namespacesFilter = [];
|
|
102
101
|
spec.unitsFilter = [];
|
|
103
102
|
spec.scalesFilter = [];
|
|
104
103
|
spec.periodFilter = [];
|
|
105
104
|
spec.conceptTypeFilter = '*';
|
|
105
|
+
spec.dataTypesFilter = [];
|
|
106
106
|
spec.dimensionTypeFilter = [];
|
|
107
107
|
spec.factValueFilter = '*';
|
|
108
108
|
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();
|
|
@@ -14,7 +14,8 @@ export class TableExport {
|
|
|
14
14
|
static addHandles(iframe, reportSet) {
|
|
15
15
|
$('table', iframe).each(function () {
|
|
16
16
|
const table = $(this);
|
|
17
|
-
|
|
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) {
|
|
18
19
|
table.css("position", "relative");
|
|
19
20
|
const exporter = new TableExport(table, reportSet);
|
|
20
21
|
$('<div class="ixbrl-table-handle"><span>Export table</span></div>')
|
|
@@ -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,36 @@
|
|
|
1
|
+
// See COPYRIGHT.md for copyright information
|
|
2
|
+
|
|
3
|
+
function getHtmlElement() {
|
|
4
|
+
return document.querySelector('html');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getVariable(name) {
|
|
8
|
+
const html = getHtmlElement();
|
|
9
|
+
return getComputedStyle(html).getPropertyValue(name);s
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function setTheme(theme) {
|
|
13
|
+
const html = getHtmlElement();
|
|
14
|
+
html.dataset.theme = `theme-${theme}`;
|
|
15
|
+
console.log('Set theme:', theme);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getTheme() {
|
|
19
|
+
const html = getHtmlElement();
|
|
20
|
+
return html.dataset.theme.replace('theme-','');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function initializeTheme() {
|
|
24
|
+
const initialTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
25
|
+
? 'dark'
|
|
26
|
+
: 'light';
|
|
27
|
+
setTheme(initialTheme);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function toggleTheme() {
|
|
31
|
+
if (getTheme() === 'light') {
|
|
32
|
+
setTheme('dark');
|
|
33
|
+
} else {
|
|
34
|
+
setTheme('light');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { NAMESPACE_ISO4217 } from "./util";
|
|
4
|
+
import i18next from "i18next";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transforms measure qname into title case label (or currency symbol, if applicable).
|
|
8
|
+
* @return {String} Measure Label
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
function measureLabel(reportSet, measure) {
|
|
12
|
+
const qname = reportSet.qname(measure);
|
|
13
|
+
if (qname.namespace === NAMESPACE_ISO4217) {
|
|
14
|
+
measure = i18next.t(`currencies:unitFormat${qname.localname}`, {defaultValue: qname.localname});
|
|
15
|
+
} else if (measure.includes(':')) {
|
|
16
|
+
measure = measure.split(':')[1];
|
|
17
|
+
}
|
|
18
|
+
return measure;
|
|
19
|
+
}
|
|
4
20
|
|
|
5
21
|
export class Unit {
|
|
6
|
-
|
|
7
22
|
constructor(reportSet, unitKey) {
|
|
8
23
|
this._reportSet = reportSet;
|
|
9
24
|
this._value = unitKey;
|
|
@@ -2,19 +2,33 @@
|
|
|
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';
|
|
11
10
|
|
|
12
11
|
export const CALC_ARCROLE = "calc";
|
|
13
12
|
export const CALC11_ARCROLE = "calc11";
|
|
14
13
|
|
|
14
|
+
export const GLOSSARY_URL = "https://xbrl.org/glossary/";
|
|
15
|
+
|
|
15
16
|
// The number of distinct highlight colors defined in inspector.less
|
|
16
17
|
export const HIGHLIGHT_COLORS = 3;
|
|
17
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_HIGHLIGHT_FACTS = "ixbrl-viewer-highlight-all-facts";
|
|
30
|
+
export const STORAGE_HOME_LINK_QUERY = "ixbrl-viewer-home-link-query";
|
|
31
|
+
|
|
18
32
|
/*
|
|
19
33
|
* Takes a moment.js oject and converts it to a human readable date, or date
|
|
20
34
|
* and time if the time component is not midnight. Adjust specifies that a
|
|
@@ -217,17 +231,3 @@ export function getIXHiddenLinkStyle(domNode) {
|
|
|
217
231
|
return null;
|
|
218
232
|
}
|
|
219
233
|
|
|
220
|
-
/**
|
|
221
|
-
* Transforms measure qname into title case label (or currency symbol, if applicable).
|
|
222
|
-
* @return {String} Measure Label
|
|
223
|
-
*/
|
|
224
|
-
|
|
225
|
-
export function measureLabel(report, measure) {
|
|
226
|
-
const qname = report.qname(measure);
|
|
227
|
-
if (qname.namespace === NAMESPACE_ISO4217) {
|
|
228
|
-
measure = i18next.t(`currencies:unitFormat${qname.localname}`, {defaultValue: qname.localname});
|
|
229
|
-
} else if (measure.includes(':')) {
|
|
230
|
-
measure = measure.split(':')[1];
|
|
231
|
-
}
|
|
232
|
-
return measure;
|
|
233
|
-
}
|
|
@@ -108,7 +108,7 @@ export class Viewer {
|
|
|
108
108
|
if (this._reportSet.isMultiDocumentViewer()) {
|
|
109
109
|
$('#ixv .ixds-tabs').show();
|
|
110
110
|
for (const [i, doc] of this._reportSet.reportFiles().entries()) {
|
|
111
|
-
$('<
|
|
111
|
+
$('<button class="tab"></button>')
|
|
112
112
|
.text(doc.file)
|
|
113
113
|
.prop('title', doc.file)
|
|
114
114
|
.data('ix-doc-id', i)
|
|
@@ -123,12 +123,17 @@ export class Viewer {
|
|
|
123
123
|
// display: block, a div is used, otherwise a span. Returns the wrapper node
|
|
124
124
|
// as a jQuery node
|
|
125
125
|
_wrapNode(n) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
let wrapper = "<span>";
|
|
127
|
+
if (getComputedStyle(n).getPropertyValue("display") === "block") {
|
|
128
|
+
wrapper = '<div>';
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const nn = n.getElementsByTagName("*");
|
|
132
|
+
for (var i = 0; i < nn.length; i++) {
|
|
133
|
+
if (getComputedStyle(nn[i]).getPropertyValue('display') === "block") {
|
|
134
|
+
wrapper = '<div>';
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
132
137
|
}
|
|
133
138
|
}
|
|
134
139
|
$(n).wrap(wrapper);
|
|
@@ -268,7 +273,7 @@ export class Viewer {
|
|
|
268
273
|
nodes.push(tableNode)
|
|
269
274
|
}
|
|
270
275
|
}
|
|
271
|
-
/* Otherwise, insert a <span> as wrapper */
|
|
276
|
+
/* Otherwise, insert a <span> or <div> as wrapper */
|
|
272
277
|
if (nodes.length == 0) {
|
|
273
278
|
nodes.push(this._wrapNode(domNode));
|
|
274
279
|
}
|
|
@@ -440,7 +445,7 @@ export class Viewer {
|
|
|
440
445
|
// Handle SEC/ESEF links-to-hidden
|
|
441
446
|
const vuid = viewerUniqueId(reportIndex, getIXHiddenLinkStyle(n));
|
|
442
447
|
if (vuid !== null) {
|
|
443
|
-
let nodes =
|
|
448
|
+
let nodes = this._findOrCreateWrapperNode(n, inHidden);
|
|
444
449
|
nodes.addClass("ixbrl-element").data('ivids', [vuid]);
|
|
445
450
|
this._docOrderItemIndex.addItem(vuid, docIndex);
|
|
446
451
|
/* We may have already seen the corresponding ix element in the hidden
|
|
@@ -749,11 +754,14 @@ export class Viewer {
|
|
|
749
754
|
// highlight color for an element that is double tagged in a
|
|
750
755
|
// table cell.
|
|
751
756
|
const ixn = $(this).data('ivids').map(id => viewer._ixNodeMap[id]).filter(ixn => !ixn.footnote)[0];
|
|
752
|
-
if (ixn
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
+
if (ixn !== undefined ) {
|
|
758
|
+
const item = reportSet.getItemById(ixn.id);
|
|
759
|
+
if (item !== undefined) {
|
|
760
|
+
const elements = viewer.elementsForItemIds(ixn.chainIXIds());
|
|
761
|
+
const i = groups[item.conceptQName().prefix];
|
|
762
|
+
if (i !== undefined) {
|
|
763
|
+
elements.addClass("ixbrl-highlight-" + i);
|
|
764
|
+
}
|
|
757
765
|
}
|
|
758
766
|
}
|
|
759
767
|
});
|
|
@@ -803,7 +811,10 @@ export class Viewer {
|
|
|
803
811
|
}
|
|
804
812
|
|
|
805
813
|
_setTitle(docIndex) {
|
|
806
|
-
|
|
814
|
+
const title = $('head title', this._iframes.eq(docIndex).contents()).text();
|
|
815
|
+
$('#top-bar .document-title')
|
|
816
|
+
.text(title)
|
|
817
|
+
.attr("aria-label", "Inline Viewer: " + title);
|
|
807
818
|
}
|
|
808
819
|
|
|
809
820
|
showDocumentForItemId(vuid) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
.accordian .card {
|
|
4
4
|
margin-top: 0.4rem;
|
|
5
|
-
background-color:
|
|
5
|
+
background-color: var(--colour-button-bg);
|
|
6
6
|
|
|
7
7
|
.card-body {
|
|
8
8
|
display: none;
|
|
@@ -16,17 +16,21 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.title {
|
|
19
|
+
.text-md();
|
|
20
|
+
|
|
19
21
|
padding: 1.2rem 1.6rem;
|
|
22
|
+
border: none;
|
|
23
|
+
width: 100%;
|
|
24
|
+
text-align: left;
|
|
20
25
|
cursor: pointer;
|
|
21
|
-
line-height: 1.8rem;
|
|
22
26
|
|
|
23
27
|
&:hover {
|
|
24
|
-
background-color:
|
|
28
|
+
background-color: var(--colour-bg-selected);
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
&.active {
|
|
29
|
-
background-color:
|
|
33
|
+
background-color: var(--colour-bg-selected);
|
|
30
34
|
|
|
31
35
|
.title {
|
|
32
36
|
font-weight: bold;
|
|
@@ -3,27 +3,33 @@
|
|
|
3
3
|
.block-list-item {
|
|
4
4
|
margin: 0.5rem 0;
|
|
5
5
|
padding: 0.3rem 0.9rem;
|
|
6
|
-
background-color:
|
|
6
|
+
background-color: var(--colour-button-bg);
|
|
7
7
|
cursor: pointer;
|
|
8
8
|
position: relative;
|
|
9
|
-
border-left: solid 0.4rem
|
|
9
|
+
border-left: solid 0.4rem var(--colour-button-bg);
|
|
10
|
+
border-right: none;
|
|
11
|
+
border-top: none;
|
|
12
|
+
border-bottom: none;
|
|
13
|
+
border-radius: 0;
|
|
14
|
+
text-align: left;
|
|
15
|
+
width: 100%;
|
|
10
16
|
|
|
11
17
|
& > * {
|
|
12
18
|
margin: 0.8rem 0;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
// Contents of .tags provide 0.2rem of non-collapsing margin
|
|
16
|
-
& > .tags {
|
|
22
|
+
& > .block-list-item-tags {
|
|
17
23
|
margin: 0.6rem 0;
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
&:hover {
|
|
21
|
-
background-color:
|
|
27
|
+
background-color: var(--colour-bg-selected);
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
&.selected {
|
|
25
|
-
border-left: solid 0.4rem
|
|
26
|
-
background-color:
|
|
31
|
+
border-left: solid 0.4rem var(--colour-primary);
|
|
32
|
+
background-color: var(--colour-bg-selected);
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
&.linked-highlight {
|
|
@@ -58,13 +58,13 @@
|
|
|
58
58
|
&.consistent .icon::before {
|
|
59
59
|
.icon-circle-tick();
|
|
60
60
|
|
|
61
|
-
color:
|
|
61
|
+
color: var(--colour-primary);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
&.inconsistent .icon::before {
|
|
65
65
|
.icon-circle-cross();
|
|
66
66
|
|
|
67
|
-
color:
|
|
67
|
+
color: var(--colour-warning);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|