1
1
/*
2
- Trix 2.0.0
3
- Copyright © 2022 Basecamp , LLC
2
+ Trix 2.0.4
3
+ Copyright © 2022 37signals , LLC
4
4
*/
5
5
var name = "trix" ;
6
- var version = "2.0.0 " ;
6
+ var version = "2.0.4 " ;
7
7
var description = "A rich text editor for everyday writing" ;
8
8
var main = "dist/trix.umd.min.js" ;
9
9
var module = "dist/trix.esm.min.js" ;
@@ -21,7 +21,7 @@ var keywords = [
21
21
"wysiwyg" ,
22
22
"editor"
23
23
] ;
24
- var author = "Basecamp , LLC" ;
24
+ var author = "37signals , LLC" ;
25
25
var license = "MIT" ;
26
26
var bugs = {
27
27
url : "https://github.com/basecamp/trix/issues"
@@ -39,7 +39,7 @@ var devDependencies = {
39
39
concurrently : "^7.4.0" ,
40
40
eslint : "^7.32.0" ,
41
41
esm : "^3.2.25" ,
42
- karma : "6.4.0 " ,
42
+ karma : "6.4.1 " ,
43
43
"karma-chrome-launcher" : "3.1.1" ,
44
44
"karma-qunit" : "^4.1.2" ,
45
45
"karma-sauce-launcher" : "^4.3.6" ,
@@ -51,6 +51,9 @@ var devDependencies = {
51
51
"rollup-plugin-terser" : "^7.0.2" ,
52
52
svgo : "^2.8.0"
53
53
} ;
54
+ var resolutions = {
55
+ webdriverio : "^7.19.5"
56
+ } ;
54
57
var scripts = {
55
58
"build-css" : "node-sass --functions=./assets/trix/stylesheets/functions assets/trix.scss dist/trix.css" ,
56
59
"build-js" : "rollup -c" ,
@@ -83,6 +86,7 @@ var _package = {
83
86
bugs : bugs ,
84
87
homepage : homepage ,
85
88
devDependencies : devDependencies ,
89
+ resolutions : resolutions ,
86
90
scripts : scripts ,
87
91
dependencies : dependencies
88
92
} ;
@@ -170,26 +174,21 @@ const tagName$1 = element => {
170
174
return element === null || element === void 0 ? void 0 : ( _element$tagName = element . tagName ) === null || _element$tagName === void 0 ? void 0 : _element$tagName . toLowerCase ( ) ;
171
175
} ;
172
176
177
+ const androidVersionMatch = navigator . userAgent . match ( / a n d r o i d \s ( [ 0 - 9 ] + .* C h r o m e ) / i) ;
178
+ const androidVersion = androidVersionMatch && parseInt ( androidVersionMatch [ 1 ] ) ;
173
179
var browser$1 = {
174
180
// Android emits composition events when moving the cursor through existing text
175
181
// Introduced in Chrome 65: https://bugs.chromium.org/p/chromium/issues/detail?id=764439#c9
176
182
composesExistingText : / A n d r o i d .* C h r o m e / . test ( navigator . userAgent ) ,
183
+ // Android 13, especially on Samsung keyboards, emits extra compositionend and beforeinput events
184
+ // that can make the input handler lose the the current selection or enter an infinite input -> render -> input
185
+ // loop.
186
+ recentAndroid : androidVersion && androidVersion > 12 ,
187
+ samsungAndroid : androidVersion && navigator . userAgent . match ( / A n d r o i d .* S M - / ) ,
177
188
// IE 11 activates resizing handles on editable elements that have "layout"
178
189
forcesObjectResizing : / T r i d e n t .* r v : 1 1 / . test ( navigator . userAgent ) ,
179
190
// https://www.w3.org/TR/input-events-1/ + https://www.w3.org/TR/input-events-2/
180
- supportsInputEvents : function ( ) {
181
- if ( typeof InputEvent === "undefined" ) {
182
- return false ;
183
- }
184
-
185
- for ( const property of [ "data" , "getTargetRanges" , "inputType" ] ) {
186
- if ( ! ( property in InputEvent . prototype ) ) {
187
- return false ;
188
- }
189
- }
190
-
191
- return true ;
192
- } ( )
191
+ supportsInputEvents : typeof InputEvent !== "undefined" && [ "data" , "getTargetRanges" , "inputType" ] . every ( prop => prop in InputEvent . prototype )
193
192
} ;
194
193
195
194
var css$3 = {
@@ -10089,12 +10088,75 @@ class FileVerificationOperation extends Operation {
10089
10088
10090
10089
}
10091
10090
10091
+ // This class detects when some buggy events are being emmitted and lets know the input controller
10092
+ // that they should be ignored.
10093
+
10094
+ class FlakyAndroidKeyboardDetector {
10095
+ constructor ( element ) {
10096
+ this . element = element ;
10097
+ }
10098
+
10099
+ shouldIgnore ( event ) {
10100
+ if ( ! browser$1 . samsungAndroid ) return false ;
10101
+ this . previousEvent = this . event ;
10102
+ this . event = event ;
10103
+ this . checkSamsungKeyboardBuggyModeStart ( ) ;
10104
+ this . checkSamsungKeyboardBuggyModeEnd ( ) ;
10105
+ return this . buggyMode ;
10106
+ } // private
10107
+ // The Samsung keyboard on Android can enter a buggy state in which it emmits a flurry of confused events that,
10108
+ // if processed, corrupts the editor. The buggy mode always starts with an insertText event, right after a
10109
+ // keydown event with for an "Unidentified" key, with the same text as the editor element, except for a few
10110
+ // extra whitespace, or exotic utf8, characters.
10111
+
10112
+
10113
+ checkSamsungKeyboardBuggyModeStart ( ) {
10114
+ if ( this . insertingLongTextAfterUnidentifiedChar ( ) && differsInWhitespace ( this . element . innerText , this . event . data ) ) {
10115
+ this . buggyMode = true ;
10116
+ this . event . preventDefault ( ) ;
10117
+ }
10118
+ } // The flurry of buggy events are always insertText. If we see any other type, it means it's over.
10119
+
10120
+
10121
+ checkSamsungKeyboardBuggyModeEnd ( ) {
10122
+ if ( this . buggyMode && this . event . inputType !== "insertText" ) {
10123
+ this . buggyMode = false ;
10124
+ }
10125
+ }
10126
+
10127
+ insertingLongTextAfterUnidentifiedChar ( ) {
10128
+ var _this$event$data ;
10129
+
10130
+ return this . isBeforeInputInsertText ( ) && this . previousEventWasUnidentifiedKeydown ( ) && ( ( _this$event$data = this . event . data ) === null || _this$event$data === void 0 ? void 0 : _this$event$data . length ) > 50 ;
10131
+ }
10132
+
10133
+ isBeforeInputInsertText ( ) {
10134
+ return this . event . type === "beforeinput" && this . event . inputType === "insertText" ;
10135
+ }
10136
+
10137
+ previousEventWasUnidentifiedKeydown ( ) {
10138
+ var _this$previousEvent , _this$previousEvent2 ;
10139
+
10140
+ return ( ( _this$previousEvent = this . previousEvent ) === null || _this$previousEvent === void 0 ? void 0 : _this$previousEvent . type ) === "keydown" && ( ( _this$previousEvent2 = this . previousEvent ) === null || _this$previousEvent2 === void 0 ? void 0 : _this$previousEvent2 . key ) === "Unidentified" ;
10141
+ }
10142
+
10143
+ }
10144
+
10145
+ const differsInWhitespace = ( text1 , text2 ) => {
10146
+ return normalize ( text1 ) === normalize ( text2 ) ;
10147
+ } ;
10148
+
10149
+ const whiteSpaceNormalizerRegexp = new RegExp ( "(" . concat ( OBJECT_REPLACEMENT_CHARACTER , "|" ) . concat ( ZERO_WIDTH_SPACE , "|" ) . concat ( NON_BREAKING_SPACE , "|\\s)+" ) , "g" ) ;
10150
+
10151
+ const normalize = text => text . replace ( whiteSpaceNormalizerRegexp , " " ) . trim ( ) ;
10152
+
10092
10153
class InputController extends BasicObject {
10093
10154
constructor ( element ) {
10094
10155
super ( ...arguments ) ;
10095
10156
this . element = element ;
10096
10157
this . mutationObserver = new MutationObserver ( this . element ) ;
10097
10158
this . mutationObserver . delegate = this ;
10159
+ this . flakyKeyboardDetector = new FlakyAndroidKeyboardDetector ( this . element ) ;
10098
10160
10099
10161
for ( const eventName in this . constructor . events ) {
10100
10162
handleEvent ( eventName , {
@@ -10146,6 +10208,7 @@ class InputController extends BasicObject {
10146
10208
if ( ! event . defaultPrevented ) {
10147
10209
this . handleInput ( ( ) => {
10148
10210
if ( ! innerElementIsActive ( this . element ) ) {
10211
+ if ( this . flakyKeyboardDetector . shouldIgnore ( event ) ) return ;
10149
10212
this . eventName = eventName ;
10150
10213
this . constructor . events [ eventName ] . call ( this , event ) ;
10151
10214
}
@@ -11198,12 +11261,12 @@ _defineProperty(Level2InputController, "events", {
11198
11261
11199
11262
if ( handler ) {
11200
11263
this . withEvent ( event , handler ) ;
11201
- return this . scheduleRender ( ) ;
11264
+ this . scheduleRender ( ) ;
11202
11265
}
11203
11266
} ,
11204
11267
11205
11268
input ( event ) {
11206
- return selectionChangeObserver . reset ( ) ;
11269
+ selectionChangeObserver . reset ( ) ;
11207
11270
} ,
11208
11271
11209
11272
dragstart ( event ) {
@@ -11273,7 +11336,7 @@ _defineProperty(Level2InputController, "events", {
11273
11336
compositionend ( event ) {
11274
11337
if ( this . composing ) {
11275
11338
this . composing = false ;
11276
- return this . scheduleRender ( ) ;
11339
+ if ( ! browser$1 . recentAndroid ) this . scheduleRender ( ) ;
11277
11340
}
11278
11341
}
11279
11342
@@ -12996,7 +13059,9 @@ const Trix = {
12996
13059
operations,
12997
13060
elements,
12998
13061
filters
12999
- } ;
13062
+ } ; // Expose models under the Trix constant for compatibility with v1
13063
+
13064
+ Object . assign ( Trix , models ) ;
13000
13065
13001
13066
function start ( ) {
13002
13067
if ( ! customElements . get ( "trix-toolbar" ) ) {
0 commit comments