@livingdocs/editable.js 3.0.13 → 3.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editable.js +1 -1
- package/dist/editable.js.map +1 -1
- package/package.json +4 -4
- package/src/config.js +8 -4
- package/src/dispatcher.js +7 -1
- package/src/highlight-text.js +2 -2
- package/src/selection.js +22 -2
- package/src/util/string.js +18 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livingdocs/editable.js",
|
|
3
3
|
"description": "Friendly contenteditable API",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.16",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/runtime": "^7.16.7",
|
|
7
7
|
"bowser": "2.11.0",
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
"isCi": true,
|
|
84
84
|
"name": "Drone",
|
|
85
85
|
"service": "drone",
|
|
86
|
-
"commit": "
|
|
87
|
-
"build": "
|
|
86
|
+
"commit": "85752c5c2a4de6108413bc50b0433086ce0d0435",
|
|
87
|
+
"build": "469",
|
|
88
88
|
"branch": "master",
|
|
89
89
|
"isPr": false,
|
|
90
90
|
"slug": "livingdocsIO/editable.js",
|
|
91
|
-
"date": "2022-
|
|
91
|
+
"date": "2022-03-15T10:07:49.382Z"
|
|
92
92
|
}
|
|
93
93
|
}
|
package/src/config.js
CHANGED
|
@@ -13,22 +13,26 @@ export default {
|
|
|
13
13
|
boldMarkup: {
|
|
14
14
|
type: 'tag',
|
|
15
15
|
name: 'strong',
|
|
16
|
-
attribs: {}
|
|
16
|
+
attribs: {},
|
|
17
|
+
trim: true
|
|
17
18
|
},
|
|
18
19
|
italicMarkup: {
|
|
19
20
|
type: 'tag',
|
|
20
21
|
name: 'em',
|
|
21
|
-
attribs: {}
|
|
22
|
+
attribs: {},
|
|
23
|
+
trim: true
|
|
22
24
|
},
|
|
23
25
|
underlineMarkup: {
|
|
24
26
|
type: 'tag',
|
|
25
27
|
name: 'u',
|
|
26
|
-
attribs: {}
|
|
28
|
+
attribs: {},
|
|
29
|
+
trim: false
|
|
27
30
|
},
|
|
28
31
|
linkMarkup: {
|
|
29
32
|
type: 'tag',
|
|
30
33
|
name: 'a',
|
|
31
|
-
attribs: {}
|
|
34
|
+
attribs: {},
|
|
35
|
+
trim: true
|
|
32
36
|
},
|
|
33
37
|
|
|
34
38
|
// Rules that are applied when filtering pasted content
|
package/src/dispatcher.js
CHANGED
|
@@ -5,6 +5,7 @@ import SelectionWatcher from './selection-watcher'
|
|
|
5
5
|
import config from './config'
|
|
6
6
|
import Keyboard from './keyboard'
|
|
7
7
|
import {closest} from './util/dom'
|
|
8
|
+
import {replaceLast, endsWithSingleSpace} from './util/string'
|
|
8
9
|
|
|
9
10
|
// This will be set to true once we detect the input event is working.
|
|
10
11
|
// Input event description on MDN:
|
|
@@ -134,7 +135,12 @@ export default class Dispatcher {
|
|
|
134
135
|
|
|
135
136
|
const {blocks, cursor} = clipboard.paste(block, selection, clipboardContent)
|
|
136
137
|
if (blocks.length) {
|
|
137
|
-
|
|
138
|
+
if (endsWithSingleSpace(evt.target.innerText)) {
|
|
139
|
+
block.innerHTML = replaceLast(block.innerHTML, ' ', ' ')
|
|
140
|
+
this.notify('paste', block, blocks, this.editable.createCursorAtEnd(block))
|
|
141
|
+
} else {
|
|
142
|
+
this.notify('paste', block, blocks, cursor)
|
|
143
|
+
}
|
|
138
144
|
|
|
139
145
|
// The input event does not fire when we process the content manually
|
|
140
146
|
// and insert it via script
|
package/src/highlight-text.js
CHANGED
|
@@ -134,7 +134,7 @@ export default {
|
|
|
134
134
|
// This has two notable behaviours:
|
|
135
135
|
// - It uses a NodeIterator which will skip elements
|
|
136
136
|
// with data-editable="remove"
|
|
137
|
-
// - It returns a
|
|
137
|
+
// - It returns a \n for <br> elements
|
|
138
138
|
// (The only block level element allowed inside of editables)
|
|
139
139
|
function getText (element, callback) {
|
|
140
140
|
const iterator = new NodeIterator(element)
|
|
@@ -143,7 +143,7 @@ function getText (element, callback) {
|
|
|
143
143
|
if (next.nodeType === nodeType.textNode && next.data !== '') {
|
|
144
144
|
callback(next.data)
|
|
145
145
|
} else if (next.nodeType === nodeType.elementNode && next.nodeName === 'BR') {
|
|
146
|
-
callback('
|
|
146
|
+
callback('\n')
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
}
|
package/src/selection.js
CHANGED
|
@@ -87,9 +87,21 @@ export default class Selection extends Cursor {
|
|
|
87
87
|
link.setAttribute(key, value)
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
if (config.linkMarkup.trim) this.trimRange()
|
|
91
|
+
|
|
90
92
|
this.forceWrap(link)
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
// trims whitespaces on the left and right of a selection, i.e. what you want in case of links
|
|
96
|
+
trimRange () {
|
|
97
|
+
const textToTrim = this.range.toString()
|
|
98
|
+
const whitespacesOnTheLeft = textToTrim.search(/\S|$/)
|
|
99
|
+
const lastNonWhitespace = textToTrim.search(/\S[\s]+$/)
|
|
100
|
+
const whitespacesOnTheRight = lastNonWhitespace === -1 ? 0 : textToTrim.length - (lastNonWhitespace + 1)
|
|
101
|
+
this.range.setStart(this.range.startContainer, this.range.startOffset + whitespacesOnTheLeft)
|
|
102
|
+
this.range.setEnd(this.range.endContainer, this.range.endOffset - whitespacesOnTheRight)
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
unlink () {
|
|
94
106
|
this.removeFormatting(config.linkMarkup.name)
|
|
95
107
|
}
|
|
@@ -137,43 +149,51 @@ export default class Selection extends Cursor {
|
|
|
137
149
|
this.setSelection()
|
|
138
150
|
}
|
|
139
151
|
|
|
140
|
-
toggleCustom ({tagName, attributes}) {
|
|
152
|
+
toggleCustom ({tagName, attributes, trim = false}) {
|
|
141
153
|
const customElem = this.createElement(tagName, attributes)
|
|
154
|
+
if (trim) this.trimRange()
|
|
142
155
|
this.toggle(customElem)
|
|
143
156
|
}
|
|
144
157
|
|
|
145
|
-
makeCustom ({tagName, attributes}) {
|
|
158
|
+
makeCustom ({tagName, attributes, trim = false}) {
|
|
146
159
|
const customElem = this.createElement(tagName, attributes)
|
|
160
|
+
if (trim) this.trimRange()
|
|
147
161
|
this.forceWrap(customElem)
|
|
148
162
|
}
|
|
149
163
|
|
|
150
164
|
makeBold () {
|
|
151
165
|
const bold = this.createElement(config.boldMarkup.name, config.boldMarkup.attribs)
|
|
166
|
+
if (config.boldMarkup.trim) this.trimRange()
|
|
152
167
|
this.forceWrap(bold)
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
toggleBold () {
|
|
156
171
|
const bold = this.createElement(config.boldMarkup.name, config.boldMarkup.attribs)
|
|
172
|
+
if (config.boldMarkup.trim) this.trimRange()
|
|
157
173
|
this.toggle(bold)
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
giveEmphasis () {
|
|
161
177
|
const em = this.createElement(config.italicMarkup.name, config.italicMarkup.attribs)
|
|
178
|
+
if (config.italicMarkup.trim) this.trimRange()
|
|
162
179
|
this.forceWrap(em)
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
toggleEmphasis () {
|
|
166
183
|
const em = this.createElement(config.italicMarkup.name, config.italicMarkup.attribs)
|
|
184
|
+
if (config.italicMarkup.trim) this.trimRange()
|
|
167
185
|
this.toggle(em)
|
|
168
186
|
}
|
|
169
187
|
|
|
170
188
|
makeUnderline () {
|
|
171
189
|
const u = this.createElement(config.underlineMarkup.name, config.underlineMarkup.attribs)
|
|
190
|
+
if (config.underlineMarkup.trim) this.trimRange()
|
|
172
191
|
this.forceWrap(u)
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
toggleUnderline () {
|
|
176
195
|
const u = this.createElement(config.underlineMarkup.name, config.underlineMarkup.attribs)
|
|
196
|
+
if (config.underlineMarkup.trim) this.trimRange()
|
|
177
197
|
this.toggle(u)
|
|
178
198
|
}
|
|
179
199
|
|
package/src/util/string.js
CHANGED
|
@@ -61,3 +61,21 @@ export function browserEscapeHtml (str) {
|
|
|
61
61
|
div.appendChild(document.createTextNode(str))
|
|
62
62
|
return div.innerHTML
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
export function replaceLast (text, searchValue, replaceValue) {
|
|
66
|
+
if (!text) return ''
|
|
67
|
+
text = `${text}`
|
|
68
|
+
if (!searchValue || replaceValue == null) return text
|
|
69
|
+
const lastOccurrenceIndex = text.lastIndexOf(searchValue)
|
|
70
|
+
return `${
|
|
71
|
+
text.slice(0, lastOccurrenceIndex)
|
|
72
|
+
}${
|
|
73
|
+
replaceValue
|
|
74
|
+
}${
|
|
75
|
+
text.slice(lastOccurrenceIndex + searchValue.length)
|
|
76
|
+
}`
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function endsWithSingleSpace (text) {
|
|
80
|
+
return /\S+\s{1}$/.test(text)
|
|
81
|
+
}
|