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
|
@@ -39,7 +39,6 @@ const testReportData = {
|
|
|
39
39
|
"roles": {},
|
|
40
40
|
"roleDefs": {},
|
|
41
41
|
"rels": {},
|
|
42
|
-
"units": {},
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
function testReport(facts, ixData) {
|
|
@@ -159,7 +158,7 @@ describe("Scales filter options", () => {
|
|
|
159
158
|
})
|
|
160
159
|
|
|
161
160
|
test("Scales filter options with only monetary facts", () => {
|
|
162
|
-
|
|
161
|
+
const insp = new TestInspector();
|
|
163
162
|
const reportSet = testReport({
|
|
164
163
|
...monetaryFactData,
|
|
165
164
|
}, ixData);
|
|
@@ -5,11 +5,17 @@ import $ from 'jquery'
|
|
|
5
5
|
import { ReportSet } from "./reportset.js";
|
|
6
6
|
import { Viewer, DocumentTooLargeError } from "./viewer.js";
|
|
7
7
|
import { Inspector } from "./inspector.js";
|
|
8
|
+
import { initializeTheme } from './theme.js';
|
|
9
|
+
import { TaxonomyNamer } from './taxonomynamer.js';
|
|
10
|
+
import {FEATURE_GUIDE_LINK, FEATURE_REVIEW, FEATURE_SUPPORT_LINK, FEATURE_SURVEY_LINK} from "./util";
|
|
11
|
+
|
|
12
|
+
const featureFalsyValues = new Set([undefined, null, '', 'false', false]);
|
|
8
13
|
|
|
9
14
|
export class iXBRLViewer {
|
|
10
15
|
|
|
11
16
|
constructor(options) {
|
|
12
|
-
this.
|
|
17
|
+
this._staticFeatures = {};
|
|
18
|
+
this._dynamicFeatures = {};
|
|
13
19
|
this._plugins = [];
|
|
14
20
|
this.inspector = new Inspector(this);
|
|
15
21
|
this.viewer = null;
|
|
@@ -76,40 +82,68 @@ export class iXBRLViewer {
|
|
|
76
82
|
});
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
setFeatures(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
85
|
+
setFeatures(features, queryString) {
|
|
86
|
+
this._staticFeatures = {}
|
|
87
|
+
for (const [key, value] of Object.entries(features)) {
|
|
88
|
+
this._staticFeatures[key] = value;
|
|
89
|
+
}
|
|
85
90
|
|
|
86
|
-
// Enable/disable features based on query string
|
|
87
91
|
const urlParams = new URLSearchParams(queryString);
|
|
92
|
+
this._dynamicFeatures = {}
|
|
88
93
|
urlParams.forEach((value, key) => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
if (value === '') {
|
|
95
|
+
if (this._dynamicFeatures[key] === undefined) {
|
|
96
|
+
value = 'true'
|
|
97
|
+
} else {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
93
100
|
}
|
|
101
|
+
this._dynamicFeatures[key] = value;
|
|
94
102
|
});
|
|
103
|
+
}
|
|
95
104
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
105
|
+
getStaticFeatureValue(featureName) {
|
|
106
|
+
return this._staticFeatures[featureName];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getFeatureValue(featureName) {
|
|
110
|
+
if (this._dynamicFeatures[featureName]) {
|
|
111
|
+
return this._dynamicFeatures[featureName];
|
|
104
112
|
}
|
|
113
|
+
return this.getStaticFeatureValue(featureName);
|
|
105
114
|
}
|
|
106
115
|
|
|
107
116
|
isFeatureEnabled(featureName) {
|
|
108
|
-
return
|
|
117
|
+
return !featureFalsyValues.has(this.getFeatureValue(featureName));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
isStaticFeatureEnabled(featureName) {
|
|
121
|
+
return !featureFalsyValues.has(this.getStaticFeatureValue(featureName));
|
|
109
122
|
}
|
|
110
123
|
|
|
111
124
|
isReviewModeEnabled() {
|
|
112
|
-
return this.isFeatureEnabled(
|
|
125
|
+
return this.isFeatureEnabled(FEATURE_REVIEW);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getGuideLinkUrl() {
|
|
129
|
+
if (!this.isStaticFeatureEnabled(FEATURE_GUIDE_LINK)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_GUIDE_LINK));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getSupportLinkUrl() {
|
|
136
|
+
if (!this.isStaticFeatureEnabled(FEATURE_SUPPORT_LINK)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_SUPPORT_LINK));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getSurveyLinkUrl() {
|
|
143
|
+
if (!this.isStaticFeatureEnabled(FEATURE_SURVEY_LINK)) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return this.resolveRelativeUrl(this.getStaticFeatureValue(FEATURE_SURVEY_LINK));
|
|
113
147
|
}
|
|
114
148
|
|
|
115
149
|
isViewerEnabled() {
|
|
@@ -117,16 +151,34 @@ export class iXBRLViewer {
|
|
|
117
151
|
return (urlParams.get('disable-viewer') ?? 'false') === 'false';
|
|
118
152
|
}
|
|
119
153
|
|
|
154
|
+
// Resolves URL relative to the config file
|
|
155
|
+
resolveRelativeUrl(url) {
|
|
156
|
+
if (this.options.configUrl === undefined) {
|
|
157
|
+
return url;
|
|
158
|
+
}
|
|
159
|
+
const resolvedUrl = new URL(url, this.options.configUrl.href);
|
|
160
|
+
return resolvedUrl.href;
|
|
161
|
+
}
|
|
162
|
+
|
|
120
163
|
_loadInspectorHTML() {
|
|
121
164
|
/* Insert HTML and CSS styles into body */
|
|
122
|
-
|
|
123
|
-
|
|
165
|
+
const footerLogoHtml = this.runtimeConfig.skin?.footerLogoHtml ?? require("../html/footer-logo.html");
|
|
166
|
+
$(require('../html/inspector.html'))
|
|
167
|
+
.prependTo('body')
|
|
168
|
+
.find("#footer-logo").html(footerLogoHtml);
|
|
169
|
+
const inspector_css = require('../less/inspector.less').toString();
|
|
124
170
|
$('<style id="ixv-style"></style>')
|
|
125
171
|
.prop("type", "text/css")
|
|
126
172
|
.text(inspector_css)
|
|
127
173
|
.appendTo('head');
|
|
174
|
+
if (this.runtimeConfig.skin?.stylesheetUrl !== undefined) {
|
|
175
|
+
$('<link rel="stylesheet" id="ixv-style-skin" />')
|
|
176
|
+
.attr("href", this.resolveRelativeUrl(this.runtimeConfig.skin.stylesheetUrl))
|
|
177
|
+
.appendTo('head');
|
|
178
|
+
}
|
|
179
|
+
const favIconUrl = this.runtimeConfig.skin?.faviconUrl !== undefined ? this.resolveRelativeUrl(this.runtimeConfig.skin.faviconUrl) : require("../img/favicon.ico");
|
|
128
180
|
$('<link id="ixv-favicon" type="image/x-icon" rel="shortcut icon" />')
|
|
129
|
-
.attr('href',
|
|
181
|
+
.attr('href', favIconUrl)
|
|
130
182
|
.appendTo('head');
|
|
131
183
|
|
|
132
184
|
try {
|
|
@@ -140,7 +192,7 @@ export class iXBRLViewer {
|
|
|
140
192
|
_reparentDocument() {
|
|
141
193
|
const iframeContainer = $('#ixv #iframe-container');
|
|
142
194
|
|
|
143
|
-
const iframe = $('<iframe title="iXBRL document view"/>')
|
|
195
|
+
const iframe = $('<iframe title="iXBRL document view" tabindex="0"/>')
|
|
144
196
|
.data("report-index", 0)
|
|
145
197
|
.appendTo(iframeContainer)[0];
|
|
146
198
|
|
|
@@ -160,7 +212,8 @@ export class iXBRLViewer {
|
|
|
160
212
|
$('html').attr("lang", "en-US");
|
|
161
213
|
}
|
|
162
214
|
|
|
163
|
-
$('head')
|
|
215
|
+
$('head')
|
|
216
|
+
.children().not("script, style#ixv-style, link#ixv-style-skin, link#ixv-favicon").appendTo($(iframe).contents().find('head'));
|
|
164
217
|
|
|
165
218
|
$('<title>').text(docTitle).appendTo($('head'));
|
|
166
219
|
|
|
@@ -197,11 +250,41 @@ export class iXBRLViewer {
|
|
|
197
250
|
}
|
|
198
251
|
}
|
|
199
252
|
|
|
253
|
+
_loadRuntimeConfig() {
|
|
254
|
+
return new Promise((resolve, reject) => {
|
|
255
|
+
if (this.options.configUrl === undefined) {
|
|
256
|
+
resolve({});
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
fetch(this.options.configUrl)
|
|
260
|
+
.then((resp) => {
|
|
261
|
+
if (resp.status == 404) {
|
|
262
|
+
return Promise.resolve({});
|
|
263
|
+
}
|
|
264
|
+
else if (resp.status != 200) {
|
|
265
|
+
return Promise.reject("Fetch failed: " + resp.status);
|
|
266
|
+
}
|
|
267
|
+
return resp.json();
|
|
268
|
+
})
|
|
269
|
+
.then((data) => {
|
|
270
|
+
resolve(data);
|
|
271
|
+
})
|
|
272
|
+
.catch((err) => {
|
|
273
|
+
console.log(err);
|
|
274
|
+
resolve({});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
200
280
|
load() {
|
|
201
281
|
const iv = this;
|
|
202
282
|
const inspector = this.inspector;
|
|
283
|
+
|
|
284
|
+
this._loadRuntimeConfig().then((runtimeConfig) => {
|
|
285
|
+
this.runtimeConfig = runtimeConfig;
|
|
286
|
+
initializeTheme();
|
|
203
287
|
|
|
204
|
-
setTimeout(function () {
|
|
205
288
|
const stubViewer = $('body').hasClass('ixv-stub-viewer');
|
|
206
289
|
|
|
207
290
|
// If viewer is disabled, but not in stub viewer mode, just abort
|
|
@@ -217,9 +300,25 @@ export class iXBRLViewer {
|
|
|
217
300
|
// We need to parse JSON first so that we can determine feature enablement before loading begins.
|
|
218
301
|
const taxonomyData = iv._getTaxonomyData();
|
|
219
302
|
const parsedTaxonomyData = taxonomyData && JSON.parse(taxonomyData);
|
|
220
|
-
|
|
303
|
+
let features = parsedTaxonomyData && parsedTaxonomyData["features"];
|
|
304
|
+
if (!features) {
|
|
305
|
+
features = {};
|
|
306
|
+
}
|
|
307
|
+
// `features` was previously an array of flag values
|
|
308
|
+
// Support this for backwards compatability
|
|
309
|
+
else if (Array.isArray(features)) {
|
|
310
|
+
features = features.reduce((obj, val) => {
|
|
311
|
+
obj[val] = true;
|
|
312
|
+
return obj;
|
|
313
|
+
}, {});
|
|
314
|
+
}
|
|
315
|
+
if (this.runtimeConfig.features !== undefined) {
|
|
316
|
+
features = {...this.runtimeConfig.features, features};
|
|
317
|
+
}
|
|
318
|
+
iv.setFeatures(features, window.location.search);
|
|
221
319
|
|
|
222
320
|
const reportSet = new ReportSet(parsedTaxonomyData);
|
|
321
|
+
reportSet.taxonomyNamer = new TaxonomyNamer(new Map(Object.entries(this.runtimeConfig.taxonomyNames ?? {})));
|
|
223
322
|
|
|
224
323
|
// Viewer disabled in stub viewer mode => redirect to first iXBRL document
|
|
225
324
|
if (!iv.isViewerEnabled()) {
|
|
@@ -239,7 +338,7 @@ export class iXBRLViewer {
|
|
|
239
338
|
const ds = reportSet.reportFiles();
|
|
240
339
|
let hasExternalIframe = false;
|
|
241
340
|
for (let i = stubViewer ? 0 : 1; i < ds.length; i++) {
|
|
242
|
-
const iframe = $(
|
|
341
|
+
const iframe = $('<iframe tabindex="0" />').attr("src", ds[i].file).data("report-index", ds[i].index).appendTo("#ixv #iframe-container");
|
|
243
342
|
iframes = iframes.add(iframe);
|
|
244
343
|
hasExternalIframe = true;
|
|
245
344
|
}
|
|
@@ -292,7 +391,6 @@ export class iXBRLViewer {
|
|
|
292
391
|
$('#ixv .loader').remove();
|
|
293
392
|
|
|
294
393
|
/* Focus on fact specified in URL fragment, if any */
|
|
295
|
-
inspector.handleFactDeepLink();
|
|
296
394
|
if (iv.options.showValidationWarningOnStart) {
|
|
297
395
|
inspector.showValidationWarning();
|
|
298
396
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
3
|
import {iXBRLViewer} from "./ixbrlviewer";
|
|
4
|
+
import {
|
|
5
|
+
FEATURE_GUIDE_LINK,
|
|
6
|
+
FEATURE_REVIEW,
|
|
7
|
+
FEATURE_SUPPORT_LINK,
|
|
8
|
+
FEATURE_SURVEY_LINK
|
|
9
|
+
} from "./util";
|
|
4
10
|
describe("Feature enablement", () => {
|
|
5
11
|
var viewer = null;
|
|
6
12
|
beforeAll(() => {
|
|
@@ -8,58 +14,99 @@ describe("Feature enablement", () => {
|
|
|
8
14
|
});
|
|
9
15
|
|
|
10
16
|
test("Query parameter with no value results in enablement", () => {
|
|
11
|
-
viewer.setFeatures(
|
|
12
|
-
expect(viewer.
|
|
17
|
+
viewer.setFeatures({}, 'a')
|
|
18
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
19
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'true'});
|
|
13
20
|
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
14
21
|
});
|
|
15
22
|
|
|
16
23
|
test("Excluded from JSON, excluded from query", () => {
|
|
17
|
-
viewer.setFeatures(
|
|
18
|
-
expect(viewer.
|
|
24
|
+
viewer.setFeatures({}, '')
|
|
25
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
26
|
+
expect(viewer._dynamicFeatures).toEqual({});
|
|
19
27
|
expect(viewer.isFeatureEnabled('a')).toBeFalsy();
|
|
20
28
|
});
|
|
21
29
|
|
|
22
30
|
test("Excluded from JSON, enabled in query", () => {
|
|
23
|
-
viewer.setFeatures(
|
|
24
|
-
expect(viewer.
|
|
31
|
+
viewer.setFeatures({}, 'a=true')
|
|
32
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
33
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'true'});
|
|
25
34
|
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
26
35
|
});
|
|
27
36
|
|
|
28
37
|
test("Excluded from JSON, disabled in query", () => {
|
|
29
|
-
viewer.setFeatures(
|
|
30
|
-
expect(viewer.
|
|
38
|
+
viewer.setFeatures({}, 'a=false')
|
|
39
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
40
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'false'});
|
|
31
41
|
expect(viewer.isFeatureEnabled('a')).toBeFalsy();
|
|
32
42
|
});
|
|
33
43
|
|
|
34
44
|
test("Excluded from JSON, enabled and disabled in query", () => {
|
|
35
|
-
viewer.setFeatures(
|
|
36
|
-
expect(viewer.
|
|
45
|
+
viewer.setFeatures({}, 'a=true&a=false&a')
|
|
46
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
47
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'false'});
|
|
37
48
|
expect(viewer.isFeatureEnabled('a')).toBeFalsy();
|
|
38
49
|
});
|
|
39
50
|
|
|
40
51
|
test("Included in JSON, excluded from query", () => {
|
|
41
|
-
viewer.setFeatures(
|
|
42
|
-
expect(viewer.
|
|
52
|
+
viewer.setFeatures({'a': true}, '')
|
|
53
|
+
expect(viewer._staticFeatures).toEqual({'a': true});
|
|
54
|
+
expect(viewer._dynamicFeatures).toEqual({});
|
|
43
55
|
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
44
56
|
});
|
|
45
57
|
|
|
46
58
|
test("Included in JSON, enabled in query", () => {
|
|
47
|
-
viewer.setFeatures(
|
|
48
|
-
expect(viewer.
|
|
59
|
+
viewer.setFeatures({'a': true}, 'a=true')
|
|
60
|
+
expect(viewer._staticFeatures).toEqual({'a': true});
|
|
61
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'true'});
|
|
49
62
|
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
50
63
|
});
|
|
51
64
|
|
|
52
65
|
test("Included in JSON, disabled in query", () => {
|
|
53
|
-
viewer.setFeatures(
|
|
54
|
-
expect(viewer.
|
|
66
|
+
viewer.setFeatures({'a': true}, 'a=false')
|
|
67
|
+
expect(viewer._staticFeatures).toEqual({'a': true});
|
|
68
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'false'});
|
|
55
69
|
expect(viewer.isFeatureEnabled('a')).toBeFalsy();
|
|
56
70
|
});
|
|
57
71
|
|
|
58
72
|
test("Included in JSON, enabled and disabled in query", () => {
|
|
59
|
-
viewer.setFeatures(
|
|
60
|
-
expect(viewer.
|
|
73
|
+
viewer.setFeatures({'a': true}, 'a=true&a=false&a')
|
|
74
|
+
expect(viewer._staticFeatures).toEqual({'a': true});
|
|
75
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'false'});
|
|
61
76
|
expect(viewer.isFeatureEnabled('a')).toBeFalsy();
|
|
62
77
|
});
|
|
78
|
+
|
|
79
|
+
test("Value set in JSON, not included in query", () => {
|
|
80
|
+
viewer.setFeatures({'a': '1'}, '')
|
|
81
|
+
expect(viewer._staticFeatures).toEqual({'a': '1'});
|
|
82
|
+
expect(viewer._dynamicFeatures).toEqual({});
|
|
83
|
+
expect(viewer.getFeatureValue('a')).toEqual('1');
|
|
84
|
+
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("Value not set in JSON, set in query", () => {
|
|
88
|
+
viewer.setFeatures({}, 'a=1')
|
|
89
|
+
expect(viewer._staticFeatures).toEqual({});
|
|
90
|
+
expect(viewer._dynamicFeatures).toEqual({'a': '1'});
|
|
91
|
+
expect(viewer.getFeatureValue('a')).toEqual('1');
|
|
92
|
+
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("Value set in JSON, overwritten in query", () => {
|
|
96
|
+
viewer.setFeatures({'a': '1'}, 'a=2')
|
|
97
|
+
expect(viewer._staticFeatures).toEqual({'a': '1'});
|
|
98
|
+
expect(viewer._dynamicFeatures).toEqual({'a': '2'});
|
|
99
|
+
expect(viewer.getFeatureValue('a')).toEqual('2');
|
|
100
|
+
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("Value set in JSON, overwritten in query with blank", () => {
|
|
104
|
+
viewer.setFeatures({'a': '1'}, 'a')
|
|
105
|
+
expect(viewer._staticFeatures).toEqual({'a': '1'});
|
|
106
|
+
expect(viewer._dynamicFeatures).toEqual({'a': 'true'});
|
|
107
|
+
expect(viewer.getFeatureValue('a')).toEqual('true');
|
|
108
|
+
expect(viewer.isFeatureEnabled('a')).toBeTruthy();
|
|
109
|
+
});
|
|
63
110
|
});
|
|
64
111
|
|
|
65
112
|
describe("Review mode enablement", () => {
|
|
@@ -69,12 +116,78 @@ describe("Review mode enablement", () => {
|
|
|
69
116
|
});
|
|
70
117
|
|
|
71
118
|
test("Review mode enabled", () => {
|
|
72
|
-
viewer.setFeatures([
|
|
119
|
+
viewer.setFeatures({[FEATURE_REVIEW]: true}, '')
|
|
73
120
|
expect(viewer.isReviewModeEnabled()).toBeTruthy();
|
|
74
121
|
});
|
|
75
122
|
|
|
76
123
|
test("Review mode disabled", () => {
|
|
77
|
-
viewer.setFeatures(
|
|
124
|
+
viewer.setFeatures({'a': true}, '')
|
|
78
125
|
expect(viewer.isReviewModeEnabled()).toBeFalsy();
|
|
79
126
|
});
|
|
80
127
|
});
|
|
128
|
+
|
|
129
|
+
describe("Support link enablement", () => {
|
|
130
|
+
var viewer = null;
|
|
131
|
+
beforeAll(() => {
|
|
132
|
+
viewer = new iXBRLViewer({})
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("Support link enabled by JSON", () => {
|
|
136
|
+
viewer.setFeatures({[FEATURE_SUPPORT_LINK]: '/help'}, '')
|
|
137
|
+
expect(viewer.getSupportLinkUrl()).toEqual('/help');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("Support link enabled by query", () => {
|
|
141
|
+
viewer.setFeatures({}, FEATURE_SUPPORT_LINK + '=/help')
|
|
142
|
+
expect(viewer.getSupportLinkUrl()).toEqual(null);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("Support link disabled by query", () => {
|
|
146
|
+
viewer.setFeatures({[FEATURE_SUPPORT_LINK]: '/help'}, FEATURE_SUPPORT_LINK + '=false')
|
|
147
|
+
expect(viewer.getSupportLinkUrl()).toEqual('/help');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("Survey link enablement", () => {
|
|
152
|
+
var viewer = null;
|
|
153
|
+
beforeAll(() => {
|
|
154
|
+
viewer = new iXBRLViewer({})
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("Survey link enabled by JSON", () => {
|
|
158
|
+
viewer.setFeatures({[FEATURE_SURVEY_LINK]: '/survey'}, '')
|
|
159
|
+
expect(viewer.getSurveyLinkUrl()).toEqual('/survey');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("Survey link enabled by query", () => {
|
|
163
|
+
viewer.setFeatures({}, FEATURE_SURVEY_LINK + '=/survey')
|
|
164
|
+
expect(viewer.getSurveyLinkUrl()).toEqual(null);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("Survey link disabled by query", () => {
|
|
168
|
+
viewer.setFeatures({[FEATURE_SURVEY_LINK]: '/survey'}, FEATURE_SURVEY_LINK + '=false')
|
|
169
|
+
expect(viewer.getSurveyLinkUrl()).toEqual('/survey');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe("Guide link enablement", () => {
|
|
174
|
+
var viewer = null;
|
|
175
|
+
beforeAll(() => {
|
|
176
|
+
viewer = new iXBRLViewer({})
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("Guide link enabled by JSON", () => {
|
|
180
|
+
viewer.setFeatures({[FEATURE_GUIDE_LINK]: '/guide'}, '')
|
|
181
|
+
expect(viewer.getGuideLinkUrl()).toEqual('/guide');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("Guide link enabled by query", () => {
|
|
185
|
+
viewer.setFeatures({}, FEATURE_GUIDE_LINK + '=/guide')
|
|
186
|
+
expect(viewer.getGuideLinkUrl()).toEqual(null);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("Guide link disabled by query", () => {
|
|
190
|
+
viewer.setFeatures({[FEATURE_GUIDE_LINK]: '/guide'}, FEATURE_GUIDE_LINK + '=false')
|
|
191
|
+
expect(viewer.getGuideLinkUrl()).toEqual('/guide');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -46,6 +46,6 @@ export class IXNode {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
htmlHidden() {
|
|
49
|
-
return this.wrapperNodes.is(':hidden') || this.wrapperNodes.is((i,e) => isTransparent($(e).css('color')));
|
|
49
|
+
return this.wrapperNodes.filter(':not(.ixbrl-no-highlight)').is(':hidden') || this.wrapperNodes.is((i,e) => isTransparent($(e).css('color')));
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
3
|
import $ from 'jquery'
|
|
4
|
+
import i18next from "i18next";
|
|
4
5
|
|
|
5
6
|
export class Menu {
|
|
6
7
|
constructor(elt, attr) {
|
|
@@ -8,14 +9,14 @@ export class Menu {
|
|
|
8
9
|
attr = attr || {};
|
|
9
10
|
this.type = attr.type || "dropdown";
|
|
10
11
|
|
|
11
|
-
elt.find(".menu-title").click(
|
|
12
|
+
elt.find(".menu-title").on("click", (e) => {
|
|
12
13
|
elt.find(".content-container").toggle();
|
|
13
14
|
/* Stop an opening click from also being treated as an "out-of-menu"
|
|
14
15
|
* closing click */
|
|
15
16
|
e.stopPropagation();
|
|
16
17
|
});
|
|
17
18
|
|
|
18
|
-
$('html').click(
|
|
19
|
+
$('html').on("click", (event) => {
|
|
19
20
|
if ($(".content", elt).find($(event.target)).length === 0) {
|
|
20
21
|
this.close();
|
|
21
22
|
}
|
|
@@ -50,7 +51,7 @@ export class Menu {
|
|
|
50
51
|
.attr({
|
|
51
52
|
href: filename})
|
|
52
53
|
.text(name)
|
|
53
|
-
.click(
|
|
54
|
+
.on("click", () => menu.close());
|
|
54
55
|
this._add(item);
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -65,14 +66,14 @@ export class Menu {
|
|
|
65
66
|
$('<input type="checkbox"></input>')
|
|
66
67
|
.prop("checked", onByDefault)
|
|
67
68
|
.change(function () {
|
|
68
|
-
callback($(this).prop("checked"));
|
|
69
|
+
callback($(this).prop("checked"), true);
|
|
69
70
|
menu.close();
|
|
70
71
|
})
|
|
71
72
|
)
|
|
72
73
|
.append($("<span></span>").addClass("checkmark"));
|
|
73
74
|
this._add(item, after);
|
|
74
75
|
if (onByDefault) {
|
|
75
|
-
callback(true);
|
|
76
|
+
callback(true, false);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -89,9 +90,8 @@ export class Menu {
|
|
|
89
90
|
.prepend(
|
|
90
91
|
$('<input type="radio"></input>')
|
|
91
92
|
.attr({ "name": name, "value": v})
|
|
92
|
-
.change
|
|
93
|
+
.on("change", function () {
|
|
93
94
|
callback($(this).val())
|
|
94
|
-
menu.close();
|
|
95
95
|
})
|
|
96
96
|
)
|
|
97
97
|
.append($("<span></span>").addClass("checkmark"))
|
|
@@ -102,4 +102,22 @@ export class Menu {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
addLabel(name) {
|
|
107
|
+
const item = $('<div></div>')
|
|
108
|
+
.addClass("label")
|
|
109
|
+
.text(name)
|
|
110
|
+
this._add(item);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
addLink(label, href) {
|
|
114
|
+
const item = $("<a></a>")
|
|
115
|
+
.attr("href", href)
|
|
116
|
+
.attr("target", "_blank")
|
|
117
|
+
.attr("title", label)
|
|
118
|
+
.attr("aria-label", label)
|
|
119
|
+
.addClass("item")
|
|
120
|
+
.text(label);
|
|
121
|
+
this._add(item);
|
|
122
|
+
}
|
|
105
123
|
}
|
|
@@ -47,9 +47,9 @@ const hyphen = '[-\u2014]';
|
|
|
47
47
|
|
|
48
48
|
// everything that we allow immediately before a match
|
|
49
49
|
// (201c = left double quote, 2014 = em dash, 201d = right double quote)
|
|
50
|
-
const begin_guard = '(?:^|(?<=(?:[/\u201c\u2014(]|' + one_ws + '|' + hyphen + ')))';
|
|
50
|
+
const begin_guard = '(?:^|(?<=(?:[/\u201c\u2014([]|' + one_ws + '|' + hyphen + ')))';
|
|
51
51
|
// everything that we allow immediately after a match
|
|
52
|
-
const end_guard = '(?:$|(?=(?:[/,.:;\u201d\u2014)]|' + one_ws + '|' + hyphen + ')))';
|
|
52
|
+
const end_guard = '(?:$|(?=(?:[/,.:;\u201d\u2014)\\]]|' + one_ws + '|' + hyphen + ')))';
|
|
53
53
|
|
|
54
54
|
const ordinal_suffix = '(?:st|nd|rd|th)';
|
|
55
55
|
const day = '[123]?\\d' + ordinal_suffix + '?';
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
|
-
import $ from 'jquery'
|
|
4
|
-
|
|
5
3
|
export class ReportSetOutline {
|
|
6
4
|
constructor(reportSet) {
|
|
7
5
|
this._reportSet = reportSet;
|
|
@@ -173,9 +171,9 @@ export class DocumentOutline {
|
|
|
173
171
|
sortedSections() {
|
|
174
172
|
const sections = Object.keys(this.sections);
|
|
175
173
|
const re = /\(parenthetical\)\s*$/i;
|
|
176
|
-
const filteredSections = sections.filter(s => !re.test(this.report.
|
|
174
|
+
const filteredSections = sections.filter(s => !re.test(this.report.getRoleLabelOrURI(s)));
|
|
177
175
|
return filteredSections
|
|
178
|
-
.sort((a, b) => this.report.
|
|
176
|
+
.sort((a, b) => this.report.getRoleLabelOrURI(a).localeCompare(this.report.getRoleLabelOrURI(b)))
|
|
179
177
|
.map(elr => ({ report: this.report, fact: this.sections[elr], elr: elr }));
|
|
180
178
|
}
|
|
181
179
|
}
|