ixbrl-viewer 1.4.39__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.

Files changed (95) hide show
  1. iXBRLViewerPlugin/__init__.py +25 -22
  2. iXBRLViewerPlugin/_version.py +2 -2
  3. iXBRLViewerPlugin/constants.py +86 -1
  4. iXBRLViewerPlugin/featureConfig.py +4 -1
  5. iXBRLViewerPlugin/iXBRLViewer.py +28 -14
  6. iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
  7. iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
  8. iXBRLViewerPlugin/viewer/src/html/fact-details.html +69 -38
  9. iXBRLViewerPlugin/viewer/src/html/footer-logo.html +4 -0
  10. iXBRLViewerPlugin/viewer/src/html/footnote-details.html +1 -1
  11. iXBRLViewerPlugin/viewer/src/html/inspector.html +318 -211
  12. iXBRLViewerPlugin/viewer/src/i18n/cy/balancetypes.json +1 -0
  13. iXBRLViewerPlugin/viewer/src/i18n/cy/currencies.json +13 -0
  14. iXBRLViewerPlugin/viewer/src/i18n/cy/datatypes.json +9 -0
  15. iXBRLViewerPlugin/viewer/src/i18n/cy/labelroles.json +24 -0
  16. iXBRLViewerPlugin/viewer/src/i18n/cy/referenceparts.json +10 -0
  17. iXBRLViewerPlugin/viewer/src/i18n/cy/scale.json +16 -0
  18. iXBRLViewerPlugin/viewer/src/i18n/cy/tooltips.json +17 -0
  19. iXBRLViewerPlugin/viewer/src/i18n/cy/translation.json +179 -0
  20. iXBRLViewerPlugin/viewer/src/i18n/en/balancetypes.json +4 -0
  21. iXBRLViewerPlugin/viewer/src/i18n/en/datatypes.json +10 -0
  22. iXBRLViewerPlugin/viewer/src/i18n/en/labelroles.json +4 -0
  23. iXBRLViewerPlugin/viewer/src/i18n/en/scale.json +16 -0
  24. iXBRLViewerPlugin/viewer/src/i18n/en/tooltips.json +17 -0
  25. iXBRLViewerPlugin/viewer/src/i18n/en/translation.json +50 -25
  26. iXBRLViewerPlugin/viewer/src/i18n/es/balancetypes.json +4 -0
  27. iXBRLViewerPlugin/viewer/src/i18n/es/datatypes.json +10 -0
  28. iXBRLViewerPlugin/viewer/src/i18n/es/labelroles.json +24 -0
  29. iXBRLViewerPlugin/viewer/src/i18n/es/scale.json +16 -0
  30. iXBRLViewerPlugin/viewer/src/i18n/es/tooltips.json +17 -0
  31. iXBRLViewerPlugin/viewer/src/i18n/es/translation.json +66 -40
  32. iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
  33. iXBRLViewerPlugin/viewer/src/img/arelle-dark.svg +179 -0
  34. iXBRLViewerPlugin/viewer/src/img/inline-viewer-dark.svg +59 -0
  35. iXBRLViewerPlugin/viewer/src/js/accordian.js +2 -1
  36. iXBRLViewerPlugin/viewer/src/js/aspect.js +18 -7
  37. iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
  38. iXBRLViewerPlugin/viewer/src/js/chart.js +10 -6
  39. iXBRLViewerPlugin/viewer/src/js/concept.js +28 -1
  40. iXBRLViewerPlugin/viewer/src/js/concept.test.js +23 -2
  41. iXBRLViewerPlugin/viewer/src/js/datatype.js +20 -0
  42. iXBRLViewerPlugin/viewer/src/js/datatype.test.js +62 -0
  43. iXBRLViewerPlugin/viewer/src/js/dialog.js +3 -1
  44. iXBRLViewerPlugin/viewer/src/js/fact.js +16 -0
  45. iXBRLViewerPlugin/viewer/src/js/fact.test.js +3 -0
  46. iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
  47. iXBRLViewerPlugin/viewer/src/js/inspector.js +498 -120
  48. iXBRLViewerPlugin/viewer/src/js/inspector.test.js +1 -1
  49. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +128 -30
  50. iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +133 -20
  51. iXBRLViewerPlugin/viewer/src/js/menu.js +21 -3
  52. iXBRLViewerPlugin/viewer/src/js/outline.js +2 -2
  53. iXBRLViewerPlugin/viewer/src/js/report.js +60 -8
  54. iXBRLViewerPlugin/viewer/src/js/report.test.js +51 -5
  55. iXBRLViewerPlugin/viewer/src/js/reportset.js +20 -0
  56. iXBRLViewerPlugin/viewer/src/js/reportset.test.js +3 -3
  57. iXBRLViewerPlugin/viewer/src/js/search.js +23 -2
  58. iXBRLViewerPlugin/viewer/src/js/search.test.js +2 -2
  59. iXBRLViewerPlugin/viewer/src/js/summary.js +14 -0
  60. iXBRLViewerPlugin/viewer/src/js/tableExport.js +2 -1
  61. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
  62. iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
  63. iXBRLViewerPlugin/viewer/src/js/theme.js +36 -0
  64. iXBRLViewerPlugin/viewer/src/js/unit.js +17 -2
  65. iXBRLViewerPlugin/viewer/src/js/util.js +16 -16
  66. iXBRLViewerPlugin/viewer/src/js/viewer.js +13 -7
  67. iXBRLViewerPlugin/viewer/src/less/accordian.less +8 -4
  68. iXBRLViewerPlugin/viewer/src/less/block-list.less +12 -6
  69. iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +2 -2
  70. iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
  71. iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
  72. iXBRLViewerPlugin/viewer/src/less/colours.less +28 -21
  73. iXBRLViewerPlugin/viewer/src/less/common.less +1 -1
  74. iXBRLViewerPlugin/viewer/src/less/components.less +3 -3
  75. iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
  76. iXBRLViewerPlugin/viewer/src/less/dialog.less +13 -10
  77. iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
  78. iXBRLViewerPlugin/viewer/src/less/inspector.less +538 -299
  79. iXBRLViewerPlugin/viewer/src/less/loader.less +2 -2
  80. iXBRLViewerPlugin/viewer/src/less/menu.less +33 -15
  81. iXBRLViewerPlugin/viewer/src/less/summary.less +16 -6
  82. iXBRLViewerPlugin/viewer/src/less/tabs.less +5 -5
  83. iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
  84. iXBRLViewerPlugin/viewer/src/less/validation-report.less +1 -1
  85. iXBRLViewerPlugin/viewer/src/less/viewer.less +30 -18
  86. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/METADATA +33 -5
  87. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/RECORD +95 -66
  88. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/WHEEL +1 -1
  89. tests/puppeteer/framework/page_objects/doc_frame.js +1 -1
  90. tests/puppeteer/tests/fact_properties.test.js +4 -4
  91. tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +69 -28
  92. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/LICENSE +0 -0
  93. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/NOTICE +0 -0
  94. {ixbrl_viewer-1.4.39.dist-info → ixbrl_viewer-1.4.40.dist-info}/entry_points.txt +0 -0
  95. {ixbrl_viewer-1.4.39.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/role4"
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.getRoleLabel("role1")).toBe("Role 1 Label");
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.getRoleLabel("role2")).toBe("https://www.example.com/role2");
185
+ expect(testReport.getLabelRoleLabel("role2")).toBe("Role2");
140
186
  });
