1
0
Эх сурвалжийг харах

fix add-unique and toggle mode

Falko Schindler 1 жил өмнө
parent
commit
0017582caa

+ 25 - 11
nicegui/elements/select.py

@@ -49,6 +49,8 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
         if label is not None:
         if label is not None:
             self._props['label'] = label
             self._props['label'] = label
         if new_value_mode is not None:
         if new_value_mode is not None:
+            if isinstance(options, dict) and new_value_mode == 'add':
+                raise ValueError('new_value_mode "add" is not supported for dict options')
             self._props['new-value-mode'] = new_value_mode
             self._props['new-value-mode'] = new_value_mode
             with_input = True
             with_input = True
         if with_input:
         if with_input:
@@ -66,21 +68,18 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
             if e.args is None:
             if e.args is None:
                 return []
                 return []
             else:
             else:
-                out = []
+                args = [self._values[arg['value']] if isinstance(arg, dict) else arg for arg in e.args]
                 for arg in e.args:
                 for arg in e.args:
                     if isinstance(arg, str):
                     if isinstance(arg, str):
                         self._handle_new_value(arg)
                         self._handle_new_value(arg)
-                        out.append(self._values[len(self.options) - 1])
-                    else:
-                        out.append(self._values[arg['value']])
-                return out
+                return [arg for arg in args if arg in self._values]
         else:
         else:
             if e.args is None:
             if e.args is None:
                 return None
                 return None
             else:
             else:
                 if isinstance(e.args, str):
                 if isinstance(e.args, str):
                     self._handle_new_value(e.args)
                     self._handle_new_value(e.args)
-                    return self._values[len(self.options) - 1]
+                    return e.args if e.args in self._values else None
                 else:
                 else:
                     return self._values[e.args['value']]
                     return self._values[e.args['value']]
 
 
@@ -103,11 +102,26 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
                 return None
                 return None
 
 
     def _handle_new_value(self, value: str) -> None:
     def _handle_new_value(self, value: str) -> None:
-        # TODO: handle add-unique and toggle
+        mode = self._props['new-value-mode']
         if isinstance(self.options, list):
         if isinstance(self.options, list):
-            self.options.append(value)
+            if mode == 'add':
+                self.options.append(value)
+            elif mode == 'add-unique':
+                if value not in self.options:
+                    self.options.append(value)
+            elif mode == 'toggle':
+                if value in self.options:
+                    self.options.remove(value)
+                else:
+                    self.options.append(value)
             # NOTE: self._labels and self._values are updated via self.options since they share the same references
             # NOTE: self._labels and self._values are updated via self.options since they share the same references
         else:
         else:
-            self.options[value] = value
-            self._labels.append(value)
-            self._values.append(value)
+            if mode in 'add-unique':
+                if value not in self.options:
+                    self.options[value] = value
+            elif mode == 'toggle':
+                if value in self.options:
+                    self.options.pop(value)
+                else:
+                    self.options.update({value: value})
+            self._update_values_and_labels()

+ 25 - 8
tests/test_select.py

@@ -99,9 +99,14 @@ def test_set_options(screen:  Screen):
 
 
 @pytest.mark.parametrize('option_dict', [False, True])
 @pytest.mark.parametrize('option_dict', [False, True])
 @pytest.mark.parametrize('multiple', [False, True])
 @pytest.mark.parametrize('multiple', [False, True])
-@pytest.mark.parametrize('new_value_mode', ['add', None])
+@pytest.mark.parametrize('new_value_mode', ['add', 'add-unique', 'toggle', None])
 def test_add_new_values(screen:  Screen, option_dict: bool, multiple: bool, new_value_mode: Optional[str]):
 def test_add_new_values(screen:  Screen, option_dict: bool, multiple: bool, new_value_mode: Optional[str]):
     options = {'a': 'A', 'b': 'B', 'c': 'C'} if option_dict else ['a', 'b', 'c']
     options = {'a': 'A', 'b': 'B', 'c': 'C'} if option_dict else ['a', 'b', 'c']
+    if option_dict and new_value_mode == 'add':
+        with pytest.raises(ValueError, match='new_value_mode "add" is not supported for dict options'):
+            ui.select(options=options, multiple=multiple, new_value_mode=new_value_mode)
+        return
+
     s = ui.select(options=options, multiple=multiple, new_value_mode=new_value_mode)
     s = ui.select(options=options, multiple=multiple, new_value_mode=new_value_mode)
     ui.label().bind_text_from(s, 'value', lambda v: f'value = {v}')
     ui.label().bind_text_from(s, 'value', lambda v: f'value = {v}')
     ui.label().bind_text_from(s, 'options', lambda v: f'options = {v}')
     ui.label().bind_text_from(s, 'options', lambda v: f'options = {v}')
@@ -116,10 +121,22 @@ def test_add_new_values(screen:  Screen, option_dict: bool, multiple: bool, new_
     screen.should_contain("value = ['a']" if multiple else 'value = a')
     screen.should_contain("value = ['a']" if multiple else 'value = a')
 
 
     if new_value_mode:
     if new_value_mode:
-        screen.find_by_tag('input').send_keys(Keys.BACKSPACE + 'd')
-        screen.wait(0.5)
-        screen.find_by_tag('input').send_keys(Keys.ENTER)
-        screen.wait(0.5)
-        screen.should_contain("value = ['a', 'd']" if multiple else 'value = d')
-        screen.should_contain(
-            "options = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'd'}" if option_dict else "options = ['a', 'b', 'c', 'd']")
+        for _ in range(2):
+            screen.find_by_tag('input').send_keys(Keys.BACKSPACE + 'd')
+            screen.wait(0.5)
+            screen.find_by_tag('input').click()
+            screen.wait(0.5)
+            screen.find_by_tag('input').send_keys(Keys.ENTER)
+            screen.wait(0.5)
+        if new_value_mode == 'add':
+            screen.should_contain("value = ['a', 'd', 'd']" if multiple else 'value = d')
+            screen.should_contain("options = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'd', 'd': 'd'}" if option_dict else
+                                  "options = ['a', 'b', 'c', 'd', 'd']")
+        elif new_value_mode == 'add-unique':
+            screen.should_contain("value = ['a', 'd', 'd']" if multiple else 'value = d')
+            screen.should_contain("options = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'd'}" if option_dict else
+                                  "options = ['a', 'b', 'c', 'd']")
+        elif new_value_mode == 'toggle':
+            screen.should_contain("value = ['a']" if multiple else 'value = None')
+            screen.should_contain("options = {'a': 'A', 'b': 'B', 'c': 'C'}" if option_dict else
+                                  "options = ['a', 'b', 'c']")