Passed
Push — 2.x ( 5d5eda...426827 )
by Ramon
08:21
created

SelectOtherWidget.update()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE.
4
#
5
# SENAITE.CORE is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free Software
7
# Foundation, version 2.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
# details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 51
16
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#
18
# Copyright 2018-2024 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
import json
22
from bika.lims import _
23
from senaite.core.i18n import translate as t
24
from senaite.core.interfaces import ISenaiteFormLayer
25
from senaite.core.schema.interfaces import ISelectOtherField
26
from senaite.core.z3cform.interfaces import ISelectOtherWidget
27
from senaite.core.z3cform.widgets.basewidget import BaseWidget
28
from z3c.form.browser import widget
29
from z3c.form.browser.widget import HTMLTextInputWidget
30
from z3c.form.converter import BaseDataConverter
31
from z3c.form.interfaces import IFieldWidget
32
from z3c.form.widget import FieldWidget
33
from zope.component import adapter
34
from zope.component import queryUtility
35
from zope.interface import implementer
36
from zope.schema.interfaces import IVocabularyFactory
37
38
OTHER_OPTION_VALUE = "__other__"
39
40
41
@adapter(ISelectOtherField, ISelectOtherWidget)
42
class SelectOtherDataConverter(BaseDataConverter):
43
    """Converts the value between the field and the widget
44
    """
45
46
    def toWidgetValue(self, value):
47
        """Converts from field value to widget
48
        """
49
        return value
50
51
    def toFieldValue(self, value):
52
        """Converts from widget to field value
53
        """
54
        if isinstance(value, list):
55
            if value[0] == OTHER_OPTION_VALUE:
56
                return str(value[1])
57
            value = value[0]
58
        return str(value)
59
60
61
@implementer(ISelectOtherWidget)
62
class SelectOtherWidget(HTMLTextInputWidget, BaseWidget):
63
    """Widget for the selection of an option from a pre-populated list or
64
    manual introduction
65
    """
66
    klass = u"senaite-selectother-widget-input"
67
68
    def get_display_value(self):
69
        """Returns the value to display
70
        """
71
        choices = self.get_choices()
72
        choices = dict(choices)
73
        return choices.get(self.value) or self.value
74
75 View Code Duplication
    def get_input_widget_attributes(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
76
        """Return input widget attributes for the ReactJS component
77
        """
78
        option = ""
79
        other = ""
80
81
        # find out if the value is a predefined option
82
        choices = self.get_choices()
83
        options = dict(choices).keys()
84
        if self.value in options:
85
            option = self.value
86
        elif self.value:
87
            option = OTHER_OPTION_VALUE
88
            other = self.value
89
90
        attributes = {
91
            "data-id": self.id,
92
            "data-name": self.name,
93
            "data-choices": choices,
94
            "data-option": option,
95
            "data-option_other": OTHER_OPTION_VALUE,
96
            "data-other": other,
97
        }
98
99
        # convert all attributes to JSON
100
        for key, value in attributes.items():
101
            attributes[key] = json.dumps(value)
102
103
        return attributes
104
105
    def update(self):
106
        """Computes self.value for the widget templates
107
108
        see z3c.form.widget.Widget
109
        """
110
        super(SelectOtherWidget, self).update()
111
        widget.addFieldClass(self)
112
113
    def get_vocabulary(self):
114
        if not self.field:
115
            return None
116
117
        vocabulary = getattr(self.field, "vocabularyName", None)
118
        if not vocabulary:
119
            return None
120
121
        factory = queryUtility(IVocabularyFactory, vocabulary,)
122
        if not factory:
123
            return None
124
125
        return factory(self.context)
126
127
    def get_choices(self):
128
        """Returns the predefined options for this field
129
        """
130
        # generate a list of tuples (value, text) from vocabulary
131
        vocabulary = self.get_vocabulary()
132
        choices = [(term.value, t(term.title)) for term in vocabulary]
133
134
        # insert the empty option
135
        choices.insert(0, ("", ""))
136
137
        # append the "Other..." choice
138
        other = (OTHER_OPTION_VALUE, t(_("Other...")))
139
        choices.append(other)
140
141
        return choices
142
143
144
@adapter(ISelectOtherField, ISenaiteFormLayer)
145
@implementer(IFieldWidget)
146
def SelectOtherWidgetFactory(field, request):
147
    """Widget factory for SelectOther field
148
    """
149
    return FieldWidget(field, SelectOtherWidget(request))
150