フレームワークの概要

入門

Odoo Javascriptフレームワークは、ブラウザーで動作するodoアプリケーションを構築するために、web/ アドオンによって提供される一連の機能/ビルディングブロックです。 同時に、Odoo Javascriptフレームワークは単一のページアプリケーションであり、通常は*ウェブクライアント* (url ``/web``で利用可能) として知られています。

カスタム クラスとウィジェット システムで作成されたアプリケーションとして開始された web クライアント しかし、今では代わりにネイティブの javascript クラスを使用し、Owl をコンポーネントシステムとして使用するようになりました。 これにより、両方のシステムが現在コードベースで使用されている理由が説明されます。

高レベルの観点から Web クライアントは単一ページのアプリケーションであり、ユーザがアクションを実行するたびにサーバにフルページを要求する必要はありません。 代わりに、必要なものだけを要求し、それに応じて現在の画面を置き換え/更新します。 また、現在の状態と同期させるために URL を管理します。

javascriptフレームワーク(全部または一部)は、Odooウェブサイトや販売ポイントなどの他の状況でも使用されます。 このリファレンスは主にウェブクライアントに焦点を当てています。

注釈

Odooエコシステムでは、*frontend*と*backend*という単語をodoのウェブサイト(公開)とウェブクライアントの同義語として見ることが一般的です。 を選択します。 この用語は、browser-code (フロントエンド) と server (バックエンド) のより一般的な使用と混同されることはありません。

注釈

このドキュメントでは、component という単語は常に新しいOwlコンポーネントを指し、*widget*は古いOdooウィジェットを指します。

注釈

すべての新しい開発は、可能であれば、Owlで行う必要があります!

コード構造

web/static/src フォルダには、すべての web/ javascript (および css とテンプレート) のコードベースが含まれています。ここで最も重要なフォルダのリストを示します。

  • core/ 低レベルの機能

  • fields/ すべてのフィールドコンポーネント

  • views/ すべての javascript ビューのコンポーネント (form, list, ...)

  • search/ コントロールパネル、検索バー、検索パネル、...

  • webclient/ web クライアント固有のコード: navbar, user menu, action service, ...

web/static/src はルートフォルダです。内部のすべては @web プレフィックスを使用してインポートすることができます。 例えば、web/static/src/core/utils/functions にある memoize 関数をインポートする方法は次のとおりです。

import { memoize } from "@web/core/utils/functions";

WebClient アーキテクチャ

上記のように, ウェブクライアントはフクロウアプリケーションです. ここでは、そのテンプレートの若干簡素化されたバージョンです:

<t t-name="web.WebClient">
    <body class="o_web_client">
        <NavBar/>
        <ActionContainer/>
        <MainComponentsContainer/>
    </body>
</t>

ご覧のとおり、これは基本的にナビバーのラッパーであり、現在の動作といくつかの追加コンポーネントです。 ActionContainer は、現在のアクションコントローラを表示する高次コンポーネントです。 クライアントアクション、または act_window 型のアクションの場合の特定のビュー。 アクションを管理することは、その作業の大きな部分です。アクションサービスは、すべてのアクティブなアクションのスタックをメモリに保持します (パンくずリストで表されます) それぞれの変化を調整しています

注意すべきもう一つの興味深いことは、 MainComponentsContainer です: 単に、 main_components レジストリに登録されているすべてのコンポーネントを表示するコンポーネントです。 これは、システムの他の部分がWebクライアントを拡張する方法です。

環境

Odoo Web クライアントは、Owl アプリケーションとして独自の環境を定義します (コンポーネントは this を使用してアクセスできます)。 nv). ここでは、共有された env オブジェクトに Odoo が追加したものの説明を示します。

キー

数値

qweb

(すべてのテンプレートが含まれている) Owl が必要

bus

main bus, used to coordinate some generic events

サービス

デプロイされた services (通常は useService フックでアクセスする必要があります)

debug

文字列。空でない場合、Webクライアントは デバッグモード

_t

翻訳関数

isSmall

真偽値。true の場合、ウェブクライアントは現在モバイルモードになっています(画面幅 <= 767px)

そのため、例えば、コンポーネント内の文字列を翻訳するために (注: テンプレートは自動的に翻訳されます) その場合具体的な行動は必要ありませんこんなことができます

const someString = this.env._t('some text');

注釈

環境への参照を持つことは、すべてのサービスへのアクセスを提供するため、非常に強力です。 これは多くの場合に便利です: 例えば、ユーザーメニューアイテムは主に文字列として定義されています。 そして、`env`を一意の引数にしている関数。 これは、すべてのユーザーメニューのニーズを表現するのに十分です。

Building Blocks

