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" />