如何改进标准控制

好的,我已经按照您的要求,将 HTML 内容中的文本翻译成了通俗易懂的中文,同时严格保留了所有 HTML 标签、属性和结构,并原样保留了形如 <pre><code> frappe.ui.form.ControlData = frappe.ui.form.ControlData.$extend({ make_input: function(){ var options = this.df.options; if (!options || options!=="Translatable"){ this._super(); return; } var me = this; $('\ \ \ \\ \ ').prependTo(this.input_area); this.$input_area = $(this.input_area); this.$input = this.$input_area.find('input'); this.$btn = this.$input_area.find('.dialog-btn'); this.set_input_attributes(); this.$input.on("focus", function(){ me.$btn.toggle(true); }); this.$input.on("blur", function(){ setTimeout(function(){ me.$btn.toggle(false) }, 500); }); this.input = $this.input.get(0); this.has_input = true; var me = this; this.setup_button(); }, setup_button: function(){ var me = this; if (this.only_input){ this.$btn.remove(); return; } this.$btn.on("click", function(){ var value = me.get_value(); var options = me.df.options; if (value && options && options==="Translatable"){ this.open_dialog(); } }); }, open_dialog: function(){ if (this.frm && !this.frm.is_dirty()) { new frappe.ui.form.TranslationSelector({ doc: doc, df: this.doc, text: this.value }); } } }); 的代码块占位符。


<article :class="{ 'opacity-50': $store.navigation.loading, 'xl:!max-w-[100ch]': $store.sidebar?.isCollapsed }" class="min-w-0 w-full transition-opacity duration-300 xl:max-w-[85ch]">
<!-- 页面头部 -->

<!-- 页面内容 -->
<!-- prose prose-v3 镜像了 SPA 编辑器中的 EditorContent 默认样式 -->
<div class="prose prose-v3 !max-w-none" id="wiki-content">
<p>Frappe 有一些优雅且实用的控件,但有时我们需要对它们进行修改以添加一些小的改进。这篇小文章将介绍如何向标准控件中添加新的资源。</p>
<p>首先,让我解释一下我们的目标:</p>
<blockquote>
<p>在 <code>numerous records 和 lot of doctypes 中添加 many 的替代翻译

看看目标中高亮的部分,我们需要在许多记录和许多文档类型中添加许多翻译,因此,我们有很多工作要做,对吧?

这个问题的答案是:-当然不是!因为我们知道,如果一个元素存在于许多记录和许多文档类型中,那么这个元素就是 Control 或 Widget

所以,我们需要做的是,基于 Control 来改进你的目标,以减少我们的工作量。

但是,我们将在哪里找到这个神奇的元素,即控件呢?-目前,我们可以在 JavaScript 源码中查看它 - 现在让我们看看 Github

如果现在看不懂代码,请不要担心,我们的目标是简化我们的工作。

让我们继续思考!

我们知道需要在何处进行更改,但我们如何区分哪些控件受我们功能的影响,哪些不受影响呢?

我们需要记住,Control 是 DocFields 的实例,并且 DocFields 有一个字段在这种情况下对我们非常重要,这个能帮助我们区分哪些受功能影响、哪些不受影响的字段是 DocField 中的 options 字段。

-等等!我们明白了 options 字段可以帮助我们,但是,它将如何帮助我们呢?

问得好,我们将定义一个词,放在我们需要包含该功能的 DocFields 的 options 中,这个词将是 Translatable。

如果你忘记了如何自定义字段的选项,可以看看这篇文章,它能帮你复习一下相关知识。

好了,在我们选定的 DocFields 的 options 中定义了关键词后,现在是时候编写代码了:

-终于,我们以为我们永远不会停止讨论呢!

 frappe.ui.form.ControlData = frappe.ui.form.ControlData.$extend({
 make_input: function(){
 var options = this.df.options;
 if (!options || options!=="Translatable"){
 this._super();
 return;
 }
 var me = this;
 $('\
 \
 \
 \\
 \
 ').prependTo(this.input_area);
 this.$input_area = $(this.input_area);
 this.$input = this.$input_area.find('input');
 this.$btn = this.$input_area.find('.dialog-btn');
 this.set_input_attributes();
 this.$input.on("focus", function(){
 me.$btn.toggle(true);
 });
 this.$input.on("blur", function(){
 setTimeout(function(){ me.$btn.toggle(false) }, 500);
 });
 this.input = $this.input.get(0);
 this.has_input = true;
 var me = this;
 this.setup_button();
 },
 setup_button: function(){
 var me = this;
 if (this.only_input){
 this.$btn.remove();
 return;
 }
 this.$btn.on("click", function(){
 var value = me.get_value();
 var options = me.df.options;
 if (value && options && options==="Translatable"){
 this.open_dialog();
 }
 });
 },
 open_dialog: function(){
 if (this.frm && !this.frm.is_dirty()) {
 new frappe.ui.form.TranslationSelector({
 doc: doc,
 df: this.doc,
 text: this.value
 });
 }
 }
 });

-我的天,又是一堆字母汤!

事实上,对于新手来说,它确实是一堆字母汤,但我们不是初学者。

让我解释一下这段代码的作用;

  • 第 1 行,代码通过其自身的扩展 Class 覆盖了 ControlData。
  • 方法 make_input 检查 docfield 是否为 Translatable,以创建新的 Control,如果不是,则使用 _super() 调用原始的 make_input。
  • 方法 setup_button 检查 docfield 是否为 Translatable,以启用它显示一个 dialog。
  • 方法 open_dialog 调用我们将在下面代码中创建的 TranslationSelector 的一个新实例。

在文档类型事件上执行代码

要在 DocType 被插入、验证(保存前)、更新、提交、取消、删除时执行代码,你必须在 DocType 的控制器模块中编写代码。

1. 控制器模块

控制器模块位于 DocType 模块的 doctype 文件夹中。例如,ToDo 的控制器位于 frappe/desk/doctype/todo/todo.py(版本 5)。创建 DocType 时会自动生成一个控制器模板,内容如下:

from future import unicode_literals

import frappe
from frappe.model.document import Document

class CustomType(Document):
pass

2. 文档属性

所有字段和子表都可以作为类的属性访问。例如,name 属性就是 self.name

3. 添加方法

在此模块中,你可以向类中添加标准方法,这些方法会在创建该类型的文档时被调用。标准处理器包括:

  1. autoname:在命名时调用。你可以在此方法中设置 self.name 属性。
  2. before_insert:在文档插入前调用。
  3. validate:在文档保存前调用。如果你不希望文档被保存,可以抛出异常。
  4. on_update:在文档插入或更新到数据库后调用。
  5. on_submit:在提交后调用。
  6. on_cancel:在取消后调用。
  7. on_trash:在文档被删除后调用。

链接字段中的自定义操作

您可以通过在命名空间 frappe.ui.form.ControlLink.link_options 中定义函数,为标准链接字段添加新的自定义链接选项。

在 frappe.ui.form.ControlLink.link_options 中,您可以访问链接字段对象。

1. 添加自定义选项

frappe.ui.form.ControlLink.link_options = function(link) {
 return [
 {
 html: ""
 + " "
 + __("Custom Link Option")
 + "",
 label: __("Custom Link Option"),
 value: "custom__link_option",
 action: () => {}
 }
 ];
}

一旦将函数分配给 frappe.ui.form.ControlLink.link_options,链接字段将出现一个新的链接选项: