yafowil.widget.array 2.0.0__py2.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,341 @@
1
+ from node.utils import UNSET
2
+ from yafowil.base import factory
3
+ from yafowil.base import fetch_value
4
+ from yafowil.common import generic_extractor
5
+ from yafowil.common import generic_required_extractor
6
+ from yafowil.compat import ITER_TYPES
7
+ from yafowil.compound import compound_renderer
8
+ from yafowil.utils import attr_value
9
+ from yafowil.utils import css_managed_props
10
+ from yafowil.utils import cssclasses
11
+ from yafowil.utils import cssid
12
+ from yafowil.utils import managedprops
13
+ from yafowil.base import factory
14
+
15
+ @managedprops(*css_managed_props)
16
+ def array_display_proxy_renderer(widget, data):
17
+ """B/C. Use ``display_proxy`` widget attribute.
18
+ """
19
+ input_attrs = {
20
+ 'type': 'hidden',
21
+ 'value': fetch_value(widget, data),
22
+ 'name_': widget.dottedpath,
23
+ 'id': cssid(widget, 'input'),
24
+ 'class_': cssclasses(widget, data),
25
+ 'required': attr_value('required', widget, data) and 'required' or None
26
+ }
27
+ return data.tag('input', **input_attrs) + data.rendered
28
+
29
+
30
+ factory.register(
31
+ 'array_display_proxy',
32
+ extractors=[generic_extractor],
33
+ edit_renderers=[array_display_proxy_renderer],
34
+ display_renderers=[array_display_proxy_renderer]
35
+ )
36
+
37
+ # do not document internal widget
38
+ factory.doc['blueprint']['array_display_proxy'] = UNSET
39
+
40
+
41
+ ICON_CSS = {
42
+ 'add': 'icon-plus-sign',
43
+ 'remove': 'icon-minus-sign',
44
+ 'up': 'icon-circle-arrow-up',
45
+ 'down': 'icon-circle-arrow-down',
46
+ }
47
+ BS_ICON = {
48
+ 'add': 'bi-plus-circle-fill',
49
+ 'remove': 'bi-dash-circle-fill',
50
+ 'up': 'bi-arrow-up-circle-fill',
51
+ 'down': 'bi-arrow-down-circle-fill',
52
+ }
53
+
54
+
55
+ def actions_renderer(widget, data):
56
+ tag = data.tag
57
+ actions = list()
58
+ icons = BS_ICON if factory.theme == 'bootstrap5' else ICON_CSS
59
+ for key in ['add', 'remove', 'up', 'down']:
60
+ if widget.attrs.get(key):
61
+ class_ = 'array_row_%s' % key
62
+ icon = tag('span', ' ', class_=icons[key])
63
+ action = tag('a', icon, href='#', class_=class_)
64
+ actions.append(action)
65
+ kw = dict(class_='array_actions')
66
+ return tag('div', *actions, **kw)
67
+
68
+
69
+ factory.register(
70
+ 'array_actions',
71
+ edit_renderers=[actions_renderer]
72
+ )
73
+
74
+ # do not document internal widget
75
+ factory.doc['blueprint']['array_actions'] = UNSET
76
+
77
+
78
+ def array_builder(widget, factory):
79
+ table = widget['table'] = factory('table', props={
80
+ 'structural': True,
81
+ 'class': widget.attrs['table_class'],
82
+ })
83
+ head = table['head'] = factory('thead', props={
84
+ 'structural': True,
85
+ })
86
+ row = head['row'] = factory('tr', props={
87
+ 'structural': True,
88
+ })
89
+ label = widget.attrs.get('label', u' ')
90
+ if callable(label):
91
+ label = label()
92
+ row['label'] = factory('th', props={
93
+ 'structural': True,
94
+ 'label': label,
95
+ })
96
+ if not widget.attrs['static']:
97
+ props = dict()
98
+ props['structural'] = True
99
+ props['th.class'] = 'head_actions'
100
+ if widget.attrs['add']:
101
+ props['add'] = True
102
+ row['actions'] = factory('th:array_actions', props=props)
103
+ table['body'] = factory('tbody', props={
104
+ 'structural': True,
105
+ })
106
+
107
+
108
+ @managedprops('add', 'remove', 'sort', 'static', 'table_class', *css_managed_props)
109
+ def array_wrapper_renderer(widget, data):
110
+ add_css = ''
111
+ if not widget.attrs['static']:
112
+ for attr in ['add', 'remove', 'sort']:
113
+ if widget.attrs[attr]:
114
+ add_css += ' array-%s' % attr
115
+ else:
116
+ add_css += ' array-static'
117
+ kw = {
118
+ 'id': cssid(widget, 'array'),
119
+ 'class': cssclasses(widget, data) + add_css,
120
+ }
121
+ if 'array' not in kw['class'].split(' '):
122
+ kw['class'] = 'array %s' % kw['class']
123
+ rendered = data.rendered
124
+ return data.tag('div', rendered, **kw)
125
+
126
+
127
+ CONTAINER = 'TEMPLATE_CONTAINER'
128
+ TEMPLATE = 'TEMPLATE'
129
+
130
+
131
+ def array_edit_renderer(widget, data):
132
+ if len(widget) == 1 and CONTAINER not in widget:
133
+ raise Exception(u"Empty array widget defined")
134
+ if CONTAINER not in widget:
135
+ template = widget.detach(widget.keys()[1])
136
+ hook_array_template(widget, template)
137
+ value = fetch_value(widget, data)
138
+ # XXX: reset table body if already filled -> case form in memory.
139
+ if value:
140
+ widget.getter = UNSET
141
+ data.value = UNSET
142
+ template = widget[CONTAINER][TEMPLATE]
143
+ create_array_children(widget, template, value)
144
+ if not widget.attrs['add'] or widget.attrs['static']:
145
+ del widget[CONTAINER]
146
+
147
+
148
+ def create_array_children(widget, template, value):
149
+ if isinstance(value, dict):
150
+ try:
151
+ indices = [int(_) for _ in value.keys()]
152
+ except ValueError as e:
153
+ raise Exception(u"Array value error. %s" % str(e))
154
+ indices = sorted(indices)
155
+ for i in indices:
156
+ create_array_entry(str(i), widget, template, value[str(i)])
157
+ elif type(value) in ITER_TYPES:
158
+ indices = range(len(value))
159
+ for i in indices:
160
+ create_array_entry(str(i), widget, template, value[i])
161
+ else:
162
+ raise ValueError(u"Expected list or dict as value. Got '{}'".format(
163
+ str(type(value)))
164
+ )
165
+
166
+
167
+ def create_array_entry(idx, widget, template, value):
168
+ tbody = widget['table']['body']
169
+ row = tbody['row_%s' % idx] = factory('tr', props={'structural': True})
170
+ props = dict()
171
+ props['structural'] = True
172
+ props['class'] = 'widget'
173
+ widget_col = row['widget_col'] = factory('td', props=props)
174
+ if not widget.attrs['static']:
175
+ props = dict()
176
+ props['structural'] = True
177
+ props['class'] = 'actions'
178
+ actions_col = row['actions_col'] = factory('td', props=props)
179
+ props = dict()
180
+ props['structural'] = True
181
+ if widget.attrs['add']:
182
+ props['add'] = True
183
+ if widget.attrs['remove']:
184
+ props['remove'] = True
185
+ if widget.attrs['sort']:
186
+ props['up'] = True
187
+ props['down'] = True
188
+ actions_col['actions'] = factory('array_actions', props=props)
189
+ child_widget = widget_col[idx] = duplicate_widget(template, value)
190
+ if 'array' in template.blueprints:
191
+ if len(template):
192
+ create_array_entry_children(child_widget, template)
193
+ orgin = template[template.keys()[-1]]
194
+ template = duplicate_recursiv(orgin)
195
+ hook_array_template(child_widget, template)
196
+ # If array in array with compound. Compound template children get
197
+ # hooked to array widget. Remove them.
198
+ for key in child_widget.keys():
199
+ if key not in ['table', CONTAINER]:
200
+ del child_widget[key]
201
+ return
202
+ create_array_entry_children(child_widget, template)
203
+
204
+
205
+ def create_array_entry_children(widget, template):
206
+ for name, child_template in template.items():
207
+ child_widget = widget[name] = duplicate_recursiv(child_template)
208
+ create_array_entry_children(child_widget, child_template)
209
+
210
+
211
+ def hook_array_template(widget, template):
212
+ props = dict()
213
+ props['structural'] = True
214
+ props['class'] = 'arraytemplate'
215
+ container = widget[CONTAINER] = factory('div', props=props)
216
+ if template.attrs.get('structural'):
217
+ raise Exception(
218
+ u"Compound templates for arrays must not be structural.")
219
+ container[TEMPLATE] = template
220
+
221
+
222
+ def duplicate_widget(widget, value=UNSET):
223
+ blueprints = widget.blueprints
224
+ leaf = len(widget) == 0
225
+ # B/C: use display_property widget attribute!
226
+ if leaf and (widget.mode == 'display' or widget.attrs.get('disabled')) \
227
+ and 'array_display_proxy' not in blueprints:
228
+ if not widget.attrs.get('display_proxy'):
229
+ blueprints.insert(0, 'array_display_proxy')
230
+ return factory(
231
+ blueprints,
232
+ value=value,
233
+ props=widget.properties,
234
+ custom=widget.custom,
235
+ mode=widget.mode)
236
+
237
+
238
+ def duplicate_recursiv(widget):
239
+ node = duplicate_widget(widget)
240
+ for k, v in widget.items():
241
+ node[k] = duplicate_recursiv(v)
242
+ return node
243
+
244
+
245
+ def array_extractor(widget, data):
246
+ template = widget[widget.keys()[-1]]
247
+ helper = duplicate_recursiv(template)
248
+ request = data.request
249
+ ret = list()
250
+ index = 0
251
+ while True:
252
+ helper.__parent__ = widget
253
+ helper.__name__ = str(index)
254
+ if not check_base_name_in_request(helper, request):
255
+ break
256
+ entry_data = helper.extract(request, parent=data)
257
+ ret.append(entry_data.extracted)
258
+ data[str(index)] = entry_data
259
+ index += 1
260
+ return ret
261
+
262
+
263
+ def check_base_name_in_request(widget, request):
264
+ basename = widget.dottedpath
265
+ for key in request.keys():
266
+ if key.startswith(basename):
267
+ return True
268
+ return False
269
+
270
+
271
+ def set_display_mode(widget):
272
+ for child in widget.values():
273
+ child.mode = 'display'
274
+ set_display_mode(child)
275
+
276
+
277
+ def array_display_renderer(widget, data):
278
+ array_edit_renderer(widget, data)
279
+ del widget['table']['head']['row']['actions']
280
+ for row in widget['table']['body'].values():
281
+ del row['actions_col']
282
+ del widget[CONTAINER]
283
+ set_display_mode(widget)
284
+
285
+
286
+ factory.register(
287
+ 'array',
288
+ extractors=[
289
+ array_extractor,
290
+ generic_required_extractor
291
+ ],
292
+ edit_renderers=[
293
+ array_edit_renderer,
294
+ compound_renderer,
295
+ array_wrapper_renderer
296
+ ],
297
+ display_renderers=[
298
+ array_display_renderer,
299
+ compound_renderer
300
+ ],
301
+ builders=[array_builder]
302
+ )
303
+
304
+ factory.doc['blueprint']['array'] = """\
305
+ Add-on widget `yafowil.widget.array
306
+ <http://github.com/conestack/yafowil.widget.array/>`_.
307
+ """
308
+
309
+ factory.defaults['array.class'] = 'array card'
310
+
311
+ factory.defaults['array.required'] = False
312
+
313
+ factory.defaults['array.error_class'] = 'error'
314
+
315
+ factory.defaults['array.message_class'] = 'errormessage'
316
+
317
+ factory.defaults['array.table_class'] = None
318
+ factory.doc['props']['array.table_class'] = """\
319
+ CSS classes rendered on array table.
320
+ """
321
+
322
+ factory.defaults['array.static'] = False
323
+ factory.doc['props']['array.static'] = """\
324
+ Array is immutable. No Array actions are rendered. If True, ``add``,
325
+ ``remove`` and ``sort`` properties are ignored.
326
+ """
327
+
328
+ factory.defaults['array.add'] = True
329
+ factory.doc['props']['array.add'] = """\
330
+ Render ``add`` action.
331
+ """
332
+
333
+ factory.defaults['array.remove'] = True
334
+ factory.doc['props']['array.remove'] = """\
335
+ Render ``remove`` action.
336
+ """
337
+
338
+ factory.defaults['array.sort'] = True
339
+ factory.doc['props']['array.sort'] = """\
340
+ Render ``move up`` and ``move down`` actions.
341
+ """
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: yafowil.widget.array
3
+ Version: 2.0.0
4
+ Summary: Array Widget for YAFOWIL
5
+ Author-email: Yafowil Contributors <dev@conestack.org>
6
+ License: Simplified BSD
7
+ License-File: LICENSE.rst
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: License :: OSI Approved :: BSD License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
18
+ Requires-Dist: yafowil>3.99
19
+ Provides-Extra: test
20
+ Requires-Dist: lxml; extra == 'test'
21
+ Requires-Dist: pytest; extra == 'test'
22
+ Description-Content-Type: text/x-rst
23
+
24
+ .. image:: https://img.shields.io/pypi/v/yafowil.widget.array.svg
25
+ :target: https://pypi.python.org/pypi/yafowil.widget.array
26
+ :alt: Latest PyPI version
27
+
28
+ .. image:: https://img.shields.io/pypi/dm/yafowil.widget.array.svg
29
+ :target: https://pypi.python.org/pypi/yafowil.widget.array
30
+ :alt: Number of PyPI downloads
31
+
32
+ .. image:: https://github.com/conestack/yafowil.widget.array/actions/workflows/test_py.yaml/badge.svg
33
+ :target: https://github.com/conestack/yafowil.widget.array/actions/workflows/test_py.yaml
34
+ :alt: Test yafowil.widget.array Python
35
+
36
+ .. image:: https://github.com/conestack/yafowil.widget.array/actions/workflows/test_js.yaml/badge.svg
37
+ :target: https://github.com/conestack/yafowil.widget.array/actions/workflows/test_js.yaml
38
+ :alt: Test yafowil.widget.array JS
39
+
40
+ This is an **array widget** for for `YAFOWIL
41
+ <http://pypi.python.org/pypi/yafowil>`_.
42
+
43
+ - `Documentation <http://docs.yafowil.info/en/latest/blueprints.html#array>`_
44
+ - `DEMO - see it Live <http://demo.yafowil.info/++widget++yafowil.widget.array/index.html>`_
45
+
46
+ Source Code
47
+ ===========
48
+
49
+ The sources are in a GIT DVCS with its main branches at
50
+ `github <http://github.com/conestack/yafowil.widget.array>`_.
51
+
52
+ We'd be happy to see many forks and pull-requests to make YAFOWIL even better.
53
+
54
+
55
+ Contributors
56
+ ============
57
+
58
+ - Robert Niederreiter
59
+
60
+ - Georg Bernhard
61
+
62
+ - Lena Daxenbichler
@@ -0,0 +1,23 @@
1
+ yafowil/widget/array/__init__.py,sha256=ed-QB1XiTIllllK-H3yLPXyT3xFW8x2hFPmUiRpAkIE,5687
2
+ yafowil/widget/array/example.py,sha256=zCOm5BRVUsZKJmd0LcNiOXU87kqoCmB-6P8QvlEUPE4,12219
3
+ yafowil/widget/array/widget.py,sha256=pR2MdPgHCE_vmuL5A8iQS4O5AvaZGRbNCBl7ZVxB5V4,10472
4
+ yafowil/widget/array/resources/bootstrap/widget.min.css,sha256=Ud2Wu5-68ZQEAuLPmIvQTAze8H-la_upQCCPX-a1LsA,1090
5
+ yafowil/widget/array/resources/bootstrap5/widget.js,sha256=h9sXU_QtHMe7MnQ1_kI7fliw8h4RVWGvsWLI9_P_s88,10271
6
+ yafowil/widget/array/resources/bootstrap5/widget.min.css,sha256=gj4nryz0kZtfjtIKE5NyGlFJZd9SlNrMemxBPp_yAso,1066
7
+ yafowil/widget/array/resources/bootstrap5/widget.min.js,sha256=nIbxATqBgDJJtTlnVc8LLR3JUArmLmd39AsA6qaCtIA,4989
8
+ yafowil/widget/array/resources/default/widget.js,sha256=SZJN2GQSlTKtX76tohHO0jnp61-pgI6oN5kab5tipM8,9627
9
+ yafowil/widget/array/resources/default/widget.min.css,sha256=CPrc0q9Fn9KCKEaZwrLAroj-rk20lKPQJI69SCn9zyQ,1268
10
+ yafowil/widget/array/resources/default/widget.min.js,sha256=geahGtiyMFF1PQZG4NXP2jflSkThLiCtqc7vfjoImj8,4641
11
+ yafowil/widget/array/resources/default/images/icon_add.png,sha256=fMDUpDyadrUFZKi1tmg8MewGlNtE7i95Z29F1f_lkWU,403
12
+ yafowil/widget/array/resources/default/images/icon_down.png,sha256=lZaOHin1R-mRJDIgogM3Xa-Ky4fjyyGKucENmCzQIQE,584
13
+ yafowil/widget/array/resources/default/images/icon_down_disabled.png,sha256=r9rzJce1ZcBN4uTxd18uu4u5RFqApQ9p7Pb7WAj3ajI,392
14
+ yafowil/widget/array/resources/default/images/icon_remove.png,sha256=SRk6RKB2VXAYmigvv0EY9V6ENeRfjM0aNw58ab-1wcI,221
15
+ yafowil/widget/array/resources/default/images/icon_up.png,sha256=Fh7PTO6ZQ0tpb0rQ3HkHaUS-jIfyY34m0JLT5AEVPPw,560
16
+ yafowil/widget/array/resources/default/images/icon_up_disabled.png,sha256=-MonqfrQOPIv1u9x0GMbU4UgCrjZ3mh-OKQUv2WjjZ8,382
17
+ yafowil/widget/array/resources/plone5/widget.min.css,sha256=gvJ738oMgW1uuOHx8N_aOz9Uv_OenNorotVgS-2LNQ0,1523
18
+ yafowil/widget/array/tests/test_widget.py,sha256=JWfTcZq0BufrYUzubNMxci-_WZnd0QfmSMwe7ucOQyc,83771
19
+ yafowil_widget_array-2.0.0.dist-info/METADATA,sha256=qion7oUj36wLU7-uCbhft2arwq9kWVtd9jWrs8pTx8A,2240
20
+ yafowil_widget_array-2.0.0.dist-info/WHEEL,sha256=aha0VrrYvgDJ3Xxl3db_g_MDIW-ZexDdrc_m-Hk8YY4,105
21
+ yafowil_widget_array-2.0.0.dist-info/entry_points.txt,sha256=7dISa7epdwrzzAMjYpE4TgHTd5398sa7VxVnL2AmYFo,109
22
+ yafowil_widget_array-2.0.0.dist-info/licenses/LICENSE.rst,sha256=F-rGZAUY0JHMT0A0X81pC1v3QlzPgNUUntZLhOAdPAs,1403
23
+ yafowil_widget_array-2.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [yafowil.plugin]
2
+ example = yafowil.widget.array.example:get_example
3
+ register = yafowil.widget.array:register
@@ -0,0 +1,27 @@
1
+ License
2
+ =======
3
+
4
+ Copyright (c) 2011-2021, BlueDynamics Alliance, Austria, Germany, Switzerland
5
+ Copyright (c) 2021-2025, Yafowil Contributors
6
+ All rights reserved.
7
+
8
+ Redistribution and use in source and binary forms, with or without
9
+ modification, are permitted provided that the following conditions are met:
10
+
11
+ * Redistributions of source code must retain the above copyright notice, this
12
+ list of conditions and the following disclaimer.
13
+
14
+ * Redistributions in binary form must reproduce the above copyright notice, this
15
+ list of conditions and the following disclaimer in the documentation and/or
16
+ other materials provided with the distribution.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.