@livingdocs/editable.js 3.0.2 → 3.0.6
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 +18 -18
- package/src/clipboard.js +8 -34
- package/src/cursor.js +8 -2
- package/src/dispatcher.js +14 -13
- package/src/plugins/highlighting/text-highlighting.js +16 -6
- package/src/selection.js +9 -1
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.6",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/runtime": "^7.13.17",
|
|
7
7
|
"bowser": "2.11.0",
|
|
@@ -9,21 +9,21 @@
|
|
|
9
9
|
"rangy": "^1.3.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@babel/cli": "^7.
|
|
13
|
-
"@babel/core": "^7.
|
|
14
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
15
|
-
"@babel/preset-env": "^7.
|
|
12
|
+
"@babel/cli": "^7.15.7",
|
|
13
|
+
"@babel/core": "^7.15.8",
|
|
14
|
+
"@babel/plugin-transform-runtime": "^7.15.8",
|
|
15
|
+
"@babel/preset-env": "^7.15.8",
|
|
16
16
|
"@babel/preset-react": "^7.13.13",
|
|
17
17
|
"@esm-bundle/chai": "^4.3.4-fix.0",
|
|
18
|
-
"babel-loader": "^8.2.
|
|
18
|
+
"babel-loader": "^8.2.3",
|
|
19
19
|
"babel-plugin-add-module-exports": "^1.0.4",
|
|
20
|
-
"babel-plugin-istanbul": "^6.
|
|
21
|
-
"css-loader": "^
|
|
22
|
-
"eslint": "^7.
|
|
20
|
+
"babel-plugin-istanbul": "^6.1.1",
|
|
21
|
+
"css-loader": "^6.4.0",
|
|
22
|
+
"eslint": "^7.32.0",
|
|
23
23
|
"eslint-plugin-react": "^7.23.2",
|
|
24
24
|
"font-awesome": "^4.7.0",
|
|
25
25
|
"gh-pages": "^3.1.0",
|
|
26
|
-
"karma": "^6.3.
|
|
26
|
+
"karma": "^6.3.6",
|
|
27
27
|
"karma-chrome-launcher": "^3.1.0",
|
|
28
28
|
"karma-coverage": "^2.0.3",
|
|
29
29
|
"karma-firefox-launcher": "^2.1.0",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"karma-safari-launcher": "^1.0.0",
|
|
32
32
|
"karma-sourcemap-loader": "^0.3.8",
|
|
33
33
|
"karma-webpack": "^5.0.0",
|
|
34
|
-
"mocha": "^9.
|
|
34
|
+
"mocha": "^9.1.3",
|
|
35
35
|
"normalize.css": "^8.0.1",
|
|
36
|
-
"prismjs": "^1.
|
|
36
|
+
"prismjs": "^1.25.0",
|
|
37
37
|
"react": "^17.0.2",
|
|
38
38
|
"react-dom": "^17.0.2",
|
|
39
39
|
"react-transition-group": "^4.4.1",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"sinon": "^10.0.0",
|
|
42
42
|
"style-loader": "^2.0.0",
|
|
43
43
|
"url-loader": "^4.1.1",
|
|
44
|
-
"webpack": "^5.
|
|
45
|
-
"webpack-cli": "^4.
|
|
46
|
-
"webpack-dev-server": "^4.
|
|
44
|
+
"webpack": "^5.60.0",
|
|
45
|
+
"webpack-cli": "^4.9.1",
|
|
46
|
+
"webpack-dev-server": "^4.3.1"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": ">=12"
|
|
@@ -84,11 +84,11 @@
|
|
|
84
84
|
"isCi": true,
|
|
85
85
|
"name": "Drone",
|
|
86
86
|
"service": "drone",
|
|
87
|
-
"commit": "
|
|
88
|
-
"build": "
|
|
87
|
+
"commit": "371fd4f350c9d109eb57b0e68d2308702137f6c7",
|
|
88
|
+
"build": "376",
|
|
89
89
|
"branch": "master",
|
|
90
90
|
"isPr": false,
|
|
91
91
|
"slug": "livingdocsIO/editable.js",
|
|
92
|
-
"date": "2021-
|
|
92
|
+
"date": "2021-10-26T16:02:22.840Z"
|
|
93
93
|
}
|
|
94
94
|
}
|
package/src/clipboard.js
CHANGED
|
@@ -25,46 +25,20 @@ export function updateConfig (conf) {
|
|
|
25
25
|
rules.splitIntoBlocks.forEach((name) => { splitIntoBlocks[name] = true })
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function paste (element, cursor,
|
|
28
|
+
export function paste (element, cursor, clipboardContent) {
|
|
29
29
|
const document = element.ownerDocument
|
|
30
30
|
element.setAttribute(config.pastingAttribute, true)
|
|
31
31
|
|
|
32
32
|
if (cursor.isSelection) cursor = cursor.deleteContent()
|
|
33
33
|
|
|
34
|
-
// Create a placeholder
|
|
35
|
-
// to redirect the browser pasting into the pasteholder.
|
|
36
|
-
cursor.save()
|
|
37
|
-
const pasteHolder = injectPasteholder(document)
|
|
38
|
-
pasteHolder.focus()
|
|
39
|
-
|
|
40
|
-
// Use a timeout to give the browser some time to paste the content.
|
|
41
|
-
// After that grab the pasted content, filter it and restore the focus.
|
|
42
|
-
setTimeout(() => {
|
|
43
|
-
const blocks = parseContent(pasteHolder)
|
|
44
|
-
pasteHolder.remove()
|
|
45
|
-
element.removeAttribute(config.pastingAttribute)
|
|
46
|
-
cursor.restore()
|
|
47
|
-
callback(blocks, cursor)
|
|
48
|
-
}, 0)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @param { Document } document
|
|
53
|
-
*/
|
|
54
|
-
export function injectPasteholder (document) {
|
|
34
|
+
// Create a placeholder to help parse HTML
|
|
55
35
|
const pasteHolder = document.createElement('div')
|
|
56
|
-
pasteHolder.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pasteHolder.style.overflow = 'hidden'
|
|
63
|
-
pasteHolder.style.outline = 'none'
|
|
64
|
-
|
|
65
|
-
document.body.appendChild(pasteHolder)
|
|
66
|
-
|
|
67
|
-
return pasteHolder
|
|
36
|
+
pasteHolder.innerHTML = clipboardContent
|
|
37
|
+
|
|
38
|
+
const blocks = parseContent(pasteHolder)
|
|
39
|
+
|
|
40
|
+
element.removeAttribute(config.pastingAttribute)
|
|
41
|
+
return {blocks, cursor}
|
|
68
42
|
}
|
|
69
43
|
|
|
70
44
|
/**
|
package/src/cursor.js
CHANGED
|
@@ -96,7 +96,7 @@ export default class Cursor {
|
|
|
96
96
|
hostRange.collapse(false)
|
|
97
97
|
const hostCoords = getRangeBoundingClientRect(hostRange, this.win)
|
|
98
98
|
const cursorCoords = getRangeBoundingClientRect(this.range.nativeRange, this.win)
|
|
99
|
-
return hostCoords.bottom
|
|
99
|
+
return isCloseTo(hostCoords.bottom, cursorCoords.bottom)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
isAtFirstLine () {
|
|
@@ -105,7 +105,7 @@ export default class Cursor {
|
|
|
105
105
|
hostRange.collapse(true)
|
|
106
106
|
const hostCoords = getRangeBoundingClientRect(hostRange, this.win)
|
|
107
107
|
const cursorCoords = getRangeBoundingClientRect(this.range.nativeRange, this.win)
|
|
108
|
-
return hostCoords.top
|
|
108
|
+
return isCloseTo(hostCoords.top, cursorCoords.top)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
isAtBeginning () {
|
|
@@ -368,3 +368,9 @@ function getRangeBoundingClientRect (range, win) {
|
|
|
368
368
|
el.remove()
|
|
369
369
|
return coords
|
|
370
370
|
}
|
|
371
|
+
|
|
372
|
+
function isCloseTo (a, b) {
|
|
373
|
+
if (a === b) return true
|
|
374
|
+
if (Math.abs(a - b) <= 2) return true
|
|
375
|
+
return false
|
|
376
|
+
}
|
package/src/dispatcher.js
CHANGED
|
@@ -127,20 +127,21 @@ export default class Dispatcher {
|
|
|
127
127
|
.setupDocumentListener('paste', function pasteListener (evt) {
|
|
128
128
|
const block = this.getEditableBlockByEvent(evt)
|
|
129
129
|
if (!block) return
|
|
130
|
-
const afterPaste = (blocks, cursor) => {
|
|
131
|
-
if (blocks.length) {
|
|
132
|
-
this.notify('paste', block, blocks, cursor)
|
|
133
|
-
|
|
134
|
-
// The input event does not fire when we process the content manually
|
|
135
|
-
// and insert it via script
|
|
136
|
-
this.notify('change', block)
|
|
137
|
-
} else {
|
|
138
|
-
cursor.setVisibleSelection()
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
130
|
|
|
142
|
-
|
|
143
|
-
|
|
131
|
+
evt.preventDefault()
|
|
132
|
+
const selection = this.selectionWatcher.getFreshSelection()
|
|
133
|
+
const clipboardContent = evt.clipboardData.getData('text/html') || evt.clipboardData.getData('text/plain')
|
|
134
|
+
|
|
135
|
+
const {blocks, cursor} = clipboard.paste(block, selection, clipboardContent)
|
|
136
|
+
if (blocks.length) {
|
|
137
|
+
this.notify('paste', block, blocks, cursor)
|
|
138
|
+
|
|
139
|
+
// The input event does not fire when we process the content manually
|
|
140
|
+
// and insert it via script
|
|
141
|
+
this.notify('change', block)
|
|
142
|
+
} else {
|
|
143
|
+
cursor.setVisibleSelection()
|
|
144
|
+
}
|
|
144
145
|
})
|
|
145
146
|
.setupDocumentListener('input', function inputListener (evt) {
|
|
146
147
|
const block = this.getEditableBlockByEvent(evt)
|
|
@@ -7,8 +7,22 @@ export default class WordHighlighting {
|
|
|
7
7
|
this.matchMode = matchMode
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
isElement (obj) {
|
|
11
|
+
try {
|
|
12
|
+
// Using W3 DOM2 (works for FF, Opera and Chrome)
|
|
13
|
+
return obj instanceof HTMLElement
|
|
14
|
+
} catch (e) {
|
|
15
|
+
// Browsers not supporting W3 DOM2 don't have HTMLElement and
|
|
16
|
+
// an exception is thrown and we end up here. Testing some
|
|
17
|
+
// properties that all elements have (works on IE7)
|
|
18
|
+
return (typeof obj === 'object') &&
|
|
19
|
+
(obj.nodeType === 1) && (typeof obj.style === 'object') &&
|
|
20
|
+
(typeof obj.ownerDocument === 'object')
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
findMatches (text, highlights) {
|
|
11
|
-
if (!text) return
|
|
25
|
+
if (!text || text === '' || !this.isElement(this.marker)) return
|
|
12
26
|
|
|
13
27
|
if (highlights && highlights.length > 0) {
|
|
14
28
|
return this.searchMatches(text, highlights)
|
|
@@ -21,11 +35,7 @@ export default class WordHighlighting {
|
|
|
21
35
|
: createHighlightRegex
|
|
22
36
|
|
|
23
37
|
const regex = createRegex(highlights)
|
|
24
|
-
const matches = []
|
|
25
|
-
let match
|
|
26
|
-
while ((match = regex.exec(text))) {
|
|
27
|
-
matches.push(match)
|
|
28
|
-
}
|
|
38
|
+
const matches = [...text.matchAll(regex)]
|
|
29
39
|
|
|
30
40
|
return matches.map((entry) => this.prepareMatch(entry))
|
|
31
41
|
}
|
package/src/selection.js
CHANGED
|
@@ -78,7 +78,15 @@ export default class Selection extends Cursor {
|
|
|
78
78
|
link (href, attrs = {}) {
|
|
79
79
|
if (href) attrs.href = href
|
|
80
80
|
const link = this.createElement(config.linkMarkup.name, config.linkMarkup.attribs)
|
|
81
|
-
for (const key in attrs)
|
|
81
|
+
for (const key in attrs) {
|
|
82
|
+
const value = attrs[key]
|
|
83
|
+
if (value === undefined) continue
|
|
84
|
+
if (value === null) {
|
|
85
|
+
link.removeAttribute(key)
|
|
86
|
+
} else {
|
|
87
|
+
link.setAttribute(key, value)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
82
90
|
this.forceWrap(link)
|
|
83
91
|
}
|
|
84
92
|
|