input_ctrl.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import logging
  2. from .framework import WebIOFuture, Global
  3. logger = logging.getLogger(__name__)
  4. def run_async(coro_obj):
  5. Global.active_ws.inactive_coro_instances.append(coro_obj)
  6. def send_msg(cmd, spec=None):
  7. msg = dict(command=cmd, spec=spec, coro_id=Global.active_coro_id)
  8. Global.active_ws.add_server_msg(msg)
  9. async def next_event():
  10. res = await WebIOFuture()
  11. return res
  12. async def single_input(item_spec, valid_func, preprocess_func):
  13. """
  14. Note: 鲁棒性在上层完成
  15. 将单个input构造成input_group,并获取返回值
  16. :param item_spec: 单个输入项的参数 'name' must in item_spec, 参数一定已经验证通过
  17. :param valid_func: Not None
  18. :param preprocess_func: Not None
  19. """
  20. label = item_spec['label']
  21. name = item_spec['name']
  22. # todo 是否可以原地修改spec
  23. item_spec['label'] = ''
  24. item_spec.setdefault('auto_focus', True) # 如果没有设置autofocus参数,则开启参数 todo CHECKBOX, RADIO 特殊处理
  25. spec = dict(label=label, inputs=[item_spec])
  26. data = await input_control(spec, {name: preprocess_func}, {name: valid_func})
  27. return data[name]
  28. async def input_control(spec, preprocess_funcs, item_valid_funcs, form_valid_funcs=None):
  29. """
  30. 发送input命令,监听事件,验证输入项,返回结果
  31. :param spec:
  32. :param preprocess_funcs: keys 严格等于 spec中的name集合
  33. :param item_valid_funcs: keys 严格等于 spec中的name集合
  34. :param form_valid_funcs:
  35. :return:
  36. """
  37. send_msg('input_group', spec)
  38. data = await input_event_handle(item_valid_funcs, form_valid_funcs, preprocess_funcs)
  39. send_msg('destroy_form')
  40. return data
  41. def check_item(name, data, valid_func, preprocess_func):
  42. try:
  43. data = preprocess_func(data)
  44. error_msg = valid_func(data)
  45. except:
  46. # todo log warning
  47. error_msg = '字段内容不合法'
  48. if error_msg is not None:
  49. send_msg('update_input', dict(target_name=name, attributes={
  50. 'valid_status': False,
  51. 'invalid_feedback': error_msg
  52. }))
  53. return False
  54. return True
  55. async def input_event_handle(item_valid_funcs, form_valid_funcs, preprocess_funcs):
  56. """
  57. 根据提供的校验函数处理表单事件
  58. :param item_valid_funcs: map(name -> valid_func) valid_func 为 None 时,不进行验证
  59. valid_func: callback(data) -> error_msg or None
  60. :param form_valid_funcs: callback(data) -> (name, error_msg) or None
  61. :param preprocess_funcs:
  62. :return:
  63. """
  64. while True:
  65. event = await next_event()
  66. event_name, event_data = event['event'], event['data']
  67. if event_name == 'input_event':
  68. input_event = event_data['event_name']
  69. if input_event == 'blur':
  70. onblur_name = event_data['name']
  71. check_item(onblur_name, event_data['value'], item_valid_funcs[onblur_name],
  72. preprocess_funcs[onblur_name])
  73. elif event_name == 'from_submit':
  74. all_valid = True
  75. # 调用输入项验证函数进行校验
  76. for name, valid_func in item_valid_funcs.items():
  77. if not check_item(name, event_data[name], valid_func, preprocess_funcs[name]):
  78. all_valid = False
  79. if all_valid: # todo 减少preprocess_funcs[name]调用次数
  80. data = {name: preprocess_funcs[name](val) for name, val in event_data.items()}
  81. # 调用表单验证函数进行校验
  82. if form_valid_funcs:
  83. v_res = form_valid_funcs(data)
  84. if v_res is not None:
  85. all_valid = False
  86. onblur_name, error_msg = v_res
  87. send_msg('update_input', dict(target_name=onblur_name, attributes={
  88. 'valid_status': False,
  89. 'invalid_feedback': error_msg
  90. }))
  91. if all_valid:
  92. break
  93. else:
  94. logger.warning("Unhandled Event: %s", event)
  95. return data