通过 Tornado UIModule 嵌入多个 JavaScript

Embedding multiple pieces of JavaScript via a Tornado UIModule

我正在开发一个 Python 包,它使用 Tornado 将数据发送到浏览器以进行可视化。为了做到这一点,我希望用户能够为服务器编写多个任意模块以在单个页面上一起呈现——包括每个模块自己的 JavaScript。

但是,默认情况下,Tornado 的 UIModule class 的 embedded_javascript() 方法每个模块仅将 JavaScript 附加到 <script>...</script> 一次 class.我希望有一种简单的方法来嵌入多个 JS,每个 UIModule 一个(或另一种获得相同效果的方法)。

下面是我所说内容的一个最小示例:

import tornado.ioloop
import tornado.web
import tornado.template

class Element(tornado.web.UIModule):
    '''
    Module to add some custom JavaScript to the page.
    '''
    def render(self, element):
        self.js_code = element.js_code
        return ""

    def embedded_javascript(self):
        return self.js_code

class InterfaceElement(object):
    '''
    Object to store some custom JavaScript code.
    '''
    def __init__(self, js_code):
        '''
        Args:
            js_code: Some JavaScript code in string form to add to the page.
        '''
        self.js_code = js_code


class MainPageHandler(tornado.web.RequestHandler):
    def get(self):
        elements = self.application.modules
        self.render("uitest_template.html", app_name="Testing", elements=elements)


class ThisApp(tornado.web.Application):
    def __init__(self, modules):
        self.modules = modules
        main_handler = (r'/', MainPageHandler)
        #settings = {"ui_modules": {"Element": Element}}
        settings = {"ui_modules": {"Element": Element},
                    "template_path": "ui_templates"}
        super().__init__([main_handler], **settings)

# Create two objects with some custom JavaScript to render
module_1 = InterfaceElement("var a = 1;")
module_2 = InterfaceElement("var b = 2;")

app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()

uitest_template.html的模板就是

<!DOCTYPE html>
<head>
    <title> Hello World </title>
</head>
<body>
    {% for element in elements %}
        {%module Element(element) %}
    {% end %}
</body>

呈现的页面然后在正文中包含一个 <script> 标记,即:

<script type="text/javascript">
//<![CDATA[
var b = 2;
//]]>
</script>

而我想要的是:

<script type="text/javascript">
//<![CDATA[
var a = 1;
var b = 2;
//]]>
</script>

或类似的东西。有什么想法吗?

已添加 - 我的解决方案

根据下面的回答,我最终是这样处理的:

import tornado.ioloop
import tornado.web
import tornado.template


class InterfaceElement(object):
    include_js = [] # List of .js files to include
    js_code = '' # JavaScript string to include

    def __init__(self, include_js=[], js_code=''):
        self.include_js = include_js
        self.js_code = js_code

class MainPageHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("modular_template.html", 
                    includes=self.application.include_js, 
                    scripts=self.application.js_code)


class ThisApp(tornado.web.Application):
    def __init__(self, modules):
        # Extract the relevant info from modules:
        self.modules = modules
        self.include_js = set()
        self.js_code = []
        for module in self.modules:
            for include_file in module.include_js:
                self.include_js.add(include_file)
            if module.js_code != '':
                self.js_code.append(module.js_code)


        main_handler = (r'/', MainPageHandler)
        settings = {"template_path": "ui_templates",
                    "static_path": "ui_templates"}
        super().__init__([main_handler], **settings)

module_1 = InterfaceElement(js_code="var a = 1;")
module_2 = InterfaceElement(include_js=["test.js"], js_code="var b = 1;")

app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()

使用以下模板:

<!DOCTYPE html>
<head>
    <title> Hello world </title>
</head>
<body>
    <!-- Script includes go here -->
    {% for file_name in includes %}
        <script src="/static/{{ file_name }}" type="text/javascript"></script>
    {% end %}
    <script type="text/javascript">
        // Actual script snippets go here.
        {% for script in scripts %}
            {% raw script %}
        {% end %}
    </script> 

</body>

embedded_javascript 和相关方法是(有效的)class 级方法;对于 class 的任何实例,它们必须 return 具有相同的值。 (它们旨在成为一种依赖管理系统,因此您只能在包含需要它的模块的页面上加载 javascript)

每个实例唯一允许变化的是 render() 的输出,因此要嵌入多个 javascript,您应该在 render() 方法的结果中包含脚本标记。