ほとんどのWebクライアントは、レジストリ、サービス、コンポーネント、フックといういくつかの種類の抽象化で構築されています。

Registries

Registries は基本的に特定の種類のオブジェクトを格納する単純なキー/値マッピングです。 これらは UI の拡張性の重要な部分です: あるオブジェクトが登録されると、残りの Web クライアントはそれを使用できます。 たとえば、フィールドレジストリにはビューで使用できるすべてのフィールドコンポーネント (またはウィジェット) が含まれています。

import { Component } from "@odoo/owl";
import { registry } from "./core/registry";

class MyFieldChar extends Component {
    // some code
}

registry.category("fields").add("my_field_char", MyFieldChar);

メインレジストリを @web/core/registry からインポートし、サブレジストリの fields を開くことに注意してください。

サービス

Services は長く生きているコードで、機能を提供します。 これらはコンポーネント(useService``と共に)または他のサービスによってインポートすることができます。また、依存関係のセットを宣言することもできます。 その意味で、サービスは基本的にDI(依存性注入)システムです。 例えば、``notification サービスは通知を表示する方法を提供します。 または、 rpc サービスは、Odoo サーバーへのリクエストを実行するための適切な方法です。

以下の例では、5秒ごとに通知を表示するシンプルなサービスを登録します。

import { registry } from "./core/registry";

const serviceRegistry = registry.category("services");

const myService = {
    dependencies: ["notification"],
    start(env, { notification }) {
        let counter = 1;
        setInterval(() => {
            notification.add(`Tick Tock ${counter++}`);
        }, 5000);
    }
};

serviceRegistry.add("myService", myService);

コンポーネントとフック

ComponentsHooksOwl component system から来るアイデアです。 Odooコンポーネントは、単にWebクライアントの一部であるフクロウコンポーネントです。

フック は、たとえライフサイクルに依存していてもコードを因数分解する方法です。 これはコンポーネントにフィーチャーを注入するための複合/機能的な方法です。ミックスインの一種と見なすことができます。

function useCurrentTime() {
    const state = useState({ now: new Date() });
    const update = () => state.now = new Date();
    let timer;
    onWillStart(() => timer = setInterval(update, 1000));
    onWillUnmount(() => clearInterval(timer));
    return state;
}

コンテキスト

Odoo javascript の重要な概念は context です: 関数呼び出しや rpc にコンテキストを与えるコードを提供します。 システムの他の部分はその情報に適切に反応することができます ある意味では、どこにでも広がっている情報の袋のようなものです。 モデルrpcが特定のフォームビューから来ていることをOdooサーバーに知らせるなど、いくつかの状況で便利です。 またはコンポーネント内の一部の機能を有効/無効にします。

Odoo ウェブクライアントには 2 つの異なるコンテキストがあります: ユーザーコンテキストアクションコンテキスト です。 *context*という言葉を使うときは、状況によって異なることを意味するかもしれません。

注釈

context オブジェクトは多くの場合役に立つかもしれませんが、使いすぎないように注意してください。 コンテキストを変更することなく、多くの問題を標準的な方法で解決できます。

ユーザーのコンテキスト

*ユーザーコンテキスト*は、現在のユーザーに関連するさまざまな情報を含む小さなオブジェクトです。user サービスを通じて利用できます。

class MyComponent extends Component {
    setup() {
        const user = useService("user");
        console.log(user.context);
    }
}

以下の情報が含まれています:

名前(name)

説明

allowed_company_ids

