From 4f403475e1078647e26255eba4c6ea9e33f229f2 Mon Sep 17 00:00:00 2001 From: wutong <34541195+igrowp@users.noreply.github.com> Date: Thu, 26 Oct 2023 10:36:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=E5=AF=8C=E6=96=87=E6=9C=AC=E5=92=8C?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E7=BB=84=E4=BB=B6=E4=BA=8B=E4=BB=B6=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E6=96=B0=E5=A2=9Echange=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh-CN/components/form/input-rich-text.md | 9 + docs/zh-CN/components/pagination.md | 7 + .../src/plugin/Form/InputRichText.tsx | 39 ++++- .../amis-editor/src/plugin/Pagination.tsx | 36 +++- .../amis-ui/src/components/Pagination.tsx | 20 ++- .../renderers/pagination.test.tsx | 159 ++++++++++++++++++ .../__tests__/renderers/Pagination.test.tsx | 6 +- .../amis/src/renderers/Form/InputRichText.tsx | 12 +- 8 files changed, 274 insertions(+), 14 deletions(-) create mode 100644 packages/amis/__tests__/event-action/renderers/pagination.test.tsx diff --git a/docs/zh-CN/components/form/input-rich-text.md b/docs/zh-CN/components/form/input-rich-text.md index b3f53ad30..232ae956b 100755 --- a/docs/zh-CN/components/form/input-rich-text.md +++ b/docs/zh-CN/components/form/input-rich-text.md @@ -230,3 +230,12 @@ froala 可以通过设置 buttons 参数来控制显示哪些按钮,默认是 | size | `string` | | 框的大小,可设置为 `md` 或者 `lg` | | options | `object` | | 需要参考 [tinymce](https://www.tiny.cloud/docs/configure/integration-and-setup/) 或 [froala](https://www.froala.com/wysiwyg-editor/docs/options) 的文档 | | buttons | `Array` | | froala 专用,配置显示的按钮,tinymce 可以通过前面的 options 设置 [toolbar](https://www.tiny.cloud/docs/demo/custom-toolbar-button/) 字符串 | + +## 事件表 + +当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`或`${event.data.[事件参数名]}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。 + +> `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。 +> | 事件名称 | 事件参数 | 说明 | +> | -------- | ------------------------------------- | ------------------------------------------- | +> | change | `[value]: object` 富文本组件的值
| 富文本值改变时触发 | diff --git a/docs/zh-CN/components/pagination.md b/docs/zh-CN/components/pagination.md index 675766a1b..6e4949833 100644 --- a/docs/zh-CN/components/pagination.md +++ b/docs/zh-CN/components/pagination.md @@ -67,3 +67,10 @@ order: 73 | showPageInput | `boolean` | false | 是否显示快速跳转输入框 layout 和 showPageInput 都可以控制 | | disabled | `boolean` | false | 是否禁用 | | onPageChange | page、perPage 改变时会触发 | (page: number, perPage: number) => void; | 分页改变触发 | + +当前组件会对外派发以下事件,可以通过`onEvent`来监听这些事件,并通过`actions`来配置执行的动作,在`actions`中可以通过`${事件参数名}`或`${event.data.[事件参数名]}`来获取事件产生的数据,详细请查看[事件动作](../../docs/concepts/event-action)。 + +> `[name]`表示当前组件绑定的名称,即`name`属性,如果没有配置`name`属性,则通过`value`取值。 +> | 事件名称 | 事件参数 | 说明 | +> | -------- | ------------------------------------- | ------------------------------------------- | +> | change | `[value]: object` 当前页码的值
| 当前页码值改变时触发 | \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Form/InputRichText.tsx b/packages/amis-editor/src/plugin/Form/InputRichText.tsx index d8a6f8b2d..f1d3c1bce 100644 --- a/packages/amis-editor/src/plugin/Form/InputRichText.tsx +++ b/packages/amis-editor/src/plugin/Form/InputRichText.tsx @@ -2,11 +2,12 @@ import { BaseEventContext, getSchemaTpl, defaultValue, + RendererPluginEvent, tipedLabel } from 'amis-editor-core'; import {registerEditorPlugin} from 'amis-editor-core'; import {BasePlugin} from 'amis-editor-core'; - +import {getEventControlConfig} from '../../renderer/event-control/helper'; import {ValidatorTag} from '../../validator'; const tinymceToolbarsDelimiter = ' '; @@ -183,6 +184,32 @@ export class RichTextControlPlugin extends BasePlugin { panelTitle = '富文本'; + events: RendererPluginEvent[] = [ + { + eventName: 'change', + eventLabel: '值变化', + description: '输入内容变化', + dataSchema: [ + { + type: 'object', + properties: { + data: { + type: 'object', + title: '数据', + properties: { + value: { + type: 'string', + title: '富文本的值' + } + }, + description: '当前数据域,可以通过.字段名读取对应的值' + } + } + } + ] + } + ]; + notRenderFormZone = true; panelJustify = true; @@ -432,6 +459,16 @@ export class RichTextControlPlugin extends BasePlugin { getSchemaTpl('style:classNames') ]) ] + }, + { + title: '事件', + className: 'p-none', + body: [ + getSchemaTpl('eventControl', { + name: 'onEvent', + ...getEventControlConfig(this.manager, context) + }) + ] } ]); }; diff --git a/packages/amis-editor/src/plugin/Pagination.tsx b/packages/amis-editor/src/plugin/Pagination.tsx index f4e3a2f74..fe4479dc3 100644 --- a/packages/amis-editor/src/plugin/Pagination.tsx +++ b/packages/amis-editor/src/plugin/Pagination.tsx @@ -1,15 +1,15 @@ -import {registerEditorPlugin} from 'amis-editor-core'; import { BasePlugin, RegionConfig, BaseEventContext, - tipedLabel + tipedLabel, + defaultValue, + getSchemaTpl, + RendererPluginEvent, + registerEditorPlugin } from 'amis-editor-core'; import {ValidatorTag} from '../validator'; import {getEventControlConfig} from '../renderer/event-control/helper'; -import {RendererPluginEvent} from 'amis-editor-core'; - -import {defaultValue, getSchemaTpl} from 'amis-editor-core'; export class PaginationPlugin extends BasePlugin { static id = 'PaginationPlugin'; @@ -49,6 +49,32 @@ export class PaginationPlugin extends BasePlugin { }; panelTitle = '分页器'; + events: RendererPluginEvent[] = [ + { + eventName: 'change', + eventLabel: '值变化', + description: '输入内容变化', + dataSchema: [ + { + type: 'object', + properties: { + data: { + type: 'object', + title: '数据', + properties: { + value: { + type: 'string', + title: '当前页码值' + } + }, + description: '当前数据域,可以通过.字段名读取对应的值' + } + } + } + ] + } + ]; + panelJustify = true; panelBodyCreator = (context: BaseEventContext) => { diff --git a/packages/amis-ui/src/components/Pagination.tsx b/packages/amis-ui/src/components/Pagination.tsx index 6ddfc3b4e..652bafc78 100644 --- a/packages/amis-ui/src/components/Pagination.tsx +++ b/packages/amis-ui/src/components/Pagination.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import isInteger from 'lodash/isInteger'; -import {localeable, LocaleProps} from 'amis-core'; +import {localeable, LocaleProps, resolveEventData} from 'amis-core'; import {themeable, ThemeProps} from 'amis-core'; import {autobind} from 'amis-core'; import {Icon} from './icons'; @@ -93,7 +93,8 @@ export interface BasicPaginationProps { */ popOverContainerSelector?: string; - onPageChange?: (page: number, perPage?: number) => void; + onPageChange?: (page: number, perPage?: number, dir?: string) => void; + dispatchEvent?: Function; } export interface PaginationProps extends BasicPaginationProps, @@ -139,13 +140,22 @@ export class Pagination extends React.Component< } } - handlePageNumChange(page: number, perPage?: number) { - const {disabled, onPageChange} = this.props; + async handlePageNumChange(page: number, perPage?: number, dir?: string) { + const {disabled, onPageChange, dispatchEvent} = this.props; + const _page = isNaN(Number(page)) || Number(page) < 1 ? 1 : page; if (disabled) { return; } - onPageChange?.(isNaN(Number(page)) || Number(page) < 1 ? 1 : page, perPage); + + const rendererEvent = await dispatchEvent?.( + 'change', + resolveEventData(this.props, {_page}) + ); + if (rendererEvent?.prevented) { + return; + } + onPageChange?.(_page, perPage, dir); } /** diff --git a/packages/amis/__tests__/event-action/renderers/pagination.test.tsx b/packages/amis/__tests__/event-action/renderers/pagination.test.tsx new file mode 100644 index 000000000..da9073260 --- /dev/null +++ b/packages/amis/__tests__/event-action/renderers/pagination.test.tsx @@ -0,0 +1,159 @@ +import {fireEvent, render} from '@testing-library/react'; +import '../../../src'; +import {render as amisRender} from '../../../src'; +import {makeEnv, wait} from '../../helper'; + +test('pagination: pageNum change event', async () => { + const mockFn = jest.fn(); + const pageChange = jest.fn(); + const {container} = render( + amisRender( + { + type: 'pagination', + layout: 'total,perPage,pager,go', + mode: 'normal', + activePage: 2, + lastPage: 99999, + total: 999, + perPage: 10, + maxButtons: 7, + showPerPage: true, + perPageAvailable: [10, 20, 50, 100], + showPageInput: true, + disabled: false, + id: 'u:1bf323bc4dbd', + onPageChange: pageChange, + onEvent: { + change: { + weight: 0, + actions: [ + { + actionType: 'custom', + script: mockFn + } + ] + } + } + }, + {}, + makeEnv({}) + ) + ); + // 当前页码改变 + const prev = container.querySelector('.cxd-Pagination-prev')!; + fireEvent.click(prev); // 上一页 + await wait(100); + expect(mockFn).toBeCalledTimes(1); + await wait(200); + expect(pageChange).toBeCalled(); + expect(pageChange.mock.calls[0]).toEqual([1, 10]); + + const next = container.querySelector('.cxd-Pagination-next')!; + fireEvent.click(next); // 下一页 + await wait(300); + expect(mockFn).toBeCalledTimes(2); + await wait(200); + expect(pageChange).toBeCalled(); + expect(pageChange.mock.calls[1]).toEqual([3, 10]); + + const go = container.querySelector('.cxd-Pagination-inputGroup')!; + fireEvent.change(go.querySelector('.cxd-Pagination-inputGroup-input')!, { + target: {value: 9} + }); + await wait(400); + fireEvent.click(go.querySelector('.cxd-Pagination-inputGroup-right')!); // 输入后点击go + await wait(500); + expect(mockFn).toBeCalledTimes(3); + await wait(200); + expect(pageChange).toBeCalled(); + expect(pageChange.mock.calls[2]).toEqual([9, 10]); + + function getPagerItem() { + const pager = container.querySelectorAll( + '.cxd-Pagination > .cxd-Pagination-pager-item' + ); + return pager[3]; + } + fireEvent.click(getPagerItem()!); // 点击页码切换 + await wait(600); + expect(mockFn).toBeCalledTimes(4); + await wait(200); + expect(pageChange).toBeCalled(); + expect(pageChange.mock.calls[3]).toEqual([4, 10]); +}); + +test('pagination: prevent pageNum change event ', async () => { + const mockFn = jest.fn(); + const pageChange = jest.fn(); + const {container} = render( + amisRender( + { + type: 'pagination', + layout: 'total,perPage,pager,go', + mode: 'normal', + activePage: 2, + lastPage: 99999, + total: 999, + perPage: 10, + maxButtons: 7, + showPerPage: true, + perPageAvailable: [10, 20, 50, 100], + showPageInput: true, + disabled: false, + id: 'u:1bf323bc4dbd', + onPageChange: pageChange, + onEvent: { + change: { + weight: 0, + actions: [ + { + actionType: 'custom', + preventDefault: true, // 阻止事件默认行为 + script: mockFn + } + ] + } + } + }, + {}, + makeEnv({}) + ) + ); + // 当前页码改变 + const prev = container.querySelector('.cxd-Pagination-prev')!; + fireEvent.click(prev); // 上一页 + await wait(100); + expect(mockFn).toBeCalledTimes(1); + await wait(200); + expect(pageChange).not.toBeCalled(); + + const next = container.querySelector('.cxd-Pagination-next')!; + fireEvent.click(next); // 下一页 + await wait(300); + expect(mockFn).toBeCalledTimes(2); + await wait(200); + expect(pageChange).not.toBeCalled(); + + const go = container.querySelector('.cxd-Pagination-inputGroup')!; + fireEvent.change(go.querySelector('.cxd-Pagination-inputGroup-input')!, { + target: {value: 9} + }); + await wait(400); + fireEvent.click(go.querySelector('.cxd-Pagination-inputGroup-right')!); // 输入后点击go + await wait(500); + expect(mockFn).toBeCalledTimes(3); + await wait(200); + expect(pageChange).not.toBeCalled(); + + function getPagerItem() { + const pager = container.querySelectorAll( + '.cxd-Pagination > .cxd-Pagination-pager-item' + ); + return pager[3]; + } + fireEvent.click(getPagerItem()!); // 点击页码切换 + await wait(600); + expect(mockFn).toBeCalledTimes(4); + await wait(200); + expect(pageChange).not.toBeCalled(); +}); diff --git a/packages/amis/__tests__/renderers/Pagination.test.tsx b/packages/amis/__tests__/renderers/Pagination.test.tsx index 52a158202..ff228ab9b 100644 --- a/packages/amis/__tests__/renderers/Pagination.test.tsx +++ b/packages/amis/__tests__/renderers/Pagination.test.tsx @@ -117,8 +117,12 @@ test('Renderer:Pagination with simple mode', async () => { expect(next).not.toHaveClass('is-disabled'); fireEvent.click(next); + + await wait(500); expect(pageChange).toBeCalled(); - expect(pageChange.mock.calls[0]).toEqual([3, 10]); + + await wait(200); + expect(pageChange.mock.calls[0]).toEqual([3, 10, 'forward']); rerender( amisRender( diff --git a/packages/amis/src/renderers/Form/InputRichText.tsx b/packages/amis/src/renderers/Form/InputRichText.tsx index 96f5a9ead..2e0ffc10b 100644 --- a/packages/amis/src/renderers/Form/InputRichText.tsx +++ b/packages/amis/src/renderers/Form/InputRichText.tsx @@ -5,6 +5,7 @@ import { FormBaseControl, buildApi, qsstringify, + resolveEventData, autobind } from 'amis-core'; import cx from 'classnames'; @@ -252,17 +253,24 @@ export default class RichTextControl extends React.Component< }); } - handleChange( + async handleChange( value: any, submitOnChange?: boolean, changeImmediately?: boolean ) { - const {onChange, disabled} = this.props; + const {onChange, disabled, dispatchEvent} = this.props; if (disabled) { return; } + const rendererEvent = await dispatchEvent( + 'change', + resolveEventData(this.props, {value}) + ); + if (rendererEvent?.prevented) { + return; + } onChange?.(value, submitOnChange, changeImmediately); } From ef80d814f74a07265b761fb39f0b23b16f9ddf6c Mon Sep 17 00:00:00 2001 From: miaoxinyu01 Date: Thu, 26 Oct 2023 11:23:31 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=95=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/amis/__tests__/renderers/Pagination.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amis/__tests__/renderers/Pagination.test.tsx b/packages/amis/__tests__/renderers/Pagination.test.tsx index ff228ab9b..76e32b056 100644 --- a/packages/amis/__tests__/renderers/Pagination.test.tsx +++ b/packages/amis/__tests__/renderers/Pagination.test.tsx @@ -122,7 +122,7 @@ test('Renderer:Pagination with simple mode', async () => { expect(pageChange).toBeCalled(); await wait(200); - expect(pageChange.mock.calls[0]).toEqual([3, 10, 'forward']); + expect(pageChange.mock.calls[0]).toEqual([3, 10]); rerender( amisRender(