@livingdocs/editable.js 3.0.15 → 3.1.1

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/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.15",
4
+ "version": "3.1.1",
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": "cfb72eb34899004520ea0b1d0bd7bb9434681502",
87
- "build": "454",
86
+ "commit": "9957094d8242121b94e2584b57ba04cd1c7067ed",
87
+ "build": "495",
88
88
  "branch": "master",
89
89
  "isPr": false,
90
90
  "slug": "livingdocsIO/editable.js",
91
- "date": "2022-02-23T12:28:23.761Z"
91
+ "date": "2022-05-17T13:22:55.296Z"
92
92
  }
93
93
  }
package/src/config.js CHANGED
@@ -10,6 +10,7 @@ export default {
10
10
  editableClass: 'js-editable',
11
11
  editableDisabledClass: 'js-editable-disabled',
12
12
  pastingAttribute: 'data-editable-is-pasting',
13
+ trimLeadingAndTrailingWhitespaces: true,
13
14
  boldMarkup: {
14
15
  type: 'tag',
15
16
  name: 'strong',
package/src/content.js CHANGED
@@ -4,6 +4,7 @@ import * as rangeSaveRestore from './range-save-restore'
4
4
  import * as parser from './parser'
5
5
  import * as string from './util/string'
6
6
  import {createElement} from './util/dom'
7
+ import config from './config'
7
8
 
8
9
  function restoreRange (host, range, func) {
9
10
  range = rangeSaveRestore.save(range)
@@ -161,7 +162,9 @@ function removeWhitespaces (node, type, firstCall = true) {
161
162
  if (elem?.nodeType !== nodeType.textNode) return
162
163
  // Remove whitespaces at the end or start of a block with content
163
164
  // e.g. ' Hello world' > 'Hello World'
164
- elem.textContent = elem.textContent.replace(type.startsWith('last') ? /\s+$/ : /^\s+/, '')
165
+ if (config.trimLeadingAndTrailingWhitespaces) {
166
+ elem.textContent = elem.textContent.replace(type.startsWith('last') ? / +$/ : /^ +/, '')
167
+ }
165
168
  }
166
169
 
167
170
  // Remove elements that were inserted for internal or user interface purposes
package/src/core.js CHANGED
@@ -400,7 +400,7 @@ export class Editable {
400
400
  )
401
401
  return -1
402
402
  }
403
- return highlightSupport.highlightRange(editableHost, highlightId, textRange.start, textRange.end, raiseEvents ? this.dispatcher : undefined, type)
403
+ return highlightSupport.highlightRange(editableHost, text, highlightId, textRange.start, textRange.end, raiseEvents ? this.dispatcher : undefined, type)
404
404
  }
405
405
 
406
406
  /**
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
- this.notify('paste', block, blocks, cursor)
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
@@ -12,7 +12,6 @@ const highlightSupport = {
12
12
 
13
13
  highlightText (editableHost, text, highlightId, type) {
14
14
  if (this.hasHighlight(editableHost, highlightId)) return
15
-
16
15
  const blockText = highlightText.extractText(editableHost)
17
16
 
18
17
  const marker = `<span class="highlight-${type}"></span>`
@@ -28,12 +27,23 @@ const highlightSupport = {
28
27
  }
29
28
  },
30
29
 
31
- highlightRange (editableHost, highlightId, startIndex, endIndex, dispatcher, type = 'comment') {
30
+
31
+ // This function was changed to track matches when text is added to the start of a component, but multiple white spaces break it in a strict sense
32
+ // The function works in the editor and in browsers, but tests with multiple white spaces will fail.
33
+ // Browsers change the white spaces to &nbsp and the function works, and the tests in highlight.spec.js have been updated to represent this.
34
+
35
+ highlightRange (editableHost, text, highlightId, startIndex, endIndex, dispatcher, type = 'comment') {
32
36
  if (this.hasHighlight(editableHost, highlightId)) {
33
37
  this.removeHighlight(editableHost, highlightId)
34
38
  }
39
+ const firstMarker = `<span class="highlight-${type}"></span>`
40
+ const markerNode = highlightSupport.createMarkerNode(firstMarker, type, this.win)
41
+ const textSearch = new TextHighlighting(markerNode, 'text')
42
+ const blockText = highlightText.extractText(editableHost)
43
+ const matchesArray = textSearch.findMatches(blockText, [text])
44
+ const {actualStartIndex, actualEndIndex} = this.getIndex(matchesArray, startIndex, endIndex)
35
45
  const range = rangy.createRange()
36
- range.selectCharacters(editableHost, startIndex, endIndex)
46
+ range.selectCharacters(editableHost, actualStartIndex, actualEndIndex)
37
47
 
38
48
  if (!isInHost(range.commonAncestorContainer, editableHost)) {
39
49
  return -1
@@ -52,7 +62,7 @@ const highlightSupport = {
52
62
  if (dispatcher) {
53
63
  dispatcher.notify('change', editableHost)
54
64
  }
55
- return startIndex
65
+ return actualStartIndex
56
66
  },
57
67
 
58
68
  updateHighlight (editableHost, highlightId, addCssClass, removeCssClass) {
@@ -136,6 +146,18 @@ const highlightSupport = {
136
146
  marker.setAttribute('data-editable', 'ui-unwrap')
137
147
  marker.setAttribute('data-highlight', highlightType)
138
148
  return marker
149
+ },
150
+
151
+ // This function checks to see if text has been added to the component before the comment
152
+ // If it has, the start index is updated, otherwise it remains the same
153
+ getIndex (matchesArray, startIndex, endIndex) {
154
+ const newStartIndex = matchesArray.find((match) => {
155
+ return match.startIndex >= startIndex // checks if the startIndex has increased
156
+ })
157
+ const actualStartIndex = newStartIndex ? newStartIndex.startIndex : startIndex
158
+ const actualEndIndex = actualStartIndex ? (actualStartIndex + (endIndex - startIndex)) : endIndex
159
+
160
+ return {actualStartIndex, actualEndIndex}
139
161
  }
140
162
 
141
163
  }
@@ -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
+ }