Skip to content

Commit 89268d2

Browse files
committed
feat: add dynamic values support to WYSIWYG (ProseMirror & TinyMCE) editor fields
- Register 'editor' and 'wysiwyg' types in allowedTypes and defaultConfig (insert mode only) - Wrap ProseMirror editor with BaseWrapper; append token via setValue - Wrap TinyMCE with BaseWrapper; insert at cursor via tinyMCE.activeEditor.insertContent() - Fix BaseWrapper hasClear logic to require props.remove !== undefined - Fix List.updateItem: remove setTimeout so visibility toggle updates synchronously - Add editor dynamic value examples (ProseMirror and TinyMCE) to example page - Fix npm test script to quote path for environments with spaces (e.g. Local Sites)
1 parent ca0b8b2 commit 89268d2

8 files changed

Lines changed: 122 additions & 23 deletions

File tree

assets/src/components/dynamic/base-wrapper/BaseWrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ const BaseWrapper = props => {
148148
*/
149149
const buttonType = props.buttonType ?? 'outside'
150150
const hasInsert = !( props.readOnly || props.inputMasking ) && (buttonType === 'outside' || (! props.remove || props.remove.isDisabled))
151-
const hasClear = !( props.readOnly || props.inputMasking ) && (buttonType === 'outside' || (props.remove && props.remove.isDisabled === false))
151+
const hasClear = !( props.readOnly || props.inputMasking ) && props.remove !== undefined && (buttonType === 'outside' || props.remove.isDisabled === false)
152152

153153
const classes = `tf-dynamic-wrapper tf-dynamic-wrapper-buttons-${buttonType} ${props.className ?? ''}`
154154

assets/src/components/field/editor/TinyMce.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
Description
1212
} from '../../base'
1313

