Skip to content

Commit 50ceb49

Browse files
authored
Merge pull request #204 from WebCoder49/ctrl-cmd-keys
Make keyboard shortcuts more intuitive in Apple
2 parents c063195 + 488cf6e commit 50ceb49

File tree

8 files changed

+57
-37
lines changed

8 files changed

+57
-37
lines changed

code-input.d.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,16 @@ export namespace plugins {
129129

130130
// ESM-SUPPORT-START-PLUGIN-find-and-replace Do not (re)move this - it's needed for ESM generation
131131
/**
132-
* Add Find-and-Replace (Ctrl+F for find, Ctrl+H for replace by default) functionality to the code editor.
132+
* Add Find-and-Replace (Ctrl/Cmd+F for find, Ctrl+H for replace by default) functionality to the code editor.
133133
* Files: find-and-replace.js / find-and-replace.css
134134
*/
135135
class FindAndReplace extends Plugin {
136136
/**
137-
* Create a find-and-replace command plugin to pass into a template
138-
* @param {boolean} useCtrlF Should Ctrl+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
137+
* Create a find-and-replace command plugin to pass into a template. To ensure keyboard shortcuts remain intuitive, set the alwaysCtrl parameter to false.
138+
* @param {boolean} useCtrlF Should Ctrl/Cmd+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
139139
* @param {boolean} useCtrlH Should Ctrl+H be overriden for find-and-replace replace functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
140140
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the find-and-replace.js source code for the English text.
141+
* @param {boolean} alwaysCtrl Setting this to false makes the keyboard shortcuts follow the operating system while avoiding clashes (right now: Cmd+F/Ctrl+H on Apple, Ctrl+F/Ctrl+H otherwise.) and is recommended; true forces Ctrl+F/Ctrl+H and is default for backwards compatibility.
141142
*/
142143
constructor(useCtrlF?: boolean, useCtrlH?: boolean,
143144
instructionTranslations?: {
@@ -159,7 +160,8 @@ export namespace plugins {
159160
replaceAction?: string;
160161
replaceAllActionShort?: string;
161162
replaceAllAction?: string
162-
}
163+
},
164+
alwaysCtrl?: boolean
163165
);
164166
/**
165167
* Show a find-and-replace dialog.
@@ -172,13 +174,13 @@ export namespace plugins {
172174

173175
// ESM-SUPPORT-START-PLUGIN-go-to-line Do not (re)move this - it's needed for ESM generation
174176
/**
175-
* Add basic Go-To-Line (ctrl-G by default) functionality to the code editor.
177+
* Add Go-To-Line (Ctrl/Cmd+G by default) functionality to the code editor.
176178
* Files: go-to-line.js / go-to-line.css
177179
*/
178180
class GoToLine extends Plugin {
179181
/**
180-
* Create a go-to-line command plugin to pass into a template
181-
* @param {boolean} useCtrlG Should Ctrl+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
182+
* Create a go-to-line command plugin to pass into a template.
183+
* @param {boolean} useCtrlG Should Ctrl/Cmd+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
182184
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the go-to-line.js source code for the English text.
183185
*/
184186
constructor(useCtrlG?: boolean,
@@ -190,7 +192,8 @@ export namespace plugins {
190192
guidanceColumnRange?: (line: Number, current: Number, max: Number) => string;
191193
guidanceValidLine?: (line: Number) => string;
192194
guidanceValidColumn?: (line: Number, column: Number) => string;
193-
});
195+
},
196+
);
194197
/**
195198
* Show a search-like dialog prompting line number.
196199
* @param {codeInput.CodeInput} codeInput the `<code-input>` element.

docs/i18n/_index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ code-input:not(.code-input_registered)::after {
2020

2121
It is only present for debugging and explanatory purposes when highlighting cannot be seen, and should not contain important or specific information about the editor state; if you need such information, especially for screen reader users, add separate text to your application which disappears after registering the code-input without errors.
2222

23-
**Plugins** sometimes come with user interface features (e.g. the find-and-replace dialog) which contain text to be translated. The text is provided as an extra argument to the plugin constructor containing translated strings or functions to produce them for each translation key, with the keys and their English values found in either the `code-input.d.ts` or the plugin's source code file. Here's an example:
23+
**Plugins** sometimes come with user interface features (e.g. the find-and-replace dialog) which contain text to be translated. The text is provided as an argument to the plugin constructor containing translated strings or functions to produce them for each translation key, with the keys and their English values found in either the `code-input.d.ts` or the plugin's source code file. Here's an example:
2424
```javascript
2525
// CC-BY; Attribution: Translated by Oliver Geer with some help from English Wiktionary
2626
let findAndReplaceTranslations = {
@@ -45,7 +45,7 @@ let findAndReplaceTranslations = {
4545
};
4646
// ...
4747
// passed when the plugin is constructed:
48-
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations),
48+
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations, false),
4949
```
5050

5151
## Other

docs/plugins/_index.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,10 @@ Right now, you can only add one plugin of each type (e.g. one SelectTokenCallbac
144144
145145
<script>
146146
let findAndReplacePlugin = new codeInput.plugins.FindAndReplace(
147-
true, // Should Ctrl+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
148-
true, // Should Ctrl+H be overriden for find-and-replace replace functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
147+
true, // Should Ctrl/Cmd+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
148+
true, // Should Ctrl/Cmd+H be overriden for find-and-replace replace functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
149+
{}, // Keep this as an empty object for the English UI, or add translations as in https://code-input-js.org/i18n/
150+
false // Setting this to false makes the keyboard shortcuts follow the operating system while avoiding clashes (right now: Cmd+F/Ctrl+H on Apple, Ctrl+F/Ctrl+H otherwise.) and is recommended; true forces Ctrl+F/Ctrl+H and is default for backwards compatibility.
149151
);
150152
// Programatically opening the dialogs, to integrate with your user interface
151153
function find() {
@@ -195,7 +197,8 @@ Hickory dickory dock.</code-input>
195197
196198
<script>
197199
let goToLinePlugin = new codeInput.plugins.GoToLine(
198-
true, // Should Ctrl+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
200+
true, // Should Ctrl/Cmd+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
201+
{}, // Keep this as an empty object for the English UI, or add translations as in https://code-input-js.org/i18n/
199202
);
200203
// Programatically opening the dialogs, to integrate with your user interface
201204
function goToLine() {

plugins/find-and-replace.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Add Find-and-Replace (Ctrl+F for find, Ctrl+H for replace by default) functionality to the code editor.
2+
* Add Find-and-Replace (Ctrl/Cmd+F for find, Ctrl+H for replace by default) functionality to the code editor.
33
* Files: find-and-replace.js / find-and-replace.css
44
*/
55
"use strict";
@@ -32,15 +32,17 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
3232
};
3333

