JavaScript¶
CubicWeb 在其用户界面中使用了相当多的javascript,并随jquery(1.3.x)和jquery UI库的一部分一起提供,另外还有一些本地文件和其他第三方库。
所有javascript文件都存储在cubicWeb/web/data/中。那里大约有30个JS文件。在多维数据集中,它转到数据/。
显然,人们不希望同时加载所有的javascript片段,因此框架提供了许多机制和约定来处理javascript资源。
习俗¶
在多维数据集的名称后面命名多维数据集特定的JS文件是一种很好的做法,例如:“cube.mycube.js”,以避免名称冲突。
服务器端javascript API¶
JavaScript资源通常是根据需要从视图加载的。请求对象(从大多数应用程序对象,例如视图和实体对象,以self._cw形式提供)有几种方法可以做到这一点:
add_js(self, jsfiles, localfile=True) 它获取一系列的javascript文件,并将适当的条目写入HTML标题部分。localfile参数允许声明不来自web/data的资源(例如,驻留在内容交付网络上)。
add_onload(self, jscode) 它在HTML标题中添加了一个内嵌的原始JavaScript代码段。这对于设置早期jquery(document).ready(…)初始化非常有用。
javascript事件¶
server-response
:此事件由HTTP响应(标准和Ajax)触发。以下两个额外参数将传递给回调:ajax
:一个布尔值,表示响应是否由Ajax请求发出。node
:如果是Ajax请求,服务器返回的DOM节点,否则是标准HTTP请求的文档本身。
重要的javascript Ajax API¶
asyncRemoteExec 和 remoteExec 是执行任意异步(resp.同步)与服务器的通信
reloadComponent 是用来自特定注册表的服务器提供的内容替换DOM节点的一个方便函数(这对于刷新实例的某些框的内容非常方便)
jQuery.fn.loadxhtml 是jquery的一个重要扩展,它允许对xhtml视图进行适当的加载和本地的dom更新。它被适当地增强以触发必要的事件,并处理CubicWeb特定的元素,如方面系统、fckeditor等。
AsyncRemoteExec的简单示例¶
在python方面,我们必须定义 cubicweb.web.views.ajaxcontroller.AjaxFunction
对象。最简单的方法是使用 cubicweb.web.views.ajaxcontroller.ajaxfunc()
装饰师(有关详细信息,请参阅 阿贾克斯 )
在JavaScript方面,我们执行异步调用。注意它如何创建 deferred 对象。必须通过addCallback和adderrback方法正确处理返回值或错误处理。
重新加载组件调用的剖析¶
reloadComponent 允许用新元素动态替换某些DOM节点。签字如下:
compid (强制)是要重新加载的组件的名称
rql (可选)将用于生成作为所选组件的参数提供的结果集
registry (可选)默认为“components”,但可以是任何其他有效的注册表名称
nodeid (可选)默认为compid+“component”,但可以是任何显式指定的dom节点id
extraargs (可选)应该是一个值字典,该字典将提供给组件的单元调用方法
一个简单的reloadcomponent示例¶
The server side implementation of reloadComponent is the
cubicweb.web.views.ajaxcontroller.component()
AjaxFunction appobject.
下面的函数实现了两步删除标准书签和刷新用户界面的方法,同时保持用户界面的响应性。
function removeBookmark(beid) {
d = asyncRemoteExec('delete_bookmark', beid);
d.addCallback(function(boxcontent) {
reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
document.location.hash = '#header';
updateMessage(_("bookmark has been removed"));
});
}
reloadComponent 调用时使用书签框的ID作为参数,不使用Rql表达式(因为书签显示实际上不依赖于任何数据集上下文),引用“box”注册表(它承载所有左、右和上下文框),最后使用显式的“bookmarks_box”nodeid参数that指定目标dom节点。
loadXHTML调用的剖析¶
jQuery.fn.loadxhtml is an important extension to jQuery which allows proper loading and in-place DOM update of xhtml views. The existing jQuery.load 函数不处理XHTML,因此添加了。loadXHTML的API与 jQuery.load .
url (强制)应为完整的URL(通常引用
cubicweb.web.views.ajaxcontroller.AjaxController
,但这不是严格的强制性要求)data (可选)是通过 url 参数;根据所选控制器(例如 fname 对于jsonController);The callback 键(如果存在)必须引用要在loadXHTML结尾处调用的函数(有关详细信息,请参阅下文)。
reqtype (可选)指定要使用的请求方法(get或post);如果参数为“post”,则使用post方法,否则使用get方法。
mode (可选)是 replace (默认)这意味着加载的节点将替换当前节点内容, swap 将当前节点替换为加载的节点,以及 append 将加载的节点附加到当前节点内容
关于 callback 选项:
它由两个参数调用:当前节点和包含已加载(和后处理)节点的列表。
每当它返回另一个函数时,就会使用与上面相同的参数依次调用该函数
此机制允许回调链接。
LoadXHTML的一个简单示例¶
这里我们关注的是要注入到活动DOM中的特定视图的检索。当然,将使用客户端提供的实体ID来选择服务器端视图。
from cubicweb.web.views.ajaxcontroller import ajaxfunc
@ajaxfunc(output_type='xhtml')
def frob_status(self, eid, frobname):
entity = self._cw.entity_from_eid(eid)
return entity.view('frob', name=frobname)
function updateSomeDiv(divid, eid, frobname) {
var params = {fname:'frob_status', eid: eid, frobname:frobname};
jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
}
在本例中,url参数是多维数据集实例的基本JSON URL(它应该包含类似于 http://myinstance/ajax? )。实际AjaxController方法名编码在 params 字典使用 fname 关键。
更真实的例子¶
Web 2应用程序的一个常见需求是延迟(或按需驱动)加载DOM的各个部分。这通常是通过准备初始的DOM节点、jQuery事件处理和正确使用loadXHTML来实现的。
我们在此介绍了CubicWeb中使用的Mecanism的框架版本,并在web/views/tabs.py中提供。 LazyViewMixin 班级。
def lazyview(self, vid, rql=None):
""" a lazy version of wview """
w = self.w
self._cw.add_js('cubicweb.lazy.js')
urlparams = {'vid' : vid, 'fname' : 'view'}
if rql is not None:
urlparams['rql'] = rql
w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
vid, xml_escape(self._cw.build_url('json', **urlparams))))
w(u'</div>')
self._cw.add_onload(u"""
jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
loadNow('#lazy-%(vid)s');});"""
% {'event': 'load_%s' % vid, 'vid': vid})
这创造了一个 div 与它相关联的特定事件。
完整版本涉及:
可选参数,如实体ID、RSET
进一步重新加载碎片的能力
在碎片未加载时显示旋转轮的能力
处理不支持Ajax的浏览器(搜索引擎、基于文本的浏览器,如lynx等)
由于loadXHTML的出色性能,JavaScript方面相当简单。
function loadNow(eltsel) {
var lazydiv = jQuery(eltsel);
lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
}
这与以前的情况大不相同 simple example (尽管这个例子实际上来自真实的代码)。
注意如何 cubicweb:loadurl 用于传递URL信息。此URL的基与全局javascript json_base_URL类似。根据前面描述的模式, fname 参数参照标准 js_view jsonController的方法。此方法呈现提供视图ID的任意视图(或 vid )提供,并且很可能是一个RQL表达式,生成一个结果集,根据该结果集选择适当的视图实例。
这个 cubicweb:loadurl 是特定CubicWeb命名空间中XHTML的29个属性扩展之一。它是一种传递信息的方法,不会破坏HTML或XHTML的遵从性,也不会诉诸于不道德的黑客攻击。
考虑到所有这些,很容易添加一个小而有用的特性来强制加载一个懒惰的视图(例如,一个非常计算密集的网页可以闪烁成一个快速加载部分和一个延迟部分)。
在服务器端,对javascript函数的简单调用就足够了。
def forceview(self, vid):
"""trigger an event that will force immediate loading of the view
on dom readyness
"""
self._cw.add_onload("triggerLoad('%s');" % vid)
浏览器端定义如下。
function triggerLoad(divid) {
jQuery('#lazy-' + divd).trigger('load_' + divid);
}
javascript库:概述¶
jquery.*:jquery和jquery UI库
cubicweb.ajax.js:集中所有与Ajax相关的工具(它使用loahxhtml函数扩展jquery,提供大量高级Ajaxy操作,如asyncRemoteExec、reloadcomponent、replaceCapageChunk、getdomFromResponse)
python.js:向stdanrd javascript对象(日期、数组、字符串、一些列表和字典操作)添加了大量实用的扩展,以及一种构建类的pythonesque方法。定义CubicWeb命名空间。
cubicweb.htmlhelpers.js:一小包方便函数,用于各种其他cubicweb javascript资源(baseuri、进度光标处理、弹出登录框、html2dom函数等)。
cubicweb.widgets.js:为各种小部件(主要是方面和时间线)提供小部件名称空间、构造函数和帮助器。
cubicWeb.edition.js:由版本表单使用
cubicWeb.preferences.js:由首选项窗体使用
cubicWeb.facets.js:由facets机制使用
还有对massmail、gmap(谷歌地图)、fckcwconfig(fck编辑器)、timeline、calendar、goa(cubicweb over appengine)、flot(图表绘图)、选项卡和书签的javascript支持。
API¶
测试javascript¶
You with the cubicweb.qunit.QUnitTestCase
can include standard Qunit tests
inside the python unittest run . You simply have to define a new class that
inherit from QUnitTestCase
and register your javascript test file in the
all_js_tests
lclass attribut. This all_js_tests
is a sequence a
3-tuple (<test_file, [<dependencies> ,] [<data_files>]):
<test_file>应该包含qunit测试。<dependencies>定义测试脚本之前必须导入的javascript文件列表。依赖项包括其定义顺序。<data_files>是在测试目录中复制的附加文件。<dependencies>和<data_files>都是可选的。 jquery.js
包括在所有测试中。
from cubicweb.qunit import QUnitTestCase
class MyQUnitTest(QUnitTestCase):
all_js_tests = (
("relative/path/to/my_simple_testcase.js",)
("relative/path/to/my_qunit_testcase.js",(
"rel/path/to/dependency_1.js",
"rel/path/to/dependency_2.js",)),
("relative/path/to/my_complexe_qunit_testcase.js",(
"rel/path/to/dependency_1.js",
"rel/path/to/dependency_2.js",
),(
"rel/path/file_dependency.html",
"path/file_dependency.json")
),
)