`number[]

ユーザーのアクティブな会社IDのリスト

lang

string

ユーザーの言語コード("en_us"など)

tz

string

ユーザーの現在のタイムゾーン(例えば「Europe/Brussels」)

実際には、orm サービスは自動的に各リクエストにユーザーコンテキストを追加します。 そのため、通常は直接インポートする必要はありません。

注釈

allowed_company_ids の最初の要素は、ユーザーの主要な会社です。

アクションのコンテキスト

The ir.actions.act_window and ir.actions.client support an optional context field. This field is a char that represents an object. Whenever the corresponding action is loaded in the web client, this context field will be evaluated as an object and given to the component that corresponds to the action.

<field name="context">{'search_default_customer': 1}</field>

これは、さまざまな方法で使用できます。たとえば、ビューは、サーバーへのすべてのリクエストにアクションコンテキストを追加します。 もう一つの重要な用途は、デフォルトで検索フィルターを有効にすることです(上記の例を参照)。

新しいアクションを手動で実行する場合(javascriptなど)、アクションコンテキストを拡張できるようにすると便利な場合があります。 これは additional_context 引数で行えます。

// in setup
let actionService = useService("action");

// in some event handler
actionService.doAction("addon_name.something", {
    additional_context:{
        default_period_id: defaultPeriodId
    }
});

この例では、xml_id addon_name.something`のアクションがロードされ、コンテキストは `default_period_id の値で拡張されます。 これは、開発者が次のアクションにいくつかの情報を提供することによってアクションを組み合わせることができる非常に重要なユースケースです。

Python Interpreter

Odooフレームワークは、組み込みの小さなPythonインタプリタを備えています。その目的は、小さなPython表現を評価することです。 これは重要なことです。なぜなら、Odoo のビューには Python で書かれた修飾子がありますが、ブラウザーで評価する必要があるからです。

例:

import { evaluateExpr } from "@web/core/py_js/py";

evaluateExpr("1 + 2*{'a': 1}.get('b', 54) + v", { v: 33 }); // returns 142

py javascriptコードは5つの関数をエクスポートします。

tokenize(expr)
引数
  • expr (string()) -- トークン化する表現

戻り値

Token[] トークンのリスト

parse(tokens)
引数
  • tokens (Token[]()) -- トークンのリスト

戻り値

式を表す抽象構文ツリー構造

parseExpr(expr)
引数
  • expr (string()) -- a string representing a valid python expression

戻り値

式を表す抽象構文ツリー構造

evaluate(ast[, context])
引数
  • ast (AST()) -- このAST構造は

  • context (Object()) -- 追加の評価コンテキストを提供するオブジェクト

戻り値

文脈に対する式の結果の値は

evaluateExpr(expr[, context])
引数
  • expr (string()) -- a string representing a valid python expression

  • context (Object()) -- 追加の評価コンテキストを提供するオブジェクト

戻り値

文脈に対する式の結果の値は

ドメイン

大まかに言えば、Odoo のドメインは、特定の条件に一致する一連のレコードを表しています。 javascriptでは通常、条件のリストとして表されます(または演算子のリスト:|&、または`! を入力します)、または文字列式として入力します。 正規化する必要はありません(必要に応じて`&`演算子が暗示されます)。例えば:

