Skip to content

Commit e7ef3b6

Browse files
ztomaszykspocke
andauthored
TINY-10871: replace placeholders with labels in Find & Replace dialog (#9689)
* TINY-10871: change placeholders to labels and fix tests * TINY-10871: changelog * TINY-10871: improve phrasing in changelog Co-authored-by: spocke <[email protected]> * TINY-10871: use utils func in place --------- Co-authored-by: spocke <[email protected]>
1 parent 6ce11b6 commit e7ef3b6

File tree

8 files changed

+164
-51
lines changed

8 files changed

+164
-51
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
project: tinymce
2+
kind: Improved
3+
body: Improved Find & Replace dialog accessibility by changing placeholders to
4+
labels.
5+
time: 2024-06-05T14:25:44.504736+02:00
6+
custom:
7+
Issue: TINY-10871

modules/tinymce/src/plugins/searchreplace/main/ts/ui/Dialog.ts

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,37 +102,43 @@ const open = (editor: Editor, currentSearchState: Cell<Actions.SearchState>): vo
102102
const getPanelItems = (error: boolean): Dialog.BodyComponentSpec[] => {
103103
const items: Dialog.BodyComponentSpec[] = [
104104
{
105-
type: 'bar',
105+
type: 'label',
106+
label: 'Find',
107+
for: 'findtext',
106108
items: [
107109
{
108-
type: 'input',
109-
name: 'findtext',
110-
placeholder: 'Find',
111-
maximized: true,
112-
inputMode: 'search'
113-
},
114-
{
115-
type: 'button',
116-
name: 'prev',
117-
text: 'Previous',
118-
icon: 'action-prev',
119-
enabled: false,
120-
borderless: true
121-
},
122-
{
123-
type: 'button',
124-
name: 'next',
125-
text: 'Next',
126-
icon: 'action-next',
127-
enabled: false,
128-
borderless: true
110+
type: 'bar',
111+
items: [
112+
{
113+
type: 'input',
114+
name: 'findtext',
115+
maximized: true,
116+
inputMode: 'search'
117+
},
118+
{
119+
type: 'button',
120+
name: 'prev',
121+
text: 'Previous',
122+
icon: 'action-prev',
123+
enabled: false,
124+
borderless: true
125+
},
126+
{
127+
type: 'button',
128+
name: 'next',
129+
text: 'Next',
130+
icon: 'action-next',
131+
enabled: false,
132+
borderless: true
133+
}
134+
]
129135
}
130136
]
131137
},
132138
{
133139
type: 'input',
134140
name: 'replacetext',
135-
placeholder: 'Replace with',
141+
label: 'Replace with',
136142
inputMode: 'search'
137143
},
138144
];

modules/tinymce/src/plugins/searchreplace/test/ts/browser/SearchReplaceDialogCyclingTest.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogCyclingTest',
2121
base_url: '/project/tinymce/js/tinymce',
2222
}, [ Plugin ]);
2323

24+
const findInputSelector = Utils.getFindInputSelector();
25+
2426
const assertMatchFound = (editor: Editor, index: number) => {
2527
const matches = SelectorFilter.descendants(TinyDom.body(editor), '.mce-match-marker');
2628
const elem = matches[index];
@@ -40,7 +42,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogCyclingTest',
4042
editor.setContent('<p>fish fish fish</p>');
4143
TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 4);
4244
await Utils.pOpenDialog(editor);
43-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
45+
await Utils.pAssertFieldValue(editor, findInputSelector, 'fish');
4446
Utils.clickFind(editor);
4547
assertMatchFound(editor, 0);
4648
cycle(editor);
@@ -57,7 +59,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogCyclingTest',
5759
editor.setContent('<p>fish Fish fish Fish</p>');
5860
TinySelections.setSelection(editor, [ 0, 0 ], 5, [ 0, 0 ], 9);
5961
await Utils.pOpenDialog(editor);
60-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'Fish');
62+
await Utils.pAssertFieldValue(editor, findInputSelector, 'Fish');
6163
await Utils.pSelectPreference(editor, 'Match case');
6264
Utils.clickFind(editor);
6365
assertMatchFound(editor, 0);
@@ -74,7 +76,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogCyclingTest',
7476
editor.setContent('<p>ttt TTT ttt ttttt</p>');
7577
TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 3);
7678
await Utils.pOpenDialog(editor);
77-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'ttt');
79+
await Utils.pAssertFieldValue(editor, findInputSelector, 'ttt');
7880
await Utils.pSelectPreference(editor, 'Find whole words only');
7981
Utils.clickFind(editor);
8082
assertMatchFound(editor, 0);
@@ -93,7 +95,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogCyclingTest',
9395
editor.setContent('<p>^^ ^^ ^^ fish</p>');
9496
TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 2);
9597
await Utils.pOpenDialog(editor);
96-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', '^^');
98+
await Utils.pAssertFieldValue(editor, findInputSelector, '^^');
9799
Utils.clickFind(editor);
98100
assertMatchFound(editor, 0);
99101
cycle(editor);

