@@ -40,6 +40,8 @@ define(function (require, exports, module) {
4040 return ( val < 0 ? 0 : ( val > max ? max : val ) ) ;
4141 }
4242
43+ var uniqueNum = 0 ; // used to ensure unique undo batching per drag
44+
4345
4446 // Scrubbing a single number (with optional suffix)
4547 function SimpleNumberScrub ( origStringValue , prefix , suffix ) {
@@ -94,7 +96,7 @@ define(function (require, exports, module) {
9496 // Colors in LESS are type number
9597 return token . string ;
9698 } else if ( token . className === "string" ) {
97- // Token type string may contain a number, e.g. in HTML or SVG code
99+ // Token type string may contain a number in the attrs of XML-like modes ( e.g. HTML or SVG)
98100 return token . string ;
99101 }
100102 }
@@ -156,11 +158,16 @@ define(function (require, exports, module) {
156158 } ;
157159
158160 function parseForScrub ( token ) {
159- return (
161+ var initialState = (
160162 Color3Scrub . parse ( token ) ||
161163 Color6Scrub . parse ( token ) ||
162164 SimpleNumberScrub . parse ( token )
163165 ) ;
166+ if ( initialState ) {
167+ // in Sprint 20 (CMv3), this ensures the entire drag (or consecutive nudges) is undone atomically; ignored in earlier builds
168+ initialState . origin = "*everyscrub" + ( ++ uniqueNum ) ;
169+ }
170+ return initialState ;
164171 }
165172
166173
@@ -182,7 +189,7 @@ define(function (require, exports, module) {
182189
183190 if ( newVal !== lastValue ) {
184191 lastValue = newVal ;
185- editor . _codeMirror . replaceRange ( newVal , lastRange . start , lastRange . end ) ;
192+ editor . _codeMirror . replaceRange ( newVal , lastRange . start , lastRange . end , scrubState . origin ) ;
186193 lastRange . end . ch = lastRange . start . ch + newVal . length ;
187194 editor . setSelection ( lastRange . start , lastRange . end ) ;
188195 }
@@ -198,8 +205,9 @@ define(function (require, exports, module) {
198205 // ------------------- X = coordsChar().ch, interpreted as a char pos
199206 // | | *I X | I = coordsChar().ch, interpreted as a cursor pos / insertion point
200207 // -------------------
201- var pos = editor . _codeMirror . coordsChar ( { x : event . pageX , y : event . pageY } ) ;
202- var chLeftEdge = editor . _codeMirror . charCoords ( pos ) . x ;
208+ var pos = editor . _codeMirror . coordsChar ( { x : event . pageX , y : event . pageY , left : event . pageX , top : event . pageY } ) ; // x/y for CMv2; left/top for v3
209+ var charBounds = editor . _codeMirror . charCoords ( pos ) ;
210+ var chLeftEdge = ( charBounds . x !== undefined ) ? charBounds . x : charBounds . left ; // x for CMv2; left for CMv3
203211 var mousedownCh = ( chLeftEdge <= event . pageX ) ? pos . ch : pos . ch - 1 ;
204212
205213 // ch+1 because getTokenAt() returns the token *ending* at cursor pos 'ch' (char at 'ch' is NOT part of the token)
@@ -305,7 +313,7 @@ define(function (require, exports, module) {
305313 if ( scrubState ) {
306314 var newVal = scrubState . update ( lastNudge . delta ) ;
307315 var tokenRange = { start : { line : cursorPos . line , ch : token . start } , end : { line : cursorPos . line , ch : token . end } } ;
308- editor . _codeMirror . replaceRange ( newVal , tokenRange . start , tokenRange . end ) ;
316+ editor . _codeMirror . replaceRange ( newVal , tokenRange . start , tokenRange . end , scrubState . origin ) ;
309317 lastNudge . lastText = newVal ;
310318
311319 tokenRange . end . ch = tokenRange . start . ch + newVal . length ;
0 commit comments