chiyin0490 2016-02-01 17:05:00 137 已收藏 1
文章标签: javascript json python
版权
-----------
更新日期
15:17 2016-02-16 星期二
-----------
* 用到的js库
我们可以打开 addons/web/views/webclient_template.xml
看到如下:
# es5-shim 给傻逼浏览器做兼容性,使得傻逼浏览器可以支持一些 es5 的 api
# spinjs ajax异步时,等待出现一个轮的图片
# datejs 日期处理js
# jQuery库,这是经典库了 http://t.mb5u.com/jquery/ 1.8.3
# jquery.blockUI 提示窗口
# jquery.hotkeys 键盘js处理
# jquery.placeholder 实现文本框显示描述文字
# jquery.timeago 时间格式
# jquery.form 表单处理
# jquery.ba-bbq
# underscore库,弥补了jQuery没有实现的地方 文档http://www.css88.com/doc/underscore1.6.0/
所有的功能都封装在名为"_"命名空间内
常用_.each()来代替javascript中的循环
_.range()产生一个范围的数列
function sumTotal(){
var x=0;
_.each(_.range(1,101),function(i){
x+=i;
});
console.log("Result",x);
}
*jQuery 简单操作
#选择器
@ $("input") 选择特定的HTML元素
@ $("#content") 选择指定的id的HTML元素
@ $(".title") 选择明确的css样式类的所有元素
@ $("span.title") 组合选择元素,可以更精确选择元素
# 事件
@ $("button").click(function){
console.log("someone clicked on the button")
}); // 按钮上的单点事件
# 修改DOM
@ $(".main_content").html('
var module = instance.stock;
var _t = instance.web._t;
var _lt = instance.web._lt;
var QWeb = instance.web.qweb;
// This widget makes sure that the scaling is disabled on mobile devices.
// Widgets that want to display fullscreen on mobile phone need to extend this
// widget.
module.MobileWidget = instance.web.Widget.extend({
start: function(){
if(!$('#oe-mobilewidget-viewport').length){
$('head').append('');
}
return this._super();
},
destroy: function(){
$('#oe-mobilewidget-viewport').remove();
return this._super();
},
});
#var _t = instance.web._t; 翻译
* 采用异步 做 (a+b)*(c+d) 这个功能 ,这是例子,主要参考模式思想
(function(){
app = {};
function main(){
$("button").click(function(){
plusmultplus(1,2,3,4).then(function(result){
console.log("(1+2)*(3+4)=",result.multiplication);
});
});
}
app.main = main;
function plusmultplus(a,b,c,d){
var def1 = $.ajax("/service_plus",{
type:"POST",
dataType:"json",
data:JSON.stringify({
"a":a,
"b":b,
}),
contentType:"application/json",
});
var def2 = $.ajax("/service_plus",{
type:"POST",
dataType:"json",
data:JSON.stringify({
"c":c,
"d":d,
}),
contentType:"application/json",
});
return $.when(def1,def2).then(function(result1,result2){
return $.ajax("/service_mult",{
type:"POST",
dataType:"json",
data:JSON.stringify({
"a":result1[0].addition,
"b":result2[0].addition,
}),
contentType:"application/json",
});
});
}
})();
--------------------------------
@app.route('/service_plus', methods=["POST"])
def service_plus():
data = flask.request.json
a = data["a"]
b = data["b"]
delay = data.get("delay", 0)
time.sleep(delay)
return flask.jsonify(**{
"addition": a + b,
})
@app.route('/service_mult', methods=["POST"])
def service_mult():
data = flask.request.json
a = data["a"]
b = data["b"]
delay = data.get("delay", 0)
time.sleep(delay)
return flask.jsonify(**{
"multiplication": a * b,
})
* Web Framework 构造图形化的javascript 应用
# 基础框架js所在位置 addons/web/static/src/js/openerpframework
#js 在odoo中的运用
openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.oepetstore = {};
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
console.log("pet store home page loaded");
},
});
instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
}
@ odoo运行时会把所有的javascript文件连接为一个文件,然后压缩,若要调试,必须采用debug模式
@ 上面创建了, oepetstore 模块,且做为属性放在全局变量openerp中;模块名和addon的模块名要一
致,否则不能运行
@ 当载入addon这个模块时,该js模块调用,传入instance参数,这个参数代表当前 OpenERP 的 Web 客户端实例,
包含了所有相关当前会话数据, 以及所有 Web 模块的变量
@ instance.oepetstore = {}; 这是命名空间,用来声明我们模块内自己使用的所有类和变量
# js在odoo定义一个新类
instance.oepetstore.MyClass = instance.web.Class.extend({
say_hello: function(){
console.log("hello");
}
});
@ 调用instance.web.Class.extend() 传入一个dictionary 参数
@ 在方法内,用this访问属性值
instance.oepetstore.MyClass = instance.web.Class.extend({
say_hello: function() {
console.log("hello", this.name);
},
});
var my_object = new instance.oepetstore.MyClass();
my_object.name = "Nicolas";
my_object.say_hello();
@ 类可以有一个构造函数 init()
instance.oepetstore.MyClass = instance.web.Class.extend({
init: function(name) {
this.name = name;
},
say_hello: function() {
console.log("hello", this.name);
},
});
var my_object = new instance.oepetstore.MyClass("Nicolas");
my_object.say_hello();
@ 重载方法时,使用 this._super()调用原来的方法
instance.oepetstore.MySpanishClass = instance.oepetstore.MyClass.extend({
say_hello: function() {
this._super();
console.log("translation in Spanish: hola", this.name);
},
});
var my_object = new instance.oepetstore.MySpanishClass("Nicolas");
my_object.say_hello();
* Widgets
# 第一个部件
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
console.log("pet store home page loaded");
},
});
instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
这句是把这个部件注册为客户端的action
@ start 这个方法部件初始化会自动调用
@ 改造一下用上jQuery 的$el
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
this.$el.append("
显示结果:
@ this 隐式传入到所有的函数,每个已声明的函数都有自己的 this 。
所以,当我们在一个函数内声明了另一个函数,这个新功能将有自己的 this ,
这和父函数 this 含义不同,采用了 var self = this; 保存
@ self.trigger("user_choose", true); 定义user_choose为名事件的触发器
Widget.trigger(event_name [, ...]) 方法的第一个参数是待触发的事件名,
也接受任何数量的其他参数。这些参数将被传递到所有的事件侦听器
@ widget.on("user_choose", this, this.user_choose); 监听user_choose 事件
Widget.on(event_name, object, func) 允许绑定一个事件 event_name 触发时调
用的函数 func 。 如果 func) 是个方法,则 object 是 func) 函数的引用关联
对象。 当 func) 被调用时, trigger() 的其他参数会传递给它
# 属性
和普通对象属性一样,但多了一个功能,会触发事件
start: function() {
this.widget = ...
this.widget.on("change:name", this, this.name_changed);
this.widget.set("name", "Nicolas");
},
name_changed: function() {
console.log("The new value of the property 'name' is", this.widget.get("name"));
}
@ Widget.set(name, value) 方法设置某个属性的值。如果该值改变(或以前没有
值) , 对象将触发一个事件 change:xxx : xxx 是属性名称。
Widget.get(name) 读取属性值。
# 部件辅助工具
选择器 this.$el.find("input.my_input") <=> this.$("input.my_input")
要分析jQuery事件和部件事件
简化jQuery事件写法
start: function() {
var self = this;
this.$(".my_button").click(function() {
self.button_clicked();
});
}
--------
events: {
"click .my_button": "button_clicked",
},
# 翻译
记得js源码有两行
var _t = instance.web._t,
_lt = instance.web._lt;
这是导入翻译功能
this.$el.text(_t("Hello dear user!"));
和对应python代码中 _() 翻译
_lt()返回一个函数
var text_func = _lt("Hello dear user!");
this.$el.text(text_func());
class openerp.Widget()
是所有可视化组件的基础类
# DOM Root
Widget() 得到DOM Root
openerp.Widget.el Root
openerp.Widget.$el jQuery打包
openerp.Widget.template 生成Root
openerp.Widget.tagName 生成元素 默认是div
openerp.Widget.id 生成Root的id属性
openerp.Widget.className
openerp.Widget.renderElement() 渲染是生成Root
# 使用widget
openerp.Widget.init(parent)
加元素
openerp.Widget.appendTo(element) 加到后面
openerp.Widget.prependTo(element) 加到前面
openerp.Widget.insertAfter(element) 插在元素的后面
openerp.Widget.insertBefore(element) 插在元素的前面
openerp.Widget.destory()清理
openerp.Widget.alive(deferred[, reject=false]) 状态操作
openerp.Widget.isDestroyed() 检测有没有销毁
# 访问DOM内容
openerp.Widget.$(selector)
this.$(selector)
this.$el.find(selector)
# 重设DOM Root
openerp.Widget.setElement(element)
element 可以是元素,也可以jQuery对象
# DOM事件处理
openerp.Widget.events
如
events:{
'click p.oe_some_class a':'some_method',
'change input':function(e){
e.stopPropagation()
}
}
openerp.Widget.delegateEvents() 代理绑定到DOM上面
openerp.Widget.undelegateEvents() 解绑
# 子类Widget
通过extend
var MyWidget = openerp.Widget.extend({
// QWeb template to use when rendering the object
template: "MyQWebTemplate",
events: {
// events binding example
'click .my-button': 'handle_click',
},
init: function(parent) {
this._super(parent);
// insert code to execute before rendering, for object
// initialization
},
start: function() {
var sup = this._super();
// post-rendering initialization code, at this point
// allows multiplexing deferred objects
return $.when(
// propagate asynchronous signal from parent class
sup,
// return own's asynchronous signal
this.rpc(/* … */))
}
});
// Create the instance
var my_widget = new MyWidget(this);
// Render and insert into DOM
my_widget.appendTo(".some-div");
my_widget.destroy();
# 开发指南
@ 尽量少用id ,万一要用id 要用 _.uniqueId() 生成
this.id=_.uniqueId()
@ 尽量少用普通css名字 如 content navigator
@ 尽量少用全局选择器 用 Widget.$el 或 Widget.$()
@ 所有的组件都要继承 Widget()
@ 要用QWeb进行HTML模板和渲染
* QWeb
instance.web.Widget 特别支持 QWeb
前面js源码,有 var QWeb = instance.web.qweb; 这样可以用QWeb功能了
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
this.$el.append(QWeb.render("HomePageTemplate"));
},
});
@ 渲染了 HomePageTemplate 模板
@ 也可以采用集成方式
instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePageTemplate",
start: function() {
},
});
发生在start方法之前,会用模板的根标签替换部件的默认根标签
# 传递参数
------
QWeb.render("HomePageTemplate", {name: "Nicolas"});
当采用集成式,要用变量 widget
--------
instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePageTemplate",
init: function(parent) {
this._super(parent);
this.name = "Nicolas";
},
start: function() {
},
});
# 模板基础 https://doc.odoo.com/trunk/web/qweb/
@
前缀 t-
@ t-name 标识模板, QWeb.render() 可以调用指定模板
@ t-esc 在HTML中放置文本 会转义html标签
@ t-raw 保持原有内容输出
@ t-if 条件语句
true is true
@ t-foreach t-as 循环
Hello
@ t-att-xx 设置属性值
* 部件调用数据
class message_of_the_day(osv.osv):
_name = "message_of_the_day"
def my_method(self, cr, uid, context=None):
return {"hello": "world"}
_columns = {
'message': fields.text(string="Message"),
'color': fields.char(string="Color", size=20),
}
-----------
instance.oepetstore.HomePage = instance.web.Widget.extend({
start: function() {
var self = this;
var model = new instance.web.Model("message_of_the_day");
model.call("my_method", [], {context: new instance.web.CompoundConte
xt()}).then(function(result) {
self.$el.append("
// will show "Hello world" to the user
});
},
});
#连接模型用 instance.web.Model
#采用model.call()来调用数据 call(name, args, kwargs) 是 Model 的方法
args 是对象方法的参数列表
kwargs 命名参数列表,这里只传了context
# 模型中的方法始终有一个参数 context , context 是一个包含多个key的dictonary
# CompoundContext 这个类用来传递用户上下文(语言,时区等..) 给服务器的
其构造函数的参数是任意数量的 dictionary
* 部件较好的例子
openerp.oepetstore = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.oepetstore = {};
instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePage",
start: function() {
var pettoys = new instance.oepetstore.PetToysList(this);
pettoys.appendTo(this.$(".oe_petstore_homepage_left"));
var motd = new instance.oepetstore.MessageOfTheDay(this);
motd.appendTo(this.$(".oe_petstore_homepage_right"));
},
});
instance.web.client_actions.add('petstore.homepage', 'instance.oepetstore.HomePage');
instance.oepetstore.MessageOfTheDay = instance.web.Widget.extend({
template: "MessageofTheDay",
init: function() {
this._super.apply(this, arguments);
},
start: function() {
var self = this;
new instance.web.Model("message_of_the_day").query(["message"]).
first().then(function(result) {
self.$(".oe_mywidget_message_of_the_day").text(result.message);
});
},
});
instance.oepetstore.PetToysList = instance.web.Widget.extend({
template: "PetToysList",
start: function() {
var self = this;
new instance.web.Model("product.product").query(["name", "image"])
.filter([["categ_id.name", "=", "Pet Toys"]]).limit(5).all().
then(function(result) {
_.each(result, function(item) {
var $item = $(QWeb.render("PetToy", {item: item}));
self.$el.append($item);
});
});
},
});
}
----------------
.oe_petstore_homepage {
display: table;
}
.oe_petstore_homepage_left {
display: table-cell;
width : 300px;
}
.oe_petstore_homepage_right {
display: table-cell;
width : 300px;
}
.oe_petstore_motd {
margin: 5px;
padding: 5px;
border-radius: 3px;
background-color: #F0EEEE;
}
.oe_petstore_pettoyslist {
padding: 5px;
}
.oe_petstore_pettoy {
margin: 5px;
padding: 5px;
border-radius: 3px;
background-color: #F0EEEE;
}
====================
* RPC
采用异步的方式来调用
#高级API
访问对象方法用 openerp.Module
映射服务端对象用 call() 和 query()
var Users = new openerp.Model('res.users');
Users.call('change_password', ['oldpassword', 'newpassword'],
{context: some_context}).then(function (result) {
// do something with change_password result
});
query()是 search+read 在后端操作
Users.query(['name', 'login', 'user_email', 'signature'])
.filter([['active', '=', true], ['company_id', '=', main_company]])
.limit(15)
.all().then(function (users) {
// do work with users records
});
openerp.Model.call(method[, args][, kwargs])
method 是rpc的方法名
args 传入方法的参数
kwargs 关键词参数
openerp.Model.query(fields)
fields 字段列表
first() 取第一个记录
class openerp.web.Query(fields)类下方法
openerp.web.Query.all() 得到上面query() 集的所有
openerp.web.Query.first() 要第一条,没有就是null
openerp.web.Query.count() 得到的记录总数
openerp.web.Query.group_by(grouping...) 分组来列表
openerp.web.Query.context(ctx) 添加上下文
openerp.web.Query.filter(domain) 条件过滤domain表达式
opeenrp.web.Query.offset(offset) 设定起点
openerp.web.Query.limit(limit) 设定要返回的数量
openerp.web.Query.order_by(fields…) 记录排序
#聚合
some_query.group_by(['field1', 'field2']).then(function (groups) {
// do things with the fetched groups
})
openerp.web.QueryGroup.get(key)
得到key的值,key可以为:
@ grouped_on
@ value
@ length
@ aggregates
openerp.web.QueryGroup.query([fields...]) 等价于
openerp.web.Model.query()
openerp.web.QueryGroup.subgroups()
#低级API RPC访问python
opeenrp.session()
如:
openerp.session.rpc('/web/dataset/resequence', {
model: some_model,
ids: array_of_ids,
offset: 42
}).then(function (result) {
// resequence didn't error out
}, function () {
// an error occured during during call
});
========================
* Web 客户端
写测试用例
# 断言
ok(state[, message])
strictEqual(actual, expected[, message]) 相当于 ok(actual === expected, message))
notStrictEqual(actual, expected[, message]) 相当于 ok(actual !== expected, message))
deepEqual(actual, expected[, message])
notDeepEqual(actual, expected[, message])
throws(block[, expected][, message]) 抛出异常
equal(actual, expected[, message]) 宽松相等
notEqual(actual, expected[, message])
示例:
{
'name': "Demonstration of web/javascript tests",
'category': 'Hidden',
'depends': ['web'],
'js': ['static/src/js/demo.js'],
'test': ['static/test/demo.js'],
}
// src/js/demo.js
openerp.web_tests_demo = function (instance) {
instance.web_tests_demo = {
value_true: true,
SomeType: instance.web.Class.extend({
init: function (value) {
this.value = value;
}
})
};
};
// test/demo.js
test('module content', function (instance) {
ok(instance.web_tests_demo.value_true, "should have a true value");
var type_instance = new instance.web_tests_demo.SomeType(42);
strictEqual(type_instance.value, 42, "should have provided value");
});
* 显示图片
* Web Components (Action manager)
# 看一列子:
作者:陈伟明 | 联系 : QQ 942923305 | 微信 toby942923305 | E-mail: [email protected]
转载于:https://my.oschina.net/toby2chen/blog/612679