modules/tinymce/src/plugins/searchreplace/test/ts/browser/SearchReplaceDialogTest.ts

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApproxStructure, Assertions, UiFinder } from '@ephox/agar';
12
import { describe, it } from '@ephox/bedrock-client';
23
import { Css, Scroll } from '@ephox/sugar';
34
import { TinyAssertions, TinyDom, TinyHooks, TinySelections, TinyUiActions } from '@ephox/wrap-mcagar';
@@ -16,6 +17,8 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
1617
base_url: '/project/tinymce/js/tinymce',
1718
}, [ Plugin ]);
1819

20+
const findInputSelector = Utils.getFindInputSelector();
21+
1922
const assertFound = (editor: Editor, count: number) => TinyAssertions.assertContentPresence(editor, {
2023
'.mce-match-marker': count
2124
});
@@ -29,7 +32,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
2932
const editor = hook.editor();
3033
editor.setContent('<p>fish fish fish</p>');
3134
await Utils.pOpenDialog(editor);
32-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', '');
35+
await Utils.pAssertFieldValue(editor, findInputSelector, '');
3336
TinyUiActions.closeDialog(editor);
3437
});
3538

@@ -38,7 +41,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
3841
editor.setContent('<p>fish fish fish</p>');
3942
TinySelections.setSelection(editor, [ 0, 0 ], 5, [ 0, 0 ], 9);
4043
await Utils.pOpenDialog(editor);
41-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
44+
await Utils.pAssertFieldValue(editor, findInputSelector, 'fish');
4245
findAndAssertFound(editor, 3);
4346
TinyUiActions.closeDialog(editor);
4447
});
@@ -48,7 +51,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
4851
editor.setContent('<p>fish Fish fish</p>');
4952
TinySelections.setSelection(editor, [ 0, 0 ], 5, [ 0, 0 ], 9);
5053
await Utils.pOpenDialog(editor);
51-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'Fish');
54+
await Utils.pAssertFieldValue(editor, findInputSelector, 'Fish');
5255
await Utils.pSelectPreference(editor, 'Match case');
5356
findAndAssertFound(editor, 1);
5457
await Utils.pSelectPreference(editor, 'Match case');
@@ -60,7 +63,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
6063
editor.setContent('<p>ttt TTT ttt ttttt</p>');
6164
TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 3);
6265
await Utils.pOpenDialog(editor);
63-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'ttt');
66+
await Utils.pAssertFieldValue(editor, findInputSelector, 'ttt');
6467
await Utils.pSelectPreference(editor, 'Find whole words only');
6568
findAndAssertFound(editor, 3);
6669
await Utils.pSelectPreference(editor, 'Find whole words only');
@@ -72,8 +75,8 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
7275
editor.setContent('<p>ttt TTT ttt ttttt</p>');
7376
TinySelections.setSelection(editor, [ 0, 0 ], 0, [ 0, 0 ], 7);
7477
await Utils.pOpenDialog(editor);
75-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'ttt TTT');
76-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'ttt');
78+
await Utils.pAssertFieldValue(editor, findInputSelector, 'ttt TTT');
79+
await Utils.pSetFieldValue(editor, findInputSelector, 'ttt');
7780
await Utils.pSelectPreference(editor, 'Find in selection');
7881
findAndAssertFound(editor, 2);
7982
TinyAssertions.assertSelection(editor, [ 0 ], 0, [ 0 ], 4);
@@ -86,7 +89,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
8689
editor.setContent('<p>fish fish Fish fishy</p>');
8790
TinySelections.setSelection(editor, [ 0, 0 ], 5, [ 0, 0 ], 9);
8891
await Utils.pOpenDialog(editor);
89-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
92+
await Utils.pAssertFieldValue(editor, findInputSelector, 'fish');
9093
findAndAssertFound(editor, 4);
9194
await Utils.pSelectPreference(editor, 'Match case');
9295
assertFound(editor, 0);
@@ -101,7 +104,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
101104
const editor = hook.editor();
102105
editor.setContent('<p>fish fish fish</p>');
103106
await Utils.pOpenDialogWithKeyboard(editor);
104-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', '');
107+
await Utils.pAssertFieldValue(editor, findInputSelector, '');
105108
TinyUiActions.closeDialog(editor);
106109
});
107110

