JavaScript
Warstwa JavaScript jest w Odoo inspirowana przez bibliotekę requirejs (http://requirejs.org/). Główną ideą jest ładowanie tylko tych plików które są aktualnie potrzebne - zgodnie ze specyfikacją AMD (Asynchronous Module Definition).
Dlatego programowanie polega na definicji obiektów i sposobów ich wykorzystania.
Typowa definicja dla RequireJS:
require.config({
baseUrl: '/my/app/path'
});
Więcej informacji na ten temat znajdziesz na stronie: https://blog.gutek.pl/2016/03/14/co-jest-requirejs/
W Odoo wygląda to tak:
odoo.define('nazwa_modulu.funkcja', function(require) {
});
Obiekt odoo jest zawsze dodawany na początku strony. Można to stwierdzić wyświetlając źródło strony. Zobaczymy coś podobnego do:
<script type="text/javascript">
var myodoo = {
csrf_token: "80ee15f0deaf3d210d004a0b4ee1a36864fbb215o",
};
</script>
Token csrf zabezpiecza stronę przed atakami CSRF (zobacz: https://sekurak.pl/czym-jest-podatnosc-csrf-cross-site-request-forgery/).
Zmienna globalna odoo służy jako zbiornik informacji o obiektach (na przykład kontrolkach/widgetach) i innych parametrach.
Mogą to być na przykład dane o sesji (to także znajdziesz w źródłach strony):
<script type="text/javascript">
odoo.session_info = {
is_superuser: true,
is_frontend: true,
};
</script>
Struktura odoo jest rozszerzana (w skrypcie addons/web/static/src/js/boot.js) między innymi o wspomnianą powyżej funkcję define(), którą definiujemy usługi (obiekty) do załadowania/wykonania.
Potrzebne w danym momencie usługi ładujemy funkcją require().
Na przykład:
var core = require('web.core');
var ajax = require('web.ajax');
var Widget = require('web.Widget');
var base = require('web_editor.base');
Ta ostatnia struktura ('web_editor.base') jest najczęściej wykorzystywana do definiowania operacji wykonywanych po załadowaniu strony (odpowiednik $( document ).ready( ) z jQuery):
Przykład:
odoo.define('demo_js.start', function(require) {
'use strict';
var base = require('web_editor.base');
base.ready().done(function () {
// inicjowanie
});
});
Najczęściej wykorzystujemy JavaScript do rozszerzenia funkcjonalności formularzy. Możemy w tym celu definiować własne kontrolki (widgets).
Przykład własnej kontrolki
1) Definiujemy wygląd kontrolki w pliku umieszczanym w katalogu static/src/xml. Nazwijmy go "mywidget0.xml":
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="myWidget0">
<div>
Hello World
</div>
</t>
</templates>
Zwróć uwagę na xml:space="preserve"
2) Konieczność jego załadowania deklarujemy w manifeście:
# fragment __manifest__.py:
'qweb': [
'static/src/xml/mywidget0.xml',
],
Jeśli mamy więcej wzorców kontrolek, możemy je umieścić w jednym pliku xml, albo wielu plikach, podając w manifeście wzorzec: 'static/src/xml/*.xml',
3) Przystępujemy do implementacji - w pliku static/src/js/mywidget0.js:
odoo.debug = true; // włączamy debugowanie js
odoo.define('demo_js.demo_js', function (require) {
'use strict';
// czego potrzebujemy?
var core = require('web.core');
var Widget = require('web.Widget');
var MyWidget0 = Widget.extend({ // własna kontrolka
template: "
", // zadeklarowany wzorzec
init: function (parent) { // tu możemy zainicjować parametry kontrolki
this._super(parent);
},
});
// rejestrujemy kontrolkę w systemie
core.form_custom_registry.add("mywidget0", MyWidget0);
});
Na temat dyrektywy 'use strict' czytaj: https://www.w3schools.com/js/js_strict.asp
Więcej informacji o JavaScript w Odoo: https://framagit.org/framasoft/OCB/blob/9.0/doc/reference/javascript.rst
4) Dołączamy kontrolkę do naszej strony (plik xml/templates.xml, nasz przykładowy moduł nazywa się demo_js):
<odoo>
<data>
<template id="assets_backend" name="web_demo_js_assets" inherit_id="web.assets_backend">
<!-- dołączenie javascript -->
<xpath expr="script[last()]" position="after">
<script type="text/javascript" src="/demo_js/static/src/js/mywidget0.js"/>
</xpath>
</template>
</data>
</odoo>
5) Wykorzystujemy go w formularzu (plik xml/views.xml)
<odoo>
<data>
<!-- widok -->
<record id="demo_form0" model="ir.ui.view">
<field name="name">demo_js_form0</field>
<field name="model">res.users</field>
<field name="arch" type="xml">
<form string="Demo JS" id="form0">
<widget type="mywidget0" attrs="{}">
</widget>
</form>
</field>
</record>
<!-- okno w którym otwieramy widok -->
<record id="akcja_otwarcia_form0" model="ir.actions.act_window">
<field name="name">Demo JS</field>
<field name="res_model">res.users</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="demo_form0"/>
</record>
<menuitem action="akcja_otwarcia_form0" id="demo_js_form_menu0"/>
</data>
</odoo>
6) Dodajemy informację o plikach do manifestu:
'data': [
'views/templates.xml',
'views/views.xml',
],
Po zajnstalowaniu naszego modułu (demo_js) pojawi się w menu "Demo JS" otwarcie formularza z kontrolką.
Zamiast tworzyć kontrolki na bazie web.Widget, możemy wykorzystać którąś z pozostałych zaimplementowanych w module web kontrolek:
- web.ActionManager
- web.core
- web.data
- web.Dialog
- web.FavoriteMenu
- web.form_common
- web.formats
- web.FormView
- web.form_relational
- web.form_widgets
- web.framework
- web.ListView
- web.DataModel
- web.pyeval
- web.Registry
- web.SearchView
- web.session
- web.Sidebar
- web.SystrayMenu
- web.time
- web.UserMenu
- web.utils
- web.View
- web.ViewManager
- web.WebClient
- web.Widget
Na przykład:
var ListView = require('web.ListView');
var MyWidget = ListView.extend({
......
Zaimplementowane wzorce dla nich znajdziesz w pliku: addons/web/static/src/xml/base.xml
Własne akcje
Poza kontrolkami można definiować własne akcje uruchamiane przyciskiem lub z menu. Wykorzystuje się do tego strukturę ir.actions.client.
Najprostsza definicja akcji:
odoo.define('demo_js.akcja', function (require) {
'use strict';
var core = require('web.core');
var Widget = require('web.Widget');
var MyWidget1 = Widget.extend({
start: function() {
alert('Hello World!');
}
});
core.action_registry.add("myaction1", MyWidget1);
});
Jej wywołanie z menu:
<!-- wlasna akcja - mywidget1.js -->
<record id="akcja_js" model="ir.actions.client">
<field name="name">zdefiniowane w js</field>
<field name="tag">myaction1</field>
</record>
<menuitem action="akcja_js" id="demo_js_form_menu1" />