141
187
  test("No label", () => {
142
- expect(testReport.getRoleLabel("role3")).toBe("https://www.example.com/role3");
188
+ expect(testReport.getLabelRoleLabel("role3")).toBe("Role3");
143
189
  });
144
190
  test("Not present in roleDef", () => {
145
- expect(testReport.getRoleLabel("role4")).toBe("https://www.example.com/role4");
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].getRoleLabel("role1")).toBe("Role 1 Label");
244
- expect(testReportSet.reports[1].getRoleLabel("role1")).toBe("https://www.example.com/role1");
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].getRoleLabel("role1")).toBe("Role 1 Label");
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 item.isHidden() ? s.showHiddenFacts : s.showVisibleFacts;
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.showVisibleFacts = true;
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
- if (table.find(".ixbrl-element").length > 0) {
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 { measureLabel, NAMESPACE_ISO4217 } from "./util";
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
- $('<div class="tab"></div>')
111
+ $('<button class="tab"></button>')
112
112
  .text(doc.file)
113
113
  .prop('title', doc.file)
114
114
  .data('ix-doc-id', i)
@@ -754,11 +754,14 @@ export class Viewer {
754
754
  // highlight color for an element that is double tagged in a
755
755
  // table cell.
756
756
  const ixn = $(this).data('ivids').map(id => viewer._ixNodeMap[id]).filter(ixn => !ixn.footnote)[0];
757
- if (ixn != undefined) {
758
- const elements = viewer.elementsForItemIds(ixn.chainIXIds());
759
- const i = groups[reportSet.getItemById(ixn.id).conceptQName().prefix];
760
- if (i !== undefined) {
761
- elements.addClass("ixbrl-highlight-" + i);
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
+ }
762
765
  }
763
766
  }
764
767
  });
