tdrpa.tdworker 1.2.13.2__py312-none-win_amd64.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.
Files changed (101) hide show
  1. tdrpa/_tdxlwings/__init__.py +193 -0
  2. tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
  3. tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
  4. tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
  5. tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
  6. tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
  7. tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
  8. tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
  9. tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
  10. tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
  11. tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
  12. tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
  13. tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
  14. tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
  15. tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
  16. tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
  17. tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
  18. tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
  19. tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
  20. tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
  21. tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
  22. tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
  23. tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
  24. tdrpa/_tdxlwings/_win32patch.py +90 -0
  25. tdrpa/_tdxlwings/_xlmac.py +2240 -0
  26. tdrpa/_tdxlwings/_xlwindows.py +2518 -0
  27. tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
  28. tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
  29. tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
  30. tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
  31. tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
  32. tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
  33. tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
  34. tdrpa/_tdxlwings/apps.py +35 -0
  35. tdrpa/_tdxlwings/base_classes.py +1092 -0
  36. tdrpa/_tdxlwings/cli.py +1306 -0
  37. tdrpa/_tdxlwings/com_server.py +385 -0
  38. tdrpa/_tdxlwings/constants.py +3080 -0
  39. tdrpa/_tdxlwings/conversion/__init__.py +103 -0
  40. tdrpa/_tdxlwings/conversion/framework.py +147 -0
  41. tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
  42. tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
  43. tdrpa/_tdxlwings/conversion/standard.py +321 -0
  44. tdrpa/_tdxlwings/expansion.py +83 -0
  45. tdrpa/_tdxlwings/ext/__init__.py +3 -0
  46. tdrpa/_tdxlwings/ext/sql.py +73 -0
  47. tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
  48. tdrpa/_tdxlwings/js/xlwings.js +577 -0
  49. tdrpa/_tdxlwings/js/xlwings.ts +729 -0
  50. tdrpa/_tdxlwings/mac_dict.py +6399 -0
  51. tdrpa/_tdxlwings/main.py +5205 -0
  52. tdrpa/_tdxlwings/mistune/__init__.py +63 -0
  53. tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
  54. tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
  55. tdrpa/_tdxlwings/mistune/markdown.py +84 -0
  56. tdrpa/_tdxlwings/mistune/renderers.py +220 -0
  57. tdrpa/_tdxlwings/mistune/scanner.py +121 -0
  58. tdrpa/_tdxlwings/mistune/util.py +41 -0
  59. tdrpa/_tdxlwings/pro/__init__.py +40 -0
  60. tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
  61. tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
  62. tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
  63. tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
  64. tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
  65. tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
  66. tdrpa/_tdxlwings/pro/utils.py +199 -0
  67. tdrpa/_tdxlwings/quickstart.xlsm +0 -0
  68. tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
  69. tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
  70. tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
  71. tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
  72. tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
  73. tdrpa/_tdxlwings/reports.py +12 -0
  74. tdrpa/_tdxlwings/rest/__init__.py +1 -0
  75. tdrpa/_tdxlwings/rest/api.py +368 -0
  76. tdrpa/_tdxlwings/rest/serializers.py +103 -0
  77. tdrpa/_tdxlwings/server.py +14 -0
  78. tdrpa/_tdxlwings/udfs.py +775 -0
  79. tdrpa/_tdxlwings/utils.py +777 -0
  80. tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
  81. tdrpa/_tdxlwings/xlwings.bas +2061 -0
  82. tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
  83. tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
  84. tdrpa/tdworker/__init__.pyi +12 -0
  85. tdrpa/tdworker/_clip.pyi +50 -0
  86. tdrpa/tdworker/_excel.pyi +743 -0
  87. tdrpa/tdworker/_file.pyi +77 -0
  88. tdrpa/tdworker/_img.pyi +226 -0
  89. tdrpa/tdworker/_network.pyi +94 -0
  90. tdrpa/tdworker/_os.pyi +47 -0
  91. tdrpa/tdworker/_sp.pyi +21 -0
  92. tdrpa/tdworker/_w.pyi +129 -0
  93. tdrpa/tdworker/_web.pyi +995 -0
  94. tdrpa/tdworker/_winE.pyi +228 -0
  95. tdrpa/tdworker/_winK.pyi +74 -0
  96. tdrpa/tdworker/_winM.pyi +117 -0
  97. tdrpa/tdworker.cp312-win_amd64.pyd +0 -0
  98. tdrpa_tdworker-1.2.13.2.dist-info/METADATA +38 -0
  99. tdrpa_tdworker-1.2.13.2.dist-info/RECORD +101 -0
  100. tdrpa_tdworker-1.2.13.2.dist-info/WHEEL +5 -0
  101. tdrpa_tdworker-1.2.13.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,321 @@
