mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
move code in init file, remove menu helpers
This commit is contained in:
@@ -1,53 +0,0 @@
|
|||||||
import { Ajax } from "./core/ajax";
|
|
||||||
import { NotificationManager } from "./core/notifications";
|
|
||||||
import { QWeb } from "./core/qweb_vdom";
|
|
||||||
import { Router } from "./core/router";
|
|
||||||
import { idGenerator, memoize } from "./core/utils";
|
|
||||||
import { actionRegistry } from "./registries";
|
|
||||||
import { ActionManager } from "./services/action_manager";
|
|
||||||
import { Env } from "./widgets/widget";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* makeEnvironment returns the main environment for the application.
|
|
||||||
*
|
|
||||||
* Note that it does not make much sense (except for tests) to have more than
|
|
||||||
* one environment. For example, with two environment, the router code in one
|
|
||||||
* environment will probably interfere with the code from the other environment.
|
|
||||||
*
|
|
||||||
* For this reason, the result of makeEnvironment is memoized: every call to
|
|
||||||
* this function will actually return the same environment.
|
|
||||||
*/
|
|
||||||
export const makeEnvironment = memoize(async function(): Promise<Env> {
|
|
||||||
// services
|
|
||||||
const qweb = new QWeb();
|
|
||||||
const router = new Router();
|
|
||||||
const ajax = new Ajax();
|
|
||||||
const actionManager = new ActionManager(actionRegistry);
|
|
||||||
const notifications = new NotificationManager();
|
|
||||||
|
|
||||||
// templates
|
|
||||||
const result = await fetch("templates.xml");
|
|
||||||
if (!result.ok) {
|
|
||||||
throw new Error("Error while fetching xml templates");
|
|
||||||
}
|
|
||||||
const templates = await result.text();
|
|
||||||
qweb.addTemplate("default", "<div/>");
|
|
||||||
qweb.loadTemplates(templates);
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Base widget requirements
|
|
||||||
qweb,
|
|
||||||
getID: idGenerator(),
|
|
||||||
|
|
||||||
actionManager,
|
|
||||||
ajax,
|
|
||||||
notifications,
|
|
||||||
actionRegistry,
|
|
||||||
router,
|
|
||||||
|
|
||||||
rpc: ajax.rpc,
|
|
||||||
|
|
||||||
debug: false,
|
|
||||||
isMobile: window.innerWidth <= 768
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { Ajax } from "./core/ajax";
|
||||||
|
import { NotificationManager } from "./core/notifications";
|
||||||
|
import { QWeb } from "./core/qweb_vdom";
|
||||||
|
import { Router } from "./core/router";
|
||||||
|
import { findInTree, idGenerator, memoize } from "./core/utils";
|
||||||
|
import { actionRegistry } from "./registries";
|
||||||
|
import { ActionManager } from "./services/action_manager";
|
||||||
|
import { MenuInfo, MenuItem } from "./widgets/root";
|
||||||
|
import { Env } from "./widgets/widget";
|
||||||
|
|
||||||
|
interface InitializedData {
|
||||||
|
env: Env;
|
||||||
|
menuInfo: MenuInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makeEnvironment returns the main environment for the application.
|
||||||
|
*
|
||||||
|
* Note that it does not make much sense (except for tests) to have more than
|
||||||
|
* one environment. For example, with two environment, the router code in one
|
||||||
|
* environment will probably interfere with the code from the other environment.
|
||||||
|
*
|
||||||
|
* For this reason, the result of makeEnvironment is memoized: every call to
|
||||||
|
* this function will actually return the same environment.
|
||||||
|
*/
|
||||||
|
export const init = memoize(async function(): Promise<InitializedData> {
|
||||||
|
// services
|
||||||
|
const qweb = new QWeb();
|
||||||
|
const router = new Router();
|
||||||
|
const ajax = new Ajax();
|
||||||
|
const actionManager = new ActionManager(actionRegistry);
|
||||||
|
const notifications = new NotificationManager();
|
||||||
|
|
||||||
|
// templates
|
||||||
|
const templates = await loadTemplates();
|
||||||
|
qweb.addTemplate("default", "<div/>");
|
||||||
|
qweb.loadTemplates(templates);
|
||||||
|
|
||||||
|
const menuInfo = loadMenus();
|
||||||
|
|
||||||
|
const env: Env = {
|
||||||
|
// Base widget requirements
|
||||||
|
qweb,
|
||||||
|
getID: idGenerator(),
|
||||||
|
|
||||||
|
actionManager,
|
||||||
|
ajax,
|
||||||
|
notifications,
|
||||||
|
actionRegistry,
|
||||||
|
router,
|
||||||
|
|
||||||
|
rpc: ajax.rpc,
|
||||||
|
|
||||||
|
debug: false,
|
||||||
|
isMobile: window.innerWidth <= 768
|
||||||
|
};
|
||||||
|
return { env, menuInfo };
|
||||||
|
});
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Adapters
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function loadMenus(): MenuInfo {
|
||||||
|
const menuItems: BaseMenuItem[] = (<any>window).odoo.menus;
|
||||||
|
const menuInfo = getMenuInfo(menuItems);
|
||||||
|
delete (<any>window).odoo.menus; // overkill?
|
||||||
|
return menuInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTemplates(): Promise<string> {
|
||||||
|
const result = await fetch("templates.xml");
|
||||||
|
if (!result.ok) {
|
||||||
|
throw new Error("Error while fetching xml templates");
|
||||||
|
}
|
||||||
|
return result.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BaseMenuItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
parent_id: number | false;
|
||||||
|
action: string | false;
|
||||||
|
icon: string | false;
|
||||||
|
children: BaseMenuItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a valid MenuInfo object from a list of BaseMenuItems. This function
|
||||||
|
* is supposed to be called once at startup.
|
||||||
|
*/
|
||||||
|
export function getMenuInfo(items: BaseMenuItem[]): MenuInfo {
|
||||||
|
const menuMap: { [key: number]: MenuItem | undefined } = {};
|
||||||
|
const actionMap: { [id: number]: number | undefined } = {};
|
||||||
|
const roots: number[] = [];
|
||||||
|
|
||||||
|
// build MenuItems
|
||||||
|
for (let root of items) {
|
||||||
|
roots.push(root.id);
|
||||||
|
addToMap(root, root.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToMap(m: BaseMenuItem, appId: number): MenuItem {
|
||||||
|
const item: MenuItem = {
|
||||||
|
id: m.id,
|
||||||
|
name: m.name,
|
||||||
|
parentId: m.parent_id,
|
||||||
|
action: m.action,
|
||||||
|
icon: m.icon,
|
||||||
|
appId: appId,
|
||||||
|
actionId: -1, // will be filled later on with correct id
|
||||||
|
children: m.children.map(c => addToMap(c, appId))
|
||||||
|
};
|
||||||
|
menuMap[item.id] = item;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add proper actionId to every menuitems
|
||||||
|
for (let menuId in menuMap) {
|
||||||
|
const menu = menuMap[menuId]!;
|
||||||
|
let menuWithAction = menu && findInTree(menu, m => Boolean(m.action));
|
||||||
|
if (menuWithAction) {
|
||||||
|
menu.actionId = parseInt(
|
||||||
|
(<string>menuWithAction.action).split(",")[1],
|
||||||
|
10
|
||||||
|
);
|
||||||
|
if (menuWithAction === menu) {
|
||||||
|
actionMap[menu.actionId] = menu.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { menuMap, roots, actionMap };
|
||||||
|
}
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
///<amd-module name="main" />
|
///<amd-module name="main" />
|
||||||
|
|
||||||
import { makeEnvironment } from "./env";
|
import { init } from "./init";
|
||||||
import { BaseMenuItem, processMenuItems } from "./misc/menu_helpers";
|
|
||||||
import { Root } from "./widgets/root";
|
import { Root } from "./widgets/root";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Application bootstrapping
|
// Web Client Bootstrapping
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", async function() {
|
document.addEventListener("DOMContentLoaded", async function() {
|
||||||
const env = await makeEnvironment();
|
const { env, menuInfo } = await init();
|
||||||
|
|
||||||
// menu processing
|
// Creating root widget
|
||||||
const menuItems: BaseMenuItem[] = (<any>window).odoo.menus;
|
|
||||||
const menuInfo = processMenuItems(menuItems);
|
|
||||||
delete (<any>window).odoo.menus; // overkill?
|
|
||||||
|
|
||||||
// creating root widget
|
|
||||||
const rootWidget = new Root(env, { menuInfo });
|
const rootWidget = new Root(env, { menuInfo });
|
||||||
await rootWidget.mount(document.body);
|
await rootWidget.mount(document.body);
|
||||||
|
|
||||||
|
// For debugging purpose, we keep a reference to the root widget in odoo
|
||||||
(<any>window).odoo.rootWidget = rootWidget;
|
(<any>window).odoo.rootWidget = rootWidget;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
import { findInTree } from "../core/utils";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Types
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export interface BaseMenuItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
parent_id: number | false;
|
|
||||||
action: string | false;
|
|
||||||
icon: string | false;
|
|
||||||
children: BaseMenuItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuItem extends BaseMenuItem {
|
|
||||||
// root menu id
|
|
||||||
menuId: number;
|
|
||||||
actionId: number;
|
|
||||||
children: MenuItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MenuInfo {
|
|
||||||
menuMap: { [key: number]: MenuItem | undefined };
|
|
||||||
roots: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Helpers
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a valid MenuInfo object from a list of BaseMenuItems. This function
|
|
||||||
* is supposed to be called once at startup.
|
|
||||||
*/
|
|
||||||
export function processMenuItems(items: BaseMenuItem[]): MenuInfo {
|
|
||||||
const menuMap: MenuInfo["menuMap"] = {};
|
|
||||||
const roots: number[] = [];
|
|
||||||
|
|
||||||
// build MenuItems
|
|
||||||
for (let root of items) {
|
|
||||||
roots.push(root.id);
|
|
||||||
addToMap(root, root.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addToMap(m: BaseMenuItem, menuId: number): MenuItem {
|
|
||||||
let item: MenuItem = Object.assign({ menuId, actionId: -1 }, <MenuItem>m);
|
|
||||||
menuMap[item.id] = item;
|
|
||||||
item.children = m.children.map(c => addToMap(c, menuId));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add proper actionId to every menuitems
|
|
||||||
for (let menuId in menuMap) {
|
|
||||||
const menu = menuMap[menuId]!;
|
|
||||||
let menuWithAction = menu && findInTree(menu, m => Boolean(m.action));
|
|
||||||
if (menuWithAction) {
|
|
||||||
menu.actionId = parseInt(
|
|
||||||
(<string>menuWithAction.action).split(",")[1],
|
|
||||||
10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { menuMap, roots };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAppAndAction(
|
|
||||||
info: MenuInfo,
|
|
||||||
query: { menu_id?: string; action_id?: string }
|
|
||||||
): { app: MenuItem | null; actionId: number | null } {
|
|
||||||
let app = findApp(info, query.menu_id, query.action_id);
|
|
||||||
let actionId = findAction(info, query.menu_id, query.action_id);
|
|
||||||
|
|
||||||
return { app, actionId };
|
|
||||||
}
|
|
||||||
|
|
||||||
function findApp(
|
|
||||||
info: MenuInfo,
|
|
||||||
menu_id?: string,
|
|
||||||
action_id?: string
|
|
||||||
): MenuItem | null {
|
|
||||||
if (menu_id) {
|
|
||||||
const menuID = parseInt(menu_id, 10);
|
|
||||||
if (info.roots.indexOf(menuID) > -1) {
|
|
||||||
const menu = info.menuMap[menuID];
|
|
||||||
if (menu) {
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (action_id) {
|
|
||||||
for (let itemID in info.menuMap) {
|
|
||||||
let menu = info.menuMap[itemID];
|
|
||||||
const actionId = menu && menu.actionId;
|
|
||||||
if (actionId && String(actionId) === action_id) {
|
|
||||||
if (menu) {
|
|
||||||
let topMenu = info.menuMap[menu.menuId];
|
|
||||||
if (topMenu) {
|
|
||||||
return topMenu;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findAction(
|
|
||||||
info: MenuInfo,
|
|
||||||
menu_id?: string,
|
|
||||||
action_id?: string
|
|
||||||
): number | null {
|
|
||||||
if (action_id) {
|
|
||||||
return parseInt(action_id, 10);
|
|
||||||
}
|
|
||||||
if (menu_id) {
|
|
||||||
const menuID = parseInt(menu_id, 10);
|
|
||||||
const menu = info.menuMap[menuID]!;
|
|
||||||
return menu.actionId;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,42 @@
|
|||||||
import { INotification } from "../core/notifications";
|
import { INotification } from "../core/notifications";
|
||||||
import { Widget } from "./widget";
|
import { Query } from "../core/router";
|
||||||
import { debounce } from "../core/utils";
|
import { debounce } from "../core/utils";
|
||||||
import { Env } from "./widget";
|
|
||||||
import { MenuInfo, MenuItem, getAppAndAction } from "../misc/menu_helpers";
|
|
||||||
import { ActionStack } from "../services/action_manager";
|
import { ActionStack } from "../services/action_manager";
|
||||||
import { ActionContainer } from "./action_container";
|
import { ActionContainer } from "./action_container";
|
||||||
import { HomeMenu } from "./home_menu";
|
import { HomeMenu } from "./home_menu";
|
||||||
import { Navbar } from "./navbar";
|
import { Navbar } from "./navbar";
|
||||||
import { Notification } from "./notification";
|
import { Notification } from "./notification";
|
||||||
import { Query } from "../core/router";
|
import { Env, Widget } from "./widget";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Types
|
// Types
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export interface MenuItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
parentId: number | false;
|
||||||
|
action: string | false;
|
||||||
|
icon: string | false;
|
||||||
|
|
||||||
|
// root menu id
|
||||||
|
appId: number;
|
||||||
|
actionId: number;
|
||||||
|
children: MenuItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MenuInfo {
|
||||||
|
menuMap: { [key: number]: MenuItem | undefined };
|
||||||
|
|
||||||
|
// mapping from action id to menu id
|
||||||
|
actionMap: { [id: number]: number | undefined };
|
||||||
|
roots: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
menuInfo: MenuInfo;
|
||||||
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
notifications: INotification[];
|
notifications: INotification[];
|
||||||
stack: ActionStack;
|
stack: ActionStack;
|
||||||
@@ -21,10 +44,6 @@ interface State {
|
|||||||
currentApp: MenuItem | null;
|
currentApp: MenuItem | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
|
||||||
menuInfo: MenuInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Root Widget
|
// Root Widget
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -43,7 +62,7 @@ export class Root extends Widget<Props, State> {
|
|||||||
constructor(env: Env, props: Props) {
|
constructor(env: Env, props: Props) {
|
||||||
super(env, props);
|
super(env, props);
|
||||||
const query = this.env.router.getQuery();
|
const query = this.env.router.getQuery();
|
||||||
let { app, actionId } = getAppAndAction(props.menuInfo, query);
|
let { app, actionId } = this.getAppAndAction(query);
|
||||||
this.state.currentApp = app;
|
this.state.currentApp = app;
|
||||||
if (!actionId) {
|
if (!actionId) {
|
||||||
this.state.inHome = true;
|
this.state.inHome = true;
|
||||||
@@ -73,7 +92,7 @@ export class Root extends Widget<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateAction(query: Query) {
|
private updateAction(query: Query) {
|
||||||
let { app, actionId } = getAppAndAction(this.props.menuInfo, query);
|
let { app, actionId } = this.getAppAndAction(query);
|
||||||
this.updateAppState(app, actionId);
|
this.updateAppState(app, actionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +100,7 @@ export class Root extends Widget<Props, State> {
|
|||||||
const newApp = app || this.state.currentApp;
|
const newApp = app || this.state.currentApp;
|
||||||
if (actionId) {
|
if (actionId) {
|
||||||
const query: Query = { action_id: String(actionId) };
|
const query: Query = { action_id: String(actionId) };
|
||||||
const menuId = newApp ? newApp.menuId : false;
|
const menuId = newApp ? newApp.appId : false;
|
||||||
if (menuId) {
|
if (menuId) {
|
||||||
query.menu_id = String(menuId);
|
query.menu_id = String(menuId);
|
||||||
}
|
}
|
||||||
@@ -100,7 +119,34 @@ export class Root extends Widget<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openMenu(menu: MenuItem) {
|
openMenu(menu: MenuItem) {
|
||||||
const app = this.props.menuInfo.menuMap[menu.menuId]!;
|
const app = this.props.menuInfo.menuMap[menu.appId]!;
|
||||||
this.updateAppState(app, menu.actionId);
|
this.updateAppState(app, menu.actionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getAppAndAction(
|
||||||
|
query: Query
|
||||||
|
): { app: MenuItem | null; actionId: number | null } {
|
||||||
|
const menuInfo = this.props.menuInfo;
|
||||||
|
let app: MenuItem | null = null;
|
||||||
|
let actionId: number | null = null;
|
||||||
|
if ("action_id" in query) {
|
||||||
|
actionId = parseInt(query.action_id, 10);
|
||||||
|
if (menuInfo.actionMap[actionId]) {
|
||||||
|
const menuId = menuInfo.actionMap[actionId]!;
|
||||||
|
const appId = menuInfo.menuMap[menuId]!.appId;
|
||||||
|
app = menuInfo.menuMap[appId]!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("menu_id" in query) {
|
||||||
|
const menuId = parseInt(query.menu_id, 10);
|
||||||
|
const menu = menuInfo.menuMap[menuId];
|
||||||
|
if (menu) {
|
||||||
|
app = menuInfo.menuMap[menu.appId] || null;
|
||||||
|
if (!actionId) {
|
||||||
|
actionId = menu.actionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { app, actionId };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user