ActionAdapter


Action Adapter is a base class for clientAdapther and viewAdapter, it support some common fuction. like set the state of the action, direct the messages to service, call widgetdetach call back etc. notice that, the use the exportState to get the legacy widget and __legacy__isActionInStack to check the widget destroy or not. so you can hook it to keep your widget.

class ActionAdapter extends ComponentAdapter {
    setup() {
        super.setup();
        this.actionService = useService("action");
        this.router = useService("router");
        this.title = useService("title");
        this.notifications = useService("notification");
        this.dialogs = useService("dialog");
        this.wowlEnv = this.env;
        // a legacy widget widget can push_state anytime including during its async rendering
        // In Wowl, we want to have all states pushed during the same setTimeout.
        // This is protected in legacy (backward compatibility) but should not e supported in Wowl
        this.tempQuery = {};
        let originalUpdateControlPanel;
        useEffect(
            () => {
                const query = this.widget.getState();
                Object.assign(query, this.tempQuery);
                this.tempQuery = null;
                this.__widget = this.widget;
                if (!this.wowlEnv.inDialog) {
                    this.pushState(query);
                }
                this.wowlEnv.bus.on("ACTION_MANAGER:UPDATE", this, () => {
                    this.env.bus.trigger("close_dialogs");
                    cleanDomFromBootstrap();
                });
                originalUpdateControlPanel = this.__widget.updateControlPanel.bind(this.__widget);
                this.__widget.updateControlPanel = (newProps) => {
                    this.trigger("controller-title-updated", this.__widget.getTitle());
                    return originalUpdateControlPanel(newProps);
                };
                core.bus.trigger("DOM_updated");

                return () => {
                    this.__widget.updateControlPanel = originalUpdateControlPanel;
                    this.wowlEnv.bus.off("ACTION_MANAGER:UPDATE", this);
                };
            },
            () => []
        );
        hooks.useExternalListener(window, "click", () => {
            cleanDomFromBootstrap();
        });
    }

    get actionId() {
        throw new Error("Should be implement by specific adapters");
    }

    pushState(state) {
        if (this.wowlEnv.inDialog) {
            return;
        }
        const query = objectToQuery(state);
        if (this.tempQuery) {
            Object.assign(this.tempQuery, query);
            return;
        }
        if (this.widget) {
            const actionTitle = this.widget.getTitle();
            if (actionTitle) {
                this.trigger("controller-title-updated", actionTitle);
            }
        }
        this.router.pushState(query);
    }

    _trigger_up(ev) {
        const payload = ev.data;
        if (ev.name === "do_action") {
            if (payload.action.context) {
                payload.action.context = new Context(payload.action.context).eval();
            }
            this.onReverseBreadcrumb = payload.options && payload.options.on_reverse_breadcrumb;
            const legacyOptions = mapDoActionOptionAPI(payload.options);
            wrapSuccessOrFail(this.actionService.doAction(payload.action, legacyOptions), payload);
        } else if (ev.name === "breadcrumb_clicked") {
            this.actionService.restore(payload.controllerID);
        } else if (ev.name === "push_state") {
            this.pushState(payload.state);
        } else if (ev.name === "set_title_part") {
            const { part, title } = payload;
            this.title.setParts({ [part]: title || null });
        } else if (ev.name === "warning") {
            if (payload.type === "dialog") {
                class WarningDialog extends Dialog {
                    setup() {
                        super.setup();
                        this.title = this.props.title;
                    }
                }
                WarningDialog.bodyTemplate = warningDialogBodyTemplate;
                this.dialogs.add(WarningDialog, {
                    title: payload.title,
                    message: payload.message,
                });
            } else {
                this.notifications.add(payload.message, {
                    className: payload.className,
                    sticky: payload.sticky,
                    title: payload.title,
                    type: "warning",
                });
            }
        } else {
            super._trigger_up(ev);
        }
    }

    /**
     * This function is called just before the component will be unmounted,
     * because it will be replaced by another one. However, we need to keep it
     * alive, because we might come back to this one later. We thus return the
     * widget instance, and set this.widget to null so that it is not destroyed
     * by the compatibility layer. That instance will be destroyed by the
     * ActionManager service when it will be removed from the controller stack,
     * and if we ever come back to that controller, the instance will be given
     * in props so that we can re-use it.
     */
    exportState() {
        this.widget = null;
        return {
            __legacy_widget__: this.__widget,
            __on_reverse_breadcrumb__: this.onReverseBreadcrumb,
        };
    }

    canBeRemoved() {
        return this.__widget.canBeRemoved();
    }

    /**
     * @override
     */
    willUnmount() {
        if (this.__widget && this.__widget.on_detach_callback) {
            this.__widget.on_detach_callback();
        }
        super.willUnmount();
    }
    __destroy() {
        if (this.actionService.__legacy__isActionInStack(this.actionId)) {
            this.widget = null;
        }
        super.__destroy(...arguments);
    }
}
Moduledidi libray analyse