3434
/**
35-
* Create a find-and-replace command plugin to pass into a template
36-
* @param {boolean} useCtrlF Should Ctrl+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
35+
* Create a find-and-replace command plugin to pass into a template. To ensure keyboard shortcuts remain intuitive, set the alwaysCtrl parameter to false.
36+
* @param {boolean} useCtrlF Should Ctrl/Cmd+F be overriden for find-and-replace find functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
3737
* @param {boolean} useCtrlH Should Ctrl+H be overriden for find-and-replace replace functionality? Either way, you can also trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, true)`.
38-
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the find-and-replace.js source code for the English text and available keys.
38+
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the find-and-replace.js source code for the English text.
39+
* @param {boolean} alwaysCtrl Setting this to false makes the keyboard shortcuts follow the operating system while avoiding clashes (right now: Cmd+F/Ctrl+H on Apple, Ctrl+F/Ctrl+H otherwise.) and is recommended; true forces Ctrl+F/Ctrl+H and is default for backwards compatibility.
3940
*/
40-
constructor(useCtrlF = true, useCtrlH = true, instructionTranslations = {}) {
41+
constructor(useCtrlF = true, useCtrlH = true, instructionTranslations = {}, alwaysCtrl = true) {
4142
super([]); // No observed attributes
4243
this.useCtrlF = useCtrlF;
4344
this.useCtrlH = useCtrlH;
45+
this.alwaysCtrl = alwaysCtrl;
4446
this.addTranslations(this.instructions, instructionTranslations);
4547
}
4648

@@ -420,11 +422,18 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
420422
this.updateFindMatches(dialog);
421423
}
422424

423-
/* Event handler for keydown event that makes Ctrl+F open find dialog */
425+
/* Event handler for keydown event that makes Ctrl/Cmd+F open find dialog */
424426
checkCtrlF(codeInput, event) {
425-
if (event.ctrlKey && event.key == 'f') {
426-
event.preventDefault();
427-
this.showPrompt(codeInput, false);
427+
if(!this.alwaysCtrl && (navigator.platform.startsWith("Mac") || navigator.platform === "iPhone")) {
428+
if (event.metaKey && event.key == 'f') { // Cmd+F
429+
event.preventDefault();
430+
this.showPrompt(codeInput, false);
431+
}
432+
} else {
433+
if (event.ctrlKey && event.key == 'f') {
434+
event.preventDefault();
435+
this.showPrompt(codeInput, false);
436+
}
428437
}
429438
}
430439

plugins/go-to-line.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Add basic Go-To-Line (Ctrl+G by default) functionality to the code editor.
2+
* Add Go-To-Line (Ctrl/Cmd+G by default) functionality to the code editor.
33
* Files: go-to-line.js / go-to-line.css
44
*/
55
"use strict";
@@ -18,9 +18,9 @@ codeInput.plugins.GoToLine = class extends codeInput.Plugin {
1818
};
1919

2020
/**
21-
* Create a go-to-line command plugin to pass into a template
22-
* @param {boolean} useCtrlG Should Ctrl+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
23-
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the go-to-line.js source code for the available keys and English text.
21+
* Create a go-to-line command plugin to pass into a template.
22+
* @param {boolean} useCtrlG Should Ctrl/Cmd+G be overriden for go-to-line functionality? Either way, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element)`.
23+
* @param {Object} instructionTranslations: user interface string keys mapped to translated versions for localisation. Look at the go-to-line.js source code for the English text.
2424
*/
2525
constructor(useCtrlG = true, instructionTranslations = {}) {
2626
super([]); // No observed attributes

tests/i18n-hljs.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
}
6363
}),
6464
new codeInput.plugins.Autodetect(),
65-
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations),
66-
new codeInput.plugins.GoToLine(true, goToLineTranslations),
65+
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations, false),
66+
new codeInput.plugins.GoToLine(true, goToLineTranslations, false),
6767
new codeInput.plugins.Indent(true, 2, {"(": ")", "[": "]", "{": "}"}, true, indentTranslations),
6868
new codeInput.plugins.SelectTokenCallbacks(codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks.createClassSynchronisation("in-selection"), false, true, true, true, true, false),
6969
//new codeInput.plugins.SpecialChars(true),

