ixbrl-viewer 1.4.1__py3-none-any.whl → 1.4.86__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.
- iXBRLViewerPlugin/__init__.py +231 -127
- iXBRLViewerPlugin/_version.py +33 -3
- iXBRLViewerPlugin/constants.py +96 -2
- iXBRLViewerPlugin/featureConfig.py +8 -1
- iXBRLViewerPlugin/iXBRLViewer.py +356 -214
- iXBRLViewerPlugin/plugin.py +12 -0
- iXBRLViewerPlugin/ui.py +81 -50
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js +1 -1
- iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js.LICENSE.txt +12 -5
- iXBRLViewerPlugin/viewer/i18next-parser.config.js +1 -1
- iXBRLViewerPlugin/viewer/src/data/utr.json +1244 -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 +2 -2
- iXBRLViewerPlugin/viewer/src/html/inspector.html +352 -197
- 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/da/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/da/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/de/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 +73 -23
- 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 +87 -37
- iXBRLViewerPlugin/viewer/src/i18n/fr/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/fr/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/nl/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/balancetypes.json +4 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/currencies.json +13 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/datatypes.json +9 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/labelroles.json +24 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/referenceparts.json +10 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/scale.json +15 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/tooltips.json +17 -0
- iXBRLViewerPlugin/viewer/src/i18n/uk/translation.json +179 -0
- iXBRLViewerPlugin/viewer/src/icons/calculator.svg +13 -0
- iXBRLViewerPlugin/viewer/src/icons/circle-cross.svg +11 -0
- iXBRLViewerPlugin/viewer/src/icons/circle-tick.svg +11 -0
- iXBRLViewerPlugin/viewer/src/icons/dark-mode.svg +4 -0
- iXBRLViewerPlugin/viewer/src/icons/dimension.svg +1 -5
- iXBRLViewerPlugin/viewer/src/icons/member.svg +2 -5
- iXBRLViewerPlugin/viewer/src/icons/multi-tag.svg +10 -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 +5 -4
- iXBRLViewerPlugin/viewer/src/js/aspect.js +29 -10
- iXBRLViewerPlugin/viewer/src/js/aspect.test.js +40 -31
- iXBRLViewerPlugin/viewer/src/js/balance.js +14 -0
- iXBRLViewerPlugin/viewer/src/js/calculation.js +213 -0
- iXBRLViewerPlugin/viewer/src/js/calculation.test.js +306 -0
- iXBRLViewerPlugin/viewer/src/js/calculationInspector.js +187 -0
- iXBRLViewerPlugin/viewer/src/js/chart.js +26 -24
- iXBRLViewerPlugin/viewer/src/js/chart.test.js +10 -9
- iXBRLViewerPlugin/viewer/src/js/concept.js +37 -4
- iXBRLViewerPlugin/viewer/src/js/concept.test.js +30 -6
- 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/docOrderIndex.js +7 -7
- iXBRLViewerPlugin/viewer/src/js/fact.js +156 -59
- iXBRLViewerPlugin/viewer/src/js/fact.test.js +160 -29
- iXBRLViewerPlugin/viewer/src/js/factset.js +64 -15
- iXBRLViewerPlugin/viewer/src/js/factset.test.js +102 -31
- iXBRLViewerPlugin/viewer/src/js/footnote.js +8 -2
- iXBRLViewerPlugin/viewer/src/js/index.js +11 -3
- iXBRLViewerPlugin/viewer/src/js/inspector.js +747 -221
- iXBRLViewerPlugin/viewer/src/js/inspector.test.js +143 -25
- iXBRLViewerPlugin/viewer/src/js/interval.js +70 -0
- iXBRLViewerPlugin/viewer/src/js/interval.test.js +153 -0
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.js +391 -262
- iXBRLViewerPlugin/viewer/src/js/ixbrlviewer.test.js +134 -20
- iXBRLViewerPlugin/viewer/src/js/ixnode.js +1 -1
- iXBRLViewerPlugin/viewer/src/js/menu.js +25 -7
- iXBRLViewerPlugin/viewer/src/js/number-matcher.js +7 -3
- iXBRLViewerPlugin/viewer/src/js/number-matcher.test.js +4 -0
- iXBRLViewerPlugin/viewer/src/js/outline.js +34 -13
- iXBRLViewerPlugin/viewer/src/js/outline.test.js +97 -91
- iXBRLViewerPlugin/viewer/src/js/period.js +0 -1
- iXBRLViewerPlugin/viewer/src/js/report.js +260 -351
- iXBRLViewerPlugin/viewer/src/js/report.test.js +95 -27
- iXBRLViewerPlugin/viewer/src/js/reportset.js +264 -0
- iXBRLViewerPlugin/viewer/src/js/reportset.test.js +357 -0
- iXBRLViewerPlugin/viewer/src/js/search.js +72 -38
- iXBRLViewerPlugin/viewer/src/js/search.test.js +184 -84
- iXBRLViewerPlugin/viewer/src/js/summary.js +34 -8
- iXBRLViewerPlugin/viewer/src/js/summary.test.js +69 -25
- iXBRLViewerPlugin/viewer/src/js/tableExport.js +9 -9
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.js +34 -0
- iXBRLViewerPlugin/viewer/src/js/taxonomynamer.test.js +32 -0
- iXBRLViewerPlugin/viewer/src/js/test-utils.js +46 -0
- iXBRLViewerPlugin/viewer/src/js/theme.js +50 -0
- iXBRLViewerPlugin/viewer/src/js/unit.js +90 -32
- iXBRLViewerPlugin/viewer/src/js/unit.test.js +62 -25
- iXBRLViewerPlugin/viewer/src/js/util.js +94 -0
- iXBRLViewerPlugin/viewer/src/js/util.test.js +33 -1
- iXBRLViewerPlugin/viewer/src/js/utr.js +27 -0
- iXBRLViewerPlugin/viewer/src/js/viewer.js +205 -181
- iXBRLViewerPlugin/viewer/src/js/viewerOptions.js +0 -2
- iXBRLViewerPlugin/viewer/src/less/accordian.less +10 -6
- iXBRLViewerPlugin/viewer/src/less/block-list.less +16 -5
- iXBRLViewerPlugin/viewer/src/less/calculation-inspector.less +83 -0
- iXBRLViewerPlugin/viewer/src/less/chart.less +8 -5
- iXBRLViewerPlugin/viewer/src/less/colours-dark-mode.less +40 -0
- iXBRLViewerPlugin/viewer/src/less/colours.less +32 -20
- iXBRLViewerPlugin/viewer/src/less/common.less +3 -3
- iXBRLViewerPlugin/viewer/src/less/components.less +6 -4
- iXBRLViewerPlugin/viewer/src/less/core.less +2 -0
- iXBRLViewerPlugin/viewer/src/less/dialog.less +21 -14
- iXBRLViewerPlugin/viewer/src/less/form-controls.less +33 -11
- iXBRLViewerPlugin/viewer/src/less/inspector.less +1045 -726
- 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 +9 -9
- iXBRLViewerPlugin/viewer/src/less/text-block-viewer.less +2 -0
- iXBRLViewerPlugin/viewer/src/less/text-mixins.less +2 -1
- iXBRLViewerPlugin/viewer/src/less/validation-report.less +2 -3
- iXBRLViewerPlugin/viewer/src/less/viewer.less +105 -74
- iXBRLViewerPlugin/viewer/webpack.common.js +19 -9
- iXBRLViewerPlugin/xhtmlserialize.py +59 -45
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/METADATA +181 -50
- ixbrl_viewer-1.4.86.dist-info/RECORD +217 -0
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/WHEEL +1 -1
- ixbrl_viewer-1.4.1.dist-info/LICENSE → ixbrl_viewer-1.4.86.dist-info/licenses/LICENSE.md +8 -14
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/top_level.txt +0 -1
- iXBRLViewerPlugin/viewer/src/js/calculations.js +0 -111
- iXBRLViewerPlugin/viewer/src/js/interact.min.js +0 -6
- ixbrl_viewer-1.4.1.dist-info/RECORD +0 -155
- tests/__init__.py +0 -0
- tests/puppeteer/framework/core_elements.js +0 -117
- tests/puppeteer/framework/page_objects/doc_frame.js +0 -105
- tests/puppeteer/framework/page_objects/fact_details_panel.js +0 -80
- tests/puppeteer/framework/page_objects/search_panel.js +0 -76
- tests/puppeteer/framework/page_objects/toolbar.js +0 -18
- tests/puppeteer/framework/utils.js +0 -3
- tests/puppeteer/framework/viewer_page.js +0 -103
- tests/puppeteer/puppeteer_test_run_via_intellij.jpg +0 -0
- tests/puppeteer/test_filings/filing_documents_smoke_test.zip +0 -0
- tests/puppeteer/test_filings/highlights.zip +0 -0
- tests/puppeteer/tests/fact_properties.test.js +0 -78
- tests/puppeteer/tests/highlight.test.js +0 -186
- tests/puppeteer/tests/search.test.js +0 -86
- tests/puppeteer/tools/generate.sh +0 -15
- tests/unit_tests/__init__.py +0 -0
- tests/unit_tests/iXBRLViewerPlugin/__init__.py +0 -0
- tests/unit_tests/iXBRLViewerPlugin/mock_arelle.py +0 -39
- tests/unit_tests/iXBRLViewerPlugin/test_iXBRLViewer.py +0 -641
- tests/unit_tests/iXBRLViewerPlugin/test_xhtmlserialize.py +0 -310
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info}/entry_points.txt +0 -0
- {ixbrl_viewer-1.4.1.dist-info → ixbrl_viewer-1.4.86.dist-info/licenses}/NOTICE +0 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# See COPYRIGHT.md for copyright information
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
5
|
import re
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import IO
|
|
8
|
+
|
|
9
|
+
from lxml import etree
|
|
6
10
|
|
|
7
11
|
XHTML_NS = 'http://www.w3.org/1999/xhtml'
|
|
8
12
|
XML_NS = 'http://www.w3.org/XML/1998/namespace'
|
|
@@ -34,31 +38,31 @@ class XHTMLSerializer:
|
|
|
34
38
|
ATTR_ESCAPE_RE = re.compile('([' + MUST_ESCAPE_CHARS + '>"])')
|
|
35
39
|
STYLE_ESCAPE_RE = re.compile('([' + MUST_ESCAPE_CHARS + ']|' + CDATA_END + ')')
|
|
36
40
|
|
|
37
|
-
def __init__(self, fout, xml_declaration = True, assume_xhtml = True):
|
|
41
|
+
def __init__(self, fout: IO[bytes], xml_declaration: bool = True, assume_xhtml: bool = True) -> None:
|
|
38
42
|
self.fout = fout
|
|
39
43
|
self.encoding = "utf-8"
|
|
40
44
|
self.xml_declaration = xml_declaration
|
|
41
45
|
self.assume_xhtml = assume_xhtml
|
|
42
46
|
|
|
43
|
-
def write(self, s):
|
|
47
|
+
def write(self, s: str) -> None:
|
|
44
48
|
self.fout.write(s.encode(self.encoding))
|
|
45
49
|
|
|
46
|
-
def prefix_sort(self, p):
|
|
50
|
+
def prefix_sort(self, p: str | None) -> str:
|
|
47
51
|
return p if p is not None else '0'
|
|
48
52
|
|
|
49
|
-
def qname_for_node(self, node):
|
|
50
|
-
qname = etree.QName(node
|
|
53
|
+
def qname_for_node(self, node: etree._Element) -> str:
|
|
54
|
+
qname = etree.QName(node)
|
|
51
55
|
if qname.namespace is None:
|
|
52
56
|
prefix = None
|
|
53
57
|
elif node.nsmap.get(node.prefix, None) == qname.namespace:
|
|
54
58
|
prefix = node.prefix
|
|
55
59
|
else:
|
|
56
|
-
prefix = next(iter(sorted((p for p, ns in nsmap.items() if ns == qname.namespace), key = self.prefix_sort)))
|
|
60
|
+
prefix = next(iter(sorted((p for p, ns in node.nsmap.items() if ns == qname.namespace), key = self.prefix_sort)))
|
|
57
61
|
if prefix is None:
|
|
58
62
|
return qname.localname
|
|
59
|
-
return "
|
|
63
|
+
return f"{prefix}:{qname.localname}"
|
|
60
64
|
|
|
61
|
-
def qname_for_attr(self, tag, nsmap):
|
|
65
|
+
def qname_for_attr(self, tag: etree._Element | str, nsmap: dict[str | None, str]) -> str:
|
|
62
66
|
qname = etree.QName(tag)
|
|
63
67
|
if qname.namespace is None:
|
|
64
68
|
return qname.localname
|
|
@@ -66,9 +70,9 @@ class XHTMLSerializer:
|
|
|
66
70
|
prefix = 'xml'
|
|
67
71
|
else:
|
|
68
72
|
prefix = next(iter(sorted((p for p, ns in nsmap.items() if ns == qname.namespace and p is not None), key = self.prefix_sort)))
|
|
69
|
-
return "
|
|
73
|
+
return f"{prefix}:{qname.localname}"
|
|
70
74
|
|
|
71
|
-
def is_selfclosable(self, n):
|
|
75
|
+
def is_selfclosable(self, n: etree._Element | str) -> bool:
|
|
72
76
|
qname = etree.QName(n)
|
|
73
77
|
return (
|
|
74
78
|
qname.localname in XHTMLSerializer.SELF_CLOSABLE
|
|
@@ -76,22 +80,22 @@ class XHTMLSerializer:
|
|
|
76
80
|
qname.namespace == XHTML_NS
|
|
77
81
|
or (self.assume_xhtml and qname.namespace is None)))
|
|
78
82
|
|
|
79
|
-
def escape_attr(self, s):
|
|
83
|
+
def escape_attr(self, s: str) -> str:
|
|
80
84
|
return self.ATTR_ESCAPE_RE.sub(lambda m: self.escape_str(m[0]), s)
|
|
81
85
|
|
|
82
|
-
def xmlns_declaration(self, prefix, uri):
|
|
86
|
+
def xmlns_declaration(self, prefix: str | None, uri: str) -> str:
|
|
83
87
|
if prefix is None:
|
|
84
|
-
return 'xmlns="
|
|
85
|
-
return 'xmlns
|
|
88
|
+
return f'xmlns="{self.escape_attr(uri)}"'
|
|
89
|
+
return f'xmlns:{prefix}="{self.escape_attr(uri)}"'
|
|
86
90
|
|
|
87
|
-
def namespace_declarations(self, new_nsmap, cur_nsmap):
|
|
91
|
+
def namespace_declarations(self, new_nsmap: dict[str | None, str], cur_nsmap: dict[str | None, str]) -> list[str]:
|
|
88
92
|
changed = set(p[0] for p in (set(new_nsmap.items()) ^ set(cur_nsmap.items())))
|
|
89
93
|
return sorted(self.xmlns_declaration(p, new_nsmap[p]) for p in changed)
|
|
90
94
|
|
|
91
|
-
def escape_str(self, c):
|
|
92
|
-
return self.ESCAPES.get(c, '&#x
|
|
95
|
+
def escape_str(self, c: str) -> str:
|
|
96
|
+
return self.ESCAPES.get(c, f'&#x{ord(c[0]):02X};')
|
|
93
97
|
|
|
94
|
-
def write_escape_text(self, s, escape_mode):
|
|
98
|
+
def write_escape_text(self, s: str | None, escape_mode: EscapeMode) -> None:
|
|
95
99
|
if s is None:
|
|
96
100
|
return
|
|
97
101
|
if escape_mode == EscapeMode.STYLE:
|
|
@@ -105,24 +109,31 @@ class XHTMLSerializer:
|
|
|
105
109
|
else:
|
|
106
110
|
self.write(self.ESCAPE_RE.sub(lambda m: self.escape_str(m[0]),s))
|
|
107
111
|
|
|
108
|
-
def write_attributes(self, node):
|
|
112
|
+
def write_attributes(self, node: etree._Element) -> None:
|
|
109
113
|
for qname, value in sorted((self.qname_for_attr(k, node.nsmap), v) for k, v in node.items()):
|
|
110
|
-
self.write('
|
|
114
|
+
self.write(f' {qname}="')
|
|
111
115
|
self.write(self.escape_attr(value))
|
|
112
116
|
self.write("\"")
|
|
113
117
|
|
|
114
|
-
def write_comment(self, n, escape_mode):
|
|
118
|
+
def write_comment(self, n: etree._Comment, escape_mode: EscapeMode) -> None:
|
|
115
119
|
self.write('<!--' + n.text + '-->')
|
|
116
120
|
self.write_escape_text(n.tail, escape_mode)
|
|
117
121
|
|
|
118
|
-
def write_processing_instruction(self, n, escape_mode):
|
|
122
|
+
def write_processing_instruction(self, n: etree._ProcessingInstruction, escape_mode: EscapeMode) -> None:
|
|
119
123
|
self.write( '<?' + n.target )
|
|
120
124
|
if n.text != '':
|
|
121
125
|
self.write(' ' + n.text)
|
|
122
126
|
self.write('?>')
|
|
123
127
|
self.write_escape_text(n.tail, escape_mode)
|
|
124
128
|
|
|
125
|
-
def write_node(
|
|
129
|
+
def write_node(
|
|
130
|
+
self,
|
|
131
|
+
n: etree._Element,
|
|
132
|
+
nsmap: dict[str | None, str] | None = None,
|
|
133
|
+
escape_mode: EscapeMode = EscapeMode.DEFAULT,
|
|
134
|
+
) -> None:
|
|
135
|
+
if nsmap is None:
|
|
136
|
+
nsmap = {}
|
|
126
137
|
if isinstance(n, etree._Comment):
|
|
127
138
|
self.write_comment(n, escape_mode)
|
|
128
139
|
elif isinstance(n, etree._ProcessingInstruction):
|
|
@@ -130,18 +141,22 @@ class XHTMLSerializer:
|
|
|
130
141
|
else:
|
|
131
142
|
self.write_element(n, nsmap, escape_mode)
|
|
132
143
|
|
|
133
|
-
def write_element(
|
|
144
|
+
def write_element(
|
|
145
|
+
self,
|
|
146
|
+
n: etree._Element,
|
|
147
|
+
parent_nsmap: dict[str | None, str] | None = None,
|
|
148
|
+
escape_mode: EscapeMode = EscapeMode.DEFAULT,
|
|
149
|
+
) -> None:
|
|
150
|
+
if parent_nsmap is None:
|
|
151
|
+
parent_nsmap = {}
|
|
134
152
|
name = self.qname_for_node(n)
|
|
135
|
-
qname = etree.QName(n
|
|
153
|
+
qname = etree.QName(n)
|
|
136
154
|
selfclose = len(n) == 0 and n.text is None and self.is_selfclosable(n)
|
|
137
|
-
parts = [ name ] + self.namespace_declarations(n.nsmap, parent_nsmap)
|
|
155
|
+
parts = [ name ] + self.namespace_declarations(n.nsmap, parent_nsmap)
|
|
138
156
|
self.write('<' + ' '.join(parts))
|
|
139
157
|
self.write_attributes(n)
|
|
140
158
|
|
|
141
|
-
if qname.localname == 'style'
|
|
142
|
-
inner_escape_mode = EscapeMode.STYLE
|
|
143
|
-
else:
|
|
144
|
-
inner_escape_mode = escape_mode
|
|
159
|
+
inner_escape_mode = EscapeMode.STYLE if qname.localname == 'style' else escape_mode
|
|
145
160
|
|
|
146
161
|
if selfclose:
|
|
147
162
|
self.write('/>')
|
|
@@ -150,11 +165,11 @@ class XHTMLSerializer:
|
|
|
150
165
|
self.write_escape_text(n.text, inner_escape_mode)
|
|
151
166
|
for child in n.iterchildren():
|
|
152
167
|
self.write_node(child, n.nsmap, inner_escape_mode)
|
|
153
|
-
self.write('
|
|
168
|
+
self.write(f'</{name}>')
|
|
154
169
|
|
|
155
170
|
self.write_escape_text(n.tail, escape_mode)
|
|
156
171
|
|
|
157
|
-
def write_xml_declaration(self, docinfo = None):
|
|
172
|
+
def write_xml_declaration(self, docinfo: etree.DocInfo | None = None) -> None:
|
|
158
173
|
if self.xml_declaration:
|
|
159
174
|
version = "1.0"
|
|
160
175
|
standalone = ""
|
|
@@ -162,23 +177,22 @@ class XHTMLSerializer:
|
|
|
162
177
|
version = docinfo.xml_version
|
|
163
178
|
if docinfo.standalone:
|
|
164
179
|
standalone = ' standalone="yes"'
|
|
165
|
-
self.write('<?xml version="
|
|
180
|
+
self.write(f'<?xml version="{version}" encoding="{self.encoding}"{standalone}?>\n')
|
|
166
181
|
|
|
167
|
-
def serialize(self, element):
|
|
168
|
-
if
|
|
182
|
+
def serialize(self, element: etree._ElementTree[etree._Element] | etree._Element) -> None:
|
|
183
|
+
if isinstance(element, etree._ElementTree):
|
|
169
184
|
self.write_xml_declaration(element.docinfo)
|
|
170
185
|
|
|
171
|
-
|
|
172
|
-
while
|
|
173
|
-
|
|
186
|
+
node: etree._Element | None = element.getroot()
|
|
187
|
+
while node is not None and node.getprevious() is not None:
|
|
188
|
+
node = node.getprevious()
|
|
174
189
|
|
|
175
|
-
while
|
|
176
|
-
self.write_node(
|
|
177
|
-
if isinstance(
|
|
190
|
+
while node is not None:
|
|
191
|
+
self.write_node(node)
|
|
192
|
+
if isinstance(node, (etree._Comment, etree._ProcessingInstruction)):
|
|
178
193
|
self.write("\n")
|
|
179
|
-
|
|
194
|
+
node = node.getnext()
|
|
180
195
|
|
|
181
196
|
else:
|
|
182
197
|
self.write_xml_declaration()
|
|
183
198
|
self.write_element(element)
|
|
184
|
-
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: ixbrl-viewer
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.86
|
|
4
4
|
Summary: The Arelle iXBRL Viewer allows iXBRL reports to be viewed interactively in a web browser.
|
|
5
5
|
Author-email: "arelle.org" <support@arelle.org>
|
|
6
|
-
License: Apache-2.0
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
7
|
Project-URL: Homepage, https://arelle.org/
|
|
8
8
|
Project-URL: Downloads, https://arelle.org/arelle/pub/
|
|
9
9
|
Project-URL: Documentation, https://arelle.org/arelle/documentation/
|
|
@@ -16,64 +16,115 @@ Platform: any
|
|
|
16
16
|
Classifier: Development Status :: 5 - Production/Stable
|
|
17
17
|
Classifier: Intended Audience :: End Users/Desktop
|
|
18
18
|
Classifier: Intended Audience :: Developers
|
|
19
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
20
19
|
Classifier: Natural Language :: English
|
|
21
20
|
Classifier: Programming Language :: Python :: 3
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
24
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
25
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
26
|
Classifier: Operating System :: OS Independent
|
|
27
27
|
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
28
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
|
-
License-File: LICENSE
|
|
30
|
+
License-File: LICENSE.md
|
|
31
31
|
License-File: NOTICE
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: lxml
|
|
34
|
-
|
|
32
|
+
Requires-Dist: bottle<0.14,>=0.13
|
|
33
|
+
Requires-Dist: lxml<7,>=4
|
|
34
|
+
Provides-Extra: arelle
|
|
35
|
+
Requires-Dist: arelle_release==2.*; extra == "arelle"
|
|
35
36
|
Provides-Extra: dev
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: flake8==7.3.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy==1.19.1; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest==9.0.2; extra == "dev"
|
|
40
|
+
Requires-Dist: types-lxml==2026.1.1; extra == "dev"
|
|
41
|
+
Requires-Dist: typing-extensions==4.15.0; extra == "dev"
|
|
42
|
+
Dynamic: license-file
|
|
38
43
|
|
|
39
44
|
# Arelle iXBRL Viewer
|
|
40
45
|
|
|
46
|
+
[](https://pypi.org/project/ixbrl-viewer/)
|
|
47
|
+
[](https://pypi.org/project/ixbrl-viewer/)
|
|
48
|
+
[](https://www.npmjs.com/package/ixbrl-viewer)
|
|
49
|
+
[](https://arelle-ixbrl-viewer.readthedocs.io/)
|
|
50
|
+
|
|
41
51
|

|
|
42
52
|
|
|
53
|
+
## Table of Contents
|
|
54
|
+
|
|
55
|
+
- [Arelle iXBRL Viewer](#arelle-ixbrl-viewer)
|
|
56
|
+
- [Table of Contents](#table-of-contents)
|
|
57
|
+
- [Description](#description)
|
|
58
|
+
- [Documentation](#documentation)
|
|
59
|
+
- [Installation](#installation)
|
|
60
|
+
- [Accessing the JavaScript viewer application](#accessing-the-javascript-viewer-application)
|
|
61
|
+
- [Accessing via the CDN](#accessing-via-the-cdn)
|
|
62
|
+
- [Accessing via Github](#accessing-via-github)
|
|
63
|
+
- [Building the JavaScript locally](#building-the-javascript-locally)
|
|
64
|
+
- [JavaScript Versioning](#javascript-versioning)
|
|
65
|
+
- [Producing an ixbrl-viewer via the Arelle GUI](#producing-an-ixbrl-viewer-via-the-arelle-gui)
|
|
66
|
+
- [Preparing an iXBRL file via the GUI](#preparing-an-ixbrl-file-via-the-gui)
|
|
67
|
+
- [Preparing an iXBRL document set using the Arelle GUI](#preparing-an-ixbrl-document-set-using-the-arelle-gui)
|
|
68
|
+
- [Producing an ixbrl-viewer via the Arelle command line](#producing-an-ixbrl-viewer-via-the-arelle-command-line)
|
|
69
|
+
- [Preparing an iXBRL file via the command line](#preparing-an-ixbrl-file-via-the-command-line)
|
|
70
|
+
- [Preparing an iXBRL document set](#preparing-an-ixbrl-document-set)
|
|
71
|
+
- [Using build-viewer.py](#using-build-viewerpy)
|
|
72
|
+
- [Stub viewer mode](#stub-viewer-mode)
|
|
73
|
+
- [Optional Features](#optional-features)
|
|
74
|
+
- [Feature: Review Mode](#feature-review-mode)
|
|
75
|
+
- [Runtime config](#runtime-config)
|
|
76
|
+
- [Disable viewer loading](#disable-viewer-loading)
|
|
77
|
+
- [Running tests](#running-tests)
|
|
78
|
+
- [Running unit tests](#running-unit-tests)
|
|
79
|
+
- [Running Puppeteer tests](#running-puppeteer-tests)
|
|
80
|
+
- [👥 Contributors](#-contributors)
|
|
81
|
+
- [License](#license)
|
|
82
|
+
|
|
83
|
+
## Description
|
|
84
|
+
|
|
43
85
|
The [Arelle](https://arelle.org/) iXBRL Viewer allows [Inline XBRL](https://www.xbrl.org/ixbrl) (or iXBRL) reports to be
|
|
44
86
|
viewed interactively in a web browser. The viewer allows users to access the tagged XBRL data embedded in an iXBRL
|
|
45
87
|
report. Key features include:
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
89
|
+
- Full text search on taxonomy labels and references
|
|
90
|
+
- View full details of tagged facts
|
|
91
|
+
- Export tables to Excel
|
|
92
|
+
- Visualize and navigate calculation relationships
|
|
93
|
+
- Produce on-the-fly graphs using XBRL data
|
|
52
94
|
|
|
53
95
|
A sample viewer is provided in the [examples](https://github.com/Arelle/ixbrl-viewer/blob/master/examples/README.md) for those interested.
|
|
54
96
|
|
|
55
97
|
The viewer project consists of two components:
|
|
56
98
|
|
|
57
|
-
|
|
58
|
-
|
|
99
|
+
- A plugin for the [Arelle](https://www.arelle.org) XBRL tool
|
|
100
|
+
- The Javascript viewer application
|
|
59
101
|
|
|
60
102
|
In order to view an iXBRL report in the viewer, it must first be prepared using
|
|
61
103
|
the Arelle plugin. The preparation process updates the iXBRL file to include:
|
|
62
104
|
|
|
63
|
-
1. A link to the
|
|
105
|
+
1. A link to the JavaScript viewer
|
|
64
106
|
2. A block of JSON data that contains the results of processing the XBRL data and associated taxonomy
|
|
65
107
|
|
|
66
|
-
Once prepared, the resulting file provides an entirely standalone viewer
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
108
|
+
Once prepared, the resulting file provides an entirely standalone viewer, and
|
|
109
|
+
does not require access to the taxonomy, or to any online services. The only
|
|
110
|
+
dependency is on the JavaScript viewer application, which is a single file
|
|
111
|
+
which can be accessed directly online, downloaded or built locally.
|
|
112
|
+
|
|
113
|
+
It is also possible to place the link to the viewer, and the block of JSON data
|
|
114
|
+
in a separate file. See Stub Viewer Mode below.
|
|
115
|
+
|
|
116
|
+
The JavaScript viewer application is a single JavaScript file called ixbrlviewer.js. It
|
|
117
|
+
contains all of the JavaScript that runs the viewer functionality.
|
|
70
118
|
|
|
71
|
-
|
|
72
|
-
|
|
119
|
+
## Documentation
|
|
120
|
+
|
|
121
|
+
Need help with the Arelle iXBRL Viewer? Go check out [our documentation][read-the-docs].
|
|
122
|
+
|
|
123
|
+
[read-the-docs]: https://arelle-ixbrl-viewer.readthedocs.io/
|
|
73
124
|
|
|
74
125
|
## Installation
|
|
75
126
|
|
|
76
|
-
The
|
|
127
|
+
The Python portion of this repo is developed using Python 3.14.
|
|
77
128
|
|
|
78
129
|
1. Clone the [iXBRL Viewer git repository][ixbrlviewer-github].
|
|
79
130
|
2. Download and install [Arelle][arelle-download]
|
|
@@ -113,11 +164,15 @@ the ixbrl-viewer.
|
|
|
113
164
|
|
|
114
165
|
## JavaScript Versioning
|
|
115
166
|
|
|
116
|
-
The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a
|
|
117
|
-
by the JavaScript. The metadata produced
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
167
|
+
The ixbrl-viewer plugin embeds processed XBRL metadata in the HTML that has a
|
|
168
|
+
specific format read by the JavaScript. The metadata produced will work with a
|
|
169
|
+
viewer application that has the same major version, and the same or later minor
|
|
170
|
+
version as the plugin used to create it.
|
|
171
|
+
|
|
172
|
+
This means that once an XBRL report has been prepared by the plugin, the
|
|
173
|
+
associated JavaScript viewer application can be upgraded within the same major
|
|
174
|
+
version. Any features introduced in newer versions of the viewer that rely on
|
|
175
|
+
additional metadata will degrade gracefully if that metadata is not present.
|
|
121
176
|
|
|
122
177
|
## Producing an ixbrl-viewer via the Arelle GUI
|
|
123
178
|
|
|
@@ -163,9 +218,9 @@ python3 Arelle/arelleCmdLine.py --plugins=<path to iXBRLViewerPlugin> -f ixbrl-r
|
|
|
163
218
|
|
|
164
219
|
Notes:
|
|
165
220
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
221
|
+
- "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
|
|
222
|
+
- The plugin path needs to an absolute file path to the ixbrl-viewer plugin
|
|
223
|
+
- The viewer url can be one of the following:
|
|
169
224
|
|
|
170
225
|
1. `https://cdn.jsdelivr.net/npm/ixbrl-viewer@<version>/iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js`
|
|
171
226
|
2. A relative url to the downloaded ixviewer.js from github
|
|
@@ -195,17 +250,20 @@ python3 Arelle/arelleCmdLine.py --plugins '/path/to/iXBRLViewerPlugin|inlineXbrl
|
|
|
195
250
|
|
|
196
251
|
Notes:
|
|
197
252
|
|
|
198
|
-
|
|
253
|
+
- The first file specified is the "primary" file, and should be opened in a
|
|
199
254
|
browser to use the viewer. The other files will be loaded in separate tabs
|
|
200
255
|
within the viewer.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
256
|
+
- "Arelle/arelleCmdLine.py" should be the path to your installation of Arelle
|
|
257
|
+
- The plugin path needs to an absolute file path to the ixbrl-viewer plugin
|
|
258
|
+
- The viewer url can be one of the following:
|
|
204
259
|
|
|
205
260
|
1. `https://cdn.jsdelivr.net/npm/ixbrl-viewer@<version>/iXBRLViewerPlugin/viewer/dist/ixbrlviewer.js`
|
|
206
261
|
2. A relative url to the downloaded ixviewer.js from github
|
|
207
262
|
3. A relative url to the locally built ixviewer.js
|
|
208
263
|
|
|
264
|
+
- Due to browser security restrictions, the resulting viewer cannot be loaded
|
|
265
|
+
directly from `file:` URLs; it must be served by a web server.
|
|
266
|
+
|
|
209
267
|
### Using build-viewer.py
|
|
210
268
|
|
|
211
269
|
As an alternative to the standard Arelle command line, the
|
|
@@ -229,10 +287,33 @@ e.g.
|
|
|
229
287
|
```shell
|
|
230
288
|
PYTHONPATH=/path/to/Arelle:/path/to/ixbrl-viewer ./samples/build-viewer.py --out out-dir --package-dir /my/packages/ ixds-dir
|
|
231
289
|
```
|
|
232
|
-
|
|
290
|
+
|
|
291
|
+
## Stub viewer mode
|
|
292
|
+
|
|
293
|
+
By default, the link to the JavaScript viewer and the JSON data block are added
|
|
294
|
+
to the iXBRL report file (or to the first file, in the case of a document set).
|
|
295
|
+
|
|
296
|
+
Stub viewer mode is an optional generation mode that creates an additional,
|
|
297
|
+
minimal HTML file containing the JSON data block, and the link to the
|
|
298
|
+
JavaScript viewer. This mode has two advantages over the default approach of
|
|
299
|
+
embedding the JSON data and JavaScript link in the iXBRL report:
|
|
300
|
+
|
|
301
|
+
1. Provided that all facts and footnotes in the iXBRL report already have ID
|
|
302
|
+
attributes, no modification of the iXBRL report is required.
|
|
303
|
+
2. The iXBRL viewer loading mask will be displayed much more quickly. This is
|
|
304
|
+
helpful for very large iXBRL reports which can otherwise result in a long
|
|
305
|
+
delay before there is any sign of the iXBRL Viewer loading.
|
|
306
|
+
|
|
307
|
+
The downside of this mode is that due to browser security restrictions, the
|
|
308
|
+
viewer cannot be loaded directly from files (using `file:` URLs); they must be
|
|
309
|
+
served by a web server.
|
|
310
|
+
|
|
311
|
+
## Optional Features
|
|
312
|
+
|
|
233
313
|
Some features are disabled by default but can be enabled at generation time or with query parameters.
|
|
234
314
|
|
|
235
315
|
To enable features:
|
|
316
|
+
|
|
236
317
|
- Via CLI: `--viewer-feature-{feature name}`
|
|
237
318
|
- Via query parameter:`?{feature name}=true`
|
|
238
319
|
|
|
@@ -251,7 +332,8 @@ This table uses the 'review' feature as an example to demonstrate how these opti
|
|
|
251
332
|
| `review` | `true` | `enabled` |
|
|
252
333
|
| `review` | `false` | `disabled` |
|
|
253
334
|
|
|
254
|
-
|
|
335
|
+
### Feature: Review Mode
|
|
336
|
+
|
|
255
337
|

|
|
256
338
|
|
|
257
339
|
A review mode is available that is intended to assist in reviewing partially tagged or incomplete documents.
|
|
@@ -261,6 +343,40 @@ This mode replaces the namespace-based highlighting with optional highlighting b
|
|
|
261
343
|
|---------------------------|----------------|
|
|
262
344
|
| `--viewer-feature-review` | `?review=true` |
|
|
263
345
|
|
|
346
|
+
## Runtime config
|
|
347
|
+
|
|
348
|
+
When launched, the viewer will check for the existence of
|
|
349
|
+
`ixbrlviewer.config.json` in the same directory as `ixbrlviewer.js`. If found,
|
|
350
|
+
this will be loaded and used to configure the viewer.
|
|
351
|
+
|
|
352
|
+
The file supports the following keys:
|
|
353
|
+
|
|
354
|
+
- `features` - a JSON object containing defaults for features. These will be
|
|
355
|
+
overridden by features defined at generation time, and then by query
|
|
356
|
+
parameters, as defined above.
|
|
357
|
+
|
|
358
|
+
- `skin` - a JSON object supporting the following keys:
|
|
359
|
+
|
|
360
|
+
- `stylesheetUrl` - a URL to additional CSS definitions.
|
|
361
|
+
- `faviconUrl` - a URL to an icon file to be used as the favicon for the viewer.
|
|
362
|
+
- `footerLogoHtml` - a fragment of HTML that will be included in place of the standard footer logo.
|
|
363
|
+
|
|
364
|
+
- `taxonomyNames` - a JSON object where:
|
|
365
|
+
|
|
366
|
+
- Keys are strings that will be treated as a regular expression to match
|
|
367
|
+
against a namespace.
|
|
368
|
+
- Values are an array of (prefix, name) where "prefix" is the preferred
|
|
369
|
+
namespace prefix for the namespace, and "name" is a short descriptive
|
|
370
|
+
name for the taxonomy.
|
|
371
|
+
|
|
372
|
+
Relative URLs defined in the config file are resolved relative to the config file.
|
|
373
|
+
|
|
374
|
+
## Disable viewer loading
|
|
375
|
+
|
|
376
|
+
Loading of the viewer can be disabled by specifying `?disable-viewer` as a
|
|
377
|
+
query parameter. This will leave the iXBRL document loaded in the browser, but
|
|
378
|
+
without any viewer functionality. In the case of an iXBRL document set, or
|
|
379
|
+
multi-document viewer, the first document will be shown.
|
|
264
380
|
|
|
265
381
|
## Running tests
|
|
266
382
|
|
|
@@ -272,7 +388,7 @@ Run the following command to run javascript unit tests: `npm run test`
|
|
|
272
388
|
|
|
273
389
|
In order to run the python unit tests make sure that you have pip installed requirements-dev.txt.
|
|
274
390
|
|
|
275
|
-
Run the following command to run python unit tests: `
|
|
391
|
+
Run the following command to run python unit tests: `pytest tests/unit_tests`
|
|
276
392
|
|
|
277
393
|
### Running Puppeteer tests
|
|
278
394
|
|
|
@@ -282,7 +398,7 @@ All commands should be run from repository root
|
|
|
282
398
|
2. Install Arelle
|
|
283
399
|
|
|
284
400
|
```shell
|
|
285
|
-
pip install arelle
|
|
401
|
+
pip install .[arelle]
|
|
286
402
|
```
|
|
287
403
|
|
|
288
404
|
3. [Terminal 1] Start the puppeteer serve
|
|
@@ -291,16 +407,31 @@ All commands should be run from repository root
|
|
|
291
407
|
npm run puppeteerServe
|
|
292
408
|
```
|
|
293
409
|
|
|
294
|
-
|
|
295
|
-
|
|
410
|
+
- This command generates the `ixbrlviewer.js`, uses Arelle to generate several test files, then serves the files via a nodejs http-server.
|
|
411
|
+
- Currently changes to application code require restarting this step to take effect.
|
|
296
412
|
4. Start the puppeteer tests
|
|
297
|
-
|
|
413
|
+
- [Terminal 2]:
|
|
298
414
|
|
|
299
415
|
```shell
|
|
300
416
|
npm run test:puppeteer
|
|
301
417
|
```
|
|
302
418
|
|
|
303
|
-
|
|
304
|
-
|
|
419
|
+
- IDE:
|
|
420
|
+
- Many of the IDE's on the market can run tests via the UI. The following is an example configuration for intellij. Once set you can right-click on the test name or file and select the run option.
|
|
305
421
|

|
|
306
|
-
|
|
422
|
+
- Debug runs with breakpoints are also typically supported.
|
|
423
|
+
|
|
424
|
+
## 👥 Contributors
|
|
425
|
+
|
|
426
|
+
<div align="center">
|
|
427
|
+
<a href="https://github.com/Arelle/ixbrl-viewer/graphs/contributors">
|
|
428
|
+
<img src="https://contrib.rocks/image?repo=Arelle/ixbrl-viewer&max=100&columns=10" style="margin: 5px;" />
|
|
429
|
+
</a>
|
|
430
|
+
<p>Join our community and become a contributor today! 🚀 </p>
|
|
431
|
+
</div>
|
|
432
|
+
|
|
433
|
+
## License
|
|
434
|
+
|
|
435
|
+
[Apache License 2.0][license]
|
|
436
|
+
|
|
437
|
+
[license]: https://arelle-ixbrl-viewer.readthedocs.io/en/latest/license.html
|