瀏覽代碼

feat: `run_js` & `eval_js` support set arguments

wangweimin 4 年之前
父節點
當前提交
d6c82f6fb1
共有 4 個文件被更改,包括 33 次插入18 次删除
  1. 4 1
      docs/spec.rst
  2. 18 11
      pywebio/session/__init__.py
  3. 2 3
      test/template.py
  4. 9 3
      webiojs/src/handlers/script.ts

+ 4 - 1
docs/spec.rst

@@ -266,7 +266,10 @@ run_script
 ^^^^^^^^^^^^^^^
 运行js代码
 
-命令 spec 字段为字符串格式的要运行的js代码
+命令 spec 字段:
+
+* code: 字符串格式的要运行的js代码
+* args: 传递给代码的局部变量。字典类型,字典键表示变量名,字典值表示变量值(变量值需要可以被json序列化)
 
 download
 ^^^^^^^^^^^^^^^

+ 18 - 11
pywebio/session/__init__.py

@@ -148,23 +148,30 @@ def download(name, content):
     send_msg('download', spec=dict(name=name, content=content))
 
 
-def run_js(code):
+def run_js(code, **args):
     """运行js代码.
 
     代码运行在浏览器的JS全局作用域中
 
     :param str code: js代码
+    :param args: 传递给js代码的局部变量。变量值需要可以被json序列化
+
+    Example::
+
+        run_js('console.log(a + b)', a=1, b=2)
+
     """
     from ..io_ctrl import send_msg
-    send_msg('run_script', spec=code)
+    send_msg('run_script', spec=dict(code=code, args=args))
 
 
 @chose_impl
-def eval_js(expression):
+def eval_js(expression, **args):
     """执行js表达式,并获取表达式的值
 
     :param str expression: js表达式. 表达式的值需要能JSON序列化
     :return: js表达式的值
+    :param args: 传递给js代码的局部变量。变量值需要可以被json序列化
 
     注意⚠️:在 :ref:`基于协程 <coroutine_based_session>` 的会话上下文中,需要使用 ``await eval_js(expression)`` 语法来进行调用。
 
@@ -174,29 +181,29 @@ def eval_js(expression):
 
         function_res = eval_js('''(function(){
             var a = 1;
-            a += 100;
+            a += b;
             return a;
-        })()''')
+        })()''', b=100)
     """
     script = r"""
     (function(WebIO){
-        let result = null;
+        let ____result____ = null;  // to avoid naming conflict
         try{
-            result = eval(%r);
+            ____result____ = eval(%r);
         }catch{};
         
         WebIO.sendMessage({
             event: "js_yield",
             task_id: WebIOCurrentTaskID,  // local var in run_script command
-            data: result || null
+            data: ____result____ || null
         });
     })(WebIO);""" % expression
 
-    run_js(script)
+    run_js(script, **args)
 
     res = yield next_client_event()
-    assert res[
-               'event'] == 'js_yield', "Internal Error, please report this bug on https://github.com/wang0618/PyWebIO/issues"
+    assert res['event'] == 'js_yield', "Internal Error, please report this bug on " \
+                                       "https://github.com/wang0618/PyWebIO/issues"
     return res['data']
 
 

+ 2 - 3
test/template.py

@@ -365,11 +365,10 @@ def test_output(browser: Chrome, enable_percy=False):
 
 def basic_input():
     js_res = yield eval_js('''(function(){
-        var a = 0;
-        for(var i=0;i<=100;i++)
+        for(var i=0;i<=limit;i++)
             a += i;
         return a;
-    })()''')
+    })()''', a=0, limit=100)
     assert js_res == 5050
 
     age = yield input("How old are you?", type=NUMBER)

+ 9 - 3
webiojs/src/handlers/script.ts

@@ -12,8 +12,14 @@ export class ScriptHandler implements CommandHandler {
     }
 
     handle_message(msg: Command) {
-        let script = msg.spec as string;
-        const script_func = new Function('WebIOCurrentTaskID', script);
-        script_func(msg.task_id);
+        let script = msg.spec.code as string;
+        let args = msg.spec.args as { [i: string]: any };
+        let arg_names:string[] = ['WebIOCurrentTaskID'], arg_vals:any[] = [msg.task_id];
+        for(let key in args){
+            arg_names.push(key);
+            arg_vals.push(args[key]);
+        }
+        const script_func = new Function(...arg_names, script);
+        script_func(...arg_vals);
     }
 }