tricc-oo 1.5.23__py3-none-any.whl → 1.5.24__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.
@@ -0,0 +1,224 @@
1
+ import logging
2
+ import os
3
+ import datetime
4
+ from tricc_oo.strategies.output.base_output_strategy import BaseOutPutStrategy
5
+ from tricc_oo.models.base import (
6
+ TriccOperation,
7
+ TriccStatic, TriccReference
8
+ )
9
+ from tricc_oo.models.tricc import (
10
+ TriccNodeSelectOption,
11
+ TriccNodeInputModel,
12
+ TriccNodeBaseModel
13
+ )
14
+ from tricc_oo.converters.tricc_to_xls_form import get_export_name
15
+
16
+ logger = logging.getLogger("default")
17
+
18
+
19
+ class HTMLStrategy(BaseOutPutStrategy):
20
+ processes = ["main"]
21
+ project = None
22
+ output_path = None
23
+
24
+ def __init__(self, project, output_path):
25
+ super().__init__(project, output_path)
26
+ self.html_content = ""
27
+ self.js_statements = []
28
+
29
+ def get_tricc_operation_expression(self, operation):
30
+ ref_expressions = []
31
+ if not hasattr(operation, "reference"):
32
+ return self.get_tricc_operation_operand(operation)
33
+ for r in operation.reference:
34
+ if isinstance(r, list):
35
+ r_expr = [
36
+ (
37
+ self.get_tricc_operation_expression(sr)
38
+ if isinstance(sr, TriccOperation)
39
+ else self.get_tricc_operation_operand(sr)
40
+ )
41
+ for sr in r
42
+ ]
43
+ elif isinstance(r, TriccOperation):
44
+ r_expr = self.get_tricc_operation_expression(r)
45
+ else:
46
+ r_expr = self.get_tricc_operation_operand(r)
47
+ if isinstance(r_expr, TriccReference):
48
+ r_expr = self.get_tricc_operation_operand(r_expr)
49
+ ref_expressions.append(r_expr)
50
+
51
+ # build lower level
52
+ if hasattr(self, f"tricc_operation_{operation.operator}"):
53
+ callable = getattr(self, f"tricc_operation_{operation.operator}")
54
+ return callable(ref_expressions)
55
+ else:
56
+ raise NotImplementedError(
57
+ f"This type of operation '{operation.operator}' is not supported in this strategy"
58
+ )
59
+
60
+ def execute(self):
61
+ version = datetime.datetime.now().strftime("%Y%m%d%H%M")
62
+ logger.info(f"build version: {version}")
63
+ if "main" in self.project.start_pages:
64
+ self.process_base(self.project.start_pages, pages=self.project.pages, version=version)
65
+ else:
66
+ logger.critical("Main process required")
67
+
68
+ logger.info("generate the relevance based on edges")
69
+ self.process_relevance(self.project.start_pages, pages=self.project.pages)
70
+
71
+ logger.info("generate the calculate based on edges")
72
+ self.process_calculate(self.project.start_pages, pages=self.project.pages)
73
+
74
+ logger.info("generate the export format")
75
+ self.process_export(self.project.start_pages, pages=self.project.pages)
76
+
77
+ logger.info("print the export")
78
+ self.export(self.project.start_pages, version=version)
79
+
80
+ def generate_base(self, node, **kwargs):
81
+ # Generate base HTML for nodes
82
+ if hasattr(node, 'label') and node.label:
83
+ self.html_content += f"<label for='{node.get_name()}'>{node.label}</label>\n"
84
+ if hasattr(node, 'tricc_type'):
85
+ onchange = "onchange='updateForm()'"
86
+ if node.tricc_type == 'text':
87
+ self.html_content += f"<input type='text' id='{node.get_name()}' name='{node.get_name()}' {onchange} />\n" # noqa: E501
88
+ elif node.tricc_type == 'integer':
89
+ self.html_content += f"<input type='number' id='{node.get_name()}' name='{node.get_name()}' {onchange} />\n" # noqa: E501
90
+ # Add more types as needed
91
+ return True
92
+
93
+ def generate_relevance(self, node, **kwargs):
94
+ # Generate JS for skip logic (relevance)
95
+ if hasattr(node, 'expression') and node.expression:
96
+ relevance_js = f"if ({self.convert_expression_to_js(node.expression)}) {{ document.getElementById('{node.get_name()}').style.display = 'block'; }} else {{ document.getElementById('{node.get_name()}').style.display = 'none'; }}" # noqa: E501
97
+ self.js_statements.append(relevance_js)
98
+ return True
99
+
100
+ def generate_calculate(self, node, **kwargs):
101
+ # Generate JS for calculations
102
+ if hasattr(node, 'expression') and node.expression:
103
+ calc_js = f"document.getElementById('{node.get_name()}').value = {self.convert_expression_to_js(node.expression)};" # noqa: E501
104
+ self.js_statements.append(calc_js)
105
+ return True
106
+
107
+ def generate_export(self, node, **kwargs):
108
+ # For OpenMRS, export is part of building HTML
109
+ return True
110
+
111
+ def export(self, start_pages, version):
112
+ form_id = start_pages["main"].root.form_id or "openmrs_form"
113
+ file_name = f"{form_id}.html"
114
+ newpath = os.path.join(self.output_path, file_name)
115
+ if not os.path.exists(self.output_path):
116
+ os.makedirs(self.output_path)
117
+
118
+ js_function = f"""
119
+ function updateForm() {{
120
+ {"\n ".join(self.js_statements)}
121
+ }}
122
+ window.onload = updateForm;
123
+ """
124
+
125
+ full_html = f"""
126
+ <!DOCTYPE html>
127
+ <html>
128
+ <head>
129
+ <title>{start_pages["main"].root.label or 'OpenMRS Form'}</title>
130
+ </head>
131
+ <body>
132
+ <form id="{form_id}">
133
+ {self.html_content}
134
+ </form>
135
+ <script>
136
+ {js_function}
137
+ </script>
138
+ </body>
139
+ </html>
140
+ """
141
+
142
+ with open(newpath, 'w') as f:
143
+ f.write(full_html)
144
+ logger.info(f"Exported OpenMRS form to {newpath}")
145
+
146
+ def get_tricc_operation_operand(self, r):
147
+ if isinstance(r, TriccOperation):
148
+ return self.get_tricc_operation_expression(r)
149
+ elif isinstance(r, TriccReference):
150
+ return f"document.getElementById('{get_export_name(r.value)}').value"
151
+ elif isinstance(r, TriccStatic):
152
+ if isinstance(r.value, bool):
153
+ return str(r.value).lower()
154
+ if isinstance(r.value, str):
155
+ return f"'{r.value}'"
156
+ else:
157
+ return str(r.value)
158
+ elif isinstance(r, str):
159
+ return f"{r}"
160
+ elif isinstance(r, (int, float)):
161
+ return str(r)
162
+ elif isinstance(r, TriccNodeSelectOption):
163
+ return f"'{r.name}'"
164
+ elif issubclass(r.__class__, TriccNodeInputModel):
165
+ return f"document.getElementById('{get_export_name(r)}').value"
166
+ elif issubclass(r.__class__, TriccNodeBaseModel):
167
+ return f"document.getElementById('{get_export_name(r)}').value"
168
+ else:
169
+ raise NotImplementedError(f"This type of node {r.__class__} is not supported within an operation")
170
+
171
+ def convert_expression_to_js(self, expression):
172
+ if isinstance(expression, TriccOperation):
173
+ return self.get_tricc_operation_expression(expression)
174
+ else:
175
+ return self.get_tricc_operation_operand(expression)
176
+
177
+ # Implement operation methods as needed, similar to XLSForm but for JS
178
+ def tricc_operation_equal(self, ref_expressions):
179
+ return f"{ref_expressions[0]} === {ref_expressions[1]}"
180
+
181
+ def tricc_operation_not_equal(self, ref_expressions):
182
+ return f"{ref_expressions[0]} !== {ref_expressions[1]}"
183
+
184
+ def tricc_operation_and(self, ref_expressions):
185
+ if len(ref_expressions) == 1:
186
+ return ref_expressions[0]
187
+ if len(ref_expressions) > 1:
188
+ return " && ".join(ref_expressions)
189
+ else:
190
+ return "true"
191
+
192
+ def tricc_operation_or(self, ref_expressions):
193
+ if len(ref_expressions) == 1:
194
+ return ref_expressions[0]
195
+ if len(ref_expressions) > 1:
196
+ return " || ".join(ref_expressions)
197
+ else:
198
+ return "true"
199
+
200
+ def tricc_operation_not(self, ref_expressions):
201
+ return f"!({ref_expressions[0]})"
202
+
203
+ def tricc_operation_plus(self, ref_expressions):
204
+ return " + ".join(ref_expressions)
205
+
206
+ def tricc_operation_minus(self, ref_expressions):
207
+ if len(ref_expressions) > 1:
208
+ return " - ".join(map(str, ref_expressions))
209
+ elif len(ref_expressions) == 1:
210
+ return f"-{ref_expressions[0]}"
211
+
212
+ def tricc_operation_more(self, ref_expressions):
213
+ return f"{ref_expressions[0]} > {ref_expressions[1]}"
214
+
215
+ def tricc_operation_less(self, ref_expressions):
216
+ return f"{ref_expressions[0]} < {ref_expressions[1]}"
217
+
218
+ def tricc_operation_more_or_equal(self, ref_expressions):
219
+ return f"{ref_expressions[0]} >= {ref_expressions[1]}"
220
+
221
+ def tricc_operation_less_or_equal(self, ref_expressions):
222
+ return f"{ref_expressions[0]} <= {ref_expressions[1]}"
223
+
224
+ # Add more operations as needed...