@@ -110,7 +113,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
110113
editor.setContent('<p>fish fish fish</p>');
111114
TinySelections.setSelection(editor, [ 0, 0 ], 5, [ 0, 0 ], 9);
112115
await Utils.pOpenDialogWithKeyboard(editor);
113-
await Utils.pAssertFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
116+
await Utils.pAssertFieldValue(editor, findInputSelector, 'fish');
114117
findAndAssertFound(editor, 3);
115118
TinyUiActions.closeDialog(editor);
116119
});
@@ -130,7 +133,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
130133
const editor = hook.editor();
131134
editor.setContent('<p>tiny tiny tiny tiny</p>');
132135
await Utils.pOpenDialog(editor);
133-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'tiny');
136+
await Utils.pSetFieldValue(editor, findInputSelector, 'tiny');
134137
findAndAssertFound(editor, 4);
135138
await Utils.pSelectPreference(editor, 'Find in selection');
136139
assertFound(editor, 0);
@@ -141,4 +144,87 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceDialogTest', () =>
141144
assert.isFalse(await Utils.pAssertAlertInDialog(editor));
142145
TinyUiActions.closeDialog(editor);
143146
});
147+
148+
it('TINY-10871: Find label should point to the correct input through for attribute', async () => {
149+
const editor = hook.editor();
150+
editor.setContent('');
151+
const dialog = await Utils.pOpenDialog(editor);
152+
153+
Assertions.assertStructure('Check dialog form content syructure',
154+
ApproxStructure.build((s, str, arr) => s.element('div', {
155+
classes: [ arr.has('tox-form') ],
156+
children: [
157+
s.element('div', {
158+
classes: [ arr.has('tox-form__group') ],
159+
children: [
160+
s.element('label', {
161+
attrs: {
162+
for: str.startsWith('form-field')
163+
},
164+
children: [
165+
s.text(str.is('Find'))
166+
]
167+
}),
168+
s.element('div', {
169+
classes: [ arr.has('tox-bar') ],
170+
children: [
171+
s.element('div', {
172+
classes: [ arr.has('tox-form__group') ],
173+
children: [
174+
s.element('input', {
175+
attrs: {
176+
id: str.startsWith('form-field')
177+
}
178+
})
179+
]
180+
}),
181+
s.element('div', {
182+
classes: [ arr.has('tox-form__group') ],
183+
children: [
184+
s.element('button', {
185+
attrs: {
186+
'aria-label': str.is('Previous')
187+
}
188+
})
189+
]
190+
}),
191+
s.element('div', {
192+
classes: [ arr.has('tox-form__group') ],
193+
children: [
194+
s.element('button', {
195+
attrs: {
196+
'aria-label': str.is('Next')
197+
}
198+
})
199+
]
200+
})
201+
]
202+
})
203+
]
204+
}),
205+
s.element('div', {
206+
classes: [ arr.has('tox-form__group') ],
207+
children: [
208+
s.element('label', {
209+
attrs: {
210+
for: str.startsWith('form-field')
211+
},
212+
children: [
213+
s.text(str.is('Replace with'))
214+
]
215+
}),
216+
s.element('input', {
217+
attrs: {
218+
id: str.startsWith('form-field')
219+
}
220+
})
221+
]
222+
})
223+
]
224+
})),
225+
UiFinder.findIn(dialog, '.tox-dialog__body-content .tox-form').getOrDie()
226+
);
227+
228+
TinyUiActions.closeDialog(editor);
229+
});
144230
});

modules/tinymce/src/plugins/searchreplace/test/ts/browser/SearchReplaceKeyboardNavigationTest.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceKeyboardNavigationT
2222

2323
const doc = SugarDocument.getDocument();
2424

