diff --git a/addons/account/static/src/components/account_payment_field/account_payment_field.js b/addons/account/static/src/components/account_payment_field/account_payment_field.js index b85831ed525..2d123abafc4 100644 --- a/addons/account/static/src/components/account_payment_field/account_payment_field.js +++ b/addons/account/static/src/components/account_payment_field/account_payment_field.js @@ -88,6 +88,10 @@ export class AccountPaymentField extends Component { } } AccountPaymentField.template = "account.AccountPaymentField"; -AccountPaymentField.supportedTypes = ["char"]; -registry.category("fields").add("payment", AccountPaymentField); +export const accountPaymentField = { + component: AccountPaymentField, + supportedTypes: ["char"], +}; + +registry.category("fields").add("payment", accountPaymentField); diff --git a/addons/account/static/src/components/account_resequence/account_resequence_field.js b/addons/account/static/src/components/account_resequence/account_resequence_field.js index ecb9b3d173e..4f33b087dba 100644 --- a/addons/account/static/src/components/account_resequence/account_resequence_field.js +++ b/addons/account/static/src/components/account_resequence/account_resequence_field.js @@ -21,4 +21,6 @@ class ShowResequenceRenderer extends Component { ShowResequenceRenderer.template = "account.ResequenceRenderer"; ShowResequenceRenderer.components = { ChangeLine }; -registry.category("fields").add("account_resequence_widget", ShowResequenceRenderer); +registry.category("fields").add("account_resequence_widget", { + component: ShowResequenceRenderer, +}); diff --git a/addons/account/static/src/components/account_type_selection/account_type_selection.js b/addons/account/static/src/components/account_type_selection/account_type_selection.js index 6e43dff1935..a2b79d82c19 100644 --- a/addons/account/static/src/components/account_type_selection/account_type_selection.js +++ b/addons/account/static/src/components/account_type_selection/account_type_selection.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { SelectionField } from "@web/views/fields/selection/selection_field"; +import { SelectionField, selectionField } from "@web/views/fields/selection/selection_field"; export class AccountTypeSelection extends SelectionField { get hierarchyOptions() { @@ -20,4 +20,9 @@ export class AccountTypeSelection extends SelectionField { } AccountTypeSelection.template = "account.AccountTypeSelection"; -registry.category("fields").add("account_type_selection", AccountTypeSelection); +export const accountTypeSelection = { + ...selectionField, + component: AccountTypeSelection, +}; + +registry.category("fields").add("account_type_selection", accountTypeSelection); diff --git a/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js b/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js index 6f368a34353..76f195efdf7 100644 --- a/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js +++ b/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; +import { Many2ManyTagsField, many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; const { onWillUpdateProps } = owl; @@ -46,4 +46,9 @@ export class AutosaveMany2ManyTagsField extends Many2ManyTagsField { } } -registry.category("fields").add("autosave_many2many_tags", AutosaveMany2ManyTagsField); +export const autosaveMany2ManyTagsField = { + ...many2ManyTagsField, + component: AutosaveMany2ManyTagsField, +}; + +registry.category("fields").add("autosave_many2many_tags", autosaveMany2ManyTagsField); diff --git a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js index f8b90ab2dd7..6f06f801316 100644 --- a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js +++ b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js @@ -28,4 +28,6 @@ class ShowGroupedList extends Component { ShowGroupedList.template = "account.GroupedListTemplate"; ShowGroupedList.components = { ListGroup }; -registry.category("fields").add("grouped_view_widget", ShowGroupedList); +registry.category("fields").add("grouped_view_widget", { + component: ShowGroupedList, +}); diff --git a/addons/account/static/src/components/journal_dashboard_activity/journal_dashboard_activity.js b/addons/account/static/src/components/journal_dashboard_activity/journal_dashboard_activity.js index c8b9d5d069b..ace961bc683 100644 --- a/addons/account/static/src/components/journal_dashboard_activity/journal_dashboard_activity.js +++ b/addons/account/static/src/components/journal_dashboard_activity/journal_dashboard_activity.js @@ -45,4 +45,8 @@ export class JournalDashboardActivity extends Component { } JournalDashboardActivity.template = "account.JournalDashboardActivity"; -registry.category("fields").add("kanban_vat_activity", JournalDashboardActivity); +export const journalDashboardActivity = { + component: JournalDashboardActivity, +}; + +registry.category("fields").add("kanban_vat_activity", journalDashboardActivity); diff --git a/addons/account/static/src/components/open_move_line_move_widget/open_move_line_move_widget.js b/addons/account/static/src/components/open_move_line_move_widget/open_move_line_move_widget.js index 815607938b4..ba7ad0119de 100644 --- a/addons/account/static/src/components/open_move_line_move_widget/open_move_line_move_widget.js +++ b/addons/account/static/src/components/open_move_line_move_widget/open_move_line_move_widget.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2OneField } from "@web/views/fields/many2one/many2one_field"; +import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field"; class LineOpenMoveWidget extends Many2OneField { async openAction() { @@ -10,4 +10,9 @@ class LineOpenMoveWidget extends Many2OneField { } } -registry.category("fields").add("line_open_move_widget", LineOpenMoveWidget); +export const lineOpenMoveWidget = { + ...many2OneField, + component: LineOpenMoveWidget, +}; + +registry.category("fields").add("line_open_move_widget", lineOpenMoveWidget); diff --git a/addons/account/static/src/components/open_move_widget/open_move_widget.js b/addons/account/static/src/components/open_move_widget/open_move_widget.js index d996876d065..b546b430e58 100644 --- a/addons/account/static/src/components/open_move_widget/open_move_widget.js +++ b/addons/account/static/src/components/open_move_widget/open_move_widget.js @@ -19,4 +19,6 @@ class OpenMoveWidget extends Component { } OpenMoveWidget.template = "account.OpenMoveWidget"; -registry.category("fields").add("open_move_widget", OpenMoveWidget); +registry.category("fields").add("open_move_widget", { + component: OpenMoveWidget, +}); diff --git a/addons/account/static/src/components/section_and_note_fields_backend/section_and_note_fields_backend.js b/addons/account/static/src/components/section_and_note_fields_backend/section_and_note_fields_backend.js index ec37200c5a6..77c8c99d4ca 100644 --- a/addons/account/static/src/components/section_and_note_fields_backend/section_and_note_fields_backend.js +++ b/addons/account/static/src/components/section_and_note_fields_backend/section_and_note_fields_backend.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; import { ListRenderer } from "@web/views/list/list_renderer"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; import { TextField, ListTextField } from "@web/views/fields/text/text_field"; import { CharField } from "@web/views/fields/char/char_field"; @@ -82,7 +82,6 @@ export class SectionAndNoteText extends Component { } } SectionAndNoteText.template = "account.SectionAndNoteText"; -SectionAndNoteText.additionalClasses = ["o_field_text"]; export class ListSectionAndNoteText extends SectionAndNoteText { get componentToUse() { @@ -92,6 +91,21 @@ export class ListSectionAndNoteText extends SectionAndNoteText { } } -registry.category("fields").add("section_and_note_one2many", SectionAndNoteFieldOne2Many); -registry.category("fields").add("section_and_note_text", SectionAndNoteText); -registry.category("fields").add("list.section_and_note_text", ListSectionAndNoteText); +export const sectionAndNoteFieldOne2Many = { + ...x2ManyField, + component: SectionAndNoteFieldOne2Many, +}; + +export const sectionAndNoteText = { + component: SectionAndNoteText, + additionalClasses: ["o_field_text"], +}; + +export const listSectionAndNoteText = { + ...sectionAndNoteText, + component: ListSectionAndNoteText, +}; + +registry.category("fields").add("section_and_note_one2many", sectionAndNoteFieldOne2Many); +registry.category("fields").add("section_and_note_text", sectionAndNoteText); +registry.category("fields").add("list.section_and_note_text", listSectionAndNoteText); diff --git a/addons/account/static/src/components/tax_totals/tax_totals.js b/addons/account/static/src/components/tax_totals/tax_totals.js index d8fa1f82523..556f89712f3 100644 --- a/addons/account/static/src/components/tax_totals/tax_totals.js +++ b/addons/account/static/src/components/tax_totals/tax_totals.js @@ -186,4 +186,8 @@ TaxTotalsComponent.props = { ...standardFieldProps, }; -registry.category("fields").add("account-tax-totals-field", TaxTotalsComponent); +export const taxTotalsComponent = { + component: TaxTotalsComponent, +}; + +registry.category("fields").add("account-tax-totals-field", taxTotalsComponent); diff --git a/addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js b/addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js index a435740a6eb..357f472c651 100644 --- a/addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js +++ b/addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js @@ -573,15 +573,11 @@ export class AnalyticDistribution extends Component { } } AnalyticDistribution.template = "analytic.AnalyticDistribution"; -AnalyticDistribution.supportedTypes = ["char", "text"]; AnalyticDistribution.components = { AnalyticAutoComplete, TagsList, } -AnalyticDistribution.fieldDependencies = { - analytic_precision: { type: 'integer' }, -} AnalyticDistribution.props = { ...standardFieldProps, business_domain: { type: String, optional: true }, @@ -591,15 +587,21 @@ AnalyticDistribution.props = { force_applicability: { type: String, optional: true }, allow_save: { type: Boolean }, } -AnalyticDistribution.extractProps = ({ field, attrs }) => { - return { + +export const analyticDistribution = { + component: AnalyticDistribution, + supportedTypes: ["char", "text"], + fieldDependencies: { + analytic_precision: { type: "integer" }, + }, + extractProps: ({ attrs }) => ({ business_domain: attrs.options.business_domain, account_field: attrs.options.account_field, product_field: attrs.options.product_field, business_domain_compute: attrs.business_domain_compute, force_applicability: attrs.options.force_applicability, - allow_save: !Boolean(attrs.options.disable_save), - }; + allow_save: !attrs.options.disable_save, + }), }; -registry.category("fields").add("analytic_distribution", AnalyticDistribution); +registry.category("fields").add("analytic_distribution", analyticDistribution); diff --git a/addons/auth_password_policy/static/src/password_field.js b/addons/auth_password_policy/static/src/password_field.js index 87477d49c65..8e10f8ea8b2 100644 --- a/addons/auth_password_policy/static/src/password_field.js +++ b/addons/auth_password_policy/static/src/password_field.js @@ -30,8 +30,6 @@ export class PasswordField extends Component { this.recommendations = recommendations; } } -PasswordField.displayName = _lt("Password"); -PasswordField.supportedTypes = ["char"]; PasswordField.props = standardFieldProps; PasswordField.components = { Meter }; PasswordField.template = xml` @@ -46,4 +44,10 @@ PasswordField.template = xml` `; -registry.category("fields").add("password_meter", PasswordField); +export const passwordField = { + component: PasswordField, + displayName: _lt("Password"), + supportedTypes: ["char"], +}; + +registry.category("fields").add("password_meter", passwordField); diff --git a/addons/barcodes/static/src/barcode_handler_field.js b/addons/barcodes/static/src/barcode_handler_field.js index 4cf6cfe39a9..494c0ab7bb1 100644 --- a/addons/barcodes/static/src/barcode_handler_field.js +++ b/addons/barcodes/static/src/barcode_handler_field.js @@ -20,4 +20,8 @@ export class BarcodeHandlerField extends Component { BarcodeHandlerField.template = xml``; BarcodeHandlerField.props = { ...standardFieldProps }; -registry.category("fields").add("barcode_handler", BarcodeHandlerField); +export const barcodeHandlerField = { + component: BarcodeHandlerField, +}; + +registry.category("fields").add("barcode_handler", barcodeHandlerField); diff --git a/addons/barcodes/static/src/float_scannable_field.js b/addons/barcodes/static/src/float_scannable_field.js index 1efc750afd6..db46e9c6998 100644 --- a/addons/barcodes/static/src/float_scannable_field.js +++ b/addons/barcodes/static/src/float_scannable_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { FloatField } from "@web/views/fields/float/float_field"; +import { FloatField, floatField } from "@web/views/fields/float/float_field"; export class FloatScannableField extends FloatField { onBarcodeScanned() { @@ -10,4 +10,9 @@ export class FloatScannableField extends FloatField { } FloatScannableField.template = "barcodes.FloatScannableField"; -registry.category("fields").add("field_float_scannable", FloatScannableField); +export const floatScannableField = { + ...floatField, + component: FloatScannableField, +}; + +registry.category("fields").add("field_float_scannable", floatScannableField); diff --git a/addons/base_iban/static/src/components/iban_widget/iban_widget.js b/addons/base_iban/static/src/components/iban_widget/iban_widget.js index 991c237f5ff..d157c122251 100644 --- a/addons/base_iban/static/src/components/iban_widget/iban_widget.js +++ b/addons/base_iban/static/src/components/iban_widget/iban_widget.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; import { useDebounced } from "@web/core/utils/timing"; import { useService } from "@web/core/utils/hooks"; @@ -27,4 +27,9 @@ export class IbanWidget extends CharField { } IbanWidget.template = "base_iban.iban"; -registry.category("fields").add("iban", IbanWidget); +export const ibanWidget = { + ...charField, + component: IbanWidget, +}; + +registry.category("fields").add("iban", ibanWidget); diff --git a/addons/calendar/static/src/views/fields/many2many_attendee.js b/addons/calendar/static/src/views/fields/many2many_attendee.js index f6bb1192e45..7459a970fb1 100644 --- a/addons/calendar/static/src/views/fields/many2many_attendee.js +++ b/addons/calendar/static/src/views/fields/many2many_attendee.js @@ -1,7 +1,10 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2ManyTagsAvatarField } from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field"; +import { + Many2ManyTagsAvatarField, + many2ManyTagsAvatarField, +} from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field"; export class Many2ManyAttendee extends Many2ManyTagsAvatarField { get tags() { @@ -26,10 +29,15 @@ export class Many2ManyAttendee extends Many2ManyTagsAvatarField { return tags; } } -Many2ManyAttendee.additionalClasses = ["o_field_many2many_tags_avatar"]; -Many2ManyAttendee.legacySpecialData = "_fetchSpecialAttendeeStatus"; -registry.category("fields").add("many2manyattendee", Many2ManyAttendee); +export const many2ManyAttendee = { + ...many2ManyTagsAvatarField, + component: Many2ManyAttendee, + additionalClasses: ["o_field_many2many_tags_avatar"], + legacySpecialData: "_fetchSpecialAttendeeStatus", +}; + +registry.category("fields").add("many2manyattendee", many2ManyAttendee); export function preloadMany2ManyAttendee(orm, record, fieldName) { const context = record.getFieldContext(fieldName); diff --git a/addons/delivery_mondialrelay/static/src/components/mondialrelay_field.js b/addons/delivery_mondialrelay/static/src/components/mondialrelay_field.js index fe1cfba1c70..925896daf03 100644 --- a/addons/delivery_mondialrelay/static/src/components/mondialrelay_field.js +++ b/addons/delivery_mondialrelay/static/src/components/mondialrelay_field.js @@ -88,4 +88,8 @@ export class MondialRelayField extends Component { } MondialRelayField.template = xml`
`; -registry.category("fields").add("mondialrelay_relay", MondialRelayField); +export const mondialRelayField = { + component: MondialRelayField, +}; + +registry.category("fields").add("mondialrelay_relay", mondialRelayField); diff --git a/addons/event/static/src/icon_selection_field/icon_selection_field.js b/addons/event/static/src/icon_selection_field/icon_selection_field.js index ebb9daca39d..21c96537f1e 100644 --- a/addons/event/static/src/icon_selection_field/icon_selection_field.js +++ b/addons/event/static/src/icon_selection_field/icon_selection_field.js @@ -20,11 +20,13 @@ IconSelectionField.props = { icons: Object, }; -IconSelectionField.displayName = _lt("Icon Selection"); -IconSelectionField.supportedTypes = ["char", "text", "selection"]; +export const iconSelectionField = { + component: IconSelectionField, + displayName: _lt("Icon Selection"), + supportedTypes: ["char", "text", "selection"], + extractProps: ({ attrs }) => ({ + icons: attrs.options, + }), +}; -IconSelectionField.extractProps = ({ attrs }) => ({ - icons: attrs.options, -}); - -registry.category("fields").add("event_icon_selection", IconSelectionField); +registry.category("fields").add("event_icon_selection", iconSelectionField); diff --git a/addons/hr/static/src/components/background_image/background_image.js b/addons/hr/static/src/components/background_image/background_image.js index e691f9817fe..cc11ecc540a 100644 --- a/addons/hr/static/src/components/background_image/background_image.js +++ b/addons/hr/static/src/components/background_image/background_image.js @@ -2,9 +2,14 @@ import { registry } from '@web/core/registry'; -import { ImageField } from '@web/views/fields/image/image_field'; +import { ImageField, imageField } from '@web/views/fields/image/image_field'; export class BackgroundImageField extends ImageField {} BackgroundImageField.template = 'hr.BackgroundImage'; -registry.category("fields").add("background_image", BackgroundImageField); +export const backgroundImageField = { + ...imageField, + component: BackgroundImageField, +}; + +registry.category("fields").add("background_image", backgroundImageField); diff --git a/addons/hr/static/src/components/work_permit_upload/work_permit_upload.js b/addons/hr/static/src/components/work_permit_upload/work_permit_upload.js index 6176fd1ef1a..0e429c707ac 100644 --- a/addons/hr/static/src/components/work_permit_upload/work_permit_upload.js +++ b/addons/hr/static/src/components/work_permit_upload/work_permit_upload.js @@ -1,9 +1,14 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { BinaryField } from "@web/views/fields/binary/binary_field"; +import { BinaryField, binaryField } from "@web/views/fields/binary/binary_field"; export class WorkPermitUploadField extends BinaryField {} WorkPermitUploadField.template = "hr.WorkPermitUploadField"; -registry.category("fields").add("work_permit_upload", WorkPermitUploadField); +export const workPermitUploadField = { + ...binaryField, + component: WorkPermitUploadField, +}; + +registry.category("fields").add("work_permit_upload", workPermitUploadField); diff --git a/addons/hr/static/src/views/fields/many2many_avatar_employee_field/many2many_avatar_employee_field.js b/addons/hr/static/src/views/fields/many2many_avatar_employee_field/many2many_avatar_employee_field.js index 6e3c519bc08..434f711eead 100644 --- a/addons/hr/static/src/views/fields/many2many_avatar_employee_field/many2many_avatar_employee_field.js +++ b/addons/hr/static/src/views/fields/many2many_avatar_employee_field/many2many_avatar_employee_field.js @@ -1,15 +1,40 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2ManyTagsAvatarUserField, KanbanMany2ManyTagsAvatarUserField } from "@mail/views/fields/many2many_avatar_user_field/many2many_avatar_user_field"; +import { + Many2ManyTagsAvatarUserField, + KanbanMany2ManyTagsAvatarUserField, + many2ManyTagsAvatarUserField, + kanbanMany2ManyTagsAvatarUserField, +} from "@mail/views/fields/many2many_avatar_user_field/many2many_avatar_user_field"; export class Many2ManyTagsAvatarEmployeeField extends Many2ManyTagsAvatarUserField {} -Many2ManyTagsAvatarEmployeeField.additionalClasses = [...Many2ManyTagsAvatarUserField.additionalClasses, "o_field_many2many_avatar_user"]; -registry.category("fields").add("many2many_avatar_employee", Many2ManyTagsAvatarEmployeeField); +export const many2ManyTagsAvatarEmployeeField = { + ...many2ManyTagsAvatarUserField, + component: Many2ManyTagsAvatarEmployeeField, + additionalClasses: [ + ...many2ManyTagsAvatarUserField.additionalClasses, + "o_field_many2many_avatar_user", + ], +}; + +registry.category("fields").add("many2many_avatar_employee", many2ManyTagsAvatarEmployeeField); export class KanbanMany2ManyTagsAvatarEmployeeField extends KanbanMany2ManyTagsAvatarUserField {} -KanbanMany2ManyTagsAvatarEmployeeField.additionalClasses = [...KanbanMany2ManyTagsAvatarUserField.additionalClasses, "o_field_many2many_avatar_user"]; -registry.category("fields").add("kanban.many2many_avatar_employee", KanbanMany2ManyTagsAvatarEmployeeField); -registry.category("fields").add("list.many2many_avatar_employee", KanbanMany2ManyTagsAvatarEmployeeField); +export const kanbanMany2ManyTagsAvatarEmployeeField = { + ...kanbanMany2ManyTagsAvatarUserField, + component: KanbanMany2ManyTagsAvatarEmployeeField, + additionalClasses: [ + ...kanbanMany2ManyTagsAvatarUserField.additionalClasses, + "o_field_many2many_avatar_user", + ], +}; + +registry + .category("fields") + .add("kanban.many2many_avatar_employee", kanbanMany2ManyTagsAvatarEmployeeField); +registry + .category("fields") + .add("list.many2many_avatar_employee", kanbanMany2ManyTagsAvatarEmployeeField); diff --git a/addons/hr/static/src/views/fields/many2one_avatar_employee_field/many2one_avatar_employee_field.js b/addons/hr/static/src/views/fields/many2one_avatar_employee_field/many2one_avatar_employee_field.js index f05024ecbac..53abf16df1b 100644 --- a/addons/hr/static/src/views/fields/many2one_avatar_employee_field/many2one_avatar_employee_field.js +++ b/addons/hr/static/src/views/fields/many2one_avatar_employee_field/many2one_avatar_employee_field.js @@ -1,13 +1,33 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2OneAvatarUserField, KanbanMany2OneAvatarUserField } from "@mail/views/fields/many2one_avatar_user_field/many2one_avatar_user_field"; +import { + Many2OneAvatarUserField, + KanbanMany2OneAvatarUserField, + many2OneAvatarUserField, + kanbanMany2OneAvatarUserField, +} from "@mail/views/fields/many2one_avatar_user_field/many2one_avatar_user_field"; export class Many2OneAvatarEmployeeField extends Many2OneAvatarUserField {} -Many2OneAvatarEmployeeField.additionalClasses = [...Many2OneAvatarUserField.additionalClasses, "o_field_many2one_avatar_user"]; -registry.category("fields").add("many2one_avatar_employee", Many2OneAvatarEmployeeField); +export const many2OneAvatarEmployeeField = { + ...many2OneAvatarUserField, + component: Many2OneAvatarEmployeeField, + additionalClasses: [ + ...many2OneAvatarUserField.additionalClasses, + "o_field_many2one_avatar_user", + ], +}; + +registry.category("fields").add("many2one_avatar_employee", many2OneAvatarEmployeeField); export class KanbanMany2OneAvatarEmployeeField extends KanbanMany2OneAvatarUserField {} -registry.category("fields").add("kanban.many2one_avatar_employee", KanbanMany2OneAvatarEmployeeField); +export const kanbanMany2OneAvatarEmployeeField = { + ...kanbanMany2OneAvatarUserField, + component: KanbanMany2OneAvatarEmployeeField, +}; + +registry + .category("fields") + .add("kanban.many2one_avatar_employee", kanbanMany2OneAvatarEmployeeField); diff --git a/addons/hr_holidays/static/src/radio_image_field/radio_image_field.js b/addons/hr_holidays/static/src/radio_image_field/radio_image_field.js index ea2b4fbea45..c9944fe6275 100644 --- a/addons/hr_holidays/static/src/radio_image_field/radio_image_field.js +++ b/addons/hr_holidays/static/src/radio_image_field/radio_image_field.js @@ -1,12 +1,15 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { RadioField, preloadRadio } from "@web/views/fields/radio/radio_field"; +import { RadioField, preloadRadio, radioField } from "@web/views/fields/radio/radio_field"; class RadioImageField extends RadioField {} RadioImageField.template = "hr_holidays.RadioImageField"; -registry.category("fields").add("hr_holidays_radio_image", RadioImageField); +registry.category("fields").add("hr_holidays_radio_image", { + ...radioField, + component: RadioImageField, +}); registry.category("preloadedData").add("hr_holidays_radio_image", { loadOnTypes: ["many2one"], diff --git a/addons/hr_org_chart/static/src/fields/hr_org_chart.js b/addons/hr_org_chart/static/src/fields/hr_org_chart.js index 1d38e76412a..126c1c105ca 100644 --- a/addons/hr_org_chart/static/src/fields/hr_org_chart.js +++ b/addons/hr_org_chart/static/src/fields/hr_org_chart.js @@ -1,6 +1,5 @@ /** @odoo-module */ -import {Field} from '@web/views/fields/field'; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; import { usePopover } from "@web/core/popover/popover_hook"; @@ -49,7 +48,7 @@ class HrOrgChartPopover extends Component { } HrOrgChartPopover.template = 'hr_org_chart.hr_orgchart_emp_popover'; -export class HrOrgChart extends Field { +export class HrOrgChart extends Component { async setup() { super.setup(); @@ -143,4 +142,8 @@ HrOrgChart.components = { HrOrgChart.template = 'hr_org_chart.hr_org_chart'; -registry.category("fields").add("hr_org_chart", HrOrgChart); +export const hrOrgChart = { + component: HrOrgChart, +}; + +registry.category("fields").add("hr_org_chart", hrOrgChart); diff --git a/addons/hr_recruitment/static/src/applicant_char/applicant_char.js b/addons/hr_recruitment/static/src/applicant_char/applicant_char.js index caae452cc8b..17114b164b5 100644 --- a/addons/hr_recruitment/static/src/applicant_char/applicant_char.js +++ b/addons/hr_recruitment/static/src/applicant_char/applicant_char.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; @@ -27,4 +27,10 @@ export class ApplicantCharField extends CharField { } } ApplicantCharField.template = "hr_recruitment.ApplicantCharField"; -registry.category("fields").add("applicant_char", ApplicantCharField); + +export const applicantCharField = { + ...charField, + component: ApplicantCharField, +}; + +registry.category("fields").add("applicant_char", applicantCharField); diff --git a/addons/hr_skills/static/src/fields/resume_one2many.js b/addons/hr_skills/static/src/fields/resume_one2many.js index b6b627dabc3..040c40c5bc1 100644 --- a/addons/hr_skills/static/src/fields/resume_one2many.js +++ b/addons/hr_skills/static/src/fields/resume_one2many.js @@ -4,7 +4,7 @@ import { registry } from "@web/core/registry"; import { formatDate } from "@web/core/l10n/dates"; -import { SkillsX2ManyField } from "./skills_one2many"; +import { SkillsX2ManyField, skillsX2ManyField } from "./skills_one2many"; import { CommonSkillsListRenderer } from "../views/skills_list_renderer"; export class ResumeListRenderer extends CommonSkillsListRenderer { @@ -36,5 +36,9 @@ ResumeX2ManyField.components = { ListRenderer: ResumeListRenderer, }; -registry.category("fields") - .add("resume_one2many", ResumeX2ManyField); +export const resumeX2ManyField = { + ...skillsX2ManyField, + component: ResumeX2ManyField, +}; + +registry.category("fields").add("resume_one2many", resumeX2ManyField); diff --git a/addons/hr_skills/static/src/fields/skills_one2many.js b/addons/hr_skills/static/src/fields/skills_one2many.js index 9ff69e4d8ec..306be5e6d52 100644 --- a/addons/hr_skills/static/src/fields/skills_one2many.js +++ b/addons/hr_skills/static/src/fields/skills_one2many.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; import { registry } from "@web/core/registry"; import { CommonSkillsListRenderer } from "../views/skills_list_renderer"; @@ -41,4 +41,9 @@ SkillsX2ManyField.components = { ListRenderer: SkillsListRenderer, }; -registry.category("fields").add("skills_one2many", SkillsX2ManyField); +export const skillsX2ManyField = { + ...x2ManyField, + component: SkillsX2ManyField, +}; + +registry.category("fields").add("skills_one2many", skillsX2ManyField); diff --git a/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js b/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js index ba82247cede..9a21997aa9f 100644 --- a/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js +++ b/addons/hr_timesheet/static/src/components/task_with_hours/task_with_hours.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2OneField } from "@web/views/fields/many2one/many2one_field"; +import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field"; class TaskWithHours extends Many2OneField { @@ -48,4 +48,7 @@ class TaskWithHours extends Many2OneField { } -registry.category("fields").add("task_with_hours", TaskWithHours); +registry.category("fields").add("task_with_hours", { + ...many2OneField, + component: TaskWithHours, +}); diff --git a/addons/hr_timesheet/static/src/components/timesheet_uom/timesheet_uom.js b/addons/hr_timesheet/static/src/components/timesheet_uom/timesheet_uom.js index 21c63d2f9ff..87b65e6bbb0 100644 --- a/addons/hr_timesheet/static/src/components/timesheet_uom/timesheet_uom.js +++ b/addons/hr_timesheet/static/src/components/timesheet_uom/timesheet_uom.js @@ -30,7 +30,7 @@ export class TimesheetUOM extends Component { } get timesheetComponent() { - return registry.category("fields").get(this.timesheetWidget, FloatFactorField); + return registry.category("fields").get(this.timesheetWidget, { component: FloatFactorField }).component; } get timesheetComponentProps() { @@ -53,4 +53,8 @@ TimesheetUOM.template = "hr_timesheet.TimesheetUOM"; TimesheetUOM.components = { FloatFactorField, FloatToggleField, FloatTimeField }; -registry.category("fields").add("timesheet_uom", TimesheetUOM); +export const timesheetUOM = { + component: TimesheetUOM, +}; + +registry.category("fields").add("timesheet_uom", timesheetUOM); diff --git a/addons/hr_timesheet/static/src/components/timesheet_uom_no_toggle/timesheet_uom_no_toggle.js b/addons/hr_timesheet/static/src/components/timesheet_uom_no_toggle/timesheet_uom_no_toggle.js index 91f35d701dd..275e391f14a 100644 --- a/addons/hr_timesheet/static/src/components/timesheet_uom_no_toggle/timesheet_uom_no_toggle.js +++ b/addons/hr_timesheet/static/src/components/timesheet_uom_no_toggle/timesheet_uom_no_toggle.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; -import { TimesheetUOM } from "../timesheet_uom/timesheet_uom"; +import { TimesheetUOM, timesheetUOM } from "../timesheet_uom/timesheet_uom"; export class TimesheetUOMNoToggle extends TimesheetUOM { @@ -17,4 +17,9 @@ export class TimesheetUOMNoToggle extends TimesheetUOM { // As FloatToggleField won't be used by TimesheetUOMNoToggle, we remove it from the components that we get from TimesheetUOM. delete TimesheetUOMNoToggle.components.FloatToggleField; -registry.category("fields").add("timesheet_uom_no_toggle", TimesheetUOMNoToggle); +export const timesheetUOMNoToggle = { + ...timesheetUOM, + component: TimesheetUOMNoToggle, +}; + +registry.category("fields").add("timesheet_uom_no_toggle", timesheetUOMNoToggle); diff --git a/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js b/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js index 058cac3f438..9a37c0b3543 100644 --- a/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js +++ b/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js @@ -2,7 +2,10 @@ import { registry } from "@web/core/registry"; -import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; +import { + Many2ManyTagsField, + many2ManyTagsField, +} from "@web/views/fields/many2many_tags/many2many_tags_field"; const fieldRegistry = registry.category("fields"); @@ -22,4 +25,9 @@ export class ChatbotScriptTriggeringAnswersMany2Many extends Many2ManyTagsField } }; -fieldRegistry.add("chatbot_triggering_answers_widget", ChatbotScriptTriggeringAnswersMany2Many); +export const chatbotScriptTriggeringAnswersMany2Many = { + ...many2ManyTagsField, + component: ChatbotScriptTriggeringAnswersMany2Many, +}; + +fieldRegistry.add("chatbot_triggering_answers_widget", chatbotScriptTriggeringAnswersMany2Many); diff --git a/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js b/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js index 0a8e7b9a236..20c57e3a791 100644 --- a/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js +++ b/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js @@ -4,7 +4,7 @@ import { ListRenderer } from "@web/views/list/list_renderer"; import { registry } from "@web/core/registry"; import { patch } from '@web/core/utils/patch'; import { useX2ManyCrud, useOpenX2ManyRecord, X2ManyFieldDialog } from "@web/views/fields/relational_utils"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; const fieldRegistry = registry.category("fields"); @@ -96,7 +96,12 @@ export class ChatbotStepsOne2many extends X2ManyField { } }; -fieldRegistry.add("chatbot_steps_one2many", ChatbotStepsOne2many); +export const chatbotStepsOne2many = { + ...x2ManyField, + component: ChatbotStepsOne2many, +}; + +fieldRegistry.add("chatbot_steps_one2many", chatbotStepsOne2many); ChatbotStepsOne2many.components = { ...X2ManyField.components, diff --git a/addons/loyalty/static/src/js/filterable_selection_field/filterable_selection_field.js b/addons/loyalty/static/src/js/filterable_selection_field/filterable_selection_field.js index c925e5aec8d..b2c9b898f08 100644 --- a/addons/loyalty/static/src/js/filterable_selection_field/filterable_selection_field.js +++ b/addons/loyalty/static/src/js/filterable_selection_field/filterable_selection_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { SelectionField } from "@web/views/fields/selection/selection_field"; +import { SelectionField, selectionField } from "@web/views/fields/selection/selection_field"; /** * The purpose of this field is to be able to define some values which should not be @@ -33,12 +33,14 @@ FilterableSelectionField.props = { blacklisted_values: { type: Array, optional: true }, }; -FilterableSelectionField.extractProps = ({ attrs }) => { - return { - ...SelectionField.extractProps({ attrs }), - whitelisted_values: attrs.options.whitelisted_values, - blacklisted_values: attrs.options.blacklisted_values, - }; +export const filterableSelectionField = { + ...selectionField, + component: FilterableSelectionField, + extractProps: (params) => ({ + ...selectionField.extractProps(params), + whitelisted_values: params.attrs.options.whitelisted_values, + blacklisted_values: params.attrs.options.blacklisted_values, + }), }; -registry.category("fields").add("filterable_selection", FilterableSelectionField); +registry.category("fields").add("filterable_selection", filterableSelectionField); diff --git a/addons/loyalty/static/src/js/loyalty_control_panel_widget.js b/addons/loyalty/static/src/js/loyalty_control_panel_widget.js index caf6b1e60a9..f372baa26c1 100644 --- a/addons/loyalty/static/src/js/loyalty_control_panel_widget.js +++ b/addons/loyalty/static/src/js/loyalty_control_panel_widget.js @@ -1,9 +1,14 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; export class LoyaltyX2ManyField extends X2ManyField {}; LoyaltyX2ManyField.template = "loyalty.LoyaltyX2ManyField"; -registry.category("fields").add("loyalty_one2many", LoyaltyX2ManyField); +export const loyaltyX2ManyField = { + ...x2ManyField, + component: LoyaltyX2ManyField, +}; + +registry.category("fields").add("loyalty_one2many", loyaltyX2ManyField); diff --git a/addons/mail/static/src/backend_components/activity_exception/activity_exception.js b/addons/mail/static/src/backend_components/activity_exception/activity_exception.js index 3778b0e3c8f..71a32b81650 100644 --- a/addons/mail/static/src/backend_components/activity_exception/activity_exception.js +++ b/addons/mail/static/src/backend_components/activity_exception/activity_exception.js @@ -19,10 +19,12 @@ class ActivityException extends Component { Object.assign(ActivityException, { props: standardFieldProps, template: "mail.ActivityException", +}); + +registry.category("fields").add("activity_exception", { + component: ActivityException, fieldDependencies: { activity_exception_icon: { type: "char" }, }, noLabel: true, }); - -registry.category("fields").add("activity_exception", ActivityException); diff --git a/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js b/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js index 1abcdb67139..58cb199de29 100644 --- a/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js +++ b/addons/mail/static/src/backend_components/kanban_field_activity_view/kanban_field_activity_view_container.js @@ -78,6 +78,14 @@ export class KanbanFieldActivityViewContainer extends Component { } Object.assign(KanbanFieldActivityViewContainer, { + props: { + ...standardFieldProps, + }, + template: "mail.KanbanFieldActivityViewContainer", +}); + +export const kanbanFieldActivityViewContainer = { + component: KanbanFieldActivityViewContainer, fieldDependencies: { activity_exception_decoration: { type: "selection" }, activity_exception_icon: { type: "char" }, @@ -86,10 +94,6 @@ Object.assign(KanbanFieldActivityViewContainer, { activity_type_icon: { type: "char" }, activity_type_id: { type: "many2one", relation: "mail.activity.type" }, }, - props: { - ...standardFieldProps, - }, - template: "mail.KanbanFieldActivityViewContainer", -}); +}; -registry.category("fields").add("kanban_activity", KanbanFieldActivityViewContainer); +registry.category("fields").add("kanban_activity", kanbanFieldActivityViewContainer); diff --git a/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js b/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js index 7e60dd9eed4..ad507248c3f 100644 --- a/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js +++ b/addons/mail/static/src/backend_components/list_field_activity_view/list_field_activity_view_container.js @@ -78,6 +78,14 @@ export class ListFieldActivityViewContainer extends Component { } Object.assign(ListFieldActivityViewContainer, { + props: { + ...standardFieldProps, + }, + template: "mail.ListFieldActivityViewContainer", +}); + +export const listFieldActivityViewContainer = { + component: ListFieldActivityViewContainer, fieldDependencies: { activity_exception_decoration: { type: "selection" }, activity_exception_icon: { type: "char" }, @@ -86,10 +94,6 @@ Object.assign(ListFieldActivityViewContainer, { activity_type_icon: { type: "char" }, activity_type_id: { type: "many2one", relation: "mail.activity.type" }, }, - props: { - ...standardFieldProps, - }, - template: "mail.ListFieldActivityViewContainer", -}); +}; -registry.category("fields").add("list_activity", ListFieldActivityViewContainer); +registry.category("fields").add("list_activity", listFieldActivityViewContainer); diff --git a/addons/mail/static/src/js/onchange_on_keydown.js b/addons/mail/static/src/js/onchange_on_keydown.js index a0dc6b94219..ca8229635dc 100644 --- a/addons/mail/static/src/js/onchange_on_keydown.js +++ b/addons/mail/static/src/js/onchange_on_keydown.js @@ -2,8 +2,8 @@ import { patch } from "@web/core/utils/patch"; import { debounce } from "@web/core/utils/timing"; -import { CharField } from "@web/views/fields/char/char_field"; -import { TextField } from '@web/views/fields/text/text_field'; +import { CharField, charField } from "@web/views/fields/char/char_field"; +import { TextField, textField } from "@web/views/fields/text/text_field"; import { archParseBoolean } from "@web/views/utils"; const { useEffect } = owl; @@ -24,7 +24,7 @@ const onchangeOnKeydownMixin = { const triggerOnChange = debounce(this.triggerOnChange, this.props.keydownDebounceDelay); useEffect(() => { if (input.el) { - input.el.addEventListener('keydown', triggerOnChange.bind(this)); + input.el.addEventListener("keydown", triggerOnChange.bind(this)); } }); } @@ -32,12 +32,12 @@ const onchangeOnKeydownMixin = { triggerOnChange() { const input = this.input || this.textareaRef; - input.el.dispatchEvent(new Event('change')); - } + input.el.dispatchEvent(new Event("change")); + }, }; -patch(CharField.prototype, 'char_field_onchange_on_keydown', onchangeOnKeydownMixin); -patch(TextField.prototype, 'text_field_onchange_on_keydown', onchangeOnKeydownMixin); +patch(CharField.prototype, "char_field_onchange_on_keydown", onchangeOnKeydownMixin); +patch(TextField.prototype, "text_field_onchange_on_keydown", onchangeOnKeydownMixin); CharField.props = { ...CharField.props, @@ -51,18 +51,22 @@ TextField.props = { keydownDebounceDelay: { type: Number, optional: true }, }; -const charExtractProps = CharField.extractProps; -CharField.extractProps = ({ attrs, field }) => { - return Object.assign(charExtractProps({ attrs, field }), { +const charExtractProps = charField.extractProps; +charField.extractProps = (attrs) => { + return Object.assign(charExtractProps(attrs), { onchangeOnKeydown: archParseBoolean(attrs.onchange_on_keydown), - keydownDebounceDelay: attrs.keydown_debounce_delay ? Number(attrs.keydown_debounce_delay) : 2000, + keydownDebounceDelay: attrs.keydown_debounce_delay + ? Number(attrs.keydown_debounce_delay) + : 2000, }); }; -const textExtractProps = TextField.extractProps; -TextField.extractProps = ({ attrs, field }) => { - return Object.assign(textExtractProps({ attrs, field }), { - onchangeOnKeydown: archParseBoolean(attrs.onchange_on_keydown), - keydownDebounceDelay: attrs.keydown_debounce_delay ? Number(attrs.keydown_debounce_delay) : 2000, +const textExtractProps = textField.extractProps; +textField.extractProps = (params) => { + return Object.assign(textExtractProps(params), { + onchangeOnKeydown: archParseBoolean(params.attrs.onchange_on_keydown), + keydownDebounceDelay: params.attrs.keydown_debounce_delay + ? Number(params.attrs.keydown_debounce_delay) + : 2000, }); }; diff --git a/addons/mail/static/src/views/activity/activity_arch_parser.js b/addons/mail/static/src/views/activity/activity_arch_parser.js index adbe2ffb418..f5d0b77ed7a 100644 --- a/addons/mail/static/src/views/activity/activity_arch_parser.js +++ b/addons/mail/static/src/views/activity/activity_arch_parser.js @@ -35,7 +35,7 @@ export class ActivityArchParser extends XMLParser { addFieldDependencies( activeFields, models[modelName], - fieldInfo.FieldComponent.fieldDependencies + fieldInfo.field.fieldDependencies ); } diff --git a/addons/mail/static/src/views/fields/emojis_char_field/emojis_char_field.js b/addons/mail/static/src/views/fields/emojis_char_field/emojis_char_field.js index 8b30660d195..c22b7dd7092 100644 --- a/addons/mail/static/src/views/fields/emojis_char_field/emojis_char_field.js +++ b/addons/mail/static/src/views/fields/emojis_char_field/emojis_char_field.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; import { patch } from "@web/core/utils/patch"; import MailEmojisMixin from "@mail/js/emojis_mixin"; import { EmojisFieldCommon } from "@mail/views/fields/emojis_field_common/emojis_field_common"; @@ -23,5 +23,11 @@ patch(EmojisCharField.prototype, "emojis_char_field_mail_mixin", MailEmojisMixin patch(EmojisCharField.prototype, "emojis_char_field_field_mixin", EmojisFieldCommon); EmojisCharField.template = "mail.EmojisCharField"; EmojisCharField.components = { ...CharField.components }; -EmojisCharField.additionalClasses = [...(CharField.additionalClasses || []), "o_field_text"]; -registry.category("fields").add("char_emojis", EmojisCharField); + +export const emojisCharField = { + ...charField, + component: EmojisCharField, + additionalClasses: [...(charField.additionalClasses || []), "o_field_text"], +}; + +registry.category("fields").add("char_emojis", emojisCharField); diff --git a/addons/mail/static/src/views/fields/emojis_text_field/emojis_text_field.js b/addons/mail/static/src/views/fields/emojis_text_field/emojis_text_field.js index c937405dc3d..ab33e106c75 100644 --- a/addons/mail/static/src/views/fields/emojis_text_field/emojis_text_field.js +++ b/addons/mail/static/src/views/fields/emojis_text_field/emojis_text_field.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { TextField } from "@web/views/fields/text/text_field"; +import { TextField, textField } from "@web/views/fields/text/text_field"; import { patch } from "@web/core/utils/patch"; import MailEmojisMixin from "@mail/js/emojis_mixin"; import { EmojisFieldCommon } from "@mail/views/fields/emojis_field_common/emojis_field_common"; @@ -21,5 +21,11 @@ patch(EmojisTextField.prototype, "emojis_char_field_mail_mixin", MailEmojisMixin patch(EmojisTextField.prototype, "emojis_text_field_field_mixin", EmojisFieldCommon); EmojisTextField.template = "mail.EmojisTextField"; EmojisTextField.components = { ...TextField.components }; -EmojisTextField.additionalClasses = [...(TextField.additionalClasses || []), "o_field_text"]; -registry.category("fields").add("text_emojis", EmojisTextField); + +export const emojisTextField = { + ...textField, + component: EmojisTextField, + additionalClasses: [...(textField.additionalClasses || []), "o_field_text"], +}; + +registry.category("fields").add("text_emojis", emojisTextField); diff --git a/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js b/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js index 9a659cb4308..7cd7c52fb1e 100644 --- a/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js +++ b/addons/mail/static/src/views/fields/many2many_avatar_user_field/many2many_avatar_user_field.js @@ -5,6 +5,8 @@ import { TagsList } from "@web/views/fields/many2many_tags/tags_list"; import { Many2ManyTagsAvatarField, ListKanbanMany2ManyTagsAvatarField, + many2ManyTagsAvatarField, + listKanbanMany2ManyTagsAvatarField, } from "@web/views/fields/many2many_tags_avatar/many2many_tags_avatar_field"; import { useOpenChat } from "@mail/views/open_chat_hook"; import { useAssignUserCommand } from "@mail/views/fields/assign_user_command_hook"; @@ -32,9 +34,14 @@ Many2ManyTagsAvatarUserField.components = { ...Many2ManyTagsAvatarField.components, TagsList: Many2ManyAvatarUserTagsList, }; -Many2ManyTagsAvatarUserField.additionalClasses = ["o_field_many2many_tags_avatar"]; -registry.category("fields").add("many2many_avatar_user", Many2ManyTagsAvatarUserField); +export const many2ManyTagsAvatarUserField = { + ...many2ManyTagsAvatarField, + component: Many2ManyTagsAvatarUserField, + additionalClasses: ["o_field_many2many_tags_avatar"], +}; + +registry.category("fields").add("many2many_avatar_user", many2ManyTagsAvatarUserField); export class KanbanMany2ManyTagsAvatarUserField extends ListKanbanMany2ManyTagsAvatarField { setup() { @@ -63,8 +70,15 @@ KanbanMany2ManyTagsAvatarUserField.components = { ...ListKanbanMany2ManyTagsAvatarField.components, TagsList: Many2ManyAvatarUserTagsList, }; -KanbanMany2ManyTagsAvatarUserField.additionalClasses = ["o_field_many2many_tags_avatar"]; -registry.category("fields").add("kanban.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField); -registry.category("fields").add("list.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField); -registry.category("fields").add("activity.many2many_avatar_user", KanbanMany2ManyTagsAvatarUserField); +export const kanbanMany2ManyTagsAvatarUserField = { + ...listKanbanMany2ManyTagsAvatarField, + component: ListKanbanMany2ManyTagsAvatarField, + additionalClasses: ["o_field_many2many_tags_avatar"], +}; + +registry.category("fields").add("kanban.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField); +registry.category("fields").add("list.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField); +registry + .category("fields") + .add("activity.many2many_avatar_user", kanbanMany2ManyTagsAvatarUserField); diff --git a/addons/mail/static/src/views/fields/many2many_tags_email/many2many_tags_email.js b/addons/mail/static/src/views/fields/many2many_tags_email/many2many_tags_email.js index 236ef9b3282..f1d69a5069e 100644 --- a/addons/mail/static/src/views/fields/many2many_tags_email/many2many_tags_email.js +++ b/addons/mail/static/src/views/fields/many2many_tags_email/many2many_tags_email.js @@ -4,7 +4,10 @@ import { registry } from "@web/core/registry"; import { useOpenMany2XRecord } from "@web/views/fields/relational_utils"; import { sprintf } from "@web/core/utils/strings"; -import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; +import { + Many2ManyTagsField, + many2ManyTagsField, +} from "@web/views/fields/many2many_tags/many2many_tags_field"; import { TagsList } from "@web/views/fields/many2many_tags/tags_list"; import { onMounted, onWillUpdateProps } from "@odoo/owl"; @@ -87,10 +90,13 @@ FieldMany2ManyTagsEmail.components = { TagsList: FieldMany2ManyTagsEmailTagsList, }; -FieldMany2ManyTagsEmail.fieldsToFetch = (fieldInfo) => { - return [...Many2ManyTagsField.fieldsToFetch(fieldInfo), { name: "email", type: "char" }]; +export const fieldMany2ManyTagsEmail = { + ...many2ManyTagsField, + component: FieldMany2ManyTagsEmail, + fieldsToFetch: (fieldInfo) => { + return [...many2ManyTagsField.fieldsToFetch(fieldInfo), { name: "email", type: "char" }]; + }, + additionalClasses: ["o_field_many2many_tags"], }; -FieldMany2ManyTagsEmail.additionalClasses = ["o_field_many2many_tags"]; - -registry.category("fields").add("many2many_tags_email", FieldMany2ManyTagsEmail); +registry.category("fields").add("many2many_tags_email", fieldMany2ManyTagsEmail); diff --git a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js index b7abd36d2e0..babdb3bbcc2 100644 --- a/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js +++ b/addons/mail/static/src/views/fields/many2one_avatar_user_field/many2one_avatar_user_field.js @@ -1,7 +1,10 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2OneAvatarField } from "@web/views/fields/many2one_avatar/many2one_avatar_field"; +import { + Many2OneAvatarField, + many2OneAvatarField, +} from "@web/views/fields/many2one_avatar/many2one_avatar_field"; import { useOpenChat } from "@mail/views/open_chat_hook"; import { useAssignUserCommand } from "@mail/views/fields/assign_user_command_hook"; @@ -17,9 +20,14 @@ export class Many2OneAvatarUserField extends Many2OneAvatarField { } } Many2OneAvatarUserField.template = "mail.Many2OneAvatarUserField"; -Many2OneAvatarUserField.additionalClasses = ["o_field_many2one_avatar"]; -registry.category("fields").add("many2one_avatar_user", Many2OneAvatarUserField); +export const many2OneAvatarUserField = { + ...many2OneAvatarField, + component: Many2OneAvatarUserField, + additionalClasses: ["o_field_many2one_avatar"], +}; + +registry.category("fields").add("many2one_avatar_user", many2OneAvatarUserField); export class KanbanMany2OneAvatarUserField extends Many2OneAvatarUserField { /** @@ -37,12 +45,15 @@ KanbanMany2OneAvatarUserField.props = { ...Many2OneAvatarUserField.props, displayAvatarName: { type: Boolean, optional: true }, }; -KanbanMany2OneAvatarUserField.extractProps = ({ attrs, field }) => { - return { - ...Many2OneAvatarUserField.extractProps({ attrs, field }), - displayAvatarName: attrs.options.display_avatar_name || false, - }; + +export const kanbanMany2OneAvatarUserField = { + ...many2OneAvatarUserField, + component: KanbanMany2OneAvatarUserField, + extractProps: (params) => ({ + ...many2OneAvatarUserField.extractProps(params), + displayAvatarName: params.attrs.options.display_avatar_name || false, + }), }; -registry.category("fields").add("kanban.many2one_avatar_user", KanbanMany2OneAvatarUserField); -registry.category("fields").add("activity.many2one_avatar_user", KanbanMany2OneAvatarUserField); +registry.category("fields").add("kanban.many2one_avatar_user", kanbanMany2OneAvatarUserField); +registry.category("fields").add("activity.many2one_avatar_user", kanbanMany2OneAvatarUserField); diff --git a/addons/mass_mailing/static/src/js/mailing_m2o_filter.js b/addons/mass_mailing/static/src/js/mailing_m2o_filter.js index d0893cfca84..9012d3888dc 100644 --- a/addons/mass_mailing/static/src/js/mailing_m2o_filter.js +++ b/addons/mass_mailing/static/src/js/mailing_m2o_filter.js @@ -3,7 +3,7 @@ import { registry } from '@web/core/registry'; import { Dropdown } from "@web/core/dropdown/dropdown"; import { useService } from "@web/core/utils/hooks"; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; import Domain from 'web.Domain'; const { useState, useEffect } = owl; @@ -149,12 +149,15 @@ FieldMany2OneMailingFilter.defaultProps = { domain_field: "mailing_domain", model_field: "mailing_model_id", }; -FieldMany2OneMailingFilter.extractProps = ({ field, attrs }) => { - return { - ...Many2OneField.extractProps({ field, attrs }), - domain_field: attrs.options.domain_field, - model_field: attrs.options.model_field, - } + +export const fieldMany2OneMailingFilter = { + ...many2OneField, + component: FieldMany2OneMailingFilter, + extractProps: (params) => ({ + ...many2OneField.extractProps(params), + domain_field: params.attrs.options.domain_field, + model_field: params.attrs.options.model_field, + }), }; -registry.category('fields').add('mailing_filter', FieldMany2OneMailingFilter); +registry.category("fields").add("mailing_filter", fieldMany2OneMailingFilter); diff --git a/addons/mass_mailing/static/src/js/mass_mailing_html_field.js b/addons/mass_mailing/static/src/js/mass_mailing_html_field.js index 2653bda4ca1..488cb379b96 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_html_field.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_html_field.js @@ -9,7 +9,7 @@ import { loadBundle, loadJS } from "@web/core/assets"; import { qweb } from 'web.core'; import { useService } from "@web/core/utils/hooks"; import { buildQuery } from "web.rpc"; -import { HtmlField } from "@web_editor/js/backend/html_field"; +import { HtmlField, htmlField } from "@web_editor/js/backend/html_field"; import { getWysiwygClass } from 'web_editor.loader'; import { device } from 'web.config'; import { MassMailingMobilePreviewDialog } from "./mass_mailing_mobile_preview"; @@ -584,16 +584,16 @@ MassMailingHtmlField.props = { iframeHtmlClass: { type: String, optional: true }, }; -MassMailingHtmlField.displayName = _lt("Email"); -MassMailingHtmlField.extractProps = (...args) => { - const [{ attrs }] = args; - const htmlProps = HtmlField.extractProps(...args); - return { - ...htmlProps, - filterTemplates: attrs.options.filterTemplates, - inlineField: attrs.options['inline-field'], - iframeHtmlClass: attrs['iframeHtmlClass'], - }; +export const massMailingHtmlField = { + ...htmlField, + component: MassMailingHtmlField, + displayName: _lt("Email"), + extractProps: (params) => ({ + ...htmlField.extractProps(params), + filterTemplates: params.attrs.options.filterTemplates, + inlineField: params.attrs.options['inline-field'], + iframeHtmlClass: params.attrs['iframeHtmlClass'], + }), }; -registry.category("fields").add("mass_mailing_html", MassMailingHtmlField); +registry.category("fields").add("mass_mailing_html", massMailingHtmlField); diff --git a/addons/mrp/static/src/views/fields/google_slides_viewer.js b/addons/mrp/static/src/views/fields/google_slides_viewer.js index a569407d52c..507a57cd5c4 100644 --- a/addons/mrp/static/src/views/fields/google_slides_viewer.js +++ b/addons/mrp/static/src/views/fields/google_slides_viewer.js @@ -3,7 +3,7 @@ import { _lt } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; const { useState } = owl; @@ -48,6 +48,11 @@ export class SlidesViewer extends CharField { } SlidesViewer.template = "mrp.SlidesViewer"; -SlidesViewer.displayName = _lt("Google Slides Viewer"); -registry.category("fields").add("embed_viewer", SlidesViewer); +export const slidesViewer = { + ...charField, + component: SlidesViewer, + displayName: _lt("Google Slides Viewer"), +}; + +registry.category("fields").add("embed_viewer", slidesViewer); diff --git a/addons/mrp/static/src/widgets/mrp_should_consume.js b/addons/mrp/static/src/widgets/mrp_should_consume.js index 12d3148f31b..fea60f4e087 100644 --- a/addons/mrp/static/src/widgets/mrp_should_consume.js +++ b/addons/mrp/static/src/widgets/mrp_should_consume.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { FloatField } from "@web/views/fields/float/float_field"; +import { FloatField, floatField } from "@web/views/fields/float/float_field"; import { registry } from "@web/core/registry"; import { formatFloat } from "@web/views/fields/formatters"; @@ -44,6 +44,11 @@ export class MrpShouldConsumeOwl extends FloatField { } MrpShouldConsumeOwl.template = "mrp.ShouldConsume"; -MrpShouldConsumeOwl.displayName = "MRP Should Consume"; -registry.category("fields").add("mrp_should_consume", MrpShouldConsumeOwl); +export const mrpShouldConsumeOwl = { + ...floatField, + component: MrpShouldConsumeOwl, + displayName: "MRP Should Consume", +}; + +registry.category("fields").add("mrp_should_consume", mrpShouldConsumeOwl); diff --git a/addons/mrp/static/src/widgets/mrp_workorder_popover.js b/addons/mrp/static/src/widgets/mrp_workorder_popover.js index 45be7abc19b..0455bb6d189 100644 --- a/addons/mrp/static/src/widgets/mrp_workorder_popover.js +++ b/addons/mrp/static/src/widgets/mrp_workorder_popover.js @@ -1,7 +1,11 @@ /** @odoo-module */ import { useService } from "@web/core/utils/hooks"; import { registry } from "@web/core/registry"; -import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget'; +import { + PopoverComponent, + PopoverWidgetField, + popoverWidgetField, +} from "@stock/widgets/popover_widget"; /** * Link to a Char field representing a JSON: @@ -36,4 +40,7 @@ WorkOrderPopoverField.components = { Popover: WorkOrderPopover }; -registry.category("fields").add("mrp_workorder_popover", WorkOrderPopoverField); \ No newline at end of file +registry.category("fields").add("mrp_workorder_popover", { + ...popoverWidgetField, + component: WorkOrderPopoverField, +}); \ No newline at end of file diff --git a/addons/mrp/static/src/widgets/timer.js b/addons/mrp/static/src/widgets/timer.js index feaedccb48b..f3d8dedc538 100644 --- a/addons/mrp/static/src/widgets/timer.js +++ b/addons/mrp/static/src/widgets/timer.js @@ -84,7 +84,6 @@ export class MrpTimer extends Component { } } -MrpTimer.supportedTypes = ["float"]; MrpTimer.props = { ...standardFieldProps, duration: { type: Number, optional: true }, @@ -93,5 +92,10 @@ MrpTimer.props = { }; MrpTimer.template = "mrp.MrpTimer"; -registry.category("fields").add("mrp_timer", MrpTimer); +export const mrpTimer = { + component: MrpTimer, + supportedTypes: ["float"], +}; + +registry.category("fields").add("mrp_timer", mrpTimer); registry.category("formatters").add("mrp_timer", formatMinutes); \ No newline at end of file diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js index 1896b7c143c..a8140107080 100644 --- a/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js +++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_fieldchar.js @@ -5,7 +5,7 @@ import { AutoComplete } from "@web/core/autocomplete/autocomplete"; import { useChildRef } from "@web/core/utils/hooks"; import { registry } from "@web/core/registry"; import { _t } from "@web/core/l10n/translation"; -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; import { useInputField } from "@web/views/fields/input_field_hook"; import { loadJS } from "@web/core/assets"; @@ -97,4 +97,9 @@ PartnerAutoCompleteCharField.components = { AutoComplete, }; -registry.category("fields").add("field_partner_autocomplete", PartnerAutoCompleteCharField); +export const partnerAutoCompleteCharField = { + ...charField, + component: PartnerAutoCompleteCharField, +}; + +registry.category("fields").add("field_partner_autocomplete", partnerAutoCompleteCharField); diff --git a/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js b/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js index baadbe738ad..a8daeb68873 100644 --- a/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js +++ b/addons/partner_autocomplete/static/src/js/partner_autocomplete_many2one.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { Many2XAutocomplete } from '@web/views/fields/relational_utils'; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; import { _t } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; @@ -68,4 +68,9 @@ PartnerAutoCompleteMany2one.components = { Many2XAutocomplete: PartnerMany2XAutocomplete, } -registry.category("fields").add("res_partner_many2one", PartnerAutoCompleteMany2one); +export const partnerAutoCompleteMany2one = { + ...many2OneField, + component: PartnerAutoCompleteMany2one, +}; + +registry.category("fields").add("res_partner_many2one", partnerAutoCompleteMany2one); diff --git a/addons/portal/static/src/views/fields/portal_wizard_user_one2many.js b/addons/portal/static/src/views/fields/portal_wizard_user_one2many.js index 5b8773234d3..f491e60a1fe 100644 --- a/addons/portal/static/src/views/fields/portal_wizard_user_one2many.js +++ b/addons/portal/static/src/views/fields/portal_wizard_user_one2many.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { PortalWizardUserListController } from "../list/portal_wizard_user_list_controller"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; import { registry } from "@web/core/registry"; export class PortalUserX2ManyField extends X2ManyField {} @@ -10,4 +10,9 @@ PortalUserX2ManyField.components = { Controller: PortalWizardUserListController, }; -registry.category("fields").add("portal_wizard_user_one2many", PortalUserX2ManyField); +export const portalUserX2ManyField = { + ...x2ManyField, + component: PortalUserX2ManyField, +}; + +registry.category("fields").add("portal_wizard_user_one2many", portalUserX2ManyField); diff --git a/addons/project/static/src/components/project_private_task_many2one_field/project_private_task_many2one_field.js b/addons/project/static/src/components/project_private_task_many2one_field/project_private_task_many2one_field.js index 9dea8a35ca3..5c9487fc839 100644 --- a/addons/project/static/src/components/project_private_task_many2one_field/project_private_task_many2one_field.js +++ b/addons/project/static/src/components/project_private_task_many2one_field/project_private_task_many2one_field.js @@ -1,9 +1,14 @@ /** @odoo-module */ import { registry } from '@web/core/registry'; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; export class ProjectPrivateTaskMany2OneField extends Many2OneField { } ProjectPrivateTaskMany2OneField.template = 'project.ProjectPrivateTaskMany2OneField'; -registry.category('fields').add('project_private_task', ProjectPrivateTaskMany2OneField); +export const projectPrivateTaskMany2OneField = { + ...many2OneField, + component: ProjectPrivateTaskMany2OneField, +}; + +registry.category("fields").add("project_private_task", projectPrivateTaskMany2OneField); diff --git a/addons/project/static/src/components/project_state_selection/project_state_selection.js b/addons/project/static/src/components/project_state_selection/project_state_selection.js index 8ce6f9d1a2f..0be3a7aef74 100644 --- a/addons/project/static/src/components/project_state_selection/project_state_selection.js +++ b/addons/project/static/src/components/project_state_selection/project_state_selection.js @@ -1,7 +1,10 @@ /** @odoo-module */ import { registry } from '@web/core/registry'; -import { StateSelectionField } from '@web/views/fields/state_selection/state_selection_field'; +import { + StateSelectionField, + stateSelectionField, +} from "@web/views/fields/state_selection/state_selection_field"; import { STATUS_COLORS, STATUS_COLOR_PREFIX } from '../../utils/project_utils'; @@ -27,4 +30,9 @@ export class ProjectStateSelectionField extends StateSelectionField { } } -registry.category('fields').add('kanban.project_state_selection', ProjectStateSelectionField); +export const projectStateSelectionField = { + ...stateSelectionField, + component: ProjectStateSelectionField, +}; + +registry.category("fields").add("kanban.project_state_selection", projectStateSelectionField); diff --git a/addons/project/static/src/components/project_status_with_color_selection/project_status_with_color_selection_field.js b/addons/project/static/src/components/project_status_with_color_selection/project_status_with_color_selection_field.js index 7a28e722805..e840c3802fb 100644 --- a/addons/project/static/src/components/project_status_with_color_selection/project_status_with_color_selection_field.js +++ b/addons/project/static/src/components/project_status_with_color_selection/project_status_with_color_selection_field.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { SelectionField } from '@web/views/fields/selection/selection_field'; +import { SelectionField, selectionField } from '@web/views/fields/selection/selection_field'; import { registry } from '@web/core/registry'; import { STATUS_COLORS, STATUS_COLOR_PREFIX } from '../../utils/project_utils'; @@ -22,4 +22,9 @@ export class ProjectStatusWithColorSelectionField extends SelectionField { } ProjectStatusWithColorSelectionField.template = 'project.ProjectStatusWithColorSelectionField'; -registry.category('fields').add('status_with_color', ProjectStatusWithColorSelectionField); +export const projectStatusWithColorSelectionField = { + ...selectionField, + component: ProjectStatusWithColorSelectionField, +}; + +registry.category("fields").add("status_with_color", projectStatusWithColorSelectionField); diff --git a/addons/project/static/src/components/project_task_name_with_subtask_count_char_field/project_task_name_with_subtask_count_char_field.js b/addons/project/static/src/components/project_task_name_with_subtask_count_char_field/project_task_name_with_subtask_count_char_field.js index 5c73a2961bb..0cc014f92c9 100644 --- a/addons/project/static/src/components/project_task_name_with_subtask_count_char_field/project_task_name_with_subtask_count_char_field.js +++ b/addons/project/static/src/components/project_task_name_with_subtask_count_char_field/project_task_name_with_subtask_count_char_field.js @@ -1,7 +1,7 @@ /** @odoo-module */ import { registry } from '@web/core/registry'; -import { CharField } from '@web/views/fields/char/char_field'; +import { CharField, charField } from '@web/views/fields/char/char_field'; import { formatChar } from '@web/views/fields/formatters'; class ProjectTaskNameWithSubtaskCountCharField extends CharField { @@ -12,4 +12,7 @@ class ProjectTaskNameWithSubtaskCountCharField extends CharField { ProjectTaskNameWithSubtaskCountCharField.template = 'project.ProjectTaskNameWithSubtaskCountCharField'; -registry.category('fields').add('name_with_subtask_count', ProjectTaskNameWithSubtaskCountCharField); +registry.category("fields").add("name_with_subtask_count", { + ...charField, + component: ProjectTaskNameWithSubtaskCountCharField, +}); diff --git a/addons/project/static/src/views/fields/project_task_priority_switch_field.js b/addons/project/static/src/views/fields/project_task_priority_switch_field.js index c6c7acaa694..f18494167a5 100644 --- a/addons/project/static/src/views/fields/project_task_priority_switch_field.js +++ b/addons/project/static/src/views/fields/project_task_priority_switch_field.js @@ -2,7 +2,7 @@ import { sprintf } from "@web/core/utils/strings"; import { registry } from "@web/core/registry"; -import { PriorityField } from "@web/views/fields/priority/priority_field"; +import { PriorityField, priorityField } from "@web/views/fields/priority/priority_field"; import { useCommand } from "@web/core/commands/command_hook"; import { useState } from "@odoo/owl"; @@ -29,4 +29,9 @@ export class PrioritySwitchField extends PriorityField { } } -registry.category("fields").add("priority_switch", PrioritySwitchField); +export const prioritySwitchField = { + ...priorityField, + component: PrioritySwitchField, +}; + +registry.category("fields").add("priority_switch", prioritySwitchField); diff --git a/addons/purchase_product_matrix/static/src/js/purchase_product_field.js b/addons/purchase_product_matrix/static/src/js/purchase_product_field.js index bf973084f28..e42daab6869 100644 --- a/addons/purchase_product_matrix/static/src/js/purchase_product_field.js +++ b/addons/purchase_product_matrix/static/src/js/purchase_product_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from '@web/core/registry'; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; import { ProductMatrixDialog } from "@product_matrix/js/product_matrix_dialog"; import { useService } from "@web/core/utils/hooks"; @@ -107,4 +107,9 @@ export class PurchaseOrderLineProductField extends Many2OneField { PurchaseOrderLineProductField.template = "purchase.PurchaseProductField"; -registry.category("fields").add("pol_product_many2one", PurchaseOrderLineProductField); +export const purchaseOrderLineProductField = { + ...many2OneField, + component: PurchaseOrderLineProductField, +}; + +registry.category("fields").add("pol_product_many2one", purchaseOrderLineProductField); diff --git a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js index 4ada4a25f4a..31afa394b5d 100644 --- a/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js +++ b/addons/purchase_requisition/static/src/widgets/purchase_order_alternatives_widget.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; import { ListRenderer } from "@web/views/list/list_renderer"; @@ -43,4 +43,9 @@ FieldMany2ManyAltPOs.components = { ListRenderer: FieldMany2ManyAltPOsRenderer, }; -registry.category("fields").add("many2many_alt_pos", FieldMany2ManyAltPOs); +export const fieldMany2ManyAltPOs = { + ...x2ManyField, + component: FieldMany2ManyAltPOs, +}; + +registry.category("fields").add("many2many_alt_pos", fieldMany2ManyAltPOs); diff --git a/addons/resource/static/src/section_one2many_field.js b/addons/resource/static/src/section_one2many_field.js index 54ab8dd10f1..e4937b0b74b 100644 --- a/addons/resource/static/src/section_one2many_field.js +++ b/addons/resource/static/src/section_one2many_field.js @@ -2,7 +2,7 @@ import { SectionListRenderer } from "./section_list_renderer"; import { registry } from "@web/core/registry"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; class SectionOneToManyField extends X2ManyField {} SectionOneToManyField.components = { @@ -14,4 +14,7 @@ SectionOneToManyField.defaultProps = { editable: "bottom", }; -registry.category("fields").add("section_one2many", SectionOneToManyField); +registry.category("fields").add("section_one2many", { + ...x2ManyField, + component: SectionOneToManyField, +}); diff --git a/addons/sale/static/src/js/product_discount_field.js b/addons/sale/static/src/js/product_discount_field.js index 72761573e5c..75821c68678 100644 --- a/addons/sale/static/src/js/product_discount_field.js +++ b/addons/sale/static/src/js/product_discount_field.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { FloatField } from "@web/views/fields/float/float_field"; +import { FloatField, floatField } from "@web/views/fields/float/float_field"; import { _lt } from "@web/core/l10n/translation"; import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog"; @@ -57,6 +57,11 @@ export function sameValue(orderLines) { ProductDiscountField.components = { ConfirmationDialog }; ProductDiscountField.template = "sale.ProductDiscountField"; -ProductDiscountField.displayName = _lt("Disc.%"); -registry.category("fields").add("sol_discount", ProductDiscountField) +export const productDiscountField = { + ...floatField, + component: ProductDiscountField, + displayName: _lt("Disc.%"), +}; + +registry.category("fields").add("sol_discount", productDiscountField) diff --git a/addons/sale/static/src/js/sale_product_field.js b/addons/sale/static/src/js/sale_product_field.js index 83c29acc0f8..da52c54e2a5 100644 --- a/addons/sale/static/src/js/sale_product_field.js +++ b/addons/sale/static/src/js/sale_product_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from '@web/core/registry'; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; export class SaleOrderLineProductField extends Many2OneField { @@ -109,4 +109,9 @@ export class SaleOrderLineProductField extends Many2OneField { SaleOrderLineProductField.template = "sale.SaleProductField"; -registry.category("fields").add("sol_product_many2one", SaleOrderLineProductField); +export const saleOrderLineProductField = { + ...many2OneField, + component: SaleOrderLineProductField, +}; + +registry.category("fields").add("sol_product_many2one", saleOrderLineProductField); diff --git a/addons/sale/static/src/js/sale_progressbar_field.js b/addons/sale/static/src/js/sale_progressbar_field.js index 49491c3e4c6..03aef776944 100644 --- a/addons/sale/static/src/js/sale_progressbar_field.js +++ b/addons/sale/static/src/js/sale_progressbar_field.js @@ -2,7 +2,10 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { KanbanProgressBarField } from "@web/views/fields/progress_bar/kanban_progress_bar_field"; +import { + KanbanProgressBarField, + kanbanProgressBarField, +} from "@web/views/fields/progress_bar/kanban_progress_bar_field"; const { useEffect } = owl; @@ -42,4 +45,9 @@ export class SaleProgressBarField extends KanbanProgressBarField { */ SaleProgressBarField.template = "sale.SaleProgressBarField"; -registry.category("fields").add("sales_team_progressbar", SaleProgressBarField); +export const saleProgressBarField = { + ...kanbanProgressBarField, + component: SaleProgressBarField, +}; + +registry.category("fields").add("sales_team_progressbar", saleProgressBarField); diff --git a/addons/sale_expense/static/src/js/sale_order_many2one.js b/addons/sale_expense/static/src/js/sale_order_many2one.js index 38e0f99c58c..039bbf3eadf 100644 --- a/addons/sale_expense/static/src/js/sale_order_many2one.js +++ b/addons/sale_expense/static/src/js/sale_order_many2one.js @@ -1,6 +1,6 @@ /** @odoo-module alias=sale_expense.sale_order_many2one **/ -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; +import { Many2OneField, many2OneField } from '@web/views/fields/many2one/many2one_field'; import { registry } from "@web/core/registry"; @@ -21,5 +21,10 @@ export class OrderField extends Many2OneField { } } -registry.category('fields').add('sale_order_many2one', OrderField) +export const orderField = { + ...many2OneField, + component: OrderField, +}; + +registry.category("fields").add("sale_order_many2one", orderField); registry.add('sale_order_many2one', OrderField); diff --git a/addons/sale_timesheet/static/src/components/so_line_field/so_line_field.js b/addons/sale_timesheet/static/src/components/so_line_field/so_line_field.js index 00c4101ad8b..9a3d2ab9599 100644 --- a/addons/sale_timesheet/static/src/components/so_line_field/so_line_field.js +++ b/addons/sale_timesheet/static/src/components/so_line_field/so_line_field.js @@ -1,8 +1,8 @@ /** @odoo-module */ import { registry } from "@web/core/registry"; -import { Many2OneField } from "@web/views/fields/many2one/many2one_field"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { Many2OneField, many2OneField } from "@web/views/fields/many2one/many2one_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; export class SoLineField extends Many2OneField { setup() { @@ -18,8 +18,17 @@ export class SoLineField extends Many2OneField { } } -export class TimesheetsOne2ManyField extends X2ManyField {} -TimesheetsOne2ManyField.additionalClasses = ['o_field_one2many']; -registry.category("fields").add('so_line_one2many', TimesheetsOne2ManyField); // TODO: Remove me when the gantt view is converted in OWL +export const soLineField = { + ...many2OneField, + component: SoLineField, +}; +registry.category("fields").add("so_line_field", soLineField); -registry.category("fields").add("so_line_field", SoLineField); +export class TimesheetsOne2ManyField extends X2ManyField {} +export const timesheetsOne2ManyField = { + ...x2ManyField, + component: TimesheetsOne2ManyField, + additionalClasses: ['o_field_one2many'], +}; + +registry.category("fields").add('so_line_one2many', timesheetsOne2ManyField); // TODO: Remove me when the gantt view is converted in OWL diff --git a/addons/sms/static/src/components/phone_field/phone_field.js b/addons/sms/static/src/components/phone_field/phone_field.js index 6441de17581..a83b41d15b1 100644 --- a/addons/sms/static/src/components/phone_field/phone_field.js +++ b/addons/sms/static/src/components/phone_field/phone_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { patch } from "@web/core/utils/patch"; -import { PhoneField } from "@web/views/fields/phone/phone_field"; +import { PhoneField, phoneField, formPhoneField } from "@web/views/fields/phone/phone_field"; import { SendSMSButton } from '@sms/components/sms_button/sms_button'; patch(PhoneField, "sms.PhoneField", { @@ -17,10 +17,16 @@ patch(PhoneField, "sms.PhoneField", { ...PhoneField.props, enableButton: { type: Boolean, optional: true }, }, - extractProps: ({ attrs }) => { +}); + +const patchDescr = { + extractProps({ attrs }) { return { + ...this._super({ attrs }), enableButton: attrs.options.enable_sms, - placeholder: attrs.placeholder, }; }, -}); +}; + +patch(phoneField, "sms.PhoneField", patchDescr); +patch(formPhoneField, "sms.PhoneField", patchDescr); diff --git a/addons/sms/static/src/components/sms_button/sms_button.js b/addons/sms/static/src/components/sms_button/sms_button.js index 884976b8456..b9337a88295 100644 --- a/addons/sms/static/src/components/sms_button/sms_button.js +++ b/addons/sms/static/src/components/sms_button/sms_button.js @@ -34,3 +34,4 @@ export class SendSMSButton extends Component { } }; SendSMSButton.template = "sms.SendSMSButton"; +SendSMSButton.props = ["*"]; diff --git a/addons/sms/static/src/components/sms_widget/fields_sms_widget.js b/addons/sms/static/src/components/sms_widget/fields_sms_widget.js index 6481dbff149..5ecf85bd8e1 100644 --- a/addons/sms/static/src/components/sms_widget/fields_sms_widget.js +++ b/addons/sms/static/src/components/sms_widget/fields_sms_widget.js @@ -1,6 +1,9 @@ /** @odoo-module **/ -import { EmojisTextField} from '@mail/views/fields/emojis_text_field/emojis_text_field'; +import { + EmojisTextField, + emojisTextField, +} from "@mail/views/fields/emojis_text_field/emojis_text_field"; import { useService } from "@web/core/utils/hooks"; import { registry } from "@web/core/registry"; @@ -94,5 +97,15 @@ export class SmsWidget extends EmojisTextField { } } SmsWidget.template = 'sms.SmsWidget'; -SmsWidget.additionalClasses = [...(EmojisTextField.additionalClasses || []), 'o_field_text', 'o_field_text_emojis']; -registry.category("fields").add("sms_widget", SmsWidget); + +export const smsWidget = { + ...emojisTextField, + component: SmsWidget, + additionalClasses: [ + ...(emojisTextField.additionalClasses || []), + "o_field_text", + "o_field_text_emojis", + ], +}; + +registry.category("fields").add("sms_widget", smsWidget); diff --git a/addons/stock/static/src/views/picking_form/stock_move_one2many.js b/addons/stock/static/src/views/picking_form/stock_move_one2many.js index 1c4ca1b6a45..ba80a2e4b5d 100644 --- a/addons/stock/static/src/views/picking_form/stock_move_one2many.js +++ b/addons/stock/static/src/views/picking_form/stock_move_one2many.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; import { ListRenderer } from "@web/views/list/list_renderer"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; import { ViewButton } from "@web/views/view_button/view_button"; class MoveViewButton extends ViewButton { @@ -30,4 +30,9 @@ MovesListRenderer.components = { ...ListRenderer.components, ViewButton: MoveVie export class StockMoveX2ManyField extends X2ManyField {} StockMoveX2ManyField.components = { ...X2ManyField.components, ListRenderer: MovesListRenderer }; -registry.category("fields").add("stock_move_one2many", StockMoveX2ManyField); +export const stockMoveX2ManyField = { + ...x2ManyField, + component: StockMoveX2ManyField, +}; + +registry.category("fields").add("stock_move_one2many", stockMoveX2ManyField); diff --git a/addons/stock/static/src/widgets/counted_quantity_widget.js b/addons/stock/static/src/widgets/counted_quantity_widget.js index 2bd47ecaedd..a25421ca9a4 100644 --- a/addons/stock/static/src/widgets/counted_quantity_widget.js +++ b/addons/stock/static/src/widgets/counted_quantity_widget.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { FloatField } from "@web/views/fields/float/float_field"; +import { FloatField, floatField } from "@web/views/fields/float/float_field"; import { registry } from "@web/core/registry"; const { useEffect, useRef } = owl; @@ -41,4 +41,9 @@ export class CountedQuantityWidgetField extends FloatField { } } -registry.category("fields").add("counted_quantity_widget", CountedQuantityWidgetField); +export const countedQuantityWidgetField = { + ...floatField, + component: CountedQuantityWidgetField, +}; + +registry.category("fields").add("counted_quantity_widget", countedQuantityWidgetField); diff --git a/addons/stock/static/src/widgets/forecast_widget.js b/addons/stock/static/src/widgets/forecast_widget.js index 8477adb5612..379b8417856 100644 --- a/addons/stock/static/src/widgets/forecast_widget.js +++ b/addons/stock/static/src/widgets/forecast_widget.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { FloatField } from "@web/views/fields/float/float_field"; +import { FloatField, floatField } from "@web/views/fields/float/float_field"; import { formatDate } from "@web/core/l10n/dates"; import { formatFloat } from "@web/views/fields/formatters"; import { registry } from "@web/core/registry"; @@ -49,4 +49,9 @@ export class ForecastWidgetField extends FloatField { } ForecastWidgetField.template = "stock.ForecastWidget"; -registry.category("fields").add("forecast_widget", ForecastWidgetField); +export const forecastWidgetField = { + ...floatField, + component: ForecastWidgetField, +}; + +registry.category("fields").add("forecast_widget", forecastWidgetField); diff --git a/addons/stock/static/src/widgets/json_widget.js b/addons/stock/static/src/widgets/json_widget.js index 2fde6c285f4..d34ab220c08 100644 --- a/addons/stock/static/src/widgets/json_widget.js +++ b/addons/stock/static/src/widgets/json_widget.js @@ -16,8 +16,11 @@ export class JsonPopOver extends Component { } } -JsonPopOver.displayName = _lt("Json Popup"); -JsonPopOver.supportedTypes = ["char"]; +export const jsonPopOver = { + component: JsonPopOver, + displayName: _lt("Json Popup"), + supportedTypes: ["char"], +}; export class PopOverLeadDays extends JsonPopOver { setup() { @@ -50,8 +53,18 @@ export class PopOverLeadDays extends JsonPopOver { PopOverLeadDays.template = "stock.leadDays"; +export const popOverLeadDays = { + ...jsonPopOver, + component: PopOverLeadDays, +}; +registry.category("fields").add("lead_days_widget", popOverLeadDays); + export class ReplenishmentHistoryWidget extends JsonPopOver {} ReplenishmentHistoryWidget.template = "stock.replenishmentHistory"; -registry.category("fields").add("lead_days_widget", PopOverLeadDays); -registry.category("fields").add("replenishment_history_widget", ReplenishmentHistoryWidget); +export const replenishmentHistoryWidget = { + ...jsonPopOver, + component: ReplenishmentHistoryWidget, +}; + +registry.category("fields").add("replenishment_history_widget", replenishmentHistoryWidget); diff --git a/addons/stock/static/src/widgets/popover_widget.js b/addons/stock/static/src/widgets/popover_widget.js index c097c207f00..3ab687f6623 100644 --- a/addons/stock/static/src/widgets/popover_widget.js +++ b/addons/stock/static/src/widgets/popover_widget.js @@ -46,7 +46,12 @@ export class PopoverWidgetField extends Component { } } -PopoverWidgetField.supportedTypes = ['char']; PopoverWidgetField.template = 'stock.popoverButton'; PopoverWidgetField.components = { Popover: PopoverComponent } -registry.category("fields").add("popover_widget", PopoverWidgetField); + +export const popoverWidgetField = { + component: PopoverWidgetField, + supportedTypes: ['char'], +}; + +registry.category("fields").add("popover_widget", popoverWidgetField); diff --git a/addons/stock/static/src/widgets/stock_rescheduling_popover.js b/addons/stock/static/src/widgets/stock_rescheduling_popover.js index 9b2e221a75f..ccecdcb2b76 100644 --- a/addons/stock/static/src/widgets/stock_rescheduling_popover.js +++ b/addons/stock/static/src/widgets/stock_rescheduling_popover.js @@ -1,7 +1,11 @@ /** @odoo-module */ import { useService } from "@web/core/utils/hooks"; import { registry } from "@web/core/registry"; -import { PopoverComponent, PopoverWidgetField } from '@stock/widgets/popover_widget'; +import { + PopoverComponent, + PopoverWidgetField, + popoverWidgetField, +} from "@stock/widgets/popover_widget"; class StockRescheculingPopoverComponent extends PopoverComponent { setup(){ @@ -37,4 +41,7 @@ StockRescheculingPopover.components = { Popover: StockRescheculingPopoverComponent } -registry.category("fields").add("stock_rescheduling_popover", StockRescheculingPopover); +registry.category("fields").add("stock_rescheduling_popover", { + ...popoverWidgetField, + component: StockRescheculingPopover, +}); diff --git a/addons/survey/static/src/question_page/description_page_field.js b/addons/survey/static/src/question_page/description_page_field.js index d3cd74d1609..4efe161386e 100644 --- a/addons/survey/static/src/question_page/description_page_field.js +++ b/addons/survey/static/src/question_page/description_page_field.js @@ -1,6 +1,6 @@ /** @odoo-module */ -import { CharField } from "@web/views/fields/char/char_field"; +import { CharField, charField } from "@web/views/fields/char/char_field"; import { registry } from "@web/core/registry"; const { useEffect, useRef } = owl; @@ -24,4 +24,7 @@ class DescriptionPageField extends CharField { } DescriptionPageField.template = "survey.DescriptionPageField"; -registry.category("fields").add("survey_description_page", DescriptionPageField); +registry.category("fields").add("survey_description_page", { + ...charField, + component: DescriptionPageField, +}); diff --git a/addons/survey/static/src/question_page/question_page_one2many_field.js b/addons/survey/static/src/question_page/question_page_one2many_field.js index 22a96f0ce3c..bfc910abd0e 100644 --- a/addons/survey/static/src/question_page/question_page_one2many_field.js +++ b/addons/survey/static/src/question_page/question_page_one2many_field.js @@ -5,7 +5,7 @@ import { registry } from "@web/core/registry"; import { useOpenX2ManyRecord, useX2ManyCrud, X2ManyFieldDialog } from "@web/views/fields/relational_utils"; import { patch } from '@web/core/utils/patch'; import { useService } from "@web/core/utils/hooks"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; const { useSubEnv } = owl; @@ -127,4 +127,9 @@ QuestionPageOneToManyField.defaultProps = { editable: "bottom", }; -registry.category("fields").add("question_page_one2many", QuestionPageOneToManyField); +export const questionPageOneToManyField = { + ...x2ManyField, + component: QuestionPageOneToManyField, +}; + +registry.category("fields").add("question_page_one2many", questionPageOneToManyField); diff --git a/addons/web/static/src/core/debug/profiling/profiling_qweb.js b/addons/web/static/src/core/debug/profiling/profiling_qweb.js index 08e6ffb272e..b3cac1eff66 100644 --- a/addons/web/static/src/core/debug/profiling/profiling_qweb.js +++ b/addons/web/static/src/core/debug/profiling/profiling_qweb.js @@ -8,14 +8,18 @@ import { useDebounced } from "@web/core/utils/timing"; import { Component, useState, useRef, onWillStart, onMounted, onWillUnmount } from "@odoo/owl"; -class MenuItem extends Component {} -MenuItem.template = "web.ProfilingQwebView.menuitem"; +class MenuItem extends Component { + static template = "web.ProfilingQwebView.menuitem"; +} /** * This widget is intended to be used on Text fields. It will provide Ace Editor * for display XML and Python profiling. */ export class ProfilingQwebView extends Component { + static template = "web.ProfilingQwebView"; + static components = { MenuItem }; + setup() { super.setup(); @@ -36,11 +40,11 @@ export class ProfilingQwebView extends Component { onWillStart(async () => { await loadBundle({ jsLibs: [ - '/web/static/lib/ace/ace.js', + "/web/static/lib/ace/ace.js", [ - '/web/static/lib/ace/mode-python.js', - '/web/static/lib/ace/mode-xml.js', - '/web/static/lib/ace/mode-qweb.js' + "/web/static/lib/ace/mode-python.js", + "/web/static/lib/ace/mode-xml.js", + "/web/static/lib/ace/mode-qweb.js", ], ], }); @@ -81,7 +85,7 @@ export class ProfilingQwebView extends Component { * @private * @returns {Promise} */ - async _fetchViewData () { + async _fetchViewData() { const viewIDs = Array.from(new Set(this.profile.data.map((line) => line.view_id))); const viewObjects = await this.orm.call("ir.ui.view", "search_read", [], { fields: ["id", "display_name", "key"], @@ -111,7 +115,7 @@ export class ProfilingQwebView extends Component { * @param {number} delay * @returns {string} */ - _formatDelay (delay) { + _formatDelay(delay) { return delay ? _.str.sprintf("%.1f", Math.ceil(delay * 10) / 10) : "."; } @@ -122,7 +126,7 @@ export class ProfilingQwebView extends Component { * @private * @param {Node} node - the DOM element the ace library must initialize on */ - _startAce (node) { + _startAce(node) { this.aceEditor = window.ace.edit(node); this.aceEditor.setOptions({ maxLines: Infinity, @@ -150,20 +154,22 @@ export class ProfilingQwebView extends Component { this.aceEditor.renderer.on("afterRender", this.renderProfilingInformation.bind(this)); } - renderProfilingInformation () { + renderProfilingInformation() { this._unmoutInfo(); - let flat = {}; - let arch = [{ xpath: "", children: [] }]; + const flat = {}; + const arch = [{ xpath: "", children: [] }]; const rows = this.ace.el.querySelectorAll(".ace_gutter .ace_gutter-cell"); - const elems = this.ace.el.querySelectorAll(".ace_tag-open, .ace_end-tag-close, .ace_end-tag-open, .ace_qweb"); - elems.forEach(node => { + const elems = this.ace.el.querySelectorAll( + ".ace_tag-open, .ace_end-tag-close, .ace_end-tag-open, .ace_qweb" + ); + elems.forEach((node) => { const parent = arch[arch.length - 1]; let xpath = parent.xpath; if (node.classList.contains("ace_end-tag-close")) { // Close tag. let previous = node; - while (previous = previous.previousElementSibling) { + while ((previous = previous.previousElementSibling)) { if (previous && previous.classList.contains("ace_tag-name")) { break; } @@ -220,7 +226,12 @@ export class ProfilingQwebView extends Component { i++; } xpath += "[" + i + "]"; - flat[xpath] = { xpath: xpath, tag: nodeTagName.textContent, children: [], directive: [] }; + flat[xpath] = { + xpath: xpath, + tag: nodeTagName.textContent, + children: [], + directive: [], + }; arch.push(flat[xpath]); parent.children.push(flat[xpath]); @@ -278,32 +289,32 @@ export class ProfilingQwebView extends Component { } _unmoutInfo() { if (this.hover) { - if (this.ace.el.querySelector('.o_ace_hover')) { - this.ace.el.querySelector('.o_ace_hover').remove(); + if (this.ace.el.querySelector(".o_ace_hover")) { + this.ace.el.querySelector(".o_ace_hover").remove(); } } if (this.info) { - if (this.ace.el.querySelector('.o_ace_info')) { - this.ace.el.querySelector('.o_ace_info').remove(); + if (this.ace.el.querySelector(".o_ace_info")) { + this.ace.el.querySelector(".o_ace_info").remove(); } } } _renderHover(delay, query, node) { - const xml = renderToString('web.ProfilingQwebView.hover', { + const xml = renderToString("web.ProfilingQwebView.hover", { delay: this._formatDelay(delay), query: query, }); - const div = new DOMParser().parseFromString(xml, "text/html").querySelector('div'); + const div = new DOMParser().parseFromString(xml, "text/html").querySelector("div"); node.insertBefore(div, node.firstChild); } _renderInfo(delays, querys, displayDetail, groups, node) { - const xml = renderToString('web.ProfilingQwebView.info', { + const xml = renderToString("web.ProfilingQwebView.info", { delay: this._formatDelay(delays.reduce((a, b) => a + b, 0)), query: querys.reduce((a, b) => a + b, 0) || ".", displayDetail: displayDetail, groups: groups, }); - const div = new DOMParser().parseFromString(xml, "text/html").querySelector('div'); + const div = new DOMParser().parseFromString(xml, "text/html").querySelector("div"); node.insertBefore(div, node.firstChild); } @@ -315,12 +326,14 @@ export class ProfilingQwebView extends Component { * @private * @param {MouseEvent} ev */ - _onSelectView (ev) { + _onSelectView(ev) { this.state.viewID = +ev.currentTarget.dataset.id; this._renderView(); } } -ProfilingQwebView.template = "web.ProfilingQwebView"; -ProfilingQwebView.components = { MenuItem }; -registry.category("fields").add("profiling_qweb_view", ProfilingQwebView); +export const profilingQwebView = { + component: ProfilingQwebView, +}; + +registry.category("fields").add("profiling_qweb_view", profilingQwebView); diff --git a/addons/web/static/src/views/basic_relational_model.js b/addons/web/static/src/views/basic_relational_model.js index 39b03347616..ba4c4ddafce 100644 --- a/addons/web/static/src/views/basic_relational_model.js +++ b/addons/web/static/src/views/basic_relational_model.js @@ -232,8 +232,7 @@ export class Record extends DataPoint { } } - const isSet = - activeField && activeField.FieldComponent && activeField.FieldComponent.isSet; + const isSet = activeField && activeField.field && activeField.field.isSet; if (this.isRequired(fieldName) && isSet && !isSet(this.data[fieldName])) { this.setInvalidField(fieldName); diff --git a/addons/web/static/src/views/fields/ace/ace_field.js b/addons/web/static/src/views/fields/ace/ace_field.js index 9b3afdd5544..7fa48f2f36b 100644 --- a/addons/web/static/src/views/fields/ace/ace_field.js +++ b/addons/web/static/src/views/fields/ace/ace_field.js @@ -11,6 +11,15 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, onWillStart, onWillUpdateProps, useEffect, useRef } from "@odoo/owl"; export class AceField extends Component { + static template = "web.AceField"; + static props = { + ...standardFieldProps, + mode: { type: String, optional: true }, + }; + static defaultProps = { + mode: "qweb", + }; + setup() { this.aceEditor = null; this.editorRef = useRef("editor"); @@ -110,22 +119,13 @@ export class AceField extends Component { } } -AceField.template = "web.AceField"; -AceField.props = { - ...standardFieldProps, - mode: { type: String, optional: true }, -}; -AceField.defaultProps = { - mode: "qweb", -}; - -AceField.displayName = _lt("Ace Editor"); -AceField.supportedTypes = ["text"]; - -AceField.extractProps = ({ attrs }) => { - return { +export const aceField = { + component: AceField, + displayName: _lt("Ace Editor"), + supportedTypes: ["text"], + extractProps: ({ attrs }) => ({ mode: attrs.options.mode, - }; + }), }; -registry.category("fields").add("ace", AceField); +registry.category("fields").add("ace", aceField); diff --git a/addons/web/static/src/views/fields/attachment_image/attachment_image_field.js b/addons/web/static/src/views/fields/attachment_image/attachment_image_field.js index 644b2f337e3..048912d58c4 100644 --- a/addons/web/static/src/views/fields/attachment_image/attachment_image_field.js +++ b/addons/web/static/src/views/fields/attachment_image/attachment_image_field.js @@ -5,11 +5,14 @@ import { registry } from "@web/core/registry"; import { Component } from "@odoo/owl"; -export class AttachmentImageField extends Component {} +export class AttachmentImageField extends Component { + static template = "web.AttachmentImageField"; +} -AttachmentImageField.template = "web.AttachmentImageField"; +export const attachmentImageField = { + component: AttachmentImageField, + displayName: _lt("Attachment Image"), + supportedTypes: ["many2one"], +}; -AttachmentImageField.displayName = _lt("Attachment Image"); -AttachmentImageField.supportedTypes = ["many2one"]; - -registry.category("fields").add("attachment_image", AttachmentImageField); +registry.category("fields").add("attachment_image", attachmentImageField); diff --git a/addons/web/static/src/views/fields/badge/badge_field.js b/addons/web/static/src/views/fields/badge/badge_field.js index 1f890cfdc64..4c569bdd3ec 100644 --- a/addons/web/static/src/views/fields/badge/badge_field.js +++ b/addons/web/static/src/views/fields/badge/badge_field.js @@ -8,6 +8,11 @@ import { Component } from "@odoo/owl"; const formatters = registry.category("formatters"); export class BadgeField extends Component { + static template = "web.BadgeField"; + static props = { + ...standardFieldProps, + }; + get formattedValue() { const formatter = formatters.get(this.props.type); return formatter(this.props.value, { @@ -25,12 +30,10 @@ export class BadgeField extends Component { } } -BadgeField.template = "web.BadgeField"; -BadgeField.props = { - ...standardFieldProps, +export const badgeField = { + component: BadgeField, + displayName: _lt("Badge"), + supportedTypes: ["selection", "many2one", "char"], }; -BadgeField.displayName = _lt("Badge"); -BadgeField.supportedTypes = ["selection", "many2one", "char"]; - -registry.category("fields").add("badge", BadgeField); +registry.category("fields").add("badge", badgeField); diff --git a/addons/web/static/src/views/fields/badge_selection/badge_selection_field.js b/addons/web/static/src/views/fields/badge_selection/badge_selection_field.js index 95c6ae0a7c8..7c52a932658 100644 --- a/addons/web/static/src/views/fields/badge_selection/badge_selection_field.js +++ b/addons/web/static/src/views/fields/badge_selection/badge_selection_field.js @@ -7,6 +7,11 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class BadgeSelectionField extends Component { + static template = "web.BadgeSelectionField"; + static props = { + ...standardFieldProps, + }; + get options() { switch (this.props.record.fields[this.props.name].type) { case "many2one": @@ -61,18 +66,15 @@ export class BadgeSelectionField extends Component { } } -BadgeSelectionField.template = "web.BadgeSelectionField"; -BadgeSelectionField.props = { - ...standardFieldProps, +export const badgeSelectionField = { + component: BadgeSelectionField, + displayName: _lt("Badges"), + supportedTypes: ["many2one", "selection"], + isEmpty: (record, fieldName) => record.data[fieldName] === false, + legacySpecialData: "_fetchSpecialMany2ones", }; -BadgeSelectionField.displayName = _lt("Badges"); -BadgeSelectionField.supportedTypes = ["many2one", "selection"]; -BadgeSelectionField.legacySpecialData = "_fetchSpecialMany2ones"; - -BadgeSelectionField.isEmpty = (record, fieldName) => record.data[fieldName] === false; - -registry.category("fields").add("selection_badge", BadgeSelectionField); +registry.category("fields").add("selection_badge", badgeSelectionField); export function preloadSelection(orm, record, fieldName) { const field = record.fields[fieldName]; diff --git a/addons/web/static/src/views/fields/binary/binary_field.js b/addons/web/static/src/views/fields/binary/binary_field.js index fb52d34180f..0eaccda2c0c 100644 --- a/addons/web/static/src/views/fields/binary/binary_field.js +++ b/addons/web/static/src/views/fields/binary/binary_field.js @@ -10,6 +10,19 @@ import { _lt } from "@web/core/l10n/translation"; import { Component, onWillUpdateProps, useState } from "@odoo/owl"; export class BinaryField extends Component { + static template = "web.BinaryField"; + static components = { + FileUploader, + }; + static props = { + ...standardFieldProps, + acceptedFileExtensions: { type: String, optional: true }, + fileNameField: { type: String, optional: true }, + }; + static defaultProps = { + acceptedFileExtensions: "*", + }; + setup() { this.notification = useService("notification"); this.state = useState({ @@ -52,27 +65,14 @@ export class BinaryField extends Component { } } -BinaryField.template = "web.BinaryField"; -BinaryField.components = { - FileUploader, -}; -BinaryField.props = { - ...standardFieldProps, - acceptedFileExtensions: { type: String, optional: true }, - fileNameField: { type: String, optional: true }, -}; -BinaryField.defaultProps = { - acceptedFileExtensions: "*", -}; - -BinaryField.displayName = _lt("File"); -BinaryField.supportedTypes = ["binary"]; - -BinaryField.extractProps = ({ attrs }) => { - return { +export const binaryField = { + component: BinaryField, + displayName: _lt("File"), + supportedTypes: ["binary"], + extractProps: ({ attrs }) => ({ acceptedFileExtensions: attrs.options.accepted_file_extensions, fileNameField: attrs.filename, - }; + }), }; -registry.category("fields").add("binary", BinaryField); +registry.category("fields").add("binary", binaryField); diff --git a/addons/web/static/src/views/fields/boolean/boolean_field.js b/addons/web/static/src/views/fields/boolean/boolean_field.js index c63ff84edda..c2eb677138e 100644 --- a/addons/web/static/src/views/fields/boolean/boolean_field.js +++ b/addons/web/static/src/views/fields/boolean/boolean_field.js @@ -8,6 +8,12 @@ import { CheckBox } from "@web/core/checkbox/checkbox"; import { Component } from "@odoo/owl"; export class BooleanField extends Component { + static template = "web.BooleanField"; + static components = { CheckBox }; + static props = { + ...standardFieldProps, + }; + get isReadonly() { return !(this.props.record.isInEdition && !this.props.record.isReadonly(this.props.name)); } @@ -20,15 +26,11 @@ export class BooleanField extends Component { } } -BooleanField.template = "web.BooleanField"; -BooleanField.components = { CheckBox }; -BooleanField.props = { - ...standardFieldProps, +export const booleanField = { + component: BooleanField, + displayName: _lt("Checkbox"), + supportedTypes: ["boolean"], + isEmpty: () => false, }; -BooleanField.displayName = _lt("Checkbox"); -BooleanField.supportedTypes = ["boolean"]; - -BooleanField.isEmpty = () => false; - -registry.category("fields").add("boolean", BooleanField); +registry.category("fields").add("boolean", booleanField); diff --git a/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js b/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js index 395b6e0bcc0..f969361e061 100644 --- a/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js +++ b/addons/web/static/src/views/fields/boolean_favorite/boolean_favorite_field.js @@ -7,25 +7,25 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; -export class BooleanFavoriteField extends Component {} - -BooleanFavoriteField.template = "web.BooleanFavoriteField"; -BooleanFavoriteField.props = { - ...standardFieldProps, - noLabel: { type: Boolean, optional: true }, -}; -BooleanFavoriteField.defaultProps = { - noLabel: false, -}; - -BooleanFavoriteField.displayName = _lt("Favorite"); -BooleanFavoriteField.supportedTypes = ["boolean"]; - -BooleanFavoriteField.isEmpty = () => false; -BooleanFavoriteField.extractProps = ({ attrs }) => { - return { - noLabel: archParseBoolean(attrs.nolabel), +export class BooleanFavoriteField extends Component { + static template = "web.BooleanFavoriteField"; + static props = { + ...standardFieldProps, + noLabel: { type: Boolean, optional: true }, }; + static defaultProps = { + noLabel: false, + }; +} + +export const booleanFavoriteField = { + component: BooleanFavoriteField, + displayName: _lt("Favorite"), + supportedTypes: ["boolean"], + isEmpty: () => false, + extractProps: ({ attrs }) => ({ + noLabel: archParseBoolean(attrs.nolabel), + }), }; -registry.category("fields").add("boolean_favorite", BooleanFavoriteField); +registry.category("fields").add("boolean_favorite", booleanFavoriteField); diff --git a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js index d3614fed95b..8385e6f2e25 100644 --- a/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js +++ b/addons/web/static/src/views/fields/boolean_icon/boolean_icon_field.js @@ -6,24 +6,27 @@ import { _lt } from "@web/core/l10n/translation"; import { standardFieldProps } from "../standard_field_props"; export class BooleanIconField extends Component { - static defaultProps = { - icon: "fa-check-square-o", - }; - static extractProps = ({ attrs }) => { - return { - icon: attrs.options.icon, - }; - }; static template = "web.BooleanIconField"; static props = { ...standardFieldProps, icon: { type: String, optional: true }, }; - static displayName = _lt("Boolean Icon"); - static supportedTypes = ["boolean"]; + static defaultProps = { + icon: "fa-check-square-o", + }; + get label() { return this.props.record.activeFields[this.props.name].string; } } -registry.category("fields").add("boolean_icon", BooleanIconField); +export const booleanIconField = { + component: BooleanIconField, + displayName: _lt("Boolean Icon"), + supportedTypes: ["boolean"], + extractProps: ({ attrs }) => ({ + icon: attrs.options.icon, + }), +}; + +registry.category("fields").add("boolean_icon", booleanIconField); diff --git a/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js b/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js index 0230876c2c9..d50a4057b96 100644 --- a/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js +++ b/addons/web/static/src/views/fields/boolean_toggle/boolean_toggle_field.js @@ -2,16 +2,20 @@ import { registry } from "@web/core/registry"; import { _lt } from "@web/core/l10n/translation"; -import { BooleanField } from "../boolean/boolean_field"; +import { booleanField, BooleanField } from "../boolean/boolean_field"; export class BooleanToggleField extends BooleanField { + static template = "web.BooleanToggleField"; + get isReadonly() { return this.props.record.isReadonly(this.props.name); } } -BooleanToggleField.template = "web.BooleanToggleField"; +export const booleanToggleField = { + ...booleanField, + component: BooleanToggleField, + displayName: _lt("Toggle"), +}; -BooleanToggleField.displayName = _lt("Toggle"); - -registry.category("fields").add("boolean_toggle", BooleanToggleField); +registry.category("fields").add("boolean_toggle", booleanToggleField); diff --git a/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js b/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js index 8fa48458ff5..fab772db4f5 100644 --- a/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js +++ b/addons/web/static/src/views/fields/boolean_toggle/list_boolean_toggle_field.js @@ -1,9 +1,11 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { BooleanToggleField } from "./boolean_toggle_field"; +import { booleanToggleField, BooleanToggleField } from "./boolean_toggle_field"; export class ListBooleanToggleField extends BooleanToggleField { + static template = "web.ListBooleanToggleField"; + onClick() { if (!this.props.readonly) { this.props.update(!this.props.value); @@ -11,6 +13,9 @@ export class ListBooleanToggleField extends BooleanToggleField { } } -ListBooleanToggleField.template = "web.ListBooleanToggleField"; +export const listBooleanToggleField = { + ...booleanToggleField, + component: ListBooleanToggleField, +}; -registry.category("fields").add("list.boolean_toggle", ListBooleanToggleField); +registry.category("fields").add("list.boolean_toggle", listBooleanToggleField); diff --git a/addons/web/static/src/views/fields/char/char_field.js b/addons/web/static/src/views/fields/char/char_field.js index 472858e8668..3daa54a1966 100644 --- a/addons/web/static/src/views/fields/char/char_field.js +++ b/addons/web/static/src/views/fields/char/char_field.js @@ -12,6 +12,22 @@ import { useDynamicPlaceholder } from "../dynamicplaceholder_hook"; import { Component, onMounted, onWillUnmount, useRef } from "@odoo/owl"; export class CharField extends Component { + static template = "web.CharField"; + static components = { + TranslationButton, + }; + static props = { + ...standardFieldProps, + autocomplete: { type: String, optional: true }, + isPassword: { type: Boolean, optional: true }, + placeholder: { type: String, optional: true }, + dynamicPlaceholder: { type: Boolean, optional: true }, + shouldTrim: { type: Boolean, optional: true }, + maxLength: { type: Number, optional: true }, + isTranslatable: { type: Boolean, optional: true }, + }; + static defaultProps = { dynamicPlaceholder: false }; + setup() { if (this.props.dynamicPlaceholder) { this.dynamicPlaceholder = useDynamicPlaceholder(); @@ -26,34 +42,33 @@ export class CharField extends Component { if (ev.key === this.dynamicPlaceholder.TRIGGER_KEY && ev.target === this.input.el) { const baseModel = this.props.record.data.mailing_model_real; if (baseModel) { - await this.dynamicPlaceholder.open( - this.input.el, - baseModel, - { - validateCallback: this.onDynamicPlaceholderValidate.bind(this), - closeCallback: this.onDynamicPlaceholderClose.bind(this) - } - ); + await this.dynamicPlaceholder.open(this.input.el, baseModel, { + validateCallback: this.onDynamicPlaceholderValidate.bind(this), + closeCallback: this.onDynamicPlaceholderClose.bind(this), + }); } } } onMounted() { if (this.props.dynamicPlaceholder) { this.keydownListenerCallback = this.onKeydownListener.bind(this); - document.addEventListener('keydown', this.keydownListenerCallback); + document.addEventListener("keydown", this.keydownListenerCallback); } } onWillUnmount() { if (this.props.dynamicPlaceholder) { - document.removeEventListener('keydown', this.keydownListenerCallback); + document.removeEventListener("keydown", this.keydownListenerCallback); } } onDynamicPlaceholderValidate(chain, defaultValue) { if (chain) { const triggerKeyReplaceRegex = new RegExp(`${this.dynamicPlaceholder.TRIGGER_KEY}$`); - let dynamicPlaceholder = "{{object." + chain.join('.'); - dynamicPlaceholder += defaultValue && defaultValue !== '' ? ` or '''${defaultValue}'''}}` : '}}'; - this.props.update(this.input.el.value.replace(triggerKeyReplaceRegex, '') + dynamicPlaceholder); + let dynamicPlaceholder = "{{object." + chain.join("."); + dynamicPlaceholder += + defaultValue && defaultValue !== "" ? ` or '''${defaultValue}'''}}` : "}}"; + this.props.update( + this.input.el.value.replace(triggerKeyReplaceRegex, "") + dynamicPlaceholder + ); } } onDynamicPlaceholderClose() { @@ -72,35 +87,20 @@ export class CharField extends Component { } } -CharField.template = "web.CharField"; -CharField.components = { - TranslationButton, -}; -CharField.defaultProps = { dynamicPlaceholder: false }; -CharField.props = { - ...standardFieldProps, - autocomplete: { type: String, optional: true }, - isPassword: { type: Boolean, optional: true }, - placeholder: { type: String, optional: true }, - dynamicPlaceholder: { type: Boolean, optional: true}, - shouldTrim: { type: Boolean, optional: true }, - maxLength: { type: Number, optional: true }, - isTranslatable: { type: Boolean, optional: true }, -}; +export const charField = { + component: CharField, + displayName: _lt("Text"), + supportedTypes: ["char"], + extractProps: ({ attrs, field }) => ({ + isPassword: archParseBoolean(attrs.password), + dynamicPlaceholder: attrs.options.dynamic_placeholder, + autocomplete: attrs.autocomplete, + placeholder: attrs.placeholder, -CharField.displayName = _lt("Text"); -CharField.supportedTypes = ["char"]; - -CharField.extractProps = ({ attrs, field }) => { - return { shouldTrim: field.trim && !archParseBoolean(attrs.password), // passwords shouldn't be trimmed maxLength: field.size, isTranslatable: field.translate, - dynamicPlaceholder: attrs.options.dynamic_placeholder, - autocomplete: attrs.autocomplete, - isPassword: archParseBoolean(attrs.password), - placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("char", CharField); +registry.category("fields").add("char", charField); diff --git a/addons/web/static/src/views/fields/color/color_field.js b/addons/web/static/src/views/fields/color/color_field.js index afd51f6de1e..57c68c42818 100644 --- a/addons/web/static/src/views/fields/color/color_field.js +++ b/addons/web/static/src/views/fields/color/color_field.js @@ -6,13 +6,18 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, useState, onWillUpdateProps } from "@odoo/owl"; export class ColorField extends Component { + static template = "web.ColorField"; + static props = { + ...standardFieldProps, + }; + setup() { this.state = useState({ - color: this.props.value || '', + color: this.props.value || "", }); onWillUpdateProps((nextProps) => { - this.state.color = nextProps.value || ''; + this.state.color = nextProps.value || ""; }); } @@ -21,11 +26,9 @@ export class ColorField extends Component { } } -ColorField.template = "web.ColorField"; -ColorField.props = { - ...standardFieldProps, +export const colorField = { + component: ColorField, + supportedTypes: ["char"], }; -ColorField.supportedTypes = ["char"]; - -registry.category("fields").add("color", ColorField); +registry.category("fields").add("color", colorField); diff --git a/addons/web/static/src/views/fields/color_picker/color_picker_field.js b/addons/web/static/src/views/fields/color_picker/color_picker_field.js index 853d2b0bf3c..d2b523f77b7 100644 --- a/addons/web/static/src/views/fields/color_picker/color_picker_field.js +++ b/addons/web/static/src/views/fields/color_picker/color_picker_field.js @@ -7,6 +7,16 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class ColorPickerField extends Component { + static template = "web.ColorPickerField"; + static components = { + ColorList, + }; + static props = { + ...standardFieldProps, + }; + + static RECORD_COLORS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + get canToggle() { return this.props.record.activeFields[this.props.name].viewType !== "list"; } @@ -20,15 +30,9 @@ export class ColorPickerField extends Component { } } -ColorPickerField.template = "web.ColorPickerField"; -ColorPickerField.components = { - ColorList, -}; -ColorPickerField.props = { - ...standardFieldProps, +export const colorPickerField = { + component: ColorPickerField, + supportedTypes: ["integer"], }; -ColorPickerField.supportedTypes = ["integer"]; -ColorPickerField.RECORD_COLORS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - -registry.category("fields").add("color_picker", ColorPickerField); +registry.category("fields").add("color_picker", colorPickerField); diff --git a/addons/web/static/src/views/fields/copy_clipboard/copy_button.js b/addons/web/static/src/views/fields/copy_clipboard/copy_button.js index 7318da43fb2..a93ad6479c3 100644 --- a/addons/web/static/src/views/fields/copy_clipboard/copy_button.js +++ b/addons/web/static/src/views/fields/copy_clipboard/copy_button.js @@ -6,6 +6,15 @@ import { useService } from "@web/core/utils/hooks"; import { Component, useRef } from "@odoo/owl"; export class CopyButton extends Component { + static template = "web.CopyButton"; + static props = { + className: { type: String, optional: true }, + copyText: { type: String, optional: true }, + disabled: { type: Boolean, optional: true }, + successText: { type: String, optional: true }, + content: { type: [String, Object], optional: true }, + }; + setup() { this.button = useRef("button"); this.popover = useService("popover"); @@ -40,11 +49,3 @@ export class CopyButton extends Component { this.showTooltip(); } } -CopyButton.template = "web.CopyButton"; -CopyButton.props = { - className: { type: String, optional: true }, - copyText: { type: String, optional: true }, - disabled: { type: Boolean, optional: true }, - successText: { type: String, optional: true }, - content: { type: [String, Object], optional: true }, -}; diff --git a/addons/web/static/src/views/fields/copy_clipboard/copy_clipboard_field.js b/addons/web/static/src/views/fields/copy_clipboard/copy_clipboard_field.js index c2f77211a0e..1b885e43a9d 100644 --- a/addons/web/static/src/views/fields/copy_clipboard/copy_clipboard_field.js +++ b/addons/web/static/src/views/fields/copy_clipboard/copy_clipboard_field.js @@ -15,10 +15,18 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; class CopyClipboardField extends Component { + static template = "web.CopyClipboardField"; + static props = { + ...standardFieldProps, + string: { type: String, optional: true }, + disabledExpr: { type: String, optional: true }, + }; + setup() { this.copyText = this.props.string || this.env._t("Copy"); this.successText = this.env._t("Copied"); } + get copyButtonClassName() { return `o_btn_${this.props.type}_copy btn-sm`; } @@ -34,47 +42,68 @@ class CopyClipboardField extends Component { return Boolean(evaluated); } } -CopyClipboardField.template = "web.CopyClipboardField"; -CopyClipboardField.props = { - ...standardFieldProps, - string: { type: String, optional: true }, - disabledExpr: { type: String, optional: true }, -}; -CopyClipboardField.extractProps = ({ attrs }) => { - return { - string: attrs.string, - disabledExpr: attrs.disabled, - }; -}; export class CopyClipboardButtonField extends CopyClipboardField { + static template = "web.CopyClipboardButtonField"; + static components = { CopyButton }; + get copyButtonClassName() { return `o_btn_${this.props.type}_copy rounded-2`; } } -CopyClipboardButtonField.template = "web.CopyClipboardButtonField"; -CopyClipboardButtonField.components = { CopyButton }; -CopyClipboardButtonField.displayName = _lt("Copy to Clipboard"); -registry.category("fields").add("CopyClipboardButton", CopyClipboardButtonField); +export class CopyClipboardCharField extends CopyClipboardField { + static components = { Field: CharField, CopyButton }; +} -export class CopyClipboardCharField extends CopyClipboardField {} -CopyClipboardCharField.components = { Field: CharField, CopyButton }; -CopyClipboardCharField.displayName = _lt("Copy Text to Clipboard"); -CopyClipboardCharField.supportedTypes = ["char"]; +export class CopyClipboardTextField extends CopyClipboardField { + static components = { Field: TextField, CopyButton }; +} -registry.category("fields").add("CopyClipboardChar", CopyClipboardCharField); +export class CopyClipboardURLField extends CopyClipboardField { + static components = { Field: UrlField, CopyButton }; +} -export class CopyClipboardTextField extends CopyClipboardField {} -CopyClipboardTextField.components = { Field: TextField, CopyButton }; -CopyClipboardTextField.displayName = _lt("Copy Multiline Text to Clipboard"); -CopyClipboardTextField.supportedTypes = ["text"]; +// ---------------------------------------------------------------------------- -registry.category("fields").add("CopyClipboardText", CopyClipboardTextField); +function extractProps({ attrs }) { + return { + string: attrs.string, + disabledExpr: attrs.disabled, + }; +} -export class CopyClipboardURLField extends CopyClipboardField {} -CopyClipboardURLField.components = { Field: UrlField, CopyButton }; -CopyClipboardURLField.displayName = _lt("Copy URL to Clipboard"); -CopyClipboardURLField.supportedTypes = ["char"]; +export const copyClipboardButtonField = { + component: CopyClipboardButtonField, + displayName: _lt("Copy to Clipboard"), + extractProps, +}; -registry.category("fields").add("CopyClipboardURL", CopyClipboardURLField); +registry.category("fields").add("CopyClipboardButton", copyClipboardButtonField); + +export const copyClipboardCharField = { + component: CopyClipboardCharField, + displayName: _lt("Copy Text to Clipboard"), + supportedTypes: ["char"], + extractProps, +}; + +registry.category("fields").add("CopyClipboardChar", copyClipboardCharField); + +export const copyClipboardTextField = { + component: CopyClipboardTextField, + displayName: _lt("Copy Multiline Text to Clipboard"), + supportedTypes: ["text"], + extractProps, +}; + +registry.category("fields").add("CopyClipboardText", copyClipboardTextField); + +export const copyClipboardURLField = { + component: CopyClipboardURLField, + displayName: _lt("Copy URL to Clipboard"), + supportedTypes: ["char"], + extractProps, +}; + +registry.category("fields").add("CopyClipboardURL", copyClipboardURLField); diff --git a/addons/web/static/src/views/fields/date/date_field.js b/addons/web/static/src/views/fields/date/date_field.js index 61957696dd4..fc1ed6d6f07 100644 --- a/addons/web/static/src/views/fields/date/date_field.js +++ b/addons/web/static/src/views/fields/date/date_field.js @@ -10,6 +10,19 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class DateField extends Component { + static template = "web.DateField"; + static components = { + DatePicker, + }; + static props = { + ...standardFieldProps, + pickerOptions: { type: Object, optional: true }, + placeholder: { type: String, optional: true }, + }; + static defaultProps = { + pickerOptions: {}, + }; + setup() { /** * The last value that has been commited to the model. @@ -17,6 +30,7 @@ export class DateField extends Component { */ this.lastSetValue = null; } + get isDateTime() { return this.props.record.fields[this.props.name].type === "datetime"; } @@ -44,27 +58,14 @@ export class DateField extends Component { } } -DateField.template = "web.DateField"; -DateField.components = { - DatePicker, -}; -DateField.props = { - ...standardFieldProps, - pickerOptions: { type: Object, optional: true }, - placeholder: { type: String, optional: true }, -}; -DateField.defaultProps = { - pickerOptions: {}, -}; - -DateField.displayName = _lt("Date"); -DateField.supportedTypes = ["date", "datetime"]; - -DateField.extractProps = ({ attrs }) => { - return { +export const dateField = { + component: DateField, + displayName: _lt("Date"), + supportedTypes: ["date", "datetime"], + extractProps: ({ attrs }) => ({ pickerOptions: attrs.options.datepicker, placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("date", DateField); +registry.category("fields").add("date", dateField); diff --git a/addons/web/static/src/views/fields/daterange/daterange_field.js b/addons/web/static/src/views/fields/daterange/daterange_field.js index 95cbd47c75d..09494c25a1e 100644 --- a/addons/web/static/src/views/fields/daterange/daterange_field.js +++ b/addons/web/static/src/views/fields/daterange/daterange_field.js @@ -11,6 +11,15 @@ const formatters = registry.category("formatters"); const parsers = registry.category("parsers"); export class DateRangeField extends Component { + static template = "web.DateRangeField"; + static props = { + ...standardFieldProps, + relatedEndDateField: { type: String, optional: true }, + relatedStartDateField: { type: String, optional: true }, + formatType: { type: String, optional: true }, + placeholder: { type: String, optional: true }, + }; + setup() { this.notification = useService("notification"); this.root = useRef("root"); @@ -138,24 +147,17 @@ export class DateRangeField extends Component { this.isPickerShown = false; } } -DateRangeField.template = "web.DateRangeField"; -DateRangeField.props = { - ...standardFieldProps, - relatedEndDateField: { type: String, optional: true }, - relatedStartDateField: { type: String, optional: true }, - formatType: { type: String, optional: true }, - placeholder: { type: String, optional: true }, -}; -DateRangeField.supportedTypes = ["date", "datetime"]; - -DateRangeField.extractProps = ({ attrs, field }) => { - return { +export const dateRangeField = { + component: DateRangeField, + supportedTypes: ["date", "datetime"], + extractProps: ({ attrs, field }) => ({ relatedEndDateField: attrs.options.related_end_date, relatedStartDateField: attrs.options.related_start_date, - formatType: attrs.options.format_type || field.type, placeholder: attrs.placeholder, - }; + + formatType: attrs.options.format_type || field.type, + }), }; -registry.category("fields").add("daterange", DateRangeField); +registry.category("fields").add("daterange", dateRangeField); diff --git a/addons/web/static/src/views/fields/datetime/datetime_field.js b/addons/web/static/src/views/fields/datetime/datetime_field.js index 9eaa36ba482..bbf1cce4e0a 100644 --- a/addons/web/static/src/views/fields/datetime/datetime_field.js +++ b/addons/web/static/src/views/fields/datetime/datetime_field.js @@ -9,6 +9,19 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class DateTimeField extends Component { + static template = "web.DateTimeField"; + static components = { + DateTimePicker, + }; + static props = { + ...standardFieldProps, + pickerOptions: { type: Object, optional: true }, + placeholder: { type: String, optional: true }, + }; + static defaultProps = { + pickerOptions: {}, + }; + setup() { /** * The last value that has been commited to the model. @@ -16,6 +29,7 @@ export class DateTimeField extends Component { */ this.lastSetValue = null; } + get formattedValue() { return formatDateTime(this.props.value); } @@ -34,27 +48,14 @@ export class DateTimeField extends Component { } } -DateTimeField.template = "web.DateTimeField"; -DateTimeField.components = { - DateTimePicker, -}; -DateTimeField.props = { - ...standardFieldProps, - pickerOptions: { type: Object, optional: true }, - placeholder: { type: String, optional: true }, -}; -DateTimeField.defaultProps = { - pickerOptions: {}, -}; - -DateTimeField.displayName = _lt("Date & Time"); -DateTimeField.supportedTypes = ["datetime"]; - -DateTimeField.extractProps = ({ attrs }) => { - return { +export const dateTimeField = { + component: DateTimeField, + displayName: _lt("Date & Time"), + supportedTypes: ["datetime"], + extractProps: ({ attrs }) => ({ pickerOptions: attrs.options.datepicker, placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("datetime", DateTimeField); +registry.category("fields").add("datetime", dateTimeField); diff --git a/addons/web/static/src/views/fields/domain/domain_field.js b/addons/web/static/src/views/fields/domain/domain_field.js index 3a5e7fd67aa..bd53da421d8 100644 --- a/addons/web/static/src/views/fields/domain/domain_field.js +++ b/addons/web/static/src/views/fields/domain/domain_field.js @@ -12,6 +12,19 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, onWillStart, onWillUpdateProps, useState } from "@odoo/owl"; export class DomainField extends Component { + static template = "web.DomainField"; + static components = { + DomainSelector, + }; + static props = { + ...standardFieldProps, + editInDialog: { type: Boolean, optional: true }, + resModel: { type: String, optional: true }, + }; + static defaultProps = { + editInDialog: false, + }; + setup() { this.orm = useService("orm"); this.state = useState({ @@ -126,28 +139,15 @@ export class DomainField extends Component { } } -DomainField.template = "web.DomainField"; -DomainField.components = { - DomainSelector, -}; -DomainField.props = { - ...standardFieldProps, - editInDialog: { type: Boolean, optional: true }, - resModel: { type: String, optional: true }, -}; -DomainField.defaultProps = { - editInDialog: false, -}; - -DomainField.displayName = _lt("Domain"); -DomainField.supportedTypes = ["char"]; - -DomainField.isEmpty = () => false; -DomainField.extractProps = ({ attrs }) => { - return { +export const domainField = { + component: DomainField, + displayName: _lt("Domain"), + supportedTypes: ["char"], + isEmpty: () => false, + extractProps: ({ attrs }) => ({ editInDialog: attrs.options.in_dialog, resModel: attrs.options.model, - }; + }), }; -registry.category("fields").add("domain", DomainField); +registry.category("fields").add("domain", domainField); diff --git a/addons/web/static/src/views/fields/email/email_field.js b/addons/web/static/src/views/fields/email/email_field.js index 96fd83282a2..630650e1b42 100644 --- a/addons/web/static/src/views/fields/email/email_field.js +++ b/addons/web/static/src/views/fields/email/email_field.js @@ -8,27 +8,35 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class EmailField extends Component { + static template = "web.EmailField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + }; + setup() { useInputField({ getValue: () => this.props.value || "" }); } } -EmailField.template = "web.EmailField"; -EmailField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, -}; -EmailField.extractProps = ({ attrs }) => { - return { +export const emailField = { + component: EmailField, + displayName: _lt("Email"), + supportedTypes: ["char"], + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder, - }; + }), }; -EmailField.displayName = _lt("Email"); -EmailField.supportedTypes = ["char"]; +registry.category("fields").add("email", emailField); -class FormEmailField extends EmailField {} -FormEmailField.template = "web.FormEmailField"; +class FormEmailField extends EmailField { + static template = "web.FormEmailField"; +} -registry.category("fields").add("email", EmailField); -registry.category("fields").add("form.email", FormEmailField); +export const formEmailField = { + ...emailField, + component: FormEmailField, +}; + +registry.category("fields").add("form.email", formEmailField); diff --git a/addons/web/static/src/views/fields/field.js b/addons/web/static/src/views/fields/field.js index 3d51d513319..235d89866b7 100644 --- a/addons/web/static/src/views/fields/field.js +++ b/addons/web/static/src/views/fields/field.js @@ -50,17 +50,17 @@ function getFieldClassFromRegistry(fieldType, widget, viewType, jsClass) { return fieldRegistry.get(fieldType); } - return DefaultField; + return { component: DefaultField }; } -export function fieldVisualFeedback(FieldComponent, record, fieldName, fieldInfo) { +export function fieldVisualFeedback(field, record, fieldName, fieldInfo) { const modifiers = fieldInfo.modifiers || {}; const readonly = evalDomain(modifiers.readonly, record.evalContext); const inEdit = record.isInEdition; let empty = !record.isVirtual; - if ("isEmpty" in FieldComponent) { - empty = empty && FieldComponent.isEmpty(record, fieldName); + if ("isEmpty" in field) { + empty = empty && field.isEmpty(record, fieldName); } else { empty = empty && !record.data[fieldName]; } @@ -75,17 +75,17 @@ export function fieldVisualFeedback(FieldComponent, record, fieldName, fieldInfo export class Field extends Component { setup() { - this.FieldComponent = this.props.fieldInfo.FieldComponent; - if (!this.FieldComponent) { + this.field = this.props.fieldInfo.field; + if (!this.field) { const fieldType = this.props.record.fields[this.props.name].type; - this.FieldComponent = getFieldClassFromRegistry(fieldType, this.props.type); + this.field = getFieldClassFromRegistry(fieldType, this.props.type); } } get classNames() { const { class: _class, fieldInfo, name, record } = this.props; const { readonly, required, invalid, empty } = fieldVisualFeedback( - this.FieldComponent, + this.field, record, name, fieldInfo @@ -99,8 +99,8 @@ export class Field extends Component { [`o_field_${this.type}`]: true, [_class]: Boolean(_class), }; - if (this.FieldComponent.additionalClasses) { - for (const cls of this.FieldComponent.additionalClasses) { + if (this.field.additionalClasses) { + for (const cls of this.field.additionalClasses) { classNames[cls] = true; } } @@ -139,10 +139,10 @@ export class Field extends Component { decorationMap[decoName] = value; } - let propsFromAttrs = fieldInfo.propsFromAttrs; + let propsFromAttrs = fieldInfo.propsFromAttrs || {}; if (this.props.attrs) { - const extractProps = this.FieldComponent.extractProps || (() => ({})); - propsFromAttrs = extractProps({ + const extractProps = this.field.extractProps || (() => ({})); + propsFromAttrs = extractProps.call(this.field, { field, attrs: { ...this.props.attrs, @@ -202,18 +202,18 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) { const name = node.getAttribute("name"); const widget = node.getAttribute("widget"); const fields = models[modelName]; - const field = fields[name]; const modifiers = JSON.parse(node.getAttribute("modifiers") || "{}"); + const field = getFieldClassFromRegistry(fields[name].type, widget, viewType, jsClass); const fieldInfo = { name, viewType, context: node.getAttribute("context") || "{}", - string: node.getAttribute("string") || field.string, + string: node.getAttribute("string") || fields[name].string, help: node.getAttribute("help"), widget, modifiers, onChange: archParseBoolean(node.getAttribute("on_change")), - FieldComponent: getFieldClassFromRegistry(fields[name].type, widget, viewType, jsClass), + field, forceSave: archParseBoolean(node.getAttribute("force_save")), decorations: {}, // populated below noLabel: archParseBoolean(node.getAttribute("nolabel")), @@ -244,26 +244,26 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) { if (viewType !== "kanban") { // FIXME WOWL: find a better solution - const extractProps = fieldInfo.FieldComponent.extractProps || (() => ({})); - fieldInfo.propsFromAttrs = extractProps({ - field, + const extractProps = field.extractProps || (() => ({})); + fieldInfo.propsFromAttrs = extractProps.call(field, { + field: fields[name], attrs: { ...fieldInfo.rawAttrs, options: fieldInfo.options }, }); } - if (X2M_TYPES.includes(field.type)) { + if (X2M_TYPES.includes(fields[name].type)) { const views = {}; for (const child of node.children) { const viewType = child.tagName === "tree" ? "list" : child.tagName; const { ArchParser } = viewRegistry.get(viewType); const xmlSerializer = new XMLSerializer(); const subArch = xmlSerializer.serializeToString(child); - const archInfo = new ArchParser().parse(subArch, models, field.relation); + const archInfo = new ArchParser().parse(subArch, models, fields[name].relation); views[viewType] = { ...archInfo, - fields: models[field.relation], + fields: models[fields[name].relation], }; - fieldInfo.relatedFields = models[field.relation]; + fieldInfo.relatedFields = models[fields[name].relation]; } let viewMode = node.getAttribute("mode"); @@ -279,10 +279,10 @@ Field.parseFieldNode = function (node, models, modelName, viewType, jsClass) { viewMode = viewMode.replace("tree", "list"); } fieldInfo.viewMode = viewMode; - fieldInfo.relation = field.relation; // not really necessary + fieldInfo.relation = fields[name].relation; // not really necessary fieldInfo.views = views; - let fieldsToFetch = fieldInfo.FieldComponent.fieldsToFetch; + let fieldsToFetch = field.fieldsToFetch; if (fieldsToFetch) { if (fieldsToFetch instanceof Function) { fieldsToFetch = fieldsToFetch(fieldInfo); diff --git a/addons/web/static/src/views/fields/field.xml b/addons/web/static/src/views/fields/field.xml index 40812cd7268..824b75d33d3 100644 --- a/addons/web/static/src/views/fields/field.xml +++ b/addons/web/static/src/views/fields/field.xml @@ -3,7 +3,7 @@
- +
diff --git a/addons/web/static/src/views/fields/field_tooltip.js b/addons/web/static/src/views/fields/field_tooltip.js index 5648cf542d0..9b92b79dec4 100644 --- a/addons/web/static/src/views/fields/field_tooltip.js +++ b/addons/web/static/src/views/fields/field_tooltip.js @@ -3,7 +3,7 @@ export function getTooltipInfo(params) { let widgetDescription = undefined; if (params.fieldInfo.widget) { - widgetDescription = params.fieldInfo.FieldComponent.displayName; + widgetDescription = params.fieldInfo.field.displayName; } const info = { diff --git a/addons/web/static/src/views/fields/float/float_field.js b/addons/web/static/src/views/fields/float/float_field.js index ade8dd2daf0..5e6066a9296 100644 --- a/addons/web/static/src/views/fields/float/float_field.js +++ b/addons/web/static/src/views/fields/float/float_field.js @@ -11,6 +11,18 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class FloatField extends Component { + static template = "web.FloatField"; + static props = { + ...standardFieldProps, + inputType: { type: String, optional: true }, + step: { type: Number, optional: true }, + digits: { type: Array, optional: true }, + placeholder: { type: String, optional: true }, + }; + static defaultProps = { + inputType: "text", + }; + setup() { this.inputRef = useInputField({ getValue: () => this.formattedValue, @@ -32,39 +44,30 @@ export class FloatField extends Component { } } -FloatField.template = "web.FloatField"; -FloatField.props = { - ...standardFieldProps, - inputType: { type: String, optional: true }, - step: { type: Number, optional: true }, - digits: { type: Array, optional: true }, - placeholder: { type: String, optional: true }, -}; -FloatField.defaultProps = { - inputType: "text", +export const floatField = { + component: FloatField, + displayName: _lt("Float"), + supportedTypes: ["float"], + isEmpty: () => false, + extractProps: ({ attrs, field }) => { + // Sadly, digits param was available as an option and an attr. + // The option version could be removed with some xml refactoring. + let digits; + if (attrs.digits) { + digits = JSON.parse(attrs.digits); + } else if (attrs.options.digits) { + digits = attrs.options.digits; + } else if (Array.isArray(field.digits)) { + digits = field.digits; + } + + return { + inputType: attrs.options.type, + step: attrs.options.step, + digits, + placeholder: attrs.placeholder, + }; + }, }; -FloatField.displayName = _lt("Float"); -FloatField.supportedTypes = ["float"]; - -FloatField.isEmpty = () => false; -FloatField.extractProps = ({ attrs, field }) => { - // Sadly, digits param was available as an option and an attr. - // The option version could be removed with some xml refactoring. - let digits; - if (attrs.digits) { - digits = JSON.parse(attrs.digits); - } else if (attrs.options.digits) { - digits = attrs.options.digits; - } else if (Array.isArray(field.digits)) { - digits = field.digits; - } - return { - inputType: attrs.options.type, - step: attrs.options.step, - digits, - placeholder: attrs.placeholder, - }; -}; - -registry.category("fields").add("float", FloatField); +registry.category("fields").add("float", floatField); diff --git a/addons/web/static/src/views/fields/float_factor/float_factor_field.js b/addons/web/static/src/views/fields/float_factor/float_factor_field.js index e35fe2eb521..946e6f350bd 100644 --- a/addons/web/static/src/views/fields/float_factor/float_factor_field.js +++ b/addons/web/static/src/views/fields/float_factor/float_factor_field.js @@ -1,10 +1,21 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { FloatField } from "../float/float_field"; - +import { floatField, FloatField } from "../float/float_field"; import { Component } from "@odoo/owl"; + export class FloatFactorField extends Component { + static template = "web.FloatFactorField"; + static components = { FloatField }; + static props = { + ...FloatField.props, + factor: { type: Number, optional: true }, + }; + static defaultProps = { + ...FloatField.defaultProps, + factor: 1, + }; + get factor() { return this.props.factor; } @@ -20,25 +31,13 @@ export class FloatFactorField extends Component { } } -FloatFactorField.template = "web.FloatFactorField"; -FloatFactorField.components = { FloatField }; -FloatFactorField.props = { - ...FloatField.props, - factor: { type: Number, optional: true }, -}; -FloatFactorField.defaultProps = { - ...FloatField.defaultProps, - factor: 1, +export const floatFactorField = { + ...floatField, + component: FloatFactorField, + extractProps: (params) => ({ + ...floatField.extractProps(params), + factor: params.attrs.options.factor, + }), }; -FloatFactorField.supportedTypes = ["float"]; - -FloatFactorField.isEmpty = () => false; -FloatFactorField.extractProps = ({ attrs, field }) => { - return { - ...FloatField.extractProps({ attrs, field }), - factor: attrs.options.factor, - }; -}; - -registry.category("fields").add("float_factor", FloatFactorField); +registry.category("fields").add("float_factor", floatFactorField); diff --git a/addons/web/static/src/views/fields/float_time/float_time_field.js b/addons/web/static/src/views/fields/float_time/float_time_field.js index dd5f0e0dd1c..2164e935c15 100644 --- a/addons/web/static/src/views/fields/float_time/float_time_field.js +++ b/addons/web/static/src/views/fields/float_time/float_time_field.js @@ -11,6 +11,12 @@ import { useNumpadDecimal } from "../numpad_decimal_hook"; import { Component } from "@odoo/owl"; export class FloatTimeField extends Component { + static template = "web.FloatTimeField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + }; + setup() { useInputField({ getValue: () => this.formattedValue, @@ -25,20 +31,14 @@ export class FloatTimeField extends Component { } } -FloatTimeField.template = "web.FloatTimeField"; -FloatTimeField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, -}; - -FloatTimeField.displayName = _lt("Time"); -FloatTimeField.supportedTypes = ["float"]; - -FloatTimeField.isEmpty = () => false; -FloatTimeField.extractProps = ({ attrs }) => { - return { +export const floatTimeField = { + component: FloatTimeField, + displayName: _lt("Time"), + supportedTypes: ["float"], + isEmpty: () => false, + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("float_time", FloatTimeField); +registry.category("fields").add("float_time", floatTimeField); diff --git a/addons/web/static/src/views/fields/float_toggle/float_toggle_field.js b/addons/web/static/src/views/fields/float_toggle/float_toggle_field.js index 4b5e15db9f0..60edbec9a1f 100644 --- a/addons/web/static/src/views/fields/float_toggle/float_toggle_field.js +++ b/addons/web/static/src/views/fields/float_toggle/float_toggle_field.js @@ -7,6 +7,20 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class FloatToggleField extends Component { + static template = "web.FloatToggleField"; + static props = { + ...standardFieldProps, + digits: { type: Array, optional: true }, + range: { type: Array, optional: true }, + factor: { type: Number, optional: true }, + disableReadOnly: { type: Boolean, optional: true }, + }; + static defaultProps = { + range: [0.0, 0.5, 1.0], + factor: 1, + disableReadOnly: false, + }; + // TODO perf issue (because of update round trip) // we probably want to have a state and a useEffect or onWillUpateProps onChange() { @@ -30,38 +44,29 @@ export class FloatToggleField extends Component { } } -FloatToggleField.template = "web.FloatToggleField"; -FloatToggleField.props = { - ...standardFieldProps, - digits: { type: Array, optional: true }, - range: { type: Array, optional: true }, - factor: { type: Number, optional: true }, - disableReadOnly: { type: Boolean, optional: true }, -}; -FloatToggleField.defaultProps = { - range: [0.0, 0.5, 1.0], - factor: 1, - disableReadOnly: false, +export const floatToggleField = { + component: FloatToggleField, + supportedTypes: ["float"], + isEmpty: () => false, + extractProps: ({ attrs, field }) => { + // Sadly, digits param was available as an option and an attr. + // The option version could be removed with some xml refactoring. + let digits; + if (attrs.digits) { + digits = JSON.parse(attrs.digits); + } else if (attrs.options.digits) { + digits = attrs.options.digits; + } else if (Array.isArray(field.digits)) { + digits = field.digits; + } + + return { + digits, + range: attrs.options.range, + factor: attrs.options.factor, + disableReadOnly: attrs.options.force_button || false, + }; + }, }; -FloatToggleField.supportedTypes = ["float"]; - -FloatToggleField.isEmpty = () => false; -FloatToggleField.extractProps = ({ attrs, field }) => { - let digits; - if (attrs.digits) { - digits = JSON.parse(attrs.digits); - } else if (attrs.options.digits) { - digits = attrs.options.digits; - } else if (Array.isArray(field.digits)) { - digits = field.digits; - } - return { - digits, - range: attrs.options.range, - factor: attrs.options.factor, - disableReadOnly: attrs.options.force_button || false, - }; -}; - -registry.category("fields").add("float_toggle", FloatToggleField); +registry.category("fields").add("float_toggle", floatToggleField); diff --git a/addons/web/static/src/views/fields/font_selection/font_selection_field.js b/addons/web/static/src/views/fields/font_selection/font_selection_field.js index f6cbc09bf25..d8f297c76cd 100644 --- a/addons/web/static/src/views/fields/font_selection/font_selection_field.js +++ b/addons/web/static/src/views/fields/font_selection/font_selection_field.js @@ -8,6 +8,12 @@ import { formatSelection } from "../formatters"; import { Component } from "@odoo/owl"; export class FontSelectionField extends Component { + static template = "web.FontSelectionField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + }; + get options() { return this.props.record.fields[this.props.name].selection.filter( (option) => option[0] !== false && option[1] !== "" @@ -33,20 +39,14 @@ export class FontSelectionField extends Component { } } -FontSelectionField.template = "web.FontSelectionField"; -FontSelectionField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, -}; - -FontSelectionField.displayName = _lt("Font Selection"); -FontSelectionField.supportedTypes = ["selection"]; -FontSelectionField.legacySpecialData = "_fetchSpecialRelation"; - -FontSelectionField.extractProps = ({ attrs }) => { - return { +export const fontSelectionField = { + component: FontSelectionField, + displayName: _lt("Font Selection"), + supportedTypes: ["selection"], + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder, - }; + }), + legacySpecialData: "_fetchSpecialRelation", }; -registry.category("fields").add("font", FontSelectionField); +registry.category("fields").add("font", fontSelectionField); diff --git a/addons/web/static/src/views/fields/handle/handle_field.js b/addons/web/static/src/views/fields/handle/handle_field.js index 0cca12a7d57..1342d033d30 100644 --- a/addons/web/static/src/views/fields/handle/handle_field.js +++ b/addons/web/static/src/views/fields/handle/handle_field.js @@ -6,14 +6,18 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; -export class HandleField extends Component {} +export class HandleField extends Component { + static template = "web.HandleField"; + static props = { + ...standardFieldProps, + }; +} -HandleField.template = "web.HandleField"; -HandleField.props = { - ...standardFieldProps, +export const handleField = { + component: HandleField, + displayName: _lt("Handle"), + supportedTypes: ["integer"], + isEmpty: () => false, }; -HandleField.displayName = _lt("Handle"); -HandleField.supportedTypes = ["integer"]; -HandleField.isEmpty = () => false; -registry.category("fields").add("handle", HandleField); +registry.category("fields").add("handle", handleField); diff --git a/addons/web/static/src/views/fields/html/html_field.js b/addons/web/static/src/views/fields/html/html_field.js index e4baee895b8..0fa28900707 100644 --- a/addons/web/static/src/views/fields/html/html_field.js +++ b/addons/web/static/src/views/fields/html/html_field.js @@ -1,10 +1,15 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { TextField } from "../text/text_field"; +import { TextField, textField } from "../text/text_field"; -export class HtmlField extends TextField {} +export class HtmlField extends TextField { + static template = "web.HtmlField"; +} -HtmlField.template = "web.HtmlField"; +export const htmlField = { + ...textField, + component: HtmlField, +}; -registry.category("fields").add("html", HtmlField); +registry.category("fields").add("html", htmlField); diff --git a/addons/web/static/src/views/fields/iframe_wrapper/iframe_wrapper_field.js b/addons/web/static/src/views/fields/iframe_wrapper/iframe_wrapper_field.js index 52ddbb50d68..fc1717d2b01 100644 --- a/addons/web/static/src/views/fields/iframe_wrapper/iframe_wrapper_field.js +++ b/addons/web/static/src/views/fields/iframe_wrapper/iframe_wrapper_field.js @@ -6,6 +6,11 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, useEffect, useRef } from "@odoo/owl"; export class IframeWrapperField extends Component { + static template = "web.IframeWrapperField"; + static props = { + ...standardFieldProps, + }; + setup() { this.iframeRef = useRef("iframe"); @@ -31,12 +36,11 @@ export class IframeWrapperField extends Component { } } -IframeWrapperField.template = "web.IframeWrapperField"; -IframeWrapperField.props = { - ...standardFieldProps, +export const iframeWrapperField = { + component: IframeWrapperField, + displayName: _lt("Wrap raw html within an iframe"), + // If HTML, don't forget to adjust the sanitize options to avoid stripping most of the metadata + supportedTypes: ["text", "html"], }; -IframeWrapperField.displayName = _lt("Wrap raw html within an iframe"); -// If HTML, don't forget to adjust the sanitize options to avoid stripping most of the metadata -IframeWrapperField.supportedTypes = ["text", "html"]; -registry.category("fields").add("iframe_wrapper", IframeWrapperField); +registry.category("fields").add("iframe_wrapper", iframeWrapperField); diff --git a/addons/web/static/src/views/fields/image/image_field.js b/addons/web/static/src/views/fields/image/image_field.js index 0c143654fd2..c42e9a29b84 100644 --- a/addons/web/static/src/views/fields/image/image_field.js +++ b/addons/web/static/src/views/fields/image/image_field.js @@ -36,6 +36,23 @@ export function imageCacheKey(value) { } export class ImageField extends Component { + static template = "web.ImageField"; + static components = { + FileUploader, + }; + static props = { + ...standardFieldProps, + enableZoom: { type: Boolean, optional: true }, + zoomDelay: { type: Number, optional: true }, + previewImage: { type: String, optional: true }, + acceptedFileExtensions: { type: String, optional: true }, + width: { type: Number, optional: true }, + height: { type: Number, optional: true }, + }; + static defaultProps = { + acceptedFileExtensions: "image/*", + }; + setup() { this.notification = useService("notification"); this.isMobile = isMobileOS(); @@ -111,32 +128,14 @@ export class ImageField extends Component { } } -ImageField.template = "web.ImageField"; -ImageField.components = { - FileUploader, -}; -ImageField.props = { - ...standardFieldProps, - enableZoom: { type: Boolean, optional: true }, - zoomDelay: { type: Number, optional: true }, - previewImage: { type: String, optional: true }, - acceptedFileExtensions: { type: String, optional: true }, - width: { type: Number, optional: true }, - height: { type: Number, optional: true }, -}; -ImageField.defaultProps = { - acceptedFileExtensions: "image/*", -}; - -ImageField.displayName = _lt("Image"); -ImageField.supportedTypes = ["binary"]; - -ImageField.fieldDependencies = { - write_date: { type: "datetime" }, -}; - -ImageField.extractProps = ({ attrs }) => { - return { +export const imageField = { + component: ImageField, + displayName: _lt("Image"), + supportedTypes: ["binary"], + fieldDependencies: { + write_date: { type: "datetime" }, + }, + extractProps: ({ attrs }) => ({ enableZoom: attrs.options.zoom, zoomDelay: attrs.options.zoom_delay, previewImage: attrs.options.preview_image, @@ -149,8 +148,8 @@ ImageField.extractProps = ({ attrs }) => { attrs.options.size && Boolean(attrs.options.size[1]) ? attrs.options.size[1] : attrs.height, - }; + }), }; -registry.category("fields").add("image", ImageField); -registry.category("fields").add("kanban.image", ImageField); // FIXME WOWL: s.t. we don't use the legacy one +registry.category("fields").add("image", imageField); +registry.category("fields").add("kanban.image", imageField); // FIXME WOWL: s.t. we don't use the legacy one diff --git a/addons/web/static/src/views/fields/image_url/image_url_field.js b/addons/web/static/src/views/fields/image_url/image_url_field.js index 05c92e00cb3..eab3bca39f1 100644 --- a/addons/web/static/src/views/fields/image_url/image_url_field.js +++ b/addons/web/static/src/views/fields/image_url/image_url_field.js @@ -8,6 +8,15 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, onWillUpdateProps, useState } from "@odoo/owl"; export class ImageUrlField extends Component { + static template = "web.ImageUrlField"; + static props = { + ...standardFieldProps, + width: { type: Number, optional: true }, + height: { type: Number, optional: true }, + }; + + static fallbackSrc = "/web/static/img/placeholder.png"; + setup() { this.notification = useService("notification"); this.state = useState({ @@ -40,25 +49,16 @@ export class ImageUrlField extends Component { } } -ImageUrlField.fallbackSrc = "/web/static/img/placeholder.png"; - -ImageUrlField.template = "web.ImageUrlField"; -ImageUrlField.props = { - ...standardFieldProps, - width: { type: Number, optional: true }, - height: { type: Number, optional: true }, -}; - -ImageUrlField.displayName = _lt("Image"); -ImageUrlField.supportedTypes = ["char"]; - -ImageUrlField.extractProps = ({ attrs }) => { - return { +export const imageUrlField = { + component: ImageUrlField, + displayName: _lt("Image"), + supportedTypes: ["char"], + extractProps: ({ attrs }) => ({ width: attrs.options.size ? attrs.options.size[0] : attrs.width, height: attrs.options.size ? attrs.options.size[1] : attrs.height, - }; + }), }; -registry.category("fields").add("image_url", ImageUrlField); +registry.category("fields").add("image_url", imageUrlField); // TODO WOWL: remove below when old registry is removed. -registry.category("fields").add("kanban.image_url", ImageUrlField); +registry.category("fields").add("kanban.image_url", imageUrlField); diff --git a/addons/web/static/src/views/fields/integer/integer_field.js b/addons/web/static/src/views/fields/integer/integer_field.js index dc875c03c9c..f8e7338bca9 100644 --- a/addons/web/static/src/views/fields/integer/integer_field.js +++ b/addons/web/static/src/views/fields/integer/integer_field.js @@ -11,6 +11,17 @@ import { useNumpadDecimal } from "../numpad_decimal_hook"; import { Component } from "@odoo/owl"; export class IntegerField extends Component { + static template = "web.IntegerField"; + static props = { + ...standardFieldProps, + inputType: { type: String, optional: true }, + step: { type: Number, optional: true }, + placeholder: { type: String, optional: true }, + }; + static defaultProps = { + inputType: "text", + }; + setup() { useInputField({ getValue: () => this.formattedValue, @@ -28,27 +39,16 @@ export class IntegerField extends Component { } } -IntegerField.template = "web.IntegerField"; -IntegerField.props = { - ...standardFieldProps, - inputType: { type: String, optional: true }, - step: { type: Number, optional: true }, - placeholder: { type: String, optional: true }, -}; -IntegerField.defaultProps = { - inputType: "text", -}; - -IntegerField.displayName = _lt("Integer"); -IntegerField.supportedTypes = ["integer"]; - -IntegerField.isEmpty = (record, fieldName) => (record.data[fieldName] === false ? true : false); -IntegerField.extractProps = ({ attrs }) => { - return { +export const integerField = { + component: IntegerField, + displayName: _lt("Integer"), + supportedTypes: ["integer"], + isEmpty: (record, fieldName) => record.data[fieldName] === false, + extractProps: ({ attrs }) => ({ inputType: attrs.options.type, step: attrs.options.step, placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("integer", IntegerField); +registry.category("fields").add("integer", integerField); diff --git a/addons/web/static/src/views/fields/journal_dashboard_graph/journal_dashboard_graph_field.js b/addons/web/static/src/views/fields/journal_dashboard_graph/journal_dashboard_graph_field.js index d14199b06fc..22f6de487bc 100644 --- a/addons/web/static/src/views/fields/journal_dashboard_graph/journal_dashboard_graph_field.js +++ b/addons/web/static/src/views/fields/journal_dashboard_graph/journal_dashboard_graph_field.js @@ -9,6 +9,12 @@ import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, useEffect, useRef } from "@odoo/owl"; export class JournalDashboardGraphField extends Component { + static template = "web.JournalDashboardGraphField"; + static props = { + ...standardFieldProps, + graphType: String, + }; + setup() { this.chart = null; this.cookies = useService("cookie"); @@ -145,18 +151,12 @@ export class JournalDashboardGraphField extends Component { } } -JournalDashboardGraphField.template = "web.JournalDashboardGraphField"; -JournalDashboardGraphField.props = { - ...standardFieldProps, - graphType: String, -}; - -JournalDashboardGraphField.supportedTypes = ["text"]; - -JournalDashboardGraphField.extractProps = ({ attrs }) => { - return { +export const journalDashboardGraphField = { + component: JournalDashboardGraphField, + supportedTypes: ["text"], + extractProps: ({ attrs }) => ({ graphType: attrs.graph_type, - }; + }), }; -registry.category("fields").add("dashboard_graph", JournalDashboardGraphField); +registry.category("fields").add("dashboard_graph", journalDashboardGraphField); diff --git a/addons/web/static/src/views/fields/label_selection/label_selection_field.js b/addons/web/static/src/views/fields/label_selection/label_selection_field.js index 23f29516f9d..263bbd98457 100644 --- a/addons/web/static/src/views/fields/label_selection/label_selection_field.js +++ b/addons/web/static/src/views/fields/label_selection/label_selection_field.js @@ -8,6 +8,15 @@ import { formatSelection } from "../formatters"; import { Component } from "@odoo/owl"; export class LabelSelectionField extends Component { + static template = "web.LabelSelectionField"; + static props = { + ...standardFieldProps, + classesObj: { type: Object, optional: true }, + }; + static defaultProps = { + classesObj: {}, + }; + get className() { return this.props.classesObj[this.props.value] || "primary"; } @@ -18,22 +27,13 @@ export class LabelSelectionField extends Component { } } -LabelSelectionField.template = "web.LabelSelectionField"; -LabelSelectionField.props = { - ...standardFieldProps, - classesObj: { type: Object, optional: true }, -}; -LabelSelectionField.defaultProps = { - classesObj: {}, -}; - -LabelSelectionField.displayName = _lt("Label Selection"); -LabelSelectionField.supportedTypes = ["selection"]; - -LabelSelectionField.extractProps = ({ attrs }) => { - return { +export const labelSelectionField = { + component: LabelSelectionField, + displayName: _lt("Label Selection"), + supportedTypes: ["selection"], + extractProps: ({ attrs }) => ({ classesObj: attrs.options.classes, - }; + }), }; -registry.category("fields").add("label_selection", LabelSelectionField); +registry.category("fields").add("label_selection", labelSelectionField); diff --git a/addons/web/static/src/views/fields/many2many_binary/many2many_binary_field.js b/addons/web/static/src/views/fields/many2many_binary/many2many_binary_field.js index e7f26fcf5b0..f9605ece90c 100644 --- a/addons/web/static/src/views/fields/many2many_binary/many2many_binary_field.js +++ b/addons/web/static/src/views/fields/many2many_binary/many2many_binary_field.js @@ -9,6 +9,17 @@ import { useX2ManyCrud } from "@web/views/fields/relational_utils"; import { Component } from "@odoo/owl"; export class Many2ManyBinaryField extends Component { + static template = "web.Many2ManyBinaryField"; + static components = { + FileInput, + }; + static props = { + ...standardFieldProps, + acceptedFileExtensions: { type: String, optional: true }, + className: { type: String, optional: true }, + uploadText: { type: String, optional: true }, + }; + setup() { this.orm = useService("orm"); this.notification = useService("notification"); @@ -45,29 +56,19 @@ export class Many2ManyBinaryField extends Component { } } -Many2ManyBinaryField.template = "web.Many2ManyBinaryField"; -Many2ManyBinaryField.components = { - FileInput, -}; -Many2ManyBinaryField.props = { - ...standardFieldProps, - acceptedFileExtensions: { type: String, optional: true }, - className: { type: String, optional: true }, - uploadText: { type: String, optional: true }, -}; -Many2ManyBinaryField.supportedTypes = ["many2many"]; -Many2ManyBinaryField.fieldsToFetch = [ - { name: "name", type: "char" }, - { name: "mimetype", type: "char" }, -]; - -Many2ManyBinaryField.isEmpty = () => false; -Many2ManyBinaryField.extractProps = ({ attrs, field }) => { - return { +export const many2ManyBinaryField = { + component: Many2ManyBinaryField, + supportedTypes: ["many2many"], + isEmpty: () => false, + fieldsToFetch: [ + { name: "name", type: "char" }, + { name: "mimetype", type: "char" }, + ], + extractProps: ({ attrs, field }) => ({ acceptedFileExtensions: attrs.options.accepted_file_extensions, className: attrs.class, uploadText: field.string, - }; + }), }; -registry.category("fields").add("many2many_binary", Many2ManyBinaryField); +registry.category("fields").add("many2many_binary", many2ManyBinaryField); diff --git a/addons/web/static/src/views/fields/many2many_checkboxes/many2many_checkboxes_field.js b/addons/web/static/src/views/fields/many2many_checkboxes/many2many_checkboxes_field.js index da1403434b9..76905792436 100644 --- a/addons/web/static/src/views/fields/many2many_checkboxes/many2many_checkboxes_field.js +++ b/addons/web/static/src/views/fields/many2many_checkboxes/many2many_checkboxes_field.js @@ -8,6 +8,12 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class Many2ManyCheckboxesField extends Component { + static template = "web.Many2ManyCheckboxesField"; + static components = { CheckBox }; + static props = { + ...standardFieldProps, + }; + get items() { return this.props.record.preloadedData[this.props.name]; } @@ -30,19 +36,15 @@ export class Many2ManyCheckboxesField extends Component { } } -Many2ManyCheckboxesField.template = "web.Many2ManyCheckboxesField"; -Many2ManyCheckboxesField.components = { CheckBox }; -Many2ManyCheckboxesField.props = { - ...standardFieldProps, +export const many2ManyCheckboxesField = { + component: Many2ManyCheckboxesField, + displayName: _lt("Checkboxes"), + supportedTypes: ["many2many"], + isEmpty: () => false, + legacySpecialData: "_fetchSpecialRelation", }; -Many2ManyCheckboxesField.legacySpecialData = "_fetchSpecialRelation"; -Many2ManyCheckboxesField.displayName = _lt("Checkboxes"); -Many2ManyCheckboxesField.supportedTypes = ["many2many"]; - -Many2ManyCheckboxesField.isEmpty = () => false; - -registry.category("fields").add("many2many_checkboxes", Many2ManyCheckboxesField); +registry.category("fields").add("many2many_checkboxes", many2ManyCheckboxesField); export function preloadMany2ManyCheckboxes(orm, record, fieldName) { const field = record.fields[fieldName]; diff --git a/addons/web/static/src/views/fields/many2many_tags/kanban_many2many_tags_field.js b/addons/web/static/src/views/fields/many2many_tags/kanban_many2many_tags_field.js index 0ce81139da2..20c85005b79 100644 --- a/addons/web/static/src/views/fields/many2many_tags/kanban_many2many_tags_field.js +++ b/addons/web/static/src/views/fields/many2many_tags/kanban_many2many_tags_field.js @@ -1,9 +1,11 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2ManyTagsField } from "./many2many_tags_field"; +import { Many2ManyTagsField, many2ManyTagsField } from "./many2many_tags_field"; export class KanbanMany2ManyTagsField extends Many2ManyTagsField { + static template = "web.KanbanMany2ManyTagsField"; + get tags() { return super.tags.reduce((kanbanTags, tag) => { if (tag.colorIndex !== 0) { @@ -15,6 +17,9 @@ export class KanbanMany2ManyTagsField extends Many2ManyTagsField { } } -KanbanMany2ManyTagsField.template = "web.KanbanMany2ManyTagsField"; +export const kanbanMany2ManyTagsField = { + ...many2ManyTagsField, + component: KanbanMany2ManyTagsField, +}; -registry.category("fields").add("kanban.many2many_tags", KanbanMany2ManyTagsField); +registry.category("fields").add("kanban.many2many_tags", kanbanMany2ManyTagsField); diff --git a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js index 5b02b501bd6..3648d01d2bc 100644 --- a/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js +++ b/addons/web/static/src/views/fields/many2many_tags/many2many_tags_field.js @@ -18,14 +18,41 @@ import { useService } from "@web/core/utils/hooks"; import { Component, useRef } from "@odoo/owl"; -class Many2ManyTagsFieldColorListPopover extends Component {} -Many2ManyTagsFieldColorListPopover.template = "web.Many2ManyTagsFieldColorListPopover"; -Many2ManyTagsFieldColorListPopover.components = { - CheckBox, - ColorList, -}; +class Many2ManyTagsFieldColorListPopover extends Component { + static template = "web.Many2ManyTagsFieldColorListPopover"; + static components = { + CheckBox, + ColorList, + }; +} export class Many2ManyTagsField extends Component { + static template = "web.Many2ManyTagsField"; + static components = { + TagsList, + Many2XAutocomplete, + }; + static props = { + ...standardFieldProps, + canCreate: { type: Boolean, optional: true }, + canQuickCreate: { type: Boolean, optional: true }, + canCreateEdit: { type: Boolean, optional: true }, + colorField: { type: String, optional: true }, + createDomain: { type: [Array, Boolean], optional: true }, + placeholder: { type: String, optional: true }, + relation: { type: String }, + nameCreateField: { type: String, optional: true }, + }; + static defaultProps = { + canCreate: true, + canQuickCreate: true, + canCreateEdit: true, + nameCreateField: "name", + }; + + static RECORD_COLORS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + static SEARCH_MORE_LIMIT = 320; + setup() { this.orm = useService("orm"); this.previousColorsMap = {}; @@ -216,69 +243,59 @@ export class Many2ManyTagsField extends Component { } } -Many2ManyTagsField.RECORD_COLORS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; -Many2ManyTagsField.SEARCH_MORE_LIMIT = 320; +export const many2ManyTagsField = { + component: Many2ManyTagsField, + displayName: _lt("Tags"), + supportedTypes: ["many2many"], + isSet: (value) => value.count > 0, + fieldsToFetch: (fieldInfo) => { + const fieldsToFetch = [{ name: "display_name", type: "char" }]; + if (fieldInfo.options.color_field) { + fieldsToFetch.push({ name: fieldInfo.options.color_field, type: "integer" }); + } + return fieldsToFetch; + }, + extractProps: ({ attrs, field }) => { + const noCreate = Boolean(attrs.options.no_create); + const canCreate = attrs.can_create && Boolean(JSON.parse(attrs.can_create)) && !noCreate; + const noQuickCreate = Boolean(attrs.options.no_quick_create); + const noCreateEdit = Boolean(attrs.options.no_create_edit); + return { + colorField: attrs.options.color_field, + nameCreateField: attrs.options.create_name_field, + canCreate, + canQuickCreate: canCreate && !noQuickCreate, + canCreateEdit: canCreate && !noCreateEdit, + createDomain: attrs.options.create, + placeholder: attrs.placeholder, -Many2ManyTagsField.template = "web.Many2ManyTagsField"; -Many2ManyTagsField.components = { - TagsList, - Many2XAutocomplete, + relation: field.relation, + }; + }, }; -Many2ManyTagsField.props = { - ...standardFieldProps, - canCreate: { type: Boolean, optional: true }, - canQuickCreate: { type: Boolean, optional: true }, - canCreateEdit: { type: Boolean, optional: true }, - colorField: { type: String, optional: true }, - createDomain: { type: [Array, Boolean], optional: true }, - placeholder: { type: String, optional: true }, - relation: { type: String }, - nameCreateField: { type: String, optional: true }, -}; -Many2ManyTagsField.defaultProps = { - canCreate: true, - canQuickCreate: true, - canCreateEdit: true, - nameCreateField: "name", -}; - -Many2ManyTagsField.displayName = _lt("Tags"); -Many2ManyTagsField.supportedTypes = ["many2many"]; -Many2ManyTagsField.fieldsToFetch = (fieldInfo) => { - const fieldsToFetch = [{ name: "display_name", type: "char" }]; - if (fieldInfo.options.color_field) { - fieldsToFetch.push({ name: fieldInfo.options.color_field, type: "integer" }); - } - return fieldsToFetch; -}; -Many2ManyTagsField.isSet = (value) => value.count > 0; - -Many2ManyTagsField.extractProps = ({ attrs, field }) => { - const noCreate = Boolean(attrs.options.no_create); - const canCreate = attrs.can_create && Boolean(JSON.parse(attrs.can_create)) && !noCreate; - const noQuickCreate = Boolean(attrs.options.no_quick_create); - const noCreateEdit = Boolean(attrs.options.no_create_edit); - - return { - colorField: attrs.options.color_field, - nameCreateField: attrs.options.create_name_field, - relation: field.relation, - canCreate, - canQuickCreate: canCreate && !noQuickCreate, - canCreateEdit: canCreate && !noCreateEdit, - createDomain: attrs.options.create, - placeholder: attrs.placeholder, - }; -}; - -registry.category("fields").add("many2many_tags", Many2ManyTagsField); +registry.category("fields").add("many2many_tags", many2ManyTagsField); +registry.category("fields").add("calendar.one2many", many2ManyTagsField); +registry.category("fields").add("calendar.many2many", many2ManyTagsField); /** * A specialization that allows to edit the color with the colorpicker. * Used in form view. */ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField { + static components = { + ...super.components, + Popover: Many2ManyTagsFieldColorListPopover, + }; + static props = { + ...super.props, + canEditColor: { type: Boolean, optional: true }, + }; + static defaultProps = { + ...super.defaultProps, + canEditColor: true, + }; + getTagProps(record) { const props = super.getTagProps(record); props.onClick = (ev) => this.onBadgeClick(ev, record); @@ -339,30 +356,13 @@ export class Many2ManyTagsFieldColorEditable extends Many2ManyTagsField { } } -Many2ManyTagsFieldColorEditable.components = { - ...Many2ManyTagsField.components, - Popover: Many2ManyTagsFieldColorListPopover, -}; -Many2ManyTagsFieldColorEditable.props = { - ...Many2ManyTagsField.props, - canEditColor: { type: Boolean, optional: true }, -}; -Many2ManyTagsFieldColorEditable.defaultProps = { - ...Many2ManyTagsField.defaultProps, - canEditColor: true, -}; -Many2ManyTagsFieldColorEditable.extractProps = (params) => { - const props = Many2ManyTagsField.extractProps(params); - const attrs = params.attrs; - const noEditColor = Boolean(attrs.options.no_edit_color); - const hasColorField = Boolean(attrs.options.color_field); - return { - ...props, - canEditColor: !noEditColor && hasColorField, - }; +export const many2ManyTagsFieldColorEditable = { + ...many2ManyTagsField, + component: Many2ManyTagsFieldColorEditable, + extractProps: (params) => ({ + ...many2ManyTagsField.extractProps(params), + canEditColor: !params.attrs.options.no_edit_color && !!params.attrs.options.color_field, + }), }; -registry.category("fields").add("form.many2many_tags", Many2ManyTagsFieldColorEditable); - -registry.category("fields").add("calendar.one2many", Many2ManyTagsField); -registry.category("fields").add("calendar.many2many", Many2ManyTagsField); +registry.category("fields").add("form.many2many_tags", many2ManyTagsFieldColorEditable); diff --git a/addons/web/static/src/views/fields/many2many_tags/tags_list.js b/addons/web/static/src/views/fields/many2many_tags/tags_list.js index 667fad5447c..0ba482aa122 100644 --- a/addons/web/static/src/views/fields/many2many_tags/tags_list.js +++ b/addons/web/static/src/views/fields/many2many_tags/tags_list.js @@ -3,6 +3,21 @@ import { Component } from "@odoo/owl"; export class TagsList extends Component { + static template = "web.TagsList"; + static defaultProps = { + className: "", + displayBadge: true, + displayText: true, + }; + static props = { + className: { type: String, optional: true }, + displayBadge: { type: Boolean, optional: true }, + displayText: { type: Boolean, optional: true }, + name: { type: String, optional: true }, + itemsVisible: { type: Number, optional: true }, + tags: { type: Object, optional: true }, + }; + get visibleTags() { if (this.props.itemsVisible && this.props.tags.length > this.props.itemsVisible) { return this.props.tags.slice(0, this.props.itemsVisible - 1); @@ -24,17 +39,3 @@ export class TagsList extends Component { }); } } -TagsList.template = "web.TagsList"; -TagsList.defaultProps = { - className: "", - displayBadge: true, - displayText: true, -}; -TagsList.props = { - className: { type: String, optional: true }, - displayBadge: { type: Boolean, optional: true }, - displayText: { type: Boolean, optional: true }, - name: { type: String, optional: true }, - itemsVisible: { type: Number, optional: true }, - tags: { type: Object, optional: true }, -}; diff --git a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js index e0c638efab3..6b111137966 100644 --- a/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js +++ b/addons/web/static/src/views/fields/many2many_tags_avatar/many2many_tags_avatar_field.js @@ -2,10 +2,19 @@ import { registry } from "@web/core/registry"; import { Many2XAutocomplete } from "@web/views/fields/relational_utils"; -import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; +import { + many2ManyTagsField, + Many2ManyTagsField, +} from "@web/views/fields/many2many_tags/many2many_tags_field"; import { TagsList } from "../many2many_tags/tags_list"; export class Many2ManyTagsAvatarField extends Many2ManyTagsField { + static template = "web.Many2ManyTagsAvatarField"; + static components = { + Many2XAutocomplete, + TagsList, + }; + get tags() { return super.tags.map((tag) => ({ ...tag, @@ -15,13 +24,12 @@ export class Many2ManyTagsAvatarField extends Many2ManyTagsField { } } -Many2ManyTagsAvatarField.template = "web.Many2ManyTagsAvatarField"; -Many2ManyTagsAvatarField.components = { - Many2XAutocomplete, - TagsList, +export const many2ManyTagsAvatarField = { + ...many2ManyTagsField, + component: Many2ManyTagsAvatarField, }; -registry.category("fields").add("many2many_tags_avatar", Many2ManyTagsAvatarField); +registry.category("fields").add("many2many_tags_avatar", many2ManyTagsAvatarField); export class ListKanbanMany2ManyTagsAvatarField extends Many2ManyTagsAvatarField { get itemsVisible() { @@ -36,5 +44,10 @@ export class ListKanbanMany2ManyTagsAvatarField extends Many2ManyTagsAvatarField } } -registry.category("fields").add("list.many2many_tags_avatar", ListKanbanMany2ManyTagsAvatarField); -registry.category("fields").add("kanban.many2many_tags_avatar", ListKanbanMany2ManyTagsAvatarField); +export const listKanbanMany2ManyTagsAvatarField = { + ...many2ManyTagsAvatarField, + component: ListKanbanMany2ManyTagsAvatarField, +}; + +registry.category("fields").add("list.many2many_tags_avatar", listKanbanMany2ManyTagsAvatarField); +registry.category("fields").add("kanban.many2many_tags_avatar", listKanbanMany2ManyTagsAvatarField); diff --git a/addons/web/static/src/views/fields/many2one/many2one_field.js b/addons/web/static/src/views/fields/many2one/many2one_field.js index ffeb238a9cc..88e72b19afe 100644 --- a/addons/web/static/src/views/fields/many2one/many2one_field.js +++ b/addons/web/static/src/views/fields/many2one/many2one_field.js @@ -14,6 +14,9 @@ import * as BarcodeScanner from "@web/webclient/barcode/barcode_scanner"; import { Component, onWillUpdateProps, useState } from "@odoo/owl"; class CreateConfirmationDialog extends Component { + static template = "web.Many2OneField.CreateConfirmationDialog"; + static components = { Dialog }; + get title() { return sprintf(this.env._t("New: %s"), this.props.name); } @@ -23,8 +26,6 @@ class CreateConfirmationDialog extends Component { this.props.close(); } } -CreateConfirmationDialog.components = { Dialog }; -CreateConfirmationDialog.template = "web.Many2OneField.CreateConfirmationDialog"; export function m2oTupleFromData(data) { const id = data.id; @@ -39,6 +40,44 @@ export function m2oTupleFromData(data) { } export class Many2OneField extends Component { + static template = "web.Many2OneField"; + static components = { + Many2XAutocomplete, + }; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + canOpen: { type: Boolean, optional: true }, + canCreate: { type: Boolean, optional: true }, + canWrite: { type: Boolean, optional: true }, + canQuickCreate: { type: Boolean, optional: true }, + canCreateEdit: { type: Boolean, optional: true }, + nameCreateField: { type: String, optional: true }, + searchLimit: { type: Number, optional: true }, + relation: { type: String, optional: true }, + string: { type: String, optional: true }, + canScanBarcode: { type: Boolean, optional: true }, + openTarget: { + type: String, + validate: (v) => ["current", "new"].includes(v), + optional: true, + }, + }; + static defaultProps = { + canOpen: true, + canCreate: true, + canWrite: true, + canQuickCreate: true, + canCreateEdit: true, + nameCreateField: "name", + searchLimit: 7, + string: "", + canScanBarcode: false, + openTarget: "current", + }; + + static SEARCH_MORE_LIMIT = 320; + setup() { this.orm = useService("orm"); this.action = useService("action"); @@ -243,68 +282,31 @@ export class Many2OneField extends Component { } } -Many2OneField.SEARCH_MORE_LIMIT = 320; +export const many2OneField = { + component: Many2OneField, + displayName: _lt("Many2one"), + supportedTypes: ["many2one"], + extractProps: ({ attrs, field }) => { + const canCreate = + attrs.can_create && Boolean(JSON.parse(attrs.can_create)) && !attrs.options.no_create; + return { + placeholder: attrs.placeholder, + canOpen: !attrs.options.no_open, + canCreate, + canWrite: attrs.can_write && Boolean(JSON.parse(attrs.can_write)), + canQuickCreate: canCreate && !attrs.options.no_quick_create, + canCreateEdit: canCreate && !attrs.options.no_create_edit, + nameCreateField: attrs.options.create_name_field, + canScanBarcode: !!attrs.options.can_scan_barcode, + openTarget: attrs.open_target, -Many2OneField.template = "web.Many2OneField"; -Many2OneField.components = { - Many2XAutocomplete, -}; -Many2OneField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, - canOpen: { type: Boolean, optional: true }, - canCreate: { type: Boolean, optional: true }, - canWrite: { type: Boolean, optional: true }, - canQuickCreate: { type: Boolean, optional: true }, - canCreateEdit: { type: Boolean, optional: true }, - nameCreateField: { type: String, optional: true }, - searchLimit: { type: Number, optional: true }, - relation: { type: String, optional: true }, - string: { type: String, optional: true }, - canScanBarcode: { type: Boolean, optional: true }, - openTarget: { type: String, validate: (v) => ["current", "new"].includes(v), optional: true }, -}; -Many2OneField.defaultProps = { - canOpen: true, - canCreate: true, - canWrite: true, - canQuickCreate: true, - canCreateEdit: true, - nameCreateField: "name", - searchLimit: 7, - string: "", - canScanBarcode: false, - openTarget: "current", + relation: field.relation, + string: attrs.string || field.string, + }; + }, }; -Many2OneField.displayName = _lt("Many2one"); -Many2OneField.supportedTypes = ["many2one"]; - -Many2OneField.extractProps = ({ attrs, field }) => { - const noOpen = Boolean(attrs.options.no_open); - const noCreate = Boolean(attrs.options.no_create); - const canCreate = attrs.can_create && Boolean(JSON.parse(attrs.can_create)) && !noCreate; - const canWrite = attrs.can_write && Boolean(JSON.parse(attrs.can_write)); - const noQuickCreate = Boolean(attrs.options.no_quick_create); - const noCreateEdit = Boolean(attrs.options.no_create_edit); - const canScanBarcode = Boolean(attrs.options.can_scan_barcode); - - return { - placeholder: attrs.placeholder, - canOpen: !noOpen, - canCreate, - canWrite, - canQuickCreate: canCreate && !noQuickCreate, - canCreateEdit: canCreate && !noCreateEdit, - relation: field.relation, - string: attrs.string || field.string, - nameCreateField: attrs.options.create_name_field, - canScanBarcode: canScanBarcode, - openTarget: attrs.open_target, - }; -}; - -registry.category("fields").add("many2one", Many2OneField); +registry.category("fields").add("many2one", many2OneField); // the two following lines are there to prevent the fallback on legacy widgets -registry.category("fields").add("list.many2one", Many2OneField); -registry.category("fields").add("kanban.many2one", Many2OneField); +registry.category("fields").add("list.many2one", many2OneField); +registry.category("fields").add("kanban.many2one", many2OneField); diff --git a/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.js b/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.js index 3ae3c1bef31..0c66776ca56 100644 --- a/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.js +++ b/addons/web/static/src/views/fields/many2one_avatar/many2one_avatar_field.js @@ -1,22 +1,23 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { Many2OneField } from "../many2one/many2one_field"; +import { many2OneField, Many2OneField } from "../many2one/many2one_field"; import { Component } from "@odoo/owl"; -export class Many2OneAvatarField extends Component {} +export class Many2OneAvatarField extends Component { + static template = "web.Many2OneAvatarField"; + static components = { + Many2OneField, + }; + static props = { + ...Many2OneField.props, + }; +} -Many2OneAvatarField.template = "web.Many2OneAvatarField"; -Many2OneAvatarField.components = { - Many2OneField, -}; -Many2OneAvatarField.props = { - ...Many2OneField.props, +export const many2OneAvatarField = { + ...many2OneField, + component: Many2OneAvatarField, }; -Many2OneAvatarField.supportedTypes = ["many2one"]; - -Many2OneAvatarField.extractProps = Many2OneField.extractProps; - -registry.category("fields").add("many2one_avatar", Many2OneAvatarField); +registry.category("fields").add("many2one_avatar", many2OneAvatarField); diff --git a/addons/web/static/src/views/fields/many2one_barcode/many2one_barcode_field.js b/addons/web/static/src/views/fields/many2one_barcode/many2one_barcode_field.js index 7b77d8efa59..bff69c3b110 100644 --- a/addons/web/static/src/views/fields/many2one_barcode/many2one_barcode_field.js +++ b/addons/web/static/src/views/fields/many2one_barcode/many2one_barcode_field.js @@ -2,27 +2,23 @@ import { _lt } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; -import { Many2OneField } from "../many2one/many2one_field"; +import { many2OneField, Many2OneField } from "../many2one/many2one_field"; -export class Many2OneBarcodeField extends Many2OneField {} - -Many2OneBarcodeField.props = { - ...Many2OneField.props, -}; -Many2OneBarcodeField.defaultProps = { - ...Many2OneField.defaultProps, - canScanBarcode: true, -}; - -Many2OneBarcodeField.displayName = _lt("Many2OneBarcode"); -Many2OneBarcodeField.template = "web.Many2OneField"; -Many2OneBarcodeField.supportedTypes = ["many2one"]; - -Many2OneBarcodeField.extractProps = (args) => { - return { - ...Many2OneField.extractProps(args), +export class Many2OneBarcodeField extends Many2OneField { + static defaultProps = { + ...super.defaultProps, canScanBarcode: true, }; +} + +export const many2OneBarcodeField = { + ...many2OneField, + component: Many2OneBarcodeField, + displayName: _lt("Many2OneBarcode"), + extractProps: (params) => ({ + ...many2OneField.extractProps(params), + canScanBarcode: true, + }), }; -registry.category("fields").add("many2one_barcode", Many2OneBarcodeField); +registry.category("fields").add("many2one_barcode", many2OneBarcodeField); diff --git a/addons/web/static/src/views/fields/many2one_reference/many2one_reference_field.js b/addons/web/static/src/views/fields/many2one_reference/many2one_reference_field.js index d0822a2fba6..8539acee6f1 100644 --- a/addons/web/static/src/views/fields/many2one_reference/many2one_reference_field.js +++ b/addons/web/static/src/views/fields/many2one_reference/many2one_reference_field.js @@ -1,6 +1,6 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { IntegerField } from "../integer/integer_field"; +import { integerField } from "../integer/integer_field"; -registry.category("fields").add("many2one_reference", IntegerField); +registry.category("fields").add("many2one_reference", integerField); diff --git a/addons/web/static/src/views/fields/monetary/monetary_field.js b/addons/web/static/src/views/fields/monetary/monetary_field.js index a6199ed1167..22b2973b8a7 100644 --- a/addons/web/static/src/views/fields/monetary/monetary_field.js +++ b/addons/web/static/src/views/fields/monetary/monetary_field.js @@ -12,6 +12,20 @@ import { session } from "@web/session"; import { Component } from "@odoo/owl"; export class MonetaryField extends Component { + static template = "web.MonetaryField"; + static props = { + ...standardFieldProps, + currencyField: { type: String, optional: true }, + inputType: { type: String, optional: true }, + useFieldDigits: { type: Boolean, optional: true }, + hideSymbol: { type: Boolean, optional: true }, + placeholder: { type: String, optional: true }, + }; + static defaultProps = { + hideSymbol: false, + inputType: "text", + }; + setup() { useInputField({ getValue: () => this.formattedValue, @@ -62,31 +76,17 @@ export class MonetaryField extends Component { } } -MonetaryField.template = "web.MonetaryField"; -MonetaryField.props = { - ...standardFieldProps, - currencyField: { type: String, optional: true }, - inputType: { type: String, optional: true }, - useFieldDigits: { type: Boolean, optional: true }, - hideSymbol: { type: Boolean, optional: true }, - placeholder: { type: String, optional: true }, -}; -MonetaryField.defaultProps = { - hideSymbol: false, - inputType: "text", -}; - -MonetaryField.supportedTypes = ["monetary", "float"]; -MonetaryField.displayName = _lt("Monetary"); - -MonetaryField.extractProps = ({ attrs }) => { - return { +export const monetaryField = { + component: MonetaryField, + supportedTypes: ["monetary", "float"], + displayName: _lt("Monetary"), + extractProps: ({ attrs }) => ({ currencyField: attrs.options.currency_field, inputType: attrs.type, useFieldDigits: attrs.options.field_digits, hideSymbol: attrs.options.no_symbol, placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("monetary", MonetaryField); +registry.category("fields").add("monetary", monetaryField); diff --git a/addons/web/static/src/views/fields/pdf_viewer/pdf_viewer_field.js b/addons/web/static/src/views/fields/pdf_viewer/pdf_viewer_field.js index a8561b0c982..e629d5cad51 100644 --- a/addons/web/static/src/views/fields/pdf_viewer/pdf_viewer_field.js +++ b/addons/web/static/src/views/fields/pdf_viewer/pdf_viewer_field.js @@ -10,6 +10,16 @@ import { FileUploader } from "../file_handler"; import { Component, onWillUpdateProps, useState } from "@odoo/owl"; export class PdfViewerField extends Component { + static template = "web.PdfViewerField"; + static components = { + FileUploader, + }; + static props = { + ...standardFieldProps, + fileNameField: { type: String, optional: true }, + previewImage: { type: String, optional: true }, + }; + setup() { this.notification = useService("notification"); this.state = useState({ @@ -75,24 +85,14 @@ export class PdfViewerField extends Component { } } -PdfViewerField.template = "web.PdfViewerField"; -PdfViewerField.components = { - FileUploader, -}; -PdfViewerField.props = { - ...standardFieldProps, - fileNameField: { type: String, optional: true }, - previewImage: { type: String, optional: true }, -}; - -PdfViewerField.displayName = _lt("PDF Viewer"); -PdfViewerField.supportedTypes = ["binary"]; - -PdfViewerField.extractProps = ({ attrs }) => { - return { +export const pdfViewerField = { + component: PdfViewerField, + displayName: _lt("PDF Viewer"), + supportedTypes: ["binary"], + extractProps: ({ attrs }) => ({ fileNameField: attrs.filename, previewImage: attrs.options.preview_image, - }; + }), }; -registry.category("fields").add("pdf_viewer", PdfViewerField); +registry.category("fields").add("pdf_viewer", pdfViewerField); diff --git a/addons/web/static/src/views/fields/percent_pie/percent_pie_field.js b/addons/web/static/src/views/fields/percent_pie/percent_pie_field.js index bf53f3cf50a..64c2de3bfae 100644 --- a/addons/web/static/src/views/fields/percent_pie/percent_pie_field.js +++ b/addons/web/static/src/views/fields/percent_pie/percent_pie_field.js @@ -7,6 +7,12 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class PercentPieField extends Component { + static template = "web.PercentPieField"; + static props = { + ...standardFieldProps, + string: { type: String, optional: true }, + }; + get transform() { const rotateDeg = (360 * this.props.value) / 100; return { @@ -17,20 +23,14 @@ export class PercentPieField extends Component { } } -PercentPieField.template = "web.PercentPieField"; -PercentPieField.props = { - ...standardFieldProps, - string: { type: String, optional: true }, -}; - -PercentPieField.displayName = _lt("PercentPie"); -PercentPieField.supportedTypes = ["float", "integer"]; - -PercentPieField.extractProps = ({ attrs }) => { - return { +export const percentPieField = { + component: PercentPieField, + displayName: _lt("PercentPie"), + supportedTypes: ["float", "integer"], + additionalClasses: ["o_field_percent_pie"], + extractProps: ({ attrs }) => ({ string: attrs.string, - }; + }), }; -PercentPieField.additionalClasses = ["o_field_percent_pie"]; -registry.category("fields").add("percentpie", PercentPieField); +registry.category("fields").add("percentpie", percentPieField); diff --git a/addons/web/static/src/views/fields/percentage/percentage_field.js b/addons/web/static/src/views/fields/percentage/percentage_field.js index 84649231e16..31eeb18c009 100644 --- a/addons/web/static/src/views/fields/percentage/percentage_field.js +++ b/addons/web/static/src/views/fields/percentage/percentage_field.js @@ -11,6 +11,13 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class PercentageField extends Component { + static template = "web.PercentageField"; + static props = { + ...standardFieldProps, + digits: { type: Array, optional: true }, + placeholder: { type: String, optional: true }, + }; + setup() { useInputField({ getValue: () => @@ -31,29 +38,27 @@ export class PercentageField extends Component { } } -PercentageField.template = "web.PercentageField"; -PercentageField.props = { - ...standardFieldProps, - digits: { type: Array, optional: true }, - placeholder: { type: String, optional: true }, +export const percentageField = { + component: PercentageField, + displayName: _lt("Percentage"), + supportedTypes: ["integer", "float"], + extractProps: ({ attrs, field }) => { + // Sadly, digits param was available as an option and an attr. + // The option version could be removed with some xml refactoring. + let digits; + if (attrs.digits) { + digits = JSON.parse(attrs.digits); + } else if (attrs.options.digits) { + digits = attrs.options.digits; + } else if (Array.isArray(field.digits)) { + digits = field.digits; + } + + return { + digits, + placeholder: attrs.placeholder, + }; + }, }; -PercentageField.displayName = _lt("Percentage"); -PercentageField.supportedTypes = ["integer", "float"]; - -PercentageField.extractProps = ({ attrs, field }) => { - let digits; - if (attrs.digits) { - digits = JSON.parse(attrs.digits); - } else if (attrs.options.digits) { - digits = attrs.options.digits; - } else if (Array.isArray(field.digits)) { - digits = field.digits; - } - return { - digits, - placeholder: attrs.placeholder, - }; -}; - -registry.category("fields").add("percentage", PercentageField); +registry.category("fields").add("percentage", percentageField); diff --git a/addons/web/static/src/views/fields/phone/phone_field.js b/addons/web/static/src/views/fields/phone/phone_field.js index 6ba836d5f32..b40dde5e190 100644 --- a/addons/web/static/src/views/fields/phone/phone_field.js +++ b/addons/web/static/src/views/fields/phone/phone_field.js @@ -8,28 +8,35 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class PhoneField extends Component { + static template = "web.PhoneField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + }; + setup() { useInputField({ getValue: () => this.props.value || "" }); } } -PhoneField.template = "web.PhoneField"; -PhoneField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, -}; - -PhoneField.displayName = _lt("Phone"); -PhoneField.supportedTypes = ["char"]; - -PhoneField.extractProps = ({ attrs }) => { - return { +export const phoneField = { + component: PhoneField, + displayName: _lt("Phone"), + supportedTypes: ["char"], + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder, - }; + }), }; -class FormPhoneField extends PhoneField {} -FormPhoneField.template = "web.FormPhoneField"; +registry.category("fields").add("phone", phoneField); -registry.category("fields").add("phone", PhoneField); -registry.category("fields").add("form.phone", FormPhoneField); +class FormPhoneField extends PhoneField { + static template = "web.FormPhoneField"; +} + +export const formPhoneField = { + ...phoneField, + component: FormPhoneField, +}; + +registry.category("fields").add("form.phone", formPhoneField); diff --git a/addons/web/static/src/views/fields/priority/priority_field.js b/addons/web/static/src/views/fields/priority/priority_field.js index b73edc079b6..31925f27153 100644 --- a/addons/web/static/src/views/fields/priority/priority_field.js +++ b/addons/web/static/src/views/fields/priority/priority_field.js @@ -8,6 +8,12 @@ import { standardFieldProps } from "../standard_field_props"; import { Component, useState } from "@odoo/owl"; export class PriorityField extends Component { + static template = "web.PriorityField"; + static props = { + ...standardFieldProps, + tooltipLabel: { type: String, optional: true }, + }; + setup() { this.state = useState({ index: -1, @@ -50,7 +56,9 @@ export class PriorityField extends Component { } getTooltip(value) { - return this.props.tooltipLabel && this.props.tooltipLabel !== value ? `${this.props.tooltipLabel}: ${value}` : value; + return this.props.tooltipLabel && this.props.tooltipLabel !== value + ? `${this.props.tooltipLabel}: ${value}` + : value; } /** * @param {string} value @@ -65,19 +73,13 @@ export class PriorityField extends Component { } } -PriorityField.template = "web.PriorityField"; -PriorityField.props = { - ...standardFieldProps, - tooltipLabel: { type: String, optional: true }, -}; - -PriorityField.displayName = _lt("Priority"); -PriorityField.supportedTypes = ["selection"]; - -PriorityField.extractProps = ({ field }) => { - return { +export const priorityField = { + component: PriorityField, + displayName: _lt("Priority"), + supportedTypes: ["selection"], + extractProps: ({ field }) => ({ tooltipLabel: field.string, - }; + }), }; -registry.category("fields").add("priority", PriorityField); +registry.category("fields").add("priority", priorityField); diff --git a/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js b/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js index 470d8bf67ff..18921386b25 100644 --- a/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js +++ b/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { ProgressBarField } from "./progress_bar_field"; +import { progressBarField, ProgressBarField } from "./progress_bar_field"; export class KanbanProgressBarField extends ProgressBarField { onClick() { @@ -11,4 +11,9 @@ export class KanbanProgressBarField extends ProgressBarField { } } -registry.category("fields").add("kanban.progressbar", KanbanProgressBarField); +export const kanbanProgressBarField = { + ...progressBarField, + component: KanbanProgressBarField, +}; + +registry.category("fields").add("kanban.progressbar", kanbanProgressBarField); diff --git a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js index 89a044ba53e..c9861843f01 100644 --- a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js +++ b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js @@ -12,6 +12,18 @@ const formatters = registry.category("formatters"); const parsers = registry.category("parsers"); export class ProgressBarField extends Component { + static template = "web.ProgressBarField"; + static props = { + ...standardFieldProps, + maxValueField: { type: [String, Number], optional: true }, + currentValueField: { type: String, optional: true }, + isEditable: { type: Boolean, optional: true }, + isEditableInReadonly: { type: Boolean, optional: true }, + isCurrentValueEditable: { type: Boolean, optional: true }, + isMaxValueEditable: { type: Boolean, optional: true }, + title: { type: String, optional: true }, + }; + setup() { useNumpadDecimal(); useAutofocus({ refName: "maxValue", selectAll: true }); @@ -139,23 +151,11 @@ export class ProgressBarField extends Component { } } -ProgressBarField.template = "web.ProgressBarField"; -ProgressBarField.props = { - ...standardFieldProps, - maxValueField: { type: [String, Number], optional: true }, - currentValueField: { type: String, optional: true }, - isEditable: { type: Boolean, optional: true }, - isEditableInReadonly: { type: Boolean, optional: true }, - isCurrentValueEditable: { type: Boolean, optional: true }, - isMaxValueEditable: { type: Boolean, optional: true }, - title: { type: String, optional: true }, -}; - -ProgressBarField.displayName = _lt("Progress Bar"); -ProgressBarField.supportedTypes = ["integer", "float"]; - -ProgressBarField.extractProps = ({ attrs }) => { - return { +export const progressBarField = { + component: ProgressBarField, + displayName: _lt("Progress Bar"), + supportedTypes: ["integer", "float"], + extractProps: ({ attrs }) => ({ maxValueField: attrs.options.max_value, currentValueField: attrs.options.current_value, isEditable: !attrs.options.readonly && attrs.options.editable, @@ -165,7 +165,7 @@ ProgressBarField.extractProps = ({ attrs }) => { (!attrs.options.edit_max_value || attrs.options.edit_current_value), isMaxValueEditable: attrs.options.editable && attrs.options.edit_max_value, title: attrs.title, - }; + }), }; -registry.category("fields").add("progressbar", ProgressBarField); +registry.category("fields").add("progressbar", progressBarField); diff --git a/addons/web/static/src/views/fields/properties/kanban_properties_field.js b/addons/web/static/src/views/fields/properties/kanban_properties_field.js index 9f1fc265d80..8748b890012 100644 --- a/addons/web/static/src/views/fields/properties/kanban_properties_field.js +++ b/addons/web/static/src/views/fields/properties/kanban_properties_field.js @@ -1,15 +1,20 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { PropertiesField } from "./properties_field"; +import { propertiesField, PropertiesField } from "./properties_field"; export class KanbanPropertiesField extends PropertiesField { + static template = "web.KanbanPropertiesField"; + async _checkDefinitionAccess() { // can not edit properties definition in the kanban view this.state.canChangeDefinition = false; } } -KanbanPropertiesField.template = "web.KanbanPropertiesField"; +export const kanbanPropertiesField = { + ...propertiesField, + component: KanbanPropertiesField, +}; -registry.category("fields").add("kanban.properties", KanbanPropertiesField); +registry.category("fields").add("kanban.properties", kanbanPropertiesField); diff --git a/addons/web/static/src/views/fields/properties/properties_field.js b/addons/web/static/src/views/fields/properties/properties_field.js index 6f13111ff20..2fffc5ee913 100644 --- a/addons/web/static/src/views/fields/properties/properties_field.js +++ b/addons/web/static/src/views/fields/properties/properties_field.js @@ -18,6 +18,19 @@ import { archParseBoolean } from "@web/views/utils"; import { Component, useRef, useState, useEffect, onWillStart } from "@odoo/owl"; export class PropertiesField extends Component { + static template = "web.PropertiesField"; + static components = { + Dropdown, + DropdownItem, + PropertyDefinition, + PropertyValue, + }; + static props = { + ...standardFieldProps, + columns: { type: Number, optional: true }, + hideKanbanOption: { type: Boolean, optional: true }, + }; + setup() { this.notification = useService("notification"); this.orm = useService("orm"); @@ -484,25 +497,14 @@ export class PropertiesField extends Component { } } -PropertiesField.template = "web.PropertiesField"; -PropertiesField.components = { - Dropdown, - DropdownItem, - PropertyDefinition, - PropertyValue, -}; -PropertiesField.props = { - ...standardFieldProps, - columns: { type: Number, optional: true }, - hideKanbanOption: { type: Boolean, optional: true }, -}; -PropertiesField.extractProps = ({ attrs, field }) => { - const columns = parseInt(attrs.columns || "1"); - const hideKanbanOption = archParseBoolean(attrs.hideKanbanOption); - return { columns, hideKanbanOption }; +export const propertiesField = { + component: PropertiesField, + displayName: _lt("Properties"), + supportedTypes: ["properties"], + extractProps: ({ attrs }) => ({ + columns: parseInt(attrs.columns || "1"), + hideKanbanOption: archParseBoolean(attrs.hideKanbanOption), + }), }; -PropertiesField.displayName = _lt("Properties"); -PropertiesField.supportedTypes = ["properties"]; - -registry.category("fields").add("properties", PropertiesField); +registry.category("fields").add("properties", propertiesField); diff --git a/addons/web/static/src/views/fields/radio/radio_field.js b/addons/web/static/src/views/fields/radio/radio_field.js index 7c52098a7e0..9f0630d73c2 100644 --- a/addons/web/static/src/views/fields/radio/radio_field.js +++ b/addons/web/static/src/views/fields/radio/radio_field.js @@ -7,6 +7,30 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class RadioField extends Component { + static template = "web.RadioField"; + static props = { + ...standardFieldProps, + orientation: { type: String, optional: true }, + }; + static defaultProps = { + orientation: "vertical", + }; + + static nextId = 0; + + static getItems(fieldName, record) { + switch (record.fields[fieldName].type) { + case "selection": + return record.fields[fieldName].selection; + case "many2one": { + const value = record.preloadedData[fieldName] || []; + return value.map((item) => [item.id, item.display_name]); + } + default: + return []; + } + } + setup() { this.id = `radio_field_${++RadioField.nextId}`; } @@ -43,42 +67,18 @@ export class RadioField extends Component { } } -RadioField.nextId = 0; - -RadioField.template = "web.RadioField"; -RadioField.props = { - ...standardFieldProps, - orientation: { type: String, optional: true }, -}; -RadioField.defaultProps = { - orientation: "vertical", -}; - -RadioField.displayName = _lt("Radio"); -RadioField.supportedTypes = ["many2one", "selection"]; -RadioField.legacySpecialData = "_fetchSpecialMany2ones"; - -RadioField.isEmpty = (record, fieldName) => record.data[fieldName] === false; -RadioField.extractProps = ({ attrs }) => { - return { +export const radioField = { + component: RadioField, + displayName: _lt("Radio"), + supportedTypes: ["many2one", "selection"], + isEmpty: (record, fieldName) => record.data[fieldName] === false, + extractProps: ({ attrs }) => ({ orientation: attrs.options.horizontal ? "horizontal" : "vertical", - }; + }), + legacySpecialData: "_fetchSpecialMany2ones", }; -RadioField.getItems = (fieldName, record) => { - switch (record.fields[fieldName].type) { - case "selection": - return record.fields[fieldName].selection; - case "many2one": { - const value = record.preloadedData[fieldName] || []; - return value.map((item) => [item.id, item.display_name]); - } - default: - return []; - } -}; - -registry.category("fields").add("radio", RadioField); +registry.category("fields").add("radio", radioField); export async function preloadRadio(orm, record, fieldName) { const field = record.fields[fieldName]; diff --git a/addons/web/static/src/views/fields/reference/reference_field.js b/addons/web/static/src/views/fields/reference/reference_field.js index 4f273212364..336e6a730d4 100644 --- a/addons/web/static/src/views/fields/reference/reference_field.js +++ b/addons/web/static/src/views/fields/reference/reference_field.js @@ -2,7 +2,7 @@ import { _lt } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; -import { Many2OneField } from "../many2one/many2one_field"; +import { many2OneField, Many2OneField } from "../many2one/many2one_field"; import { Component, onWillUpdateProps, useState } from "@odoo/owl"; @@ -11,6 +11,18 @@ function valuesEqual(a, b) { } export class ReferenceField extends Component { + static template = "web.ReferenceField"; + static components = { + Many2OneField, + }; + static props = { + ...Many2OneField.props, + hideModelSelector: { type: Boolean, optional: true }, + }; + static defaultProps = { + ...Many2OneField.defaultProps, + }; + setup() { this.state = useState({ resModel: this.relation, @@ -107,36 +119,24 @@ export class ReferenceField extends Component { } } -ReferenceField.template = "web.ReferenceField"; -ReferenceField.components = { - Many2OneField, -}; -ReferenceField.props = { - ...Many2OneField.props, - hideModelSelector: { type: Boolean, optional: true }, -}; -ReferenceField.defaultProps = { - ...Many2OneField.defaultProps, +export const referenceField = { + component: ReferenceField, + displayName: _lt("Reference"), + supportedTypes: ["reference", "char"], + legacySpecialData: "_fetchSpecialReference", + extractProps: (params) => ({ + /* + 1 - + 2 - + 3 - + 4 - + + We want to display the model selector only in the 4th case. + */ + ...many2OneField.extractProps(params), + hideModelSelector: + !!params.attrs.options["hide_model"] || !!params.attrs.options["model_field"], + }), }; -ReferenceField.displayName = _lt("Reference"); -ReferenceField.supportedTypes = ["reference", "char"]; -ReferenceField.legacySpecialData = "_fetchSpecialReference"; - -ReferenceField.extractProps = ({ attrs, field }) => { - /* - 1 - - 2 - - 3 - - 4 - - - We want to display the model selector only in the 4th case. - */ - const displayModelSelector = !attrs.options["hide_model"] && !attrs.options["model_field"]; - return { - ...Many2OneField.extractProps({ attrs, field }), - hideModelSelector: !displayModelSelector, - }; -}; - -registry.category("fields").add("reference", ReferenceField); +registry.category("fields").add("reference", referenceField); diff --git a/addons/web/static/src/views/fields/remaining_days/remaining_days_field.js b/addons/web/static/src/views/fields/remaining_days/remaining_days_field.js index 01d851abc35..c3f83258216 100644 --- a/addons/web/static/src/views/fields/remaining_days/remaining_days_field.js +++ b/addons/web/static/src/views/fields/remaining_days/remaining_days_field.js @@ -10,6 +10,11 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class RemainingDaysField extends Component { + static template = "web.RemainingDaysField"; + static props = { + ...standardFieldProps, + }; + get hasTime() { return this.props.type === "datetime"; } @@ -42,12 +47,10 @@ export class RemainingDaysField extends Component { } } -RemainingDaysField.template = "web.RemainingDaysField"; -RemainingDaysField.props = { - ...standardFieldProps, +export const remainingDaysField = { + component: RemainingDaysField, + displayName: _lt("Remaining Days"), + supportedTypes: ["date", "datetime"], }; -RemainingDaysField.displayName = _lt("Remaining Days"); -RemainingDaysField.supportedTypes = ["date", "datetime"]; - -registry.category("fields").add("remaining_days", RemainingDaysField); +registry.category("fields").add("remaining_days", remainingDaysField); diff --git a/addons/web/static/src/views/fields/selection/selection_field.js b/addons/web/static/src/views/fields/selection/selection_field.js index e13ee37ea6f..911bc7813cf 100644 --- a/addons/web/static/src/views/fields/selection/selection_field.js +++ b/addons/web/static/src/views/fields/selection/selection_field.js @@ -7,6 +7,12 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class SelectionField extends Component { + static template = "web.SelectionField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + }; + get options() { switch (this.props.record.fields[this.props.name].type) { case "many2one": @@ -63,24 +69,18 @@ export class SelectionField extends Component { } } -SelectionField.template = "web.SelectionField"; -SelectionField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, -}; - -SelectionField.displayName = _lt("Selection"); -SelectionField.supportedTypes = ["many2one", "selection"]; -SelectionField.legacySpecialData = "_fetchSpecialRelation"; - -SelectionField.isEmpty = (record, fieldName) => record.data[fieldName] === false; -SelectionField.extractProps = ({ attrs }) => { - return { +export const selectionField = { + component: SelectionField, + displayName: _lt("Selection"), + supportedTypes: ["many2one", "selection"], + legacySpecialData: "_fetchSpecialRelation", + isEmpty: (record, fieldName) => record.data[fieldName] === false, + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder, - }; + }), }; -registry.category("fields").add("selection", SelectionField); +registry.category("fields").add("selection", selectionField); export function preloadSelection(orm, record, fieldName) { const field = record.fields[fieldName]; diff --git a/addons/web/static/src/views/fields/signature/signature_field.js b/addons/web/static/src/views/fields/signature/signature_field.js index 49b8322e3f2..7740a74658b 100644 --- a/addons/web/static/src/views/fields/signature/signature_field.js +++ b/addons/web/static/src/views/fields/signature/signature_field.js @@ -13,6 +13,16 @@ import { Component, onWillUpdateProps, useState } from "@odoo/owl"; const placeholder = "/web/static/img/placeholder.png"; export class SignatureField extends Component { + static template = "web.SignatureField"; + static props = { + ...standardFieldProps, + defaultFont: { type: String }, + fullName: { type: String, optional: true }, + height: { type: Number, optional: true }, + previewImage: { type: String, optional: true }, + width: { type: Number, optional: true }, + }; + setup() { this.displaySignatureRatio = 3; @@ -124,24 +134,15 @@ export class SignatureField extends Component { } } -SignatureField.template = "web.SignatureField"; -SignatureField.props = { - ...standardFieldProps, - defaultFont: { type: String }, - fullName: { type: String, optional: true }, - height: { type: Number, optional: true }, - previewImage: { type: String, optional: true }, - width: { type: Number, optional: true }, -}; -SignatureField.extractProps = ({ attrs }) => { - const { options, width, height } = attrs; - return { +export const signatureField = { + component: SignatureField, + extractProps: ({ attrs }) => ({ defaultFont: attrs.options.default_font || "", fullName: attrs.options.full_name, - height: options.size ? options.size[1] || undefined : height, + height: attrs.options.size ? attrs.options.size[1] || undefined : attrs.height, previewImage: attrs.options.preview_image, - width: options.size ? options.size[0] || undefined : width, - }; + width: attrs.options.size ? attrs.options.size[0] || undefined : attrs.width, + }), }; -registry.category("fields").add("signature", SignatureField); +registry.category("fields").add("signature", signatureField); diff --git a/addons/web/static/src/views/fields/stat_info/stat_info_field.js b/addons/web/static/src/views/fields/stat_info/stat_info_field.js index bba74cc8a03..8ce27a91e22 100644 --- a/addons/web/static/src/views/fields/stat_info/stat_info_field.js +++ b/addons/web/static/src/views/fields/stat_info/stat_info_field.js @@ -9,6 +9,14 @@ import { Component } from "@odoo/owl"; const formatters = registry.category("formatters"); export class StatInfoField extends Component { + static template = "web.StatInfoField"; + static props = { + ...standardFieldProps, + labelField: { type: String, optional: true }, + noLabel: { type: Boolean, optional: true }, + digits: { type: Array, optional: true }, + }; + get formattedValue() { const formatter = formatters.get(this.props.type); return formatter(this.props.value || 0, { digits: this.props.digits }); @@ -20,32 +28,29 @@ export class StatInfoField extends Component { } } -StatInfoField.template = "web.StatInfoField"; -StatInfoField.props = { - ...standardFieldProps, - labelField: { type: String, optional: true }, - noLabel: { type: Boolean, optional: true }, - digits: { type: Array, optional: true }, +export const statInfoField = { + component: StatInfoField, + displayName: _lt("Stat Info"), + supportedTypes: ["float", "integer", "monetary"], + isEmpty: () => false, + extractProps: ({ attrs, field }) => { + // Sadly, digits param was available as an option and an attr. + // The option version could be removed with some xml refactoring. + let digits; + if (attrs.digits) { + digits = JSON.parse(attrs.digits); + } else if (attrs.options.digits) { + digits = attrs.options.digits; + } else if (Array.isArray(field.digits)) { + digits = field.digits; + } + + return { + digits, + labelField: attrs.options.label_field, + noLabel: archParseBoolean(attrs.nolabel), + }; + }, }; -StatInfoField.displayName = _lt("Stat Info"); -StatInfoField.supportedTypes = ["float", "integer", "monetary"]; - -StatInfoField.isEmpty = () => false; -StatInfoField.extractProps = ({ attrs, field }) => { - let digits; - if (attrs.digits) { - digits = JSON.parse(attrs.digits); - } else if (attrs.options.digits) { - digits = attrs.options.digits; - } else if (Array.isArray(field.digits)) { - digits = field.digits; - } - return { - labelField: attrs.options.label_field, - noLabel: archParseBoolean(attrs.nolabel), - digits, - }; -}; - -registry.category("fields").add("statinfo", StatInfoField); +registry.category("fields").add("statinfo", statInfoField); diff --git a/addons/web/static/src/views/fields/state_selection/state_selection_field.js b/addons/web/static/src/views/fields/state_selection/state_selection_field.js index fad3364c409..0779990c73c 100644 --- a/addons/web/static/src/views/fields/state_selection/state_selection_field.js +++ b/addons/web/static/src/views/fields/state_selection/state_selection_field.js @@ -11,6 +11,19 @@ import { formatSelection } from "../formatters"; import { Component } from "@odoo/owl"; export class StateSelectionField extends Component { + static template = "web.StateSelectionField"; + static components = { + Dropdown, + DropdownItem, + }; + static props = { + ...standardFieldProps, + hideLabel: { type: Boolean, optional: true }, + }; + static defaultProps = { + hideLabel: false, + }; + setup() { this.colorPrefix = "o_status_"; this.colors = { @@ -65,27 +78,14 @@ export class StateSelectionField extends Component { } } -StateSelectionField.template = "web.StateSelectionField"; -StateSelectionField.components = { - Dropdown, - DropdownItem, -}; -StateSelectionField.props = { - ...standardFieldProps, - hideLabel: { type: Boolean, optional: true }, -}; -StateSelectionField.defaultProps = { - hideLabel: false, -}; - -StateSelectionField.displayName = _lt("Label Selection"); -StateSelectionField.supportedTypes = ["selection"]; - -StateSelectionField.extractProps = ({ attrs }) => { - return { +export const stateSelectionField = { + component: StateSelectionField, + displayName: _lt("Label Selection"), + supportedTypes: ["selection"], + extractProps: ({ attrs }) => ({ hideLabel: !!attrs.options.hide_label, - }; + }), }; -registry.category("fields").add("state_selection", StateSelectionField); -registry.category("fields").add("list.state_selection", StateSelectionField); +registry.category("fields").add("state_selection", stateSelectionField); +registry.category("fields").add("list.state_selection", stateSelectionField); diff --git a/addons/web/static/src/views/fields/statusbar/statusbar_field.js b/addons/web/static/src/views/fields/statusbar/statusbar_field.js index 83fb685ec0b..4131c280a65 100644 --- a/addons/web/static/src/views/fields/statusbar/statusbar_field.js +++ b/addons/web/static/src/views/fields/statusbar/statusbar_field.js @@ -12,6 +12,23 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class StatusBarField extends Component { + static template = "web.StatusBarField"; + static components = { + Dropdown, + DropdownItem, + }; + static props = { + ...standardFieldProps, + canCreate: { type: Boolean, optional: true }, + canWrite: { type: Boolean, optional: true }, + displayName: { type: String, optional: true }, + isDisabled: { type: Boolean, optional: true }, + visibleSelection: { type: Array, optional: true }, + }; + static defaultProps = { + visibleSelection: [], + }; + setup() { if (this.props.record.activeFields[this.props.name].viewType === "form") { const commandName = sprintf( @@ -78,7 +95,9 @@ export class StatusBarField extends Component { get currentName() { switch (this.type) { case "many2one": { - const item = this.options.find((item) => this.props.value && item.id === this.props.value[0]); + const item = this.options.find( + (item) => this.props.value && item.id === this.props.value[0] + ); return item ? item.display_name : ""; } case "selection": { @@ -188,42 +207,24 @@ export class StatusBarField extends Component { } } -StatusBarField.template = "web.StatusBarField"; -StatusBarField.defaultProps = { - visibleSelection: [], -}; -StatusBarField.props = { - ...standardFieldProps, - canCreate: { type: Boolean, optional: true }, - canWrite: { type: Boolean, optional: true }, - displayName: { type: String, optional: true }, - isDisabled: { type: Boolean, optional: true }, - visibleSelection: { type: Array, optional: true }, -}; -StatusBarField.components = { - Dropdown, - DropdownItem, -}; - -StatusBarField.displayName = _lt("Status"); -StatusBarField.supportedTypes = ["many2one", "selection"]; -StatusBarField.legacySpecialData = "_fetchSpecialStatus"; - -StatusBarField.isEmpty = (record, fieldName) => { - return record.model.env.isSmall ? !record.data[fieldName] : false; -}; -StatusBarField.extractProps = ({ attrs, field }) => { - return { +export const statusBarField = { + component: StatusBarField, + displayName: _lt("Status"), + supportedTypes: ["many2one", "selection"], + isEmpty: (record, fieldName) => record.model.env.isSmall && !record.data[fieldName], + legacySpecialData: "_fetchSpecialStatus", + extractProps: ({ attrs, field }) => ({ canCreate: Boolean(attrs.can_create), canWrite: Boolean(attrs.can_write), - displayName: field.string, isDisabled: !attrs.options.clickable, visibleSelection: attrs.statusbar_visible && attrs.statusbar_visible.trim().split(/\s*,\s*/g), - }; + + displayName: field.string, + }), }; -registry.category("fields").add("statusbar", StatusBarField); +registry.category("fields").add("statusbar", statusBarField); export async function preloadStatusBar(orm, record, fieldName) { const fieldNames = ["id", "display_name"]; diff --git a/addons/web/static/src/views/fields/text/text_field.js b/addons/web/static/src/views/fields/text/text_field.js index 33d73accfac..f43817ce93b 100644 --- a/addons/web/static/src/views/fields/text/text_field.js +++ b/addons/web/static/src/views/fields/text/text_field.js @@ -12,6 +12,22 @@ import { TranslationButton } from "../translation_button"; import { Component, onMounted, onWillUnmount, useEffect, useRef } from "@odoo/owl"; export class TextField extends Component { + static template = "web.TextField"; + static components = { + TranslationButton, + }; + static props = { + ...standardFieldProps, + isTranslatable: { type: Boolean, optional: true }, + placeholder: { type: String, optional: true }, + dynamicPlaceholder: { type: Boolean, optional: true }, + rowCount: { type: Number, optional: true }, + }; + static defaultProps = { + dynamicPlaceholder: false, + rowCount: 2, + }; + setup() { if (this.props.dynamicPlaceholder) { this.dynamicPlaceholder = useDynamicPlaceholder(); @@ -105,40 +121,27 @@ export class TextField extends Component { } } -TextField.template = "web.TextField"; -TextField.components = { - TranslationButton, -}; -TextField.defaultProps = { - dynamicPlaceholder: false, - rowCount: 2, -}; -TextField.props = { - ...standardFieldProps, - isTranslatable: { type: Boolean, optional: true }, - placeholder: { type: String, optional: true }, - dynamicPlaceholder: { type: Boolean, optional: true }, - rowCount: { type: Number, optional: true }, -}; - -TextField.displayName = _lt("Multiline Text"); -TextField.supportedTypes = ["html", "text"]; - -TextField.extractProps = ({ attrs, field }) => { - const props = { - isTranslatable: field.translate, +export const textField = { + component: TextField, + displayName: _lt("Multiline Text"), + supportedTypes: ["html", "text"], + extractProps: ({ attrs, field }) => ({ placeholder: attrs.placeholder, dynamicPlaceholder: attrs.options.dynamic_placeholder, - }; - if (attrs.rows) { - props.rowCount = parseInteger(attrs.rows); - } - return props; + rowCount: attrs.rows && parseInteger(attrs.rows), + + isTranslatable: field.translate, + }), }; -registry.category("fields").add("text", TextField); +registry.category("fields").add("text", textField); export class ListTextField extends TextField { + static defaultProps = { + ...super.defaultProps, + rowCount: 1, + }; + get minimumHeight() { return 0; } @@ -146,9 +149,10 @@ export class ListTextField extends TextField { return this.props.rowCount; } } -ListTextField.defaultProps = { - ...TextField.defaultProps, - rowCount: 1, + +export const listTextField = { + ...textField, + component: ListTextField, }; -registry.category("fields").add("list.text", ListTextField); +registry.category("fields").add("list.text", listTextField); diff --git a/addons/web/static/src/views/fields/timezone_mismatch/timezone_mismatch_field.js b/addons/web/static/src/views/fields/timezone_mismatch/timezone_mismatch_field.js index 2f8b2f2e5d6..5fcd79d2273 100644 --- a/addons/web/static/src/views/fields/timezone_mismatch/timezone_mismatch_field.js +++ b/addons/web/static/src/views/fields/timezone_mismatch/timezone_mismatch_field.js @@ -3,11 +3,25 @@ import { formatDateTime } from "@web/core/l10n/dates"; import { _lt } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; -import { SelectionField } from "../selection/selection_field"; +import { selectionField, SelectionField } from "../selection/selection_field"; const { DateTime } = luxon; export class TimezoneMismatchField extends SelectionField { + static template = "web.TimezoneMismatchField"; + static props = { + ...super.props, + tzOffsetField: { type: String, optional: true }, + mismatchTitle: { type: String, optional: true }, + }; + static defaultProps = { + ...super.defaultProps, + tzOffsetField: "tz_offset", + mismatchTitle: _lt( + "Timezone Mismatch : This timezone is different from that of your browser.\nPlease, set the same timezone as your browser's to avoid time discrepancies in your system." + ), + }; + get mismatch() { const userOffset = this.props.record.data[this.props.tzOffsetField]; if (userOffset && this.props.value) { @@ -56,26 +70,15 @@ export class TimezoneMismatchField extends SelectionField { } } -TimezoneMismatchField.template = "web.TimezoneMismatchField"; -TimezoneMismatchField.additionalClasses = ["d-flex"]; -TimezoneMismatchField.props = { - ...SelectionField.props, - tzOffsetField: { type: String, optional: true }, - mismatchTitle: { type: String, optional: true }, -}; -TimezoneMismatchField.defaultProps = { - ...SelectionField.defaultProps, - tzOffsetField: "tz_offset", - mismatchTitle: _lt( - "Timezone Mismatch : This timezone is different from that of your browser.\nPlease, set the same timezone as your browser's to avoid time discrepancies in your system." - ), -}; -TimezoneMismatchField.extractProps = ({ attrs }) => { - return { - ...SelectionField.extractProps({ attrs }), - tzOffsetField: attrs.options.tz_offset_field, - mismatchTitle: attrs.options.mismatch_title, - }; +export const timezoneMismatchField = { + ...selectionField, + component: TimezoneMismatchField, + additionalClasses: ["d-flex"], + extractProps: (params) => ({ + ...selectionField.extractProps(params), + tzOffsetField: params.attrs.options.tz_offset_field, + mismatchTitle: params.attrs.options.mismatch_title, + }), }; -registry.category("fields").add("timezone_mismatch", TimezoneMismatchField); +registry.category("fields").add("timezone_mismatch", timezoneMismatchField); diff --git a/addons/web/static/src/views/fields/url/url_field.js b/addons/web/static/src/views/fields/url/url_field.js index 5de41383054..88194ad8c94 100644 --- a/addons/web/static/src/views/fields/url/url_field.js +++ b/addons/web/static/src/views/fields/url/url_field.js @@ -8,6 +8,14 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class UrlField extends Component { + static template = "web.UrlField"; + static props = { + ...standardFieldProps, + placeholder: { type: String, optional: true }, + text: { type: String, optional: true }, + websitePath: { type: Boolean, optional: true }, + }; + setup() { useInputField({ getValue: () => this.props.value || "" }); } @@ -26,27 +34,26 @@ export class UrlField extends Component { } } -UrlField.template = "web.UrlField"; -UrlField.props = { - ...standardFieldProps, - placeholder: { type: String, optional: true }, - text: { type: String, optional: true }, - websitePath: { type: Boolean, optional: true }, -}; - -UrlField.displayName = _lt("URL"); -UrlField.supportedTypes = ["char"]; - -UrlField.extractProps = ({ attrs }) => { - return { +export const urlField = { + component: UrlField, + displayName: _lt("URL"), + supportedTypes: ["char"], + extractProps: ({ attrs }) => ({ text: attrs.text, websitePath: attrs.options.website_path, placeholder: attrs.placeholder, - }; + }), }; -class FormUrlField extends UrlField {} -FormUrlField.template = "web.FormUrlField"; +registry.category("fields").add("url", urlField); -registry.category("fields").add("url", UrlField); -registry.category("fields").add("form.url", FormUrlField); +class FormUrlField extends UrlField { + static template = "web.FormUrlField"; +} + +export const formUrlField = { + ...urlField, + component: FormUrlField, +}; + +registry.category("fields").add("form.url", formUrlField); diff --git a/addons/web/static/src/views/fields/x2many/list_x2many_field.js b/addons/web/static/src/views/fields/x2many/list_x2many_field.js index 274a98fc6d2..b993954149a 100644 --- a/addons/web/static/src/views/fields/x2many/list_x2many_field.js +++ b/addons/web/static/src/views/fields/x2many/list_x2many_field.js @@ -7,15 +7,18 @@ import { standardFieldProps } from "../standard_field_props"; import { Component } from "@odoo/owl"; export class ListX2ManyField extends Component { + static template = "web.ListX2ManyField"; + static props = { ...standardFieldProps }; + get formattedValue() { return formatX2many(this.props.value); } } -ListX2ManyField.template = "web.ListX2ManyField"; -ListX2ManyField.props = { ...standardFieldProps }; +export const listX2ManyField = { + component: ListX2ManyField, + useSubView: false, +}; -ListX2ManyField.useSubView = false; - -registry.category("fields").add("list.one2many", ListX2ManyField); -registry.category("fields").add("list.many2many", ListX2ManyField); +registry.category("fields").add("list.one2many", listX2ManyField); +registry.category("fields").add("list.many2many", listX2ManyField); diff --git a/addons/web/static/src/views/fields/x2many/x2many_field.js b/addons/web/static/src/views/fields/x2many/x2many_field.js index ae4a0d07f95..94525578ad2 100644 --- a/addons/web/static/src/views/fields/x2many/x2many_field.js +++ b/addons/web/static/src/views/fields/x2many/x2many_field.js @@ -21,6 +21,14 @@ import { ViewButton } from "@web/views/view_button/view_button"; import { Component } from "@odoo/owl"; export class X2ManyField extends Component { + static template = "web.X2ManyField"; + static components = { Pager, KanbanRenderer, ListRenderer, ViewButton }; + static props = { + ...standardFieldProps, + addLabel: { type: String, optional: true }, + editable: { type: String, optional: true }, + }; + setup() { this.activeField = this.props.record.activeFields[this.props.name]; this.field = this.props.record.fields[this.props.name]; @@ -244,21 +252,16 @@ export class X2ManyField extends Component { } } } -X2ManyField.components = { Pager, KanbanRenderer, ListRenderer, ViewButton }; -X2ManyField.props = { - ...standardFieldProps, - addLabel: { type: String, optional: true }, - editable: { type: String, optional: true }, -}; -X2ManyField.supportedTypes = ["one2many", "many2many"]; -X2ManyField.displayName = _lt("Relational table"); -X2ManyField.template = "web.X2ManyField"; -X2ManyField.useSubView = true; -X2ManyField.extractProps = ({ attrs }) => { - return { + +export const x2ManyField = { + component: X2ManyField, + displayName: _lt("Relational table"), + supportedTypes: ["one2many", "many2many"], + useSubView: true, + extractProps: ({ attrs }) => ({ addLabel: attrs["add-label"], - }; + }), }; -registry.category("fields").add("one2many", X2ManyField); -registry.category("fields").add("many2many", X2ManyField); +registry.category("fields").add("one2many", x2ManyField); +registry.category("fields").add("many2many", x2ManyField); diff --git a/addons/web/static/src/views/form/form_arch_parser.js b/addons/web/static/src/views/form/form_arch_parser.js index 002d439d3bc..81779e07a76 100644 --- a/addons/web/static/src/views/form/form_arch_parser.js +++ b/addons/web/static/src/views/form/form_arch_parser.js @@ -32,7 +32,7 @@ export class FormArchParser extends XMLParser { addFieldDependencies( activeFields, models[modelName], - fieldInfo.FieldComponent.fieldDependencies + fieldInfo.field.fieldDependencies ); return false; } else if (node.tagName === "div" && node.classList.contains("oe_chatter")) { diff --git a/addons/web/static/src/views/form/form_controller.js b/addons/web/static/src/views/form/form_controller.js index d0397f1db47..211b04ab97e 100644 --- a/addons/web/static/src/views/form/form_controller.js +++ b/addons/web/static/src/views/form/form_controller.js @@ -42,7 +42,7 @@ export async function loadSubViews( continue; // no need to fetch the sub view if the field is always invisible } - if (!fieldInfo.FieldComponent.useSubView) { + if (!fieldInfo.field.useSubView) { continue; // the FieldComponent used to render the field doesn't need a sub view } diff --git a/addons/web/static/src/views/form/form_label.js b/addons/web/static/src/views/form/form_label.js index a3025f435b3..f8e8d6b92ba 100644 --- a/addons/web/static/src/views/form/form_label.js +++ b/addons/web/static/src/views/form/form_label.js @@ -9,7 +9,7 @@ import { Component } from "@odoo/owl"; export class FormLabel extends Component { get className() { const { invalid, empty, readonly } = fieldVisualFeedback( - this.props.fieldInfo.FieldComponent, + this.props.fieldInfo.field, this.props.record, this.props.fieldName, this.props.fieldInfo diff --git a/addons/web/static/src/views/kanban/kanban_arch_parser.js b/addons/web/static/src/views/kanban/kanban_arch_parser.js index b3b16ced60b..42d0e849358 100644 --- a/addons/web/static/src/views/kanban/kanban_arch_parser.js +++ b/addons/web/static/src/views/kanban/kanban_arch_parser.js @@ -120,7 +120,7 @@ export class KanbanArchParser extends XMLParser { addFieldDependencies( activeFields, models[modelName], - fieldInfo.FieldComponent.fieldDependencies + fieldInfo.field.fieldDependencies ); } if (node.tagName === "widget") { diff --git a/addons/web/static/src/views/legacy_utils.js b/addons/web/static/src/views/legacy_utils.js index 3eb8bfa48e1..27c69d45586 100644 --- a/addons/web/static/src/views/legacy_utils.js +++ b/addons/web/static/src/views/legacy_utils.js @@ -73,12 +73,14 @@ export function mapActiveFieldsToFieldsInfo(activeFields, fields, viewType, env) fieldsInfo[viewType] = {}; for (const [fieldName, fieldDescr] of Object.entries(activeFields)) { const views = mapViews(fieldDescr.views, env); - const field = fields[fieldName]; let Widget; if (fieldDescr.widget) { Widget = fieldRegistry.getAny([`${viewType}.${fieldDescr.widget}`, fieldDescr.widget]); } else { - Widget = fieldRegistry.getAny([`${viewType}.${field.type}`, field.type]); + Widget = fieldRegistry.getAny([ + `${viewType}.${fields[fieldName].type}`, + fields[fieldName].type, + ]); } Widget = Widget || fieldRegistry.get("abstract"); let domain; @@ -89,10 +91,9 @@ export function mapActiveFieldsToFieldsInfo(activeFields, fields, viewType, env) if (mode && mode.split(",").length !== 1) { mode = env.isSmall ? "kanban" : "list"; } - const FieldComponent = fieldDescr.FieldComponent; const fieldInfo = { Widget, // remove this when we no longer support legacy fields inside wowl views - specialData: FieldComponent && FieldComponent.legacySpecialData, + specialData: fieldDescr.field && fieldDescr.field.legacySpecialData, domain, context: fieldDescr.context, fieldDependencies: {}, // ?? @@ -106,16 +107,16 @@ export function mapActiveFieldsToFieldsInfo(activeFields, fields, viewType, env) __WOWL_FIELD_DESCR__: fieldDescr, }; - if (FieldComponent && FieldComponent.limit) { - fieldInfo.limit = FieldComponent.limit; + if (fieldDescr.field && fieldDescr.field.limit) { + fieldInfo.limit = fieldDescr.field.limit; } if (fieldDescr.modifiers && fieldDescr.modifiers.invisible === true) { fieldInfo.__no_fetch = true; } - if (!fieldInfo.__no_fetch && FieldComponent && FieldComponent.fieldsToFetch) { - let fieldsToFetch = FieldComponent.fieldsToFetch; + if (!fieldInfo.__no_fetch && fieldDescr.field && fieldDescr.field.fieldsToFetch) { + let fieldsToFetch = fieldDescr.field.fieldsToFetch; if (fieldsToFetch instanceof Function) { fieldsToFetch = fieldsToFetch(fieldInfo.__WOWL_FIELD_DESCR__); } diff --git a/addons/web/static/src/views/list/list_arch_parser.js b/addons/web/static/src/views/list/list_arch_parser.js index 9d19061ffba..7d9fbf6088f 100644 --- a/addons/web/static/src/views/list/list_arch_parser.js +++ b/addons/web/static/src/views/list/list_arch_parser.js @@ -106,17 +106,17 @@ export class ListArchParser extends XMLParser { addFieldDependencies( activeFields, models[modelName], - fieldInfo.FieldComponent.fieldDependencies + fieldInfo.field.fieldDependencies ); if (this.isColumnVisible(fieldInfo.modifiers.column_invisible)) { - const label = fieldInfo.FieldComponent.label; + const label = fieldInfo.field.label; columns.push({ ...fieldInfo, id: `column_${nextId++}`, className: node.getAttribute("class"), // for oe_edit_only and oe_read_only optional: node.getAttribute("optional") || false, type: "field", - hasLabel: !(fieldInfo.noLabel || fieldInfo.FieldComponent.noLabel), + hasLabel: !(fieldInfo.noLabel || fieldInfo.field.noLabel), label: (fieldInfo.widget && label && label.toString()) || fieldInfo.string, }); } @@ -210,7 +210,9 @@ export class ListArchParser extends XMLParser { treeAttr.decorations = getDecoration(xmlDoc); treeAttr.defaultGroupBy = xmlDoc.getAttribute("default_group_by"); - treeAttr.defaultOrder = stringToOrderBy(xmlDoc.getAttribute("default_order") || null); + treeAttr.defaultOrder = stringToOrderBy( + xmlDoc.getAttribute("default_order") || null + ); // custom open action when clicking on record row const action = xmlDoc.getAttribute("action"); diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index 001160e5ad6..3eba5582b62 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -604,8 +604,7 @@ export class Record extends DataPoint { continue; } - const isSet = - activeField && activeField.FieldComponent && activeField.FieldComponent.isSet; + const isSet = activeField && activeField.field && activeField.field.isSet; if (this.isRequired(fieldName) && isSet && !isSet(this.data[fieldName])) { this.setInvalidField(fieldName); diff --git a/addons/web/static/src/webclient/settings_form_view/fields/upgrade_boolean_field.js b/addons/web/static/src/webclient/settings_form_view/fields/upgrade_boolean_field.js index 385b6cd1c0b..ac3ade9fb70 100644 --- a/addons/web/static/src/webclient/settings_form_view/fields/upgrade_boolean_field.js +++ b/addons/web/static/src/webclient/settings_form_view/fields/upgrade_boolean_field.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { BooleanField } from "@web/views/fields/boolean/boolean_field"; +import { booleanField, BooleanField } from "@web/views/fields/boolean/boolean_field"; import { useService } from "@web/core/utils/hooks"; import { UpgradeDialog } from "./upgrade_dialog"; @@ -33,10 +33,12 @@ export class UpgradeBooleanField extends BooleanField { } } } -UpgradeBooleanField.isUpgradeField = true; -UpgradeBooleanField.additionalClasses = [ - ...UpgradeBooleanField.additionalClasses || [], - "o_field_boolean", -]; -registry.category("fields").add("upgrade_boolean", UpgradeBooleanField); +export const upgradeBooleanField = { + ...booleanField, + component: UpgradeBooleanField, + isUpgradeField: true, + additionalClasses: [...(booleanField.additionalClasses || []), "o_field_boolean"], +}; + +registry.category("fields").add("upgrade_boolean", upgradeBooleanField); diff --git a/addons/web/static/src/webclient/settings_form_view/highlight_text/form_label_highlight_text.js b/addons/web/static/src/webclient/settings_form_view/highlight_text/form_label_highlight_text.js index 49863a59849..8dcb737e9ef 100644 --- a/addons/web/static/src/webclient/settings_form_view/highlight_text/form_label_highlight_text.js +++ b/addons/web/static/src/webclient/settings_form_view/highlight_text/form_label_highlight_text.js @@ -8,8 +8,8 @@ export class FormLabelHighlightText extends FormLabel { const isEnterprise = odoo.info && odoo.info.isEnterprise; if ( this.props.fieldInfo && - this.props.fieldInfo.FieldComponent && - this.props.fieldInfo.FieldComponent.isUpgradeField && + this.props.fieldInfo.field && + this.props.fieldInfo.field.isUpgradeField && !isEnterprise ) { this.upgradeEnterprise = true; diff --git a/addons/web/static/src/webclient/settings_form_view/highlight_text/settings_radio_field.js b/addons/web/static/src/webclient/settings_form_view/highlight_text/settings_radio_field.js index 5741c2132cc..17aaf665d52 100644 --- a/addons/web/static/src/webclient/settings_form_view/highlight_text/settings_radio_field.js +++ b/addons/web/static/src/webclient/settings_form_view/highlight_text/settings_radio_field.js @@ -1,16 +1,21 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { RadioField } from "@web/views/fields/radio/radio_field"; +import { radioField, RadioField } from "@web/views/fields/radio/radio_field"; import { HighlightText } from "./highlight_text"; -export class SettingsRadioField extends RadioField {} +export class SettingsRadioField extends RadioField { + static template = "web.SettingsRadioField"; + static components = { ...super.components, HighlightText }; +} -SettingsRadioField.extractStringExpr = (fieldName, record) => { - const radioItems = SettingsRadioField.getItems(fieldName, record); - return radioItems.map((r) => r[1]); +export const settingsRadioField = { + ...radioField, + component: SettingsRadioField, + extractStringExpr(fieldName, record) { + const radioItems = SettingsRadioField.getItems(fieldName, record); + return radioItems.map((r) => r[1]); + }, }; -SettingsRadioField.template = "web.SettingsRadioField"; -SettingsRadioField.components = { ...RadioField.components, HighlightText }; -registry.category("fields").add("base_settings.radio", SettingsRadioField); +registry.category("fields").add("base_settings.radio", settingsRadioField); diff --git a/addons/web/static/tests/views/calendar/calendar_view_tests.js b/addons/web/static/tests/views/calendar/calendar_view_tests.js index b4d24006a3d..243320a993c 100644 --- a/addons/web/static/tests/views/calendar/calendar_view_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_view_tests.js @@ -1421,7 +1421,7 @@ QUnit.module("Views", ({ beforeEach }) => { QUnit.test(`render popover with widget which has specialData attribute`, async (assert) => { assert.expect(3); - fieldRegistry.add("specialWidget", CharField); + fieldRegistry.add("specialWidget", { component: CharField }); preloadedDataRegistry.add("specialWidget", { loadOnTypes: ["char"], preload: () => { @@ -4484,7 +4484,7 @@ QUnit.module("Views", ({ beforeEach }) => { } } DeferredWidget.template = owl.xml``; - fieldRegistry.add("deferred_widget", DeferredWidget); + fieldRegistry.add("deferred_widget", { component: DeferredWidget }); registerCleanup(() => fieldRegistry.remove("deferred_widget")); await makeView({ diff --git a/addons/web/static/tests/views/fields/html_field_tests.js b/addons/web/static/tests/views/fields/html_field_tests.js index e8e6f19a1fc..2170f9633c3 100644 --- a/addons/web/static/tests/views/fields/html_field_tests.js +++ b/addons/web/static/tests/views/fields/html_field_tests.js @@ -3,7 +3,7 @@ import { click, editInput, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; import { registry } from "@web/core/registry"; -import { HtmlField } from "@web/views/fields/html/html_field"; +import { htmlField } from "@web/views/fields/html/html_field"; import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services"; import { session } from "@web/session"; @@ -32,7 +32,7 @@ QUnit.module("Fields", ({ beforeEach }) => { setupViewRegistries(); // Explicitly removed by web_editor, we need to add it back - registry.category("fields").add("html", HtmlField, { force: true }); + registry.category("fields").add("html", htmlField, { force: true }); }); QUnit.module("HtmlField"); diff --git a/addons/web/static/tests/views/fields/many2many_tags_field_tests.js b/addons/web/static/tests/views/fields/many2many_tags_field_tests.js index 44da436a973..a5cd81985c4 100644 --- a/addons/web/static/tests/views/fields/many2many_tags_field_tests.js +++ b/addons/web/static/tests/views/fields/many2many_tags_field_tests.js @@ -2,7 +2,7 @@ import { AutoComplete } from "@web/core/autocomplete/autocomplete"; import { browser } from "@web/core/browser/browser"; -import { Many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; +import { many2ManyTagsFieldColorEditable } from "@web/views/fields/many2many_tags/many2many_tags_field"; import { click, clickDiscard, @@ -683,7 +683,7 @@ QUnit.module("Fields", (hooks) => { QUnit.test( "Many2ManyTagsField loads records according to limit defined on widget prototype", async function (assert) { - patchWithCleanup(Many2ManyTagsField, { + patchWithCleanup(many2ManyTagsFieldColorEditable, { limit: 30, }); @@ -1616,8 +1616,7 @@ QUnit.module("Fields", (hooks) => { type: "form", resModel: "partner", serverData, - arch: - '
', + arch: '
', }); assert.strictEqual( diff --git a/addons/web/static/tests/views/fields/one2many_field_tests.js b/addons/web/static/tests/views/fields/one2many_field_tests.js index 80246fa777a..534fdbe2ce2 100644 --- a/addons/web/static/tests/views/fields/one2many_field_tests.js +++ b/addons/web/static/tests/views/fields/one2many_field_tests.js @@ -4450,8 +4450,8 @@ QUnit.module("Fields", (hooks) => { QUnit.test("one2many with CREATE onchanges correctly refreshed", async function (assert) { let delta = 0; const fieldRegistry = registry.category("fields"); - for (const [name, Field] of fieldRegistry.getEntries()) { - class DeltaField extends Field { + for (const [name, field] of fieldRegistry.getEntries()) { + class DeltaField extends field.component { setup() { super.setup(); owl.onWillStart(() => { @@ -4462,7 +4462,7 @@ QUnit.module("Fields", (hooks) => { }); } } - fieldRegistry.add(name, DeltaField, { force: true }); + fieldRegistry.add(name, { ...field, component: DeltaField }, { force: true }); } let deactiveOnchange = true; diff --git a/addons/web/static/tests/views/form/form_compiler_tests.js b/addons/web/static/tests/views/form/form_compiler_tests.js index d0e467b26e3..5fe3b332746 100644 --- a/addons/web/static/tests/views/form/form_compiler_tests.js +++ b/addons/web/static/tests/views/form/form_compiler_tests.js @@ -417,15 +417,19 @@ QUnit.module("Form Renderer", (hooks) => { QUnit.test("render field with placeholder", async (assert) => { assert.expect(1); - class CharField extends owl.Component { - setup() { - assert.strictEqual(this.props.placeholder, "e.g. Contact's Name or //someinfo..."); - } - } - CharField.template = owl.xml`
`; - CharField.extractProps = ({ attrs }) => ({ placeholder: attrs.placeholder }); - - registry.category("fields").add("char", CharField, { force: true }); + const charField = { + component: class CharField extends owl.Component { + static template = owl.xml`
`; + setup() { + assert.strictEqual( + this.props.placeholder, + "e.g. Contact's Name or //someinfo..." + ); + } + }, + extractProps: ({ attrs }) => ({ placeholder: attrs.placeholder }), + }; + registry.category("fields").add("char", charField, { force: true }); serverData.views = { "partner,1,form": /*xml*/ ` diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 4fb480c09f8..02c55c6b902 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -585,7 +585,7 @@ QUnit.module("Views", (hooks) => { return def; } } - fieldRegistry.add("asyncwidget", AsyncField); + fieldRegistry.add("asyncwidget", { component: AsyncField }); const viewProm = makeView({ type: "form", @@ -691,10 +691,10 @@ QUnit.module("Views", (hooks) => { // (int_field) in our case, isn't in the form view. This test ensures that we can open // the form view in this situation. class MyField extends CharField {} - MyField.fieldDependencies = { - int_field: { type: "integer" }, - }; - fieldRegistry.add("my_widget", MyField); + fieldRegistry.add("my_widget", { + component: MyField, + fieldDependencies: { int_field: { type: "integer" } }, + }); serverData.models.partner.records[1].p = [1]; await makeView({ type: "form", @@ -3135,7 +3135,7 @@ QUnit.module("Views", (hooks) => { }); } } - fieldRegistry.add("asyncwidget", AsyncField); + fieldRegistry.add("asyncwidget", { component: AsyncField }); await makeView({ type: "form", @@ -3563,12 +3563,14 @@ QUnit.module("Views", (hooks) => { assert.strictEqual(this.props.horizontal, true); } } - MyField.extractProps = function ({ attrs }) { - assert.deepEqual(attrs.options, { horizontal: true }); - return { horizontal: attrs.options.horizontal }; - }; MyField.template = owl.xml`
ok
`; - fieldRegistry.add("my_field", MyField); + fieldRegistry.add("my_field", { + component: MyField, + extractProps: function ({ attrs }) { + assert.deepEqual(attrs.options, { horizontal: true }); + return { horizontal: attrs.options.horizontal }; + }, + }); await makeView({ type: "form", @@ -12565,12 +12567,15 @@ QUnit.module("Views", (hooks) => { QUnit.test("fieldDependencies support for fields", async (assert) => { serverData.models.partner.records = [{ id: 1, int_field: 2 }]; - class CustomField extends Component {} - CustomField.fieldDependencies = { - int_field: { type: "integer" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + int_field: { type: "integer" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ type: "form", @@ -12592,12 +12597,15 @@ QUnit.module("Views", (hooks) => { async (assert) => { serverData.models.partner.records[0].product_id = 37; - class CustomField extends Component {} - CustomField.fieldDependencies = { - product_id: { type: "many2one", relation: "product" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + product_id: { type: "many2one", relation: "product" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ type: "form", diff --git a/addons/web/static/tests/views/kanban_view_tests.js b/addons/web/static/tests/views/kanban_view_tests.js index 44bd827e7bd..ac8db5e46dc 100644 --- a/addons/web/static/tests/views/kanban_view_tests.js +++ b/addons/web/static/tests/views/kanban_view_tests.js @@ -855,24 +855,26 @@ QUnit.module("Views", (hooks) => { QUnit.test("field with widget and attributes in kanban", async (assert) => { assert.expect(1); - class MyField extends Component { - setup() { - if (this.props.record.resId === 1) { - assert.deepEqual(this.props.attrs, { - name: "int_field", - widget: "my_field", - str: "some string", - bool: "true", - num: "4.5", - options: {}, - field_id: "int_field", - }); + const myField = { + component: class MyField extends Component { + static template = xml``; + setup() { + if (this.props.record.resId === 1) { + assert.deepEqual(this.props.attrs, { + name: "int_field", + widget: "my_field", + str: "some string", + bool: "true", + num: "4.5", + options: {}, + field_id: "int_field", + }); + } } - } - } - MyField.template = xml``; - MyField.extractProps = ({ attrs }) => ({ attrs }); - registry.category("fields").add("my_field", MyField); + }, + extractProps: ({ attrs }) => ({ attrs }), + }; + registry.category("fields").add("my_field", myField); await makeView({ type: "kanban", @@ -897,14 +899,17 @@ QUnit.module("Views", (hooks) => { }); QUnit.test("field with widget and dynamic attributes in kanban", async (assert) => { - class MyField extends Component {} - MyField.template = xml``; - MyField.extractProps = ({ attrs }) => { - assert.step( - `${attrs["dyn-bool"]}/${attrs["interp-str"]}/${attrs["interp-str2"]}/${attrs["interp-str3"]}` - ); + const myField = { + component: class MyField extends Component { + static template = xml``; + }, + extractProps: ({ attrs }) => { + assert.step( + `${attrs["dyn-bool"]}/${attrs["interp-str"]}/${attrs["interp-str2"]}/${attrs["interp-str3"]}` + ); + }, }; - registry.category("fields").add("my_field", MyField); + registry.category("fields").add("my_field", myField); await makeView({ type: "kanban", @@ -11875,12 +11880,15 @@ QUnit.module("Views", (hooks) => { }); QUnit.test("fieldDependencies support for fields", async (assert) => { - class CustomField extends Component {} - CustomField.fieldDependencies = { - int_field: { type: "integer" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + int_field: { type: "integer" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ resModel: "partner", @@ -11905,12 +11913,15 @@ QUnit.module("Views", (hooks) => { QUnit.test( "fieldDependencies support for fields: dependence on a relational field", async (assert) => { - class CustomField extends Component {} - CustomField.fieldDependencies = { - product_id: { type: "many2one", relation: "product" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + product_id: { type: "many2one", relation: "product" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ resModel: "partner", diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index c70625c2196..809eabf59ed 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -10,7 +10,7 @@ import { uiService } from "@web/core/ui/ui_service"; import { getNextTabableElement } from "@web/core/utils/ui"; import { session } from "@web/session"; import { FloatField } from "@web/views/fields/float/float_field"; -import { TextField } from "@web/views/fields/text/text_field"; +import { textField } from "@web/views/fields/text/text_field"; import { ListController } from "@web/views/list/list_controller"; import { DynamicRecordList, DynamicGroupList } from "@web/views/relational_model"; import { actionService } from "@web/webclient/actions/action_service"; @@ -1123,15 +1123,21 @@ QUnit.module("Views", (hooks) => { QUnit.test("column names (noLabel, label, string and default)", async function (assert) { const fieldRegistry = registry.category("fields"); - const CharField = fieldRegistry.get("char"); + const charField = fieldRegistry.get("char"); - class NoLabelCharField extends CharField {} - NoLabelCharField.noLabel = true; - fieldRegistry.add("nolabel_char", NoLabelCharField); + class NoLabelCharField extends charField.component {} + fieldRegistry.add("nolabel_char", { + ...charField, + component: NoLabelCharField, + noLabel: true, + }); - class LabelCharField extends CharField {} - LabelCharField.label = "Some static label"; - fieldRegistry.add("label_char", LabelCharField); + class LabelCharField extends charField.component {} + fieldRegistry.add("label_char", { + ...charField, + component: LabelCharField, + label: "Some static label", + }); await makeView({ type: "list", @@ -11711,7 +11717,7 @@ QUnit.module("Views", (hooks) => { "editable form alongside html field: click out to unselect the row", async function (assert) { // FIXME WOWL hack: add back the text field as html field removed by web_editor html_field file - registry.category("fields").add("html", TextField, { force: true }); + registry.category("fields").add("html", textField, { force: true }); await makeView({ type: "form", @@ -14732,9 +14738,9 @@ QUnit.module("Views", (hooks) => { const def = makeDeferred(); const fieldRegistry = registry.category("fields"); - const CharField = fieldRegistry.get("char"); + const charField = fieldRegistry.get("char"); - class AsyncCharField extends CharField { + class AsyncCharField extends charField.component { setup() { super.setup(); onWillStart(async () => { @@ -14743,7 +14749,7 @@ QUnit.module("Views", (hooks) => { }); } } - fieldRegistry.add("asyncwidget", AsyncCharField); + fieldRegistry.add("asyncwidget", { component: AsyncCharField }); await makeView({ type: "list", @@ -15916,7 +15922,7 @@ QUnit.module("Views", (hooks) => { "selecting a row after another one containing a table within an html field should be the correct one", async function (assert) { // FIXME WOWL hack: add back the text field as html field removed by web_editor html_field file - registry.category("fields").add("html", TextField, { force: true }); + registry.category("fields").add("html", textField, { force: true }); serverData.models.foo.fields.html = { string: "HTML field", type: "html" }; serverData.models.foo.records[0].html = ` @@ -16210,12 +16216,15 @@ QUnit.module("Views", (hooks) => { QUnit.test("fieldDependencies support for fields", async (assert) => { serverData.models.foo.records = [{ id: 1, int_field: 2 }]; - class CustomField extends Component {} - CustomField.fieldDependencies = { - int_field: { type: "integer" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + int_field: { type: "integer" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ resModel: "foo", @@ -16234,12 +16243,15 @@ QUnit.module("Views", (hooks) => { QUnit.test( "fieldDependencies support for fields: dependence on a relational field", async (assert) => { - class CustomField extends Component {} - CustomField.fieldDependencies = { - m2o: { type: "many2one", relation: "bar" }, + const customField = { + component: class CustomField extends Component { + static template = xml``; + }, + fieldDependencies: { + m2o: { type: "many2one", relation: "bar" }, + }, }; - CustomField.template = xml``; - registry.category("fields").add("custom_field", CustomField); + registry.category("fields").add("custom_field", customField); await makeView({ resModel: "foo", diff --git a/addons/web_editor/static/src/js/backend/html_field.js b/addons/web_editor/static/src/js/backend/html_field.js index ca3d5668611..e5dfc960685 100644 --- a/addons/web_editor/static/src/js/backend/html_field.js +++ b/addons/web_editor/static/src/js/backend/html_field.js @@ -616,62 +616,64 @@ HtmlField.props = { wysiwygOptions: { type: Object }, }; -HtmlField.displayName = _lt("Html"); -HtmlField.supportedTypes = ["html"]; +export const htmlField = { + component: HtmlField, + displayName: _lt("Html"), + supportedTypes: ["html"], + extractProps: ({ attrs, field }) => { + const wysiwygOptions = { + placeholder: attrs.placeholder, + noAttachment: attrs.options['no-attachment'], + inIframe: Boolean(attrs.options.cssEdit), + iframeCssAssets: attrs.options.cssEdit, + iframeHtmlClass: attrs.iframeHtmlClass, + snippets: attrs.options.snippets, + mediaModalParams: { + noVideos: 'noVideos' in attrs.options ? attrs.options.noVideos : true, + useMediaLibrary: true, + }, + linkForceNewWindow: true, + tabsize: 0, + height: attrs.options.height, + minHeight: attrs.options.minHeight, + maxHeight: attrs.options.maxHeight, + resizable: 'resizable' in attrs.options ? attrs.options.resizable : false, + editorPlugins: [QWebPlugin], + }; + if ('collaborative' in attrs.options) { + wysiwygOptions.collaborative = attrs.options.collaborative; + } + if ('allowCommandImage' in attrs.options) { + // Set the option only if it is explicitly set in the view so a default + // can be set elsewhere otherwise. + wysiwygOptions.allowCommandImage = Boolean(attrs.options.allowCommandImage); + } + if (field.sanitize_tags || (field.sanitize_tags === undefined && field.sanitize)) { + wysiwygOptions.allowCommandVideo = false; // Tag-sanitized fields remove videos. + } else if ('allowCommandVideo' in attrs.options) { + // Set the option only if it is explicitly set in the view so a default + // can be set elsewhere otherwise. + wysiwygOptions.allowCommandVideo = Boolean(attrs.options.allowCommandVideo); + } + return { + isTranslatable: field.translate, + fieldName: field.name, + codeview: Boolean(odoo.debug && attrs.options.codeview), + placeholder: attrs.placeholder, -HtmlField.extractProps = ({ attrs, field }) => { - const wysiwygOptions = { - placeholder: attrs.placeholder, - noAttachment: attrs.options['no-attachment'], - inIframe: Boolean(attrs.options.cssEdit), - iframeCssAssets: attrs.options.cssEdit, - iframeHtmlClass: attrs.iframeHtmlClass, - snippets: attrs.options.snippets, - mediaModalParams: { - noVideos: 'noVideos' in attrs.options ? attrs.options.noVideos : true, - useMediaLibrary: true, - }, - linkForceNewWindow: true, - tabsize: 0, - height: attrs.options.height, - minHeight: attrs.options.minHeight, - maxHeight: attrs.options.maxHeight, - resizable: 'resizable' in attrs.options ? attrs.options.resizable : false, - editorPlugins: [QWebPlugin], - }; - if ('collaborative' in attrs.options) { - wysiwygOptions.collaborative = attrs.options.collaborative; - } - if ('allowCommandImage' in attrs.options) { - // Set the option only if it is explicitly set in the view so a default - // can be set elsewhere otherwise. - wysiwygOptions.allowCommandImage = Boolean(attrs.options.allowCommandImage); - } - if (field.sanitize_tags || (field.sanitize_tags === undefined && field.sanitize)) { - wysiwygOptions.allowCommandVideo = false; // Tag-sanitized fields remove videos. - } else if ('allowCommandVideo' in attrs.options) { - // Set the option only if it is explicitly set in the view so a default - // can be set elsewhere otherwise. - wysiwygOptions.allowCommandVideo = Boolean(attrs.options.allowCommandVideo); - } - return { - isTranslatable: field.translate, - fieldName: field.name, - codeview: Boolean(odoo.debug && attrs.options.codeview), - placeholder: attrs.placeholder, + isCollaborative: attrs.options.collaborative, + cssReadonlyAssetId: attrs.options.cssReadonly, + dynamicPlaceholder: attrs.options.dynamic_placeholder, + cssEditAssetId: attrs.options.cssEdit, + isInlineStyle: attrs.options['style-inline'], + wrapper: attrs.options.wrapper, - isCollaborative: attrs.options.collaborative, - cssReadonlyAssetId: attrs.options.cssReadonly, - dynamicPlaceholder: attrs.options.dynamic_placeholder, - cssEditAssetId: attrs.options.cssEdit, - isInlineStyle: attrs.options['style-inline'], - wrapper: attrs.options.wrapper, - - wysiwygOptions, - }; + wysiwygOptions, + }; + }, }; -registry.category("fields").add("html", HtmlField, { force: true }); +registry.category("fields").add("html", htmlField, { force: true }); function stripHistoryIds(value) { return value && value.replace(/\sdata-last-history-steps="[^"]*?"/, '') || value; diff --git a/addons/web_kanban_gauge/static/src/gauge_field.js b/addons/web_kanban_gauge/static/src/gauge_field.js index 429a3cb37d4..c3eba165bdf 100644 --- a/addons/web_kanban_gauge/static/src/gauge_field.js +++ b/addons/web_kanban_gauge/static/src/gauge_field.js @@ -88,11 +88,13 @@ GaugeField.props = { title: { type: String }, }; -GaugeField.extractProps = ({ attrs, field }) => { - return { +export const gaugeField = { + component: GaugeField, + extractProps: ({ attrs, field }) => ({ maxValueField: attrs.options.max_field, + title: attrs.options.title || field.string, - }; + }), }; -registry.category("fields").add("gauge", GaugeField); +registry.category("fields").add("gauge", gaugeField); diff --git a/addons/website/static/src/components/fields/fields.js b/addons/website/static/src/components/fields/fields.js index 7c88740d5f4..3cd15eb92ca 100644 --- a/addons/website/static/src/components/fields/fields.js +++ b/addons/website/static/src/components/fields/fields.js @@ -48,20 +48,23 @@ class PageUrlField extends Component { this.props.update(this.state); } } + PageUrlField.components = {Switch, PageDependencies}; PageUrlField.template = 'website.PageUrlField'; PageUrlField.props = { ...standardFieldProps, placeholder: {type: String, optional: true}, }; -PageUrlField.extractProps = ({attrs}) => { - return { - placeholder: attrs.placeholder, - }; -}; -PageUrlField.supportedTypes = ['char']; -registry.category("fields").add("page_url", PageUrlField); +const pageUrlField = { + component: PageUrlField, + supportedTypes: ['char'], + extractProps: ({ attrs }) => ({ + placeholder: attrs.placeholder, + }), +}; + +registry.category("fields").add("page_url", pageUrlField); /** * Displays 'Selection' field's values as images to select. @@ -86,16 +89,19 @@ export class ImageRadioField extends Component { this.props.update(value); } } -ImageRadioField.supportedTypes = ['selection']; + ImageRadioField.template = 'website.FieldImageRadio'; ImageRadioField.props = { ...standardFieldProps, images: {type: Array, element: String}, }; -ImageRadioField.extractProps = ({attrs}) => { - return { + +export const imageRadioField = { + component: ImageRadioField, + supportedTypes: ['selection'], + extractProps: ({ attrs }) => ({ images: attrs.options.images, - }; + }), }; -registry.category("fields").add("image_radio", ImageRadioField); +registry.category("fields").add("image_radio", imageRadioField); diff --git a/addons/website/static/src/components/fields/publish_button.js b/addons/website/static/src/components/fields/publish_button.js index cc60352dc23..8a969f20cb2 100644 --- a/addons/website/static/src/components/fields/publish_button.js +++ b/addons/website/static/src/components/fields/publish_button.js @@ -7,4 +7,6 @@ const { Component } = owl; class PublishField extends Component {} PublishField.template = "website.PublishField"; -registry.category("fields").add("website_publish_button", PublishField); +registry.category("fields").add("website_publish_button", { + component: PublishField, +}); diff --git a/addons/website/static/src/components/fields/redirect_field.js b/addons/website/static/src/components/fields/redirect_field.js index cfda848b8fb..3d45914365c 100644 --- a/addons/website/static/src/components/fields/redirect_field.js +++ b/addons/website/static/src/components/fields/redirect_field.js @@ -23,4 +23,7 @@ class RedirectField extends Component { } RedirectField.template = "website.RedirectField"; -registry.category("fields").add("website_redirect_button", RedirectField); + +registry.category("fields").add("website_redirect_button", { + component: RedirectField, +}); diff --git a/addons/website/static/src/components/fields/widget_iframe.js b/addons/website/static/src/components/fields/widget_iframe.js index 3850d857f99..c806ae7351d 100644 --- a/addons/website/static/src/components/fields/widget_iframe.js +++ b/addons/website/static/src/components/fields/widget_iframe.js @@ -16,4 +16,8 @@ class FieldIframePreview extends Component { } FieldIframePreview.template = 'website.iframeWidget'; -registry.category('fields').add('iframe', FieldIframePreview); +export const fieldIframePreview = { + component: FieldIframePreview, +}; + +registry.category("fields").add("iframe", fieldIframePreview); diff --git a/addons/website_sale/static/src/js/website_sale_video_field_preview.js b/addons/website_sale/static/src/js/website_sale_video_field_preview.js index a1754726861..a1c38a5e2cc 100644 --- a/addons/website_sale/static/src/js/website_sale_video_field_preview.js +++ b/addons/website_sale/static/src/js/website_sale_video_field_preview.js @@ -7,4 +7,8 @@ const { Component } = owl; export class FieldVideoPreview extends Component {} FieldVideoPreview.template = 'website_sale.FieldVideoPreview'; -registry.category("fields").add("video_preview", FieldVideoPreview); +export const fieldVideoPreview = { + component: FieldVideoPreview, +}; + +registry.category("fields").add("video_preview", fieldVideoPreview); diff --git a/addons/website_slides/static/src/slide_category_one2many_field.js b/addons/website_slides/static/src/slide_category_one2many_field.js index eb4fc168916..3fe751b018c 100644 --- a/addons/website_slides/static/src/slide_category_one2many_field.js +++ b/addons/website_slides/static/src/slide_category_one2many_field.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; import { SlideCategoryListRenderer } from "./slide_category_list_renderer"; -import { X2ManyField } from "@web/views/fields/x2many/x2many_field"; +import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; class SlideCategoryOneToManyField extends X2ManyField { setup() { @@ -19,4 +19,7 @@ SlideCategoryOneToManyField.defaultProps = { editable: "bottom", }; -registry.category("fields").add("slide_category_one2many", SlideCategoryOneToManyField); +registry.category("fields").add("slide_category_one2many", { + ...x2ManyField, + component: SlideCategoryOneToManyField, +});