1
+ import datetime
2
+ import math
3
+ from collections import OrderedDict
4
+
5
+ from .. import LicenseError
6
+ from ..main import Range
7
+ from ..utils import chunk, xlserial_to_datetime
8
+ from . import Accessor, Converter, Options, Pipeline, accessors
9
+
10
+ try:
11
+ from ..pro import Markdown
12
+ from ..pro.reports import markdown
13
+ except (ImportError, LicenseError, AttributeError):
14
+ Markdown = None
15
+ try:
16
+ import numpy as np
17
+ except ImportError:
18
+ np = None
19
+
20
+
21
+ _date_handlers = {
22
+ datetime.datetime: datetime.datetime,
23
+ datetime.date: lambda year, month, day, **kwargs: datetime.date(year, month, day),
24
+ }
25
+
26
+ _number_handlers = {
27
+ int: lambda x: int(round(x)),
28
+ "raw int": int,
29
+ }
30
+
31
+
32
+ class ExpandRangeStage:
33
+ def __init__(self, options):
34
+ self.expand = options.get("expand", None)
35
+
36
+ def __call__(self, c):
37
+ if c.range:
38
+ # auto-expand the range
39
+ if self.expand:
40
+ c.range = c.range.expand(self.expand)
41
+
42
+
43
+ class WriteValueToRangeStage:
44
+ def __init__(self, options, raw=False):
45
+ self.raw = raw
46
+ self.options = options
47
+
48
+ def _write_value(self, rng, value, scalar):
49
+ if rng.api and value:
50
+ # it is assumed by this stage that value is a list of lists
51
+ if scalar:
52
+ value = value[0][0]
53
+ else:
54
+ rng = rng.resize(len(value), len(value[0]))
55
+
56
+ chunksize = self.options.get("chunksize")
57
+ if chunksize:
58
+ for ix, value_chunk in enumerate(chunk(value, chunksize)):
59
+ rng[
60
+ ix * chunksize : ix * chunksize + chunksize, :
61
+ ].raw_value = value_chunk
62
+ else:
63
+ rng.raw_value = value
64
+
65
+ def __call__(self, ctx):
66
+ if ctx.range and ctx.value:
67
+ if self.raw:
68
+ ctx.range.raw_value = ctx.value
69
+ return
70
+
71
+ scalar = ctx.meta.get("scalar", False)
72
+ if not scalar:
73
+ ctx.range = ctx.range.resize(len(ctx.value), len(ctx.value[0]))
74
+
75
+ self._write_value(ctx.range, ctx.value, scalar)
76
+
77
+
78
+ class ReadValueFromRangeStage:
79
+ def __init__(self, options):
80
+ self.options = options
81
+
82
+ def __call__(self, c):
83
+ chunksize = self.options.get("chunksize")
84
+ if c.range and chunksize:
85
+ parts = []
86
+ for i in range(math.ceil(c.range.shape[0] / chunksize)):
87
+ raw_value = c.range[
88
+ i * chunksize : (i * chunksize) + chunksize, :
89
+ ].raw_value
90
+ if isinstance(raw_value[0], (list, tuple)):
91
+ parts.extend(raw_value)
92
+ else:
93
+ # Turn a single row list into a 2d list
94
+ parts.extend([raw_value])
95
+
96
+ c.value = parts
97
+ elif c.range:
98
+ c.value = c.range.raw_value
99
+
100
+
101
+ class CleanDataFromReadStage:
102
+ def __init__(self, options):
103
+ self.options = options
104
+ dates_as = options.get("dates", datetime.datetime)
105
+ self.empty_as = options.get("empty", None)
106
+ self.dates_handler = _date_handlers.get(dates_as, dates_as)
107
+ numbers_as = options.get("numbers", None)
108
+ self.numbers_handler = _number_handlers.get(numbers_as, numbers_as)
109
+ self.err_to_str = options.get("err_to_str", False)
110
+
111
+ def __call__(self, c):
112
+ c.value = c.engine.impl.clean_value_data(
113
+ c.value,
114
+ self.dates_handler,
115
+ self.empty_as,
116
+ self.numbers_handler,
117
+ self.err_to_str,
118
+ )
119
+
120
+
121
+ class CleanDataForWriteStage:
122
+ def __init__(self, options):
123
+ self.options = options
124
+
125
+ def __call__(self, c):
126
+ c.value = [
127
+ [c.engine.impl.prepare_xl_data_element(x, self.options) for x in y]
128
+ for y in c.value
129
+ ]
130
+
131
+
132
+ class AdjustDimensionsStage:
133
+ def __init__(self, options):
134
+ self.ndim = options.get("ndim", None)
135
+
136
+ def __call__(self, c):
137
+ # the assumption is that value is 2-dimensional at this stage
138
+
139
+ if self.ndim is None:
140
+ if len(c.value) == 1:
141
+ c.value = c.value[0][0] if len(c.value[0]) == 1 else c.value[0]
142
+ elif len(c.value[0]) == 1:
143
+ c.value = [x[0] for x in c.value]
144
+ else:
145
+ c.value = c.value
146
+
147
+ elif self.ndim == 1:
148
+ if len(c.value) == 1:
149
+ c.value = c.value[0]
150
+ elif len(c.value[0]) == 1:
151
+ c.value = [x[0] for x in c.value]
152
+ else:
153
+ raise Exception("Range must be 1-by-n or n-by-1 when ndim=1.")
154
+
155
+ # ndim = 2 is a no-op
156
+ elif self.ndim != 2:
157
+ raise ValueError("Invalid c.value ndim=%s" % self.ndim)
158
+
159
+
160
+ class Ensure2DStage:
161
+ def __call__(self, c):
162
+ if isinstance(c.value, (list, tuple)):
163
+ if len(c.value) > 0:
164
+ if not isinstance(c.value[0], (list, tuple)):
165
+ c.value = [c.value]
166
+ else:
167
+ c.meta["scalar"] = True
168
+ c.value = [[c.value]]
169
+
170
+
171
+ class TransposeStage:
172
+ def __call__(self, c):
173
+ c.value = [
174
+ [e[i] for e in c.value] for i in range(len(c.value[0]) if c.value else 0)
175
+ ]
176
+
177
+
178
+ class FormatStage:
179
+ def __init__(self, options):
180
+ self.options = options
181
+
182
+ def __call__(self, ctx):
183
+ if Markdown and isinstance(ctx.source_value, Markdown):
184
+ markdown.format_text(
185
+ ctx.range, ctx.source_value.text, ctx.source_value.style
186
+ )
187
+ if "formatter" in self.options:
188
+ self.options["formatter"](ctx.range, ctx.source_value)
189
+
190
+
191
+ class BaseAccessor(Accessor):
192
+ @classmethod
193
+ def reader(cls, options):
194
+ return Pipeline().append_stage(
195
+ ExpandRangeStage(options), only_if=options.get("expand", None)
196
+ )
197
+
198
+
199
+ class RangeAccessor(Accessor):
200
+ @staticmethod
201
+ def copy_range_to_value(c):
202
+ c.value = c.range
203
+
204
+ @classmethod
205
+ def reader(cls, options):
206
+ return BaseAccessor.reader(options).append_stage(
207
+ RangeAccessor.copy_range_to_value
208
+ )
209
+
210
+
211
+ RangeAccessor.register("range", Range)
212
+
213
+
214
+ class RawValueAccessor(Accessor):
215
+ @classmethod
216
+ def reader(cls, options):
217
+ return Accessor.reader(options).append_stage(ReadValueFromRangeStage(options))
218
+
219
+ @classmethod
220
+ def writer(cls, options):
221
+ return Accessor.writer(options).prepend_stage(
222
+ WriteValueToRangeStage(options, raw=True)
223
+ )
224
+
225
+
226
+ RawValueAccessor.register("raw")
227
+
228
+
229
+ class ValueAccessor(Accessor):
230
+ @staticmethod
231
+ def reader(options):
232
+ return (
233
+ BaseAccessor.reader(options)
234
+ .append_stage(ReadValueFromRangeStage(options))
235
+ .append_stage(Ensure2DStage())
236
+ .append_stage(CleanDataFromReadStage(options))
237
+ .append_stage(TransposeStage(), only_if=options.get("transpose", False))
238
+ .append_stage(AdjustDimensionsStage(options))
239
+ )
240
+
241
+ @staticmethod
242
+ def writer(options):
243
+ return (
244
+ Pipeline()
245
+ .prepend_stage(FormatStage(options))
246
+ .prepend_stage(WriteValueToRangeStage(options))
247
+ .prepend_stage(CleanDataForWriteStage(options))
248
+ .prepend_stage(TransposeStage(), only_if=options.get("transpose", False))
249
+ .prepend_stage(Ensure2DStage())
250
+ )
251
+
252
+ @classmethod
253
+ def router(cls, value, rng, options):
254
+ return accessors.get(type(value), cls)
255
+
256
+
257
+ ValueAccessor.register(None)
258
+
259
+
260
+ class DictConverter(Converter):
261
+ @classmethod
262
+ def base_reader(cls, options):
263
+ return super(DictConverter, cls).base_reader(Options(options).override(ndim=2))
264
+
265
+ @classmethod
266
+ def read_value(cls, value, options):
267
+ assert not value or len(value[0]) == 2
268
+ return dict(value)
269
+
270
+ @classmethod
271
+ def write_value(cls, value, options):
272
+ return list(value.items())
273
+
274
+
275
+ DictConverter.register(dict)
276
+
277
+
278
+ class OrderedDictConverter(Converter):
279
+ @classmethod
280
+ def base_reader(cls, options):
281
+ return super(OrderedDictConverter, cls).base_reader(
282
+ Options(options).override(ndim=2)
283
+ )
284
+
285
+ @classmethod
286
+ def read_value(cls, value, options):
287
+ assert not value or len(value[0]) == 2
288
+ return OrderedDict(value)
289
+
290
+ @classmethod
291
+ def write_value(cls, value, options):
292
+ return list(value.items())
293
+
294
+
295
+ OrderedDictConverter.register(OrderedDict)
296
+
297
+
298
+ class DatetimeConverter(Converter):
299
+ @classmethod
300
+ def read_value(cls, value, options):
301
+ return xlserial_to_datetime(value)
302
+
303
+ @classmethod
304
+ def write_value(cls, value, options):
305
+ return value
306
+
307
+
308
+ DatetimeConverter.register(datetime.datetime)
309
+
310
+
311
+ class DateConverter(Converter):
312
+ @classmethod
313
+ def read_value(cls, value, options):
314
+ return xlserial_to_datetime(value).date()
315
+
316
+ @classmethod
317
+ def write_value(cls, value, options):
318
+ return value
319
+
320
+
321
+ DateConverter.register(datetime.date)
@@ -0,0 +1,83 @@
1
+ from .main import Range
2
+
3
+ expanders = {}
4
+
5
+ _empty = (None, "", [[""]], [[None]], [("",)], [(None,)])
6
+
7
+
8
+ class Expander:
9
+ def register(self, *aliases):
10
+ for alias in aliases:
11
+ expanders[alias] = self
12
+
13
+ def expand(self, rng):
14
+ """
15
+ Expands a range
16
+
17
+ Arguments
18
+ ---------
19
+ rng: Range
20
+ The reference range
21
+
22
+ Returns
23
+ -------
24
+ Range object: The expanded range
25
+
26
+ """
27
+ raise NotImplementedError()
28
+
29
+
30
+ class TableExpander(Expander):
31
+ def expand(self, rng):
32
+ origin = rng(1, 1)
33
+
34
+ if origin.has_array:
35
+ bottom_left = origin.end("down")
36
+ elif origin(2, 1).raw_value in _empty:
37
+ bottom_left = origin
38
+ elif origin(3, 1).raw_value in _empty:
39
+ bottom_left = origin(2, 1)
40
+ else:
41
+ bottom_left = origin(2, 1).end("down")
42
+
43
+ if origin.has_array:
44
+ top_right = origin.end("right")
45
+ elif origin(1, 2).raw_value in _empty:
46
+ top_right = origin
47
+ elif origin(1, 3).raw_value in _empty:
48
+ top_right = origin(1, 2)
49
+ else:
50
+ top_right = origin(1, 2).end("right")
51
+
52
+ return Range(top_right, bottom_left)
53
+
54
+
55
+ TableExpander().register("table")
56
+
57
+
58
+ class VerticalExpander(Expander):
59
+ def expand(self, rng):
60
+ if rng(2, 1).raw_value in _empty:
61
+ return Range(rng(1, 1), rng(1, rng.shape[1]))
62
+ elif rng(3, 1).raw_value in _empty:
63
+ return Range(rng(1, 1), rng(2, rng.shape[1]))
64
+ else:
65
+ end_row = rng(2, 1).end("down").row - rng.row + 1
66
+ return Range(rng(1, 1), rng(end_row, rng.shape[1]))
67
+
68
+
69
+ VerticalExpander().register("vertical", "down", "d")
70
+
71
+
72
+ class HorizontalExpander(Expander):
73
+ def expand(self, rng):
74
+ if rng(1, 2).raw_value in _empty:
75
+ return Range(rng(1, 1), rng(rng.shape[0], 1))
76
+ elif rng(1, 3).raw_value in _empty:
77
+ return Range(rng(1, 1), rng(rng.shape[0], 2))
78
+ else:
79
+ end_column = rng(1, 2).end("right").column - rng.column + 1
80
+ return Range(rng(1, 1), rng(rng.shape[0], end_column))
81
+
82
+
83
+ HorizontalExpander().register("horizontal", "right", "r")
@@ -0,0 +1,3 @@
1
+ from .sql import sql, sql_dynamic
2
+
3
+ __all__ = "sql", "sql_dynamic"
@@ -0,0 +1,73 @@
1
+ import sqlite3
2
+
3
+ from .. import arg, func, ret
4
+
5
+
6
+ def conv_value(value, col_is_str):
7
+ if value is None:
8
+ return "NULL"
9
+ if col_is_str:
10
+ return repr(str(value))
11
+ elif isinstance(value, bool):
12
+ return 1 if value else 0
13
+ else:
14
+ return repr(value)
15
+
16
+
17
+ @func
18
+ @arg("tables", expand="table", ndim=2)
19
+ @ret(expand="table")
20
+ def sql(query, *tables):
21
+ return _sql(query, *tables)
22
+
23
+
24
+ @func
25
+ @arg("tables", expand="table", ndim=2)
26
+ def sql_dynamic(query, *tables):
27
+ """Called if native dynamic arrays are available"""
28
+ return _sql(query, *tables)
29
+
30
+
31
+ def _sql(query, *tables):
32
+ conn = sqlite3.connect(":memory:")
33
+
34
+ c = conn.cursor()
35
+
36
+ for i, table in enumerate(tables):
37
+ cols = table[0]
38
+ rows = table[1:]
39
+ types = [any(isinstance(row[j], str) for row in rows) for j in range(len(cols))]
40
+ name = chr(65 + i)
41
+
42
+ stmt = "CREATE TABLE %s (%s)" % (
43
+ name,
44
+ ", ".join(
45
+ "'%s' %s" % (col, "STRING" if typ else "REAL")
46
+ for col, typ in zip(cols, types)
47
+ ),
48
+ )
49
+ c.execute(stmt)
50
+
51
+ if rows:
52
+ stmt = "INSERT INTO %s VALUES %s" % (
53
+ name,
54
+ ", ".join(
55
+ "(%s)"
56
+ % ", ".join(
57
+ conv_value(value, type) for value, typ in zip(row, types)
58
+ )
59
+ for row in rows
60
+ ),
61
+ )
62
+ # Fixes values like these:
63
+ # sql('SELECT a FROM a', [['a', 'b'], ["""X"Y'Z""", 'd']])
64
+ stmt = stmt.replace("\\'", "''")
65
+ c.execute(stmt)
66
+
67
+ res = []
68
+ c.execute(query)
69
+ res.append([x[0] for x in c.description])
70
+ for row in c:
71
+ res.append(list(row))
72
+
73
+ return res
@@ -0,0 +1,71 @@
1
+ <!doctype html>
2
+ <!--
3
+ Copyright (C) 2014 - present, Zoomer Analytics GmbH. All rights reserved.
4
+ Licensed under BSD-3-Clause license, see: https://docs.xlwings.org/en/stable/license.html
5
+
6
+ This file also contains code from Bootstrap
7
+ Copyright (c) 2011-2023 The Bootstrap Authors, Licensed under MIT license, see https://raw.githubusercontent.com/twbs/bootstrap/main/LICENSE
8
+
9
+ This file also contains code from bootstrap-ie11
10
+ Copyright (c) 2022 Christian Oliff, Licensed under MIT license, see https://raw.githubusercontent.com/coliff/bootstrap-ie11/main/LICENSE
11
+ -->
12
+ <html lang="en">
13
+
14
+ <head>
15
+ <meta charset="utf-8">
16
+ <meta name="viewport" content="width=device-width, initial-scale=1">
17
+ <title>Alert</title>
18
+ <script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
19
+ <link rel="stylesheet"
20
+ href="https://cdn.jsdelivr.net/gh/xlwings/bootstrap-xlwings@5.2.3-2/dist/bootstrap-xlwings.min.css"
21
+ integrity="sha384-TZ8CaOSXLBEEL73Aw1vX6a/2YP7QHdiuilF2C8Put8X81F3FzyRgt9ba77CMKAXq" crossorigin="anonymous">
22
+ <script
23
+ nomodule>window.MSInputMethodContext && document.documentMode && document.write('<link rel="stylesheet" href="/css/bootstrap-ie11.min.css"><script src="https://cdn.jsdelivr.net/combine/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js,npm/ie11-custom-properties@4,npm/element-qsa-scope@1"><\/script><script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=default%2CNumber.parseInt%2CNumber.parseFloat%2CArray.prototype.find%2CArray.prototype.includes"><\/script>');</script>
24
+ </head>
25
+
26
+ <body>
27
+ <div id="callback" data-callback="{{ callback }}"></div>
28
+ <div class="container-fluid">
29
+ <div class="d-flex flex-column pb-3 px-2 vh-100">
30
+ <h1 class="pt-4">{{ title }}</h1>
31
+ <p>{{ prompt|replace("\n", "<br>"|safe) }}</p>
32
+ <div class="mt-auto">
33
+ <div class="float-end">
34
+ {% if "ok" in buttons %}
35
+ <button id="ok" type="button" class="btn btn-primary btn-xl-alert">OK</button>
36
+ {% endif %}
37
+ {% if "yes" in buttons %}
38
+ <button id="yes" type="button" class="btn btn-primary btn-xl-alert">Yes</button>
39
+ {% endif %}
40
+ {% if "no" in buttons %}
41
+ <button id="no" type="button" class="btn btn-outline-secondary btn-xl-alert">No</button>
42
+ {% endif %}
43
+ {% if "cancel" in buttons %}
44
+ <button id="cancel" type="button" class="btn btn-outline-secondary btn-xl-alert">Cancel</button>
45
+ {% endif %}
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </div>
50
+
51
+ <script>
52
+ Office.onReady(function (info) { });
53
+ if (document.getElementById("ok")) {
54
+ document.getElementById("ok").addEventListener("click", buttonCallback);
55
+ }
56
+ if (document.getElementById("yes")) {
57
+ document.getElementById("yes").addEventListener("click", buttonCallback);
58
+ }
59
+ if (document.getElementById("no")) {
60
+ document.getElementById("no").addEventListener("click", buttonCallback);
61
+ }
62
+ if (document.getElementById("cancel")) {
63
+ document.getElementById("cancel").addEventListener("click", buttonCallback);
64
+ }
65
+ function buttonCallback() {
66
+ Office.context.ui.messageParent(this.id + "|" + document.getElementById("callback").getAttribute("data-callback"));
67
+ }
68
+ </script>
69
+ </body>
70
+
71
+ </html>