14+
import { BaseWrapper } from '../../dynamic/'
15+
1416
const TinyMce = props => {
1517

1618
const ref = useRef()
@@ -48,13 +50,27 @@ const TinyMce = props => {
4850

4951
useEffect(() => props.onChange && props.onChange(value), [value])
5052

53+
const insertDynamicValue = token => {
54+
if( tinyMCE.activeEditor ) {
55+
tinyMCE.activeEditor.insertContent(token)
56+
} else {
57+
setValue(prev => (prev ?? '') + token)
58+
}
59+
}
60+
5161
return (
5262
<div className="tf-editor">
5363
{props.label &&
5464
<Label labelProps={ labelProps } parent={ props }>
5565
{props.label}
5666
</Label>}
57-
<textarea ref={ref} {...inputProps}>{value}</textarea>
67+
<BaseWrapper
68+
config={ props.dynamic ?? false }
69+
onValueSelection={ insertDynamicValue }
70+
buttonType="outside"
71+
>
72+
<textarea ref={ref} {...inputProps}>{value}</textarea>
73+
</BaseWrapper>
5874
{ props.description &&
5975
<Description descriptionProps={ descriptionProps } parent={ props }>
6076
{ props.description }

assets/src/components/field/editor/prosemirror/Editor.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
Description
1313
} from '../../../base'
1414

15+
import { BaseWrapper } from '../../../dynamic/'
16+
1517
const Editor = props => {
1618

1719
const [value, setValue] = useState(props.value)
@@ -27,19 +29,27 @@ const Editor = props => {
2729
props.onChange && props.onChange(value)
2830
}, [value])
2931

32+
const insertDynamicValue = token => setValue(prev => (prev ?? '') + token)
33+
3034
return (
3135
<div className="tf-editor">
3236
{ props.label &&
3337
<Label labelProps={ labelProps } parent={ props }>
3438
{ props.label }
3539
</Label> }
36-
<input { ...inputProps } type="hidden" name={ props.name } value={ value } />
37-
<ProseMirror
38-
ref={ editorRef }
39-
value={ value }
40-
onChange={ setValue }
41-
rawView={ props.rawView ?? true }
42-
/>
40+
<BaseWrapper
41+
config={ props.dynamic ?? false }
42+
onValueSelection={ insertDynamicValue }
43+
buttonType="outside"
44+
>
45+
<input { ...inputProps } type="hidden" name={ props.name } value={ value } />
46+
<ProseMirror
47+
ref={ editorRef }
48+
value={ value }
49+
onChange={ setValue }
50+
rawView={ props.rawView ?? true }
51+
/>
52+
</BaseWrapper>
4353
{ props.description &&
4454
<Description descriptionProps={ descriptionProps } parent={ props }>
4555
{ props.description }

assets/src/components/field/list/List.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,11 @@ const List = props => {
5858
}
5959

6060
const updateItem = (i, name, value) => {
61-
setTimeout(() => {
62-
setItems([
63-
...items.slice(0, i),
64-
{ ...items[i], [name]: value },
65-
...items.slice(i + 1)
66-
])
67-
})
61+
setItems([
62+
...items.slice(0, i),
63+
{ ...items[i], [name]: value },
64+
...items.slice(i + 1)
65+
])
6866
}
6967

7068
const getItemText = item => (

assets/src/dynamic-values/index.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ const allowedTypes = [
1111
'color-picker',
1212
'conditional-panel',
1313
'date-picker',
14+
'editor', // alias of wysiwyg
1415
'number',
15-
'text'
16+
'text',
17+
'wysiwyg'
1618
]
1719

1820
/**
@@ -81,6 +83,30 @@ const defaultConfig = {
8183
'color',
8284
'number'
8385
]
86+
},
87+
'editor': {
88+
mode : {
89+
default : 'insert',
90+
supported : [ 'insert' ]
91+
},
92+
types : [
93+
'text',
94+
'date',
95+
'color',
96+
'number'
97+
]
98+
},
99+
'wysiwyg': {
100+
mode : {
101+
default : 'insert',
102+
supported : [ 'insert' ]
103+
},
104+
types : [
105+
'text',
106+
'date',
107+
'color',
108+
'number'
109+
]
84110
}
85111
}
86112

example/register/sections.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,13 @@
483483
'title' => 'Examples',
484484
'path' => 'dynamic-values/examples',
485485
'fields' => [
486-
'dynamic-text' => [ 'json' => true ],
487-
'dynamic-text-replace' => [ 'json' => true ],
488-
'dynamic-color' => [],
489-
'dynamic-date' => [],
490-
'dynamic-number' => [],
486+
'dynamic-text' => [ 'json' => true ],
487+
'dynamic-text-replace' => [ 'json' => true ],
488+
'dynamic-color' => [],
489+
'dynamic-date' => [],
490+
'dynamic-number' => [],
491+
'dynamic-editor' => [ 'json' => true ],
492+
'dynamic-editor-tinymce' => [ 'json' => true ],
491493
]
492494
]
493495
]

example/templates/dynamic-values/examples.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,50 @@
117117
<div class="tangible-settings-row">
118118
<?php submit_button() ?>
119119
</div>
120+
121+
<h4>Editor (ProseMirror)</h4>
122+
123+
<div class="tangible-settings-row">
124+
<?= $fields->render_field('dynamic-editor', [
125+
'label' => 'Editor field',
126+
'type' => 'wysiwyg',
127+
'value' => $fields->fetch_value('dynamic-editor'),
128+
'description' => 'Example description',
129+
'dynamic' => true
130+
]) ?>
131+
</div>
132+
133+
<?php tangible\see(
134+
'Raw value: ' . $fields->fetch_value('dynamic-editor'),
135+
'Parsed value: ' . $fields->render_value(
136+
$fields->fetch_value('dynamic-editor')
137+
),
138+
); ?>
139+
140+
<div class="tangible-settings-row">
141+
<?php submit_button() ?>
142+
</div>
143+
144+
<h4>Editor (TinyMCE)</h4>
145+
146+
<div class="tangible-settings-row">
147+
<?= $fields->render_field('dynamic-editor-tinymce', [
148+
'label' => 'Editor field (TinyMCE)',
149+
'type' => 'wysiwyg',
150+
'editor' => 'tinymce',
151+
'value' => $fields->fetch_value('dynamic-editor-tinymce'),
152+
'description' => 'Example description',
153+
'dynamic' => true
154+
]) ?>
155+
</div>
156+
157+
<?php tangible\see(
158+
'Raw value: ' . $fields->fetch_value('dynamic-editor-tinymce'),
159+
'Parsed value: ' . $fields->render_value(
160+
$fields->fetch_value('dynamic-editor-tinymce')
161+
),
162+
); ?>
163+
164+
<div class="tangible-settings-row">
165+
<?php submit_button() ?>
166+
</div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"composer": "FOLDER=`basename $(realpath $PWD)`; wp-env run cli --env-cwd=wp-content/plugins/$FOLDER composer",
3535
"composer:install": "wp-env run cli sudo apk add git && npm run composer install",
3636
"composer:update": "npm run composer update",
37-
"test": "FOLDER=`basename $(realpath $PWD)`; wp-env run tests-wordpress /var/www/html/wp-content/plugins/$FOLDER/vendor/bin/phpunit --testdox -c /var/www/html/wp-content/plugins/$FOLDER/phpunit.xml --verbose",
37+
"test": "FOLDER=`basename \"$(realpath \"$PWD\")\"`; wp-env run tests-wordpress /var/www/html/wp-content/plugins/$FOLDER/vendor/bin/phpunit --testdox -c /var/www/html/wp-content/plugins/$FOLDER/phpunit.xml --verbose",
3838
"test:7.4": "WP_ENV_PHP_VERSION=7.4 wp-env start && npm run test",
3939
"test:8.2": "WP_ENV_PHP_VERSION=8.2 wp-env start && npm run test",
4040
"test:all": "npm run test:7.4 && npm run test:8.2 && npm run e2e",

0 commit comments

Comments
 (0)