25+
const findInputSelector = Utils.getFindInputSelector();
26+
const replaceWithInputSelector = Utils.getReplaceWithInputSelector();
27+
2528
const pressTab = (editor: Editor) => TinyUiActions.keydown(editor, Keys.tab());
2629
const pressEsc = (editor: Editor) => TinyUiActions.keyup(editor, Keys.escape());
2730
const pressDown = (editor: Editor) => TinyUiActions.keydown(editor, Keys.down());
@@ -50,9 +53,9 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceKeyboardNavigationT
5053
it('TINY-3914: Dialog keyboard navigation', async () => {
5154
const editor = hook.editor();
5255
await Utils.pOpenDialog(editor);
53-
await pAssertFocused('Find input', '.tox-textfield[placeholder="Find"]');
56+
await pAssertFocused('Find input', findInputSelector);
5457
pressTab(editor);
55-
await pAssertFocused('Replace with input', '.tox-textfield[placeholder="Replace with"]');
58+
await pAssertFocused('Replace with input', replaceWithInputSelector);
5659
pressTab(editor);
5760
await pAssertFocused('Placeholder menu button', '.tox-tbtn--select[aria-label="Preferences"]');
5861
pressDown(editor);
@@ -68,33 +71,33 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplaceKeyboardNavigationT
6871
const editor = hook.editor();
6972
editor.setContent('<p>fish fish fish</p>');
7073
await Utils.pOpenDialog(editor);
71-
await pAssertFocused('Find input', '.tox-textfield[placeholder="Find"]');
74+
await pAssertFocused('Find input', findInputSelector);
7275
pressTab(editor);
73-
await pAssertFocused('Replace with input', '.tox-textfield[placeholder="Replace with"]');
76+
await pAssertFocused('Replace with input', replaceWithInputSelector);
7477
pressTab(editor);
7578
await pAssertFocused('Placeholder menu button', '.tox-tbtn--select[aria-label="Preferences"]');
7679
pressTab(editor);
7780
await pAssertFocused('Find button', '.tox-button[data-mce-name="Find"]');
78-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
81+
await Utils.pSetFieldValue(editor, findInputSelector, 'fish');
7982
pressEnter(editor);
8083
pressTab(editor);
8184
await pAssertFocused('Find button', '.tox-button[data-mce-name="Replace"]');
8285
pressTab(editor);
8386
await pAssertFocused('Find button', '.tox-button[data-mce-name="Replace all"]');
8487
pressEnter(editor);
85-
await pAssertFocused('Find input', '.tox-textfield[placeholder="Find"]');
88+
await pAssertFocused('Find input', findInputSelector);
8689
pressEsc(editor);
8790
});
8891

8992
it('TINY-4014: Dialog keyboard focus is returned to find input after displaying an alert', async () => {
9093
const editor = hook.editor();
9194
editor.setContent('<p>fish fish fish</p>');
9295
await Utils.pOpenDialog(editor);
93-
await pAssertFocused('Find input', '.tox-textfield[placeholder="Find"]');
94-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'notfound');
96+
await pAssertFocused('Find input', findInputSelector);
97+
await Utils.pSetFieldValue(editor, findInputSelector, 'notfound');
9598
pressEnter(editor);
9699
await TinyUi(editor).pWaitForUi('.tox-notification.tox-notification--error:contains("Could not find the specified string.")');
97-
await pAssertFocused('Find input', '.tox-textfield[placeholder="Find"]');
100+
await pAssertFocused('Find input', findInputSelector);
98101
pressEsc(editor);
99102
});
100103
});

modules/tinymce/src/plugins/searchreplace/test/ts/browser/SearchReplacePrevNextTest.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplacePrevNextTest', () =
3232
const editor = hook.editor();
3333
editor.setContent('<p>fish fish fish</p>');
3434
await Utils.pOpenDialog(editor);
35-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Find"]', 'fish');
35+
await Utils.pSetFieldValue(editor, Utils.getFindInputSelector(), 'fish');
3636
Utils.clickFind(editor);
3737

3838
// Initial button states for first match
@@ -51,7 +51,7 @@ describe('browser.tinymce.plugins.searchreplace.SearchReplacePrevNextTest', () =
5151
await pAssertButtonsEnabled();
5252

5353
// replace all but one value and assert next/previous are disabled
54-
await Utils.pSetFieldValue(editor, 'input.tox-textfield[placeholder="Replace with"]', 'squid');
54+
await Utils.pSetFieldValue(editor, Utils.getReplaceWithInputSelector(), 'squid');
5555
Utils.clickReplace(editor);
5656
await pAssertButtonsEnabled();
5757
Utils.clickReplace(editor);

0 commit comments

Comments
 (0)