元素扩展开发人员指南¶
扩展是一种向现有元素添加自定义逻辑和额外复杂性的方法。每个元素都能够加载相关扩展,因此,扩展应该针对一个特定元素进行定制。
伸展解剖¶
扩展只能在课程中定义,位于 [course directory]/elementExtensions 中。该文件夹的组织方式使得元素包含为子文件夹,然后扩展包含在元素文件夹内。例如,如果您的扩展名 exampleExtension 扩展了 exampleElement,则文件夹结构将为:[course directory]/elementExtensions/exampleElement/exampleExtension。
每个扩展只需要一个包含有关元素的元数据的 info.json,并且可以包含可选信息,例如 Python 脚本、CSS 样式和客户端 JavaScript 文件。
info.json 文件在结构上与元素信息文件类似,可能包含以下字段:
{
"controller": "Python script",
"dependencies": {
"nodeModulesStyles": ["style_file_path"],
"nodeModulesScripts": ["script_file_path"],
"clientFilesCourseStyles": ["style_file_path"],
"clientFilesCourseScripts": ["script_file_path"],
"extensionStyles": ["style_file_path"],
"extensionScripts": ["script_file_path"]
},
"dynamicDependencies": {
"nodeModulesScripts": { "module_name": "module_path" },
"clientFilesCourseScripts": { "file_name": "file_path" },
"extensionScripts": { "file_name": "file_path" }
}
}
有关可以添加到此文件的内容的更多信息,请参阅infoElementExtension.json 的参考。
Python控制器¶
主 Python 控制器脚本没有通用结构,而是由正在扩展的元素定义。任何全局函数和变量都可供宿主元素使用。
主机元素可以调用 load_extension() 函数来加载一个特定的扩展,或者调用 load_all_extensions() 来加载所有可用的内容。这些在自由格式 prairielearn 模块中定义。
元素及其扩展之间存在双向的逻辑和信息流。
从元素导入扩展¶
加载扩展 Python 脚本会返回所有全局定义的函数和变量的命名元组。加载所有扩展将返回一个将扩展名称映射到其命名元组的字典。例如,如果扩展要在其控制器中定义以下内容:
def my_cool_function():
return "hello, world!"
然后,宿主元素可以通过运行以下命令来调用它:
import prairielearn as pl
def render(element_html, data):
extension = pl.load_extension(data, "extension_name")
contents = extension.my_cool_function()
return contents
上面的这个小例子会将 "hello world!" 渲染到问题页面。请注意,当使用 load_all_extensions() 加载所有扩展时,模块按字母升序返回。
从扩展导入主机元素¶
扩展还可以使用 load_host_script() 函数从其主机元素导入文件。这可用于获取辅助函数、类定义、常量变量等。
例如,如果宿主元素包含:
import prairielearn as pl
STATIC_VARIABLE = "hello"
def render(element_html, data):
extension = pl.load_extension(data, "extension_name")
contents = extension.my_cool_function()
return contents
然后,扩展程序可以通过导入主机脚本来访问 STATIC_VARIABLE:
import prairielearn as pl
host_element = pl.load_host_script("pl-host-element.py")
def my_cool_function():
return host_element.STATIC_VARIABLE
扩展依赖项¶
与问题和元素可能需要客户端资产(如元素开发人员指南 中所述)类似,扩展也可能需要客户端 JavaScript 和 CSS。这里总结了不同的属性。请注意,脚本依赖项可以设置为静态或动态依赖项,而样式只能设置为静态依赖项。
| 物业 | 描述 |
|---|---|
nodeModulesStyles |
此扩展所需的样式,相对于 [ZJUI-Learn directory]/node_modules。 |
nodeModulesScripts |
此扩展所需的脚本,相对于 [ZJUI-Learn directory]/node_modules。 |
extensionStyles |
该元素所需的样式相对于扩展的目录 [course directory]/elementExtensions/element-name/extension-name。 |
extensionScripts |
该元素所需的脚本相对于扩展的目录 [course directory]/elementExtensions/element-name/extension-name。 |
clientFilesCourseStyles |
此扩展所需的样式相对于[course directory]/clientFilesCourse。 |
clientFilesCourseScripts |
此扩展所需的脚本相对于 [course directory]/clientFilesCourse。 |
请注意,在 dependencies 中声明的任何元素扩展资源都将始终被加载,无论其 Python 控制器是否已加载。因此,建议在合适的情况下,根据元素的上下文/用法,扩展仅在必要时才使用 dynamicDependencies 加载脚本。
Warning
请记住,应避免节点模块依赖项,因为它们可能会在没有警告的情况下进行更新,这在某些情况下可能会破坏您的扩展。更多信息可以在元素开发者指南中找到。
其他客户端文件¶
还可以加载客户端可用的其他文件,例如图像或任何可下载内容。这些客户端文件应放置在扩展目录中的 clientFilesExtension 中,并且该文件夹的完整 URL 会提供给 data["options"]["client_files_extensions_url"][extension_name] 中的主机扩展。如果扩展本身需要此路径,则可以将其作为参数传递给已定义的扩展函数。