// list of conditions
[]
[["a", "=", 3]]
[["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]
["&", "&", ["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]
["&", "!", ["a", "=", 1], "|", ["a", "=", 2], ["a", "=", 3]]

// string expressions
"[('some_file', '>', a)]"
"[('date','>=', (context_today() - datetime.timedelta(days=30)).strftime('%Y-%m-%d'))]"
"[('date', '!=', False)]"

文字列式はリスト式よりも強力です: いくつかの評価コンテキストに依存するPython式と評価されていない値を含むことができます。 しかし、文字列式を操作するのは難しい。

ドメインはウェブクライアントで非常に重要なので、Odoo は Domain クラスを提供します。

new Domain([["a", "=", 3]]).contains({ a: 3 }) // true

const domain = new Domain(["&", "&", ["a", "=", 1], ["b", "=", 2], ["c", "=", 3]]);
domain.contains({ a: 1, b: 2, c: 3 }); // true
domain.contains({ a: -1, b: 2, c: 3 }); // false

// next expression returns ["|", ("a", "=", 1), ("b", "<=", 3)]
Domain.or([[["a", "=", 1]], "[('b', '<=', 3)]"]).toString();

以下は Domain クラスの説明です。

class Domain([descr])
引数
  • descr (string | any[] | Domain()) -- ドメインの説明

Domain.contains(record)
引数
  • record (Object()) -- レコードオブジェクト

戻り値

boolean

ドメインによって指定されたすべての条件にレコードが一致する場合は true を返します。

Domain.toString()
戻り値

文字列

ドメインの文字列説明を返します。

Domain.toList([context])
引数
  • context (Object()) -- 評価コンテキスト

戻り値

誰でも

ドメインのリストの説明を返します。このメソッドはすべての自由な変数を置き換えるために使用されるオプションの context オブジェクトを取ることに注意してください。

new Domain(`[('a', '>', b)]`).toList({ b:3 }); // [['a', '>', 3]]

`Domain`クラスは、ドメインを組み合わせるための4つの有用な静的メソッドも提供します。

// ["&", ("a", "=", 1), ("uid", "<=", uid)]
Domain.and([[["a", "=", 1]], "[('uid', '<=', uid)]"]).toString();

// ["|", ("a", "=", 1), ("uid", "<=", uid)]
Domain.or([[["a", "=", 1]], "[('uid', '<=', uid)]"]).toString();

// ["!", ("a", "=", 1)]
Domain.not([["a", "=", 1]]).toString();

// ["&", ("a", "=", 1), ("uid", "<=", uid)]
Domain.combine([[["a", "=", 1]], "[('uid', '<=', uid)]"], "AND").toString();
static Domain.and(domains)
パラメータ

domains (string[] | any[][] | Domain[]) -- ドメイン表現のリスト

戻り値

ドメイン

すべてのドメインの交点を表すドメインを返します。

static Domain.or(domains)
パラメータ

domains (string[] | any[][] | Domain[]) -- ドメイン表現のリスト

戻り値

ドメイン

すべてのドメインの組合せを表すドメインを返します。

static Domain.not(domain)
パラメータ

domain (string | any[] | Domain) -- ドメイン表現

戻り値

ドメイン

ドメイン引数の否定を表すドメインを返します。

static Domain.combine(domains, operator)
パラメータ
  • domains (string[] | any[][] | Domain[]) -- ドメイン表現のリスト

  • operator ('AND' or 'OR') -- 演算子

戻り値

ドメイン

演算子引数の値に応じて、交差またはすべてのドメインの組合せを表すドメインを返します。

バス

The web client environment object contains an event bus, named bus. Its purpose is to allow various parts of the system to properly coordinate themselves, without coupling them. The env.bus is an owl EventBus, that should be used for global events of interest.

// for example, in some service code:
env.bus.on("WEB_CLIENT_READY", null, doSomething);

このバスでトリガーできるイベントのリストは次のとおりです。

メッセージ

積載量

トリガー

ACTION_MANAGER:UI-UPDATED

uiのどの部分が更新されたかを示すモード ('current', 'new' or 'fullscreen')

アクションマネージャーに要求されたアクションのレンダリングが完了しました

ACTION_MANAGER:UPDATE

次のレンダリング情報

アクションマネージャーは次のインターフェースの計算を終えました

MENUS:APP-CHANGED

なし

メニューサービスの現在のアプリが変更されました

ROUTE_CHANGE

なし

URLハッシュが変更されました

RPC:REQUEST

rpc id

rpcのリクエストが始まったばかりです

RPC:RESPONSE

rpc id

rpcのリクエストが完了しました

WEB_CLIENT_READY

なし

ウェブクライアントがマウントされました

FOCUS-VIEW

なし

メインビューは自分自身に焦点を当てるべきです

CLEAR-CACHES

なし

すべての内部キャッシュをクリアする必要があります

CLEAR-UNCOMMITTED-CHANGES

関数のリスト

コミットされていない変更を含むすべてのビューをクリアし、リスト内のコールバックをプッシュします

ブラウザーオブジェクト

javascript フレームワークは、locationlocalStoragesetTimeout のような多くのブラウザ API へのアクセスを提供する特別なオブジェクト browser も提供します。 例えば、browser.setTimeout 関数を使用する方法は次のとおりです。

import { browser } from "@web/core/browser/browser";

// somewhere in code
browser.setTimeout(someFunction, 1000);

テスト目的では主に興味深いものです。ブラウザーオブジェクトを使用するすべてのコードは、テスト期間中、関連する関数をモックすることで簡単にテストできます。

次の内容が含まれています:

addEventListener

cancelAnimationFrame

clearInterval

clearTimeout

console

日付

fetch

履歴

localStorage

ロケーション

navigator

open

random

removeEventListener

requestAnimationFrame

sessionStorage

setInterval

setTimeout

XMLHttpRequest

デバッグモード

Odoo は debug モードと呼ばれる特殊なモードで動作することがあります。

  • 特定の画面の追加情報/フィールドを表示する

  • Odooインターフェイスのデバッグに役立つ追加ツールを提供します。

debug`モードは文字列で記述されています。空の文字列は`debug`モードがアクティブではないことを意味します。それ以外の場合はアクティブです。 文字列に `assets または tests が含まれている場合、対応する特定のサブモードが有効になります (下記参照)。 どちらのモードも同時にアクティブにすることができます。例えば、`assets,tests`という文字列です。

environment: env.debug で現在の値を読み込むことができます。

ちなみに

デバッグモードでのみメニュー、フィールド、または要素の表示を表示するには、base.group_no_one グループをターゲットにする必要があります。

<field name="fname" groups="base.group_no_one"/>

アセットモード

debug=assets サブモードは、javascript のコードが有効になったらデバッグするのに役立ちます。 :ref:の assets<reference/assets> バンドルは圧縮されなくなり、ソースマップも生成されます。 これにより、あらゆる種類の javascript コードをデバッグするのに役立ちます。

テストモード

tests`という名前の別のサブモードがあります:有効にすると、サーバーはバンドル`web.assets_tests`をページに注入します。 このバンドルには主にテストツアーが含まれています (その目的は、機能をテストすることであり、ユーザーに興味深いものを見せることではありません)。 `tests モードは、これらのツアーを実行するのに役立ちます。

関連項目