Skip to content

Commit 157cb46

Browse files
committed
feat: add delay before smartQuotes are applied
1 parent 3f5f4c7 commit 157cb46

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

src/dispatcher.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export default class Dispatcher {
8989
* @method setupElementListeners
9090
*/
9191
setupElementListeners () {
92+
const currentInput = {offset: undefined}
9293
this
9394
.setupDocumentListener('focus', function focusListener (evt) {
9495
const block = this.getEditableBlockByEvent(evt)
@@ -148,7 +149,12 @@ export default class Dispatcher {
148149

149150
if (shouldApplySmartQuotes(config, evt.target)) {
150151
const selection = this.selectionWatcher.getFreshSelection()
151-
applySmartQuotes(selection.range, config, evt.data, evt.target)
152+
// Save offset of new input, to reset cursor correctly after timeout delay
153+
currentInput.offset = selection.range?.startOffset
154+
setTimeout(() => {
155+
applySmartQuotes(selection.range, config, evt.data, evt.target, currentInput.offset)
156+
}, 500
157+
)
152158
}
153159

154160
this.notify('change', block)

src/smartQuotes.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,38 @@ const shouldBeClosingQuote = (text, indexCharBefore) => text[indexCharBefore] &&
1616

1717
const replaceQuote = (range, index, quoteType) => {
1818
const startContainer = range.startContainer
19+
if (!startContainer.nodeValue) {
20+
return
21+
}
1922
const textNode = document.createTextNode(`${startContainer.nodeValue.substring(0, index)}${quoteType}${startContainer.nodeValue.substring(index + 1)}`)
20-
range.startContainer.replaceWith(textNode)
23+
startContainer.replaceWith(textNode)
2124
return textNode
2225
}
2326

27+
// TODO: Fix ‹Didn’t› case -> only works with timeout
28+
const hasCharAfter = (textArr, offset) => {
29+
console.log('textArr :>> ', textArr)
30+
console.log('offset :>> ', offset)
31+
return false
32+
}
33+
2434
const hasSingleOpeningQuote = (textArr, offset, singleOpeningQuote) => {
2535
if (offset <= 0) {
2636
return false
2737
}
2838
for (let i = offset - 1; i >= 0; i--) {
2939
if (isSingleQuote(textArr[i]) && (!isApostrophe(singleOpeningQuote) && !isApostrophe(textArr[i]))) {
3040
return textArr[i] === singleOpeningQuote
41+
// TODO: keep on looking for an unclosed single opening quote -> need to save single opening and closing quotes
42+
// if (textArr[i] === singleOpeningQuote) {
43+
// return true
44+
// }
3145
}
3246
}
3347
return false
3448
}
3549

36-
export const applySmartQuotes = (range, config, char, target) => {
50+
export const applySmartQuotes = (range, config, char, target, carretOffset) => {
3751
const isCharSingleQuote = isSingleQuote(char)
3852
const isCharDoubleQuote = isDoubleQuote(char)
3953

@@ -47,14 +61,16 @@ export const applySmartQuotes = (range, config, char, target) => {
4761
let newTextNode
4862

4963
if (shouldBeClosingQuote(textArr, offset - 2)) {
50-
// Don't transform single-quote if there is no respective single-opening-quote
51-
if (isCharSingleQuote && !hasSingleOpeningQuote(textArr, offset, singleQuotes[0])) {
52-
return
64+
if (isCharSingleQuote) {
65+
// Don't transform apostrophes
66+
if (hasCharAfter(textArr, offset)) {
67+
return
68+
}
69+
// Don't transform single-quote if there is no respective single-opening-quote
70+
if (!hasSingleOpeningQuote(textArr, offset, singleQuotes[0])) {
71+
return
72+
}
5373
}
54-
// TODO: Fix ‹Didn’t› case -> only works with timeout
55-
// if (isCharSingleQuote && hasTextAfter(target, offset)) {
56-
// return
57-
// }
5874
const closingQuote = isCharSingleQuote ? singleQuotes[1] : quotes[1]
5975
newTextNode = replaceQuote(range, offset - 1, closingQuote)
6076
} else if (shouldBeOpeningQuote(textArr, offset - 2)) {
@@ -69,5 +85,7 @@ export const applySmartQuotes = (range, config, char, target) => {
6985
// Resets the cursor
7086
const window = target.ownerDocument.defaultView
7187
const selection = window.getSelection()
72-
selection.collapse(newTextNode, offset)
88+
selection.collapse(newTextNode, carretOffset ?? offset)
7389
}
90+
91+
// TODO: fix special case when quickly typing two quotes after each other

0 commit comments

Comments
 (0)