本指南是关于为Odoo的web客户创建模块。
警告:该指南需要以下知识:Javascript、jQuery、Underscore.js同时也需要安装Odoo和Git。一个简单的模型让我们从一个简单的Odoo模块开始,它包含基本的web组件配置,并让我们测试web框架。示例模块可以在线下载,可以使用以下命令下载:
如果您浏览petstore文件夹,您应该看到以下内容:
在Odoo模块的“web”端中使用的文件必须放置在静态文件夹中,这样它们就可以在web浏览器中使用,而浏览器之外的文件也不能被浏览器获取。src/css、src/js和src/xml子文件夹是常规的,并不是绝对必要的。
oepetstore/static/css/petstore.css目前为空,将为宠物店(petstore)内容保留CSS。
oepetstore/static/xml/petstore.xml大部分也是空的,将保存QWeb模板。
oepetstore/static/js/petstore.js最重要(也是最有趣的)部分,包含javascript应用程序的逻辑(或者至少是它的web浏览器端)。它现在应该是:
openerp.oepetstore=function(instance,local){//特别注意:红色部分在开发文档中10.0版本中用odoo关键字,但是测试时无法通过,必须是openerp,估计是尚未完全支持odoo关键字var_t=instance.web._t,_lt=instance.web._lt;varQWeb=instance.web.qweb;local.HomePage=instance.Widget.extend({start:function(){console.log("petstorehomepageloaded");},});instance.web.client_actions.add('petstore.homepage','instance.oepetstore.HomePage');}它只在浏览器的控制台打印一个小消息。
静态文件夹中的文件,需要在模块中定义,以便正确加载它们。src/xml中的所有内容都在__manifest.__中定义。在petstore.xml或类似的文件中定义或引用src/css和src/js的内容。
当Web客户端加载你的模块时,它会调用根函数并提供两个参数:
第一个参数(instance)是OdooWeb客户端的当前实例,它允许访问由Odoo(网络服务)定义的各种功能以及由内核或其他模块定义的对象。
第二个参数(local)是您自己的本地名称空间,由Web客户端自动创建。应该可以从模块外部访问的对象和变量(无论是因为OdooWeb客户端需要调用它们,还是因为其他人可能想要定制它们)应该在该名称空间内设置。
就像模块一样,并且与大多数面向对象的语言相反,JavaScript不会构建在classes中,尽管它提供了大致相同(如果是较低级别和更详细的)机制。
为了简单和开发人员友好,Odooweb提供了一个基于JohnResig的简单JavaScript继承的类系统。
通过调用odoo.web.Class()的extend()方法来定义新的类:
varMyClass=instance.web.Class.extend({say_hello:function(){console.log("hello");},});extend()方法需要一个描述新类的内容(方法和静态属性)的字典。在这种情况下,它只会有一个不带参数的say_hello方法。
类使用new运算符实例化:
varmy_object=newMyClass();my_object.say_hello();//print"hello"intheconsole实例的属性可以通过以下方式this访问:
varMyClass=instance.web.Class.extend({say_hello:function(){console.log("hello",this.name);},});varmy_object=newMyClass();my_object.name="Bob";my_object.say_hello();//print"helloBob"intheconsole通过定义init()方法,类可以提供初始化程序来执行实例的初始设置。初始化程序接收使用新运算符时传递的参数:
varMyClass=instance.web.Class.extend({init:function(name){this.name=name;},say_hello:function(){console.log("hello",this.name);},});varmy_object=newMyClass("Bob");my_object.say_hello();//print"helloBob"intheconsole也可以通过在父类上调用extend()来创建现有(使用定义的)类的子类,如同子类Class()所做的那样:
varMySpanishClass=MyClass.extend({say_hello:function(){console.log("hola",this.name);},});varmy_object=newMySpanishClass("Bob");my_object.say_hello();//print"holaBob"intheconsole当使用继承覆盖方法时,可以使用this._super()调用原始方法:
varMySpanishClass=MyClass.extend({say_hello:function(){//已覆盖的方法this._super();//调用父类中的原始方法,即“hello。。。”console.log("translationinSpanish:hola",this.name);},});varmy_object=newMySpanishClass("Bob");my_object.say_hello();//print"helloBob\ntranslationinSpanish:holaBob"intheconsole警告_super不是一个标准的方法,它被设置为当前继承链中的一个方法(如果有的话)。它只在方法调用的同步部分中定义,用于异步处理程序(在网络调用或setTimeout回调之后)应该保留对其值的引用,因此不应通过以下方式访问它:
//以下调用会产生错误say_hello:function(){setTimeout(function(){this._super();}.bind(this),0);}//以下方式正确say_hello:function(){//不能忘记.bind()var_super=this._super.bind(this);setTimeout(function(){_super();}.bind(this),0);}Widgets基础Odooweb客户端捆绑了jQuery以实现简单的DOM操作。它比标准的W3CDOM2更有用,并且提供了更好的API,但不足以构成复杂的应用程序,导致难以维护。很像面向对象的桌面UI工具包(例如Qt,Cocoa或GTK),OdooWeb使特定组件负责页面的各个部分。在Odoo网站中,这些组件的基础是Widget()类,它是专门处理页面部分并显示用户信息的组件。
初始演示模块已经提供了一个基本的widget:
local.HomePage=instance.Widget.extend({start:function(){console.log("petstorehomepageloaded");},});它扩展了Widget()并重载了标准方法start(),它与之前的MyClass很像,现在做的很少。
该行在文件末尾:
instance.web.client_actions.add('petstore.homepage','instance.oepetstore.HomePage');将我们的widget注册为客户端操作。客户端操作将在稍后解释,现在这只是当我们选择PetStorePetStoreHomePage菜单时,可以调用和显示我们的窗口小部件。
警告
由于该组件将从我们的模块外部调用,Web客户端需要其“完全限定(规范)”名称,而不是任意名称。
local.HomePage=instance.Widget.extend({start:function(){this.$el.append("
注意
要刷新OdooWeb中加载的JavaScript代码,您需要重新加载页面(升级一下模块)。没有必要重新启动Odoo服务器。
HomePageWidget由OdooWeb使用并自动管理。要学习如何从头开始使用Widget,我们来创建一个新Widget:
local.GreetingsWidget=instance.Widget.extend({start:function(){this.$el.append("
local.HomePage=instance.Widget.extend({start:function(){this.$el.append("
HomePage然后实例化GreetingsWidget;
最后,它告诉GreetingsWidget将自己的部分插入到GreetingsWidget中。
当调用appendTo()方法时,它会要求小部件(widget,以下将的小部件就是widget)将自身插入指定位置并显示其内容。在调用appendTo()期间,将调用start()方法。
要查看显示界面下发生了什么,我们将使用浏览器的DOMExplorer。但首先让我们稍微修改我们的小部件,以便通过向它们的根元素添加一个类来更轻松地找到它们的位置: