7878 * The first parameter of pin widget function is always the name of the widget,
7979 and if you output two pin widgets with the same name, the previous one will expire.
8080 * Pin functions don't support the ``on_change`` and ``validate`` callbacks, and the ``required`` parameter.
81+ (There is a :func:`pin_on_change()` function as an alternative to ``on_change``)
8182 * Pin functions have additional ``scope`` and ``position`` parameters for output control.
8283
8384.. autofunction:: put_input
121122"""
122123
123124import string
124- import threading
125- from collections import defaultdict
126125
127126from pywebio .input import parse_input_update_spec
128127from pywebio .output import OutputPosition , Output
129128from pywebio .output import _get_output_spec
130- from .io_ctrl import send_msg , single_input_kwargs
131- from .session import next_client_event , chose_impl , get_current_session , get_session_implement , CoroutineBasedSession , \
132- run_async , register_thread , SessionException
133- from .utils import run_as_function , to_coroutine
129+ from .io_ctrl import send_msg , single_input_kwargs , output_register_callback
130+ from .session import next_client_event , chose_impl
134131
135132_pin_name_chars = set (string .ascii_letters + string .digits + '_-' )
136133
@@ -334,7 +331,7 @@ def pin_update(name, **spec):
334331 send_msg ('pin_update' , spec = dict (name = name , attributes = attributes ))
335332
336333
337- def pin_on_change (name , onchange , clear = False ):
334+ def pin_on_change (name , onchange = None , clear = False , ** callback_options ):
338335 """
339336 Bind a callback function to pin widget, the function will be called when user change the value of the pin widget.
340337
@@ -344,41 +341,16 @@ def pin_on_change(name, onchange, clear=False):
344341
345342 :param str name: pin widget name
346343 :param callable onchange: callback function
347- :param bool clear: whether to clear the previous callbacks bound to this pin widget
344+ :param bool clear: whether to clear the previous callbacks bound to this pin widget.
345+ If you just want to clear callbacks and not set new callback, use ``pin_on_change(name, clear=True)``.
346+ :param callback_options: Other options of the ``onclick`` callback.
347+ Refer to the ``callback_options`` parameter of :func:`put_buttons() <pywebio.output.put_buttons>`
348348
349349 .. versionadded:: 1.6
350350 """
351- current_session = get_current_session ()
352-
353- def pin_on_change_gen ():
354- while True :
355- names = list (current_session .internal_save ['pin_on_change_callbacks' ].keys ())
356- if not names :
357- continue
358-
359- info = yield pin_wait_change (* names )
360- callbacks = current_session .internal_save ['pin_on_change_callbacks' ][info ['name' ]]
361- for callback in callbacks :
362- try :
363- callback (info ['value' ])
364- except Exception as e :
365- if not isinstance (e , SessionException ):
366- current_session .on_task_exception ()
367-
368- first_run = False
369- if 'pin_on_change_callbacks' not in current_session .internal_save :
370- current_session .internal_save ['pin_on_change_callbacks' ] = defaultdict (list )
371- first_run = True
372-
373- if clear :
374- current_session .internal_save ['pin_on_change_callbacks' ][name ] = [onchange ]
351+ assert not (onchange is None and clear is False ), "When `onchange` is `None`, `clear` must be `True`"
352+ if onchange is not None :
353+ callback_id = output_register_callback (onchange , ** callback_options )
375354 else :
376- current_session .internal_save ['pin_on_change_callbacks' ][name ].append (onchange )
377-
378- if first_run :
379- if get_session_implement () == CoroutineBasedSession :
380- run_async (to_coroutine (pin_on_change_gen ()))
381- else :
382- t = threading .Thread (target = lambda : run_as_function (pin_on_change_gen ()), daemon = True )
383- register_thread (t )
384- t .start ()
355+ callback_id = None
356+ send_msg ('pin_onchange' , spec = dict (name = name , callback_id = callback_id , clear = clear ))
0 commit comments