odoo前端的Patch用法

一、Patching code:根据官方功能解释

     我们需要自定义 UI 的工作方式。一些受支持的 API 涵盖了许多常见需求。

例如,所有注册表都是很好的扩展点: 字段注册表允许添加/删除专门的字段组件,或者主组件注册表允许添加应该一直显示的组件。

但是,在某些情况下它是不够的。在这些情况下,我们可能需要就地修改对象或类。为此,Odoo 提供了实用功能patch。

覆盖/更新无法控制的其他一些组件/代码段的行为最有用。

 

二、Patch源码位置 :../web/static/src/core/utils/patch.js

      引用方式:   import { patch } from 'web.utils';

      patch方法的定义:

/** @odoo-module **/

const patchMap = new WeakMap();
/**
 * Patch an object
 *
 * If the intent is to patch a class, don't forget to patch the prototype, unless
 * you want to patch static properties/methods.
 * 如果目的是修补一个类,不要忘记修补原型,除非你想修补静态属性方法。
 *
 * @param {Object} obj   添加补丁的对象
 * @param {string} patchName 补丁名
 * @param {Object} patchValue 补丁值
 * @param {{pure?: boolean}} [options]  其他选项
 */
export function patch(obj, patchName, patchValue, options = {}) {
    const pure = Boolean(options.pure);
    if (!patchMap.has(obj)) {
        patchMap.set(obj, {
            original: {},
            patches: [],
        });
    }
    const objDesc = patchMap.get(obj);
    if (objDesc.patches.some((p) => p.name === patchName)) {
        throw new Error(`Class ${obj.name} already has a patch ${patchName}`);
    }
    objDesc.patches.push({
        name: patchName,
        patch: patchValue,
        pure,
    });

    for (const k in patchValue) {
        let prevDesc = null;
        let proto = obj;
        do {
            prevDesc = Object.getOwnPropertyDescriptor(proto, k);
            proto = Object.getPrototypeOf(proto);
        } while (!prevDesc && proto);

        const newDesc = Object.getOwnPropertyDescriptor(patchValue, k);
        if (!objDesc.original.hasOwnProperty(k)) {
            objDesc.original[k] = Object.getOwnPropertyDescriptor(obj, k);
        }

        if (prevDesc) {
            const patchedFnName = `${k} (patch ${patchName})`;

            if (prevDesc.value && typeof newDesc.value === "function") {
                makeIntermediateFunction("value", prevDesc, newDesc, patchedFnName);
            }
            if ((newDesc.get || newDesc.set) && (prevDesc.get || prevDesc.set)) {
                // get and set are defined together. If they are both defined
                // in the previous descriptor but only one in the new descriptor
                // then the other will be undefined so we need to apply the
                // previous descriptor in the new one.
                // get和set一起定义。如果它们都在前一个描述符中定义,
                // 但在新的描述符中只有一个,那么另一个将是未定义的,因此我们需要在新的描述符中应用前一个描述符。
                // 发挥中间作用
                newDesc.get = newDesc.get || prevDesc.get;
                newDesc.set = newDesc.set || prevDesc.set;
                if (prevDesc.get && typeof newDesc.get === "function") {
                    makeIntermediateFunction("get", prevDesc, newDesc, patchedFnName);
                }
                if (prevDesc.set && typeof newDesc.set === "function") {
                    makeIntermediateFunction("set", prevDesc, newDesc, patchedFnName);
                }
            }
        }

        Object.defineProperty(obj, k, newDesc);
    }

    function makeIntermediateFunction(key, prevDesc, newDesc, patchedFnName) {
        const _superFn = prevDesc[key];
        const patchFn = newDesc[key];
        if (pure) {
            newDesc[key] = patchFn;
        } else {
            newDesc[key] = {
                [patchedFnName](...args) {
                    let prevSuper;
                    if (this) {
                        prevSuper = this._super;
                        Object.defineProperty(this, "_super", {
                            value: _superFn.bind(this),
                            configurable: true,
                            writable: true,
                        });
                    }
                    const result = patchFn.call(this, ...args);
                    if (this) {
                        Object.defineProperty(this, "_super", {
                            value: prevSuper,
                            configurable: true,
                            writable: true,
                        });
                    }
                    return result;
                },
            }[patchedFnName];
        }
    }
}

 

 

案例:设置主题的背景、前景、和图片方法,js部分代码截图

 

/** @odoo-module */

import { NavBar } from "@web/webclient/navbar/navbar";
import { registry } from "@web/core/registry";
const { fuzzyLookup } = require('@web/core/utils/search');
import { computeAppsAndMenuItems } from "@web/webclient/menus/menu_helpers";
import core from 'web.core';

const commandProviderRegistry = registry.category("command_provider");

import { patch } from 'web.utils';
var rpc = require('web.rpc');
//'backend_theme/static/src/components/app_menu/search_apps.js'  
// 字符串名称:官方写法是该js的路径来命名
//对象名称
NavBar.prototype
patch(NavBar.prototype, 'backend_theme/static/src/components/app_menu/search_apps.js', {

    //--------------------------------------------------------------------------
    // Public  设置背景、前景、悬浮颜色
    //--------------------------------------------------------------------------
    /**
     * @override
     */
     setup() {
        this._super();
        this._search_def = $.Deferred();
        let { apps, menuItems } = computeAppsAndMenuItems(this.menuService.getMenuAsTree("root"));
        this._apps = apps;
        this._searchableMenus = menuItems;
        this.colors = this.fetch_data();
    },
    fetch_data: function() {
        var self = this;
        rpc.query({model: 'res.config.settings',method: 'config_color_settings',args: [0],}).then(function(result){
            self.colors = result;
            console.log("$$$",result);
            if (result.primary_accent !== false){
                document.documentElement.style.setProperty("--primary-accent",result.primary_accent);
            }
            if (result.appbar_color !== false){
                document.documentElement.style.setProperty("--app-bar-accent",result.appbar_color);}
            if (result.primary_hover !== false){
                document.documentElement.style.setProperty("--primary-hover",result.primary_hover);}
            if (result.secondary_color !== false){
                document.documentElement.style.setProperty("--primary-accent-border",result.secondary_color);}
            if (result.full_bg_img !== false){
                document.documentElement.style.setProperty("--full-screen-bg",'url(data:image/png;base64,'+result.full_bg_img+')');

            }
            if (result.appbar_text !== false){
                document.documentElement.style.setProperty("--app-menu-font-color",result.appbar_text);}
            if (result.secoundary_hover !== false){
                document.documentElement.style.setProperty("--secoundary-hover",result.secoundary_hover);}
            if (result.kanban_bg_color !== false){
                document.documentElement.style.setProperty("--kanban-bg-color",result.kanban_bg_color);}
        });
    },

});

 

 

posted @ 2022-05-14 09:25  何双新  阅读(223)  评论(0编辑  收藏  举报