From 33202c4e5b8e64954ef9bf36d463297952190947 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Wed, 5 Feb 2020 16:49:50 +0300 Subject: [PATCH 01/24] Implement base template --- js/renovation/button.tsx | 10 +++++++++- js/renovation/dist/button.j.jsx | 9 +++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index 78d951809d23..f83d31246135 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -105,13 +105,14 @@ export const viewFunction = (viewModel: Button) => { export default class Button extends Widget { @Prop() activeStateEnabled?: boolean = true; @Prop() classNames?: string[]; - @Prop() contentRender?: any; + @Prop() contentRender?: ButtonTemplateFn; @Prop() focusStateEnabled?: boolean = true; @Prop() hoverStateEnabled?: boolean = true; @Prop() icon?: string; @Prop() onSubmit?: (e: any) => any = (() => undefined); @Prop() pressed?: boolean; @Prop() stylingMode?: string; + @Prop() template?: ButtonTemplate = ''; @Prop() text?: string = ''; @Prop() type?: string; @Prop() useSubmitBehavior?: boolean = false; @@ -130,3 +131,10 @@ export default class Button extends Widget { return () => click.off(this.widgetRef, { namespace }); } } + +type ButtonContent = { + text: string, + icon: string, +} +type ButtonTemplateFn = (data: ButtonContent, container: any) => any +type ButtonTemplate = ButtonTemplateFn | string diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 7457e5f4cb97..b6c10bf4dd21 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -2,6 +2,7 @@ import registerComponent from '../../core/component_registrator'; import Widget from '../preact_wrapper'; import { extend } from '../../core/utils/extend'; import ButtonView from '../button.p'; +import * as Preact from 'preact'; class Button extends Widget { getView() { @@ -10,18 +11,17 @@ class Button extends Widget { getProps(isFirstRender) { const props = super.getProps(isFirstRender); - if(props.contentRender) { + if(props.template) { props.contentRender = (data) => { - const template = this._getTemplate(props.contentRender); + const template = this._getTemplate(props.template); return (
{ - if(element && element.parentElement) { + if(element?.parentElement) { const parent = element.parentElement; while(parent.firstChild) { parent.removeChild(parent.firstChild); } template.render({ model: data, container: parent }); - parent.appendChild(element); } }}/>); }; @@ -42,6 +42,7 @@ class Button extends Widget { activeStateEnabled: true, focusStateEnabled: true, hoverStateEnabled: true, + template: '', text: '', }); } From 4f1ee7ddc517576afcacb925ec8414bc3ce7f1a0 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Fri, 7 Feb 2020 17:34:22 +0300 Subject: [PATCH 02/24] Fix template rerender --- js/renovation/button.tsx | 6 +++--- js/renovation/dist/button.j.jsx | 18 ++++++++++++++++-- js/renovation/preact_wrapper.js | 7 +++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index 4c9dfd4ce5bf..efcc772b70f5 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -141,9 +141,9 @@ export default class Button extends JSXComponent { } } -type ButtonContent = { +declare type ButtonContent = { text: string, icon: string, } -type ButtonTemplateFn = (data: ButtonContent, container: any) => any -type ButtonTemplate = ButtonTemplateFn | string +declare type ButtonTemplateFn = (data: ButtonContent, container: any) => any +declare type ButtonTemplate = ButtonTemplateFn | string diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index b6c10bf4dd21..0984bf17290b 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -1,9 +1,14 @@ import registerComponent from '../../core/component_registrator'; import Widget from '../preact_wrapper'; import { extend } from '../../core/utils/extend'; +import { equalByValue } from '../../core/utils/common'; import ButtonView from '../button.p'; import * as Preact from 'preact'; +// NOTE: workaround to memoize template +let prevData; +let prevTemplate; + class Button extends Widget { getView() { return ButtonView; @@ -13,15 +18,24 @@ class Button extends Widget { const props = super.getProps(isFirstRender); if(props.template) { props.contentRender = (data) => { - const template = this._getTemplate(props.template); + const templateProp = this.option('template'); + + if(equalByValue(data, prevData) && prevTemplate === templateProp) return; + + const template = this._getTemplate(templateProp); return (
{ + prevTemplate = templateProp; + prevData = data; if(element?.parentElement) { const parent = element.parentElement; while(parent.firstChild) { parent.removeChild(parent.firstChild); } - template.render({ model: data, container: parent }); + template.render({ + model: data, + container: parent + }); } }}/>); }; diff --git a/js/renovation/preact_wrapper.js b/js/renovation/preact_wrapper.js index 300c12113cd7..0935716fbbe1 100644 --- a/js/renovation/preact_wrapper.js +++ b/js/renovation/preact_wrapper.js @@ -23,15 +23,18 @@ export default class PreactWrapper extends Widget { getProps(isFirstRender) { const options = extend({}, this.option()); + const attributes = this.$element()[0].attributes; if(isFirstRender) { - const attributes = this.$element()[0].attributes; options.elementAttr = extend(Object.keys(attributes).reduce((a, key) => { if(attributes[key].specified) { a[attributes[key].name] = attributes[key].value; } return a; }, {}), options.elementAttr); + } else { + // NOTE: workaround to save container id + options.elementAttr = extend({ [attributes.id.name]: attributes.id.value }, options.elementAttr); } return options; @@ -39,7 +42,7 @@ export default class PreactWrapper extends Widget { _renderContent() { const isFirstRender = this.$element().children().length === 0; - const container = isFirstRender ? this.$element().get(0) : undefined; + const container = isFirstRender ? this.$element().get(0) : this.$element().get(0); Preact.render(this.renderView(this.getProps(isFirstRender)), this.$element().get(0), container); } From 9b83fb3bf20e5ca9745bfbbc74ef7d1c5057b5d2 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Fri, 7 Feb 2020 17:46:47 +0300 Subject: [PATCH 03/24] Refactor --- js/renovation/preact_wrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/renovation/preact_wrapper.js b/js/renovation/preact_wrapper.js index 0935716fbbe1..4704270a61a7 100644 --- a/js/renovation/preact_wrapper.js +++ b/js/renovation/preact_wrapper.js @@ -42,7 +42,7 @@ export default class PreactWrapper extends Widget { _renderContent() { const isFirstRender = this.$element().children().length === 0; - const container = isFirstRender ? this.$element().get(0) : this.$element().get(0); + const container = isFirstRender ? this.$element().get(0) : undefined; Preact.render(this.renderView(this.getProps(isFirstRender)), this.$element().get(0), container); } From 02584023e38f8097771b77f04a0675aed364c80d Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Mon, 10 Feb 2020 12:36:00 +0300 Subject: [PATCH 04/24] Fix wrong render on set empty template property --- js/renovation/button.tsx | 1 + js/renovation/dist/button.j.jsx | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index e1a4a0b88c92..1e2bb1bccf91 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -100,6 +100,7 @@ export class ButtonInput extends WidgetInput { @OneWay() onSubmit?: (e: any) => any = (() => undefined); @OneWay() pressed?: boolean; @OneWay() stylingMode?: 'outlined' | 'text' | 'contained'; + @OneWay() template?: ButtonTemplate = ''; @OneWay() text?: string = ''; @OneWay() type?: string; @OneWay() useSubmitBehavior?: boolean = false; diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 0984bf17290b..2f99b899aa23 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -8,6 +8,13 @@ import * as Preact from 'preact'; // NOTE: workaround to memoize template let prevData; let prevTemplate; +let parent; + +const removeChildren = (element) => { + while(element.firstChild) { + element.removeChild(element.firstChild); + } +}; class Button extends Widget { getView() { @@ -16,6 +23,12 @@ class Button extends Widget { getProps(isFirstRender) { const props = super.getProps(isFirstRender); + + // NOTE: workaround to switch from custom template to default + if(!props.template) { + parent && removeChildren(parent); + } + if(props.template) { props.contentRender = (data) => { const templateProp = this.option('template'); @@ -27,11 +40,10 @@ class Button extends Widget { return (
{ prevTemplate = templateProp; prevData = data; + if(element?.parentElement) { - const parent = element.parentElement; - while(parent.firstChild) { - parent.removeChild(parent.firstChild); - } + parent = element.parentElement; + removeChildren(parent); template.render({ model: data, container: parent From cfddfb4ba8aba61d2cd314e6d3831cd518272974 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Mon, 10 Feb 2020 16:51:35 +0300 Subject: [PATCH 05/24] Add some tests --- testing/tests/Renovation/button.tests.js | 46 ++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 testing/tests/Renovation/button.tests.js diff --git a/testing/tests/Renovation/button.tests.js b/testing/tests/Renovation/button.tests.js new file mode 100644 index 000000000000..c59298266ac8 --- /dev/null +++ b/testing/tests/Renovation/button.tests.js @@ -0,0 +1,46 @@ +import $ from 'jquery'; +import 'renovation/dist/button.j'; +import { isRenderer } from 'core/utils/type'; +import globalConfig from 'core/config'; + +QUnit.testStart(function() { + $('#qunit-fixture').html(` +
+
+ `); +}); + +const config = { + beforeEach: function(module) { + // it needs for Preact timers https://github.com/preactjs/preact/blob/master/hooks/src/index.js#L273 + this.clock = sinon.useFakeTimers(); + }, + afterEach: function() { + this.clock.tick(100); + this.clock.restore(); + } +}; + +QUnit.module('Props: template', config); + +QUnit.test('should render button with default template', function(assert) { + const $element = $('#component'); + $element.Button({ text: 'test', icon: 'check' }); + const $contentElements = $element.find('.dx-button-content').children(); + + assert.equal($element.Button('instance').option('template'), '', 'default template value'); + assert.ok($contentElements.eq(0).hasClass('dx-icon'), 'render icon'); + assert.ok($contentElements.eq(1).hasClass('dx-button-text'), 'render test'); +}); + +QUnit.test('should render template function', function(assert) { + const $element = $('#component'); + + $element.Button({ + template: function(data, container) { + assert.equal(isRenderer(container), !!globalConfig().useJQuery, 'container is correct'); + return $('
'); + } + }); + assert.equal($element.find('#custom-template').length, 1, 'render custom template'); +}); From 89883f4a5d8f10ccb7b311b83548b49826478efe Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Tue, 11 Feb 2020 12:50:58 +0300 Subject: [PATCH 06/24] Implement wrapper behaviour --- js/renovation/button.tsx | 24 +++++++------ js/renovation/dist/button.j.jsx | 61 ++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index 1e2bb1bccf91..160a4090c562 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -75,17 +75,19 @@ export const viewFunction = (viewModel: ButtonViewModel) => { visible={viewModel.visible} width={viewModel.width} > -
- {viewModel.contentRender && - } - {!viewModel.contentRender && viewModel.icon} - {!viewModel.contentRender && viewModel.text && - {viewModel.text} - } - {viewModel.useSubmitBehavior && - - } -
+ {(viewModel.contentRender && + + ) || ( +
+ {viewModel.icon} + {viewModel.text && + {viewModel.text} + } + {viewModel.useSubmitBehavior && + + } +
+ )} ; }; diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 2f99b899aa23..91100c5cb312 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -1,17 +1,20 @@ + +import $ from '../../core/renderer'; +import * as Preact from 'preact'; import registerComponent from '../../core/component_registrator'; import Widget from '../preact_wrapper'; import { extend } from '../../core/utils/extend'; import { equalByValue } from '../../core/utils/common'; import ButtonView from '../button.p'; -import * as Preact from 'preact'; // NOTE: workaround to memoize template let prevData; let prevTemplate; -let parent; +let component; +let wrapper = false; const removeChildren = (element) => { - while(element.firstChild) { + while(element?.firstChild) { element.removeChild(element.firstChild); } }; @@ -26,32 +29,43 @@ class Button extends Widget { // NOTE: workaround to switch from custom template to default if(!props.template) { - parent && removeChildren(parent); + component && removeChildren($(component).parent().get(0)); } if(props.template) { props.contentRender = (data) => { const templateProp = this.option('template'); + const shouldRender = !equalByValue(data, prevData) || prevTemplate !== templateProp; - if(equalByValue(data, prevData) && prevTemplate === templateProp) return; + if(shouldRender) { + const template = this._getTemplate(templateProp); - const template = this._getTemplate(templateProp); + component && removeChildren($(component).parent().get(0)); - return (
{ prevTemplate = templateProp; prevData = data; + wrapper = false; - if(element?.parentElement) { - parent = element.parentElement; - removeChildren(parent); - template.render({ - model: data, - container: parent - }); - } - }}/>); + component =
{ + if(element) { + const $template = $(template.render({ + model: data, + container: element + })); + if($template.hasClass('dx-template-wrapper')) { + $template.addClass('dx-button-content'); + $(element).replaceWith($template); + component = $template; + wrapper = true; + } + } + }}/>; + } + + return !wrapper && component; }; } + props.onClick = this._createActionByOption('onClick', { excludeValidators: ['readOnly'], afterExecute: () => { @@ -72,6 +86,21 @@ class Button extends Widget { text: '', }); } + + _initTemplates() { + super._initTemplates(); + this._templateManager.addDefaultTemplates({ + test: { + render: function(args) { + const $element = $('') + .addClass('dx-template-wrapper') + .text('button'); + + return $element.get(0); + } + } + }); + } } registerComponent('Button', Button); From 3a091e470287d9d85c7f9a6b4796bfa35b86a37c Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Wed, 12 Feb 2020 16:49:27 +0300 Subject: [PATCH 07/24] Refactor template render --- js/renovation/button.tsx | 6 +-- js/renovation/dist/button.j.jsx | 68 +++++++++++++-------------------- 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index d57115e9b5af..82d33ea558b5 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -95,9 +95,9 @@ export const viewFunction = (viewModel: ButtonViewModel) => { width={viewModel.width} > {(viewModel.contentRender && - + ) || ( -
+
{viewModel.icon} {viewModel.text && {viewModel.text} @@ -136,7 +136,7 @@ export class ButtonInput extends WidgetInput { }) export default class Button extends JSXComponent { - @Ref() contentRef!: HTMLDivElement; + @Ref() contentRef!: HTMLElement; @Ref() submitInputRef!: HTMLInputElement; @Effect() diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 91100c5cb312..67c61186ea72 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -4,19 +4,25 @@ import * as Preact from 'preact'; import registerComponent from '../../core/component_registrator'; import Widget from '../preact_wrapper'; import { extend } from '../../core/utils/extend'; -import { equalByValue } from '../../core/utils/common'; import ButtonView from '../button.p'; -// NOTE: workaround to memoize template -let prevData; -let prevTemplate; -let component; -let wrapper = false; +const HTMLToPreact = (node) => { + if(node.nodeType === 3) { + return node.wholeText; + } -const removeChildren = (element) => { - while(element?.firstChild) { - element.removeChild(element.firstChild); + const tag = node.tagName; + const attributes = [...node.attributes].reduce((acc, attr) => { + acc[attr.name] = attr.value; + return acc; + }, {}); + const childNodes = node.childNodes; + const children = []; + for(let i = 0; i < childNodes.length; i++) { + children.push(HTMLToPreact(childNodes[i])); } + + return Preact.h(tag, attributes, children); }; class Button extends Widget { @@ -27,42 +33,22 @@ class Button extends Widget { getProps(isFirstRender) { const props = super.getProps(isFirstRender); - // NOTE: workaround to switch from custom template to default - if(!props.template) { - component && removeChildren($(component).parent().get(0)); - } - if(props.template) { - props.contentRender = (data) => { + props.contentRender = ({ text, icon, contentRef }) => { + const data = { text, icon }; + let $content = $('
'); const templateProp = this.option('template'); - const shouldRender = !equalByValue(data, prevData) || prevTemplate !== templateProp; - - if(shouldRender) { - const template = this._getTemplate(templateProp); - - component && removeChildren($(component).parent().get(0)); - - prevTemplate = templateProp; - prevData = data; - wrapper = false; - - component =
{ - if(element) { - const $template = $(template.render({ - model: data, - container: element - })); - if($template.hasClass('dx-template-wrapper')) { - $template.addClass('dx-button-content'); - $(element).replaceWith($template); - component = $template; - wrapper = true; - } - } - }}/>; + const $template = $(this._getTemplate(templateProp).render({ model: data, container: $content })); + + if($template.hasClass('dx-template-wrapper')) { + $template.addClass('dx-button-content'); + $content = $template; } - return !wrapper && component; + const result = HTMLToPreact($content.get(0)); + result.ref = contentRef; + + return result; }; } From 0c84358bf50954fe7e13794210e7bb256c846530 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Wed, 12 Feb 2020 16:57:35 +0300 Subject: [PATCH 08/24] Correct className assignment --- js/renovation/dist/button.j.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 67c61186ea72..f013db4af2ad 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -36,15 +36,16 @@ class Button extends Widget { if(props.template) { props.contentRender = ({ text, icon, contentRef }) => { const data = { text, icon }; - let $content = $('
'); + let $content = $('
'); const templateProp = this.option('template'); const $template = $(this._getTemplate(templateProp).render({ model: data, container: $content })); if($template.hasClass('dx-template-wrapper')) { - $template.addClass('dx-button-content'); $content = $template; } + $content.addClass('dx-button-content'); + const result = HTMLToPreact($content.get(0)); result.ref = contentRef; From f834f7784149cbe299d5b5e93334edc610d50e9f Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Wed, 12 Feb 2020 17:00:44 +0300 Subject: [PATCH 09/24] Remove useless code --- js/renovation/dist/button.j.jsx | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index f013db4af2ad..2859254d687e 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -12,16 +12,18 @@ const HTMLToPreact = (node) => { } const tag = node.tagName; - const attributes = [...node.attributes].reduce((acc, attr) => { - acc[attr.name] = attr.value; - return acc; - }, {}); const childNodes = node.childNodes; + const children = []; for(let i = 0; i < childNodes.length; i++) { children.push(HTMLToPreact(childNodes[i])); } + const attributes = [...node.attributes].reduce((acc, attr) => { + acc[attr.name] = attr.value; + return acc; + }, {}); + return Preact.h(tag, attributes, children); }; @@ -73,21 +75,6 @@ class Button extends Widget { text: '', }); } - - _initTemplates() { - super._initTemplates(); - this._templateManager.addDefaultTemplates({ - test: { - render: function(args) { - const $element = $('') - .addClass('dx-template-wrapper') - .text('button'); - - return $element.get(0); - } - } - }); - } } registerComponent('Button', Button); From a0b2e778780f29bfd789df4e0092065f04e206e5 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Thu, 13 Feb 2020 10:13:39 +0300 Subject: [PATCH 10/24] Put converter function in separate file --- js/renovation/dist/button.j.jsx | 36 +++++-------------- js/renovation/dist/widget.j.jsx | 2 +- .../component.js} | 4 +-- js/renovation/preact-wrapper/utils.js | 23 ++++++++++++ 4 files changed, 35 insertions(+), 30 deletions(-) rename js/renovation/{preact_wrapper.js => preact-wrapper/component.js} (93%) create mode 100644 js/renovation/preact-wrapper/utils.js diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 2859254d687e..4ce549e92512 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -1,31 +1,10 @@ import $ from '../../core/renderer'; -import * as Preact from 'preact'; import registerComponent from '../../core/component_registrator'; -import Widget from '../preact_wrapper'; +import Widget from '../preact-wrapper/component'; import { extend } from '../../core/utils/extend'; import ButtonView from '../button.p'; - -const HTMLToPreact = (node) => { - if(node.nodeType === 3) { - return node.wholeText; - } - - const tag = node.tagName; - const childNodes = node.childNodes; - - const children = []; - for(let i = 0; i < childNodes.length; i++) { - children.push(HTMLToPreact(childNodes[i])); - } - - const attributes = [...node.attributes].reduce((acc, attr) => { - acc[attr.name] = attr.value; - return acc; - }, {}); - - return Preact.h(tag, attributes, children); -}; +import { HTMLToPreact } from '../preact-wrapper/utils'; class Button extends Widget { getView() { @@ -39,15 +18,18 @@ class Button extends Widget { props.contentRender = ({ text, icon, contentRef }) => { const data = { text, icon }; let $content = $('
'); - const templateProp = this.option('template'); - const $template = $(this._getTemplate(templateProp).render({ model: data, container: $content })); + $content.addClass('dx-button-content'); + const $template = $( + this._getTemplate(this.option('template')).render({ + model: data, container: $content + }) + ); if($template.hasClass('dx-template-wrapper')) { + $template.addClass('dx-button-content'); $content = $template; } - $content.addClass('dx-button-content'); - const result = HTMLToPreact($content.get(0)); result.ref = contentRef; diff --git a/js/renovation/dist/widget.j.jsx b/js/renovation/dist/widget.j.jsx index 2eebc9111096..a26c4ad4d28c 100644 --- a/js/renovation/dist/widget.j.jsx +++ b/js/renovation/dist/widget.j.jsx @@ -1,5 +1,5 @@ import registerComponent from '../../core/component_registrator'; -import WidgetBase from '../preact_wrapper'; +import WidgetBase from '../preact-wrapper/component'; import { extend } from '../../core/utils/extend'; import WidgetView from '../widget.p'; diff --git a/js/renovation/preact_wrapper.js b/js/renovation/preact-wrapper/component.js similarity index 93% rename from js/renovation/preact_wrapper.js rename to js/renovation/preact-wrapper/component.js index 4704270a61a7..f2ea92f3c224 100644 --- a/js/renovation/preact_wrapper.js +++ b/js/renovation/preact-wrapper/component.js @@ -1,6 +1,6 @@ -import Widget from '../ui/widget/ui.widget'; +import Widget from '../../ui/widget/ui.widget'; import * as Preact from 'preact'; -import { extend } from '../core/utils/extend'; +import { extend } from '../../core/utils/extend'; export default class PreactWrapper extends Widget { getInstance() { diff --git a/js/renovation/preact-wrapper/utils.js b/js/renovation/preact-wrapper/utils.js new file mode 100644 index 000000000000..be776ee5c6cf --- /dev/null +++ b/js/renovation/preact-wrapper/utils.js @@ -0,0 +1,23 @@ +import { h } from 'preact'; + +export const HTMLToPreact = (node) => { + // NOTE: nodeType === 3 => text node + if(node.nodeType === 3) { + return node.wholeText; + } + + const tag = node.tagName; + const childNodes = node.childNodes; + + const children = []; + for(let i = 0; i < childNodes.length; i++) { + children.push(HTMLToPreact(childNodes[i])); + } + + const attributes = [...node.attributes].reduce((result, attr) => { + result[attr.name] = attr.value; + return result; + }, {}); + + return h(tag, attributes, children); +}; From 43079c0a7bbe489d8c3cffef2657fa2a5b6b5199 Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Thu, 13 Feb 2020 12:36:32 +0300 Subject: [PATCH 11/24] Pass input for submit into template --- js/renovation/button.tsx | 6 +++++- js/renovation/dist/button.j.jsx | 4 ++-- js/renovation/preact-wrapper/utils.js | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/js/renovation/button.tsx b/js/renovation/button.tsx index 47e12eeef0dd..2c557d5ba159 100644 --- a/js/renovation/button.tsx +++ b/js/renovation/button.tsx @@ -103,7 +103,11 @@ export const viewFunction = (viewModel: ButtonViewModel) => { icon={viewModel.icon} text={viewModel.text} contentRef={viewModel.contentRef} - /> + > + {viewModel.useSubmitBehavior && + + } + ) || (
{isIconLeft && icon} diff --git a/js/renovation/dist/button.j.jsx b/js/renovation/dist/button.j.jsx index 8b7587dde044..3b1182e1c3b6 100644 --- a/js/renovation/dist/button.j.jsx +++ b/js/renovation/dist/button.j.jsx @@ -15,7 +15,7 @@ class Button extends Widget { const props = super.getProps(isFirstRender); if(props.template) { - props.contentRender = ({ text, icon, contentRef }) => { + props.contentRender = ({ text, icon, contentRef, children }) => { const data = { text, icon }; let $content = $('
'); $content.addClass('dx-button-content'); @@ -30,7 +30,7 @@ class Button extends Widget { $content = $template; } - const result = HTMLToPreact($content.get(0)); + const result = HTMLToPreact($content.get(0), children); result.ref = contentRef; return result; diff --git a/js/renovation/preact-wrapper/utils.js b/js/renovation/preact-wrapper/utils.js index be776ee5c6cf..7d7b538fef3e 100644 --- a/js/renovation/preact-wrapper/utils.js +++ b/js/renovation/preact-wrapper/utils.js @@ -1,6 +1,6 @@ import { h } from 'preact'; -export const HTMLToPreact = (node) => { +export const HTMLToPreact = (node, ...restChildren) => { // NOTE: nodeType === 3 => text node if(node.nodeType === 3) { return node.wholeText; @@ -19,5 +19,5 @@ export const HTMLToPreact = (node) => { return result; }, {}); - return h(tag, attributes, children); + return h(tag, attributes, [...children, ...restChildren]); }; From f319a551bfeb04eeba9e3382acc2c7938dad651b Mon Sep 17 00:00:00 2001 From: Andrey Ignatovskiy Date: Thu, 13 Feb 2020 14:06:39 +0300 Subject: [PATCH 12/24] Add jest tests --- testing/jest/button.tests.tsx | 45 +++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/testing/jest/button.tests.tsx b/testing/jest/button.tests.tsx index 40a75d059302..4177b7f26d38 100644 --- a/testing/jest/button.tests.tsx +++ b/testing/jest/button.tests.tsx @@ -210,16 +210,51 @@ describe('Button', () => { }); describe('contentRender', () => { - it('should render template', () => { + const contentRender = ({ text }) => +
+
{text + 123}
+
; + + it('should render contentRender', () => { const button = render({ text: 'My button', - contentRender: ({ text }) =>
{text + 123}
, + contentRender, }); - const buttonContentChildren = button.find('.dx-button-content').children(); + const customRender = button.find(contentRender); + + expect(customRender.exists()).toBe(true); + expect(customRender.exists('.dx-button-content')).toBe(true); + expect(customRender.exists('.custom-content')).toBe(true); - expect(buttonContentChildren.props().text).toBe('My button'); - expect(buttonContentChildren.render().text()).toBe('My button123'); + expect(customRender.props().text).toBe('My button'); + expect(customRender.render().text()).toBe('My button123'); }); + + it('should rerender contentRender in runtime', () => { + const button = mount(