Skip to content

Commit cffc4d6

Browse files
committed
feat: create smartQuotes functionality and add to dispatcher
1 parent 0049bf6 commit cffc4d6

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/dispatcher.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import config from './config.js'
66
import Keyboard from './keyboard.js'
77
import {closest} from './util/dom.js'
88
import {replaceLast, endsWithSingleSpace} from './util/string.js'
9+
import {shouldApplySmartQuotes, isQuote, isOpeningQuote, isClosingQuote} from './smartQuotes.js'
910

1011
/**
1112
* The Dispatcher module is responsible for dealing with events and their handlers.
@@ -144,6 +145,39 @@ export default class Dispatcher {
144145
.setupDocumentListener('input', function inputListener (evt) {
145146
const block = this.getEditableBlockByEvent(evt)
146147
if (!block) return
148+
149+
const target = evt.target
150+
const currentChar = evt.data
151+
152+
153+
if (target.isContentEditable && shouldApplySmartQuotes(config)) {
154+
if (isQuote(currentChar)) {
155+
const selection = this.selectionWatcher.getFreshSelection()
156+
const wholeText = selection.range.startContainer.wholeText
157+
// const firstPart = selection.range.startContainer.textContent
158+
const offset = selection.range.startOffset
159+
if (isClosingQuote([...wholeText], offset - 2)) {
160+
const textArr = [...target.innerText]
161+
const index = offset - 1
162+
if (index >= 0 && index < textArr.length) {
163+
textArr[index] = '»'
164+
target.innerText = textArr.join('')
165+
}
166+
this.editable.createCursorAtCharacterOffset({element: block, offset})
167+
}
168+
169+
if (isOpeningQuote([...wholeText], offset - 2)) {
170+
const textArr = [...target.innerText]
171+
const index = offset - 1
172+
if (index >= 0 && index < textArr.length) {
173+
textArr[index] = '«'
174+
target.innerText = textArr.join('')
175+
}
176+
this.editable.createCursorAtCharacterOffset({element: block, offset})
177+
}
178+
}
179+
180+
}
147181
this.notify('change', block)
148182
})
149183

src/smartQuotes.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const isValidQuotePairConfig = (quotePair) => Array.isArray(quotePair) && quotePair.length === 2
2+
3+
export const shouldApplySmartQuotes = (config) => {
4+
const {smartQuotes, quotes, singleQuotes} = config
5+
return !!smartQuotes && isValidQuotePairConfig(quotes) && isValidQuotePairConfig(singleQuotes)
6+
}
7+
8+
export const isQuote = (char) => /^['«»"]$/.test(char)
9+
export const isDoubleQuote = (char) => /^[«»"]$/.test(char)
10+
export const isSingleQuote = (char) => /^[']$/.test(char)
11+
12+
// Test: '>', ' ', no space & all kinds of dashes dash
13+
export const isOpeningQuote = (text, indexCharBefore) => indexCharBefore < 0 || /\s|[>\-]/.test(text[indexCharBefore])
14+
15+
export const isClosingQuote = (text, indexCharBefore) => text[indexCharBefore] !== ' '

0 commit comments

Comments
 (0)