tests/i18n-prism.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
popupElem.style.display = "none";
6262
}
6363
}),
64-
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations),
65-
new codeInput.plugins.GoToLine(true, goToLineTranslations),
64+
new codeInput.plugins.FindAndReplace(true, true, findAndReplaceTranslations, false),
65+
new codeInput.plugins.GoToLine(true, goToLineTranslations, false),
6666
new codeInput.plugins.Indent(true, 2, {"(": ")", "[": "]", "{": "}"}, true, indentTranslations),
6767
new codeInput.plugins.SelectTokenCallbacks(new codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks(selectBrace, deselectAllBraces), true),
6868
//new codeInput.plugins.SpecialChars(true),

tests/tester.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,15 @@ function beginTest(isHLJS) {
120120
}
121121
}),
122122
new codeInput.plugins.Autodetect(),
123-
new codeInput.plugins.FindAndReplace(),
124-
new codeInput.plugins.GoToLine(),
123+
new codeInput.plugins.FindAndReplace(true, true, {}, false),
124+
new codeInput.plugins.GoToLine(true, {}),
125125
new codeInput.plugins.Indent(true, 2),
126126
new codeInput.plugins.SelectTokenCallbacks(codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks.createClassSynchronisation("in-selection"), false, true, true, true, true, false),
127127
new codeInput.plugins.SpecialChars(true),
128128
]));
129129
} else {
130130
codeInput.registerTemplate("code-editor", new codeInput.templates.Prism(Prism, [
131-
new codeInput.plugins.AutoCloseBrackets(),
131+
new codeInput.plugins.AutoCloseBrackets(),
132132
new codeInput.plugins.Autocomplete(function(popupElem, textarea, selectionEnd, selectionStart) {
133133
if(selectionStart == selectionEnd && textarea.value.substring(selectionEnd-5, selectionEnd) == "popup") {
134134
// Show popup
@@ -138,8 +138,8 @@ function beginTest(isHLJS) {
138138
popupElem.style.display = "none";
139139
}
140140
}),
141-
new codeInput.plugins.FindAndReplace(),
142-
new codeInput.plugins.GoToLine(),
141+
new codeInput.plugins.FindAndReplace(true, true, {}, false),
142+
new codeInput.plugins.GoToLine(true, {}),
143143
new codeInput.plugins.Indent(true, 2),
144144
new codeInput.plugins.SelectTokenCallbacks(new codeInput.plugins.SelectTokenCallbacks.TokenSelectorCallbacks(selectBrace, deselectAllBraces), true),
145145
new codeInput.plugins.SpecialChars(true),
@@ -489,7 +489,12 @@ console.log("I've got another line!", 2 &lt; 3, "should be true.");
489489
await waitAsync(50); // Wait for highlighting so text updates
490490

491491
// Open dialog and get interactive elements
492-
textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "f", "ctrlKey": true }));
492+
// Thanks to https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform
493+
if(navigator.platform.startsWith("Mac") || navigator.platform === "iPhone") {
494+
textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "f", "metaKey": true }));
495+
} else {
496+
textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "f", "ctrlKey": true }));
497+
}
493498
let inputBoxes = codeInputElement.querySelectorAll(".code-input_find-and-replace_dialog input");
494499
let findInput = inputBoxes[0];
495500
let regExpCheckbox = inputBoxes[1];
@@ -587,7 +592,7 @@ console.log("I've got another line!", 2 &lt; 3, "should be true.");
587592
lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));
588593
lineInput.dispatchEvent(new KeyboardEvent("keyup", { "key": "Enter" }));
589594
assertEqual("GoToLine", "Line and Column", textarea.selectionStart, 45);
590-
595+
591596
textarea.dispatchEvent(new KeyboardEvent("keydown", { "cancelable": true, "key": "g", "ctrlKey": true }));
592597
lineInput.value = "10";
593598
lineInput.dispatchEvent(new KeyboardEvent("keydown", { "key": "Enter" }));

0 commit comments

Comments
 (0)