ixbrl-viewer 1.4.38__py3-none-any.whl → 1.4.40__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ixbrl-viewer might be problematic. Click here for more details.

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 +26 -15
  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.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/METADATA +33 -5
  87. {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/RECORD +95 -66
  88. {ixbrl_viewer-1.4.38.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.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/LICENSE +0 -0
  93. {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/NOTICE +0 -0
  94. {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/entry_points.txt +0 -0
  95. {ixbrl_viewer-1.4.38.dist-info → ixbrl_viewer-1.4.40.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,7 @@ import tempfile
10
10
  import traceback
11
11
  from optparse import OptionGroup, OptionParser
12
12
  from pathlib import Path
13
+ from typing import Any
13
14
 
14
15
  from arelle import Cntlr
15
16
  from arelle.LocalViewer import LocalViewer
@@ -100,8 +101,14 @@ def iXBRLViewerCommandLineOptionExtender(parser, *args, **kwargs):
100
101
  featureGroup = OptionGroup(parser, "Viewer Features",
101
102
  "See viewer README for information on enabling/disabling features.")
102
103
  for featureConfig in FEATURE_CONFIGS:
103
- arg = f'--viewer-feature-{featureConfig.key}'
104
- featureGroup.add_option(arg, arg.lower(), action="store_true", default=False, help=featureConfig.description)
104
+ arg = f'--viewer-feature-{featureConfig.key}'.replace('_', '-')
105
+ featureGroup.add_option(
106
+ arg,
107
+ arg.lower(),
108
+ action=featureConfig.cliAction,
109
+ default=featureConfig.cliDefault,
110
+ help=featureConfig.description
111
+ )
105
112
  parser.add_option_group(featureGroup)
106
113
 
107
114
  def pluginData(cntlr: Cntlr):
@@ -130,7 +137,6 @@ def generateViewer(
130
137
  viewerURL: str | None = None,
131
138
  showValidationMessages: bool = False,
132
139
  zipViewerOutput: bool = False,
133
- features: list[str] | None = None,
134
140
  packageDownloadURL: str | None = None,
135
141
  copyScript: bool = True,
136
142
  ) -> None:
@@ -143,7 +149,6 @@ def generateViewer(
143
149
  :param showValidationMessages: True if validation messages should be shown in the viewer.
144
150
  :param useStubViewer: True if the stub viewer should be used.
145
151
  :param zipViewerOutput: True if the destination is a zip archive.
146
- :param features: Optional list of features to enable.
147
152
  :param packageDownloadURL: Optional URL to use as the report package download URL.
148
153
  :param copyScript: Controls if the script referenced by viewerURL is copied into the output directory, or directly set as the 'src' value of the script tag in the HTML iXBRL Viewer.
149
154
  """
@@ -185,9 +190,6 @@ def generateViewer(
185
190
  return
186
191
 
187
192
  try:
188
- if features:
189
- for feature in features:
190
- bldr.enableFeature(feature)
191
193
  iv = bldr.createViewer(scriptUrl=viewerURL, showValidations=showValidationMessages, packageDownloadURL=packageDownloadURL)
192
194
  if iv is not None:
193
195
  iv.save(saveViewerDest, zipOutput=zipViewerOutput, copyScriptPath=copyScriptPath)
@@ -199,17 +201,21 @@ def generateViewer(
199
201
  resetPluginData(cntlr)
200
202
 
201
203
 
202
- def getFeaturesFromOptions(options: argparse.Namespace | OptionParser):
203
- return [
204
- featureConfig.key
205
- for featureConfig in FEATURE_CONFIGS
206
- if getattr(options, f'viewer_feature_{featureConfig.key}') or getattr(options, f'viewer_feature_{featureConfig.key.lower()}')
207
- ]
204
+ def getFeaturesFromOptions(options: argparse.Namespace | OptionParser) -> dict[str, Any]:
205
+ features = {}
206
+ for featureConfig in FEATURE_CONFIGS:
207
+ key = featureConfig.key
208
+ option = f'viewer_feature_{key}'
209
+ value = getattr(options, option, None)
210
+ if value is not None:
211
+ features[key] = value
212
+ return features
213
+
208
214
 
209
215
  def iXBRLViewerCommandLineXbrlRun(cntlr, options, modelXbrl, *args, **kwargs):
210
216
  pd = pluginData(cntlr)
211
217
  if pd.builder is None:
212
- pd.builder = IXBRLViewerBuilder(cntlr, useStubViewer = options.useStubViewer)
218
+ pd.builder = IXBRLViewerBuilder(cntlr, useStubViewer = options.useStubViewer, features=getFeaturesFromOptions(options))
213
219
  processModel(cntlr, modelXbrl)
214
220
 
215
221
  def iXBRLViewerCommandLineFilingEnd(cntlr, options, *args, **kwargs):
@@ -220,7 +226,6 @@ def iXBRLViewerCommandLineFilingEnd(cntlr, options, *args, **kwargs):
220
226
  copyScript=not options.viewerNoCopyScript,
221
227
  showValidationMessages=options.validationMessages,
222
228
  zipViewerOutput=options.zipViewerOutput,
223
- features=getFeaturesFromOptions(options),
224
229
  packageDownloadURL=options.packageDownloadURL,
225
230
  )
226
231
 
@@ -315,19 +320,17 @@ def guiRun(cntlr, modelXbrl, attach, *args, **kwargs):
315
320
  global tempViewer
316
321
  tempViewer = tempfile.TemporaryDirectory()
317
322
  viewer_file_name = DEFAULT_OUTPUT_NAME
318
- features = [
319
- c.key
320
- for c in FEATURE_CONFIGS
321
- if cntlr.config.setdefault(f'{CONFIG_FEATURE_PREFIX}{c.key}', False)
322
- ]
323
- pluginData(cntlr).builder = IXBRLViewerBuilder(cntlr, useStubViewer = True)
323
+ features = {}
324
+ for featureConfig in FEATURE_CONFIGS:
325
+ if cntlr.config.setdefault(f'{CONFIG_FEATURE_PREFIX}{featureConfig.key}', False):
326
+ features[featureConfig.key] = True
327
+ pluginData(cntlr).builder = IXBRLViewerBuilder(cntlr, useStubViewer=True, features=features)
324
328
  processModel(cntlr, modelXbrl)
325
329
  generateViewer(
326
330
  cntlr=cntlr,
327
331
  saveViewerDest=tempViewer.name,
328
332
  viewerURL=cntlr.config.get(CONFIG_SCRIPT_URL),
329
333
  copyScript=cntlr.config.get(CONFIG_COPY_SCRIPT, DEFAULT_COPY_SCRIPT),
330
- features=features,
331
334
  )
332
335
  if Path(tempViewer.name, viewer_file_name).exists():
333
336
  localViewer = iXBRLViewerLocalViewer("iXBRL Viewer", os.path.dirname(__file__))
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.38'
16
- __version_tuple__ = version_tuple = (1, 4, 38)
15
+ __version__ = version = '1.4.40'
16
+ __version_tuple__ = version_tuple = (1, 4, 40)
@@ -23,13 +23,98 @@ DEFAULT_JS_FILENAME = 'ixbrlviewer.js'
23
23
  DEFAULT_VIEWER_PATH = os.path.join(os.path.dirname(__file__), "viewer", "dist", DEFAULT_JS_FILENAME)
24
24
 
25
25
  FEATURE_CONFIGS = [
26
+ FeatureConfig(
27
+ key='home_link_label',
28
+ label='Home Link (Label)',
29
+ description='Customizes the label of the "Home" link enabled by "home_link_url".',
30
+ cliAction='store',
31
+ cliDefault=None,
32
+ guiVisible=False,
33
+ guiDefault=None,
34
+ ),
35
+ FeatureConfig(
36
+ key='home_link_url',
37
+ label='Home Link (URL)',
38
+ description='Adds a "Home" link that directs to the specified URL. Label can be customized with "home_link_label".',
39
+ cliAction='store',
40
+ cliDefault=None,
41
+ guiVisible=False,
42
+ guiDefault=None,
43
+ ),
44
+ FeatureConfig(
45
+ key='support_link',
46
+ label='Support Link',
47
+ description='Adds a "Support" link that directs to the specified URL.',
48
+ cliAction='store',
49
+ cliDefault=None,
50
+ guiVisible=False,
51
+ guiDefault=None,
52
+ ),
53
+ FeatureConfig(
54
+ key='survey_link',
55
+ label='Survey Link',
56
+ description='Adds a "Survey" link that directs to the specified URL.',
57
+ cliAction='store',
58
+ cliDefault=None,
59
+ guiVisible=False,
60
+ guiDefault=None,
61
+ ),
26
62
  FeatureConfig(
27
63
  key='review',
28
64
  label='Review Mode',
29
65
  description='Enables highlighting of untagged numbers and dates.',
66
+ cliAction='store_true',
67
+ cliDefault=False,
30
68
  guiVisible=True,
31
69
  guiDefault=False
70
+ ),
71
+ FeatureConfig(
72
+ key='mandatory_facts',
73
+ label='Mandatory Facts',
74
+ description='Enables the display of mandatory facts for the selected taxonomy.',
75
+ cliAction='store',
76
+ cliDefault=None,
77
+ guiVisible=False,
78
+ guiDefault=None
79
+ ),
80
+ FeatureConfig(
81
+ key='search_on_startup',
82
+ label='Search on startup',
83
+ description='Show the search pane by default on startup',
84
+ cliAction='store_true',
85
+ cliDefault=None,
86
+ guiVisible=False,
87
+ guiDefault=None
88
+ ),
89
+ FeatureConfig(
90
+ key='highlight_facts_on_startup',
91
+ label='Highlight facts on startup',
92
+ description='Default "Highlight all facts" to on',
93
+ cliAction='store_true',
94
+ cliDefault=None,
95
+ guiVisible=False,
96
+ guiDefault=None
32
97
  )
33
98
  ]
34
-
35
99
  GUI_FEATURE_CONFIGS = [c for c in FEATURE_CONFIGS if c.guiVisible]
100
+
101
+ MANDATORY_FACTS = {
102
+ "companies-house": [
103
+ "UKCompaniesHouseRegisteredNumber",
104
+ "EntityCurrentLegalOrRegisteredName",
105
+ "BalanceSheetDate",
106
+ "DateAuthorisationFinancialStatementsForIssue",
107
+ "DirectorSigningFinancialStatements",
108
+ "EntityDormantTruefalse",
109
+ "EntityTradingStatus",
110
+ "AccountsStatusAuditedOrUnaudited",
111
+ "AccountsTypeFullOrAbbreviated",
112
+ "AccountingStandardsApplied",
113
+ "LegalFormEntity",
114
+ "StartDateForPeriodCoveredByReport",
115
+ "EndDateForPeriodCoveredByReport",
116
+ "CharityRegistrationNumberEnglandWales",
117
+ "CharityRegistrationNumberScotland",
118
+ "CharityRegistrationNumberNorthernIreland"
119
+ ]
120
+ }
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Any
2
3
 
3
4
 
4
5
  @dataclass(frozen=True, repr=False, eq=False)
@@ -6,5 +7,7 @@ class FeatureConfig:
6
7
  key: str
7
8
  label: str
8
9
  description: str
10
+ cliAction: str
11
+ cliDefault: Any
9
12
  guiVisible: bool
10
- guiDefault: bool
13
+ guiDefault: Any
@@ -13,6 +13,7 @@ import zipfile
13
13
  from collections import defaultdict
14
14
  from copy import deepcopy
15
15
  from pathlib import Path
16
+ from typing import Any
16
17
 
17
18
  from arelle import XbrlConst
18
19
  from arelle.ModelDocument import ModelDocument, Type
@@ -23,7 +24,7 @@ from arelle.UrlUtil import isHttpUrl
23
24
  from arelle.ValidateXbrlCalcs import inferredDecimals
24
25
  from lxml import etree
25
26
 
26
- from .constants import DEFAULT_JS_FILENAME, DEFAULT_OUTPUT_NAME, ERROR_MESSAGE_CODE, FEATURE_CONFIGS, INFO_MESSAGE_CODE
27
+ from .constants import DEFAULT_JS_FILENAME, DEFAULT_OUTPUT_NAME, ERROR_MESSAGE_CODE, FEATURE_CONFIGS, INFO_MESSAGE_CODE, MANDATORY_FACTS
27
28
  from .xhtmlserialize import XHTMLSerializer
28
29
 
29
30
  REPORT_TYPE_EXTENSIONS = ('.xbrl', '.xhtml', '.html', '.htm', '.json')
@@ -89,13 +90,20 @@ class IXBRLViewerBuilder:
89
90
  cntlr: Cntlr,
90
91
  basenameSuffix: str = '',
91
92
  useStubViewer: bool = False,
93
+ features: dict[str, Any] | None = None,
92
94
  ):
95
+ if features is None:
96
+ features = {}
97
+ featureNames = {c.key for c in FEATURE_CONFIGS}
98
+ for featureName in features:
99
+ assert featureName in featureNames, \
100
+ f'Given feature name `{featureName}` does not match any defined features: {featureNames}'
93
101
  self.reportZip = None
94
102
  self.nsmap = NamespaceMap()
95
103
  self.roleMap = NamespaceMap()
96
104
  self.taxonomyData = {
97
105
  "sourceReports": [],
98
- "features": [],
106
+ "features": features,
99
107
  }
100
108
  self.basenameSuffix = basenameSuffix
101
109
  self.currentTargetReport = None
@@ -120,14 +128,6 @@ class IXBRLViewerBuilder:
120
128
  self.reportCount = 0
121
129
  self.assets = []
122
130
 
123
- def enableFeature(self, featureName: str):
124
- if featureName in self.taxonomyData["features"]:
125
- return
126
- featureNames = [c.key for c in FEATURE_CONFIGS]
127
- assert featureName in featureNames, \
128
- f'Given feature name `{featureName}` does not match any defined features: {featureNames}'
129
- self.taxonomyData["features"].append(featureName)
130
-
131
131
  def outputFilename(self, filename):
132
132
  (base, ext) = os.path.splitext(filename)
133
133
  return base + self.basenameSuffix + ext
@@ -155,7 +155,7 @@ class IXBRLViewerBuilder:
155
155
  """
156
156
  return s.replace("<","\\u003C").replace(">","\\u003E").replace("&","\\u0026")
157
157
 
158
- def addELR(self, report: ModelXbrl, elr):
158
+ def addRoleDefinition(self, report: ModelXbrl, elr):
159
159
  prefix = self.roleMap.getPrefix(elr)
160
160
  if self.currentTargetReport.setdefault("roleDefs",{}).get(prefix, None) is None:
161
161
  rts = report.roleTypes.get(elr, [])
@@ -176,6 +176,7 @@ class IXBRLViewerBuilder:
176
176
  for lr in labels:
177
177
  l = lr.toModelObject
178
178
  conceptData["labels"].setdefault(self.roleMap.getPrefix(l.role),{})[l.xmlLang.lower()] = l.text;
179
+ self.addRoleDefinition(report, l.role)
179
180
 
180
181
  refData = []
181
182
  for _refRel in concept.modelXbrl.relationshipSet(XbrlConst.conceptReference).fromModelObject(concept):
@@ -193,9 +194,15 @@ class IXBRLViewerBuilder:
193
194
  if concept.isEnumeration:
194
195
  conceptData["e"] = True
195
196
 
196
- if concept.type is not None and concept.type.isTextBlock:
197
+ if concept.isTextBlock:
197
198
  conceptData['t'] = True
198
199
 
200
+ if concept.balance is not None:
201
+ conceptData['b'] = concept.balance
202
+
203
+ if concept.type is not None:
204
+ conceptData['dt'] = self.nsmap.qname(concept.type.qname)
205
+
199
206
  if concept.isTypedDimension:
200
207
  typedDomainElement = concept.typedDomainElement
201
208
  if typedDomainElement is not None:
@@ -216,7 +223,7 @@ class IXBRLViewerBuilder:
216
223
  for baseSetKey, baseSetModelLinks in report.baseSets.items():
217
224
  arcrole, ELR, linkqname, arcqname = baseSetKey
218
225
  if arcrole in (XbrlConst.summationItem, XbrlConst.summationItem11, WIDER_NARROWER_ARCROLE, XbrlConst.parentChild, XbrlConst.dimensionDefault) and ELR is not None:
219
- self.addELR(report, ELR)
226
+ self.addRoleDefinition(report, ELR)
220
227
  rr = dict()
221
228
  relSet = report.relationshipSet(arcrole, ELR)
222
229
  for r in relSet.modelRelationships:
@@ -256,11 +263,14 @@ class IXBRLViewerBuilder:
256
263
 
257
264
  self.idGen += 1
258
265
  conceptName = self.nsmap.qname(f.qname)
266
+ factList = MANDATORY_FACTS.get(self.taxonomyData["features"].get("mandatory_facts"), [])
267
+ isMandatory = f.qname.localName in factList
259
268
  scheme, ident = f.context.entityIdentifier
260
269
 
261
270
  aspects = {
262
271
  "c": conceptName,
263
272
  "e": self.nsmap.qname(QName(self.nsmap.getPrefix(scheme,"e"), scheme, ident)),
273
+ "m": isMandatory
264
274
  }
265
275
 
266
276
  factData = {
@@ -414,7 +424,11 @@ class IXBRLViewerBuilder:
414
424
  if softwareCredits:
415
425
  self.currentTargetReport["softwareCredits"] = list(softwareCredits)
416
426
  for f in report.facts:
417
- self.addFact(report, f)
427
+ if f.isTuple:
428
+ for nestedTupleFact in f.ixIter():
429
+ self.addFact(report, nestedTupleFact)
430
+ else:
431
+ self.addFact(report, f)
418
432
  self.currentTargetReport["rels"] = self.getRelationships(report)
419
433
 
420
434
  docSetFiles = None