@@ -45,11 +45,27 @@ var TextInput = function(parentNode, host) {
45
45
var lastSelectionStart = 0 ;
46
46
var lastSelectionEnd = 0 ;
47
47
var lastRestoreEnd = 0 ;
48
+ var rowStart = Number . MAX_SAFE_INTEGER ;
49
+ var rowEnd = Number . MIN_SAFE_INTEGER ;
50
+ var numberOfExtraLines = 0 ;
48
51
49
52
// FOCUS
50
53
// ie9 throws error if document.activeElement is accessed too soon
51
54
try { var isFocused = document . activeElement === text ; } catch ( e ) { }
52
55
56
+ // Set number of extra lines in textarea, some screenreaders
57
+ // perform better with extra lines above and below in the textarea.
58
+ this . setNumberOfExtraLines = function ( number ) {
59
+ rowStart = Number . MAX_SAFE_INTEGER ;
60
+ rowEnd = Number . MIN_SAFE_INTEGER ;
61
+
62
+ if ( number < 0 ) {
63
+ numberOfExtraLines = 0 ;
64
+ return ;
65
+ }
66
+
67
+ numberOfExtraLines = number ;
68
+ } ;
53
69
this . setAriaOptions = function ( options ) {
54
70
if ( options . activeDescendant ) {
55
71
text . setAttribute ( "aria-haspopup" , "true" ) ;
@@ -63,21 +79,16 @@ var TextInput = function(parentNode, host) {
63
79
if ( options . role ) {
64
80
text . setAttribute ( "role" , options . role ) ;
65
81
}
66
- } ;
67
- this . setAriaLabel = function ( ) {
68
- if ( host . session && host . renderer . enableKeyboardAccessibility ) {
69
- var row = host . session . selection . cursor . row ;
70
-
82
+ if ( options . setLabel ) {
71
83
text . setAttribute ( "aria-roledescription" , nls ( "editor" ) ) ;
72
- text . setAttribute ( "aria-label" , nls ( "Cursor at row $0" , [ row + 1 ] ) ) ;
73
- } else {
74
- text . removeAttribute ( "aria-roledescription" ) ;
75
- text . removeAttribute ( "aria-label" ) ;
84
+ if ( host . session ) {
85
+ var row = host . session . selection . cursor . row ;
86
+ text . setAttribute ( "aria-label" , nls ( "Cursor at row $0" , [ row + 1 ] ) ) ;
87
+ }
76
88
}
77
89
} ;
78
90
79
- this . setAriaOptions ( { role : "textbox" } ) ;
80
- this . setAriaLabel ( ) ;
91
+ this . setAriaOptions ( { role : "textbox" } ) ;
81
92
82
93
event . addListener ( text , "blur" , function ( e ) {
83
94
if ( ignoreFocusEvents ) return ;
@@ -103,7 +114,9 @@ var TextInput = function(parentNode, host) {
103
114
this . $focusScroll = false ;
104
115
this . focus = function ( ) {
105
116
// On focusing on the textarea, read active row number to assistive tech.
106
- this . setAriaLabel ( ) ;
117
+ this . setAriaOptions ( {
118
+ setLabel : host . renderer . enableKeyboardAccessibility
119
+ } ) ;
107
120
108
121
if ( tempStyle || HAS_FOCUS_ARGS || this . $focusScroll == "browser" )
109
122
return text . focus ( { preventScroll : true } ) ;
@@ -163,6 +176,17 @@ var TextInput = function(parentNode, host) {
163
176
resetSelection ( ) ;
164
177
} ) ;
165
178
179
+ // Convert from row,column position to the linear position with respect to the current
180
+ // block of lines in the textarea.
181
+ var positionToSelection = function ( row , column ) {
182
+ var selection = column ;
183
+
184
+ for ( var i = 1 ; i <= row - rowStart && i < 2 * numberOfExtraLines + 1 ; i ++ ) {
185
+ selection += host . session . getLine ( row - i ) . length + 1 ;
186
+ }
187
+ return selection ;
188
+ } ;
189
+
166
190
var resetSelection = isIOS
167
191
? function ( value ) {
168
192
if ( ! isFocused || ( copied && ! value ) || sendingText ) return ;
@@ -199,19 +223,43 @@ var TextInput = function(parentNode, host) {
199
223
var selection = host . selection ;
200
224
var range = selection . getRange ( ) ;
201
225
var row = selection . cursor . row ;
202
- selectionStart = range . start . column ;
203
- selectionEnd = range . end . column ;
204
- line = host . session . getLine ( row ) ;
205
226
206
- if ( range . start . row != row ) {
207
- var prevLine = host . session . getLine ( row - 1 ) ;
208
- selectionStart = range . start . row < row - 1 ? 0 : selectionStart ;
227
+ // We keep 2*numberOfExtraLines + 1 lines in the textarea, if the new active row
228
+ // is within the current block of lines in the textarea we do nothing. If the new row
229
+ // is one row above or below the current block, move up or down to the next block of lines.
230
+ // If the new row is further than 1 row away from the current block grab a new block centered
231
+ // around the new row.
232
+ if ( row === rowEnd + 1 ) {
233
+ rowStart = rowEnd + 1 ;
234
+ rowEnd = rowStart + 2 * numberOfExtraLines ;
235
+ } else if ( row === rowStart - 1 ) {
236
+ rowEnd = rowStart - 1 ;
237
+ rowStart = rowEnd - 2 * numberOfExtraLines ;
238
+ } else if ( row < rowStart - 1 || row > rowEnd + 1 ) {
239
+ rowStart = row > numberOfExtraLines ? row - numberOfExtraLines : 0 ;
240
+ rowEnd = row > numberOfExtraLines ? row + numberOfExtraLines : 2 * numberOfExtraLines ;
241
+ }
242
+
243
+ var lines = [ ] ;
244
+
245
+ for ( var i = rowStart ; i <= rowEnd ; i ++ ) {
246
+ lines . push ( host . session . getLine ( i ) ) ;
247
+ }
248
+
249
+ line = lines . join ( '\n' ) ;
250
+
251
+ selectionStart = positionToSelection ( range . start . row , range . start . column ) ;
252
+ selectionEnd = positionToSelection ( range . end . row , range . end . column ) ;
253
+
254
+ if ( range . start . row < rowStart ) {
255
+ var prevLine = host . session . getLine ( rowStart - 1 ) ;
256
+ selectionStart = range . start . row < rowStart - 1 ? 0 : selectionStart ;
209
257
selectionEnd += prevLine . length + 1 ;
210
258
line = prevLine + "\n" + line ;
211
259
}
212
- else if ( range . end . row != row ) {
213
- var nextLine = host . session . getLine ( row + 1 ) ;
214
- selectionEnd = range . end . row > row + 1 ? nextLine . length : selectionEnd ;
260
+ else if ( range . end . row > rowEnd ) {
261
+ var nextLine = host . session . getLine ( rowEnd + 1 ) ;
262
+ selectionEnd = range . end . row > rowEnd + 1 ? nextLine . length : range . end . column ;
215
263
selectionEnd += line . length + 1 ;
216
264
line = line + "\n" + nextLine ;
217
265
}
@@ -235,12 +283,12 @@ var TextInput = function(parentNode, host) {
235
283
}
236
284
}
237
285
}
238
- }
239
-
240
- var newValue = line + "\n\n" ;
241
- if ( newValue ! = lastValue ) {
242
- text . value = lastValue = newValue ;
243
- lastSelectionStart = lastSelectionEnd = newValue . length ;
286
+
287
+ var newValue = line + "\n\n" ;
288
+ if ( newValue != lastValue ) {
289
+ text . value = lastValue = newValue ;
290
+ lastSelectionStart = lastSelectionEnd = newValue . length ;
291
+ }
244
292
}
245
293
246
294
// contextmenu on mac may change the selection
0 commit comments