@@ -808,7 +811,10 @@ export class Viewer {
808
811
  }
809
812
 
810
813
  _setTitle(docIndex) {
811
- $('#top-bar .document-title').text($('head title', this._iframes.eq(docIndex).contents()).text());
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);
812
818
  }
813
819
 
814
820
  showDocumentForItemId(vuid) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  .accordian .card {
4
4
  margin-top: 0.4rem;
5
- background-color: @button-background;
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: #f3f3f3;
28
+ background-color: var(--colour-bg-selected);
25
29
  }
26
30
  }
27
31
 
28
32
  &.active {
29
- background-color: #f3f3f3;
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: @button-background;
6
+ background-color: var(--colour-button-bg);
7
7
  cursor: pointer;
8
8
  position: relative;
9
- border-left: solid 0.4rem @button-background;
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: @background-selected;
27
+ background-color: var(--colour-bg-selected);
22
28
  }
23
29
 
24
30
  &.selected {
25
- border-left: solid 0.4rem #0085e6;
26
- background-color: @background-selected;
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: @workiva-green;
61
+ color: var(--colour-primary);
62
62
  }
63
63
 
64
64
  &.inconsistent .icon::before {
65
65
  .icon-circle-cross();
66
66
 
67
- color: @warning-orange;
67
+ color: var(--colour-warning);
68
68
  }
69
69
  }
70
70
 
@@ -12,6 +12,9 @@
12
12
  width: 100%;
13
13
  position: absolute;
14
14
  bottom: 0;
15
+ left: 0;
16
+ padding: 1rem;
17
+ box-sizing: border-box;
15
18
 
16
19
  .other-aspect {
17
20
  display: inline-block;
@@ -24,21 +27,21 @@
24
27
  }
25
28
 
26
29
  &.addable {
27
- color: @primary;
30
+ color: var(--colour-primary);
28
31
 
29
32
  &:hover {
30
- color: @primary-focus;
33
+ color: var(--colour-primary)-focus;
31
34
  text-decoration: underline;
32
35
  }
33
36
  }
34
37
 
35
38
  &.selected {
36
- background-color: @button-primary-bg;
39
+ background-color: var(--colour-button-primary-bg);
37
40
  border-radius: 0.4rem;
38
- border: 0.1rem solid @button-primary-border;
41
+ border: 0.1rem solid var(--colour-button-primary-border);
39
42
 
40
43
  /* border: solid 1px #399; */
41
- color: #fff;
44
+ color: var(--colour-bg);
42
45
  }
43
46
  }
44
47
  }