mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
refactoring: implement actionmanager, and router
So we now have a working SPA!
This commit is contained in:
@@ -1,22 +1,81 @@
|
||||
import { Action } from "./actions";
|
||||
import { Bus } from "../core/bus";
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
import { Router, Query } from "./router";
|
||||
import { Discuss } from "../widgets/discuss";
|
||||
import { CRM } from "../widgets/crm";
|
||||
|
||||
// export interface Action {
|
||||
// id: number;
|
||||
// title: string;
|
||||
// Widget: Type<Widget<Env>>;
|
||||
// default?: boolean;
|
||||
// }
|
||||
interface Type<T> extends Function {
|
||||
new (...args: any[]): T;
|
||||
}
|
||||
|
||||
// const actions: Action[] = [
|
||||
// { id: 1, title: "Discuss", Widget: Discuss, default: true },
|
||||
// { id: 2, title: "CRM", Widget: CRM }
|
||||
// ];
|
||||
interface ClientAction {
|
||||
type: "client";
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ActionManager {
|
||||
doAction(action: Action) {
|
||||
console.log(action);
|
||||
// load data (??)
|
||||
// trigger action somewhere
|
||||
// upload url with router
|
||||
interface ActWindowAction {
|
||||
type: "act_window";
|
||||
views: string[];
|
||||
}
|
||||
|
||||
export type Action = ClientAction | ActWindowAction;
|
||||
|
||||
export interface ActionWidget {
|
||||
id: number;
|
||||
Widget: Type<Widget<Env>>;
|
||||
props: any;
|
||||
}
|
||||
|
||||
const actions: any[] = [
|
||||
{ id: 1, title: "Discuss", Widget: Discuss, default: true },
|
||||
{ id: 2, title: "CRM", Widget: CRM }
|
||||
];
|
||||
|
||||
export class ActionManager extends Bus {
|
||||
router: Router;
|
||||
currentAction: ActionWidget | null = null;
|
||||
|
||||
constructor(router: Router) {
|
||||
super();
|
||||
this.router = router;
|
||||
const query = this.router.getQuery();
|
||||
this.update(query);
|
||||
this.router.on("query_changed", this, this.update);
|
||||
if (!this.currentAction) {
|
||||
const action = actions.find(a => a.default);
|
||||
if (action) {
|
||||
this.doAction(action.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(query: Query) {
|
||||
const initialAction = this.currentAction;
|
||||
if ("action_id" in query) {
|
||||
const actionID = parseInt(query.action_id);
|
||||
this.doAction(actionID);
|
||||
}
|
||||
if (this.currentAction && initialAction !== this.currentAction) {
|
||||
}
|
||||
}
|
||||
|
||||
doAction(actionID: number) {
|
||||
const action = actions.find(a => a.id === actionID);
|
||||
if (action) {
|
||||
this.currentAction = {
|
||||
id: action.id,
|
||||
Widget: action.Widget,
|
||||
props: {}
|
||||
};
|
||||
}
|
||||
this.trigger("action_ready", this.currentAction);
|
||||
this.router.navigate({ action_id: String(actionID) });
|
||||
}
|
||||
|
||||
registerAction(action: Action) {}
|
||||
|
||||
getCurrentAction(): ActionWidget | null {
|
||||
return this.currentAction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { CRM } from "../widgets/crm";
|
||||
import { Discuss } from "../widgets/discuss";
|
||||
import { Widget } from "../core/widget";
|
||||
import { Env } from "../env";
|
||||
|
||||
interface Type<T> extends Function {
|
||||
new (...args: any[]): T;
|
||||
}
|
||||
|
||||
export interface Action {
|
||||
id: number;
|
||||
title: string;
|
||||
Widget: Type<Widget<Env>>;
|
||||
default?: boolean;
|
||||
}
|
||||
|
||||
export const actions: Action[] = [
|
||||
{ id: 1, title: "Discuss", Widget: Discuss, default: true },
|
||||
{ id: 2, title: "CRM", Widget: CRM }
|
||||
];
|
||||
|
||||
// class ActionManager {
|
||||
|
||||
// doAction(action: Action) {
|
||||
|
||||
// }
|
||||
// }
|
||||
@@ -1 +1 @@
|
||||
export default class Ajax {}
|
||||
export class Ajax {}
|
||||
|
||||
@@ -2,76 +2,49 @@ import { Bus } from "../core/bus";
|
||||
|
||||
export type Query = { [key: string]: string };
|
||||
|
||||
export interface Route {
|
||||
// this is the part before the hash: www.something.com/web#action=1 => web
|
||||
path: string;
|
||||
query: Query;
|
||||
title: string;
|
||||
}
|
||||
|
||||
function clearSlaches(s: string): string {
|
||||
function clearSlashes(s: string): string {
|
||||
return s.replace(/\/$/, "").replace(/^\//, "");
|
||||
}
|
||||
|
||||
export default class Router extends Bus {
|
||||
listeners: { owner: any; callback: (info: Route) => void }[] = [];
|
||||
export class Router extends Bus {
|
||||
currentQuery: Query;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
window.addEventListener("popstate", this.onUrlChange.bind(this));
|
||||
window.onhashchange = function() {
|
||||
console.log("aaaa");
|
||||
debugger;
|
||||
this.currentQuery = this.getQuery();
|
||||
window.onhashchange = () => {
|
||||
this.currentQuery = this.getQuery();
|
||||
this.trigger("query_changed", this.currentQuery);
|
||||
};
|
||||
}
|
||||
|
||||
onUrlChange(event: PopStateEvent) {
|
||||
debugger;
|
||||
event.preventDefault();
|
||||
const info = this.getRoute();
|
||||
for (let listener of this.listeners) {
|
||||
listener.callback.call(listener.owner, info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Route} route relative route: for example, /web/
|
||||
* @param {Query} query
|
||||
*/
|
||||
navigate(info: Partial<Route>) {
|
||||
const currentRoute = this.getRoute();
|
||||
const route = info.path || currentRoute.path;
|
||||
const query = info.query || {};
|
||||
const title = info.title || currentRoute.title;
|
||||
const url = this.formatURL(route, query);
|
||||
window.history.pushState(null, title, url);
|
||||
}
|
||||
register(owner: any, callback: (info: Route) => void) {
|
||||
this.listeners.push({ owner, callback });
|
||||
navigate(query: Query) {
|
||||
const url = this.formatURL("", query);
|
||||
window.history.replaceState(null, document.title, url);
|
||||
}
|
||||
|
||||
unregister(owner: any) {
|
||||
this.listeners = this.listeners.filter(l => l.owner !== owner);
|
||||
formatQuery(query: Query): string {
|
||||
let parts: string[] = [];
|
||||
for (let key in query) {
|
||||
parts.push(`${key}=${query[key]}`);
|
||||
}
|
||||
return parts.join("&");
|
||||
}
|
||||
|
||||
formatURL(path: string, query: Query): string {
|
||||
let url = clearSlaches(path);
|
||||
let hasHash = false;
|
||||
for (let key in query) {
|
||||
url = url + (hasHash ? "&" : "#");
|
||||
url = url + `${key}=${query[key]}`;
|
||||
hasHash = true;
|
||||
}
|
||||
return "/" + url;
|
||||
let url = clearSlashes(path);
|
||||
return `/${url}#${this.formatQuery(query)}`;
|
||||
}
|
||||
|
||||
getRoute(): Route {
|
||||
const path = clearSlaches(window.location.pathname);
|
||||
getQuery(): Query {
|
||||
const query = {};
|
||||
for (let part of window.location.hash.slice(1).split("?")) {
|
||||
let [key, value] = part.split("=");
|
||||
query[key] = value;
|
||||
}
|
||||
return { path, query, title: document.title };
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user