/ * *
* simplemde v1 . 11.2
* Copyright Next Step Webs , Inc .
* @ link https : //github.com/NextStepWebs/simplemde-markdown-editor
* @ license MIT
* /
( function ( f ) { if ( typeof exports === "object" && typeof module !== "undefined" ) { module . exports = f ( ) } else if ( typeof define === "function" && define . amd ) { define ( [ ] , f ) } else { var g ; if ( typeof window !== "undefined" ) { g = window } else if ( typeof global !== "undefined" ) { g = global } else if ( typeof self !== "undefined" ) { g = self } else { g = this } g . SimpleMDE = f ( ) } } ) ( function ( ) { var define , module , exports ; return ( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
'use strict'
exports . byteLength = byteLength
exports . toByteArray = toByteArray
exports . fromByteArray = fromByteArray
var lookup = [ ]
var revLookup = [ ]
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for ( var i = 0 , len = code . length ; i < len ; ++ i ) {
lookup [ i ] = code [ i ]
revLookup [ code . charCodeAt ( i ) ] = i
}
revLookup [ '-' . charCodeAt ( 0 ) ] = 62
revLookup [ '_' . charCodeAt ( 0 ) ] = 63
function placeHoldersCount ( b64 ) {
var len = b64 . length
if ( len % 4 > 0 ) {
throw new Error ( 'Invalid string. Length must be a multiple of 4' )
}
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
return b64 [ len - 2 ] === '=' ? 2 : b64 [ len - 1 ] === '=' ? 1 : 0
}
function byteLength ( b64 ) {
// base64 is 4/3 + up to two characters of the original data
return b64 . length * 3 / 4 - placeHoldersCount ( b64 )
}
function toByteArray ( b64 ) {
var i , j , l , tmp , placeHolders , arr
var len = b64 . length
placeHolders = placeHoldersCount ( b64 )
arr = new Arr ( len * 3 / 4 - placeHolders )
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? len - 4 : len
var L = 0
for ( i = 0 , j = 0 ; i < l ; i += 4 , j += 3 ) {
tmp = ( revLookup [ b64 . charCodeAt ( i ) ] << 18 ) | ( revLookup [ b64 . charCodeAt ( i + 1 ) ] << 12 ) | ( revLookup [ b64 . charCodeAt ( i + 2 ) ] << 6 ) | revLookup [ b64 . charCodeAt ( i + 3 ) ]
arr [ L ++ ] = ( tmp >> 16 ) & 0xFF
arr [ L ++ ] = ( tmp >> 8 ) & 0xFF
arr [ L ++ ] = tmp & 0xFF
}
if ( placeHolders === 2 ) {
tmp = ( revLookup [ b64 . charCodeAt ( i ) ] << 2 ) | ( revLookup [ b64 . charCodeAt ( i + 1 ) ] >> 4 )
arr [ L ++ ] = tmp & 0xFF
} else if ( placeHolders === 1 ) {
tmp = ( revLookup [ b64 . charCodeAt ( i ) ] << 10 ) | ( revLookup [ b64 . charCodeAt ( i + 1 ) ] << 4 ) | ( revLookup [ b64 . charCodeAt ( i + 2 ) ] >> 2 )
arr [ L ++ ] = ( tmp >> 8 ) & 0xFF
arr [ L ++ ] = tmp & 0xFF
}
return arr
}
function tripletToBase64 ( num ) {
return lookup [ num >> 18 & 0x3F ] + lookup [ num >> 12 & 0x3F ] + lookup [ num >> 6 & 0x3F ] + lookup [ num & 0x3F ]
}
function encodeChunk ( uint8 , start , end ) {
var tmp
var output = [ ]
for ( var i = start ; i < end ; i += 3 ) {
tmp = ( uint8 [ i ] << 16 ) + ( uint8 [ i + 1 ] << 8 ) + ( uint8 [ i + 2 ] )
output . push ( tripletToBase64 ( tmp ) )
}
return output . join ( '' )
}
function fromByteArray ( uint8 ) {
var tmp
var len = uint8 . length
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
var output = ''
var parts = [ ]
var maxChunkLength = 16383 // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for ( var i = 0 , len2 = len - extraBytes ; i < len2 ; i += maxChunkLength ) {
parts . push ( encodeChunk ( uint8 , i , ( i + maxChunkLength ) > len2 ? len2 : ( i + maxChunkLength ) ) )
}
// pad the end with zeros, but make sure to not forget the extra bytes
if ( extraBytes === 1 ) {
tmp = uint8 [ len - 1 ]
output += lookup [ tmp >> 2 ]
output += lookup [ ( tmp << 4 ) & 0x3F ]
output += '=='
} else if ( extraBytes === 2 ) {
tmp = ( uint8 [ len - 2 ] << 8 ) + ( uint8 [ len - 1 ] )
output += lookup [ tmp >> 10 ]
output += lookup [ ( tmp >> 4 ) & 0x3F ]
output += lookup [ ( tmp << 2 ) & 0x3F ]
output += '='
}
parts . push ( output )
return parts . join ( '' )
}
} , { } ] , 2 : [ function ( require , module , exports ) {
} , { } ] , 3 : [ function ( require , module , exports ) {
/ * !
* The buffer module from node . js , for the browser .
*
* @ author Feross Aboukhadijeh < feross @ feross . org > < http : //feross.org>
* @ license MIT
* /
/* eslint-disable no-proto */
'use strict'
var base64 = require ( 'base64-js' )
var ieee754 = require ( 'ieee754' )
exports . Buffer = Buffer
exports . SlowBuffer = SlowBuffer
exports . INSPECT _MAX _BYTES = 50
var K _MAX _LENGTH = 0x7fffffff
exports . kMaxLength = K _MAX _LENGTH
/ * *
* If ` Buffer.TYPED_ARRAY_SUPPORT ` :
* === true Use Uint8Array implementation ( fastest )
* === false Print warning and recommend using ` buffer ` v4 . x which has an Object
* implementation ( most compatible , even IE6 )
*
* Browsers that support typed arrays are IE 10 + , Firefox 4 + , Chrome 7 + , Safari 5.1 + ,
* Opera 11.6 + , iOS 4.2 + .
*
* We report that the browser does not support typed arrays if the are not subclassable
* using _ _proto _ _ . Firefox 4 - 29 lacks support for adding new properties to ` Uint8Array `
* ( See : https : //bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
* for _ _proto _ _ and has a buggy typed array implementation .
* /
Buffer . TYPED _ARRAY _SUPPORT = typedArraySupport ( )
if ( ! Buffer . TYPED _ARRAY _SUPPORT && typeof console !== 'undefined' &&
typeof console . error === 'function' ) {
console . error (
'This browser lacks typed array (Uint8Array) support which is required by ' +
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
)
}
function typedArraySupport ( ) {
// Can typed array instances can be augmented?
try {
var arr = new Uint8Array ( 1 )
arr . _ _proto _ _ = { _ _proto _ _ : Uint8Array . prototype , foo : function ( ) { return 42 } }
return arr . foo ( ) === 42
} catch ( e ) {
return false
}
}
function createBuffer ( length ) {
if ( length > K _MAX _LENGTH ) {
throw new RangeError ( 'Invalid typed array length' )
}
// Return an augmented `Uint8Array` instance
var buf = new Uint8Array ( length )
buf . _ _proto _ _ = Buffer . prototype
return buf
}
/ * *
* The Buffer constructor returns instances of ` Uint8Array ` that have their
* prototype changed to ` Buffer.prototype ` . Furthermore , ` Buffer ` is a subclass of
* ` Uint8Array ` , so the returned instances will have all the node ` Buffer ` methods
* and the ` Uint8Array ` methods . Square bracket notation works as expected -- it
* returns a single octet .
*
* The ` Uint8Array ` prototype remains unmodified .
* /
function Buffer ( arg , encodingOrOffset , length ) {
// Common case.
if ( typeof arg === 'number' ) {
if ( typeof encodingOrOffset === 'string' ) {
throw new Error (
'If encoding is specified then the first argument must be a string'
)
}
return allocUnsafe ( arg )
}
return from ( arg , encodingOrOffset , length )
}
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
if ( typeof Symbol !== 'undefined' && Symbol . species &&
Buffer [ Symbol . species ] === Buffer ) {
Object . defineProperty ( Buffer , Symbol . species , {
value : null ,
configurable : true ,
enumerable : false ,
writable : false
} )
}
Buffer . poolSize = 8192 // not used by this implementation
function from ( value , encodingOrOffset , length ) {
if ( typeof value === 'number' ) {
throw new TypeError ( '"value" argument must not be a number' )
}
if ( value instanceof ArrayBuffer ) {
return fromArrayBuffer ( value , encodingOrOffset , length )
}
if ( typeof value === 'string' ) {
return fromString ( value , encodingOrOffset )
}
return fromObject ( value )
}
/ * *
* Functionally equivalent to Buffer ( arg , encoding ) but throws a TypeError
* if value is a number .
* Buffer . from ( str [ , encoding ] )
* Buffer . from ( array )
* Buffer . from ( buffer )
* Buffer . from ( arrayBuffer [ , byteOffset [ , length ] ] )
* * /
Buffer . from = function ( value , encodingOrOffset , length ) {
return from ( value , encodingOrOffset , length )
}
// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
// https://github.com/feross/buffer/pull/148
Buffer . prototype . _ _proto _ _ = Uint8Array . prototype
Buffer . _ _proto _ _ = Uint8Array
function assertSize ( size ) {
if ( typeof size !== 'number' ) {
throw new TypeError ( '"size" argument must be a number' )
} else if ( size < 0 ) {
throw new RangeError ( '"size" argument must not be negative' )
}
}
function alloc ( size , fill , encoding ) {
assertSize ( size )
if ( size <= 0 ) {
return createBuffer ( size )
}
if ( fill !== undefined ) {
// Only pay attention to encoding if it's a string. This
// prevents accidentally sending in a number that would
// be interpretted as a start offset.
return typeof encoding === 'string'
? createBuffer ( size ) . fill ( fill , encoding )
: createBuffer ( size ) . fill ( fill )
}
return createBuffer ( size )
}
/ * *
* Creates a new filled Buffer instance .
* alloc ( size [ , fill [ , encoding ] ] )
* * /
Buffer . alloc = function ( size , fill , encoding ) {
return alloc ( size , fill , encoding )
}
function allocUnsafe ( size ) {
assertSize ( size )
return createBuffer ( size < 0 ? 0 : checked ( size ) | 0 )
}
/ * *
* Equivalent to Buffer ( num ) , by default creates a non - zero - filled Buffer instance .
* * /
Buffer . allocUnsafe = function ( size ) {
return allocUnsafe ( size )
}
/ * *
* Equivalent to SlowBuffer ( num ) , by default creates a non - zero - filled Buffer instance .
* /
Buffer . allocUnsafeSlow = function ( size ) {
return allocUnsafe ( size )
}
function fromString ( string , encoding ) {
if ( typeof encoding !== 'string' || encoding === '' ) {
encoding = 'utf8'
}
if ( ! Buffer . isEncoding ( encoding ) ) {
throw new TypeError ( '"encoding" must be a valid string encoding' )
}
var length = byteLength ( string , encoding ) | 0
var buf = createBuffer ( length )
var actual = buf . write ( string , encoding )
if ( actual !== length ) {
// Writing a hex string, for example, that contains invalid characters will
// cause everything after the first invalid character to be ignored. (e.g.
// 'abxxcd' will be treated as 'ab')
buf = buf . slice ( 0 , actual )
}
return buf
}
function fromArrayLike ( array ) {
var length = array . length < 0 ? 0 : checked ( array . length ) | 0
var buf = createBuffer ( length )
for ( var i = 0 ; i < length ; i += 1 ) {
buf [ i ] = array [ i ] & 255
}
return buf
}
function fromArrayBuffer ( array , byteOffset , length ) {
if ( byteOffset < 0 || array . byteLength < byteOffset ) {
throw new RangeError ( '\'offset\' is out of bounds' )
}
if ( array . byteLength < byteOffset + ( length || 0 ) ) {
throw new RangeError ( '\'length\' is out of bounds' )
}
var buf
if ( byteOffset === undefined && length === undefined ) {
buf = new Uint8Array ( array )
} else if ( length === undefined ) {
buf = new Uint8Array ( array , byteOffset )
} else {
buf = new Uint8Array ( array , byteOffset , length )
}
// Return an augmented `Uint8Array` instance
buf . _ _proto _ _ = Buffer . prototype
return buf
}
function fromObject ( obj ) {
if ( Buffer . isBuffer ( obj ) ) {
var len = checked ( obj . length ) | 0
var buf = createBuffer ( len )
if ( buf . length === 0 ) {
return buf
}
obj . copy ( buf , 0 , 0 , len )
return buf
}
if ( obj ) {
if ( isArrayBufferView ( obj ) || 'length' in obj ) {
if ( typeof obj . length !== 'number' || numberIsNaN ( obj . length ) ) {
return createBuffer ( 0 )
}
return fromArrayLike ( obj )
}
if ( obj . type === 'Buffer' && Array . isArray ( obj . data ) ) {
return fromArrayLike ( obj . data )
}
}
throw new TypeError ( 'First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.' )
}
function checked ( length ) {
// Note: cannot use `length < K_MAX_LENGTH` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if ( length >= K _MAX _LENGTH ) {
throw new RangeError ( 'Attempt to allocate Buffer larger than maximum ' +
'size: 0x' + K _MAX _LENGTH . toString ( 16 ) + ' bytes' )
}
return length | 0
}
function SlowBuffer ( length ) {
if ( + length != length ) { // eslint-disable-line eqeqeq
length = 0
}
return Buffer . alloc ( + length )
}
Buffer . isBuffer = function isBuffer ( b ) {
return b != null && b . _isBuffer === true
}
Buffer . compare = function compare ( a , b ) {
if ( ! Buffer . isBuffer ( a ) || ! Buffer . isBuffer ( b ) ) {
throw new TypeError ( 'Arguments must be Buffers' )
}
if ( a === b ) return 0
var x = a . length
var y = b . length
for ( var i = 0 , len = Math . min ( x , y ) ; i < len ; ++ i ) {
if ( a [ i ] !== b [ i ] ) {
x = a [ i ]
y = b [ i ]
break
}
}
if ( x < y ) return - 1
if ( y < x ) return 1
return 0
}
Buffer . isEncoding = function isEncoding ( encoding ) {
switch ( String ( encoding ) . toLowerCase ( ) ) {
case 'hex' :
case 'utf8' :
case 'utf-8' :
case 'ascii' :
case 'latin1' :
case 'binary' :
case 'base64' :
case 'ucs2' :
case 'ucs-2' :
case 'utf16le' :
case 'utf-16le' :
return true
default :
return false
}
}
Buffer . concat = function concat ( list , length ) {
if ( ! Array . isArray ( list ) ) {
throw new TypeError ( '"list" argument must be an Array of Buffers' )
}
if ( list . length === 0 ) {
return Buffer . alloc ( 0 )
}
var i
if ( length === undefined ) {
length = 0
for ( i = 0 ; i < list . length ; ++ i ) {
length += list [ i ] . length
}
}
var buffer = Buffer . allocUnsafe ( length )
var pos = 0
for ( i = 0 ; i < list . length ; ++ i ) {
var buf = list [ i ]
if ( ! Buffer . isBuffer ( buf ) ) {
throw new TypeError ( '"list" argument must be an Array of Buffers' )
}
buf . copy ( buffer , pos )
pos += buf . length
}
return buffer
}
function byteLength ( string , encoding ) {
if ( Buffer . isBuffer ( string ) ) {
return string . length
}
if ( isArrayBufferView ( string ) || string instanceof ArrayBuffer ) {
return string . byteLength
}
if ( typeof string !== 'string' ) {
string = '' + string
}
var len = string . length
if ( len === 0 ) return 0
// Use a for loop to avoid recursion
var loweredCase = false
for ( ; ; ) {
switch ( encoding ) {
case 'ascii' :
case 'latin1' :
case 'binary' :
return len
case 'utf8' :
case 'utf-8' :
case undefined :
return utf8ToBytes ( string ) . length
case 'ucs2' :
case 'ucs-2' :
case 'utf16le' :
case 'utf-16le' :
return len * 2
case 'hex' :
return len >>> 1
case 'base64' :
return base64ToBytes ( string ) . length
default :
if ( loweredCase ) return utf8ToBytes ( string ) . length // assume utf8
encoding = ( '' + encoding ) . toLowerCase ( )
loweredCase = true
}
}
}
Buffer . byteLength = byteLength
function slowToString ( encoding , start , end ) {
var loweredCase = false
// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
// property of a typed array.
// This behaves neither like String nor Uint8Array in that we set start/end
// to their upper/lower bounds if the value passed is out of range.
// undefined is handled specially as per ECMA-262 6th Edition,
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
if ( start === undefined || start < 0 ) {
start = 0
}
// Return early if start > this.length. Done here to prevent potential uint32
// coercion fail below.
if ( start > this . length ) {
return ''
}
if ( end === undefined || end > this . length ) {
end = this . length
}
if ( end <= 0 ) {
return ''
}
// Force coersion to uint32. This will also coerce falsey/NaN values to 0.
end >>>= 0
start >>>= 0
if ( end <= start ) {
return ''
}
if ( ! encoding ) encoding = 'utf8'
while ( true ) {
switch ( encoding ) {
case 'hex' :
return hexSlice ( this , start , end )
case 'utf8' :
case 'utf-8' :
return utf8Slice ( this , start , end )
case 'ascii' :
return asciiSlice ( this , start , end )
case 'latin1' :
case 'binary' :
return latin1Slice ( this , start , end )
case 'base64' :
return base64Slice ( this , start , end )
case 'ucs2' :
case 'ucs-2' :
case 'utf16le' :
case 'utf-16le' :
return utf16leSlice ( this , start , end )
default :
if ( loweredCase ) throw new TypeError ( 'Unknown encoding: ' + encoding )
encoding = ( encoding + '' ) . toLowerCase ( )
loweredCase = true
}
}
}
// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
// reliably in a browserify context because there could be multiple different
// copies of the 'buffer' package in use. This method works even for Buffer
// instances that were created from another copy of the `buffer` package.
// See: https://github.com/feross/buffer/issues/154
Buffer . prototype . _isBuffer = true
function swap ( b , n , m ) {
var i = b [ n ]
b [ n ] = b [ m ]
b [ m ] = i
}
Buffer . prototype . swap16 = function swap16 ( ) {
var len = this . length
if ( len % 2 !== 0 ) {
throw new RangeError ( 'Buffer size must be a multiple of 16-bits' )
}
for ( var i = 0 ; i < len ; i += 2 ) {
swap ( this , i , i + 1 )
}
return this
}
Buffer . prototype . swap32 = function swap32 ( ) {
var len = this . length
if ( len % 4 !== 0 ) {
throw new RangeError ( 'Buffer size must be a multiple of 32-bits' )
}
for ( var i = 0 ; i < len ; i += 4 ) {
swap ( this , i , i + 3 )
swap ( this , i + 1 , i + 2 )
}
return this
}
Buffer . prototype . swap64 = function swap64 ( ) {
var len = this . length
if ( len % 8 !== 0 ) {
throw new RangeError ( 'Buffer size must be a multiple of 64-bits' )
}
for ( var i = 0 ; i < len ; i += 8 ) {
swap ( this , i , i + 7 )
swap ( this , i + 1 , i + 6 )
swap ( this , i + 2 , i + 5 )
swap ( this , i + 3 , i + 4 )
}
return this
}
Buffer . prototype . toString = function toString ( ) {
var length = this . length
if ( length === 0 ) return ''
if ( arguments . length === 0 ) return utf8Slice ( this , 0 , length )
return slowToString . apply ( this , arguments )
}
Buffer . prototype . equals = function equals ( b ) {
if ( ! Buffer . isBuffer ( b ) ) throw new TypeError ( 'Argument must be a Buffer' )
if ( this === b ) return true
return Buffer . compare ( this , b ) === 0
}
Buffer . prototype . inspect = function inspect ( ) {
var str = ''
var max = exports . INSPECT _MAX _BYTES
if ( this . length > 0 ) {
str = this . toString ( 'hex' , 0 , max ) . match ( /.{2}/g ) . join ( ' ' )
if ( this . length > max ) str += ' ... '
}
return '<Buffer ' + str + '>'
}
Buffer . prototype . compare = function compare ( target , start , end , thisStart , thisEnd ) {
if ( ! Buffer . isBuffer ( target ) ) {
throw new TypeError ( 'Argument must be a Buffer' )
}
if ( start === undefined ) {
start = 0
}
if ( end === undefined ) {
end = target ? target . length : 0
}
if ( thisStart === undefined ) {
thisStart = 0
}
if ( thisEnd === undefined ) {
thisEnd = this . length
}
if ( start < 0 || end > target . length || thisStart < 0 || thisEnd > this . length ) {
throw new RangeError ( 'out of range index' )
}
if ( thisStart >= thisEnd && start >= end ) {
return 0
}
if ( thisStart >= thisEnd ) {
return - 1
}
if ( start >= end ) {
return 1
}
start >>>= 0
end >>>= 0
thisStart >>>= 0
thisEnd >>>= 0
if ( this === target ) return 0
var x = thisEnd - thisStart
var y = end - start
var len = Math . min ( x , y )
var thisCopy = this . slice ( thisStart , thisEnd )
var targetCopy = target . slice ( start , end )
for ( var i = 0 ; i < len ; ++ i ) {
if ( thisCopy [ i ] !== targetCopy [ i ] ) {
x = thisCopy [ i ]
y = targetCopy [ i ]
break
}
}
if ( x < y ) return - 1
if ( y < x ) return 1
return 0
}
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf ( buffer , val , byteOffset , encoding , dir ) {
// Empty buffer means no match
if ( buffer . length === 0 ) return - 1
// Normalize byteOffset
if ( typeof byteOffset === 'string' ) {
encoding = byteOffset
byteOffset = 0
} else if ( byteOffset > 0x7fffffff ) {
byteOffset = 0x7fffffff
} else if ( byteOffset < - 0x80000000 ) {
byteOffset = - 0x80000000
}
byteOffset = + byteOffset // Coerce to Number.
if ( numberIsNaN ( byteOffset ) ) {
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
byteOffset = dir ? 0 : ( buffer . length - 1 )
}
// Normalize byteOffset: negative offsets start from the end of the buffer
if ( byteOffset < 0 ) byteOffset = buffer . length + byteOffset
if ( byteOffset >= buffer . length ) {
if ( dir ) return - 1
else byteOffset = buffer . length - 1
} else if ( byteOffset < 0 ) {
if ( dir ) byteOffset = 0
else return - 1
}
// Normalize val
if ( typeof val === 'string' ) {
val = Buffer . from ( val , encoding )
}
// Finally, search either indexOf (if dir is true) or lastIndexOf
if ( Buffer . isBuffer ( val ) ) {
// Special case: looking for empty string/buffer always fails
if ( val . length === 0 ) {
return - 1
}
return arrayIndexOf ( buffer , val , byteOffset , encoding , dir )
} else if ( typeof val === 'number' ) {
val = val & 0xFF // Search for a byte value [0-255]
if ( typeof Uint8Array . prototype . indexOf === 'function' ) {
if ( dir ) {
return Uint8Array . prototype . indexOf . call ( buffer , val , byteOffset )
} else {
return Uint8Array . prototype . lastIndexOf . call ( buffer , val , byteOffset )
}
}
return arrayIndexOf ( buffer , [ val ] , byteOffset , encoding , dir )
}
throw new TypeError ( 'val must be string, number or Buffer' )
}
function arrayIndexOf ( arr , val , byteOffset , encoding , dir ) {
var indexSize = 1
var arrLength = arr . length
var valLength = val . length
if ( encoding !== undefined ) {
encoding = String ( encoding ) . toLowerCase ( )
if ( encoding === 'ucs2' || encoding === 'ucs-2' ||
encoding === 'utf16le' || encoding === 'utf-16le' ) {
if ( arr . length < 2 || val . length < 2 ) {
return - 1
}
indexSize = 2
arrLength /= 2
valLength /= 2
byteOffset /= 2
}
}
function read ( buf , i ) {
if ( indexSize === 1 ) {
return buf [ i ]
} else {
return buf . readUInt16BE ( i * indexSize )
}
}
var i
if ( dir ) {
var foundIndex = - 1
for ( i = byteOffset ; i < arrLength ; i ++ ) {
if ( read ( arr , i ) === read ( val , foundIndex === - 1 ? 0 : i - foundIndex ) ) {
if ( foundIndex === - 1 ) foundIndex = i
if ( i - foundIndex + 1 === valLength ) return foundIndex * indexSize
} else {
if ( foundIndex !== - 1 ) i -= i - foundIndex
foundIndex = - 1
}
}
} else {
if ( byteOffset + valLength > arrLength ) byteOffset = arrLength - valLength
for ( i = byteOffset ; i >= 0 ; i -- ) {
var found = true
for ( var j = 0 ; j < valLength ; j ++ ) {
if ( read ( arr , i + j ) !== read ( val , j ) ) {
found = false
break
}
}
if ( found ) return i
}
}
return - 1
}
Buffer . prototype . includes = function includes ( val , byteOffset , encoding ) {
return this . indexOf ( val , byteOffset , encoding ) !== - 1
}
Buffer . prototype . indexOf = function indexOf ( val , byteOffset , encoding ) {
return bidirectionalIndexOf ( this , val , byteOffset , encoding , true )
}
Buffer . prototype . lastIndexOf = function lastIndexOf ( val , byteOffset , encoding ) {
return bidirectionalIndexOf ( this , val , byteOffset , encoding , false )
}
function hexWrite ( buf , string , offset , length ) {
offset = Number ( offset ) || 0
var remaining = buf . length - offset
if ( ! length ) {
length = remaining
} else {
length = Number ( length )
if ( length > remaining ) {
length = remaining
}
}
// must be an even number of digits
var strLen = string . length
if ( strLen % 2 !== 0 ) throw new TypeError ( 'Invalid hex string' )
if ( length > strLen / 2 ) {
length = strLen / 2
}
for ( var i = 0 ; i < length ; ++ i ) {
var parsed = parseInt ( string . substr ( i * 2 , 2 ) , 16 )
if ( numberIsNaN ( parsed ) ) return i
buf [ offset + i ] = parsed
}
return i
}
function utf8Write ( buf , string , offset , length ) {
return blitBuffer ( utf8ToBytes ( string , buf . length - offset ) , buf , offset , length )
}
function asciiWrite ( buf , string , offset , length ) {
return blitBuffer ( asciiToBytes ( string ) , buf , offset , length )
}
function latin1Write ( buf , string , offset , length ) {
return asciiWrite ( buf , string , offset , length )
}
function base64Write ( buf , string , offset , length ) {
return blitBuffer ( base64ToBytes ( string ) , buf , offset , length )
}
function ucs2Write ( buf , string , offset , length ) {
return blitBuffer ( utf16leToBytes ( string , buf . length - offset ) , buf , offset , length )
}
Buffer . prototype . write = function write ( string , offset , length , encoding ) {
// Buffer#write(string)
if ( offset === undefined ) {
encoding = 'utf8'
length = this . length
offset = 0
// Buffer#write(string, encoding)
} else if ( length === undefined && typeof offset === 'string' ) {
encoding = offset
length = this . length
offset = 0
// Buffer#write(string, offset[, length][, encoding])
} else if ( isFinite ( offset ) ) {
offset = offset >>> 0
if ( isFinite ( length ) ) {
length = length >>> 0
if ( encoding === undefined ) encoding = 'utf8'
} else {
encoding = length
length = undefined
}
} else {
throw new Error (
'Buffer.write(string, encoding, offset[, length]) is no longer supported'
)
}
var remaining = this . length - offset
if ( length === undefined || length > remaining ) length = remaining
if ( ( string . length > 0 && ( length < 0 || offset < 0 ) ) || offset > this . length ) {
throw new RangeError ( 'Attempt to write outside buffer bounds' )
}
if ( ! encoding ) encoding = 'utf8'
var loweredCase = false
for ( ; ; ) {
switch ( encoding ) {
case 'hex' :
return hexWrite ( this , string , offset , length )
case 'utf8' :
case 'utf-8' :
return utf8Write ( this , string , offset , length )
case 'ascii' :
return asciiWrite ( this , string , offset , length )
case 'latin1' :
case 'binary' :
return latin1Write ( this , string , offset , length )
case 'base64' :
// Warning: maxLength not taken into account in base64Write
return base64Write ( this , string , offset , length )
case 'ucs2' :
case 'ucs-2' :
case 'utf16le' :
case 'utf-16le' :
return ucs2Write ( this , string , offset , length )
default :
if ( loweredCase ) throw new TypeError ( 'Unknown encoding: ' + encoding )
encoding = ( '' + encoding ) . toLowerCase ( )
loweredCase = true
}
}
}
Buffer . prototype . toJSON = function toJSON ( ) {
return {
type : 'Buffer' ,
data : Array . prototype . slice . call ( this . _arr || this , 0 )
}
}
function base64Slice ( buf , start , end ) {
if ( start === 0 && end === buf . length ) {
return base64 . fromByteArray ( buf )
} else {
return base64 . fromByteArray ( buf . slice ( start , end ) )
}
}
function utf8Slice ( buf , start , end ) {
end = Math . min ( buf . length , end )
var res = [ ]
var i = start
while ( i < end ) {
var firstByte = buf [ i ]
var codePoint = null
var bytesPerSequence = ( firstByte > 0xEF ) ? 4
: ( firstByte > 0xDF ) ? 3
: ( firstByte > 0xBF ) ? 2
: 1
if ( i + bytesPerSequence <= end ) {
var secondByte , thirdByte , fourthByte , tempCodePoint
switch ( bytesPerSequence ) {
case 1 :
if ( firstByte < 0x80 ) {
codePoint = firstByte
}
break
case 2 :
secondByte = buf [ i + 1 ]
if ( ( secondByte & 0xC0 ) === 0x80 ) {
tempCodePoint = ( firstByte & 0x1F ) << 0x6 | ( secondByte & 0x3F )
if ( tempCodePoint > 0x7F ) {
codePoint = tempCodePoint
}
}
break
case 3 :
secondByte = buf [ i + 1 ]
thirdByte = buf [ i + 2 ]
if ( ( secondByte & 0xC0 ) === 0x80 && ( thirdByte & 0xC0 ) === 0x80 ) {
tempCodePoint = ( firstByte & 0xF ) << 0xC | ( secondByte & 0x3F ) << 0x6 | ( thirdByte & 0x3F )
if ( tempCodePoint > 0x7FF && ( tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF ) ) {
codePoint = tempCodePoint
}
}
break
case 4 :
secondByte = buf [ i + 1 ]
thirdByte = buf [ i + 2 ]
fourthByte = buf [ i + 3 ]
if ( ( secondByte & 0xC0 ) === 0x80 && ( thirdByte & 0xC0 ) === 0x80 && ( fourthByte & 0xC0 ) === 0x80 ) {
tempCodePoint = ( firstByte & 0xF ) << 0x12 | ( secondByte & 0x3F ) << 0xC | ( thirdByte & 0x3F ) << 0x6 | ( fourthByte & 0x3F )
if ( tempCodePoint > 0xFFFF && tempCodePoint < 0x110000 ) {
codePoint = tempCodePoint
}
}
}
}
if ( codePoint === null ) {
// we did not generate a valid codePoint so insert a
// replacement char (U+FFFD) and advance only 1 byte
codePoint = 0xFFFD
bytesPerSequence = 1
} else if ( codePoint > 0xFFFF ) {
// encode to utf16 (surrogate pair dance)
codePoint -= 0x10000
res . push ( codePoint >>> 10 & 0x3FF | 0xD800 )
codePoint = 0xDC00 | codePoint & 0x3FF
}
res . push ( codePoint )
i += bytesPerSequence
}
return decodeCodePointsArray ( res )
}
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
var MAX _ARGUMENTS _LENGTH = 0x1000
function decodeCodePointsArray ( codePoints ) {
var len = codePoints . length
if ( len <= MAX _ARGUMENTS _LENGTH ) {
return String . fromCharCode . apply ( String , codePoints ) // avoid extra slice()
}
// Decode in chunks to avoid "call stack size exceeded".
var res = ''
var i = 0
while ( i < len ) {
res += String . fromCharCode . apply (
String ,
codePoints . slice ( i , i += MAX _ARGUMENTS _LENGTH )
)
}
return res
}
function asciiSlice ( buf , start , end ) {
var ret = ''
end = Math . min ( buf . length , end )
for ( var i = start ; i < end ; ++ i ) {
ret += String . fromCharCode ( buf [ i ] & 0x7F )
}
return ret
}
function latin1Slice ( buf , start , end ) {
var ret = ''
end = Math . min ( buf . length , end )
for ( var i = start ; i < end ; ++ i ) {
ret += String . fromCharCode ( buf [ i ] )
}
return ret
}
function hexSlice ( buf , start , end ) {
var len = buf . length
if ( ! start || start < 0 ) start = 0
if ( ! end || end < 0 || end > len ) end = len
var out = ''
for ( var i = start ; i < end ; ++ i ) {
out += toHex ( buf [ i ] )
}
return out
}
function utf16leSlice ( buf , start , end ) {
var bytes = buf . slice ( start , end )
var res = ''
for ( var i = 0 ; i < bytes . length ; i += 2 ) {
res += String . fromCharCode ( bytes [ i ] + ( bytes [ i + 1 ] * 256 ) )
}
return res
}
Buffer . prototype . slice = function slice ( start , end ) {
var len = this . length
start = ~ ~ start
end = end === undefined ? len : ~ ~ end
if ( start < 0 ) {
start += len
if ( start < 0 ) start = 0
} else if ( start > len ) {
start = len
}
if ( end < 0 ) {
end += len
if ( end < 0 ) end = 0
} else if ( end > len ) {
end = len
}
if ( end < start ) end = start
var newBuf = this . subarray ( start , end )
// Return an augmented `Uint8Array` instance
newBuf . _ _proto _ _ = Buffer . prototype
return newBuf
}
/ *
* Need to make sure that buffer isn ' t trying to write out of bounds .
* /
function checkOffset ( offset , ext , length ) {
if ( ( offset % 1 ) !== 0 || offset < 0 ) throw new RangeError ( 'offset is not uint' )
if ( offset + ext > length ) throw new RangeError ( 'Trying to access beyond buffer length' )
}
Buffer . prototype . readUIntLE = function readUIntLE ( offset , byteLength , noAssert ) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) checkOffset ( offset , byteLength , this . length )
var val = this [ offset ]
var mul = 1
var i = 0
while ( ++ i < byteLength && ( mul *= 0x100 ) ) {
val += this [ offset + i ] * mul
}
return val
}
Buffer . prototype . readUIntBE = function readUIntBE ( offset , byteLength , noAssert ) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) {
checkOffset ( offset , byteLength , this . length )
}
var val = this [ offset + -- byteLength ]
var mul = 1
while ( byteLength > 0 && ( mul *= 0x100 ) ) {
val += this [ offset + -- byteLength ] * mul
}
return val
}
Buffer . prototype . readUInt8 = function readUInt8 ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 1 , this . length )
return this [ offset ]
}
Buffer . prototype . readUInt16LE = function readUInt16LE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 2 , this . length )
return this [ offset ] | ( this [ offset + 1 ] << 8 )
}
Buffer . prototype . readUInt16BE = function readUInt16BE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 2 , this . length )
return ( this [ offset ] << 8 ) | this [ offset + 1 ]
}
Buffer . prototype . readUInt32LE = function readUInt32LE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ( ( this [ offset ] ) |
( this [ offset + 1 ] << 8 ) |
( this [ offset + 2 ] << 16 ) ) +
( this [ offset + 3 ] * 0x1000000 )
}
Buffer . prototype . readUInt32BE = function readUInt32BE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ( this [ offset ] * 0x1000000 ) +
( ( this [ offset + 1 ] << 16 ) |
( this [ offset + 2 ] << 8 ) |
this [ offset + 3 ] )
}
Buffer . prototype . readIntLE = function readIntLE ( offset , byteLength , noAssert ) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) checkOffset ( offset , byteLength , this . length )
var val = this [ offset ]
var mul = 1
var i = 0
while ( ++ i < byteLength && ( mul *= 0x100 ) ) {
val += this [ offset + i ] * mul
}
mul *= 0x80
if ( val >= mul ) val -= Math . pow ( 2 , 8 * byteLength )
return val
}
Buffer . prototype . readIntBE = function readIntBE ( offset , byteLength , noAssert ) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) checkOffset ( offset , byteLength , this . length )
var i = byteLength
var mul = 1
var val = this [ offset + -- i ]
while ( i > 0 && ( mul *= 0x100 ) ) {
val += this [ offset + -- i ] * mul
}
mul *= 0x80
if ( val >= mul ) val -= Math . pow ( 2 , 8 * byteLength )
return val
}
Buffer . prototype . readInt8 = function readInt8 ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 1 , this . length )
if ( ! ( this [ offset ] & 0x80 ) ) return ( this [ offset ] )
return ( ( 0xff - this [ offset ] + 1 ) * - 1 )
}
Buffer . prototype . readInt16LE = function readInt16LE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 2 , this . length )
var val = this [ offset ] | ( this [ offset + 1 ] << 8 )
return ( val & 0x8000 ) ? val | 0xFFFF0000 : val
}
Buffer . prototype . readInt16BE = function readInt16BE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 2 , this . length )
var val = this [ offset + 1 ] | ( this [ offset ] << 8 )
return ( val & 0x8000 ) ? val | 0xFFFF0000 : val
}
Buffer . prototype . readInt32LE = function readInt32LE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ( this [ offset ] ) |
( this [ offset + 1 ] << 8 ) |
( this [ offset + 2 ] << 16 ) |
( this [ offset + 3 ] << 24 )
}
Buffer . prototype . readInt32BE = function readInt32BE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ( this [ offset ] << 24 ) |
( this [ offset + 1 ] << 16 ) |
( this [ offset + 2 ] << 8 ) |
( this [ offset + 3 ] )
}
Buffer . prototype . readFloatLE = function readFloatLE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ieee754 . read ( this , offset , true , 23 , 4 )
}
Buffer . prototype . readFloatBE = function readFloatBE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 4 , this . length )
return ieee754 . read ( this , offset , false , 23 , 4 )
}
Buffer . prototype . readDoubleLE = function readDoubleLE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 8 , this . length )
return ieee754 . read ( this , offset , true , 52 , 8 )
}
Buffer . prototype . readDoubleBE = function readDoubleBE ( offset , noAssert ) {
offset = offset >>> 0
if ( ! noAssert ) checkOffset ( offset , 8 , this . length )
return ieee754 . read ( this , offset , false , 52 , 8 )
}
function checkInt ( buf , value , offset , ext , max , min ) {
if ( ! Buffer . isBuffer ( buf ) ) throw new TypeError ( '"buffer" argument must be a Buffer instance' )
if ( value > max || value < min ) throw new RangeError ( '"value" argument is out of bounds' )
if ( offset + ext > buf . length ) throw new RangeError ( 'Index out of range' )
}
Buffer . prototype . writeUIntLE = function writeUIntLE ( value , offset , byteLength , noAssert ) {
value = + value
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) {
var maxBytes = Math . pow ( 2 , 8 * byteLength ) - 1
checkInt ( this , value , offset , byteLength , maxBytes , 0 )
}
var mul = 1
var i = 0
this [ offset ] = value & 0xFF
while ( ++ i < byteLength && ( mul *= 0x100 ) ) {
this [ offset + i ] = ( value / mul ) & 0xFF
}
return offset + byteLength
}
Buffer . prototype . writeUIntBE = function writeUIntBE ( value , offset , byteLength , noAssert ) {
value = + value
offset = offset >>> 0
byteLength = byteLength >>> 0
if ( ! noAssert ) {
var maxBytes = Math . pow ( 2 , 8 * byteLength ) - 1
checkInt ( this , value , offset , byteLength , maxBytes , 0 )
}
var i = byteLength - 1
var mul = 1
this [ offset + i ] = value & 0xFF
while ( -- i >= 0 && ( mul *= 0x100 ) ) {
this [ offset + i ] = ( value / mul ) & 0xFF
}
return offset + byteLength
}
Buffer . prototype . writeUInt8 = function writeUInt8 ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 1 , 0xff , 0 )
this [ offset ] = ( value & 0xff )
return offset + 1
}
Buffer . prototype . writeUInt16LE = function writeUInt16LE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 2 , 0xffff , 0 )
this [ offset ] = ( value & 0xff )
this [ offset + 1 ] = ( value >>> 8 )
return offset + 2
}
Buffer . prototype . writeUInt16BE = function writeUInt16BE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 2 , 0xffff , 0 )
this [ offset ] = ( value >>> 8 )
this [ offset + 1 ] = ( value & 0xff )
return offset + 2
}
Buffer . prototype . writeUInt32LE = function writeUInt32LE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 4 , 0xffffffff , 0 )
this [ offset + 3 ] = ( value >>> 24 )
this [ offset + 2 ] = ( value >>> 16 )
this [ offset + 1 ] = ( value >>> 8 )
this [ offset ] = ( value & 0xff )
return offset + 4
}
Buffer . prototype . writeUInt32BE = function writeUInt32BE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 4 , 0xffffffff , 0 )
this [ offset ] = ( value >>> 24 )
this [ offset + 1 ] = ( value >>> 16 )
this [ offset + 2 ] = ( value >>> 8 )
this [ offset + 3 ] = ( value & 0xff )
return offset + 4
}
Buffer . prototype . writeIntLE = function writeIntLE ( value , offset , byteLength , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) {
var limit = Math . pow ( 2 , ( 8 * byteLength ) - 1 )
checkInt ( this , value , offset , byteLength , limit - 1 , - limit )
}
var i = 0
var mul = 1
var sub = 0
this [ offset ] = value & 0xFF
while ( ++ i < byteLength && ( mul *= 0x100 ) ) {
if ( value < 0 && sub === 0 && this [ offset + i - 1 ] !== 0 ) {
sub = 1
}
this [ offset + i ] = ( ( value / mul ) >> 0 ) - sub & 0xFF
}
return offset + byteLength
}
Buffer . prototype . writeIntBE = function writeIntBE ( value , offset , byteLength , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) {
var limit = Math . pow ( 2 , ( 8 * byteLength ) - 1 )
checkInt ( this , value , offset , byteLength , limit - 1 , - limit )
}
var i = byteLength - 1
var mul = 1
var sub = 0
this [ offset + i ] = value & 0xFF
while ( -- i >= 0 && ( mul *= 0x100 ) ) {
if ( value < 0 && sub === 0 && this [ offset + i + 1 ] !== 0 ) {
sub = 1
}
this [ offset + i ] = ( ( value / mul ) >> 0 ) - sub & 0xFF
}
return offset + byteLength
}
Buffer . prototype . writeInt8 = function writeInt8 ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 1 , 0x7f , - 0x80 )
if ( value < 0 ) value = 0xff + value + 1
this [ offset ] = ( value & 0xff )
return offset + 1
}
Buffer . prototype . writeInt16LE = function writeInt16LE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 2 , 0x7fff , - 0x8000 )
this [ offset ] = ( value & 0xff )
this [ offset + 1 ] = ( value >>> 8 )
return offset + 2
}
Buffer . prototype . writeInt16BE = function writeInt16BE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 2 , 0x7fff , - 0x8000 )
this [ offset ] = ( value >>> 8 )
this [ offset + 1 ] = ( value & 0xff )
return offset + 2
}
Buffer . prototype . writeInt32LE = function writeInt32LE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 4 , 0x7fffffff , - 0x80000000 )
this [ offset ] = ( value & 0xff )
this [ offset + 1 ] = ( value >>> 8 )
this [ offset + 2 ] = ( value >>> 16 )
this [ offset + 3 ] = ( value >>> 24 )
return offset + 4
}
Buffer . prototype . writeInt32BE = function writeInt32BE ( value , offset , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) checkInt ( this , value , offset , 4 , 0x7fffffff , - 0x80000000 )
if ( value < 0 ) value = 0xffffffff + value + 1
this [ offset ] = ( value >>> 24 )
this [ offset + 1 ] = ( value >>> 16 )
this [ offset + 2 ] = ( value >>> 8 )
this [ offset + 3 ] = ( value & 0xff )
return offset + 4
}
function checkIEEE754 ( buf , value , offset , ext , max , min ) {
if ( offset + ext > buf . length ) throw new RangeError ( 'Index out of range' )
if ( offset < 0 ) throw new RangeError ( 'Index out of range' )
}
function writeFloat ( buf , value , offset , littleEndian , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) {
checkIEEE754 ( buf , value , offset , 4 , 3.4028234663852886 e + 38 , - 3.4028234663852886 e + 38 )
}
ieee754 . write ( buf , value , offset , littleEndian , 23 , 4 )
return offset + 4
}
Buffer . prototype . writeFloatLE = function writeFloatLE ( value , offset , noAssert ) {
return writeFloat ( this , value , offset , true , noAssert )
}
Buffer . prototype . writeFloatBE = function writeFloatBE ( value , offset , noAssert ) {
return writeFloat ( this , value , offset , false , noAssert )
}
function writeDouble ( buf , value , offset , littleEndian , noAssert ) {
value = + value
offset = offset >>> 0
if ( ! noAssert ) {
checkIEEE754 ( buf , value , offset , 8 , 1.7976931348623157 E + 308 , - 1.7976931348623157 E + 308 )
}
ieee754 . write ( buf , value , offset , littleEndian , 52 , 8 )
return offset + 8
}
Buffer . prototype . writeDoubleLE = function writeDoubleLE ( value , offset , noAssert ) {
return writeDouble ( this , value , offset , true , noAssert )
}
Buffer . prototype . writeDoubleBE = function writeDoubleBE ( value , offset , noAssert ) {
return writeDouble ( this , value , offset , false , noAssert )
}
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer . prototype . copy = function copy ( target , targetStart , start , end ) {
if ( ! start ) start = 0
if ( ! end && end !== 0 ) end = this . length
if ( targetStart >= target . length ) targetStart = target . length
if ( ! targetStart ) targetStart = 0
if ( end > 0 && end < start ) end = start
// Copy 0 bytes; we're done
if ( end === start ) return 0
if ( target . length === 0 || this . length === 0 ) return 0
// Fatal error conditions
if ( targetStart < 0 ) {
throw new RangeError ( 'targetStart out of bounds' )
}
if ( start < 0 || start >= this . length ) throw new RangeError ( 'sourceStart out of bounds' )
if ( end < 0 ) throw new RangeError ( 'sourceEnd out of bounds' )
// Are we oob?
if ( end > this . length ) end = this . length
if ( target . length - targetStart < end - start ) {
end = target . length - targetStart + start
}
var len = end - start
var i
if ( this === target && start < targetStart && targetStart < end ) {
// descending copy from end
for ( i = len - 1 ; i >= 0 ; -- i ) {
target [ i + targetStart ] = this [ i + start ]
}
} else if ( len < 1000 ) {
// ascending copy from start
for ( i = 0 ; i < len ; ++ i ) {
target [ i + targetStart ] = this [ i + start ]
}
} else {
Uint8Array . prototype . set . call (
target ,
this . subarray ( start , start + len ) ,
targetStart
)
}
return len
}
// Usage:
// buffer.fill(number[, offset[, end]])
// buffer.fill(buffer[, offset[, end]])
// buffer.fill(string[, offset[, end]][, encoding])
Buffer . prototype . fill = function fill ( val , start , end , encoding ) {
// Handle string cases:
if ( typeof val === 'string' ) {
if ( typeof start === 'string' ) {
encoding = start
start = 0
end = this . length
} else if ( typeof end === 'string' ) {
encoding = end
end = this . length
}
if ( val . length === 1 ) {
var code = val . charCodeAt ( 0 )
if ( code < 256 ) {
val = code
}
}
if ( encoding !== undefined && typeof encoding !== 'string' ) {
throw new TypeError ( 'encoding must be a string' )
}
if ( typeof encoding === 'string' && ! Buffer . isEncoding ( encoding ) ) {
throw new TypeError ( 'Unknown encoding: ' + encoding )
}
} else if ( typeof val === 'number' ) {
val = val & 255
}
// Invalid ranges are not set to a default, so can range check early.
if ( start < 0 || this . length < start || this . length < end ) {
throw new RangeError ( 'Out of range index' )
}
if ( end <= start ) {
return this
}
start = start >>> 0
end = end === undefined ? this . length : end >>> 0
if ( ! val ) val = 0
var i
if ( typeof val === 'number' ) {
for ( i = start ; i < end ; ++ i ) {
this [ i ] = val
}
} else {
var bytes = Buffer . isBuffer ( val )
? val
: new Buffer ( val , encoding )
var len = bytes . length
for ( i = 0 ; i < end - start ; ++ i ) {
this [ i + start ] = bytes [ i % len ]
}
}
return this
}
// HELPER FUNCTIONS
// ================
var INVALID _BASE64 _RE = /[^+/0-9A-Za-z-_]/g
function base64clean ( str ) {
// Node strips out invalid characters like \n and \t from the string, base64-js does not
str = str . trim ( ) . replace ( INVALID _BASE64 _RE , '' )
// Node converts strings with length < 2 to ''
if ( str . length < 2 ) return ''
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
while ( str . length % 4 !== 0 ) {
str = str + '='
}
return str
}
function toHex ( n ) {
if ( n < 16 ) return '0' + n . toString ( 16 )
return n . toString ( 16 )
}
function utf8ToBytes ( string , units ) {
units = units || Infinity
var codePoint
var length = string . length
var leadSurrogate = null
var bytes = [ ]
for ( var i = 0 ; i < length ; ++ i ) {
codePoint = string . charCodeAt ( i )
// is surrogate component
if ( codePoint > 0xD7FF && codePoint < 0xE000 ) {
// last char was a lead
if ( ! leadSurrogate ) {
// no lead yet
if ( codePoint > 0xDBFF ) {
// unexpected trail
if ( ( units -= 3 ) > - 1 ) bytes . push ( 0xEF , 0xBF , 0xBD )
continue
} else if ( i + 1 === length ) {
// unpaired lead
if ( ( units -= 3 ) > - 1 ) bytes . push ( 0xEF , 0xBF , 0xBD )
continue
}
// valid lead
leadSurrogate = codePoint
continue
}
// 2 leads in a row
if ( codePoint < 0xDC00 ) {
if ( ( units -= 3 ) > - 1 ) bytes . push ( 0xEF , 0xBF , 0xBD )
leadSurrogate = codePoint
continue
}
// valid surrogate pair
codePoint = ( leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 ) + 0x10000
} else if ( leadSurrogate ) {
// valid bmp char, but last char was a lead
if ( ( units -= 3 ) > - 1 ) bytes . push ( 0xEF , 0xBF , 0xBD )
}
leadSurrogate = null
// encode utf8
if ( codePoint < 0x80 ) {
if ( ( units -= 1 ) < 0 ) break
bytes . push ( codePoint )
} else if ( codePoint < 0x800 ) {
if ( ( units -= 2 ) < 0 ) break
bytes . push (
codePoint >> 0x6 | 0xC0 ,
codePoint & 0x3F | 0x80
)
} else if ( codePoint < 0x10000 ) {
if ( ( units -= 3 ) < 0 ) break
bytes . push (
codePoint >> 0xC | 0xE0 ,
codePoint >> 0x6 & 0x3F | 0x80 ,
codePoint & 0x3F | 0x80
)
} else if ( codePoint < 0x110000 ) {
if ( ( units -= 4 ) < 0 ) break
bytes . push (
codePoint >> 0x12 | 0xF0 ,
codePoint >> 0xC & 0x3F | 0x80 ,
codePoint >> 0x6 & 0x3F | 0x80 ,
codePoint & 0x3F | 0x80
)
} else {
throw new Error ( 'Invalid code point' )
}
}
return bytes
}
function asciiToBytes ( str ) {
var byteArray = [ ]
for ( var i = 0 ; i < str . length ; ++ i ) {
// Node's code seems to be doing this and not & 0x7F..
byteArray . push ( str . charCodeAt ( i ) & 0xFF )
}
return byteArray
}
function utf16leToBytes ( str , units ) {
var c , hi , lo
var byteArray = [ ]
for ( var i = 0 ; i < str . length ; ++ i ) {
if ( ( units -= 2 ) < 0 ) break
c = str . charCodeAt ( i )
hi = c >> 8
lo = c % 256
byteArray . push ( lo )
byteArray . push ( hi )
}
return byteArray
}
function base64ToBytes ( str ) {
return base64 . toByteArray ( base64clean ( str ) )
}
function blitBuffer ( src , dst , offset , length ) {
for ( var i = 0 ; i < length ; ++ i ) {
if ( ( i + offset >= dst . length ) || ( i >= src . length ) ) break
dst [ i + offset ] = src [ i ]
}
return i
}
// Node 0.10 supports `ArrayBuffer` but lacks `ArrayBuffer.isView`
function isArrayBufferView ( obj ) {
return ( typeof ArrayBuffer . isView === 'function' ) && ArrayBuffer . isView ( obj )
}
function numberIsNaN ( obj ) {
return obj !== obj // eslint-disable-line no-self-compare
}
} , { "base64-js" : 1 , "ieee754" : 15 } ] , 4 : [ function ( require , module , exports ) {
// Use strict mode (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)
"use strict" ;
// Requires
var Typo = require ( "typo-js" ) ;
// Create function
function CodeMirrorSpellChecker ( options ) {
// Initialize
options = options || { } ;
// Verify
if ( typeof options . codeMirrorInstance !== "function" || typeof options . codeMirrorInstance . defineMode !== "function" ) {
console . log ( "CodeMirror Spell Checker: You must provide an instance of CodeMirror via the option `codeMirrorInstance`" ) ;
return ;
}
// Because some browsers don't support this functionality yet
if ( ! String . prototype . includes ) {
String . prototype . includes = function ( ) {
"use strict" ;
return String . prototype . indexOf . apply ( this , arguments ) !== - 1 ;
} ;
}
// Define the new mode
options . codeMirrorInstance . defineMode ( "spell-checker" , function ( config ) {
// Load AFF/DIC data
if ( ! CodeMirrorSpellChecker . aff _loading ) {
CodeMirrorSpellChecker . aff _loading = true ;
var xhr _aff = new XMLHttpRequest ( ) ;
xhr _aff . open ( "GET" , "https://cdn.jsdelivr.net/codemirror.spell-checker/latest/en_US.aff" , true ) ;
xhr _aff . onload = function ( ) {
if ( xhr _aff . readyState === 4 && xhr _aff . status === 200 ) {
CodeMirrorSpellChecker . aff _data = xhr _aff . responseText ;
CodeMirrorSpellChecker . num _loaded ++ ;
if ( CodeMirrorSpellChecker . num _loaded == 2 ) {
CodeMirrorSpellChecker . typo = new Typo ( "en_US" , CodeMirrorSpellChecker . aff _data , CodeMirrorSpellChecker . dic _data , {
platform : "any"
} ) ;
}
}
} ;
xhr _aff . send ( null ) ;
}
if ( ! CodeMirrorSpellChecker . dic _loading ) {
CodeMirrorSpellChecker . dic _loading = true ;
var xhr _dic = new XMLHttpRequest ( ) ;
xhr _dic . open ( "GET" , "https://cdn.jsdelivr.net/codemirror.spell-checker/latest/en_US.dic" , true ) ;
xhr _dic . onload = function ( ) {
if ( xhr _dic . readyState === 4 && xhr _dic . status === 200 ) {
CodeMirrorSpellChecker . dic _data = xhr _dic . responseText ;
CodeMirrorSpellChecker . num _loaded ++ ;
if ( CodeMirrorSpellChecker . num _loaded == 2 ) {
CodeMirrorSpellChecker . typo = new Typo ( "en_US" , CodeMirrorSpellChecker . aff _data , CodeMirrorSpellChecker . dic _data , {
platform : "any"
} ) ;
}
}
} ;
xhr _dic . send ( null ) ;
}
// Define what separates a word
var rx _word = "!\"#$%&()*+,-./:;<=>?@[\\]^_`{|}~ " ;
// Create the overlay and such
var overlay = {
token : function ( stream ) {
var ch = stream . peek ( ) ;
var word = "" ;
if ( rx _word . includes ( ch ) ) {
stream . next ( ) ;
return null ;
}
while ( ( ch = stream . peek ( ) ) != null && ! rx _word . includes ( ch ) ) {
word += ch ;
stream . next ( ) ;
}
if ( CodeMirrorSpellChecker . typo && ! CodeMirrorSpellChecker . typo . check ( word ) )
return "spell-error" ; // CSS class: cm-spell-error
return null ;
}
} ;
var mode = options . codeMirrorInstance . getMode (
config , config . backdrop || "text/plain"
) ;
return options . codeMirrorInstance . overlayMode ( mode , overlay , true ) ;
} ) ;
}
// Initialize data globally to reduce memory consumption
CodeMirrorSpellChecker . num _loaded = 0 ;
CodeMirrorSpellChecker . aff _loading = false ;
CodeMirrorSpellChecker . dic _loading = false ;
CodeMirrorSpellChecker . aff _data = "" ;
CodeMirrorSpellChecker . dic _data = "" ;
CodeMirrorSpellChecker . typo ;
// Export
module . exports = CodeMirrorSpellChecker ;
} , { "typo-js" : 17 } ] , 5 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
CodeMirror . defineOption ( "fullScreen" , false , function ( cm , val , old ) {
if ( old == CodeMirror . Init ) old = false ;
if ( ! old == ! val ) return ;
if ( val ) setFullscreen ( cm ) ;
else setNormal ( cm ) ;
} ) ;
function setFullscreen ( cm ) {
var wrap = cm . getWrapperElement ( ) ;
cm . state . fullScreenRestore = { scrollTop : window . pageYOffset , scrollLeft : window . pageXOffset ,
width : wrap . style . width , height : wrap . style . height } ;
wrap . style . width = "" ;
wrap . style . height = "auto" ;
wrap . className += " CodeMirror-fullscreen" ;
document . documentElement . style . overflow = "hidden" ;
cm . refresh ( ) ;
}
function setNormal ( cm ) {
var wrap = cm . getWrapperElement ( ) ;
wrap . className = wrap . className . replace ( /\s*CodeMirror-fullscreen\b/ , "" ) ;
document . documentElement . style . overflow = "" ;
var info = cm . state . fullScreenRestore ;
wrap . style . width = info . width ; wrap . style . height = info . height ;
window . scrollTo ( info . scrollLeft , info . scrollTop ) ;
cm . refresh ( ) ;
}
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 6 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
CodeMirror . defineOption ( "placeholder" , "" , function ( cm , val , old ) {
var prev = old && old != CodeMirror . Init ;
if ( val && ! prev ) {
cm . on ( "blur" , onBlur ) ;
cm . on ( "change" , onChange ) ;
cm . on ( "swapDoc" , onChange ) ;
onChange ( cm ) ;
} else if ( ! val && prev ) {
cm . off ( "blur" , onBlur ) ;
cm . off ( "change" , onChange ) ;
cm . off ( "swapDoc" , onChange ) ;
clearPlaceholder ( cm ) ;
var wrapper = cm . getWrapperElement ( ) ;
wrapper . className = wrapper . className . replace ( " CodeMirror-empty" , "" ) ;
}
if ( val && ! cm . hasFocus ( ) ) onBlur ( cm ) ;
} ) ;
function clearPlaceholder ( cm ) {
if ( cm . state . placeholder ) {
cm . state . placeholder . parentNode . removeChild ( cm . state . placeholder ) ;
cm . state . placeholder = null ;
}
}
function setPlaceholder ( cm ) {
clearPlaceholder ( cm ) ;
var elt = cm . state . placeholder = document . createElement ( "pre" ) ;
elt . style . cssText = "height: 0; overflow: visible" ;
elt . className = "CodeMirror-placeholder" ;
var placeHolder = cm . getOption ( "placeholder" )
if ( typeof placeHolder == "string" ) placeHolder = document . createTextNode ( placeHolder )
elt . appendChild ( placeHolder )
cm . display . lineSpace . insertBefore ( elt , cm . display . lineSpace . firstChild ) ;
}
function onBlur ( cm ) {
if ( isEmpty ( cm ) ) setPlaceholder ( cm ) ;
}
function onChange ( cm ) {
var wrapper = cm . getWrapperElement ( ) , empty = isEmpty ( cm ) ;
wrapper . className = wrapper . className . replace ( " CodeMirror-empty" , "" ) + ( empty ? " CodeMirror-empty" : "" ) ;
if ( empty ) setPlaceholder ( cm ) ;
else clearPlaceholder ( cm ) ;
}
function isEmpty ( cm ) {
return ( cm . lineCount ( ) === 1 ) && ( cm . getLine ( 0 ) === "" ) ;
}
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 7 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/ ,
emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/ ,
unorderedListRE = /[*+-]\s/ ;
CodeMirror . commands . newlineAndIndentContinueMarkdownList = function ( cm ) {
if ( cm . getOption ( "disableInput" ) ) return CodeMirror . Pass ;
var ranges = cm . listSelections ( ) , replacements = [ ] ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var pos = ranges [ i ] . head ;
var eolState = cm . getStateAfter ( pos . line ) ;
var inList = eolState . list !== false ;
var inQuote = eolState . quote !== 0 ;
var line = cm . getLine ( pos . line ) , match = listRE . exec ( line ) ;
if ( ! ranges [ i ] . empty ( ) || ( ! inList && ! inQuote ) || ! match ) {
cm . execCommand ( "newlineAndIndent" ) ;
return ;
}
if ( emptyListRE . test ( line ) ) {
if ( ! />\s*$/ . test ( line ) ) cm . replaceRange ( "" , {
line : pos . line , ch : 0
} , {
line : pos . line , ch : pos . ch + 1
} ) ;
replacements [ i ] = "\n" ;
} else {
var indent = match [ 1 ] , after = match [ 5 ] ;
var bullet = unorderedListRE . test ( match [ 2 ] ) || match [ 2 ] . indexOf ( ">" ) >= 0
? match [ 2 ] . replace ( "x" , " " )
: ( parseInt ( match [ 3 ] , 10 ) + 1 ) + match [ 4 ] ;
replacements [ i ] = "\n" + indent + bullet + after ;
}
}
cm . replaceSelections ( replacements ) ;
} ;
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 8 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are
// combined.
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
CodeMirror . overlayMode = function ( base , overlay , combine ) {
return {
startState : function ( ) {
return {
base : CodeMirror . startState ( base ) ,
overlay : CodeMirror . startState ( overlay ) ,
basePos : 0 , baseCur : null ,
overlayPos : 0 , overlayCur : null ,
streamSeen : null
} ;
} ,
copyState : function ( state ) {
return {
base : CodeMirror . copyState ( base , state . base ) ,
overlay : CodeMirror . copyState ( overlay , state . overlay ) ,
basePos : state . basePos , baseCur : null ,
overlayPos : state . overlayPos , overlayCur : null
} ;
} ,
token : function ( stream , state ) {
if ( stream != state . streamSeen ||
Math . min ( state . basePos , state . overlayPos ) < stream . start ) {
state . streamSeen = stream ;
state . basePos = state . overlayPos = stream . start ;
}
if ( stream . start == state . basePos ) {
state . baseCur = base . token ( stream , state . base ) ;
state . basePos = stream . pos ;
}
if ( stream . start == state . overlayPos ) {
stream . pos = stream . start ;
state . overlayCur = overlay . token ( stream , state . overlay ) ;
state . overlayPos = stream . pos ;
}
stream . pos = Math . min ( state . basePos , state . overlayPos ) ;
// state.overlay.combineTokens always takes precedence over combine,
// unless set to null
if ( state . overlayCur == null ) return state . baseCur ;
else if ( state . baseCur != null &&
state . overlay . combineTokens ||
combine && state . overlay . combineTokens == null )
return state . baseCur + " " + state . overlayCur ;
else return state . overlayCur ;
} ,
indent : base . indent && function ( state , textAfter ) {
return base . indent ( state . base , textAfter ) ;
} ,
electricChars : base . electricChars ,
innerMode : function ( state ) { return { state : state . base , mode : base } ; } ,
blankLine : function ( state ) {
var baseToken , overlayToken ;
if ( base . blankLine ) baseToken = base . blankLine ( state . base ) ;
if ( overlay . blankLine ) overlayToken = overlay . blankLine ( state . overlay ) ;
return overlayToken == null ?
baseToken :
( combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken ) ;
}
} ;
} ;
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 9 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Because sometimes you need to mark the selected *text*.
//
// Adds an option 'styleSelectedText' which, when enabled, gives
// selected text the CSS class given as option value, or
// "CodeMirror-selectedtext" when the value is not a string.
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
CodeMirror . defineOption ( "styleSelectedText" , false , function ( cm , val , old ) {
var prev = old && old != CodeMirror . Init ;
if ( val && ! prev ) {
cm . state . markedSelection = [ ] ;
cm . state . markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext" ;
reset ( cm ) ;
cm . on ( "cursorActivity" , onCursorActivity ) ;
cm . on ( "change" , onChange ) ;
} else if ( ! val && prev ) {
cm . off ( "cursorActivity" , onCursorActivity ) ;
cm . off ( "change" , onChange ) ;
clear ( cm ) ;
cm . state . markedSelection = cm . state . markedSelectionStyle = null ;
}
} ) ;
function onCursorActivity ( cm ) {
if ( cm . state . markedSelection )
cm . operation ( function ( ) { update ( cm ) ; } ) ;
}
function onChange ( cm ) {
if ( cm . state . markedSelection && cm . state . markedSelection . length )
cm . operation ( function ( ) { clear ( cm ) ; } ) ;
}
var CHUNK _SIZE = 8 ;
var Pos = CodeMirror . Pos ;
var cmp = CodeMirror . cmpPos ;
function coverRange ( cm , from , to , addAt ) {
if ( cmp ( from , to ) == 0 ) return ;
var array = cm . state . markedSelection ;
var cls = cm . state . markedSelectionStyle ;
for ( var line = from . line ; ; ) {
var start = line == from . line ? from : Pos ( line , 0 ) ;
var endLine = line + CHUNK _SIZE , atEnd = endLine >= to . line ;
var end = atEnd ? to : Pos ( endLine , 0 ) ;
var mark = cm . markText ( start , end , { className : cls } ) ;
if ( addAt == null ) array . push ( mark ) ;
else array . splice ( addAt ++ , 0 , mark ) ;
if ( atEnd ) break ;
line = endLine ;
}
}
function clear ( cm ) {
var array = cm . state . markedSelection ;
for ( var i = 0 ; i < array . length ; ++ i ) array [ i ] . clear ( ) ;
array . length = 0 ;
}
function reset ( cm ) {
clear ( cm ) ;
var ranges = cm . listSelections ( ) ;
for ( var i = 0 ; i < ranges . length ; i ++ )
coverRange ( cm , ranges [ i ] . from ( ) , ranges [ i ] . to ( ) ) ;
}
function update ( cm ) {
if ( ! cm . somethingSelected ( ) ) return clear ( cm ) ;
if ( cm . listSelections ( ) . length > 1 ) return reset ( cm ) ;
var from = cm . getCursor ( "start" ) , to = cm . getCursor ( "end" ) ;
var array = cm . state . markedSelection ;
if ( ! array . length ) return coverRange ( cm , from , to ) ;
var coverStart = array [ 0 ] . find ( ) , coverEnd = array [ array . length - 1 ] . find ( ) ;
if ( ! coverStart || ! coverEnd || to . line - from . line < CHUNK _SIZE ||
cmp ( from , coverEnd . to ) >= 0 || cmp ( to , coverStart . from ) <= 0 )
return reset ( cm ) ;
while ( cmp ( from , coverStart . from ) > 0 ) {
array . shift ( ) . clear ( ) ;
coverStart = array [ 0 ] . find ( ) ;
}
if ( cmp ( from , coverStart . from ) < 0 ) {
if ( coverStart . to . line - from . line < CHUNK _SIZE ) {
array . shift ( ) . clear ( ) ;
coverRange ( cm , from , coverStart . to , 0 ) ;
} else {
coverRange ( cm , from , coverStart . from , 0 ) ;
}
}
while ( cmp ( to , coverEnd . to ) < 0 ) {
array . pop ( ) . clear ( ) ;
coverEnd = array [ array . length - 1 ] . find ( ) ;
}
if ( cmp ( to , coverEnd . to ) > 0 ) {
if ( to . line - coverEnd . from . line < CHUNK _SIZE ) {
array . pop ( ) . clear ( ) ;
coverRange ( cm , coverEnd . from , to ) ;
} else {
coverRange ( cm , coverEnd . to , to ) ;
}
}
}
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 10 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// This is CodeMirror (http://codemirror.net), a code editor
// implemented in JavaScript on top of the browser's DOM.
//
// You can find some technical background for some of the code below
// at http://marijnhaverbeke.nl/blog/#cm-internals .
( function ( global , factory ) {
typeof exports === 'object' && typeof module !== 'undefined' ? module . exports = factory ( ) :
typeof define === 'function' && define . amd ? define ( factory ) :
( global . CodeMirror = factory ( ) ) ;
} ( this , ( function ( ) { 'use strict' ;
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
var userAgent = navigator . userAgent ;
var platform = navigator . platform ;
var gecko = /gecko\/\d/i . test ( userAgent ) ;
var ie _upto10 = /MSIE \d/ . test ( userAgent ) ;
var ie _11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/ . exec ( userAgent ) ;
var edge = /Edge\/(\d+)/ . exec ( userAgent ) ;
var ie = ie _upto10 || ie _11up || edge ;
var ie _version = ie && ( ie _upto10 ? document . documentMode || 6 : + ( edge || ie _11up ) [ 1 ] ) ;
var webkit = ! edge && /WebKit\// . test ( userAgent ) ;
var qtwebkit = webkit && /Qt\/\d+\.\d+/ . test ( userAgent ) ;
var chrome = ! edge && /Chrome\// . test ( userAgent ) ;
var presto = /Opera\// . test ( userAgent ) ;
var safari = /Apple Computer/ . test ( navigator . vendor ) ;
var mac _geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/ . test ( userAgent ) ;
var phantom = /PhantomJS/ . test ( userAgent ) ;
var ios = ! edge && /AppleWebKit/ . test ( userAgent ) && /Mobile\/\w+/ . test ( userAgent ) ;
var android = /Android/ . test ( userAgent ) ;
// This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i . test ( userAgent ) ;
var mac = ios || /Mac/ . test ( platform ) ;
var chromeOS = /\bCrOS\b/ . test ( userAgent ) ;
var windows = /win/i . test ( platform ) ;
var presto _version = presto && userAgent . match ( /Version\/(\d*\.\d*)/ ) ;
if ( presto _version ) { presto _version = Number ( presto _version [ 1 ] ) ; }
if ( presto _version && presto _version >= 15 ) { presto = false ; webkit = true ; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
var flipCtrlCmd = mac && ( qtwebkit || presto && ( presto _version == null || presto _version < 12.11 ) ) ;
var captureRightClick = gecko || ( ie && ie _version >= 9 ) ;
function classTest ( cls ) { return new RegExp ( "(^|\\s)" + cls + "(?:$|\\s)\\s*" ) }
var rmClass = function ( node , cls ) {
var current = node . className ;
var match = classTest ( cls ) . exec ( current ) ;
if ( match ) {
var after = current . slice ( match . index + match [ 0 ] . length ) ;
node . className = current . slice ( 0 , match . index ) + ( after ? match [ 1 ] + after : "" ) ;
}
} ;
function removeChildren ( e ) {
for ( var count = e . childNodes . length ; count > 0 ; -- count )
{ e . removeChild ( e . firstChild ) ; }
return e
}
function removeChildrenAndAdd ( parent , e ) {
return removeChildren ( parent ) . appendChild ( e )
}
function elt ( tag , content , className , style ) {
var e = document . createElement ( tag ) ;
if ( className ) { e . className = className ; }
if ( style ) { e . style . cssText = style ; }
if ( typeof content == "string" ) { e . appendChild ( document . createTextNode ( content ) ) ; }
else if ( content ) { for ( var i = 0 ; i < content . length ; ++ i ) { e . appendChild ( content [ i ] ) ; } }
return e
}
// wrapper for elt, which removes the elt from the accessibility tree
function eltP ( tag , content , className , style ) {
var e = elt ( tag , content , className , style ) ;
e . setAttribute ( "role" , "presentation" ) ;
return e
}
var range ;
if ( document . createRange ) { range = function ( node , start , end , endNode ) {
var r = document . createRange ( ) ;
r . setEnd ( endNode || node , end ) ;
r . setStart ( node , start ) ;
return r
} ; }
else { range = function ( node , start , end ) {
var r = document . body . createTextRange ( ) ;
try { r . moveToElementText ( node . parentNode ) ; }
catch ( e ) { return r }
r . collapse ( true ) ;
r . moveEnd ( "character" , end ) ;
r . moveStart ( "character" , start ) ;
return r
} ; }
function contains ( parent , child ) {
if ( child . nodeType == 3 ) // Android browser always returns false when child is a textnode
{ child = child . parentNode ; }
if ( parent . contains )
{ return parent . contains ( child ) }
do {
if ( child . nodeType == 11 ) { child = child . host ; }
if ( child == parent ) { return true }
} while ( child = child . parentNode )
}
function activeElt ( ) {
// IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
// IE < 10 will throw when accessed while the page is loading or in an iframe.
// IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
var activeElement ;
try {
activeElement = document . activeElement ;
} catch ( e ) {
activeElement = document . body || null ;
}
while ( activeElement && activeElement . shadowRoot && activeElement . shadowRoot . activeElement )
{ activeElement = activeElement . shadowRoot . activeElement ; }
return activeElement
}
function addClass ( node , cls ) {
var current = node . className ;
if ( ! classTest ( cls ) . test ( current ) ) { node . className += ( current ? " " : "" ) + cls ; }
}
function joinClasses ( a , b ) {
var as = a . split ( " " ) ;
for ( var i = 0 ; i < as . length ; i ++ )
{ if ( as [ i ] && ! classTest ( as [ i ] ) . test ( b ) ) { b += " " + as [ i ] ; } }
return b
}
var selectInput = function ( node ) { node . select ( ) ; } ;
if ( ios ) // Mobile Safari apparently has a bug where select() is broken.
{ selectInput = function ( node ) { node . selectionStart = 0 ; node . selectionEnd = node . value . length ; } ; }
else if ( ie ) // Suppress mysterious IE10 errors
{ selectInput = function ( node ) { try { node . select ( ) ; } catch ( _e ) { } } ; }
function bind ( f ) {
var args = Array . prototype . slice . call ( arguments , 1 ) ;
return function ( ) { return f . apply ( null , args ) }
}
function copyObj ( obj , target , overwrite ) {
if ( ! target ) { target = { } ; }
for ( var prop in obj )
{ if ( obj . hasOwnProperty ( prop ) && ( overwrite !== false || ! target . hasOwnProperty ( prop ) ) )
{ target [ prop ] = obj [ prop ] ; } }
return target
}
// Counts the column offset in a string, taking tabs into account.
// Used mostly to find indentation.
function countColumn ( string , end , tabSize , startIndex , startValue ) {
if ( end == null ) {
end = string . search ( /[^\s\u00a0]/ ) ;
if ( end == - 1 ) { end = string . length ; }
}
for ( var i = startIndex || 0 , n = startValue || 0 ; ; ) {
var nextTab = string . indexOf ( "\t" , i ) ;
if ( nextTab < 0 || nextTab >= end )
{ return n + ( end - i ) }
n += nextTab - i ;
n += tabSize - ( n % tabSize ) ;
i = nextTab + 1 ;
}
}
var Delayed = function ( ) { this . id = null ; } ;
Delayed . prototype . set = function ( ms , f ) {
clearTimeout ( this . id ) ;
this . id = setTimeout ( f , ms ) ;
} ;
function indexOf ( array , elt ) {
for ( var i = 0 ; i < array . length ; ++ i )
{ if ( array [ i ] == elt ) { return i } }
return - 1
}
// Number of pixels added to scroller and sizer to hide scrollbar
var scrollerGap = 30 ;
// Returned or thrown by various protocols to signal 'I'm not
// handling this'.
var Pass = { toString : function ( ) { return "CodeMirror.Pass" } } ;
// Reused option objects for setSelection & friends
var sel _dontScroll = { scroll : false } ;
var sel _mouse = { origin : "*mouse" } ;
var sel _move = { origin : "+move" } ;
// The inverse of countColumn -- find the offset that corresponds to
// a particular column.
function findColumn ( string , goal , tabSize ) {
for ( var pos = 0 , col = 0 ; ; ) {
var nextTab = string . indexOf ( "\t" , pos ) ;
if ( nextTab == - 1 ) { nextTab = string . length ; }
var skipped = nextTab - pos ;
if ( nextTab == string . length || col + skipped >= goal )
{ return pos + Math . min ( skipped , goal - col ) }
col += nextTab - pos ;
col += tabSize - ( col % tabSize ) ;
pos = nextTab + 1 ;
if ( col >= goal ) { return pos }
}
}
var spaceStrs = [ "" ] ;
function spaceStr ( n ) {
while ( spaceStrs . length <= n )
{ spaceStrs . push ( lst ( spaceStrs ) + " " ) ; }
return spaceStrs [ n ]
}
function lst ( arr ) { return arr [ arr . length - 1 ] }
function map ( array , f ) {
var out = [ ] ;
for ( var i = 0 ; i < array . length ; i ++ ) { out [ i ] = f ( array [ i ] , i ) ; }
return out
}
function insertSorted ( array , value , score ) {
var pos = 0 , priority = score ( value ) ;
while ( pos < array . length && score ( array [ pos ] ) <= priority ) { pos ++ ; }
array . splice ( pos , 0 , value ) ;
}
function nothing ( ) { }
function createObj ( base , props ) {
var inst ;
if ( Object . create ) {
inst = Object . create ( base ) ;
} else {
nothing . prototype = base ;
inst = new nothing ( ) ;
}
if ( props ) { copyObj ( props , inst ) ; }
return inst
}
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ ;
function isWordCharBasic ( ch ) {
return /\w/ . test ( ch ) || ch > "\x80" &&
( ch . toUpperCase ( ) != ch . toLowerCase ( ) || nonASCIISingleCaseWordChar . test ( ch ) )
}
function isWordChar ( ch , helper ) {
if ( ! helper ) { return isWordCharBasic ( ch ) }
if ( helper . source . indexOf ( "\\w" ) > - 1 && isWordCharBasic ( ch ) ) { return true }
return helper . test ( ch )
}
function isEmpty ( obj ) {
for ( var n in obj ) { if ( obj . hasOwnProperty ( n ) && obj [ n ] ) { return false } }
return true
}
// Extending unicode characters. A series of a non-extending char +
// any number of extending chars is treated as a single unit as far
// as editing and measuring is concerned. This is not fully correct,
// since some scripts/fonts/browsers also treat other configurations
// of code points as a group.
var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ ;
function isExtendingChar ( ch ) { return ch . charCodeAt ( 0 ) >= 768 && extendingChars . test ( ch ) }
// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
function skipExtendingChars ( str , pos , dir ) {
while ( ( dir < 0 ? pos > 0 : pos < str . length ) && isExtendingChar ( str . charAt ( pos ) ) ) { pos += dir ; }
return pos
}
// Returns the value from the range [`from`; `to`] that satisfies
// `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
function findFirst ( pred , from , to ) {
for ( ; ; ) {
if ( Math . abs ( from - to ) <= 1 ) { return pred ( from ) ? from : to }
var mid = Math . floor ( ( from + to ) / 2 ) ;
if ( pred ( mid ) ) { to = mid ; }
else { from = mid ; }
}
}
// The display handles the DOM integration, both for input reading
// and content drawing. It holds references to DOM nodes and
// display-related state.
function Display ( place , doc , input ) {
var d = this ;
this . input = input ;
// Covers bottom-right square when both scrollbars are present.
d . scrollbarFiller = elt ( "div" , null , "CodeMirror-scrollbar-filler" ) ;
d . scrollbarFiller . setAttribute ( "cm-not-content" , "true" ) ;
// Covers bottom of gutter when coverGutterNextToScrollbar is on
// and h scrollbar is present.
d . gutterFiller = elt ( "div" , null , "CodeMirror-gutter-filler" ) ;
d . gutterFiller . setAttribute ( "cm-not-content" , "true" ) ;
// Will contain the actual code, positioned to cover the viewport.
d . lineDiv = eltP ( "div" , null , "CodeMirror-code" ) ;
// Elements are added to these to represent selection and cursors.
d . selectionDiv = elt ( "div" , null , null , "position: relative; z-index: 1" ) ;
d . cursorDiv = elt ( "div" , null , "CodeMirror-cursors" ) ;
// A visibility: hidden element used to find the size of things.
d . measure = elt ( "div" , null , "CodeMirror-measure" ) ;
// When lines outside of the viewport are measured, they are drawn in this.
d . lineMeasure = elt ( "div" , null , "CodeMirror-measure" ) ;
// Wraps everything that needs to exist inside the vertically-padded coordinate system
d . lineSpace = eltP ( "div" , [ d . measure , d . lineMeasure , d . selectionDiv , d . cursorDiv , d . lineDiv ] ,
null , "position: relative; outline: none" ) ;
var lines = eltP ( "div" , [ d . lineSpace ] , "CodeMirror-lines" ) ;
// Moved around its parent to cover visible view.
d . mover = elt ( "div" , [ lines ] , null , "position: relative" ) ;
// Set to the height of the document, allowing scrolling.
d . sizer = elt ( "div" , [ d . mover ] , "CodeMirror-sizer" ) ;
d . sizerWidth = null ;
// Behavior of elts with overflow: auto and padding is
// inconsistent across browsers. This is used to ensure the
// scrollable area is big enough.
d . heightForcer = elt ( "div" , null , null , "position: absolute; height: " + scrollerGap + "px; width: 1px;" ) ;
// Will contain the gutters, if any.
d . gutters = elt ( "div" , null , "CodeMirror-gutters" ) ;
d . lineGutter = null ;
// Actual scrollable element.
d . scroller = elt ( "div" , [ d . sizer , d . heightForcer , d . gutters ] , "CodeMirror-scroll" ) ;
d . scroller . setAttribute ( "tabIndex" , "-1" ) ;
// The element in which the editor lives.
d . wrapper = elt ( "div" , [ d . scrollbarFiller , d . gutterFiller , d . scroller ] , "CodeMirror" ) ;
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
if ( ie && ie _version < 8 ) { d . gutters . style . zIndex = - 1 ; d . scroller . style . paddingRight = 0 ; }
if ( ! webkit && ! ( gecko && mobile ) ) { d . scroller . draggable = true ; }
if ( place ) {
if ( place . appendChild ) { place . appendChild ( d . wrapper ) ; }
else { place ( d . wrapper ) ; }
}
// Current rendered range (may be bigger than the view window).
d . viewFrom = d . viewTo = doc . first ;
d . reportedViewFrom = d . reportedViewTo = doc . first ;
// Information about the rendered lines.
d . view = [ ] ;
d . renderedView = null ;
// Holds info about a single rendered line when it was rendered
// for measurement, while not in view.
d . externalMeasured = null ;
// Empty space (in pixels) above the view
d . viewOffset = 0 ;
d . lastWrapHeight = d . lastWrapWidth = 0 ;
d . updateLineNumbers = null ;
d . nativeBarWidth = d . barHeight = d . barWidth = 0 ;
d . scrollbarsClipped = false ;
// Used to only resize the line number gutter when necessary (when
// the amount of lines crosses a boundary that makes its width change)
d . lineNumWidth = d . lineNumInnerWidth = d . lineNumChars = null ;
// Set to true when a non-horizontal-scrolling line widget is
// added. As an optimization, line widget aligning is skipped when
// this is false.
d . alignWidgets = false ;
d . cachedCharWidth = d . cachedTextHeight = d . cachedPaddingH = null ;
// Tracks the maximum line length so that the horizontal scrollbar
// can be kept static when scrolling.
d . maxLine = null ;
d . maxLineLength = 0 ;
d . maxLineChanged = false ;
// Used for measuring wheel scrolling granularity
d . wheelDX = d . wheelDY = d . wheelStartX = d . wheelStartY = null ;
// True when shift is held down.
d . shift = false ;
// Used to track whether anything happened since the context menu
// was opened.
d . selForContextMenu = null ;
d . activeTouch = null ;
input . init ( d ) ;
}
// Find the line object corresponding to the given line number.
function getLine ( doc , n ) {
n -= doc . first ;
if ( n < 0 || n >= doc . size ) { throw new Error ( "There is no line " + ( n + doc . first ) + " in the document." ) }
var chunk = doc ;
while ( ! chunk . lines ) {
for ( var i = 0 ; ; ++ i ) {
var child = chunk . children [ i ] , sz = child . chunkSize ( ) ;
if ( n < sz ) { chunk = child ; break }
n -= sz ;
}
}
return chunk . lines [ n ]
}
// Get the part of a document between two positions, as an array of
// strings.
function getBetween ( doc , start , end ) {
var out = [ ] , n = start . line ;
doc . iter ( start . line , end . line + 1 , function ( line ) {
var text = line . text ;
if ( n == end . line ) { text = text . slice ( 0 , end . ch ) ; }
if ( n == start . line ) { text = text . slice ( start . ch ) ; }
out . push ( text ) ;
++ n ;
} ) ;
return out
}
// Get the lines between from and to, as array of strings.
function getLines ( doc , from , to ) {
var out = [ ] ;
doc . iter ( from , to , function ( line ) { out . push ( line . text ) ; } ) ; // iter aborts when callback returns truthy value
return out
}
// Update the height of a line, propagating the height change
// upwards to parent nodes.
function updateLineHeight ( line , height ) {
var diff = height - line . height ;
if ( diff ) { for ( var n = line ; n ; n = n . parent ) { n . height += diff ; } }
}
// Given a line object, find its line number by walking up through
// its parent links.
function lineNo ( line ) {
if ( line . parent == null ) { return null }
var cur = line . parent , no = indexOf ( cur . lines , line ) ;
for ( var chunk = cur . parent ; chunk ; cur = chunk , chunk = chunk . parent ) {
for ( var i = 0 ; ; ++ i ) {
if ( chunk . children [ i ] == cur ) { break }
no += chunk . children [ i ] . chunkSize ( ) ;
}
}
return no + cur . first
}
// Find the line at the given vertical position, using the height
// information in the document tree.
function lineAtHeight ( chunk , h ) {
var n = chunk . first ;
outer : do {
for ( var i$1 = 0 ; i$1 < chunk . children . length ; ++ i$1 ) {
var child = chunk . children [ i$1 ] , ch = child . height ;
if ( h < ch ) { chunk = child ; continue outer }
h -= ch ;
n += child . chunkSize ( ) ;
}
return n
} while ( ! chunk . lines )
var i = 0 ;
for ( ; i < chunk . lines . length ; ++ i ) {
var line = chunk . lines [ i ] , lh = line . height ;
if ( h < lh ) { break }
h -= lh ;
}
return n + i
}
function isLine ( doc , l ) { return l >= doc . first && l < doc . first + doc . size }
function lineNumberFor ( options , i ) {
return String ( options . lineNumberFormatter ( i + options . firstLineNumber ) )
}
// A Pos instance represents a position within the text.
function Pos ( line , ch , sticky ) {
if ( sticky === void 0 ) sticky = null ;
if ( ! ( this instanceof Pos ) ) { return new Pos ( line , ch , sticky ) }
this . line = line ;
this . ch = ch ;
this . sticky = sticky ;
}
// Compare two positions, return 0 if they are the same, a negative
// number when a is less, and a positive number otherwise.
function cmp ( a , b ) { return a . line - b . line || a . ch - b . ch }
function equalCursorPos ( a , b ) { return a . sticky == b . sticky && cmp ( a , b ) == 0 }
function copyPos ( x ) { return Pos ( x . line , x . ch ) }
function maxPos ( a , b ) { return cmp ( a , b ) < 0 ? b : a }
function minPos ( a , b ) { return cmp ( a , b ) < 0 ? a : b }
// Most of the external API clips given positions to make sure they
// actually exist within the document.
function clipLine ( doc , n ) { return Math . max ( doc . first , Math . min ( n , doc . first + doc . size - 1 ) ) }
function clipPos ( doc , pos ) {
if ( pos . line < doc . first ) { return Pos ( doc . first , 0 ) }
var last = doc . first + doc . size - 1 ;
if ( pos . line > last ) { return Pos ( last , getLine ( doc , last ) . text . length ) }
return clipToLen ( pos , getLine ( doc , pos . line ) . text . length )
}
function clipToLen ( pos , linelen ) {
var ch = pos . ch ;
if ( ch == null || ch > linelen ) { return Pos ( pos . line , linelen ) }
else if ( ch < 0 ) { return Pos ( pos . line , 0 ) }
else { return pos }
}
function clipPosArray ( doc , array ) {
var out = [ ] ;
for ( var i = 0 ; i < array . length ; i ++ ) { out [ i ] = clipPos ( doc , array [ i ] ) ; }
return out
}
// Optimize some code when these features are not used.
var sawReadOnlySpans = false ;
var sawCollapsedSpans = false ;
function seeReadOnlySpans ( ) {
sawReadOnlySpans = true ;
}
function seeCollapsedSpans ( ) {
sawCollapsedSpans = true ;
}
// TEXTMARKER SPANS
function MarkedSpan ( marker , from , to ) {
this . marker = marker ;
this . from = from ; this . to = to ;
}
// Search an array of spans for a span matching the given marker.
function getMarkedSpanFor ( spans , marker ) {
if ( spans ) { for ( var i = 0 ; i < spans . length ; ++ i ) {
var span = spans [ i ] ;
if ( span . marker == marker ) { return span }
} }
}
// Remove a span from an array, returning undefined if no spans are
// left (we don't store arrays for lines without spans).
function removeMarkedSpan ( spans , span ) {
var r ;
for ( var i = 0 ; i < spans . length ; ++ i )
{ if ( spans [ i ] != span ) { ( r || ( r = [ ] ) ) . push ( spans [ i ] ) ; } }
return r
}
// Add a span to a line.
function addMarkedSpan ( line , span ) {
line . markedSpans = line . markedSpans ? line . markedSpans . concat ( [ span ] ) : [ span ] ;
span . marker . attachLine ( line ) ;
}
// Used for the algorithm that adjusts markers for a change in the
// document. These functions cut an array of spans at a given
// character position, returning an array of remaining chunks (or
// undefined if nothing remains).
function markedSpansBefore ( old , startCh , isInsert ) {
var nw ;
if ( old ) { for ( var i = 0 ; i < old . length ; ++ i ) {
var span = old [ i ] , marker = span . marker ;
var startsBefore = span . from == null || ( marker . inclusiveLeft ? span . from <= startCh : span . from < startCh ) ;
if ( startsBefore || span . from == startCh && marker . type == "bookmark" && ( ! isInsert || ! span . marker . insertLeft ) ) {
var endsAfter = span . to == null || ( marker . inclusiveRight ? span . to >= startCh : span . to > startCh ) ; ( nw || ( nw = [ ] ) ) . push ( new MarkedSpan ( marker , span . from , endsAfter ? null : span . to ) ) ;
}
} }
return nw
}
function markedSpansAfter ( old , endCh , isInsert ) {
var nw ;
if ( old ) { for ( var i = 0 ; i < old . length ; ++ i ) {
var span = old [ i ] , marker = span . marker ;
var endsAfter = span . to == null || ( marker . inclusiveRight ? span . to >= endCh : span . to > endCh ) ;
if ( endsAfter || span . from == endCh && marker . type == "bookmark" && ( ! isInsert || span . marker . insertLeft ) ) {
var startsBefore = span . from == null || ( marker . inclusiveLeft ? span . from <= endCh : span . from < endCh ) ; ( nw || ( nw = [ ] ) ) . push ( new MarkedSpan ( marker , startsBefore ? null : span . from - endCh ,
span . to == null ? null : span . to - endCh ) ) ;
}
} }
return nw
}
// Given a change object, compute the new set of marker spans that
// cover the line in which the change took place. Removes spans
// entirely within the change, reconnects spans belonging to the
// same marker that appear on both sides of the change, and cuts off
// spans partially within the change. Returns an array of span
// arrays with one element for each line in (after) the change.
function stretchSpansOverChange ( doc , change ) {
if ( change . full ) { return null }
var oldFirst = isLine ( doc , change . from . line ) && getLine ( doc , change . from . line ) . markedSpans ;
var oldLast = isLine ( doc , change . to . line ) && getLine ( doc , change . to . line ) . markedSpans ;
if ( ! oldFirst && ! oldLast ) { return null }
var startCh = change . from . ch , endCh = change . to . ch , isInsert = cmp ( change . from , change . to ) == 0 ;
// Get the spans that 'stick out' on both sides
var first = markedSpansBefore ( oldFirst , startCh , isInsert ) ;
var last = markedSpansAfter ( oldLast , endCh , isInsert ) ;
// Next, merge those two ends
var sameLine = change . text . length == 1 , offset = lst ( change . text ) . length + ( sameLine ? startCh : 0 ) ;
if ( first ) {
// Fix up .to properties of first
for ( var i = 0 ; i < first . length ; ++ i ) {
var span = first [ i ] ;
if ( span . to == null ) {
var found = getMarkedSpanFor ( last , span . marker ) ;
if ( ! found ) { span . to = startCh ; }
else if ( sameLine ) { span . to = found . to == null ? null : found . to + offset ; }
}
}
}
if ( last ) {
// Fix up .from in last (or move them into first in case of sameLine)
for ( var i$1 = 0 ; i$1 < last . length ; ++ i$1 ) {
var span$1 = last [ i$1 ] ;
if ( span$1 . to != null ) { span$1 . to += offset ; }
if ( span$1 . from == null ) {
var found$1 = getMarkedSpanFor ( first , span$1 . marker ) ;
if ( ! found$1 ) {
span$1 . from = offset ;
if ( sameLine ) { ( first || ( first = [ ] ) ) . push ( span$1 ) ; }
}
} else {
span$1 . from += offset ;
if ( sameLine ) { ( first || ( first = [ ] ) ) . push ( span$1 ) ; }
}
}
}
// Make sure we didn't create any zero-length spans
if ( first ) { first = clearEmptySpans ( first ) ; }
if ( last && last != first ) { last = clearEmptySpans ( last ) ; }
var newMarkers = [ first ] ;
if ( ! sameLine ) {
// Fill gap with whole-line-spans
var gap = change . text . length - 2 , gapMarkers ;
if ( gap > 0 && first )
{ for ( var i$2 = 0 ; i$2 < first . length ; ++ i$2 )
{ if ( first [ i$2 ] . to == null )
{ ( gapMarkers || ( gapMarkers = [ ] ) ) . push ( new MarkedSpan ( first [ i$2 ] . marker , null , null ) ) ; } } }
for ( var i$3 = 0 ; i$3 < gap ; ++ i$3 )
{ newMarkers . push ( gapMarkers ) ; }
newMarkers . push ( last ) ;
}
return newMarkers
}
// Remove spans that are empty and don't have a clearWhenEmpty
// option of false.
function clearEmptySpans ( spans ) {
for ( var i = 0 ; i < spans . length ; ++ i ) {
var span = spans [ i ] ;
if ( span . from != null && span . from == span . to && span . marker . clearWhenEmpty !== false )
{ spans . splice ( i -- , 1 ) ; }
}
if ( ! spans . length ) { return null }
return spans
}
// Used to 'clip' out readOnly ranges when making a change.
function removeReadOnlyRanges ( doc , from , to ) {
var markers = null ;
doc . iter ( from . line , to . line + 1 , function ( line ) {
if ( line . markedSpans ) { for ( var i = 0 ; i < line . markedSpans . length ; ++ i ) {
var mark = line . markedSpans [ i ] . marker ;
if ( mark . readOnly && ( ! markers || indexOf ( markers , mark ) == - 1 ) )
{ ( markers || ( markers = [ ] ) ) . push ( mark ) ; }
} }
} ) ;
if ( ! markers ) { return null }
var parts = [ { from : from , to : to } ] ;
for ( var i = 0 ; i < markers . length ; ++ i ) {
var mk = markers [ i ] , m = mk . find ( 0 ) ;
for ( var j = 0 ; j < parts . length ; ++ j ) {
var p = parts [ j ] ;
if ( cmp ( p . to , m . from ) < 0 || cmp ( p . from , m . to ) > 0 ) { continue }
var newParts = [ j , 1 ] , dfrom = cmp ( p . from , m . from ) , dto = cmp ( p . to , m . to ) ;
if ( dfrom < 0 || ! mk . inclusiveLeft && ! dfrom )
{ newParts . push ( { from : p . from , to : m . from } ) ; }
if ( dto > 0 || ! mk . inclusiveRight && ! dto )
{ newParts . push ( { from : m . to , to : p . to } ) ; }
parts . splice . apply ( parts , newParts ) ;
j += newParts . length - 3 ;
}
}
return parts
}
// Connect or disconnect spans from a line.
function detachMarkedSpans ( line ) {
var spans = line . markedSpans ;
if ( ! spans ) { return }
for ( var i = 0 ; i < spans . length ; ++ i )
{ spans [ i ] . marker . detachLine ( line ) ; }
line . markedSpans = null ;
}
function attachMarkedSpans ( line , spans ) {
if ( ! spans ) { return }
for ( var i = 0 ; i < spans . length ; ++ i )
{ spans [ i ] . marker . attachLine ( line ) ; }
line . markedSpans = spans ;
}
// Helpers used when computing which overlapping collapsed span
// counts as the larger one.
function extraLeft ( marker ) { return marker . inclusiveLeft ? - 1 : 0 }
function extraRight ( marker ) { return marker . inclusiveRight ? 1 : 0 }
// Returns a number indicating which of two overlapping collapsed
// spans is larger (and thus includes the other). Falls back to
// comparing ids when the spans cover exactly the same range.
function compareCollapsedMarkers ( a , b ) {
var lenDiff = a . lines . length - b . lines . length ;
if ( lenDiff != 0 ) { return lenDiff }
var aPos = a . find ( ) , bPos = b . find ( ) ;
var fromCmp = cmp ( aPos . from , bPos . from ) || extraLeft ( a ) - extraLeft ( b ) ;
if ( fromCmp ) { return - fromCmp }
var toCmp = cmp ( aPos . to , bPos . to ) || extraRight ( a ) - extraRight ( b ) ;
if ( toCmp ) { return toCmp }
return b . id - a . id
}
// Find out whether a line ends or starts in a collapsed span. If
// so, return the marker for that span.
function collapsedSpanAtSide ( line , start ) {
var sps = sawCollapsedSpans && line . markedSpans , found ;
if ( sps ) { for ( var sp = ( void 0 ) , i = 0 ; i < sps . length ; ++ i ) {
sp = sps [ i ] ;
if ( sp . marker . collapsed && ( start ? sp . from : sp . to ) == null &&
( ! found || compareCollapsedMarkers ( found , sp . marker ) < 0 ) )
{ found = sp . marker ; }
} }
return found
}
function collapsedSpanAtStart ( line ) { return collapsedSpanAtSide ( line , true ) }
function collapsedSpanAtEnd ( line ) { return collapsedSpanAtSide ( line , false ) }
// Test whether there exists a collapsed span that partially
// overlaps (covers the start or end, but not both) of a new span.
// Such overlap is not allowed.
function conflictingCollapsedRange ( doc , lineNo$$1 , from , to , marker ) {
var line = getLine ( doc , lineNo$$1 ) ;
var sps = sawCollapsedSpans && line . markedSpans ;
if ( sps ) { for ( var i = 0 ; i < sps . length ; ++ i ) {
var sp = sps [ i ] ;
if ( ! sp . marker . collapsed ) { continue }
var found = sp . marker . find ( 0 ) ;
var fromCmp = cmp ( found . from , from ) || extraLeft ( sp . marker ) - extraLeft ( marker ) ;
var toCmp = cmp ( found . to , to ) || extraRight ( sp . marker ) - extraRight ( marker ) ;
if ( fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0 ) { continue }
if ( fromCmp <= 0 && ( sp . marker . inclusiveRight && marker . inclusiveLeft ? cmp ( found . to , from ) >= 0 : cmp ( found . to , from ) > 0 ) ||
fromCmp >= 0 && ( sp . marker . inclusiveRight && marker . inclusiveLeft ? cmp ( found . from , to ) <= 0 : cmp ( found . from , to ) < 0 ) )
{ return true }
} }
}
// A visual line is a line as drawn on the screen. Folding, for
// example, can cause multiple logical lines to appear on the same
// visual line. This finds the start of the visual line that the
// given line is part of (usually that is the line itself).
function visualLine ( line ) {
var merged ;
while ( merged = collapsedSpanAtStart ( line ) )
{ line = merged . find ( - 1 , true ) . line ; }
return line
}
function visualLineEnd ( line ) {
var merged ;
while ( merged = collapsedSpanAtEnd ( line ) )
{ line = merged . find ( 1 , true ) . line ; }
return line
}
// Returns an array of logical lines that continue the visual line
// started by the argument, or undefined if there are no such lines.
function visualLineContinued ( line ) {
var merged , lines ;
while ( merged = collapsedSpanAtEnd ( line ) ) {
line = merged . find ( 1 , true ) . line
; ( lines || ( lines = [ ] ) ) . push ( line ) ;
}
return lines
}
// Get the line number of the start of the visual line that the
// given line number is part of.
function visualLineNo ( doc , lineN ) {
var line = getLine ( doc , lineN ) , vis = visualLine ( line ) ;
if ( line == vis ) { return lineN }
return lineNo ( vis )
}
// Get the line number of the start of the next visual line after
// the given line.
function visualLineEndNo ( doc , lineN ) {
if ( lineN > doc . lastLine ( ) ) { return lineN }
var line = getLine ( doc , lineN ) , merged ;
if ( ! lineIsHidden ( doc , line ) ) { return lineN }
while ( merged = collapsedSpanAtEnd ( line ) )
{ line = merged . find ( 1 , true ) . line ; }
return lineNo ( line ) + 1
}
// Compute whether a line is hidden. Lines count as hidden when they
// are part of a visual line that starts with another line, or when
// they are entirely covered by collapsed, non-widget span.
function lineIsHidden ( doc , line ) {
var sps = sawCollapsedSpans && line . markedSpans ;
if ( sps ) { for ( var sp = ( void 0 ) , i = 0 ; i < sps . length ; ++ i ) {
sp = sps [ i ] ;
if ( ! sp . marker . collapsed ) { continue }
if ( sp . from == null ) { return true }
if ( sp . marker . widgetNode ) { continue }
if ( sp . from == 0 && sp . marker . inclusiveLeft && lineIsHiddenInner ( doc , line , sp ) )
{ return true }
} }
}
function lineIsHiddenInner ( doc , line , span ) {
if ( span . to == null ) {
var end = span . marker . find ( 1 , true ) ;
return lineIsHiddenInner ( doc , end . line , getMarkedSpanFor ( end . line . markedSpans , span . marker ) )
}
if ( span . marker . inclusiveRight && span . to == line . text . length )
{ return true }
for ( var sp = ( void 0 ) , i = 0 ; i < line . markedSpans . length ; ++ i ) {
sp = line . markedSpans [ i ] ;
if ( sp . marker . collapsed && ! sp . marker . widgetNode && sp . from == span . to &&
( sp . to == null || sp . to != span . from ) &&
( sp . marker . inclusiveLeft || span . marker . inclusiveRight ) &&
lineIsHiddenInner ( doc , line , sp ) ) { return true }
}
}
// Find the height above the given line.
function heightAtLine ( lineObj ) {
lineObj = visualLine ( lineObj ) ;
var h = 0 , chunk = lineObj . parent ;
for ( var i = 0 ; i < chunk . lines . length ; ++ i ) {
var line = chunk . lines [ i ] ;
if ( line == lineObj ) { break }
else { h += line . height ; }
}
for ( var p = chunk . parent ; p ; chunk = p , p = chunk . parent ) {
for ( var i$1 = 0 ; i$1 < p . children . length ; ++ i$1 ) {
var cur = p . children [ i$1 ] ;
if ( cur == chunk ) { break }
else { h += cur . height ; }
}
}
return h
}
// Compute the character length of a line, taking into account
// collapsed ranges (see markText) that might hide parts, and join
// other lines onto it.
function lineLength ( line ) {
if ( line . height == 0 ) { return 0 }
var len = line . text . length , merged , cur = line ;
while ( merged = collapsedSpanAtStart ( cur ) ) {
var found = merged . find ( 0 , true ) ;
cur = found . from . line ;
len += found . from . ch - found . to . ch ;
}
cur = line ;
while ( merged = collapsedSpanAtEnd ( cur ) ) {
var found$1 = merged . find ( 0 , true ) ;
len -= cur . text . length - found$1 . from . ch ;
cur = found$1 . to . line ;
len += cur . text . length - found$1 . to . ch ;
}
return len
}
// Find the longest line in the document.
function findMaxLine ( cm ) {
var d = cm . display , doc = cm . doc ;
d . maxLine = getLine ( doc , doc . first ) ;
d . maxLineLength = lineLength ( d . maxLine ) ;
d . maxLineChanged = true ;
doc . iter ( function ( line ) {
var len = lineLength ( line ) ;
if ( len > d . maxLineLength ) {
d . maxLineLength = len ;
d . maxLine = line ;
}
} ) ;
}
// BIDI HELPERS
function iterateBidiSections ( order , from , to , f ) {
if ( ! order ) { return f ( from , to , "ltr" ) }
var found = false ;
for ( var i = 0 ; i < order . length ; ++ i ) {
var part = order [ i ] ;
if ( part . from < to && part . to > from || from == to && part . to == from ) {
f ( Math . max ( part . from , from ) , Math . min ( part . to , to ) , part . level == 1 ? "rtl" : "ltr" ) ;
found = true ;
}
}
if ( ! found ) { f ( from , to , "ltr" ) ; }
}
var bidiOther = null ;
function getBidiPartAt ( order , ch , sticky ) {
var found ;
bidiOther = null ;
for ( var i = 0 ; i < order . length ; ++ i ) {
var cur = order [ i ] ;
if ( cur . from < ch && cur . to > ch ) { return i }
if ( cur . to == ch ) {
if ( cur . from != cur . to && sticky == "before" ) { found = i ; }
else { bidiOther = i ; }
}
if ( cur . from == ch ) {
if ( cur . from != cur . to && sticky != "before" ) { found = i ; }
else { bidiOther = i ; }
}
}
return found != null ? found : bidiOther
}
// Bidirectional ordering algorithm
// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
// that this (partially) implements.
// One-char codes used for character types:
// L (L): Left-to-Right
// R (R): Right-to-Left
// r (AL): Right-to-Left Arabic
// 1 (EN): European Number
// + (ES): European Number Separator
// % (ET): European Number Terminator
// n (AN): Arabic Number
// , (CS): Common Number Separator
// m (NSM): Non-Spacing Mark
// b (BN): Boundary Neutral
// s (B): Paragraph Separator
// t (S): Segment Separator
// w (WS): Whitespace
// N (ON): Other Neutrals
// Returns null if characters are ordered as they appear
// (left-to-right), or an array of sections ({from, to, level}
// objects) in the order in which they occur visually.
var bidiOrdering = ( function ( ) {
// Character types for codepoints 0 to 0xff
var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" ;
// Character types for codepoints 0x600 to 0x6f9
var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111" ;
function charType ( code ) {
if ( code <= 0xf7 ) { return lowTypes . charAt ( code ) }
else if ( 0x590 <= code && code <= 0x5f4 ) { return "R" }
else if ( 0x600 <= code && code <= 0x6f9 ) { return arabicTypes . charAt ( code - 0x600 ) }
else if ( 0x6ee <= code && code <= 0x8ac ) { return "r" }
else if ( 0x2000 <= code && code <= 0x200b ) { return "w" }
else if ( code == 0x200c ) { return "b" }
else { return "L" }
}
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ ;
var isNeutral = /[stwN]/ , isStrong = /[LRr]/ , countsAsLeft = /[Lb1n]/ , countsAsNum = /[1n]/ ;
function BidiSpan ( level , from , to ) {
this . level = level ;
this . from = from ; this . to = to ;
}
return function ( str , direction ) {
var outerType = direction == "ltr" ? "L" : "R" ;
if ( str . length == 0 || direction == "ltr" && ! bidiRE . test ( str ) ) { return false }
var len = str . length , types = [ ] ;
for ( var i = 0 ; i < len ; ++ i )
{ types . push ( charType ( str . charCodeAt ( i ) ) ) ; }
// W1. Examine each non-spacing mark (NSM) in the level run, and
// change the type of the NSM to the type of the previous
// character. If the NSM is at the start of the level run, it will
// get the type of sor.
for ( var i$1 = 0 , prev = outerType ; i$1 < len ; ++ i$1 ) {
var type = types [ i$1 ] ;
if ( type == "m" ) { types [ i$1 ] = prev ; }
else { prev = type ; }
}
// W2. Search backwards from each instance of a European number
// until the first strong type (R, L, AL, or sor) is found. If an
// AL is found, change the type of the European number to Arabic
// number.
// W3. Change all ALs to R.
for ( var i$2 = 0 , cur = outerType ; i$2 < len ; ++ i$2 ) {
var type$1 = types [ i$2 ] ;
if ( type$1 == "1" && cur == "r" ) { types [ i$2 ] = "n" ; }
else if ( isStrong . test ( type$1 ) ) { cur = type$1 ; if ( type$1 == "r" ) { types [ i$2 ] = "R" ; } }
}
// W4. A single European separator between two European numbers
// changes to a European number. A single common separator between
// two numbers of the same type changes to that type.
for ( var i$3 = 1 , prev$1 = types [ 0 ] ; i$3 < len - 1 ; ++ i$3 ) {
var type$2 = types [ i$3 ] ;
if ( type$2 == "+" && prev$1 == "1" && types [ i$3 + 1 ] == "1" ) { types [ i$3 ] = "1" ; }
else if ( type$2 == "," && prev$1 == types [ i$3 + 1 ] &&
( prev$1 == "1" || prev$1 == "n" ) ) { types [ i$3 ] = prev$1 ; }
prev$1 = type$2 ;
}
// W5. A sequence of European terminators adjacent to European
// numbers changes to all European numbers.
// W6. Otherwise, separators and terminators change to Other
// Neutral.
for ( var i$4 = 0 ; i$4 < len ; ++ i$4 ) {
var type$3 = types [ i$4 ] ;
if ( type$3 == "," ) { types [ i$4 ] = "N" ; }
else if ( type$3 == "%" ) {
var end = ( void 0 ) ;
for ( end = i$4 + 1 ; end < len && types [ end ] == "%" ; ++ end ) { }
var replace = ( i$4 && types [ i$4 - 1 ] == "!" ) || ( end < len && types [ end ] == "1" ) ? "1" : "N" ;
for ( var j = i$4 ; j < end ; ++ j ) { types [ j ] = replace ; }
i$4 = end - 1 ;
}
}
// W7. Search backwards from each instance of a European number
// until the first strong type (R, L, or sor) is found. If an L is
// found, then change the type of the European number to L.
for ( var i$5 = 0 , cur$1 = outerType ; i$5 < len ; ++ i$5 ) {
var type$4 = types [ i$5 ] ;
if ( cur$1 == "L" && type$4 == "1" ) { types [ i$5 ] = "L" ; }
else if ( isStrong . test ( type$4 ) ) { cur$1 = type$4 ; }
}
// N1. A sequence of neutrals takes the direction of the
// surrounding strong text if the text on both sides has the same
// direction. European and Arabic numbers act as if they were R in
// terms of their influence on neutrals. Start-of-level-run (sor)
// and end-of-level-run (eor) are used at level run boundaries.
// N2. Any remaining neutrals take the embedding direction.
for ( var i$6 = 0 ; i$6 < len ; ++ i$6 ) {
if ( isNeutral . test ( types [ i$6 ] ) ) {
var end$1 = ( void 0 ) ;
for ( end$1 = i$6 + 1 ; end$1 < len && isNeutral . test ( types [ end$1 ] ) ; ++ end$1 ) { }
var before = ( i$6 ? types [ i$6 - 1 ] : outerType ) == "L" ;
var after = ( end$1 < len ? types [ end$1 ] : outerType ) == "L" ;
var replace$1 = before == after ? ( before ? "L" : "R" ) : outerType ;
for ( var j$1 = i$6 ; j$1 < end$1 ; ++ j$1 ) { types [ j$1 ] = replace$1 ; }
i$6 = end$1 - 1 ;
}
}
// Here we depart from the documented algorithm, in order to avoid
// building up an actual levels array. Since there are only three
// levels (0, 1, 2) in an implementation that doesn't take
// explicit embedding into account, we can build up the order on
// the fly, without following the level-based algorithm.
var order = [ ] , m ;
for ( var i$7 = 0 ; i$7 < len ; ) {
if ( countsAsLeft . test ( types [ i$7 ] ) ) {
var start = i$7 ;
for ( ++ i$7 ; i$7 < len && countsAsLeft . test ( types [ i$7 ] ) ; ++ i$7 ) { }
order . push ( new BidiSpan ( 0 , start , i$7 ) ) ;
} else {
var pos = i$7 , at = order . length ;
for ( ++ i$7 ; i$7 < len && types [ i$7 ] != "L" ; ++ i$7 ) { }
for ( var j$2 = pos ; j$2 < i$7 ; ) {
if ( countsAsNum . test ( types [ j$2 ] ) ) {
if ( pos < j$2 ) { order . splice ( at , 0 , new BidiSpan ( 1 , pos , j$2 ) ) ; }
var nstart = j$2 ;
for ( ++ j$2 ; j$2 < i$7 && countsAsNum . test ( types [ j$2 ] ) ; ++ j$2 ) { }
order . splice ( at , 0 , new BidiSpan ( 2 , nstart , j$2 ) ) ;
pos = j$2 ;
} else { ++ j$2 ; }
}
if ( pos < i$7 ) { order . splice ( at , 0 , new BidiSpan ( 1 , pos , i$7 ) ) ; }
}
}
if ( order [ 0 ] . level == 1 && ( m = str . match ( /^\s+/ ) ) ) {
order [ 0 ] . from = m [ 0 ] . length ;
order . unshift ( new BidiSpan ( 0 , 0 , m [ 0 ] . length ) ) ;
}
if ( lst ( order ) . level == 1 && ( m = str . match ( /\s+$/ ) ) ) {
lst ( order ) . to -= m [ 0 ] . length ;
order . push ( new BidiSpan ( 0 , len - m [ 0 ] . length , len ) ) ;
}
return direction == "rtl" ? order . reverse ( ) : order
}
} ) ( ) ;
// Get the bidi ordering for the given line (and cache it). Returns
// false for lines that are fully left-to-right, and an array of
// BidiSpan objects otherwise.
function getOrder ( line , direction ) {
var order = line . order ;
if ( order == null ) { order = line . order = bidiOrdering ( line . text , direction ) ; }
return order
}
function moveCharLogically ( line , ch , dir ) {
var target = skipExtendingChars ( line . text , ch + dir , dir ) ;
return target < 0 || target > line . text . length ? null : target
}
function moveLogically ( line , start , dir ) {
var ch = moveCharLogically ( line , start . ch , dir ) ;
return ch == null ? null : new Pos ( start . line , ch , dir < 0 ? "after" : "before" )
}
function endOfLine ( visually , cm , lineObj , lineNo , dir ) {
if ( visually ) {
var order = getOrder ( lineObj , cm . doc . direction ) ;
if ( order ) {
var part = dir < 0 ? lst ( order ) : order [ 0 ] ;
var moveInStorageOrder = ( dir < 0 ) == ( part . level == 1 ) ;
var sticky = moveInStorageOrder ? "after" : "before" ;
var ch ;
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if ( part . level > 0 ) {
var prep = prepareMeasureForLine ( cm , lineObj ) ;
ch = dir < 0 ? lineObj . text . length - 1 : 0 ;
var targetTop = measureCharPrepared ( cm , prep , ch ) . top ;
ch = findFirst ( function ( ch ) { return measureCharPrepared ( cm , prep , ch ) . top == targetTop ; } , ( dir < 0 ) == ( part . level == 1 ) ? part . from : part . to - 1 , ch ) ;
if ( sticky == "before" ) { ch = moveCharLogically ( lineObj , ch , 1 ) ; }
} else { ch = dir < 0 ? part . to : part . from ; }
return new Pos ( lineNo , ch , sticky )
}
}
return new Pos ( lineNo , dir < 0 ? lineObj . text . length : 0 , dir < 0 ? "before" : "after" )
}
function moveVisually ( cm , line , start , dir ) {
var bidi = getOrder ( line , cm . doc . direction ) ;
if ( ! bidi ) { return moveLogically ( line , start , dir ) }
if ( start . ch >= line . text . length ) {
start . ch = line . text . length ;
start . sticky = "before" ;
} else if ( start . ch <= 0 ) {
start . ch = 0 ;
start . sticky = "after" ;
}
var partPos = getBidiPartAt ( bidi , start . ch , start . sticky ) , part = bidi [ partPos ] ;
if ( cm . doc . direction == "ltr" && part . level % 2 == 0 && ( dir > 0 ? part . to > start . ch : part . from < start . ch ) ) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically ( line , start , dir )
}
var mv = function ( pos , dir ) { return moveCharLogically ( line , pos instanceof Pos ? pos . ch : pos , dir ) ; } ;
var prep ;
var getWrappedLineExtent = function ( ch ) {
if ( ! cm . options . lineWrapping ) { return { begin : 0 , end : line . text . length } }
prep = prep || prepareMeasureForLine ( cm , line ) ;
return wrappedLineExtentChar ( cm , line , prep , ch )
} ;
var wrappedLineExtent = getWrappedLineExtent ( start . sticky == "before" ? mv ( start , - 1 ) : start . ch ) ;
if ( cm . doc . direction == "rtl" || part . level == 1 ) {
var moveInStorageOrder = ( part . level == 1 ) == ( dir < 0 ) ;
var ch = mv ( start , moveInStorageOrder ? 1 : - 1 ) ;
if ( ch != null && ( ! moveInStorageOrder ? ch >= part . from && ch >= wrappedLineExtent . begin : ch <= part . to && ch <= wrappedLineExtent . end ) ) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after" ;
return new Pos ( start . line , ch , sticky )
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function ( partPos , dir , wrappedLineExtent ) {
var getRes = function ( ch , moveInStorageOrder ) { return moveInStorageOrder
? new Pos ( start . line , mv ( ch , 1 ) , "before" )
: new Pos ( start . line , ch , "after" ) ; } ;
for ( ; partPos >= 0 && partPos < bidi . length ; partPos += dir ) {
var part = bidi [ partPos ] ;
var moveInStorageOrder = ( dir > 0 ) == ( part . level != 1 ) ;
var ch = moveInStorageOrder ? wrappedLineExtent . begin : mv ( wrappedLineExtent . end , - 1 ) ;
if ( part . from <= ch && ch < part . to ) { return getRes ( ch , moveInStorageOrder ) }
ch = moveInStorageOrder ? part . from : mv ( part . to , - 1 ) ;
if ( wrappedLineExtent . begin <= ch && ch < wrappedLineExtent . end ) { return getRes ( ch , moveInStorageOrder ) }
}
} ;
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine ( partPos + dir , dir , wrappedLineExtent ) ;
if ( res ) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent . end : mv ( wrappedLineExtent . begin , - 1 ) ;
if ( nextCh != null && ! ( dir > 0 && nextCh == line . text . length ) ) {
res = searchInVisualLine ( dir > 0 ? 0 : bidi . length - 1 , dir , getWrappedLineExtent ( nextCh ) ) ;
if ( res ) { return res }
}
// Case 4: Nowhere to move
return null
}
// EVENT HANDLING
// Lightweight event framework. on/off also work on DOM nodes,
// registering native DOM handlers.
var noHandlers = [ ] ;
var on = function ( emitter , type , f ) {
if ( emitter . addEventListener ) {
emitter . addEventListener ( type , f , false ) ;
} else if ( emitter . attachEvent ) {
emitter . attachEvent ( "on" + type , f ) ;
} else {
var map$$1 = emitter . _handlers || ( emitter . _handlers = { } ) ;
map$$1 [ type ] = ( map$$1 [ type ] || noHandlers ) . concat ( f ) ;
}
} ;
function getHandlers ( emitter , type ) {
return emitter . _handlers && emitter . _handlers [ type ] || noHandlers
}
function off ( emitter , type , f ) {
if ( emitter . removeEventListener ) {
emitter . removeEventListener ( type , f , false ) ;
} else if ( emitter . detachEvent ) {
emitter . detachEvent ( "on" + type , f ) ;
} else {
var map$$1 = emitter . _handlers , arr = map$$1 && map$$1 [ type ] ;
if ( arr ) {
var index = indexOf ( arr , f ) ;
if ( index > - 1 )
{ map$$1 [ type ] = arr . slice ( 0 , index ) . concat ( arr . slice ( index + 1 ) ) ; }
}
}
}
function signal ( emitter , type /*, values...*/ ) {
var handlers = getHandlers ( emitter , type ) ;
if ( ! handlers . length ) { return }
var args = Array . prototype . slice . call ( arguments , 2 ) ;
for ( var i = 0 ; i < handlers . length ; ++ i ) { handlers [ i ] . apply ( null , args ) ; }
}
// The DOM events that CodeMirror handles can be overridden by
// registering a (non-DOM) handler on the editor for the event name,
// and preventDefault-ing the event in that handler.
function signalDOMEvent ( cm , e , override ) {
if ( typeof e == "string" )
{ e = { type : e , preventDefault : function ( ) { this . defaultPrevented = true ; } } ; }
signal ( cm , override || e . type , cm , e ) ;
return e _defaultPrevented ( e ) || e . codemirrorIgnore
}
function signalCursorActivity ( cm ) {
var arr = cm . _handlers && cm . _handlers . cursorActivity ;
if ( ! arr ) { return }
var set = cm . curOp . cursorActivityHandlers || ( cm . curOp . cursorActivityHandlers = [ ] ) ;
for ( var i = 0 ; i < arr . length ; ++ i ) { if ( indexOf ( set , arr [ i ] ) == - 1 )
{ set . push ( arr [ i ] ) ; } }
}
function hasHandler ( emitter , type ) {
return getHandlers ( emitter , type ) . length > 0
}
// Add on and off methods to a constructor's prototype, to make
// registering events on such objects more convenient.
function eventMixin ( ctor ) {
ctor . prototype . on = function ( type , f ) { on ( this , type , f ) ; } ;
ctor . prototype . off = function ( type , f ) { off ( this , type , f ) ; } ;
}
// Due to the fact that we still support jurassic IE versions, some
// compatibility wrappers are needed.
function e _preventDefault ( e ) {
if ( e . preventDefault ) { e . preventDefault ( ) ; }
else { e . returnValue = false ; }
}
function e _stopPropagation ( e ) {
if ( e . stopPropagation ) { e . stopPropagation ( ) ; }
else { e . cancelBubble = true ; }
}
function e _defaultPrevented ( e ) {
return e . defaultPrevented != null ? e . defaultPrevented : e . returnValue == false
}
function e _stop ( e ) { e _preventDefault ( e ) ; e _stopPropagation ( e ) ; }
function e _target ( e ) { return e . target || e . srcElement }
function e _button ( e ) {
var b = e . which ;
if ( b == null ) {
if ( e . button & 1 ) { b = 1 ; }
else if ( e . button & 2 ) { b = 3 ; }
else if ( e . button & 4 ) { b = 2 ; }
}
if ( mac && e . ctrlKey && b == 1 ) { b = 3 ; }
return b
}
// Detect drag-and-drop
var dragAndDrop = function ( ) {
// There is *some* kind of drag-and-drop support in IE6-8, but I
// couldn't get it to work yet.
if ( ie && ie _version < 9 ) { return false }
var div = elt ( 'div' ) ;
return "draggable" in div || "dragDrop" in div
} ( ) ;
var zwspSupported ;
function zeroWidthElement ( measure ) {
if ( zwspSupported == null ) {
var test = elt ( "span" , "\u200b" ) ;
removeChildrenAndAdd ( measure , elt ( "span" , [ test , document . createTextNode ( "x" ) ] ) ) ;
if ( measure . firstChild . offsetHeight != 0 )
{ zwspSupported = test . offsetWidth <= 1 && test . offsetHeight > 2 && ! ( ie && ie _version < 8 ) ; }
}
var node = zwspSupported ? elt ( "span" , "\u200b" ) :
elt ( "span" , "\u00a0" , null , "display: inline-block; width: 1px; margin-right: -1px" ) ;
node . setAttribute ( "cm-text" , "" ) ;
return node
}
// Feature-detect IE's crummy client rect reporting for bidi text
var badBidiRects ;
function hasBadBidiRects ( measure ) {
if ( badBidiRects != null ) { return badBidiRects }
var txt = removeChildrenAndAdd ( measure , document . createTextNode ( "A\u062eA" ) ) ;
var r0 = range ( txt , 0 , 1 ) . getBoundingClientRect ( ) ;
var r1 = range ( txt , 1 , 2 ) . getBoundingClientRect ( ) ;
removeChildren ( measure ) ;
if ( ! r0 || r0 . left == r0 . right ) { return false } // Safari returns null in some cases (#2780)
return badBidiRects = ( r1 . right - r0 . right < 3 )
}
// See if "".split is the broken IE version, if so, provide an
// alternative way to split lines.
var splitLinesAuto = "\n\nb" . split ( /\n/ ) . length != 3 ? function ( string ) {
var pos = 0 , result = [ ] , l = string . length ;
while ( pos <= l ) {
var nl = string . indexOf ( "\n" , pos ) ;
if ( nl == - 1 ) { nl = string . length ; }
var line = string . slice ( pos , string . charAt ( nl - 1 ) == "\r" ? nl - 1 : nl ) ;
var rt = line . indexOf ( "\r" ) ;
if ( rt != - 1 ) {
result . push ( line . slice ( 0 , rt ) ) ;
pos += rt + 1 ;
} else {
result . push ( line ) ;
pos = nl + 1 ;
}
}
return result
} : function ( string ) { return string . split ( /\r\n?|\n/ ) ; } ;
var hasSelection = window . getSelection ? function ( te ) {
try { return te . selectionStart != te . selectionEnd }
catch ( e ) { return false }
} : function ( te ) {
var range$$1 ;
try { range$$1 = te . ownerDocument . selection . createRange ( ) ; }
catch ( e ) { }
if ( ! range$$1 || range$$1 . parentElement ( ) != te ) { return false }
return range$$1 . compareEndPoints ( "StartToEnd" , range$$1 ) != 0
} ;
var hasCopyEvent = ( function ( ) {
var e = elt ( "div" ) ;
if ( "oncopy" in e ) { return true }
e . setAttribute ( "oncopy" , "return;" ) ;
return typeof e . oncopy == "function"
} ) ( ) ;
var badZoomedRects = null ;
function hasBadZoomedRects ( measure ) {
if ( badZoomedRects != null ) { return badZoomedRects }
var node = removeChildrenAndAdd ( measure , elt ( "span" , "x" ) ) ;
var normal = node . getBoundingClientRect ( ) ;
var fromRange = range ( node , 0 , 1 ) . getBoundingClientRect ( ) ;
return badZoomedRects = Math . abs ( normal . left - fromRange . left ) > 1
}
// Known modes, by name and by MIME
var modes = { } ;
var mimeModes = { } ;
// Extra arguments are stored as the mode's dependencies, which is
// used by (legacy) mechanisms like loadmode.js to automatically
// load a mode. (Preferred mechanism is the require/define calls.)
function defineMode ( name , mode ) {
if ( arguments . length > 2 )
{ mode . dependencies = Array . prototype . slice . call ( arguments , 2 ) ; }
modes [ name ] = mode ;
}
function defineMIME ( mime , spec ) {
mimeModes [ mime ] = spec ;
}
// Given a MIME type, a {name, ...options} config object, or a name
// string, return a mode config object.
function resolveMode ( spec ) {
if ( typeof spec == "string" && mimeModes . hasOwnProperty ( spec ) ) {
spec = mimeModes [ spec ] ;
} else if ( spec && typeof spec . name == "string" && mimeModes . hasOwnProperty ( spec . name ) ) {
var found = mimeModes [ spec . name ] ;
if ( typeof found == "string" ) { found = { name : found } ; }
spec = createObj ( found , spec ) ;
spec . name = found . name ;
} else if ( typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/ . test ( spec ) ) {
return resolveMode ( "application/xml" )
} else if ( typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/ . test ( spec ) ) {
return resolveMode ( "application/json" )
}
if ( typeof spec == "string" ) { return { name : spec } }
else { return spec || { name : "null" } }
}
// Given a mode spec (anything that resolveMode accepts), find and
// initialize an actual mode object.
function getMode ( options , spec ) {
spec = resolveMode ( spec ) ;
var mfactory = modes [ spec . name ] ;
if ( ! mfactory ) { return getMode ( options , "text/plain" ) }
var modeObj = mfactory ( options , spec ) ;
if ( modeExtensions . hasOwnProperty ( spec . name ) ) {
var exts = modeExtensions [ spec . name ] ;
for ( var prop in exts ) {
if ( ! exts . hasOwnProperty ( prop ) ) { continue }
if ( modeObj . hasOwnProperty ( prop ) ) { modeObj [ "_" + prop ] = modeObj [ prop ] ; }
modeObj [ prop ] = exts [ prop ] ;
}
}
modeObj . name = spec . name ;
if ( spec . helperType ) { modeObj . helperType = spec . helperType ; }
if ( spec . modeProps ) { for ( var prop$1 in spec . modeProps )
{ modeObj [ prop$1 ] = spec . modeProps [ prop$1 ] ; } }
return modeObj
}
// This can be used to attach properties to mode objects from
// outside the actual mode definition.
var modeExtensions = { } ;
function extendMode ( mode , properties ) {
var exts = modeExtensions . hasOwnProperty ( mode ) ? modeExtensions [ mode ] : ( modeExtensions [ mode ] = { } ) ;
copyObj ( properties , exts ) ;
}
function copyState ( mode , state ) {
if ( state === true ) { return state }
if ( mode . copyState ) { return mode . copyState ( state ) }
var nstate = { } ;
for ( var n in state ) {
var val = state [ n ] ;
if ( val instanceof Array ) { val = val . concat ( [ ] ) ; }
nstate [ n ] = val ;
}
return nstate
}
// Given a mode and a state (for that mode), find the inner mode and
// state at the position that the state refers to.
function innerMode ( mode , state ) {
var info ;
while ( mode . innerMode ) {
info = mode . innerMode ( state ) ;
if ( ! info || info . mode == mode ) { break }
state = info . state ;
mode = info . mode ;
}
return info || { mode : mode , state : state }
}
function startState ( mode , a1 , a2 ) {
return mode . startState ? mode . startState ( a1 , a2 ) : true
}
// STRING STREAM
// Fed to the mode parsers, provides helper functions to make
// parsers more succinct.
var StringStream = function ( string , tabSize ) {
this . pos = this . start = 0 ;
this . string = string ;
this . tabSize = tabSize || 8 ;
this . lastColumnPos = this . lastColumnValue = 0 ;
this . lineStart = 0 ;
} ;
StringStream . prototype . eol = function ( ) { return this . pos >= this . string . length } ;
StringStream . prototype . sol = function ( ) { return this . pos == this . lineStart } ;
StringStream . prototype . peek = function ( ) { return this . string . charAt ( this . pos ) || undefined } ;
StringStream . prototype . next = function ( ) {
if ( this . pos < this . string . length )
{ return this . string . charAt ( this . pos ++ ) }
} ;
StringStream . prototype . eat = function ( match ) {
var ch = this . string . charAt ( this . pos ) ;
var ok ;
if ( typeof match == "string" ) { ok = ch == match ; }
else { ok = ch && ( match . test ? match . test ( ch ) : match ( ch ) ) ; }
if ( ok ) { ++ this . pos ; return ch }
} ;
StringStream . prototype . eatWhile = function ( match ) {
var start = this . pos ;
while ( this . eat ( match ) ) { }
return this . pos > start
} ;
StringStream . prototype . eatSpace = function ( ) {
var this $1 = this ;
var start = this . pos ;
while ( /[\s\u00a0]/ . test ( this . string . charAt ( this . pos ) ) ) { ++ this $1 . pos ; }
return this . pos > start
} ;
StringStream . prototype . skipToEnd = function ( ) { this . pos = this . string . length ; } ;
StringStream . prototype . skipTo = function ( ch ) {
var found = this . string . indexOf ( ch , this . pos ) ;
if ( found > - 1 ) { this . pos = found ; return true }
} ;
StringStream . prototype . backUp = function ( n ) { this . pos -= n ; } ;
StringStream . prototype . column = function ( ) {
if ( this . lastColumnPos < this . start ) {
this . lastColumnValue = countColumn ( this . string , this . start , this . tabSize , this . lastColumnPos , this . lastColumnValue ) ;
this . lastColumnPos = this . start ;
}
return this . lastColumnValue - ( this . lineStart ? countColumn ( this . string , this . lineStart , this . tabSize ) : 0 )
} ;
StringStream . prototype . indentation = function ( ) {
return countColumn ( this . string , null , this . tabSize ) -
( this . lineStart ? countColumn ( this . string , this . lineStart , this . tabSize ) : 0 )
} ;
StringStream . prototype . match = function ( pattern , consume , caseInsensitive ) {
if ( typeof pattern == "string" ) {
var cased = function ( str ) { return caseInsensitive ? str . toLowerCase ( ) : str ; } ;
var substr = this . string . substr ( this . pos , pattern . length ) ;
if ( cased ( substr ) == cased ( pattern ) ) {
if ( consume !== false ) { this . pos += pattern . length ; }
return true
}
} else {
var match = this . string . slice ( this . pos ) . match ( pattern ) ;
if ( match && match . index > 0 ) { return null }
if ( match && consume !== false ) { this . pos += match [ 0 ] . length ; }
return match
}
} ;
StringStream . prototype . current = function ( ) { return this . string . slice ( this . start , this . pos ) } ;
StringStream . prototype . hideFirstChars = function ( n , inner ) {
this . lineStart += n ;
try { return inner ( ) }
finally { this . lineStart -= n ; }
} ;
// Compute a style array (an array starting with a mode generation
// -- for invalidation -- followed by pairs of end positions and
// style strings), which is used to highlight the tokens on the
// line.
function highlightLine ( cm , line , state , forceToEnd ) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
var st = [ cm . state . modeGen ] , lineClasses = { } ;
// Compute the base array of styles
runMode ( cm , line . text , cm . doc . mode , state , function ( end , style ) { return st . push ( end , style ) ; } ,
lineClasses , forceToEnd ) ;
// Run overlays, adjust style array.
var loop = function ( o ) {
var overlay = cm . state . overlays [ o ] , i = 1 , at = 0 ;
runMode ( cm , line . text , overlay . mode , true , function ( end , style ) {
var start = i ;
// Ensure there's a token end at the current position, and that i points at it
while ( at < end ) {
var i _end = st [ i ] ;
if ( i _end > end )
{ st . splice ( i , 1 , end , st [ i + 1 ] , i _end ) ; }
i += 2 ;
at = Math . min ( end , i _end ) ;
}
if ( ! style ) { return }
if ( overlay . opaque ) {
st . splice ( start , i - start , end , "overlay " + style ) ;
i = start + 2 ;
} else {
for ( ; start < i ; start += 2 ) {
var cur = st [ start + 1 ] ;
st [ start + 1 ] = ( cur ? cur + " " : "" ) + "overlay " + style ;
}
}
} , lineClasses ) ;
} ;
for ( var o = 0 ; o < cm . state . overlays . length ; ++ o ) loop ( o ) ;
return { styles : st , classes : lineClasses . bgClass || lineClasses . textClass ? lineClasses : null }
}
function getLineStyles ( cm , line , updateFrontier ) {
if ( ! line . styles || line . styles [ 0 ] != cm . state . modeGen ) {
var state = getStateBefore ( cm , lineNo ( line ) ) ;
var result = highlightLine ( cm , line , line . text . length > cm . options . maxHighlightLength ? copyState ( cm . doc . mode , state ) : state ) ;
line . stateAfter = state ;
line . styles = result . styles ;
if ( result . classes ) { line . styleClasses = result . classes ; }
else if ( line . styleClasses ) { line . styleClasses = null ; }
if ( updateFrontier === cm . doc . frontier ) { cm . doc . frontier ++ ; }
}
return line . styles
}
function getStateBefore ( cm , n , precise ) {
var doc = cm . doc , display = cm . display ;
if ( ! doc . mode . startState ) { return true }
var pos = findStartLine ( cm , n , precise ) , state = pos > doc . first && getLine ( doc , pos - 1 ) . stateAfter ;
if ( ! state ) { state = startState ( doc . mode ) ; }
else { state = copyState ( doc . mode , state ) ; }
doc . iter ( pos , n , function ( line ) {
processLine ( cm , line . text , state ) ;
var save = pos == n - 1 || pos % 5 == 0 || pos >= display . viewFrom && pos < display . viewTo ;
line . stateAfter = save ? copyState ( doc . mode , state ) : null ;
++ pos ;
} ) ;
if ( precise ) { doc . frontier = pos ; }
return state
}
// Lightweight form of highlight -- proceed over this line and
// update state, but don't save a style array. Used for lines that
// aren't currently visible.
function processLine ( cm , text , state , startAt ) {
var mode = cm . doc . mode ;
var stream = new StringStream ( text , cm . options . tabSize ) ;
stream . start = stream . pos = startAt || 0 ;
if ( text == "" ) { callBlankLine ( mode , state ) ; }
while ( ! stream . eol ( ) ) {
readToken ( mode , stream , state ) ;
stream . start = stream . pos ;
}
}
function callBlankLine ( mode , state ) {
if ( mode . blankLine ) { return mode . blankLine ( state ) }
if ( ! mode . innerMode ) { return }
var inner = innerMode ( mode , state ) ;
if ( inner . mode . blankLine ) { return inner . mode . blankLine ( inner . state ) }
}
function readToken ( mode , stream , state , inner ) {
for ( var i = 0 ; i < 10 ; i ++ ) {
if ( inner ) { inner [ 0 ] = innerMode ( mode , state ) . mode ; }
var style = mode . token ( stream , state ) ;
if ( stream . pos > stream . start ) { return style }
}
throw new Error ( "Mode " + mode . name + " failed to advance stream." )
}
// Utility for getTokenAt and getLineTokens
function takeToken ( cm , pos , precise , asArray ) {
var getObj = function ( copy ) { return ( {
start : stream . start , end : stream . pos ,
string : stream . current ( ) ,
type : style || null ,
state : copy ? copyState ( doc . mode , state ) : state
} ) ; } ;
var doc = cm . doc , mode = doc . mode , style ;
pos = clipPos ( doc , pos ) ;
var line = getLine ( doc , pos . line ) , state = getStateBefore ( cm , pos . line , precise ) ;
var stream = new StringStream ( line . text , cm . options . tabSize ) , tokens ;
if ( asArray ) { tokens = [ ] ; }
while ( ( asArray || stream . pos < pos . ch ) && ! stream . eol ( ) ) {
stream . start = stream . pos ;
style = readToken ( mode , stream , state ) ;
if ( asArray ) { tokens . push ( getObj ( true ) ) ; }
}
return asArray ? tokens : getObj ( )
}
function extractLineClasses ( type , output ) {
if ( type ) { for ( ; ; ) {
var lineClass = type . match ( /(?:^|\s+)line-(background-)?(\S+)/ ) ;
if ( ! lineClass ) { break }
type = type . slice ( 0 , lineClass . index ) + type . slice ( lineClass . index + lineClass [ 0 ] . length ) ;
var prop = lineClass [ 1 ] ? "bgClass" : "textClass" ;
if ( output [ prop ] == null )
{ output [ prop ] = lineClass [ 2 ] ; }
else if ( ! ( new RegExp ( "(?:^|\s)" + lineClass [ 2 ] + "(?:$|\s)" ) ) . test ( output [ prop ] ) )
{ output [ prop ] += " " + lineClass [ 2 ] ; }
} }
return type
}
// Run the given mode's parser over a line, calling f for each token.
function runMode ( cm , text , mode , state , f , lineClasses , forceToEnd ) {
var flattenSpans = mode . flattenSpans ;
if ( flattenSpans == null ) { flattenSpans = cm . options . flattenSpans ; }
var curStart = 0 , curStyle = null ;
var stream = new StringStream ( text , cm . options . tabSize ) , style ;
var inner = cm . options . addModeClass && [ null ] ;
if ( text == "" ) { extractLineClasses ( callBlankLine ( mode , state ) , lineClasses ) ; }
while ( ! stream . eol ( ) ) {
if ( stream . pos > cm . options . maxHighlightLength ) {
flattenSpans = false ;
if ( forceToEnd ) { processLine ( cm , text , state , stream . pos ) ; }
stream . pos = text . length ;
style = null ;
} else {
style = extractLineClasses ( readToken ( mode , stream , state , inner ) , lineClasses ) ;
}
if ( inner ) {
var mName = inner [ 0 ] . name ;
if ( mName ) { style = "m-" + ( style ? mName + " " + style : mName ) ; }
}
if ( ! flattenSpans || curStyle != style ) {
while ( curStart < stream . start ) {
curStart = Math . min ( stream . start , curStart + 5000 ) ;
f ( curStart , curStyle ) ;
}
curStyle = style ;
}
stream . start = stream . pos ;
}
while ( curStart < stream . pos ) {
// Webkit seems to refuse to render text nodes longer than 57444
// characters, and returns inaccurate measurements in nodes
// starting around 5000 chars.
var pos = Math . min ( stream . pos , curStart + 5000 ) ;
f ( pos , curStyle ) ;
curStart = pos ;
}
}
// Finds the line to start with when starting a parse. Tries to
// find a line with a stateAfter, so that it can start with a
// valid state. If that fails, it returns the line with the
// smallest indentation, which tends to need the least context to
// parse correctly.
function findStartLine ( cm , n , precise ) {
var minindent , minline , doc = cm . doc ;
var lim = precise ? - 1 : n - ( cm . doc . mode . innerMode ? 1000 : 100 ) ;
for ( var search = n ; search > lim ; -- search ) {
if ( search <= doc . first ) { return doc . first }
var line = getLine ( doc , search - 1 ) ;
if ( line . stateAfter && ( ! precise || search <= doc . frontier ) ) { return search }
var indented = countColumn ( line . text , null , cm . options . tabSize ) ;
if ( minline == null || minindent > indented ) {
minline = search - 1 ;
minindent = indented ;
}
}
return minline
}
// LINE DATA STRUCTURE
// Line objects. These hold state related to a line, including
// highlighting info (the styles array).
var Line = function ( text , markedSpans , estimateHeight ) {
this . text = text ;
attachMarkedSpans ( this , markedSpans ) ;
this . height = estimateHeight ? estimateHeight ( this ) : 1 ;
} ;
Line . prototype . lineNo = function ( ) { return lineNo ( this ) } ;
eventMixin ( Line ) ;
// Change the content (text, markers) of a line. Automatically
// invalidates cached information and tries to re-estimate the
// line's height.
function updateLine ( line , text , markedSpans , estimateHeight ) {
line . text = text ;
if ( line . stateAfter ) { line . stateAfter = null ; }
if ( line . styles ) { line . styles = null ; }
if ( line . order != null ) { line . order = null ; }
detachMarkedSpans ( line ) ;
attachMarkedSpans ( line , markedSpans ) ;
var estHeight = estimateHeight ? estimateHeight ( line ) : 1 ;
if ( estHeight != line . height ) { updateLineHeight ( line , estHeight ) ; }
}
// Detach a line from the document tree and its markers.
function cleanUpLine ( line ) {
line . parent = null ;
detachMarkedSpans ( line ) ;
}
// Convert a style as returned by a mode (either null, or a string
// containing one or more styles) to a CSS style. This is cached,
// and also looks for line-wide styles.
var styleToClassCache = { } ;
var styleToClassCacheWithMode = { } ;
function interpretTokenStyle ( style , options ) {
if ( ! style || /^\s*$/ . test ( style ) ) { return null }
var cache = options . addModeClass ? styleToClassCacheWithMode : styleToClassCache ;
return cache [ style ] ||
( cache [ style ] = style . replace ( /\S+/g , "cm-$&" ) )
}
// Render the DOM representation of the text of a line. Also builds
// up a 'line map', which points at the DOM nodes that represent
// specific stretches of text, and is used by the measuring code.
// The returned object contains the DOM node, this map, and
// information about line-wide styles that were set by the mode.
function buildLineContent ( cm , lineView ) {
// The padding-right forces the element to have a 'border', which
// is needed on Webkit to be able to get line-level bounding
// rectangles for it (in measureChar).
var content = eltP ( "span" , null , null , webkit ? "padding-right: .1px" : null ) ;
var builder = { pre : eltP ( "pre" , [ content ] , "CodeMirror-line" ) , content : content ,
col : 0 , pos : 0 , cm : cm ,
trailingSpace : false ,
splitSpaces : ( ie || webkit ) && cm . getOption ( "lineWrapping" ) } ;
lineView . measure = { } ;
// Iterate over the logical lines that make up this visual line.
for ( var i = 0 ; i <= ( lineView . rest ? lineView . rest . length : 0 ) ; i ++ ) {
var line = i ? lineView . rest [ i - 1 ] : lineView . line , order = ( void 0 ) ;
builder . pos = 0 ;
builder . addToken = buildToken ;
// Optionally wire in some hacks into the token-rendering
// algorithm, to deal with browser quirks.
if ( hasBadBidiRects ( cm . display . measure ) && ( order = getOrder ( line , cm . doc . direction ) ) )
{ builder . addToken = buildTokenBadBidi ( builder . addToken , order ) ; }
builder . map = [ ] ;
var allowFrontierUpdate = lineView != cm . display . externalMeasured && lineNo ( line ) ;
insertLineContent ( line , builder , getLineStyles ( cm , line , allowFrontierUpdate ) ) ;
if ( line . styleClasses ) {
if ( line . styleClasses . bgClass )
{ builder . bgClass = joinClasses ( line . styleClasses . bgClass , builder . bgClass || "" ) ; }
if ( line . styleClasses . textClass )
{ builder . textClass = joinClasses ( line . styleClasses . textClass , builder . textClass || "" ) ; }
}
// Ensure at least a single node is present, for measuring.
if ( builder . map . length == 0 )
{ builder . map . push ( 0 , 0 , builder . content . appendChild ( zeroWidthElement ( cm . display . measure ) ) ) ; }
// Store the map and a cache object for the current logical line
if ( i == 0 ) {
lineView . measure . map = builder . map ;
lineView . measure . cache = { } ;
} else {
( lineView . measure . maps || ( lineView . measure . maps = [ ] ) ) . push ( builder . map )
; ( lineView . measure . caches || ( lineView . measure . caches = [ ] ) ) . push ( { } ) ;
}
}
// See issue #2901
if ( webkit ) {
var last = builder . content . lastChild ;
if ( /\bcm-tab\b/ . test ( last . className ) || ( last . querySelector && last . querySelector ( ".cm-tab" ) ) )
{ builder . content . className = "cm-tab-wrap-hack" ; }
}
signal ( cm , "renderLine" , cm , lineView . line , builder . pre ) ;
if ( builder . pre . className )
{ builder . textClass = joinClasses ( builder . pre . className , builder . textClass || "" ) ; }
return builder
}
function defaultSpecialCharPlaceholder ( ch ) {
var token = elt ( "span" , "\u2022" , "cm-invalidchar" ) ;
token . title = "\\u" + ch . charCodeAt ( 0 ) . toString ( 16 ) ;
token . setAttribute ( "aria-label" , token . title ) ;
return token
}
// Build up the DOM representation for a single token, and add it to
// the line map. Takes care to render special characters separately.
function buildToken ( builder , text , style , startStyle , endStyle , title , css ) {
if ( ! text ) { return }
var displayText = builder . splitSpaces ? splitSpaces ( text , builder . trailingSpace ) : text ;
var special = builder . cm . state . specialChars , mustWrap = false ;
var content ;
if ( ! special . test ( text ) ) {
builder . col += text . length ;
content = document . createTextNode ( displayText ) ;
builder . map . push ( builder . pos , builder . pos + text . length , content ) ;
if ( ie && ie _version < 9 ) { mustWrap = true ; }
builder . pos += text . length ;
} else {
content = document . createDocumentFragment ( ) ;
var pos = 0 ;
while ( true ) {
special . lastIndex = pos ;
var m = special . exec ( text ) ;
var skipped = m ? m . index - pos : text . length - pos ;
if ( skipped ) {
var txt = document . createTextNode ( displayText . slice ( pos , pos + skipped ) ) ;
if ( ie && ie _version < 9 ) { content . appendChild ( elt ( "span" , [ txt ] ) ) ; }
else { content . appendChild ( txt ) ; }
builder . map . push ( builder . pos , builder . pos + skipped , txt ) ;
builder . col += skipped ;
builder . pos += skipped ;
}
if ( ! m ) { break }
pos += skipped + 1 ;
var txt$1 = ( void 0 ) ;
if ( m [ 0 ] == "\t" ) {
var tabSize = builder . cm . options . tabSize , tabWidth = tabSize - builder . col % tabSize ;
txt$1 = content . appendChild ( elt ( "span" , spaceStr ( tabWidth ) , "cm-tab" ) ) ;
txt$1 . setAttribute ( "role" , "presentation" ) ;
txt$1 . setAttribute ( "cm-text" , "\t" ) ;
builder . col += tabWidth ;
} else if ( m [ 0 ] == "\r" || m [ 0 ] == "\n" ) {
txt$1 = content . appendChild ( elt ( "span" , m [ 0 ] == "\r" ? "\u240d" : "\u2424" , "cm-invalidchar" ) ) ;
txt$1 . setAttribute ( "cm-text" , m [ 0 ] ) ;
builder . col += 1 ;
} else {
txt$1 = builder . cm . options . specialCharPlaceholder ( m [ 0 ] ) ;
txt$1 . setAttribute ( "cm-text" , m [ 0 ] ) ;
if ( ie && ie _version < 9 ) { content . appendChild ( elt ( "span" , [ txt$1 ] ) ) ; }
else { content . appendChild ( txt$1 ) ; }
builder . col += 1 ;
}
builder . map . push ( builder . pos , builder . pos + 1 , txt$1 ) ;
builder . pos ++ ;
}
}
builder . trailingSpace = displayText . charCodeAt ( text . length - 1 ) == 32 ;
if ( style || startStyle || endStyle || mustWrap || css ) {
var fullStyle = style || "" ;
if ( startStyle ) { fullStyle += startStyle ; }
if ( endStyle ) { fullStyle += endStyle ; }
var token = elt ( "span" , [ content ] , fullStyle , css ) ;
if ( title ) { token . title = title ; }
return builder . content . appendChild ( token )
}
builder . content . appendChild ( content ) ;
}
function splitSpaces ( text , trailingBefore ) {
if ( text . length > 1 && ! / / . test ( text ) ) { return text }
var spaceBefore = trailingBefore , result = "" ;
for ( var i = 0 ; i < text . length ; i ++ ) {
var ch = text . charAt ( i ) ;
if ( ch == " " && spaceBefore && ( i == text . length - 1 || text . charCodeAt ( i + 1 ) == 32 ) )
{ ch = "\u00a0" ; }
result += ch ;
spaceBefore = ch == " " ;
}
return result
}
// Work around nonsense dimensions being reported for stretches of
// right-to-left text.
function buildTokenBadBidi ( inner , order ) {
return function ( builder , text , style , startStyle , endStyle , title , css ) {
style = style ? style + " cm-force-border" : "cm-force-border" ;
var start = builder . pos , end = start + text . length ;
for ( ; ; ) {
// Find the part that overlaps with the start of this text
var part = ( void 0 ) ;
for ( var i = 0 ; i < order . length ; i ++ ) {
part = order [ i ] ;
if ( part . to > start && part . from <= start ) { break }
}
if ( part . to >= end ) { return inner ( builder , text , style , startStyle , endStyle , title , css ) }
inner ( builder , text . slice ( 0 , part . to - start ) , style , startStyle , null , title , css ) ;
startStyle = null ;
text = text . slice ( part . to - start ) ;
start = part . to ;
}
}
}
function buildCollapsedSpan ( builder , size , marker , ignoreWidget ) {
var widget = ! ignoreWidget && marker . widgetNode ;
if ( widget ) { builder . map . push ( builder . pos , builder . pos + size , widget ) ; }
if ( ! ignoreWidget && builder . cm . display . input . needsContentAttribute ) {
if ( ! widget )
{ widget = builder . content . appendChild ( document . createElement ( "span" ) ) ; }
widget . setAttribute ( "cm-marker" , marker . id ) ;
}
if ( widget ) {
builder . cm . display . input . setUneditable ( widget ) ;
builder . content . appendChild ( widget ) ;
}
builder . pos += size ;
builder . trailingSpace = false ;
}
// Outputs a number of spans to make up a line, taking highlighting
// and marked text into account.
function insertLineContent ( line , builder , styles ) {
var spans = line . markedSpans , allText = line . text , at = 0 ;
if ( ! spans ) {
for ( var i$1 = 1 ; i$1 < styles . length ; i$1 += 2 )
{ builder . addToken ( builder , allText . slice ( at , at = styles [ i$1 ] ) , interpretTokenStyle ( styles [ i$1 + 1 ] , builder . cm . options ) ) ; }
return
}
var len = allText . length , pos = 0 , i = 1 , text = "" , style , css ;
var nextChange = 0 , spanStyle , spanEndStyle , spanStartStyle , title , collapsed ;
for ( ; ; ) {
if ( nextChange == pos ) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = "" ;
collapsed = null ; nextChange = Infinity ;
var foundBookmarks = [ ] , endStyles = ( void 0 ) ;
for ( var j = 0 ; j < spans . length ; ++ j ) {
var sp = spans [ j ] , m = sp . marker ;
if ( m . type == "bookmark" && sp . from == pos && m . widgetNode ) {
foundBookmarks . push ( m ) ;
} else if ( sp . from <= pos && ( sp . to == null || sp . to > pos || m . collapsed && sp . to == pos && sp . from == pos ) ) {
if ( sp . to != null && sp . to != pos && nextChange > sp . to ) {
nextChange = sp . to ;
spanEndStyle = "" ;
}
if ( m . className ) { spanStyle += " " + m . className ; }
if ( m . css ) { css = ( css ? css + ";" : "" ) + m . css ; }
if ( m . startStyle && sp . from == pos ) { spanStartStyle += " " + m . startStyle ; }
if ( m . endStyle && sp . to == nextChange ) { ( endStyles || ( endStyles = [ ] ) ) . push ( m . endStyle , sp . to ) ; }
if ( m . title && ! title ) { title = m . title ; }
if ( m . collapsed && ( ! collapsed || compareCollapsedMarkers ( collapsed . marker , m ) < 0 ) )
{ collapsed = sp ; }
} else if ( sp . from > pos && nextChange > sp . from ) {
nextChange = sp . from ;
}
}
if ( endStyles ) { for ( var j$1 = 0 ; j$1 < endStyles . length ; j$1 += 2 )
{ if ( endStyles [ j$1 + 1 ] == nextChange ) { spanEndStyle += " " + endStyles [ j$1 ] ; } } }
if ( ! collapsed || collapsed . from == pos ) { for ( var j$2 = 0 ; j$2 < foundBookmarks . length ; ++ j$2 )
{ buildCollapsedSpan ( builder , 0 , foundBookmarks [ j$2 ] ) ; } }
if ( collapsed && ( collapsed . from || 0 ) == pos ) {
buildCollapsedSpan ( builder , ( collapsed . to == null ? len + 1 : collapsed . to ) - pos ,
collapsed . marker , collapsed . from == null ) ;
if ( collapsed . to == null ) { return }
if ( collapsed . to == pos ) { collapsed = false ; }
}
}
if ( pos >= len ) { break }
var upto = Math . min ( len , nextChange ) ;
while ( true ) {
if ( text ) {
var end = pos + text . length ;
if ( ! collapsed ) {
var tokenText = end > upto ? text . slice ( 0 , upto - pos ) : text ;
builder . addToken ( builder , tokenText , style ? style + spanStyle : spanStyle ,
spanStartStyle , pos + tokenText . length == nextChange ? spanEndStyle : "" , title , css ) ;
}
if ( end >= upto ) { text = text . slice ( upto - pos ) ; pos = upto ; break }
pos = end ;
spanStartStyle = "" ;
}
text = allText . slice ( at , at = styles [ i ++ ] ) ;
style = interpretTokenStyle ( styles [ i ++ ] , builder . cm . options ) ;
}
}
}
// These objects are used to represent the visible (currently drawn)
// part of the document. A LineView may correspond to multiple
// logical lines, if those are connected by collapsed ranges.
function LineView ( doc , line , lineN ) {
// The starting line
this . line = line ;
// Continuing lines, if any
this . rest = visualLineContinued ( line ) ;
// Number of logical lines in this visual line
this . size = this . rest ? lineNo ( lst ( this . rest ) ) - lineN + 1 : 1 ;
this . node = this . text = null ;
this . hidden = lineIsHidden ( doc , line ) ;
}
// Create a range of LineView objects for the given lines.
function buildViewArray ( cm , from , to ) {
var array = [ ] , nextPos ;
for ( var pos = from ; pos < to ; pos = nextPos ) {
var view = new LineView ( cm . doc , getLine ( cm . doc , pos ) , pos ) ;
nextPos = pos + view . size ;
array . push ( view ) ;
}
return array
}
var operationGroup = null ;
function pushOperation ( op ) {
if ( operationGroup ) {
operationGroup . ops . push ( op ) ;
} else {
op . ownsGroup = operationGroup = {
ops : [ op ] ,
delayedCallbacks : [ ]
} ;
}
}
function fireCallbacksForOps ( group ) {
// Calls delayed callbacks and cursorActivity handlers until no
// new ones appear
var callbacks = group . delayedCallbacks , i = 0 ;
do {
for ( ; i < callbacks . length ; i ++ )
{ callbacks [ i ] . call ( null ) ; }
for ( var j = 0 ; j < group . ops . length ; j ++ ) {
var op = group . ops [ j ] ;
if ( op . cursorActivityHandlers )
{ while ( op . cursorActivityCalled < op . cursorActivityHandlers . length )
{ op . cursorActivityHandlers [ op . cursorActivityCalled ++ ] . call ( null , op . cm ) ; } }
}
} while ( i < callbacks . length )
}
function finishOperation ( op , endCb ) {
var group = op . ownsGroup ;
if ( ! group ) { return }
try { fireCallbacksForOps ( group ) ; }
finally {
operationGroup = null ;
endCb ( group ) ;
}
}
var orphanDelayedCallbacks = null ;
// Often, we want to signal events at a point where we are in the
// middle of some work, but don't want the handler to start calling
// other methods on the editor, which might be in an inconsistent
// state or simply not expect any other events to happen.
// signalLater looks whether there are any handlers, and schedules
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater ( emitter , type /*, values...*/ ) {
var arr = getHandlers ( emitter , type ) ;
if ( ! arr . length ) { return }
var args = Array . prototype . slice . call ( arguments , 2 ) , list ;
if ( operationGroup ) {
list = operationGroup . delayedCallbacks ;
} else if ( orphanDelayedCallbacks ) {
list = orphanDelayedCallbacks ;
} else {
list = orphanDelayedCallbacks = [ ] ;
setTimeout ( fireOrphanDelayed , 0 ) ;
}
var loop = function ( i ) {
list . push ( function ( ) { return arr [ i ] . apply ( null , args ) ; } ) ;
} ;
for ( var i = 0 ; i < arr . length ; ++ i )
loop ( i ) ;
}
function fireOrphanDelayed ( ) {
var delayed = orphanDelayedCallbacks ;
orphanDelayedCallbacks = null ;
for ( var i = 0 ; i < delayed . length ; ++ i ) { delayed [ i ] ( ) ; }
}
// When an aspect of a line changes, a string is added to
// lineView.changes. This updates the relevant part of the line's
// DOM structure.
function updateLineForChanges ( cm , lineView , lineN , dims ) {
for ( var j = 0 ; j < lineView . changes . length ; j ++ ) {
var type = lineView . changes [ j ] ;
if ( type == "text" ) { updateLineText ( cm , lineView ) ; }
else if ( type == "gutter" ) { updateLineGutter ( cm , lineView , lineN , dims ) ; }
else if ( type == "class" ) { updateLineClasses ( cm , lineView ) ; }
else if ( type == "widget" ) { updateLineWidgets ( cm , lineView , dims ) ; }
}
lineView . changes = null ;
}
// Lines with gutter elements, widgets or a background class need to
// be wrapped, and have the extra elements added to the wrapper div
function ensureLineWrapped ( lineView ) {
if ( lineView . node == lineView . text ) {
lineView . node = elt ( "div" , null , null , "position: relative" ) ;
if ( lineView . text . parentNode )
{ lineView . text . parentNode . replaceChild ( lineView . node , lineView . text ) ; }
lineView . node . appendChild ( lineView . text ) ;
if ( ie && ie _version < 8 ) { lineView . node . style . zIndex = 2 ; }
}
return lineView . node
}
function updateLineBackground ( cm , lineView ) {
var cls = lineView . bgClass ? lineView . bgClass + " " + ( lineView . line . bgClass || "" ) : lineView . line . bgClass ;
if ( cls ) { cls += " CodeMirror-linebackground" ; }
if ( lineView . background ) {
if ( cls ) { lineView . background . className = cls ; }
else { lineView . background . parentNode . removeChild ( lineView . background ) ; lineView . background = null ; }
} else if ( cls ) {
var wrap = ensureLineWrapped ( lineView ) ;
lineView . background = wrap . insertBefore ( elt ( "div" , null , cls ) , wrap . firstChild ) ;
cm . display . input . setUneditable ( lineView . background ) ;
}
}
// Wrapper around buildLineContent which will reuse the structure
// in display.externalMeasured when possible.
function getLineContent ( cm , lineView ) {
var ext = cm . display . externalMeasured ;
if ( ext && ext . line == lineView . line ) {
cm . display . externalMeasured = null ;
lineView . measure = ext . measure ;
return ext . built
}
return buildLineContent ( cm , lineView )
}
// Redraw the line's text. Interacts with the background and text
// classes because the mode may output tokens that influence these
// classes.
function updateLineText ( cm , lineView ) {
var cls = lineView . text . className ;
var built = getLineContent ( cm , lineView ) ;
if ( lineView . text == lineView . node ) { lineView . node = built . pre ; }
lineView . text . parentNode . replaceChild ( built . pre , lineView . text ) ;
lineView . text = built . pre ;
if ( built . bgClass != lineView . bgClass || built . textClass != lineView . textClass ) {
lineView . bgClass = built . bgClass ;
lineView . textClass = built . textClass ;
updateLineClasses ( cm , lineView ) ;
} else if ( cls ) {
lineView . text . className = cls ;
}
}
function updateLineClasses ( cm , lineView ) {
updateLineBackground ( cm , lineView ) ;
if ( lineView . line . wrapClass )
{ ensureLineWrapped ( lineView ) . className = lineView . line . wrapClass ; }
else if ( lineView . node != lineView . text )
{ lineView . node . className = "" ; }
var textClass = lineView . textClass ? lineView . textClass + " " + ( lineView . line . textClass || "" ) : lineView . line . textClass ;
lineView . text . className = textClass || "" ;
}
function updateLineGutter ( cm , lineView , lineN , dims ) {
if ( lineView . gutter ) {
lineView . node . removeChild ( lineView . gutter ) ;
lineView . gutter = null ;
}
if ( lineView . gutterBackground ) {
lineView . node . removeChild ( lineView . gutterBackground ) ;
lineView . gutterBackground = null ;
}
if ( lineView . line . gutterClass ) {
var wrap = ensureLineWrapped ( lineView ) ;
lineView . gutterBackground = elt ( "div" , null , "CodeMirror-gutter-background " + lineView . line . gutterClass ,
( "left: " + ( cm . options . fixedGutter ? dims . fixedPos : - dims . gutterTotalWidth ) + "px; width: " + ( dims . gutterTotalWidth ) + "px" ) ) ;
cm . display . input . setUneditable ( lineView . gutterBackground ) ;
wrap . insertBefore ( lineView . gutterBackground , lineView . text ) ;
}
var markers = lineView . line . gutterMarkers ;
if ( cm . options . lineNumbers || markers ) {
var wrap$1 = ensureLineWrapped ( lineView ) ;
var gutterWrap = lineView . gutter = elt ( "div" , null , "CodeMirror-gutter-wrapper" , ( "left: " + ( cm . options . fixedGutter ? dims . fixedPos : - dims . gutterTotalWidth ) + "px" ) ) ;
cm . display . input . setUneditable ( gutterWrap ) ;
wrap$1 . insertBefore ( gutterWrap , lineView . text ) ;
if ( lineView . line . gutterClass )
{ gutterWrap . className += " " + lineView . line . gutterClass ; }
if ( cm . options . lineNumbers && ( ! markers || ! markers [ "CodeMirror-linenumbers" ] ) )
{ lineView . lineNumber = gutterWrap . appendChild (
elt ( "div" , lineNumberFor ( cm . options , lineN ) ,
"CodeMirror-linenumber CodeMirror-gutter-elt" ,
( "left: " + ( dims . gutterLeft [ "CodeMirror-linenumbers" ] ) + "px; width: " + ( cm . display . lineNumInnerWidth ) + "px" ) ) ) ; }
if ( markers ) { for ( var k = 0 ; k < cm . options . gutters . length ; ++ k ) {
var id = cm . options . gutters [ k ] , found = markers . hasOwnProperty ( id ) && markers [ id ] ;
if ( found )
{ gutterWrap . appendChild ( elt ( "div" , [ found ] , "CodeMirror-gutter-elt" ,
( "left: " + ( dims . gutterLeft [ id ] ) + "px; width: " + ( dims . gutterWidth [ id ] ) + "px" ) ) ) ; }
} }
}
}
function updateLineWidgets ( cm , lineView , dims ) {
if ( lineView . alignable ) { lineView . alignable = null ; }
for ( var node = lineView . node . firstChild , next = ( void 0 ) ; node ; node = next ) {
next = node . nextSibling ;
if ( node . className == "CodeMirror-linewidget" )
{ lineView . node . removeChild ( node ) ; }
}
insertLineWidgets ( cm , lineView , dims ) ;
}
// Build a line's DOM representation from scratch
function buildLineElement ( cm , lineView , lineN , dims ) {
var built = getLineContent ( cm , lineView ) ;
lineView . text = lineView . node = built . pre ;
if ( built . bgClass ) { lineView . bgClass = built . bgClass ; }
if ( built . textClass ) { lineView . textClass = built . textClass ; }
updateLineClasses ( cm , lineView ) ;
updateLineGutter ( cm , lineView , lineN , dims ) ;
insertLineWidgets ( cm , lineView , dims ) ;
return lineView . node
}
// A lineView may contain multiple logical lines (when merged by
// collapsed spans). The widgets for all of them need to be drawn.
function insertLineWidgets ( cm , lineView , dims ) {
insertLineWidgetsFor ( cm , lineView . line , lineView , dims , true ) ;
if ( lineView . rest ) { for ( var i = 0 ; i < lineView . rest . length ; i ++ )
{ insertLineWidgetsFor ( cm , lineView . rest [ i ] , lineView , dims , false ) ; } }
}
function insertLineWidgetsFor ( cm , line , lineView , dims , allowAbove ) {
if ( ! line . widgets ) { return }
var wrap = ensureLineWrapped ( lineView ) ;
for ( var i = 0 , ws = line . widgets ; i < ws . length ; ++ i ) {
var widget = ws [ i ] , node = elt ( "div" , [ widget . node ] , "CodeMirror-linewidget" ) ;
if ( ! widget . handleMouseEvents ) { node . setAttribute ( "cm-ignore-events" , "true" ) ; }
positionLineWidget ( widget , node , lineView , dims ) ;
cm . display . input . setUneditable ( node ) ;
if ( allowAbove && widget . above )
{ wrap . insertBefore ( node , lineView . gutter || lineView . text ) ; }
else
{ wrap . appendChild ( node ) ; }
signalLater ( widget , "redraw" ) ;
}
}
function positionLineWidget ( widget , node , lineView , dims ) {
if ( widget . noHScroll ) {
( lineView . alignable || ( lineView . alignable = [ ] ) ) . push ( node ) ;
var width = dims . wrapperWidth ;
node . style . left = dims . fixedPos + "px" ;
if ( ! widget . coverGutter ) {
width -= dims . gutterTotalWidth ;
node . style . paddingLeft = dims . gutterTotalWidth + "px" ;
}
node . style . width = width + "px" ;
}
if ( widget . coverGutter ) {
node . style . zIndex = 5 ;
node . style . position = "relative" ;
if ( ! widget . noHScroll ) { node . style . marginLeft = - dims . gutterTotalWidth + "px" ; }
}
}
function widgetHeight ( widget ) {
if ( widget . height != null ) { return widget . height }
var cm = widget . doc . cm ;
if ( ! cm ) { return 0 }
if ( ! contains ( document . body , widget . node ) ) {
var parentStyle = "position: relative;" ;
if ( widget . coverGutter )
{ parentStyle += "margin-left: -" + cm . display . gutters . offsetWidth + "px;" ; }
if ( widget . noHScroll )
{ parentStyle += "width: " + cm . display . wrapper . clientWidth + "px;" ; }
removeChildrenAndAdd ( cm . display . measure , elt ( "div" , [ widget . node ] , null , parentStyle ) ) ;
}
return widget . height = widget . node . parentNode . offsetHeight
}
// Return true when the given mouse event happened in a widget
function eventInWidget ( display , e ) {
for ( var n = e _target ( e ) ; n != display . wrapper ; n = n . parentNode ) {
if ( ! n || ( n . nodeType == 1 && n . getAttribute ( "cm-ignore-events" ) == "true" ) ||
( n . parentNode == display . sizer && n != display . mover ) )
{ return true }
}
}
// POSITION MEASUREMENT
function paddingTop ( display ) { return display . lineSpace . offsetTop }
function paddingVert ( display ) { return display . mover . offsetHeight - display . lineSpace . offsetHeight }
function paddingH ( display ) {
if ( display . cachedPaddingH ) { return display . cachedPaddingH }
var e = removeChildrenAndAdd ( display . measure , elt ( "pre" , "x" ) ) ;
var style = window . getComputedStyle ? window . getComputedStyle ( e ) : e . currentStyle ;
var data = { left : parseInt ( style . paddingLeft ) , right : parseInt ( style . paddingRight ) } ;
if ( ! isNaN ( data . left ) && ! isNaN ( data . right ) ) { display . cachedPaddingH = data ; }
return data
}
function scrollGap ( cm ) { return scrollerGap - cm . display . nativeBarWidth }
function displayWidth ( cm ) {
return cm . display . scroller . clientWidth - scrollGap ( cm ) - cm . display . barWidth
}
function displayHeight ( cm ) {
return cm . display . scroller . clientHeight - scrollGap ( cm ) - cm . display . barHeight
}
// Ensure the lineView.wrapping.heights array is populated. This is
// an array of bottom offsets for the lines that make up a drawn
// line. When lineWrapping is on, there might be more than one
// height.
function ensureLineHeights ( cm , lineView , rect ) {
var wrapping = cm . options . lineWrapping ;
var curWidth = wrapping && displayWidth ( cm ) ;
if ( ! lineView . measure . heights || wrapping && lineView . measure . width != curWidth ) {
var heights = lineView . measure . heights = [ ] ;
if ( wrapping ) {
lineView . measure . width = curWidth ;
var rects = lineView . text . firstChild . getClientRects ( ) ;
for ( var i = 0 ; i < rects . length - 1 ; i ++ ) {
var cur = rects [ i ] , next = rects [ i + 1 ] ;
if ( Math . abs ( cur . bottom - next . bottom ) > 2 )
{ heights . push ( ( cur . bottom + next . top ) / 2 - rect . top ) ; }
}
}
heights . push ( rect . bottom - rect . top ) ;
}
}
// Find a line map (mapping character offsets to text nodes) and a
// measurement cache for the given line number. (A line view might
// contain multiple lines when collapsed ranges are present.)
function mapFromLineView ( lineView , line , lineN ) {
if ( lineView . line == line )
{ return { map : lineView . measure . map , cache : lineView . measure . cache } }
for ( var i = 0 ; i < lineView . rest . length ; i ++ )
{ if ( lineView . rest [ i ] == line )
{ return { map : lineView . measure . maps [ i ] , cache : lineView . measure . caches [ i ] } } }
for ( var i$1 = 0 ; i$1 < lineView . rest . length ; i$1 ++ )
{ if ( lineNo ( lineView . rest [ i$1 ] ) > lineN )
{ return { map : lineView . measure . maps [ i$1 ] , cache : lineView . measure . caches [ i$1 ] , before : true } } }
}
// Render a line into the hidden node display.externalMeasured. Used
// when measurement is needed for a line that's not in the viewport.
function updateExternalMeasurement ( cm , line ) {
line = visualLine ( line ) ;
var lineN = lineNo ( line ) ;
var view = cm . display . externalMeasured = new LineView ( cm . doc , line , lineN ) ;
view . lineN = lineN ;
var built = view . built = buildLineContent ( cm , view ) ;
view . text = built . pre ;
removeChildrenAndAdd ( cm . display . lineMeasure , built . pre ) ;
return view
}
// Get a {top, bottom, left, right} box (in line-local coordinates)
// for a given character.
function measureChar ( cm , line , ch , bias ) {
return measureCharPrepared ( cm , prepareMeasureForLine ( cm , line ) , ch , bias )
}
// Find a line view that corresponds to the given line number.
function findViewForLine ( cm , lineN ) {
if ( lineN >= cm . display . viewFrom && lineN < cm . display . viewTo )
{ return cm . display . view [ findViewIndex ( cm , lineN ) ] }
var ext = cm . display . externalMeasured ;
if ( ext && lineN >= ext . lineN && lineN < ext . lineN + ext . size )
{ return ext }
}
// Measurement can be split in two steps, the set-up work that
// applies to the whole line, and the measurement of the actual
// character. Functions like coordsChar, that need to do a lot of
// measurements in a row, can thus ensure that the set-up work is
// only done once.
function prepareMeasureForLine ( cm , line ) {
var lineN = lineNo ( line ) ;
var view = findViewForLine ( cm , lineN ) ;
if ( view && ! view . text ) {
view = null ;
} else if ( view && view . changes ) {
updateLineForChanges ( cm , view , lineN , getDimensions ( cm ) ) ;
cm . curOp . forceUpdate = true ;
}
if ( ! view )
{ view = updateExternalMeasurement ( cm , line ) ; }
var info = mapFromLineView ( view , line , lineN ) ;
return {
line : line , view : view , rect : null ,
map : info . map , cache : info . cache , before : info . before ,
hasHeights : false
}
}
// Given a prepared measurement object, measures the position of an
// actual character (or fetches it from the cache).
function measureCharPrepared ( cm , prepared , ch , bias , varHeight ) {
if ( prepared . before ) { ch = - 1 ; }
var key = ch + ( bias || "" ) , found ;
if ( prepared . cache . hasOwnProperty ( key ) ) {
found = prepared . cache [ key ] ;
} else {
if ( ! prepared . rect )
{ prepared . rect = prepared . view . text . getBoundingClientRect ( ) ; }
if ( ! prepared . hasHeights ) {
ensureLineHeights ( cm , prepared . view , prepared . rect ) ;
prepared . hasHeights = true ;
}
found = measureCharInner ( cm , prepared , ch , bias ) ;
if ( ! found . bogus ) { prepared . cache [ key ] = found ; }
}
return { left : found . left , right : found . right ,
top : varHeight ? found . rtop : found . top ,
bottom : varHeight ? found . rbottom : found . bottom }
}
var nullRect = { left : 0 , right : 0 , top : 0 , bottom : 0 } ;
function nodeAndOffsetInLineMap ( map$$1 , ch , bias ) {
var node , start , end , collapse , mStart , mEnd ;
// First, search the line map for the text node corresponding to,
// or closest to, the target character.
for ( var i = 0 ; i < map$$1 . length ; i += 3 ) {
mStart = map$$1 [ i ] ;
mEnd = map$$1 [ i + 1 ] ;
if ( ch < mStart ) {
start = 0 ; end = 1 ;
collapse = "left" ;
} else if ( ch < mEnd ) {
start = ch - mStart ;
end = start + 1 ;
} else if ( i == map$$1 . length - 3 || ch == mEnd && map$$1 [ i + 3 ] > ch ) {
end = mEnd - mStart ;
start = end - 1 ;
if ( ch >= mEnd ) { collapse = "right" ; }
}
if ( start != null ) {
node = map$$1 [ i + 2 ] ;
if ( mStart == mEnd && bias == ( node . insertLeft ? "left" : "right" ) )
{ collapse = bias ; }
if ( bias == "left" && start == 0 )
{ while ( i && map$$1 [ i - 2 ] == map$$1 [ i - 3 ] && map$$1 [ i - 1 ] . insertLeft ) {
node = map$$1 [ ( i -= 3 ) + 2 ] ;
collapse = "left" ;
} }
if ( bias == "right" && start == mEnd - mStart )
{ while ( i < map$$1 . length - 3 && map$$1 [ i + 3 ] == map$$1 [ i + 4 ] && ! map$$1 [ i + 5 ] . insertLeft ) {
node = map$$1 [ ( i += 3 ) + 2 ] ;
collapse = "right" ;
} }
break
}
}
return { node : node , start : start , end : end , collapse : collapse , coverStart : mStart , coverEnd : mEnd }
}
function getUsefulRect ( rects , bias ) {
var rect = nullRect ;
if ( bias == "left" ) { for ( var i = 0 ; i < rects . length ; i ++ ) {
if ( ( rect = rects [ i ] ) . left != rect . right ) { break }
} } else { for ( var i$1 = rects . length - 1 ; i$1 >= 0 ; i$1 -- ) {
if ( ( rect = rects [ i$1 ] ) . left != rect . right ) { break }
} }
return rect
}
function measureCharInner ( cm , prepared , ch , bias ) {
var place = nodeAndOffsetInLineMap ( prepared . map , ch , bias ) ;
var node = place . node , start = place . start , end = place . end , collapse = place . collapse ;
var rect ;
if ( node . nodeType == 3 ) { // If it is a text node, use a range to retrieve the coordinates.
for ( var i$1 = 0 ; i$1 < 4 ; i$1 ++ ) { // Retry a maximum of 4 times when nonsense rectangles are returned
while ( start && isExtendingChar ( prepared . line . text . charAt ( place . coverStart + start ) ) ) { -- start ; }
while ( place . coverStart + end < place . coverEnd && isExtendingChar ( prepared . line . text . charAt ( place . coverStart + end ) ) ) { ++ end ; }
if ( ie && ie _version < 9 && start == 0 && end == place . coverEnd - place . coverStart )
{ rect = node . parentNode . getBoundingClientRect ( ) ; }
else
{ rect = getUsefulRect ( range ( node , start , end ) . getClientRects ( ) , bias ) ; }
if ( rect . left || rect . right || start == 0 ) { break }
end = start ;
start = start - 1 ;
collapse = "right" ;
}
if ( ie && ie _version < 11 ) { rect = maybeUpdateRectForZooming ( cm . display . measure , rect ) ; }
} else { // If it is a widget, simply get the box for the whole widget.
if ( start > 0 ) { collapse = bias = "right" ; }
var rects ;
if ( cm . options . lineWrapping && ( rects = node . getClientRects ( ) ) . length > 1 )
{ rect = rects [ bias == "right" ? rects . length - 1 : 0 ] ; }
else
{ rect = node . getBoundingClientRect ( ) ; }
}
if ( ie && ie _version < 9 && ! start && ( ! rect || ! rect . left && ! rect . right ) ) {
var rSpan = node . parentNode . getClientRects ( ) [ 0 ] ;
if ( rSpan )
{ rect = { left : rSpan . left , right : rSpan . left + charWidth ( cm . display ) , top : rSpan . top , bottom : rSpan . bottom } ; }
else
{ rect = nullRect ; }
}
var rtop = rect . top - prepared . rect . top , rbot = rect . bottom - prepared . rect . top ;
var mid = ( rtop + rbot ) / 2 ;
var heights = prepared . view . measure . heights ;
var i = 0 ;
for ( ; i < heights . length - 1 ; i ++ )
{ if ( mid < heights [ i ] ) { break } }
var top = i ? heights [ i - 1 ] : 0 , bot = heights [ i ] ;
var result = { left : ( collapse == "right" ? rect . right : rect . left ) - prepared . rect . left ,
right : ( collapse == "left" ? rect . left : rect . right ) - prepared . rect . left ,
top : top , bottom : bot } ;
if ( ! rect . left && ! rect . right ) { result . bogus = true ; }
if ( ! cm . options . singleCursorHeightPerLine ) { result . rtop = rtop ; result . rbottom = rbot ; }
return result
}
// Work around problem with bounding client rects on ranges being
// returned incorrectly when zoomed on IE10 and below.
function maybeUpdateRectForZooming ( measure , rect ) {
if ( ! window . screen || screen . logicalXDPI == null ||
screen . logicalXDPI == screen . deviceXDPI || ! hasBadZoomedRects ( measure ) )
{ return rect }
var scaleX = screen . logicalXDPI / screen . deviceXDPI ;
var scaleY = screen . logicalYDPI / screen . deviceYDPI ;
return { left : rect . left * scaleX , right : rect . right * scaleX ,
top : rect . top * scaleY , bottom : rect . bottom * scaleY }
}
function clearLineMeasurementCacheFor ( lineView ) {
if ( lineView . measure ) {
lineView . measure . cache = { } ;
lineView . measure . heights = null ;
if ( lineView . rest ) { for ( var i = 0 ; i < lineView . rest . length ; i ++ )
{ lineView . measure . caches [ i ] = { } ; } }
}
}
function clearLineMeasurementCache ( cm ) {
cm . display . externalMeasure = null ;
removeChildren ( cm . display . lineMeasure ) ;
for ( var i = 0 ; i < cm . display . view . length ; i ++ )
{ clearLineMeasurementCacheFor ( cm . display . view [ i ] ) ; }
}
function clearCaches ( cm ) {
clearLineMeasurementCache ( cm ) ;
cm . display . cachedCharWidth = cm . display . cachedTextHeight = cm . display . cachedPaddingH = null ;
if ( ! cm . options . lineWrapping ) { cm . display . maxLineChanged = true ; }
cm . display . lineNumChars = null ;
}
function pageScrollX ( ) {
// Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
// which causes page_Offset and bounding client rects to use
// different reference viewports and invalidate our calculations.
if ( chrome && android ) { return - ( document . body . getBoundingClientRect ( ) . left - parseInt ( getComputedStyle ( document . body ) . marginLeft ) ) }
return window . pageXOffset || ( document . documentElement || document . body ) . scrollLeft
}
function pageScrollY ( ) {
if ( chrome && android ) { return - ( document . body . getBoundingClientRect ( ) . top - parseInt ( getComputedStyle ( document . body ) . marginTop ) ) }
return window . pageYOffset || ( document . documentElement || document . body ) . scrollTop
}
// Converts a {top, bottom, left, right} box from line-local
// coordinates into another coordinate system. Context may be one of
// "line", "div" (display.lineDiv), "local"./null (editor), "window",
// or "page".
function intoCoordSystem ( cm , lineObj , rect , context , includeWidgets ) {
if ( ! includeWidgets && lineObj . widgets ) { for ( var i = 0 ; i < lineObj . widgets . length ; ++ i ) { if ( lineObj . widgets [ i ] . above ) {
var size = widgetHeight ( lineObj . widgets [ i ] ) ;
rect . top += size ; rect . bottom += size ;
} } }
if ( context == "line" ) { return rect }
if ( ! context ) { context = "local" ; }
var yOff = heightAtLine ( lineObj ) ;
if ( context == "local" ) { yOff += paddingTop ( cm . display ) ; }
else { yOff -= cm . display . viewOffset ; }
if ( context == "page" || context == "window" ) {
var lOff = cm . display . lineSpace . getBoundingClientRect ( ) ;
yOff += lOff . top + ( context == "window" ? 0 : pageScrollY ( ) ) ;
var xOff = lOff . left + ( context == "window" ? 0 : pageScrollX ( ) ) ;
rect . left += xOff ; rect . right += xOff ;
}
rect . top += yOff ; rect . bottom += yOff ;
return rect
}
// Coverts a box from "div" coords to another coordinate system.
// Context may be "window", "page", "div", or "local"./null.
function fromCoordSystem ( cm , coords , context ) {
if ( context == "div" ) { return coords }
var left = coords . left , top = coords . top ;
// First move into "page" coordinate system
if ( context == "page" ) {
left -= pageScrollX ( ) ;
top -= pageScrollY ( ) ;
} else if ( context == "local" || ! context ) {
var localBox = cm . display . sizer . getBoundingClientRect ( ) ;
left += localBox . left ;
top += localBox . top ;
}
var lineSpaceBox = cm . display . lineSpace . getBoundingClientRect ( ) ;
return { left : left - lineSpaceBox . left , top : top - lineSpaceBox . top }
}
function charCoords ( cm , pos , context , lineObj , bias ) {
if ( ! lineObj ) { lineObj = getLine ( cm . doc , pos . line ) ; }
return intoCoordSystem ( cm , lineObj , measureChar ( cm , lineObj , pos . ch , bias ) , context )
}
// Returns a box for a given cursor position, which may have an
// 'other' property containing the position of the secondary cursor
// on a bidi boundary.
// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
// and after `char - 1` in writing order of `char - 1`
// A cursor Pos(line, char, "after") is on the same visual line as `char`
// and before `char` in writing order of `char`
// Examples (upper-case letters are RTL, lower-case are LTR):
// Pos(0, 1, ...)
// before after
// ab a|b a|b
// aB a|B aB|
// Ab |Ab A|b
// AB B|A B|A
// Every position after the last character on a line is considered to stick
// to the last character on the line.
function cursorCoords ( cm , pos , context , lineObj , preparedMeasure , varHeight ) {
lineObj = lineObj || getLine ( cm . doc , pos . line ) ;
if ( ! preparedMeasure ) { preparedMeasure = prepareMeasureForLine ( cm , lineObj ) ; }
function get ( ch , right ) {
var m = measureCharPrepared ( cm , preparedMeasure , ch , right ? "right" : "left" , varHeight ) ;
if ( right ) { m . left = m . right ; } else { m . right = m . left ; }
return intoCoordSystem ( cm , lineObj , m , context )
}
var order = getOrder ( lineObj , cm . doc . direction ) , ch = pos . ch , sticky = pos . sticky ;
if ( ch >= lineObj . text . length ) {
ch = lineObj . text . length ;
sticky = "before" ;
} else if ( ch <= 0 ) {
ch = 0 ;
sticky = "after" ;
}
if ( ! order ) { return get ( sticky == "before" ? ch - 1 : ch , sticky == "before" ) }
function getBidi ( ch , partPos , invert ) {
var part = order [ partPos ] , right = ( part . level % 2 ) != 0 ;
return get ( invert ? ch - 1 : ch , right != invert )
}
var partPos = getBidiPartAt ( order , ch , sticky ) ;
var other = bidiOther ;
var val = getBidi ( ch , partPos , sticky == "before" ) ;
if ( other != null ) { val . other = getBidi ( ch , other , sticky != "before" ) ; }
return val
}
// Used to cheaply estimate the coordinates for a position. Used for
// intermediate scroll updates.
function estimateCoords ( cm , pos ) {
var left = 0 ;
pos = clipPos ( cm . doc , pos ) ;
if ( ! cm . options . lineWrapping ) { left = charWidth ( cm . display ) * pos . ch ; }
var lineObj = getLine ( cm . doc , pos . line ) ;
var top = heightAtLine ( lineObj ) + paddingTop ( cm . display ) ;
return { left : left , right : left , top : top , bottom : top + lineObj . height }
}
// Positions returned by coordsChar contain some extra information.
// xRel is the relative x position of the input coordinates compared
// to the found position (so xRel > 0 means the coordinates are to
// the right of the character position, for example). When outside
// is true, that means the coordinates lie outside the line's
// vertical range.
function PosWithInfo ( line , ch , sticky , outside , xRel ) {
var pos = Pos ( line , ch , sticky ) ;
pos . xRel = xRel ;
if ( outside ) { pos . outside = true ; }
return pos
}
// Compute the character position closest to the given coordinates.
// Input must be lineSpace-local ("div" coordinate system).
function coordsChar ( cm , x , y ) {
var doc = cm . doc ;
y += cm . display . viewOffset ;
if ( y < 0 ) { return PosWithInfo ( doc . first , 0 , null , true , - 1 ) }
var lineN = lineAtHeight ( doc , y ) , last = doc . first + doc . size - 1 ;
if ( lineN > last )
{ return PosWithInfo ( doc . first + doc . size - 1 , getLine ( doc , last ) . text . length , null , true , 1 ) }
if ( x < 0 ) { x = 0 ; }
var lineObj = getLine ( doc , lineN ) ;
for ( ; ; ) {
var found = coordsCharInner ( cm , lineObj , lineN , x , y ) ;
var merged = collapsedSpanAtEnd ( lineObj ) ;
var mergedPos = merged && merged . find ( 0 , true ) ;
if ( merged && ( found . ch > mergedPos . from . ch || found . ch == mergedPos . from . ch && found . xRel > 0 ) )
{ lineN = lineNo ( lineObj = mergedPos . to . line ) ; }
else
{ return found }
}
}
function wrappedLineExtent ( cm , lineObj , preparedMeasure , y ) {
var measure = function ( ch ) { return intoCoordSystem ( cm , lineObj , measureCharPrepared ( cm , preparedMeasure , ch ) , "line" ) ; } ;
var end = lineObj . text . length ;
var begin = findFirst ( function ( ch ) { return measure ( ch - 1 ) . bottom <= y ; } , end , 0 ) ;
end = findFirst ( function ( ch ) { return measure ( ch ) . top > y ; } , begin , end ) ;
return { begin : begin , end : end }
}
function wrappedLineExtentChar ( cm , lineObj , preparedMeasure , target ) {
var targetTop = intoCoordSystem ( cm , lineObj , measureCharPrepared ( cm , preparedMeasure , target ) , "line" ) . top ;
return wrappedLineExtent ( cm , lineObj , preparedMeasure , targetTop )
}
function coordsCharInner ( cm , lineObj , lineNo$$1 , x , y ) {
y -= heightAtLine ( lineObj ) ;
var begin = 0 , end = lineObj . text . length ;
var preparedMeasure = prepareMeasureForLine ( cm , lineObj ) ;
var pos ;
var order = getOrder ( lineObj , cm . doc . direction ) ;
if ( order ) {
if ( cm . options . lineWrapping ) {
var assign ;
( ( assign = wrappedLineExtent ( cm , lineObj , preparedMeasure , y ) , begin = assign . begin , end = assign . end , assign ) ) ;
}
pos = new Pos ( lineNo$$1 , begin ) ;
var beginLeft = cursorCoords ( cm , pos , "line" , lineObj , preparedMeasure ) . left ;
var dir = beginLeft < x ? 1 : - 1 ;
var prevDiff , diff = beginLeft - x , prevPos ;
do {
prevDiff = diff ;
prevPos = pos ;
pos = moveVisually ( cm , lineObj , pos , dir ) ;
if ( pos == null || pos . ch < begin || end <= ( pos . sticky == "before" ? pos . ch - 1 : pos . ch ) ) {
pos = prevPos ;
break
}
diff = cursorCoords ( cm , pos , "line" , lineObj , preparedMeasure ) . left - x ;
} while ( ( dir < 0 ) != ( diff < 0 ) && ( Math . abs ( diff ) <= Math . abs ( prevDiff ) ) )
if ( Math . abs ( diff ) > Math . abs ( prevDiff ) ) {
if ( ( diff < 0 ) == ( prevDiff < 0 ) ) { throw new Error ( "Broke out of infinite loop in coordsCharInner" ) }
pos = prevPos ;
}
} else {
var ch = findFirst ( function ( ch ) {
var box = intoCoordSystem ( cm , lineObj , measureCharPrepared ( cm , preparedMeasure , ch ) , "line" ) ;
if ( box . top > y ) {
// For the cursor stickiness
end = Math . min ( ch , end ) ;
return true
}
else if ( box . bottom <= y ) { return false }
else if ( box . left > x ) { return true }
else if ( box . right < x ) { return false }
else { return ( x - box . left < box . right - x ) }
} , begin , end ) ;
ch = skipExtendingChars ( lineObj . text , ch , 1 ) ;
pos = new Pos ( lineNo$$1 , ch , ch == end ? "before" : "after" ) ;
}
var coords = cursorCoords ( cm , pos , "line" , lineObj , preparedMeasure ) ;
if ( y < coords . top || coords . bottom < y ) { pos . outside = true ; }
pos . xRel = x < coords . left ? - 1 : ( x > coords . right ? 1 : 0 ) ;
return pos
}
var measureText ;
// Compute the default text height.
function textHeight ( display ) {
if ( display . cachedTextHeight != null ) { return display . cachedTextHeight }
if ( measureText == null ) {
measureText = elt ( "pre" ) ;
// Measure a bunch of lines, for browsers that compute
// fractional heights.
for ( var i = 0 ; i < 49 ; ++ i ) {
measureText . appendChild ( document . createTextNode ( "x" ) ) ;
measureText . appendChild ( elt ( "br" ) ) ;
}
measureText . appendChild ( document . createTextNode ( "x" ) ) ;
}
removeChildrenAndAdd ( display . measure , measureText ) ;
var height = measureText . offsetHeight / 50 ;
if ( height > 3 ) { display . cachedTextHeight = height ; }
removeChildren ( display . measure ) ;
return height || 1
}
// Compute the default character width.
function charWidth ( display ) {
if ( display . cachedCharWidth != null ) { return display . cachedCharWidth }
var anchor = elt ( "span" , "xxxxxxxxxx" ) ;
var pre = elt ( "pre" , [ anchor ] ) ;
removeChildrenAndAdd ( display . measure , pre ) ;
var rect = anchor . getBoundingClientRect ( ) , width = ( rect . right - rect . left ) / 10 ;
if ( width > 2 ) { display . cachedCharWidth = width ; }
return width || 10
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
// view, so that we don't interleave reading and writing to the DOM.
function getDimensions ( cm ) {
var d = cm . display , left = { } , width = { } ;
var gutterLeft = d . gutters . clientLeft ;
for ( var n = d . gutters . firstChild , i = 0 ; n ; n = n . nextSibling , ++ i ) {
left [ cm . options . gutters [ i ] ] = n . offsetLeft + n . clientLeft + gutterLeft ;
width [ cm . options . gutters [ i ] ] = n . clientWidth ;
}
return { fixedPos : compensateForHScroll ( d ) ,
gutterTotalWidth : d . gutters . offsetWidth ,
gutterLeft : left ,
gutterWidth : width ,
wrapperWidth : d . wrapper . clientWidth }
}
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
// but using getBoundingClientRect to get a sub-pixel-accurate
// result.
function compensateForHScroll ( display ) {
return display . scroller . getBoundingClientRect ( ) . left - display . sizer . getBoundingClientRect ( ) . left
}
// Returns a function that estimates the height of a line, to use as
// first approximation until the line becomes visible (and is thus
// properly measurable).
function estimateHeight ( cm ) {
var th = textHeight ( cm . display ) , wrapping = cm . options . lineWrapping ;
var perLine = wrapping && Math . max ( 5 , cm . display . scroller . clientWidth / charWidth ( cm . display ) - 3 ) ;
return function ( line ) {
if ( lineIsHidden ( cm . doc , line ) ) { return 0 }
var widgetsHeight = 0 ;
if ( line . widgets ) { for ( var i = 0 ; i < line . widgets . length ; i ++ ) {
if ( line . widgets [ i ] . height ) { widgetsHeight += line . widgets [ i ] . height ; }
} }
if ( wrapping )
{ return widgetsHeight + ( Math . ceil ( line . text . length / perLine ) || 1 ) * th }
else
{ return widgetsHeight + th }
}
}
function estimateLineHeights ( cm ) {
var doc = cm . doc , est = estimateHeight ( cm ) ;
doc . iter ( function ( line ) {
var estHeight = est ( line ) ;
if ( estHeight != line . height ) { updateLineHeight ( line , estHeight ) ; }
} ) ;
}
// Given a mouse event, find the corresponding position. If liberal
// is false, it checks whether a gutter or scrollbar was clicked,
// and returns null if it was. forRect is used by rectangular
// selections, and tries to estimate a character position even for
// coordinates beyond the right of the text.
function posFromMouse ( cm , e , liberal , forRect ) {
var display = cm . display ;
if ( ! liberal && e _target ( e ) . getAttribute ( "cm-not-content" ) == "true" ) { return null }
var x , y , space = display . lineSpace . getBoundingClientRect ( ) ;
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
try { x = e . clientX - space . left ; y = e . clientY - space . top ; }
catch ( e ) { return null }
var coords = coordsChar ( cm , x , y ) , line ;
if ( forRect && coords . xRel == 1 && ( line = getLine ( cm . doc , coords . line ) . text ) . length == coords . ch ) {
var colDiff = countColumn ( line , line . length , cm . options . tabSize ) - line . length ;
coords = Pos ( coords . line , Math . max ( 0 , Math . round ( ( x - paddingH ( cm . display ) . left ) / charWidth ( cm . display ) ) - colDiff ) ) ;
}
return coords
}
// Find the view element corresponding to a given line. Return null
// when the line isn't visible.
function findViewIndex ( cm , n ) {
if ( n >= cm . display . viewTo ) { return null }
n -= cm . display . viewFrom ;
if ( n < 0 ) { return null }
var view = cm . display . view ;
for ( var i = 0 ; i < view . length ; i ++ ) {
n -= view [ i ] . size ;
if ( n < 0 ) { return i }
}
}
function updateSelection ( cm ) {
cm . display . input . showSelection ( cm . display . input . prepareSelection ( ) ) ;
}
function prepareSelection ( cm , primary ) {
var doc = cm . doc , result = { } ;
var curFragment = result . cursors = document . createDocumentFragment ( ) ;
var selFragment = result . selection = document . createDocumentFragment ( ) ;
for ( var i = 0 ; i < doc . sel . ranges . length ; i ++ ) {
if ( primary === false && i == doc . sel . primIndex ) { continue }
var range$$1 = doc . sel . ranges [ i ] ;
if ( range$$1 . from ( ) . line >= cm . display . viewTo || range$$1 . to ( ) . line < cm . display . viewFrom ) { continue }
var collapsed = range$$1 . empty ( ) ;
if ( collapsed || cm . options . showCursorWhenSelecting )
{ drawSelectionCursor ( cm , range$$1 . head , curFragment ) ; }
if ( ! collapsed )
{ drawSelectionRange ( cm , range$$1 , selFragment ) ; }
}
return result
}
// Draws a cursor for the given range
function drawSelectionCursor ( cm , head , output ) {
var pos = cursorCoords ( cm , head , "div" , null , null , ! cm . options . singleCursorHeightPerLine ) ;
var cursor = output . appendChild ( elt ( "div" , "\u00a0" , "CodeMirror-cursor" ) ) ;
cursor . style . left = pos . left + "px" ;
cursor . style . top = pos . top + "px" ;
cursor . style . height = Math . max ( 0 , pos . bottom - pos . top ) * cm . options . cursorHeight + "px" ;
if ( pos . other ) {
// Secondary cursor, shown when on a 'jump' in bi-directional text
var otherCursor = output . appendChild ( elt ( "div" , "\u00a0" , "CodeMirror-cursor CodeMirror-secondarycursor" ) ) ;
otherCursor . style . display = "" ;
otherCursor . style . left = pos . other . left + "px" ;
otherCursor . style . top = pos . other . top + "px" ;
otherCursor . style . height = ( pos . other . bottom - pos . other . top ) * . 85 + "px" ;
}
}
// Draws the given range as a highlighted selection
function drawSelectionRange ( cm , range$$1 , output ) {
var display = cm . display , doc = cm . doc ;
var fragment = document . createDocumentFragment ( ) ;
var padding = paddingH ( cm . display ) , leftSide = padding . left ;
var rightSide = Math . max ( display . sizerWidth , displayWidth ( cm ) - display . sizer . offsetLeft ) - padding . right ;
function add ( left , top , width , bottom ) {
if ( top < 0 ) { top = 0 ; }
top = Math . round ( top ) ;
bottom = Math . round ( bottom ) ;
fragment . appendChild ( elt ( "div" , null , "CodeMirror-selected" , ( "position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + ( width == null ? rightSide - left : width ) + "px;\n height: " + ( bottom - top ) + "px" ) ) ) ;
}
function drawForLine ( line , fromArg , toArg ) {
var lineObj = getLine ( doc , line ) ;
var lineLen = lineObj . text . length ;
var start , end ;
function coords ( ch , bias ) {
return charCoords ( cm , Pos ( line , ch ) , "div" , lineObj , bias )
}
iterateBidiSections ( getOrder ( lineObj , doc . direction ) , fromArg || 0 , toArg == null ? lineLen : toArg , function ( from , to , dir ) {
var leftPos = coords ( from , "left" ) , rightPos , left , right ;
if ( from == to ) {
rightPos = leftPos ;
left = right = leftPos . left ;
} else {
rightPos = coords ( to - 1 , "right" ) ;
if ( dir == "rtl" ) { var tmp = leftPos ; leftPos = rightPos ; rightPos = tmp ; }
left = leftPos . left ;
right = rightPos . right ;
}
if ( fromArg == null && from == 0 ) { left = leftSide ; }
if ( rightPos . top - leftPos . top > 3 ) { // Different lines, draw top part
add ( left , leftPos . top , null , leftPos . bottom ) ;
left = leftSide ;
if ( leftPos . bottom < rightPos . top ) { add ( left , leftPos . bottom , null , rightPos . top ) ; }
}
if ( toArg == null && to == lineLen ) { right = rightSide ; }
if ( ! start || leftPos . top < start . top || leftPos . top == start . top && leftPos . left < start . left )
{ start = leftPos ; }
if ( ! end || rightPos . bottom > end . bottom || rightPos . bottom == end . bottom && rightPos . right > end . right )
{ end = rightPos ; }
if ( left < leftSide + 1 ) { left = leftSide ; }
add ( left , rightPos . top , right - left , rightPos . bottom ) ;
} ) ;
return { start : start , end : end }
}
var sFrom = range$$1 . from ( ) , sTo = range$$1 . to ( ) ;
if ( sFrom . line == sTo . line ) {
drawForLine ( sFrom . line , sFrom . ch , sTo . ch ) ;
} else {
var fromLine = getLine ( doc , sFrom . line ) , toLine = getLine ( doc , sTo . line ) ;
var singleVLine = visualLine ( fromLine ) == visualLine ( toLine ) ;
var leftEnd = drawForLine ( sFrom . line , sFrom . ch , singleVLine ? fromLine . text . length + 1 : null ) . end ;
var rightStart = drawForLine ( sTo . line , singleVLine ? 0 : null , sTo . ch ) . start ;
if ( singleVLine ) {
if ( leftEnd . top < rightStart . top - 2 ) {
add ( leftEnd . right , leftEnd . top , null , leftEnd . bottom ) ;
add ( leftSide , rightStart . top , rightStart . left , rightStart . bottom ) ;
} else {
add ( leftEnd . right , leftEnd . top , rightStart . left - leftEnd . right , leftEnd . bottom ) ;
}
}
if ( leftEnd . bottom < rightStart . top )
{ add ( leftSide , leftEnd . bottom , null , rightStart . top ) ; }
}
output . appendChild ( fragment ) ;
}
// Cursor-blinking
function restartBlink ( cm ) {
if ( ! cm . state . focused ) { return }
var display = cm . display ;
clearInterval ( display . blinker ) ;
var on = true ;
display . cursorDiv . style . visibility = "" ;
if ( cm . options . cursorBlinkRate > 0 )
{ display . blinker = setInterval ( function ( ) { return display . cursorDiv . style . visibility = ( on = ! on ) ? "" : "hidden" ; } ,
cm . options . cursorBlinkRate ) ; }
else if ( cm . options . cursorBlinkRate < 0 )
{ display . cursorDiv . style . visibility = "hidden" ; }
}
function ensureFocus ( cm ) {
if ( ! cm . state . focused ) { cm . display . input . focus ( ) ; onFocus ( cm ) ; }
}
function delayBlurEvent ( cm ) {
cm . state . delayingBlurEvent = true ;
setTimeout ( function ( ) { if ( cm . state . delayingBlurEvent ) {
cm . state . delayingBlurEvent = false ;
onBlur ( cm ) ;
} } , 100 ) ;
}
function onFocus ( cm , e ) {
if ( cm . state . delayingBlurEvent ) { cm . state . delayingBlurEvent = false ; }
if ( cm . options . readOnly == "nocursor" ) { return }
if ( ! cm . state . focused ) {
signal ( cm , "focus" , cm , e ) ;
cm . state . focused = true ;
addClass ( cm . display . wrapper , "CodeMirror-focused" ) ;
// This test prevents this from firing when a context
// menu is closed (since the input reset would kill the
// select-all detection hack)
if ( ! cm . curOp && cm . display . selForContextMenu != cm . doc . sel ) {
cm . display . input . reset ( ) ;
if ( webkit ) { setTimeout ( function ( ) { return cm . display . input . reset ( true ) ; } , 20 ) ; } // Issue #1730
}
cm . display . input . receivedFocus ( ) ;
}
restartBlink ( cm ) ;
}
function onBlur ( cm , e ) {
if ( cm . state . delayingBlurEvent ) { return }
if ( cm . state . focused ) {
signal ( cm , "blur" , cm , e ) ;
cm . state . focused = false ;
rmClass ( cm . display . wrapper , "CodeMirror-focused" ) ;
}
clearInterval ( cm . display . blinker ) ;
setTimeout ( function ( ) { if ( ! cm . state . focused ) { cm . display . shift = false ; } } , 150 ) ;
}
// Read the actual heights of the rendered lines, and update their
// stored heights to match.
function updateHeightsInViewport ( cm ) {
var display = cm . display ;
var prevBottom = display . lineDiv . offsetTop ;
for ( var i = 0 ; i < display . view . length ; i ++ ) {
var cur = display . view [ i ] , height = ( void 0 ) ;
if ( cur . hidden ) { continue }
if ( ie && ie _version < 8 ) {
var bot = cur . node . offsetTop + cur . node . offsetHeight ;
height = bot - prevBottom ;
prevBottom = bot ;
} else {
var box = cur . node . getBoundingClientRect ( ) ;
height = box . bottom - box . top ;
}
var diff = cur . line . height - height ;
if ( height < 2 ) { height = textHeight ( display ) ; }
if ( diff > . 001 || diff < - . 001 ) {
updateLineHeight ( cur . line , height ) ;
updateWidgetHeight ( cur . line ) ;
if ( cur . rest ) { for ( var j = 0 ; j < cur . rest . length ; j ++ )
{ updateWidgetHeight ( cur . rest [ j ] ) ; } }
}
}
}
// Read and store the height of line widgets associated with the
// given line.
function updateWidgetHeight ( line ) {
if ( line . widgets ) { for ( var i = 0 ; i < line . widgets . length ; ++ i )
{ line . widgets [ i ] . height = line . widgets [ i ] . node . parentNode . offsetHeight ; } }
}
// Compute the lines that are visible in a given viewport (defaults
// the the current scroll position). viewport may contain top,
// height, and ensure (see op.scrollToPos) properties.
function visibleLines ( display , doc , viewport ) {
var top = viewport && viewport . top != null ? Math . max ( 0 , viewport . top ) : display . scroller . scrollTop ;
top = Math . floor ( top - paddingTop ( display ) ) ;
var bottom = viewport && viewport . bottom != null ? viewport . bottom : top + display . wrapper . clientHeight ;
var from = lineAtHeight ( doc , top ) , to = lineAtHeight ( doc , bottom ) ;
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
// forces those lines into the viewport (if possible).
if ( viewport && viewport . ensure ) {
var ensureFrom = viewport . ensure . from . line , ensureTo = viewport . ensure . to . line ;
if ( ensureFrom < from ) {
from = ensureFrom ;
to = lineAtHeight ( doc , heightAtLine ( getLine ( doc , ensureFrom ) ) + display . wrapper . clientHeight ) ;
} else if ( Math . min ( ensureTo , doc . lastLine ( ) ) >= to ) {
from = lineAtHeight ( doc , heightAtLine ( getLine ( doc , ensureTo ) ) - display . wrapper . clientHeight ) ;
to = ensureTo ;
}
}
return { from : from , to : Math . max ( to , from + 1 ) }
}
// Re-align line numbers and gutter marks to compensate for
// horizontal scrolling.
function alignHorizontally ( cm ) {
var display = cm . display , view = display . view ;
if ( ! display . alignWidgets && ( ! display . gutters . firstChild || ! cm . options . fixedGutter ) ) { return }
var comp = compensateForHScroll ( display ) - display . scroller . scrollLeft + cm . doc . scrollLeft ;
var gutterW = display . gutters . offsetWidth , left = comp + "px" ;
for ( var i = 0 ; i < view . length ; i ++ ) { if ( ! view [ i ] . hidden ) {
if ( cm . options . fixedGutter ) {
if ( view [ i ] . gutter )
{ view [ i ] . gutter . style . left = left ; }
if ( view [ i ] . gutterBackground )
{ view [ i ] . gutterBackground . style . left = left ; }
}
var align = view [ i ] . alignable ;
if ( align ) { for ( var j = 0 ; j < align . length ; j ++ )
{ align [ j ] . style . left = left ; } }
} }
if ( cm . options . fixedGutter )
{ display . gutters . style . left = ( comp + gutterW ) + "px" ; }
}
// Used to ensure that the line number gutter is still the right
// size for the current document size. Returns true when an update
// is needed.
function maybeUpdateLineNumberWidth ( cm ) {
if ( ! cm . options . lineNumbers ) { return false }
var doc = cm . doc , last = lineNumberFor ( cm . options , doc . first + doc . size - 1 ) , display = cm . display ;
if ( last . length != display . lineNumChars ) {
var test = display . measure . appendChild ( elt ( "div" , [ elt ( "div" , last ) ] ,
"CodeMirror-linenumber CodeMirror-gutter-elt" ) ) ;
var innerW = test . firstChild . offsetWidth , padding = test . offsetWidth - innerW ;
display . lineGutter . style . width = "" ;
display . lineNumInnerWidth = Math . max ( innerW , display . lineGutter . offsetWidth - padding ) + 1 ;
display . lineNumWidth = display . lineNumInnerWidth + padding ;
display . lineNumChars = display . lineNumInnerWidth ? last . length : - 1 ;
display . lineGutter . style . width = display . lineNumWidth + "px" ;
updateGutterSpace ( cm ) ;
return true
}
return false
}
// SCROLLING THINGS INTO VIEW
// If an editor sits on the top or bottom of the window, partially
// scrolled out of view, this ensures that the cursor is visible.
function maybeScrollWindow ( cm , rect ) {
if ( signalDOMEvent ( cm , "scrollCursorIntoView" ) ) { return }
var display = cm . display , box = display . sizer . getBoundingClientRect ( ) , doScroll = null ;
if ( rect . top + box . top < 0 ) { doScroll = true ; }
else if ( rect . bottom + box . top > ( window . innerHeight || document . documentElement . clientHeight ) ) { doScroll = false ; }
if ( doScroll != null && ! phantom ) {
var scrollNode = elt ( "div" , "\u200b" , null , ( "position: absolute;\n top: " + ( rect . top - display . viewOffset - paddingTop ( cm . display ) ) + "px;\n height: " + ( rect . bottom - rect . top + scrollGap ( cm ) + display . barHeight ) + "px;\n left: " + ( rect . left ) + "px; width: " + ( Math . max ( 2 , rect . right - rect . left ) ) + "px;" ) ) ;
cm . display . lineSpace . appendChild ( scrollNode ) ;
scrollNode . scrollIntoView ( doScroll ) ;
cm . display . lineSpace . removeChild ( scrollNode ) ;
}
}
// Scroll a given position into view (immediately), verifying that
// it actually became visible (as line heights are accurately
// measured, the position of something may 'drift' during drawing).
function scrollPosIntoView ( cm , pos , end , margin ) {
if ( margin == null ) { margin = 0 ; }
var rect ;
for ( var limit = 0 ; limit < 5 ; limit ++ ) {
var changed = false ;
var coords = cursorCoords ( cm , pos ) ;
var endCoords = ! end || end == pos ? coords : cursorCoords ( cm , end ) ;
rect = { left : Math . min ( coords . left , endCoords . left ) ,
top : Math . min ( coords . top , endCoords . top ) - margin ,
right : Math . max ( coords . left , endCoords . left ) ,
bottom : Math . max ( coords . bottom , endCoords . bottom ) + margin } ;
var scrollPos = calculateScrollPos ( cm , rect ) ;
var startTop = cm . doc . scrollTop , startLeft = cm . doc . scrollLeft ;
if ( scrollPos . scrollTop != null ) {
updateScrollTop ( cm , scrollPos . scrollTop ) ;
if ( Math . abs ( cm . doc . scrollTop - startTop ) > 1 ) { changed = true ; }
}
if ( scrollPos . scrollLeft != null ) {
setScrollLeft ( cm , scrollPos . scrollLeft ) ;
if ( Math . abs ( cm . doc . scrollLeft - startLeft ) > 1 ) { changed = true ; }
}
if ( ! changed ) { break }
}
return rect
}
// Scroll a given set of coordinates into view (immediately).
function scrollIntoView ( cm , rect ) {
var scrollPos = calculateScrollPos ( cm , rect ) ;
if ( scrollPos . scrollTop != null ) { updateScrollTop ( cm , scrollPos . scrollTop ) ; }
if ( scrollPos . scrollLeft != null ) { setScrollLeft ( cm , scrollPos . scrollLeft ) ; }
}
// Calculate a new scroll position needed to scroll the given
// rectangle into view. Returns an object with scrollTop and
// scrollLeft properties. When these are undefined, the
// vertical/horizontal position does not need to be adjusted.
function calculateScrollPos ( cm , rect ) {
var display = cm . display , snapMargin = textHeight ( cm . display ) ;
if ( rect . top < 0 ) { rect . top = 0 ; }
var screentop = cm . curOp && cm . curOp . scrollTop != null ? cm . curOp . scrollTop : display . scroller . scrollTop ;
var screen = displayHeight ( cm ) , result = { } ;
if ( rect . bottom - rect . top > screen ) { rect . bottom = rect . top + screen ; }
var docBottom = cm . doc . height + paddingVert ( display ) ;
var atTop = rect . top < snapMargin , atBottom = rect . bottom > docBottom - snapMargin ;
if ( rect . top < screentop ) {
result . scrollTop = atTop ? 0 : rect . top ;
} else if ( rect . bottom > screentop + screen ) {
var newTop = Math . min ( rect . top , ( atBottom ? docBottom : rect . bottom ) - screen ) ;
if ( newTop != screentop ) { result . scrollTop = newTop ; }
}
var screenleft = cm . curOp && cm . curOp . scrollLeft != null ? cm . curOp . scrollLeft : display . scroller . scrollLeft ;
var screenw = displayWidth ( cm ) - ( cm . options . fixedGutter ? display . gutters . offsetWidth : 0 ) ;
var tooWide = rect . right - rect . left > screenw ;
if ( tooWide ) { rect . right = rect . left + screenw ; }
if ( rect . left < 10 )
{ result . scrollLeft = 0 ; }
else if ( rect . left < screenleft )
{ result . scrollLeft = Math . max ( 0 , rect . left - ( tooWide ? 0 : 10 ) ) ; }
else if ( rect . right > screenw + screenleft - 3 )
{ result . scrollLeft = rect . right + ( tooWide ? 0 : 10 ) - screenw ; }
return result
}
// Store a relative adjustment to the scroll position in the current
// operation (to be applied when the operation finishes).
function addToScrollTop ( cm , top ) {
if ( top == null ) { return }
resolveScrollToPos ( cm ) ;
cm . curOp . scrollTop = ( cm . curOp . scrollTop == null ? cm . doc . scrollTop : cm . curOp . scrollTop ) + top ;
}
// Make sure that at the end of the operation the current cursor is
// shown.
function ensureCursorVisible ( cm ) {
resolveScrollToPos ( cm ) ;
var cur = cm . getCursor ( ) , from = cur , to = cur ;
if ( ! cm . options . lineWrapping ) {
from = cur . ch ? Pos ( cur . line , cur . ch - 1 ) : cur ;
to = Pos ( cur . line , cur . ch + 1 ) ;
}
cm . curOp . scrollToPos = { from : from , to : to , margin : cm . options . cursorScrollMargin } ;
}
function scrollToCoords ( cm , x , y ) {
if ( x != null || y != null ) { resolveScrollToPos ( cm ) ; }
if ( x != null ) { cm . curOp . scrollLeft = x ; }
if ( y != null ) { cm . curOp . scrollTop = y ; }
}
function scrollToRange ( cm , range$$1 ) {
resolveScrollToPos ( cm ) ;
cm . curOp . scrollToPos = range$$1 ;
}
// When an operation has its scrollToPos property set, and another
// scroll action is applied before the end of the operation, this
// 'simulates' scrolling that position into view in a cheap way, so
// that the effect of intermediate scroll commands is not ignored.
function resolveScrollToPos ( cm ) {
var range$$1 = cm . curOp . scrollToPos ;
if ( range$$1 ) {
cm . curOp . scrollToPos = null ;
var from = estimateCoords ( cm , range$$1 . from ) , to = estimateCoords ( cm , range$$1 . to ) ;
scrollToCoordsRange ( cm , from , to , range$$1 . margin ) ;
}
}
function scrollToCoordsRange ( cm , from , to , margin ) {
var sPos = calculateScrollPos ( cm , {
left : Math . min ( from . left , to . left ) ,
top : Math . min ( from . top , to . top ) - margin ,
right : Math . max ( from . right , to . right ) ,
bottom : Math . max ( from . bottom , to . bottom ) + margin
} ) ;
scrollToCoords ( cm , sPos . scrollLeft , sPos . scrollTop ) ;
}
// Sync the scrollable area and scrollbars, ensure the viewport
// covers the visible area.
function updateScrollTop ( cm , val ) {
if ( Math . abs ( cm . doc . scrollTop - val ) < 2 ) { return }
if ( ! gecko ) { updateDisplaySimple ( cm , { top : val } ) ; }
setScrollTop ( cm , val , true ) ;
if ( gecko ) { updateDisplaySimple ( cm ) ; }
startWorker ( cm , 100 ) ;
}
function setScrollTop ( cm , val , forceScroll ) {
val = Math . min ( cm . display . scroller . scrollHeight - cm . display . scroller . clientHeight , val ) ;
if ( cm . display . scroller . scrollTop == val && ! forceScroll ) { return }
cm . doc . scrollTop = val ;
cm . display . scrollbars . setScrollTop ( val ) ;
if ( cm . display . scroller . scrollTop != val ) { cm . display . scroller . scrollTop = val ; }
}
// Sync scroller and scrollbar, ensure the gutter elements are
// aligned.
function setScrollLeft ( cm , val , isScroller , forceScroll ) {
val = Math . min ( val , cm . display . scroller . scrollWidth - cm . display . scroller . clientWidth ) ;
if ( ( isScroller ? val == cm . doc . scrollLeft : Math . abs ( cm . doc . scrollLeft - val ) < 2 ) && ! forceScroll ) { return }
cm . doc . scrollLeft = val ;
alignHorizontally ( cm ) ;
if ( cm . display . scroller . scrollLeft != val ) { cm . display . scroller . scrollLeft = val ; }
cm . display . scrollbars . setScrollLeft ( val ) ;
}
// SCROLLBARS
// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
function measureForScrollbars ( cm ) {
var d = cm . display , gutterW = d . gutters . offsetWidth ;
var docH = Math . round ( cm . doc . height + paddingVert ( cm . display ) ) ;
return {
clientHeight : d . scroller . clientHeight ,
viewHeight : d . wrapper . clientHeight ,
scrollWidth : d . scroller . scrollWidth , clientWidth : d . scroller . clientWidth ,
viewWidth : d . wrapper . clientWidth ,
barLeft : cm . options . fixedGutter ? gutterW : 0 ,
docHeight : docH ,
scrollHeight : docH + scrollGap ( cm ) + d . barHeight ,
nativeBarWidth : d . nativeBarWidth ,
gutterWidth : gutterW
}
}
var NativeScrollbars = function ( place , scroll , cm ) {
this . cm = cm ;
var vert = this . vert = elt ( "div" , [ elt ( "div" , null , null , "min-width: 1px" ) ] , "CodeMirror-vscrollbar" ) ;
var horiz = this . horiz = elt ( "div" , [ elt ( "div" , null , null , "height: 100%; min-height: 1px" ) ] , "CodeMirror-hscrollbar" ) ;
place ( vert ) ; place ( horiz ) ;
on ( vert , "scroll" , function ( ) {
if ( vert . clientHeight ) { scroll ( vert . scrollTop , "vertical" ) ; }
} ) ;
on ( horiz , "scroll" , function ( ) {
if ( horiz . clientWidth ) { scroll ( horiz . scrollLeft , "horizontal" ) ; }
} ) ;
this . checkedZeroWidth = false ;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if ( ie && ie _version < 8 ) { this . horiz . style . minHeight = this . vert . style . minWidth = "18px" ; }
} ;
NativeScrollbars . prototype . update = function ( measure ) {
var needsH = measure . scrollWidth > measure . clientWidth + 1 ;
var needsV = measure . scrollHeight > measure . clientHeight + 1 ;
var sWidth = measure . nativeBarWidth ;
if ( needsV ) {
this . vert . style . display = "block" ;
this . vert . style . bottom = needsH ? sWidth + "px" : "0" ;
var totalHeight = measure . viewHeight - ( needsH ? sWidth : 0 ) ;
// A bug in IE8 can cause this value to be negative, so guard it.
this . vert . firstChild . style . height =
Math . max ( 0 , measure . scrollHeight - measure . clientHeight + totalHeight ) + "px" ;
} else {
this . vert . style . display = "" ;
this . vert . firstChild . style . height = "0" ;
}
if ( needsH ) {
this . horiz . style . display = "block" ;
this . horiz . style . right = needsV ? sWidth + "px" : "0" ;
this . horiz . style . left = measure . barLeft + "px" ;
var totalWidth = measure . viewWidth - measure . barLeft - ( needsV ? sWidth : 0 ) ;
this . horiz . firstChild . style . width =
Math . max ( 0 , measure . scrollWidth - measure . clientWidth + totalWidth ) + "px" ;
} else {
this . horiz . style . display = "" ;
this . horiz . firstChild . style . width = "0" ;
}
if ( ! this . checkedZeroWidth && measure . clientHeight > 0 ) {
if ( sWidth == 0 ) { this . zeroWidthHack ( ) ; }
this . checkedZeroWidth = true ;
}
return { right : needsV ? sWidth : 0 , bottom : needsH ? sWidth : 0 }
} ;
NativeScrollbars . prototype . setScrollLeft = function ( pos ) {
if ( this . horiz . scrollLeft != pos ) { this . horiz . scrollLeft = pos ; }
if ( this . disableHoriz ) { this . enableZeroWidthBar ( this . horiz , this . disableHoriz , "horiz" ) ; }
} ;
NativeScrollbars . prototype . setScrollTop = function ( pos ) {
if ( this . vert . scrollTop != pos ) { this . vert . scrollTop = pos ; }
if ( this . disableVert ) { this . enableZeroWidthBar ( this . vert , this . disableVert , "vert" ) ; }
} ;
NativeScrollbars . prototype . zeroWidthHack = function ( ) {
var w = mac && ! mac _geMountainLion ? "12px" : "18px" ;
this . horiz . style . height = this . vert . style . width = w ;
this . horiz . style . pointerEvents = this . vert . style . pointerEvents = "none" ;
this . disableHoriz = new Delayed ;
this . disableVert = new Delayed ;
} ;
NativeScrollbars . prototype . enableZeroWidthBar = function ( bar , delay , type ) {
bar . style . pointerEvents = "auto" ;
function maybeDisable ( ) {
// To find out whether the scrollbar is still visible, we
// check whether the element under the pixel in the bottom
// right corner of the scrollbar box is the scrollbar box
// itself (when the bar is still visible) or its filler child
// (when the bar is hidden). If it is still visible, we keep
// it enabled, if it's hidden, we disable pointer events.
var box = bar . getBoundingClientRect ( ) ;
var elt$$1 = type == "vert" ? document . elementFromPoint ( box . right - 1 , ( box . top + box . bottom ) / 2 )
: document . elementFromPoint ( ( box . right + box . left ) / 2 , box . bottom - 1 ) ;
if ( elt$$1 != bar ) { bar . style . pointerEvents = "none" ; }
else { delay . set ( 1000 , maybeDisable ) ; }
}
delay . set ( 1000 , maybeDisable ) ;
} ;
NativeScrollbars . prototype . clear = function ( ) {
var parent = this . horiz . parentNode ;
parent . removeChild ( this . horiz ) ;
parent . removeChild ( this . vert ) ;
} ;
var NullScrollbars = function ( ) { } ;
NullScrollbars . prototype . update = function ( ) { return { bottom : 0 , right : 0 } } ;
NullScrollbars . prototype . setScrollLeft = function ( ) { } ;
NullScrollbars . prototype . setScrollTop = function ( ) { } ;
NullScrollbars . prototype . clear = function ( ) { } ;
function updateScrollbars ( cm , measure ) {
if ( ! measure ) { measure = measureForScrollbars ( cm ) ; }
var startWidth = cm . display . barWidth , startHeight = cm . display . barHeight ;
updateScrollbarsInner ( cm , measure ) ;
for ( var i = 0 ; i < 4 && startWidth != cm . display . barWidth || startHeight != cm . display . barHeight ; i ++ ) {
if ( startWidth != cm . display . barWidth && cm . options . lineWrapping )
{ updateHeightsInViewport ( cm ) ; }
updateScrollbarsInner ( cm , measureForScrollbars ( cm ) ) ;
startWidth = cm . display . barWidth ; startHeight = cm . display . barHeight ;
}
}
// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner ( cm , measure ) {
var d = cm . display ;
var sizes = d . scrollbars . update ( measure ) ;
d . sizer . style . paddingRight = ( d . barWidth = sizes . right ) + "px" ;
d . sizer . style . paddingBottom = ( d . barHeight = sizes . bottom ) + "px" ;
d . heightForcer . style . borderBottom = sizes . bottom + "px solid transparent" ;
if ( sizes . right && sizes . bottom ) {
d . scrollbarFiller . style . display = "block" ;
d . scrollbarFiller . style . height = sizes . bottom + "px" ;
d . scrollbarFiller . style . width = sizes . right + "px" ;
} else { d . scrollbarFiller . style . display = "" ; }
if ( sizes . bottom && cm . options . coverGutterNextToScrollbar && cm . options . fixedGutter ) {
d . gutterFiller . style . display = "block" ;
d . gutterFiller . style . height = sizes . bottom + "px" ;
d . gutterFiller . style . width = measure . gutterWidth + "px" ;
} else { d . gutterFiller . style . display = "" ; }
}
var scrollbarModel = { "native" : NativeScrollbars , "null" : NullScrollbars } ;
function initScrollbars ( cm ) {
if ( cm . display . scrollbars ) {
cm . display . scrollbars . clear ( ) ;
if ( cm . display . scrollbars . addClass )
{ rmClass ( cm . display . wrapper , cm . display . scrollbars . addClass ) ; }
}
cm . display . scrollbars = new scrollbarModel [ cm . options . scrollbarStyle ] ( function ( node ) {
cm . display . wrapper . insertBefore ( node , cm . display . scrollbarFiller ) ;
// Prevent clicks in the scrollbars from killing focus
on ( node , "mousedown" , function ( ) {
if ( cm . state . focused ) { setTimeout ( function ( ) { return cm . display . input . focus ( ) ; } , 0 ) ; }
} ) ;
node . setAttribute ( "cm-not-content" , "true" ) ;
} , function ( pos , axis ) {
if ( axis == "horizontal" ) { setScrollLeft ( cm , pos ) ; }
else { updateScrollTop ( cm , pos ) ; }
} , cm ) ;
if ( cm . display . scrollbars . addClass )
{ addClass ( cm . display . wrapper , cm . display . scrollbars . addClass ) ; }
}
// Operations are used to wrap a series of changes to the editor
// state in such a way that each change won't have to update the
// cursor and display (which would be awkward, slow, and
// error-prone). Instead, display updates are batched and then all
// combined and executed at once.
var nextOpId = 0 ;
// Start a new operation.
function startOperation ( cm ) {
cm . curOp = {
cm : cm ,
viewChanged : false , // Flag that indicates that lines might need to be redrawn
startHeight : cm . doc . height , // Used to detect need to update scrollbar
forceUpdate : false , // Used to force a redraw
updateInput : null , // Whether to reset the input textarea
typing : false , // Whether this reset should be careful to leave existing text (for compositing)
changeObjs : null , // Accumulated changes, for firing change events
cursorActivityHandlers : null , // Set of handlers to fire cursorActivity on
cursorActivityCalled : 0 , // Tracks which cursorActivity handlers have been called already
selectionChanged : false , // Whether the selection needs to be redrawn
updateMaxLine : false , // Set when the widest line needs to be determined anew
scrollLeft : null , scrollTop : null , // Intermediate scroll position, not pushed to DOM yet
scrollToPos : null , // Used to scroll to a specific position
focus : false ,
id : ++ nextOpId // Unique ID
} ;
pushOperation ( cm . curOp ) ;
}
// Finish an operation, updating the display and signalling delayed events
function endOperation ( cm ) {
var op = cm . curOp ;
finishOperation ( op , function ( group ) {
for ( var i = 0 ; i < group . ops . length ; i ++ )
{ group . ops [ i ] . cm . curOp = null ; }
endOperations ( group ) ;
} ) ;
}
// The DOM updates done when an operation finishes are batched so
// that the minimum number of relayouts are required.
function endOperations ( group ) {
var ops = group . ops ;
for ( var i = 0 ; i < ops . length ; i ++ ) // Read DOM
{ endOperation _R1 ( ops [ i ] ) ; }
for ( var i$1 = 0 ; i$1 < ops . length ; i$1 ++ ) // Write DOM (maybe)
{ endOperation _W1 ( ops [ i$1 ] ) ; }
for ( var i$2 = 0 ; i$2 < ops . length ; i$2 ++ ) // Read DOM
{ endOperation _R2 ( ops [ i$2 ] ) ; }
for ( var i$3 = 0 ; i$3 < ops . length ; i$3 ++ ) // Write DOM (maybe)
{ endOperation _W2 ( ops [ i$3 ] ) ; }
for ( var i$4 = 0 ; i$4 < ops . length ; i$4 ++ ) // Read DOM
{ endOperation _finish ( ops [ i$4 ] ) ; }
}
function endOperation _R1 ( op ) {
var cm = op . cm , display = cm . display ;
maybeClipScrollbars ( cm ) ;
if ( op . updateMaxLine ) { findMaxLine ( cm ) ; }
op . mustUpdate = op . viewChanged || op . forceUpdate || op . scrollTop != null ||
op . scrollToPos && ( op . scrollToPos . from . line < display . viewFrom ||
op . scrollToPos . to . line >= display . viewTo ) ||
display . maxLineChanged && cm . options . lineWrapping ;
op . update = op . mustUpdate &&
new DisplayUpdate ( cm , op . mustUpdate && { top : op . scrollTop , ensure : op . scrollToPos } , op . forceUpdate ) ;
}
function endOperation _W1 ( op ) {
op . updatedDisplay = op . mustUpdate && updateDisplayIfNeeded ( op . cm , op . update ) ;
}
function endOperation _R2 ( op ) {
var cm = op . cm , display = cm . display ;
if ( op . updatedDisplay ) { updateHeightsInViewport ( cm ) ; }
op . barMeasure = measureForScrollbars ( cm ) ;
// If the max line changed since it was last measured, measure it,
// and ensure the document's width matches it.
// updateDisplay_W2 will use these properties to do the actual resizing
if ( display . maxLineChanged && ! cm . options . lineWrapping ) {
op . adjustWidthTo = measureChar ( cm , display . maxLine , display . maxLine . text . length ) . left + 3 ;
cm . display . sizerWidth = op . adjustWidthTo ;
op . barMeasure . scrollWidth =
Math . max ( display . scroller . clientWidth , display . sizer . offsetLeft + op . adjustWidthTo + scrollGap ( cm ) + cm . display . barWidth ) ;
op . maxScrollLeft = Math . max ( 0 , display . sizer . offsetLeft + op . adjustWidthTo - displayWidth ( cm ) ) ;
}
if ( op . updatedDisplay || op . selectionChanged )
{ op . preparedSelection = display . input . prepareSelection ( op . focus ) ; }
}
function endOperation _W2 ( op ) {
var cm = op . cm ;
if ( op . adjustWidthTo != null ) {
cm . display . sizer . style . minWidth = op . adjustWidthTo + "px" ;
if ( op . maxScrollLeft < cm . doc . scrollLeft )
{ setScrollLeft ( cm , Math . min ( cm . display . scroller . scrollLeft , op . maxScrollLeft ) , true ) ; }
cm . display . maxLineChanged = false ;
}
var takeFocus = op . focus && op . focus == activeElt ( ) && ( ! document . hasFocus || document . hasFocus ( ) ) ;
if ( op . preparedSelection )
{ cm . display . input . showSelection ( op . preparedSelection , takeFocus ) ; }
if ( op . updatedDisplay || op . startHeight != cm . doc . height )
{ updateScrollbars ( cm , op . barMeasure ) ; }
if ( op . updatedDisplay )
{ setDocumentHeight ( cm , op . barMeasure ) ; }
if ( op . selectionChanged ) { restartBlink ( cm ) ; }
if ( cm . state . focused && op . updateInput )
{ cm . display . input . reset ( op . typing ) ; }
if ( takeFocus ) { ensureFocus ( op . cm ) ; }
}
function endOperation _finish ( op ) {
var cm = op . cm , display = cm . display , doc = cm . doc ;
if ( op . updatedDisplay ) { postUpdateDisplay ( cm , op . update ) ; }
// Abort mouse wheel delta measurement, when scrolling explicitly
if ( display . wheelStartX != null && ( op . scrollTop != null || op . scrollLeft != null || op . scrollToPos ) )
{ display . wheelStartX = display . wheelStartY = null ; }
// Propagate the scroll position to the actual DOM scroller
if ( op . scrollTop != null ) { setScrollTop ( cm , op . scrollTop , op . forceScroll ) ; }
if ( op . scrollLeft != null ) { setScrollLeft ( cm , op . scrollLeft , true , true ) ; }
// If we need to scroll a specific position into view, do so.
if ( op . scrollToPos ) {
var rect = scrollPosIntoView ( cm , clipPos ( doc , op . scrollToPos . from ) ,
clipPos ( doc , op . scrollToPos . to ) , op . scrollToPos . margin ) ;
maybeScrollWindow ( cm , rect ) ;
}
// Fire events for markers that are hidden/unidden by editing or
// undoing
var hidden = op . maybeHiddenMarkers , unhidden = op . maybeUnhiddenMarkers ;
if ( hidden ) { for ( var i = 0 ; i < hidden . length ; ++ i )
{ if ( ! hidden [ i ] . lines . length ) { signal ( hidden [ i ] , "hide" ) ; } } }
if ( unhidden ) { for ( var i$1 = 0 ; i$1 < unhidden . length ; ++ i$1 )
{ if ( unhidden [ i$1 ] . lines . length ) { signal ( unhidden [ i$1 ] , "unhide" ) ; } } }
if ( display . wrapper . offsetHeight )
{ doc . scrollTop = cm . display . scroller . scrollTop ; }
// Fire change events, and delayed event handlers
if ( op . changeObjs )
{ signal ( cm , "changes" , cm , op . changeObjs ) ; }
if ( op . update )
{ op . update . finish ( ) ; }
}
// Run the given function in an operation
function runInOp ( cm , f ) {
if ( cm . curOp ) { return f ( ) }
startOperation ( cm ) ;
try { return f ( ) }
finally { endOperation ( cm ) ; }
}
// Wraps a function in an operation. Returns the wrapped function.
function operation ( cm , f ) {
return function ( ) {
if ( cm . curOp ) { return f . apply ( cm , arguments ) }
startOperation ( cm ) ;
try { return f . apply ( cm , arguments ) }
finally { endOperation ( cm ) ; }
}
}
// Used to add methods to editor and doc instances, wrapping them in
// operations.
function methodOp ( f ) {
return function ( ) {
if ( this . curOp ) { return f . apply ( this , arguments ) }
startOperation ( this ) ;
try { return f . apply ( this , arguments ) }
finally { endOperation ( this ) ; }
}
}
function docMethodOp ( f ) {
return function ( ) {
var cm = this . cm ;
if ( ! cm || cm . curOp ) { return f . apply ( this , arguments ) }
startOperation ( cm ) ;
try { return f . apply ( this , arguments ) }
finally { endOperation ( cm ) ; }
}
}
// Updates the display.view data structure for a given change to the
// document. From and to are in pre-change coordinates. Lendiff is
// the amount of lines added or subtracted by the change. This is
// used for changes that span multiple lines, or change the way
// lines are divided into visual lines. regLineChange (below)
// registers single-line changes.
function regChange ( cm , from , to , lendiff ) {
if ( from == null ) { from = cm . doc . first ; }
if ( to == null ) { to = cm . doc . first + cm . doc . size ; }
if ( ! lendiff ) { lendiff = 0 ; }
var display = cm . display ;
if ( lendiff && to < display . viewTo &&
( display . updateLineNumbers == null || display . updateLineNumbers > from ) )
{ display . updateLineNumbers = from ; }
cm . curOp . viewChanged = true ;
if ( from >= display . viewTo ) { // Change after
if ( sawCollapsedSpans && visualLineNo ( cm . doc , from ) < display . viewTo )
{ resetView ( cm ) ; }
} else if ( to <= display . viewFrom ) { // Change before
if ( sawCollapsedSpans && visualLineEndNo ( cm . doc , to + lendiff ) > display . viewFrom ) {
resetView ( cm ) ;
} else {
display . viewFrom += lendiff ;
display . viewTo += lendiff ;
}
} else if ( from <= display . viewFrom && to >= display . viewTo ) { // Full overlap
resetView ( cm ) ;
} else if ( from <= display . viewFrom ) { // Top overlap
var cut = viewCuttingPoint ( cm , to , to + lendiff , 1 ) ;
if ( cut ) {
display . view = display . view . slice ( cut . index ) ;
display . viewFrom = cut . lineN ;
display . viewTo += lendiff ;
} else {
resetView ( cm ) ;
}
} else if ( to >= display . viewTo ) { // Bottom overlap
var cut$1 = viewCuttingPoint ( cm , from , from , - 1 ) ;
if ( cut$1 ) {
display . view = display . view . slice ( 0 , cut$1 . index ) ;
display . viewTo = cut$1 . lineN ;
} else {
resetView ( cm ) ;
}
} else { // Gap in the middle
var cutTop = viewCuttingPoint ( cm , from , from , - 1 ) ;
var cutBot = viewCuttingPoint ( cm , to , to + lendiff , 1 ) ;
if ( cutTop && cutBot ) {
display . view = display . view . slice ( 0 , cutTop . index )
. concat ( buildViewArray ( cm , cutTop . lineN , cutBot . lineN ) )
. concat ( display . view . slice ( cutBot . index ) ) ;
display . viewTo += lendiff ;
} else {
resetView ( cm ) ;
}
}
var ext = display . externalMeasured ;
if ( ext ) {
if ( to < ext . lineN )
{ ext . lineN += lendiff ; }
else if ( from < ext . lineN + ext . size )
{ display . externalMeasured = null ; }
}
}
// Register a change to a single line. Type must be one of "text",
// "gutter", "class", "widget"
function regLineChange ( cm , line , type ) {
cm . curOp . viewChanged = true ;
var display = cm . display , ext = cm . display . externalMeasured ;
if ( ext && line >= ext . lineN && line < ext . lineN + ext . size )
{ display . externalMeasured = null ; }
if ( line < display . viewFrom || line >= display . viewTo ) { return }
var lineView = display . view [ findViewIndex ( cm , line ) ] ;
if ( lineView . node == null ) { return }
var arr = lineView . changes || ( lineView . changes = [ ] ) ;
if ( indexOf ( arr , type ) == - 1 ) { arr . push ( type ) ; }
}
// Clear the view.
function resetView ( cm ) {
cm . display . viewFrom = cm . display . viewTo = cm . doc . first ;
cm . display . view = [ ] ;
cm . display . viewOffset = 0 ;
}
function viewCuttingPoint ( cm , oldN , newN , dir ) {
var index = findViewIndex ( cm , oldN ) , diff , view = cm . display . view ;
if ( ! sawCollapsedSpans || newN == cm . doc . first + cm . doc . size )
{ return { index : index , lineN : newN } }
var n = cm . display . viewFrom ;
for ( var i = 0 ; i < index ; i ++ )
{ n += view [ i ] . size ; }
if ( n != oldN ) {
if ( dir > 0 ) {
if ( index == view . length - 1 ) { return null }
diff = ( n + view [ index ] . size ) - oldN ;
index ++ ;
} else {
diff = n - oldN ;
}
oldN += diff ; newN += diff ;
}
while ( visualLineNo ( cm . doc , newN ) != newN ) {
if ( index == ( dir < 0 ? 0 : view . length - 1 ) ) { return null }
newN += dir * view [ index - ( dir < 0 ? 1 : 0 ) ] . size ;
index += dir ;
}
return { index : index , lineN : newN }
}
// Force the view to cover a given range, adding empty view element
// or clipping off existing ones as needed.
function adjustView ( cm , from , to ) {
var display = cm . display , view = display . view ;
if ( view . length == 0 || from >= display . viewTo || to <= display . viewFrom ) {
display . view = buildViewArray ( cm , from , to ) ;
display . viewFrom = from ;
} else {
if ( display . viewFrom > from )
{ display . view = buildViewArray ( cm , from , display . viewFrom ) . concat ( display . view ) ; }
else if ( display . viewFrom < from )
{ display . view = display . view . slice ( findViewIndex ( cm , from ) ) ; }
display . viewFrom = from ;
if ( display . viewTo < to )
{ display . view = display . view . concat ( buildViewArray ( cm , display . viewTo , to ) ) ; }
else if ( display . viewTo > to )
{ display . view = display . view . slice ( 0 , findViewIndex ( cm , to ) ) ; }
}
display . viewTo = to ;
}
// Count the number of lines in the view whose DOM representation is
// out of date (or nonexistent).
function countDirtyView ( cm ) {
var view = cm . display . view , dirty = 0 ;
for ( var i = 0 ; i < view . length ; i ++ ) {
var lineView = view [ i ] ;
if ( ! lineView . hidden && ( ! lineView . node || lineView . changes ) ) { ++ dirty ; }
}
return dirty
}
// HIGHLIGHT WORKER
function startWorker ( cm , time ) {
if ( cm . doc . mode . startState && cm . doc . frontier < cm . display . viewTo )
{ cm . state . highlight . set ( time , bind ( highlightWorker , cm ) ) ; }
}
function highlightWorker ( cm ) {
var doc = cm . doc ;
if ( doc . frontier < doc . first ) { doc . frontier = doc . first ; }
if ( doc . frontier >= cm . display . viewTo ) { return }
var end = + new Date + cm . options . workTime ;
var state = copyState ( doc . mode , getStateBefore ( cm , doc . frontier ) ) ;
var changedLines = [ ] ;
doc . iter ( doc . frontier , Math . min ( doc . first + doc . size , cm . display . viewTo + 500 ) , function ( line ) {
if ( doc . frontier >= cm . display . viewFrom ) { // Visible
var oldStyles = line . styles , tooLong = line . text . length > cm . options . maxHighlightLength ;
var highlighted = highlightLine ( cm , line , tooLong ? copyState ( doc . mode , state ) : state , true ) ;
line . styles = highlighted . styles ;
var oldCls = line . styleClasses , newCls = highlighted . classes ;
if ( newCls ) { line . styleClasses = newCls ; }
else if ( oldCls ) { line . styleClasses = null ; }
var ischange = ! oldStyles || oldStyles . length != line . styles . length ||
oldCls != newCls && ( ! oldCls || ! newCls || oldCls . bgClass != newCls . bgClass || oldCls . textClass != newCls . textClass ) ;
for ( var i = 0 ; ! ischange && i < oldStyles . length ; ++ i ) { ischange = oldStyles [ i ] != line . styles [ i ] ; }
if ( ischange ) { changedLines . push ( doc . frontier ) ; }
line . stateAfter = tooLong ? state : copyState ( doc . mode , state ) ;
} else {
if ( line . text . length <= cm . options . maxHighlightLength )
{ processLine ( cm , line . text , state ) ; }
line . stateAfter = doc . frontier % 5 == 0 ? copyState ( doc . mode , state ) : null ;
}
++ doc . frontier ;
if ( + new Date > end ) {
startWorker ( cm , cm . options . workDelay ) ;
return true
}
} ) ;
if ( changedLines . length ) { runInOp ( cm , function ( ) {
for ( var i = 0 ; i < changedLines . length ; i ++ )
{ regLineChange ( cm , changedLines [ i ] , "text" ) ; }
} ) ; }
}
// DISPLAY DRAWING
var DisplayUpdate = function ( cm , viewport , force ) {
var display = cm . display ;
this . viewport = viewport ;
// Store some values that we'll need later (but don't want to force a relayout for)
this . visible = visibleLines ( display , cm . doc , viewport ) ;
this . editorIsHidden = ! display . wrapper . offsetWidth ;
this . wrapperHeight = display . wrapper . clientHeight ;
this . wrapperWidth = display . wrapper . clientWidth ;
this . oldDisplayWidth = displayWidth ( cm ) ;
this . force = force ;
this . dims = getDimensions ( cm ) ;
this . events = [ ] ;
} ;
DisplayUpdate . prototype . signal = function ( emitter , type ) {
if ( hasHandler ( emitter , type ) )
{ this . events . push ( arguments ) ; }
} ;
DisplayUpdate . prototype . finish = function ( ) {
var this $1 = this ;
for ( var i = 0 ; i < this . events . length ; i ++ )
{ signal . apply ( null , this $1 . events [ i ] ) ; }
} ;
function maybeClipScrollbars ( cm ) {
var display = cm . display ;
if ( ! display . scrollbarsClipped && display . scroller . offsetWidth ) {
display . nativeBarWidth = display . scroller . offsetWidth - display . scroller . clientWidth ;
display . heightForcer . style . height = scrollGap ( cm ) + "px" ;
display . sizer . style . marginBottom = - display . nativeBarWidth + "px" ;
display . sizer . style . borderRightWidth = scrollGap ( cm ) + "px" ;
display . scrollbarsClipped = true ;
}
}
function selectionSnapshot ( cm ) {
if ( cm . hasFocus ( ) ) { return null }
var active = activeElt ( ) ;
if ( ! active || ! contains ( cm . display . lineDiv , active ) ) { return null }
var result = { activeElt : active } ;
if ( window . getSelection ) {
var sel = window . getSelection ( ) ;
if ( sel . anchorNode && sel . extend && contains ( cm . display . lineDiv , sel . anchorNode ) ) {
result . anchorNode = sel . anchorNode ;
result . anchorOffset = sel . anchorOffset ;
result . focusNode = sel . focusNode ;
result . focusOffset = sel . focusOffset ;
}
}
return result
}
function restoreSelection ( snapshot ) {
if ( ! snapshot || ! snapshot . activeElt || snapshot . activeElt == activeElt ( ) ) { return }
snapshot . activeElt . focus ( ) ;
if ( snapshot . anchorNode && contains ( document . body , snapshot . anchorNode ) && contains ( document . body , snapshot . focusNode ) ) {
var sel = window . getSelection ( ) , range$$1 = document . createRange ( ) ;
range$$1 . setEnd ( snapshot . anchorNode , snapshot . anchorOffset ) ;
range$$1 . collapse ( false ) ;
sel . removeAllRanges ( ) ;
sel . addRange ( range$$1 ) ;
sel . extend ( snapshot . focusNode , snapshot . focusOffset ) ;
}
}
// Does the actual updating of the line display. Bails out
// (returning false) when there is nothing to be done and forced is
// false.
function updateDisplayIfNeeded ( cm , update ) {
var display = cm . display , doc = cm . doc ;
if ( update . editorIsHidden ) {
resetView ( cm ) ;
return false
}
// Bail out if the visible area is already rendered and nothing changed.
if ( ! update . force &&
update . visible . from >= display . viewFrom && update . visible . to <= display . viewTo &&
( display . updateLineNumbers == null || display . updateLineNumbers >= display . viewTo ) &&
display . renderedView == display . view && countDirtyView ( cm ) == 0 )
{ return false }
if ( maybeUpdateLineNumberWidth ( cm ) ) {
resetView ( cm ) ;
update . dims = getDimensions ( cm ) ;
}
// Compute a suitable new viewport (from & to)
var end = doc . first + doc . size ;
var from = Math . max ( update . visible . from - cm . options . viewportMargin , doc . first ) ;
var to = Math . min ( end , update . visible . to + cm . options . viewportMargin ) ;
if ( display . viewFrom < from && from - display . viewFrom < 20 ) { from = Math . max ( doc . first , display . viewFrom ) ; }
if ( display . viewTo > to && display . viewTo - to < 20 ) { to = Math . min ( end , display . viewTo ) ; }
if ( sawCollapsedSpans ) {
from = visualLineNo ( cm . doc , from ) ;
to = visualLineEndNo ( cm . doc , to ) ;
}
var different = from != display . viewFrom || to != display . viewTo ||
display . lastWrapHeight != update . wrapperHeight || display . lastWrapWidth != update . wrapperWidth ;
adjustView ( cm , from , to ) ;
display . viewOffset = heightAtLine ( getLine ( cm . doc , display . viewFrom ) ) ;
// Position the mover div to align with the current scroll position
cm . display . mover . style . top = display . viewOffset + "px" ;
var toUpdate = countDirtyView ( cm ) ;
if ( ! different && toUpdate == 0 && ! update . force && display . renderedView == display . view &&
( display . updateLineNumbers == null || display . updateLineNumbers >= display . viewTo ) )
{ return false }
// For big changes, we hide the enclosing element during the
// update, since that speeds up the operations on most browsers.
var selSnapshot = selectionSnapshot ( cm ) ;
if ( toUpdate > 4 ) { display . lineDiv . style . display = "none" ; }
patchDisplay ( cm , display . updateLineNumbers , update . dims ) ;
if ( toUpdate > 4 ) { display . lineDiv . style . display = "" ; }
display . renderedView = display . view ;
// There might have been a widget with a focused element that got
// hidden or updated, if so re-focus it.
restoreSelection ( selSnapshot ) ;
// Prevent selection and cursors from interfering with the scroll
// width and height.
removeChildren ( display . cursorDiv ) ;
removeChildren ( display . selectionDiv ) ;
display . gutters . style . height = display . sizer . style . minHeight = 0 ;
if ( different ) {
display . lastWrapHeight = update . wrapperHeight ;
display . lastWrapWidth = update . wrapperWidth ;
startWorker ( cm , 400 ) ;
}
display . updateLineNumbers = null ;
return true
}
function postUpdateDisplay ( cm , update ) {
var viewport = update . viewport ;
for ( var first = true ; ; first = false ) {
if ( ! first || ! cm . options . lineWrapping || update . oldDisplayWidth == displayWidth ( cm ) ) {
// Clip forced viewport to actual scrollable area.
if ( viewport && viewport . top != null )
{ viewport = { top : Math . min ( cm . doc . height + paddingVert ( cm . display ) - displayHeight ( cm ) , viewport . top ) } ; }
// Updated line heights might result in the drawn area not
// actually covering the viewport. Keep looping until it does.
update . visible = visibleLines ( cm . display , cm . doc , viewport ) ;
if ( update . visible . from >= cm . display . viewFrom && update . visible . to <= cm . display . viewTo )
{ break }
}
if ( ! updateDisplayIfNeeded ( cm , update ) ) { break }
updateHeightsInViewport ( cm ) ;
var barMeasure = measureForScrollbars ( cm ) ;
updateSelection ( cm ) ;
updateScrollbars ( cm , barMeasure ) ;
setDocumentHeight ( cm , barMeasure ) ;
}
update . signal ( cm , "update" , cm ) ;
if ( cm . display . viewFrom != cm . display . reportedViewFrom || cm . display . viewTo != cm . display . reportedViewTo ) {
update . signal ( cm , "viewportChange" , cm , cm . display . viewFrom , cm . display . viewTo ) ;
cm . display . reportedViewFrom = cm . display . viewFrom ; cm . display . reportedViewTo = cm . display . viewTo ;
}
}
function updateDisplaySimple ( cm , viewport ) {
var update = new DisplayUpdate ( cm , viewport ) ;
if ( updateDisplayIfNeeded ( cm , update ) ) {
updateHeightsInViewport ( cm ) ;
postUpdateDisplay ( cm , update ) ;
var barMeasure = measureForScrollbars ( cm ) ;
updateSelection ( cm ) ;
updateScrollbars ( cm , barMeasure ) ;
setDocumentHeight ( cm , barMeasure ) ;
update . finish ( ) ;
}
}
// Sync the actual display DOM structure with display.view, removing
// nodes for lines that are no longer in view, and creating the ones
// that are not there yet, and updating the ones that are out of
// date.
function patchDisplay ( cm , updateNumbersFrom , dims ) {
var display = cm . display , lineNumbers = cm . options . lineNumbers ;
var container = display . lineDiv , cur = container . firstChild ;
function rm ( node ) {
var next = node . nextSibling ;
// Works around a throw-scroll bug in OS X Webkit
if ( webkit && mac && cm . display . currentWheelTarget == node )
{ node . style . display = "none" ; }
else
{ node . parentNode . removeChild ( node ) ; }
return next
}
var view = display . view , lineN = display . viewFrom ;
// Loop over the elements in the view, syncing cur (the DOM nodes
// in display.lineDiv) with the view as we go.
for ( var i = 0 ; i < view . length ; i ++ ) {
var lineView = view [ i ] ;
if ( lineView . hidden ) {
} else if ( ! lineView . node || lineView . node . parentNode != container ) { // Not drawn yet
var node = buildLineElement ( cm , lineView , lineN , dims ) ;
container . insertBefore ( node , cur ) ;
} else { // Already drawn
while ( cur != lineView . node ) { cur = rm ( cur ) ; }
var updateNumber = lineNumbers && updateNumbersFrom != null &&
updateNumbersFrom <= lineN && lineView . lineNumber ;
if ( lineView . changes ) {
if ( indexOf ( lineView . changes , "gutter" ) > - 1 ) { updateNumber = false ; }
updateLineForChanges ( cm , lineView , lineN , dims ) ;
}
if ( updateNumber ) {
removeChildren ( lineView . lineNumber ) ;
lineView . lineNumber . appendChild ( document . createTextNode ( lineNumberFor ( cm . options , lineN ) ) ) ;
}
cur = lineView . node . nextSibling ;
}
lineN += lineView . size ;
}
while ( cur ) { cur = rm ( cur ) ; }
}
function updateGutterSpace ( cm ) {
var width = cm . display . gutters . offsetWidth ;
cm . display . sizer . style . marginLeft = width + "px" ;
}
function setDocumentHeight ( cm , measure ) {
cm . display . sizer . style . minHeight = measure . docHeight + "px" ;
cm . display . heightForcer . style . top = measure . docHeight + "px" ;
cm . display . gutters . style . height = ( measure . docHeight + cm . display . barHeight + scrollGap ( cm ) ) + "px" ;
}
// Rebuild the gutter elements, ensure the margin to the left of the
// code matches their width.
function updateGutters ( cm ) {
var gutters = cm . display . gutters , specs = cm . options . gutters ;
removeChildren ( gutters ) ;
var i = 0 ;
for ( ; i < specs . length ; ++ i ) {
var gutterClass = specs [ i ] ;
var gElt = gutters . appendChild ( elt ( "div" , null , "CodeMirror-gutter " + gutterClass ) ) ;
if ( gutterClass == "CodeMirror-linenumbers" ) {
cm . display . lineGutter = gElt ;
gElt . style . width = ( cm . display . lineNumWidth || 1 ) + "px" ;
}
}
gutters . style . display = i ? "" : "none" ;
updateGutterSpace ( cm ) ;
}
// Make sure the gutters options contains the element
// "CodeMirror-linenumbers" when the lineNumbers option is true.
function setGuttersForLineNumbers ( options ) {
var found = indexOf ( options . gutters , "CodeMirror-linenumbers" ) ;
if ( found == - 1 && options . lineNumbers ) {
options . gutters = options . gutters . concat ( [ "CodeMirror-linenumbers" ] ) ;
} else if ( found > - 1 && ! options . lineNumbers ) {
options . gutters = options . gutters . slice ( 0 ) ;
options . gutters . splice ( found , 1 ) ;
}
}
// Since the delta values reported on mouse wheel events are
// unstandardized between browsers and even browser versions, and
// generally horribly unpredictable, this code starts by measuring
// the scroll effect that the first few mouse wheel events have,
// and, from that, detects the way it can convert deltas to pixel
// offsets afterwards.
//
// The reason we want to know the amount a wheel event will scroll
// is that it gives us a chance to update the display before the
// actual scrolling happens, reducing flickering.
var wheelSamples = 0 ;
var wheelPixelsPerUnit = null ;
// Fill in a browser-detected starting value on browsers where we
// know one. These don't have to be accurate -- the result of them
// being wrong would just be a slight flicker on the first wheel
// scroll (if it is large enough).
if ( ie ) { wheelPixelsPerUnit = - . 53 ; }
else if ( gecko ) { wheelPixelsPerUnit = 15 ; }
else if ( chrome ) { wheelPixelsPerUnit = - . 7 ; }
else if ( safari ) { wheelPixelsPerUnit = - 1 / 3 ; }
function wheelEventDelta ( e ) {
var dx = e . wheelDeltaX , dy = e . wheelDeltaY ;
if ( dx == null && e . detail && e . axis == e . HORIZONTAL _AXIS ) { dx = e . detail ; }
if ( dy == null && e . detail && e . axis == e . VERTICAL _AXIS ) { dy = e . detail ; }
else if ( dy == null ) { dy = e . wheelDelta ; }
return { x : dx , y : dy }
}
function wheelEventPixels ( e ) {
var delta = wheelEventDelta ( e ) ;
delta . x *= wheelPixelsPerUnit ;
delta . y *= wheelPixelsPerUnit ;
return delta
}
function onScrollWheel ( cm , e ) {
var delta = wheelEventDelta ( e ) , dx = delta . x , dy = delta . y ;
var display = cm . display , scroll = display . scroller ;
// Quit if there's nothing to scroll here
var canScrollX = scroll . scrollWidth > scroll . clientWidth ;
var canScrollY = scroll . scrollHeight > scroll . clientHeight ;
if ( ! ( dx && canScrollX || dy && canScrollY ) ) { return }
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
// This hack (see related code in patchDisplay) makes sure the
// element is kept around.
if ( dy && mac && webkit ) {
outer : for ( var cur = e . target , view = display . view ; cur != scroll ; cur = cur . parentNode ) {
for ( var i = 0 ; i < view . length ; i ++ ) {
if ( view [ i ] . node == cur ) {
cm . display . currentWheelTarget = cur ;
break outer
}
}
}
}
// On some browsers, horizontal scrolling will cause redraws to
// happen before the gutter has been realigned, causing it to
// wriggle around in a most unseemly way. When we have an
// estimated pixels/delta value, we just handle horizontal
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if ( dx && ! gecko && ! presto && wheelPixelsPerUnit != null ) {
if ( dy && canScrollY )
{ updateScrollTop ( cm , Math . max ( 0 , scroll . scrollTop + dy * wheelPixelsPerUnit ) ) ; }
setScrollLeft ( cm , Math . max ( 0 , scroll . scrollLeft + dx * wheelPixelsPerUnit ) ) ;
// Only prevent default scrolling if vertical scrolling is
// actually possible. Otherwise, it causes vertical scroll
// jitter on OSX trackpads when deltaX is small and deltaY
// is large (issue #3579)
if ( ! dy || ( dy && canScrollY ) )
{ e _preventDefault ( e ) ; }
display . wheelStartX = null ; // Abort measurement, if in progress
return
}
// 'Project' the visible viewport to cover the area that is being
// scrolled into view (if we know enough to estimate it).
if ( dy && wheelPixelsPerUnit != null ) {
var pixels = dy * wheelPixelsPerUnit ;
var top = cm . doc . scrollTop , bot = top + display . wrapper . clientHeight ;
if ( pixels < 0 ) { top = Math . max ( 0 , top + pixels - 50 ) ; }
else { bot = Math . min ( cm . doc . height , bot + pixels + 50 ) ; }
updateDisplaySimple ( cm , { top : top , bottom : bot } ) ;
}
if ( wheelSamples < 20 ) {
if ( display . wheelStartX == null ) {
display . wheelStartX = scroll . scrollLeft ; display . wheelStartY = scroll . scrollTop ;
display . wheelDX = dx ; display . wheelDY = dy ;
setTimeout ( function ( ) {
if ( display . wheelStartX == null ) { return }
var movedX = scroll . scrollLeft - display . wheelStartX ;
var movedY = scroll . scrollTop - display . wheelStartY ;
var sample = ( movedY && display . wheelDY && movedY / display . wheelDY ) ||
( movedX && display . wheelDX && movedX / display . wheelDX ) ;
display . wheelStartX = display . wheelStartY = null ;
if ( ! sample ) { return }
wheelPixelsPerUnit = ( wheelPixelsPerUnit * wheelSamples + sample ) / ( wheelSamples + 1 ) ;
++ wheelSamples ;
} , 200 ) ;
} else {
display . wheelDX += dx ; display . wheelDY += dy ;
}
}
}
// Selection objects are immutable. A new one is created every time
// the selection changes. A selection is one or more non-overlapping
// (and non-touching) ranges, sorted, and an integer that indicates
// which one is the primary selection (the one that's scrolled into
// view, that getCursor returns, etc).
var Selection = function ( ranges , primIndex ) {
this . ranges = ranges ;
this . primIndex = primIndex ;
} ;
Selection . prototype . primary = function ( ) { return this . ranges [ this . primIndex ] } ;
Selection . prototype . equals = function ( other ) {
var this $1 = this ;
if ( other == this ) { return true }
if ( other . primIndex != this . primIndex || other . ranges . length != this . ranges . length ) { return false }
for ( var i = 0 ; i < this . ranges . length ; i ++ ) {
var here = this $1 . ranges [ i ] , there = other . ranges [ i ] ;
if ( ! equalCursorPos ( here . anchor , there . anchor ) || ! equalCursorPos ( here . head , there . head ) ) { return false }
}
return true
} ;
Selection . prototype . deepCopy = function ( ) {
var this $1 = this ;
var out = [ ] ;
for ( var i = 0 ; i < this . ranges . length ; i ++ )
{ out [ i ] = new Range ( copyPos ( this $1 . ranges [ i ] . anchor ) , copyPos ( this $1 . ranges [ i ] . head ) ) ; }
return new Selection ( out , this . primIndex )
} ;
Selection . prototype . somethingSelected = function ( ) {
var this $1 = this ;
for ( var i = 0 ; i < this . ranges . length ; i ++ )
{ if ( ! this $1 . ranges [ i ] . empty ( ) ) { return true } }
return false
} ;
Selection . prototype . contains = function ( pos , end ) {
var this $1 = this ;
if ( ! end ) { end = pos ; }
for ( var i = 0 ; i < this . ranges . length ; i ++ ) {
var range = this $1 . ranges [ i ] ;
if ( cmp ( end , range . from ( ) ) >= 0 && cmp ( pos , range . to ( ) ) <= 0 )
{ return i }
}
return - 1
} ;
var Range = function ( anchor , head ) {
this . anchor = anchor ; this . head = head ;
} ;
Range . prototype . from = function ( ) { return minPos ( this . anchor , this . head ) } ;
Range . prototype . to = function ( ) { return maxPos ( this . anchor , this . head ) } ;
Range . prototype . empty = function ( ) { return this . head . line == this . anchor . line && this . head . ch == this . anchor . ch } ;
// Take an unsorted, potentially overlapping set of ranges, and
// build a selection out of it. 'Consumes' ranges array (modifying
// it).
function normalizeSelection ( ranges , primIndex ) {
var prim = ranges [ primIndex ] ;
ranges . sort ( function ( a , b ) { return cmp ( a . from ( ) , b . from ( ) ) ; } ) ;
primIndex = indexOf ( ranges , prim ) ;
for ( var i = 1 ; i < ranges . length ; i ++ ) {
var cur = ranges [ i ] , prev = ranges [ i - 1 ] ;
if ( cmp ( prev . to ( ) , cur . from ( ) ) >= 0 ) {
var from = minPos ( prev . from ( ) , cur . from ( ) ) , to = maxPos ( prev . to ( ) , cur . to ( ) ) ;
var inv = prev . empty ( ) ? cur . from ( ) == cur . head : prev . from ( ) == prev . head ;
if ( i <= primIndex ) { -- primIndex ; }
ranges . splice ( -- i , 2 , new Range ( inv ? to : from , inv ? from : to ) ) ;
}
}
return new Selection ( ranges , primIndex )
}
function simpleSelection ( anchor , head ) {
return new Selection ( [ new Range ( anchor , head || anchor ) ] , 0 )
}
// Compute the position of the end of a change (its 'to' property
// refers to the pre-change end).
function changeEnd ( change ) {
if ( ! change . text ) { return change . to }
return Pos ( change . from . line + change . text . length - 1 ,
lst ( change . text ) . length + ( change . text . length == 1 ? change . from . ch : 0 ) )
}
// Adjust a position to refer to the post-change position of the
// same text, or the end of the change if the change covers it.
function adjustForChange ( pos , change ) {
if ( cmp ( pos , change . from ) < 0 ) { return pos }
if ( cmp ( pos , change . to ) <= 0 ) { return changeEnd ( change ) }
var line = pos . line + change . text . length - ( change . to . line - change . from . line ) - 1 , ch = pos . ch ;
if ( pos . line == change . to . line ) { ch += changeEnd ( change ) . ch - change . to . ch ; }
return Pos ( line , ch )
}
function computeSelAfterChange ( doc , change ) {
var out = [ ] ;
for ( var i = 0 ; i < doc . sel . ranges . length ; i ++ ) {
var range = doc . sel . ranges [ i ] ;
out . push ( new Range ( adjustForChange ( range . anchor , change ) ,
adjustForChange ( range . head , change ) ) ) ;
}
return normalizeSelection ( out , doc . sel . primIndex )
}
function offsetPos ( pos , old , nw ) {
if ( pos . line == old . line )
{ return Pos ( nw . line , pos . ch - old . ch + nw . ch ) }
else
{ return Pos ( nw . line + ( pos . line - old . line ) , pos . ch ) }
}
// Used by replaceSelections to allow moving the selection to the
// start or around the replaced test. Hint may be "start" or "around".
function computeReplacedSel ( doc , changes , hint ) {
var out = [ ] ;
var oldPrev = Pos ( doc . first , 0 ) , newPrev = oldPrev ;
for ( var i = 0 ; i < changes . length ; i ++ ) {
var change = changes [ i ] ;
var from = offsetPos ( change . from , oldPrev , newPrev ) ;
var to = offsetPos ( changeEnd ( change ) , oldPrev , newPrev ) ;
oldPrev = change . to ;
newPrev = to ;
if ( hint == "around" ) {
var range = doc . sel . ranges [ i ] , inv = cmp ( range . head , range . anchor ) < 0 ;
out [ i ] = new Range ( inv ? to : from , inv ? from : to ) ;
} else {
out [ i ] = new Range ( from , from ) ;
}
}
return new Selection ( out , doc . sel . primIndex )
}
// Used to get the editor into a consistent state again when options change.
function loadMode ( cm ) {
cm . doc . mode = getMode ( cm . options , cm . doc . modeOption ) ;
resetModeState ( cm ) ;
}
function resetModeState ( cm ) {
cm . doc . iter ( function ( line ) {
if ( line . stateAfter ) { line . stateAfter = null ; }
if ( line . styles ) { line . styles = null ; }
} ) ;
cm . doc . frontier = cm . doc . first ;
startWorker ( cm , 100 ) ;
cm . state . modeGen ++ ;
if ( cm . curOp ) { regChange ( cm ) ; }
}
// DOCUMENT DATA STRUCTURE
// By default, updates that start and end at the beginning of a line
// are treated specially, in order to make the association of line
// widgets and marker elements with the text behave more intuitive.
function isWholeLineUpdate ( doc , change ) {
return change . from . ch == 0 && change . to . ch == 0 && lst ( change . text ) == "" &&
( ! doc . cm || doc . cm . options . wholeLineUpdateBefore )
}
// Perform a change on the document data structure.
function updateDoc ( doc , change , markedSpans , estimateHeight$$1 ) {
function spansFor ( n ) { return markedSpans ? markedSpans [ n ] : null }
function update ( line , text , spans ) {
updateLine ( line , text , spans , estimateHeight$$1 ) ;
signalLater ( line , "change" , line , change ) ;
}
function linesFor ( start , end ) {
var result = [ ] ;
for ( var i = start ; i < end ; ++ i )
{ result . push ( new Line ( text [ i ] , spansFor ( i ) , estimateHeight$$1 ) ) ; }
return result
}
var from = change . from , to = change . to , text = change . text ;
var firstLine = getLine ( doc , from . line ) , lastLine = getLine ( doc , to . line ) ;
var lastText = lst ( text ) , lastSpans = spansFor ( text . length - 1 ) , nlines = to . line - from . line ;
// Adjust the line structure
if ( change . full ) {
doc . insert ( 0 , linesFor ( 0 , text . length ) ) ;
doc . remove ( text . length , doc . size - text . length ) ;
} else if ( isWholeLineUpdate ( doc , change ) ) {
// This is a whole-line replace. Treated specially to make
// sure line objects move the way they are supposed to.
var added = linesFor ( 0 , text . length - 1 ) ;
update ( lastLine , lastLine . text , lastSpans ) ;
if ( nlines ) { doc . remove ( from . line , nlines ) ; }
if ( added . length ) { doc . insert ( from . line , added ) ; }
} else if ( firstLine == lastLine ) {
if ( text . length == 1 ) {
update ( firstLine , firstLine . text . slice ( 0 , from . ch ) + lastText + firstLine . text . slice ( to . ch ) , lastSpans ) ;
} else {
var added$1 = linesFor ( 1 , text . length - 1 ) ;
added$1 . push ( new Line ( lastText + firstLine . text . slice ( to . ch ) , lastSpans , estimateHeight$$1 ) ) ;
update ( firstLine , firstLine . text . slice ( 0 , from . ch ) + text [ 0 ] , spansFor ( 0 ) ) ;
doc . insert ( from . line + 1 , added$1 ) ;
}
} else if ( text . length == 1 ) {
update ( firstLine , firstLine . text . slice ( 0 , from . ch ) + text [ 0 ] + lastLine . text . slice ( to . ch ) , spansFor ( 0 ) ) ;
doc . remove ( from . line + 1 , nlines ) ;
} else {
update ( firstLine , firstLine . text . slice ( 0 , from . ch ) + text [ 0 ] , spansFor ( 0 ) ) ;
update ( lastLine , lastText + lastLine . text . slice ( to . ch ) , lastSpans ) ;
var added$2 = linesFor ( 1 , text . length - 1 ) ;
if ( nlines > 1 ) { doc . remove ( from . line + 1 , nlines - 1 ) ; }
doc . insert ( from . line + 1 , added$2 ) ;
}
signalLater ( doc , "change" , doc , change ) ;
}
// Call f for all linked documents.
function linkedDocs ( doc , f , sharedHistOnly ) {
function propagate ( doc , skip , sharedHist ) {
if ( doc . linked ) { for ( var i = 0 ; i < doc . linked . length ; ++ i ) {
var rel = doc . linked [ i ] ;
if ( rel . doc == skip ) { continue }
var shared = sharedHist && rel . sharedHist ;
if ( sharedHistOnly && ! shared ) { continue }
f ( rel . doc , shared ) ;
propagate ( rel . doc , doc , shared ) ;
} }
}
propagate ( doc , null , true ) ;
}
// Attach a document to an editor.
function attachDoc ( cm , doc ) {
if ( doc . cm ) { throw new Error ( "This document is already in use." ) }
cm . doc = doc ;
doc . cm = cm ;
estimateLineHeights ( cm ) ;
loadMode ( cm ) ;
setDirectionClass ( cm ) ;
if ( ! cm . options . lineWrapping ) { findMaxLine ( cm ) ; }
cm . options . mode = doc . modeOption ;
regChange ( cm ) ;
}
function setDirectionClass ( cm ) {
( cm . doc . direction == "rtl" ? addClass : rmClass ) ( cm . display . lineDiv , "CodeMirror-rtl" ) ;
}
function directionChanged ( cm ) {
runInOp ( cm , function ( ) {
setDirectionClass ( cm ) ;
regChange ( cm ) ;
} ) ;
}
function History ( startGen ) {
// Arrays of change events and selections. Doing something adds an
// event to done and clears undo. Undoing moves events from done
// to undone, redoing moves them in the other direction.
this . done = [ ] ; this . undone = [ ] ;
this . undoDepth = Infinity ;
// Used to track when changes can be merged into a single undo
// event
this . lastModTime = this . lastSelTime = 0 ;
this . lastOp = this . lastSelOp = null ;
this . lastOrigin = this . lastSelOrigin = null ;
// Used by the isClean() method
this . generation = this . maxGeneration = startGen || 1 ;
}
// Create a history change event from an updateDoc-style change
// object.
function historyChangeFromChange ( doc , change ) {
var histChange = { from : copyPos ( change . from ) , to : changeEnd ( change ) , text : getBetween ( doc , change . from , change . to ) } ;
attachLocalSpans ( doc , histChange , change . from . line , change . to . line + 1 ) ;
linkedDocs ( doc , function ( doc ) { return attachLocalSpans ( doc , histChange , change . from . line , change . to . line + 1 ) ; } , true ) ;
return histChange
}
// Pop all selection events off the end of a history array. Stop at
// a change event.
function clearSelectionEvents ( array ) {
while ( array . length ) {
var last = lst ( array ) ;
if ( last . ranges ) { array . pop ( ) ; }
else { break }
}
}
// Find the top change event in the history. Pop off selection
// events that are in the way.
function lastChangeEvent ( hist , force ) {
if ( force ) {
clearSelectionEvents ( hist . done ) ;
return lst ( hist . done )
} else if ( hist . done . length && ! lst ( hist . done ) . ranges ) {
return lst ( hist . done )
} else if ( hist . done . length > 1 && ! hist . done [ hist . done . length - 2 ] . ranges ) {
hist . done . pop ( ) ;
return lst ( hist . done )
}
}
// Register a change in the history. Merges changes that are within
// a single operation, or are close together with an origin that
// allows merging (starting with "+") into a single event.
function addChangeToHistory ( doc , change , selAfter , opId ) {
var hist = doc . history ;
hist . undone . length = 0 ;
var time = + new Date , cur ;
var last ;
if ( ( hist . lastOp == opId ||
hist . lastOrigin == change . origin && change . origin &&
( ( change . origin . charAt ( 0 ) == "+" && doc . cm && hist . lastModTime > time - doc . cm . options . historyEventDelay ) ||
change . origin . charAt ( 0 ) == "*" ) ) &&
( cur = lastChangeEvent ( hist , hist . lastOp == opId ) ) ) {
// Merge this change into the last event
last = lst ( cur . changes ) ;
if ( cmp ( change . from , change . to ) == 0 && cmp ( change . from , last . to ) == 0 ) {
// Optimized case for simple insertion -- don't want to add
// new changesets for every character typed
last . to = changeEnd ( change ) ;
} else {
// Add new sub-event
cur . changes . push ( historyChangeFromChange ( doc , change ) ) ;
}
} else {
// Can not be merged, start a new event.
var before = lst ( hist . done ) ;
if ( ! before || ! before . ranges )
{ pushSelectionToHistory ( doc . sel , hist . done ) ; }
cur = { changes : [ historyChangeFromChange ( doc , change ) ] ,
generation : hist . generation } ;
hist . done . push ( cur ) ;
while ( hist . done . length > hist . undoDepth ) {
hist . done . shift ( ) ;
if ( ! hist . done [ 0 ] . ranges ) { hist . done . shift ( ) ; }
}
}
hist . done . push ( selAfter ) ;
hist . generation = ++ hist . maxGeneration ;
hist . lastModTime = hist . lastSelTime = time ;
hist . lastOp = hist . lastSelOp = opId ;
hist . lastOrigin = hist . lastSelOrigin = change . origin ;
if ( ! last ) { signal ( doc , "historyAdded" ) ; }
}
function selectionEventCanBeMerged ( doc , origin , prev , sel ) {
var ch = origin . charAt ( 0 ) ;
return ch == "*" ||
ch == "+" &&
prev . ranges . length == sel . ranges . length &&
prev . somethingSelected ( ) == sel . somethingSelected ( ) &&
new Date - doc . history . lastSelTime <= ( doc . cm ? doc . cm . options . historyEventDelay : 500 )
}
// Called whenever the selection changes, sets the new selection as
// the pending selection in the history, and pushes the old pending
// selection into the 'done' array when it was significantly
// different (in number of selected ranges, emptiness, or time).
function addSelectionToHistory ( doc , sel , opId , options ) {
var hist = doc . history , origin = options && options . origin ;
// A new event is started when the previous origin does not match
// the current, or the origins don't allow matching. Origins
// starting with * are always merged, those starting with + are
// merged when similar and close together in time.
if ( opId == hist . lastSelOp ||
( origin && hist . lastSelOrigin == origin &&
( hist . lastModTime == hist . lastSelTime && hist . lastOrigin == origin ||
selectionEventCanBeMerged ( doc , origin , lst ( hist . done ) , sel ) ) ) )
{ hist . done [ hist . done . length - 1 ] = sel ; }
else
{ pushSelectionToHistory ( sel , hist . done ) ; }
hist . lastSelTime = + new Date ;
hist . lastSelOrigin = origin ;
hist . lastSelOp = opId ;
if ( options && options . clearRedo !== false )
{ clearSelectionEvents ( hist . undone ) ; }
}
function pushSelectionToHistory ( sel , dest ) {
var top = lst ( dest ) ;
if ( ! ( top && top . ranges && top . equals ( sel ) ) )
{ dest . push ( sel ) ; }
}
// Used to store marked span information in the history.
function attachLocalSpans ( doc , change , from , to ) {
var existing = change [ "spans_" + doc . id ] , n = 0 ;
doc . iter ( Math . max ( doc . first , from ) , Math . min ( doc . first + doc . size , to ) , function ( line ) {
if ( line . markedSpans )
{ ( existing || ( existing = change [ "spans_" + doc . id ] = { } ) ) [ n ] = line . markedSpans ; }
++ n ;
} ) ;
}
// When un/re-doing restores text containing marked spans, those
// that have been explicitly cleared should not be restored.
function removeClearedSpans ( spans ) {
if ( ! spans ) { return null }
var out ;
for ( var i = 0 ; i < spans . length ; ++ i ) {
if ( spans [ i ] . marker . explicitlyCleared ) { if ( ! out ) { out = spans . slice ( 0 , i ) ; } }
else if ( out ) { out . push ( spans [ i ] ) ; }
}
return ! out ? spans : out . length ? out : null
}
// Retrieve and filter the old marked spans stored in a change event.
function getOldSpans ( doc , change ) {
var found = change [ "spans_" + doc . id ] ;
if ( ! found ) { return null }
var nw = [ ] ;
for ( var i = 0 ; i < change . text . length ; ++ i )
{ nw . push ( removeClearedSpans ( found [ i ] ) ) ; }
return nw
}
// Used for un/re-doing changes from the history. Combines the
// result of computing the existing spans with the set of spans that
// existed in the history (so that deleting around a span and then
// undoing brings back the span).
function mergeOldSpans ( doc , change ) {
var old = getOldSpans ( doc , change ) ;
var stretched = stretchSpansOverChange ( doc , change ) ;
if ( ! old ) { return stretched }
if ( ! stretched ) { return old }
for ( var i = 0 ; i < old . length ; ++ i ) {
var oldCur = old [ i ] , stretchCur = stretched [ i ] ;
if ( oldCur && stretchCur ) {
spans : for ( var j = 0 ; j < stretchCur . length ; ++ j ) {
var span = stretchCur [ j ] ;
for ( var k = 0 ; k < oldCur . length ; ++ k )
{ if ( oldCur [ k ] . marker == span . marker ) { continue spans } }
oldCur . push ( span ) ;
}
} else if ( stretchCur ) {
old [ i ] = stretchCur ;
}
}
return old
}
// Used both to provide a JSON-safe object in .getHistory, and, when
// detaching a document, to split the history in two
function copyHistoryArray ( events , newGroup , instantiateSel ) {
var copy = [ ] ;
for ( var i = 0 ; i < events . length ; ++ i ) {
var event = events [ i ] ;
if ( event . ranges ) {
copy . push ( instantiateSel ? Selection . prototype . deepCopy . call ( event ) : event ) ;
continue
}
var changes = event . changes , newChanges = [ ] ;
copy . push ( { changes : newChanges } ) ;
for ( var j = 0 ; j < changes . length ; ++ j ) {
var change = changes [ j ] , m = ( void 0 ) ;
newChanges . push ( { from : change . from , to : change . to , text : change . text } ) ;
if ( newGroup ) { for ( var prop in change ) { if ( m = prop . match ( /^spans_(\d+)$/ ) ) {
if ( indexOf ( newGroup , Number ( m [ 1 ] ) ) > - 1 ) {
lst ( newChanges ) [ prop ] = change [ prop ] ;
delete change [ prop ] ;
}
} } }
}
}
return copy
}
// The 'scroll' parameter given to many of these indicated whether
// the new cursor position should be scrolled into view after
// modifying the selection.
// If shift is held or the extend flag is set, extends a range to
// include a given position (and optionally a second position).
// Otherwise, simply returns the range between the given positions.
// Used for cursor motion and such.
function extendRange ( doc , range , head , other ) {
if ( doc . cm && doc . cm . display . shift || doc . extend ) {
var anchor = range . anchor ;
if ( other ) {
var posBefore = cmp ( head , anchor ) < 0 ;
if ( posBefore != ( cmp ( other , anchor ) < 0 ) ) {
anchor = head ;
head = other ;
} else if ( posBefore != ( cmp ( head , other ) < 0 ) ) {
head = other ;
}
}
return new Range ( anchor , head )
} else {
return new Range ( other || head , head )
}
}
// Extend the primary selection range, discard the rest.
function extendSelection ( doc , head , other , options ) {
setSelection ( doc , new Selection ( [ extendRange ( doc , doc . sel . primary ( ) , head , other ) ] , 0 ) , options ) ;
}
// Extend all selections (pos is an array of selections with length
// equal the number of selections)
function extendSelections ( doc , heads , options ) {
var out = [ ] ;
for ( var i = 0 ; i < doc . sel . ranges . length ; i ++ )
{ out [ i ] = extendRange ( doc , doc . sel . ranges [ i ] , heads [ i ] , null ) ; }
var newSel = normalizeSelection ( out , doc . sel . primIndex ) ;
setSelection ( doc , newSel , options ) ;
}
// Updates a single range in the selection.
function replaceOneSelection ( doc , i , range , options ) {
var ranges = doc . sel . ranges . slice ( 0 ) ;
ranges [ i ] = range ;
setSelection ( doc , normalizeSelection ( ranges , doc . sel . primIndex ) , options ) ;
}
// Reset the selection to a single range.
function setSimpleSelection ( doc , anchor , head , options ) {
setSelection ( doc , simpleSelection ( anchor , head ) , options ) ;
}
// Give beforeSelectionChange handlers a change to influence a
// selection update.
function filterSelectionChange ( doc , sel , options ) {
var obj = {
ranges : sel . ranges ,
update : function ( ranges ) {
var this $1 = this ;
this . ranges = [ ] ;
for ( var i = 0 ; i < ranges . length ; i ++ )
{ this $1 . ranges [ i ] = new Range ( clipPos ( doc , ranges [ i ] . anchor ) ,
clipPos ( doc , ranges [ i ] . head ) ) ; }
} ,
origin : options && options . origin
} ;
signal ( doc , "beforeSelectionChange" , doc , obj ) ;
if ( doc . cm ) { signal ( doc . cm , "beforeSelectionChange" , doc . cm , obj ) ; }
if ( obj . ranges != sel . ranges ) { return normalizeSelection ( obj . ranges , obj . ranges . length - 1 ) }
else { return sel }
}
function setSelectionReplaceHistory ( doc , sel , options ) {
var done = doc . history . done , last = lst ( done ) ;
if ( last && last . ranges ) {
done [ done . length - 1 ] = sel ;
setSelectionNoUndo ( doc , sel , options ) ;
} else {
setSelection ( doc , sel , options ) ;
}
}
// Set a new selection.
function setSelection ( doc , sel , options ) {
setSelectionNoUndo ( doc , sel , options ) ;
addSelectionToHistory ( doc , doc . sel , doc . cm ? doc . cm . curOp . id : NaN , options ) ;
}
function setSelectionNoUndo ( doc , sel , options ) {
if ( hasHandler ( doc , "beforeSelectionChange" ) || doc . cm && hasHandler ( doc . cm , "beforeSelectionChange" ) )
{ sel = filterSelectionChange ( doc , sel , options ) ; }
var bias = options && options . bias ||
( cmp ( sel . primary ( ) . head , doc . sel . primary ( ) . head ) < 0 ? - 1 : 1 ) ;
setSelectionInner ( doc , skipAtomicInSelection ( doc , sel , bias , true ) ) ;
if ( ! ( options && options . scroll === false ) && doc . cm )
{ ensureCursorVisible ( doc . cm ) ; }
}
function setSelectionInner ( doc , sel ) {
if ( sel . equals ( doc . sel ) ) { return }
doc . sel = sel ;
if ( doc . cm ) {
doc . cm . curOp . updateInput = doc . cm . curOp . selectionChanged = true ;
signalCursorActivity ( doc . cm ) ;
}
signalLater ( doc , "cursorActivity" , doc ) ;
}
// Verify that the selection does not partially select any atomic
// marked ranges.
function reCheckSelection ( doc ) {
setSelectionInner ( doc , skipAtomicInSelection ( doc , doc . sel , null , false ) ) ;
}
// Return a selection that does not partially select any atomic
// ranges.
function skipAtomicInSelection ( doc , sel , bias , mayClear ) {
var out ;
for ( var i = 0 ; i < sel . ranges . length ; i ++ ) {
var range = sel . ranges [ i ] ;
var old = sel . ranges . length == doc . sel . ranges . length && doc . sel . ranges [ i ] ;
var newAnchor = skipAtomic ( doc , range . anchor , old && old . anchor , bias , mayClear ) ;
var newHead = skipAtomic ( doc , range . head , old && old . head , bias , mayClear ) ;
if ( out || newAnchor != range . anchor || newHead != range . head ) {
if ( ! out ) { out = sel . ranges . slice ( 0 , i ) ; }
out [ i ] = new Range ( newAnchor , newHead ) ;
}
}
return out ? normalizeSelection ( out , sel . primIndex ) : sel
}
function skipAtomicInner ( doc , pos , oldPos , dir , mayClear ) {
var line = getLine ( doc , pos . line ) ;
if ( line . markedSpans ) { for ( var i = 0 ; i < line . markedSpans . length ; ++ i ) {
var sp = line . markedSpans [ i ] , m = sp . marker ;
if ( ( sp . from == null || ( m . inclusiveLeft ? sp . from <= pos . ch : sp . from < pos . ch ) ) &&
( sp . to == null || ( m . inclusiveRight ? sp . to >= pos . ch : sp . to > pos . ch ) ) ) {
if ( mayClear ) {
signal ( m , "beforeCursorEnter" ) ;
if ( m . explicitlyCleared ) {
if ( ! line . markedSpans ) { break }
else { -- i ; continue }
}
}
if ( ! m . atomic ) { continue }
if ( oldPos ) {
var near = m . find ( dir < 0 ? 1 : - 1 ) , diff = ( void 0 ) ;
if ( dir < 0 ? m . inclusiveRight : m . inclusiveLeft )
{ near = movePos ( doc , near , - dir , near && near . line == pos . line ? line : null ) ; }
if ( near && near . line == pos . line && ( diff = cmp ( near , oldPos ) ) && ( dir < 0 ? diff < 0 : diff > 0 ) )
{ return skipAtomicInner ( doc , near , pos , dir , mayClear ) }
}
var far = m . find ( dir < 0 ? - 1 : 1 ) ;
if ( dir < 0 ? m . inclusiveLeft : m . inclusiveRight )
{ far = movePos ( doc , far , dir , far . line == pos . line ? line : null ) ; }
return far ? skipAtomicInner ( doc , far , pos , dir , mayClear ) : null
}
} }
return pos
}
// Ensure a given position is not inside an atomic range.
function skipAtomic ( doc , pos , oldPos , bias , mayClear ) {
var dir = bias || 1 ;
var found = skipAtomicInner ( doc , pos , oldPos , dir , mayClear ) ||
( ! mayClear && skipAtomicInner ( doc , pos , oldPos , dir , true ) ) ||
skipAtomicInner ( doc , pos , oldPos , - dir , mayClear ) ||
( ! mayClear && skipAtomicInner ( doc , pos , oldPos , - dir , true ) ) ;
if ( ! found ) {
doc . cantEdit = true ;
return Pos ( doc . first , 0 )
}
return found
}
function movePos ( doc , pos , dir , line ) {
if ( dir < 0 && pos . ch == 0 ) {
if ( pos . line > doc . first ) { return clipPos ( doc , Pos ( pos . line - 1 ) ) }
else { return null }
} else if ( dir > 0 && pos . ch == ( line || getLine ( doc , pos . line ) ) . text . length ) {
if ( pos . line < doc . first + doc . size - 1 ) { return Pos ( pos . line + 1 , 0 ) }
else { return null }
} else {
return new Pos ( pos . line , pos . ch + dir )
}
}
function selectAll ( cm ) {
cm . setSelection ( Pos ( cm . firstLine ( ) , 0 ) , Pos ( cm . lastLine ( ) ) , sel _dontScroll ) ;
}
// UPDATING
// Allow "beforeChange" event handlers to influence a change
function filterChange ( doc , change , update ) {
var obj = {
canceled : false ,
from : change . from ,
to : change . to ,
text : change . text ,
origin : change . origin ,
cancel : function ( ) { return obj . canceled = true ; }
} ;
if ( update ) { obj . update = function ( from , to , text , origin ) {
if ( from ) { obj . from = clipPos ( doc , from ) ; }
if ( to ) { obj . to = clipPos ( doc , to ) ; }
if ( text ) { obj . text = text ; }
if ( origin !== undefined ) { obj . origin = origin ; }
} ; }
signal ( doc , "beforeChange" , doc , obj ) ;
if ( doc . cm ) { signal ( doc . cm , "beforeChange" , doc . cm , obj ) ; }
if ( obj . canceled ) { return null }
return { from : obj . from , to : obj . to , text : obj . text , origin : obj . origin }
}
// Apply a change to a document, and add it to the document's
// history, and propagating it to all linked documents.
function makeChange ( doc , change , ignoreReadOnly ) {
if ( doc . cm ) {
if ( ! doc . cm . curOp ) { return operation ( doc . cm , makeChange ) ( doc , change , ignoreReadOnly ) }
if ( doc . cm . state . suppressEdits ) { return }
}
if ( hasHandler ( doc , "beforeChange" ) || doc . cm && hasHandler ( doc . cm , "beforeChange" ) ) {
change = filterChange ( doc , change , true ) ;
if ( ! change ) { return }
}
// Possibly split or suppress the update based on the presence
// of read-only spans in its range.
var split = sawReadOnlySpans && ! ignoreReadOnly && removeReadOnlyRanges ( doc , change . from , change . to ) ;
if ( split ) {
for ( var i = split . length - 1 ; i >= 0 ; -- i )
{ makeChangeInner ( doc , { from : split [ i ] . from , to : split [ i ] . to , text : i ? [ "" ] : change . text } ) ; }
} else {
makeChangeInner ( doc , change ) ;
}
}
function makeChangeInner ( doc , change ) {
if ( change . text . length == 1 && change . text [ 0 ] == "" && cmp ( change . from , change . to ) == 0 ) { return }
var selAfter = computeSelAfterChange ( doc , change ) ;
addChangeToHistory ( doc , change , selAfter , doc . cm ? doc . cm . curOp . id : NaN ) ;
makeChangeSingleDoc ( doc , change , selAfter , stretchSpansOverChange ( doc , change ) ) ;
var rebased = [ ] ;
linkedDocs ( doc , function ( doc , sharedHist ) {
if ( ! sharedHist && indexOf ( rebased , doc . history ) == - 1 ) {
rebaseHist ( doc . history , change ) ;
rebased . push ( doc . history ) ;
}
makeChangeSingleDoc ( doc , change , null , stretchSpansOverChange ( doc , change ) ) ;
} ) ;
}
// Revert a change stored in a document's history.
function makeChangeFromHistory ( doc , type , allowSelectionOnly ) {
if ( doc . cm && doc . cm . state . suppressEdits && ! allowSelectionOnly ) { return }
var hist = doc . history , event , selAfter = doc . sel ;
var source = type == "undo" ? hist . done : hist . undone , dest = type == "undo" ? hist . undone : hist . done ;
// Verify that there is a useable event (so that ctrl-z won't
// needlessly clear selection events)
var i = 0 ;
for ( ; i < source . length ; i ++ ) {
event = source [ i ] ;
if ( allowSelectionOnly ? event . ranges && ! event . equals ( doc . sel ) : ! event . ranges )
{ break }
}
if ( i == source . length ) { return }
hist . lastOrigin = hist . lastSelOrigin = null ;
for ( ; ; ) {
event = source . pop ( ) ;
if ( event . ranges ) {
pushSelectionToHistory ( event , dest ) ;
if ( allowSelectionOnly && ! event . equals ( doc . sel ) ) {
setSelection ( doc , event , { clearRedo : false } ) ;
return
}
selAfter = event ;
}
else { break }
}
// Build up a reverse change object to add to the opposite history
// stack (redo when undoing, and vice versa).
var antiChanges = [ ] ;
pushSelectionToHistory ( selAfter , dest ) ;
dest . push ( { changes : antiChanges , generation : hist . generation } ) ;
hist . generation = event . generation || ++ hist . maxGeneration ;
var filter = hasHandler ( doc , "beforeChange" ) || doc . cm && hasHandler ( doc . cm , "beforeChange" ) ;
var loop = function ( i ) {
var change = event . changes [ i ] ;
change . origin = type ;
if ( filter && ! filterChange ( doc , change , false ) ) {
source . length = 0 ;
return { }
}
antiChanges . push ( historyChangeFromChange ( doc , change ) ) ;
var after = i ? computeSelAfterChange ( doc , change ) : lst ( source ) ;
makeChangeSingleDoc ( doc , change , after , mergeOldSpans ( doc , change ) ) ;
if ( ! i && doc . cm ) { doc . cm . scrollIntoView ( { from : change . from , to : changeEnd ( change ) } ) ; }
var rebased = [ ] ;
// Propagate to the linked documents
linkedDocs ( doc , function ( doc , sharedHist ) {
if ( ! sharedHist && indexOf ( rebased , doc . history ) == - 1 ) {
rebaseHist ( doc . history , change ) ;
rebased . push ( doc . history ) ;
}
makeChangeSingleDoc ( doc , change , null , mergeOldSpans ( doc , change ) ) ;
} ) ;
} ;
for ( var i$1 = event . changes . length - 1 ; i$1 >= 0 ; -- i$1 ) {
var returned = loop ( i$1 ) ;
if ( returned ) return returned . v ;
}
}
// Sub-views need their line numbers shifted when text is added
// above or below them in the parent document.
function shiftDoc ( doc , distance ) {
if ( distance == 0 ) { return }
doc . first += distance ;
doc . sel = new Selection ( map ( doc . sel . ranges , function ( range ) { return new Range (
Pos ( range . anchor . line + distance , range . anchor . ch ) ,
Pos ( range . head . line + distance , range . head . ch )
) ; } ) , doc . sel . primIndex ) ;
if ( doc . cm ) {
regChange ( doc . cm , doc . first , doc . first - distance , distance ) ;
for ( var d = doc . cm . display , l = d . viewFrom ; l < d . viewTo ; l ++ )
{ regLineChange ( doc . cm , l , "gutter" ) ; }
}
}
// More lower-level change function, handling only a single document
// (not linked ones).
function makeChangeSingleDoc ( doc , change , selAfter , spans ) {
if ( doc . cm && ! doc . cm . curOp )
{ return operation ( doc . cm , makeChangeSingleDoc ) ( doc , change , selAfter , spans ) }
if ( change . to . line < doc . first ) {
shiftDoc ( doc , change . text . length - 1 - ( change . to . line - change . from . line ) ) ;
return
}
if ( change . from . line > doc . lastLine ( ) ) { return }
// Clip the change to the size of this doc
if ( change . from . line < doc . first ) {
var shift = change . text . length - 1 - ( doc . first - change . from . line ) ;
shiftDoc ( doc , shift ) ;
change = { from : Pos ( doc . first , 0 ) , to : Pos ( change . to . line + shift , change . to . ch ) ,
text : [ lst ( change . text ) ] , origin : change . origin } ;
}
var last = doc . lastLine ( ) ;
if ( change . to . line > last ) {
change = { from : change . from , to : Pos ( last , getLine ( doc , last ) . text . length ) ,
text : [ change . text [ 0 ] ] , origin : change . origin } ;
}
change . removed = getBetween ( doc , change . from , change . to ) ;
if ( ! selAfter ) { selAfter = computeSelAfterChange ( doc , change ) ; }
if ( doc . cm ) { makeChangeSingleDocInEditor ( doc . cm , change , spans ) ; }
else { updateDoc ( doc , change , spans ) ; }
setSelectionNoUndo ( doc , selAfter , sel _dontScroll ) ;
}
// Handle the interaction of a change to a document with the editor
// that this document is part of.
function makeChangeSingleDocInEditor ( cm , change , spans ) {
var doc = cm . doc , display = cm . display , from = change . from , to = change . to ;
var recomputeMaxLength = false , checkWidthStart = from . line ;
if ( ! cm . options . lineWrapping ) {
checkWidthStart = lineNo ( visualLine ( getLine ( doc , from . line ) ) ) ;
doc . iter ( checkWidthStart , to . line + 1 , function ( line ) {
if ( line == display . maxLine ) {
recomputeMaxLength = true ;
return true
}
} ) ;
}
if ( doc . sel . contains ( change . from , change . to ) > - 1 )
{ signalCursorActivity ( cm ) ; }
updateDoc ( doc , change , spans , estimateHeight ( cm ) ) ;
if ( ! cm . options . lineWrapping ) {
doc . iter ( checkWidthStart , from . line + change . text . length , function ( line ) {
var len = lineLength ( line ) ;
if ( len > display . maxLineLength ) {
display . maxLine = line ;
display . maxLineLength = len ;
display . maxLineChanged = true ;
recomputeMaxLength = false ;
}
} ) ;
if ( recomputeMaxLength ) { cm . curOp . updateMaxLine = true ; }
}
// Adjust frontier, schedule worker
doc . frontier = Math . min ( doc . frontier , from . line ) ;
startWorker ( cm , 400 ) ;
var lendiff = change . text . length - ( to . line - from . line ) - 1 ;
// Remember that these lines changed, for updating the display
if ( change . full )
{ regChange ( cm ) ; }
else if ( from . line == to . line && change . text . length == 1 && ! isWholeLineUpdate ( cm . doc , change ) )
{ regLineChange ( cm , from . line , "text" ) ; }
else
{ regChange ( cm , from . line , to . line + 1 , lendiff ) ; }
var changesHandler = hasHandler ( cm , "changes" ) , changeHandler = hasHandler ( cm , "change" ) ;
if ( changeHandler || changesHandler ) {
var obj = {
from : from , to : to ,
text : change . text ,
removed : change . removed ,
origin : change . origin
} ;
if ( changeHandler ) { signalLater ( cm , "change" , cm , obj ) ; }
if ( changesHandler ) { ( cm . curOp . changeObjs || ( cm . curOp . changeObjs = [ ] ) ) . push ( obj ) ; }
}
cm . display . selForContextMenu = null ;
}
function replaceRange ( doc , code , from , to , origin ) {
if ( ! to ) { to = from ; }
if ( cmp ( to , from ) < 0 ) { var tmp = to ; to = from ; from = tmp ; }
if ( typeof code == "string" ) { code = doc . splitLines ( code ) ; }
makeChange ( doc , { from : from , to : to , text : code , origin : origin } ) ;
}
// Rebasing/resetting history to deal with externally-sourced changes
function rebaseHistSelSingle ( pos , from , to , diff ) {
if ( to < pos . line ) {
pos . line += diff ;
} else if ( from < pos . line ) {
pos . line = from ;
pos . ch = 0 ;
}
}
// Tries to rebase an array of history events given a change in the
// document. If the change touches the same lines as the event, the
// event, and everything 'behind' it, is discarded. If the change is
// before the event, the event's positions are updated. Uses a
// copy-on-write scheme for the positions, to avoid having to
// reallocate them all on every rebase, but also avoid problems with
// shared position objects being unsafely updated.
function rebaseHistArray ( array , from , to , diff ) {
for ( var i = 0 ; i < array . length ; ++ i ) {
var sub = array [ i ] , ok = true ;
if ( sub . ranges ) {
if ( ! sub . copied ) { sub = array [ i ] = sub . deepCopy ( ) ; sub . copied = true ; }
for ( var j = 0 ; j < sub . ranges . length ; j ++ ) {
rebaseHistSelSingle ( sub . ranges [ j ] . anchor , from , to , diff ) ;
rebaseHistSelSingle ( sub . ranges [ j ] . head , from , to , diff ) ;
}
continue
}
for ( var j$1 = 0 ; j$1 < sub . changes . length ; ++ j$1 ) {
var cur = sub . changes [ j$1 ] ;
if ( to < cur . from . line ) {
cur . from = Pos ( cur . from . line + diff , cur . from . ch ) ;
cur . to = Pos ( cur . to . line + diff , cur . to . ch ) ;
} else if ( from <= cur . to . line ) {
ok = false ;
break
}
}
if ( ! ok ) {
array . splice ( 0 , i + 1 ) ;
i = 0 ;
}
}
}
function rebaseHist ( hist , change ) {
var from = change . from . line , to = change . to . line , diff = change . text . length - ( to - from ) - 1 ;
rebaseHistArray ( hist . done , from , to , diff ) ;
rebaseHistArray ( hist . undone , from , to , diff ) ;
}
// Utility for applying a change to a line by handle or number,
// returning the number and optionally registering the line as
// changed.
function changeLine ( doc , handle , changeType , op ) {
var no = handle , line = handle ;
if ( typeof handle == "number" ) { line = getLine ( doc , clipLine ( doc , handle ) ) ; }
else { no = lineNo ( handle ) ; }
if ( no == null ) { return null }
if ( op ( line , no ) && doc . cm ) { regLineChange ( doc . cm , no , changeType ) ; }
return line
}
// The document is represented as a BTree consisting of leaves, with
// chunk of lines in them, and branches, with up to ten leaves or
// other branch nodes below them. The top node is always a branch
// node, and is the document object itself (meaning it has
// additional methods and properties).
//
// All nodes have parent links. The tree is used both to go from
// line numbers to line objects, and to go from objects to numbers.
// It also indexes by height, and is used to convert between height
// and line object, and to find the total height of the document.
//
// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
var LeafChunk = function ( lines ) {
var this $1 = this ;
this . lines = lines ;
this . parent = null ;
var height = 0 ;
for ( var i = 0 ; i < lines . length ; ++ i ) {
lines [ i ] . parent = this $1 ;
height += lines [ i ] . height ;
}
this . height = height ;
} ;
LeafChunk . prototype . chunkSize = function ( ) { return this . lines . length } ;
// Remove the n lines at offset 'at'.
LeafChunk . prototype . removeInner = function ( at , n ) {
var this $1 = this ;
for ( var i = at , e = at + n ; i < e ; ++ i ) {
var line = this $1 . lines [ i ] ;
this $1 . height -= line . height ;
cleanUpLine ( line ) ;
signalLater ( line , "delete" ) ;
}
this . lines . splice ( at , n ) ;
} ;
// Helper used to collapse a small branch into a single leaf.
LeafChunk . prototype . collapse = function ( lines ) {
lines . push . apply ( lines , this . lines ) ;
} ;
// Insert the given array of lines at offset 'at', count them as
// having the given height.
LeafChunk . prototype . insertInner = function ( at , lines , height ) {
var this $1 = this ;
this . height += height ;
this . lines = this . lines . slice ( 0 , at ) . concat ( lines ) . concat ( this . lines . slice ( at ) ) ;
for ( var i = 0 ; i < lines . length ; ++ i ) { lines [ i ] . parent = this $1 ; }
} ;
// Used to iterate over a part of the tree.
LeafChunk . prototype . iterN = function ( at , n , op ) {
var this $1 = this ;
for ( var e = at + n ; at < e ; ++ at )
{ if ( op ( this $1 . lines [ at ] ) ) { return true } }
} ;
var BranchChunk = function ( children ) {
var this $1 = this ;
this . children = children ;
var size = 0 , height = 0 ;
for ( var i = 0 ; i < children . length ; ++ i ) {
var ch = children [ i ] ;
size += ch . chunkSize ( ) ; height += ch . height ;
ch . parent = this $1 ;
}
this . size = size ;
this . height = height ;
this . parent = null ;
} ;
BranchChunk . prototype . chunkSize = function ( ) { return this . size } ;
BranchChunk . prototype . removeInner = function ( at , n ) {
var this $1 = this ;
this . size -= n ;
for ( var i = 0 ; i < this . children . length ; ++ i ) {
var child = this $1 . children [ i ] , sz = child . chunkSize ( ) ;
if ( at < sz ) {
var rm = Math . min ( n , sz - at ) , oldHeight = child . height ;
child . removeInner ( at , rm ) ;
this $1 . height -= oldHeight - child . height ;
if ( sz == rm ) { this $1 . children . splice ( i -- , 1 ) ; child . parent = null ; }
if ( ( n -= rm ) == 0 ) { break }
at = 0 ;
} else { at -= sz ; }
}
// If the result is smaller than 25 lines, ensure that it is a
// single leaf node.
if ( this . size - n < 25 &&
( this . children . length > 1 || ! ( this . children [ 0 ] instanceof LeafChunk ) ) ) {
var lines = [ ] ;
this . collapse ( lines ) ;
this . children = [ new LeafChunk ( lines ) ] ;
this . children [ 0 ] . parent = this ;
}
} ;
BranchChunk . prototype . collapse = function ( lines ) {
var this $1 = this ;
for ( var i = 0 ; i < this . children . length ; ++ i ) { this $1 . children [ i ] . collapse ( lines ) ; }
} ;
BranchChunk . prototype . insertInner = function ( at , lines , height ) {
var this $1 = this ;
this . size += lines . length ;
this . height += height ;
for ( var i = 0 ; i < this . children . length ; ++ i ) {
var child = this $1 . children [ i ] , sz = child . chunkSize ( ) ;
if ( at <= sz ) {
child . insertInner ( at , lines , height ) ;
if ( child . lines && child . lines . length > 50 ) {
// To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
// Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
var remaining = child . lines . length % 25 + 25 ;
for ( var pos = remaining ; pos < child . lines . length ; ) {
var leaf = new LeafChunk ( child . lines . slice ( pos , pos += 25 ) ) ;
child . height -= leaf . height ;
this $1 . children . splice ( ++ i , 0 , leaf ) ;
leaf . parent = this $1 ;
}
child . lines = child . lines . slice ( 0 , remaining ) ;
this $1 . maybeSpill ( ) ;
}
break
}
at -= sz ;
}
} ;
// When a node has grown, check whether it should be split.
BranchChunk . prototype . maybeSpill = function ( ) {
if ( this . children . length <= 10 ) { return }
var me = this ;
do {
var spilled = me . children . splice ( me . children . length - 5 , 5 ) ;
var sibling = new BranchChunk ( spilled ) ;
if ( ! me . parent ) { // Become the parent node
var copy = new BranchChunk ( me . children ) ;
copy . parent = me ;
me . children = [ copy , sibling ] ;
me = copy ;
} else {
me . size -= sibling . size ;
me . height -= sibling . height ;
var myIndex = indexOf ( me . parent . children , me ) ;
me . parent . children . splice ( myIndex + 1 , 0 , sibling ) ;
}
sibling . parent = me . parent ;
} while ( me . children . length > 10 )
me . parent . maybeSpill ( ) ;
} ;
BranchChunk . prototype . iterN = function ( at , n , op ) {
var this $1 = this ;
for ( var i = 0 ; i < this . children . length ; ++ i ) {
var child = this $1 . children [ i ] , sz = child . chunkSize ( ) ;
if ( at < sz ) {
var used = Math . min ( n , sz - at ) ;
if ( child . iterN ( at , used , op ) ) { return true }
if ( ( n -= used ) == 0 ) { break }
at = 0 ;
} else { at -= sz ; }
}
} ;
// Line widgets are block elements displayed above or below a line.
var LineWidget = function ( doc , node , options ) {
var this $1 = this ;
if ( options ) { for ( var opt in options ) { if ( options . hasOwnProperty ( opt ) )
{ this $1 [ opt ] = options [ opt ] ; } } }
this . doc = doc ;
this . node = node ;
} ;
LineWidget . prototype . clear = function ( ) {
var this $1 = this ;
var cm = this . doc . cm , ws = this . line . widgets , line = this . line , no = lineNo ( line ) ;
if ( no == null || ! ws ) { return }
for ( var i = 0 ; i < ws . length ; ++ i ) { if ( ws [ i ] == this $1 ) { ws . splice ( i -- , 1 ) ; } }
if ( ! ws . length ) { line . widgets = null ; }
var height = widgetHeight ( this ) ;
updateLineHeight ( line , Math . max ( 0 , line . height - height ) ) ;
if ( cm ) {
runInOp ( cm , function ( ) {
adjustScrollWhenAboveVisible ( cm , line , - height ) ;
regLineChange ( cm , no , "widget" ) ;
} ) ;
signalLater ( cm , "lineWidgetCleared" , cm , this , no ) ;
}
} ;
LineWidget . prototype . changed = function ( ) {
var this $1 = this ;
var oldH = this . height , cm = this . doc . cm , line = this . line ;
this . height = null ;
var diff = widgetHeight ( this ) - oldH ;
if ( ! diff ) { return }
updateLineHeight ( line , line . height + diff ) ;
if ( cm ) {
runInOp ( cm , function ( ) {
cm . curOp . forceUpdate = true ;
adjustScrollWhenAboveVisible ( cm , line , diff ) ;
signalLater ( cm , "lineWidgetChanged" , cm , this $1 , lineNo ( line ) ) ;
} ) ;
}
} ;
eventMixin ( LineWidget ) ;
function adjustScrollWhenAboveVisible ( cm , line , diff ) {
if ( heightAtLine ( line ) < ( ( cm . curOp && cm . curOp . scrollTop ) || cm . doc . scrollTop ) )
{ addToScrollTop ( cm , diff ) ; }
}
function addLineWidget ( doc , handle , node , options ) {
var widget = new LineWidget ( doc , node , options ) ;
var cm = doc . cm ;
if ( cm && widget . noHScroll ) { cm . display . alignWidgets = true ; }
changeLine ( doc , handle , "widget" , function ( line ) {
var widgets = line . widgets || ( line . widgets = [ ] ) ;
if ( widget . insertAt == null ) { widgets . push ( widget ) ; }
else { widgets . splice ( Math . min ( widgets . length - 1 , Math . max ( 0 , widget . insertAt ) ) , 0 , widget ) ; }
widget . line = line ;
if ( cm && ! lineIsHidden ( doc , line ) ) {
var aboveVisible = heightAtLine ( line ) < doc . scrollTop ;
updateLineHeight ( line , line . height + widgetHeight ( widget ) ) ;
if ( aboveVisible ) { addToScrollTop ( cm , widget . height ) ; }
cm . curOp . forceUpdate = true ;
}
return true
} ) ;
signalLater ( cm , "lineWidgetAdded" , cm , widget , typeof handle == "number" ? handle : lineNo ( handle ) ) ;
return widget
}
// TEXTMARKERS
// Created with markText and setBookmark methods. A TextMarker is a
// handle that can be used to clear or find a marked position in the
// document. Line objects hold arrays (markedSpans) containing
// {from, to, marker} object pointing to such marker objects, and
// indicating that such a marker is present on that line. Multiple
// lines may point to the same marker when it spans across lines.
// The spans will have null for their from/to properties when the
// marker continues beyond the start/end of the line. Markers have
// links back to the lines they currently touch.
// Collapsed markers have unique ids, in order to be able to order
// them, which is needed for uniquely determining an outer marker
// when they overlap (they may nest, but not partially overlap).
var nextMarkerId = 0 ;
var TextMarker = function ( doc , type ) {
this . lines = [ ] ;
this . type = type ;
this . doc = doc ;
this . id = ++ nextMarkerId ;
} ;
// Clear the marker.
TextMarker . prototype . clear = function ( ) {
var this $1 = this ;
if ( this . explicitlyCleared ) { return }
var cm = this . doc . cm , withOp = cm && ! cm . curOp ;
if ( withOp ) { startOperation ( cm ) ; }
if ( hasHandler ( this , "clear" ) ) {
var found = this . find ( ) ;
if ( found ) { signalLater ( this , "clear" , found . from , found . to ) ; }
}
var min = null , max = null ;
for ( var i = 0 ; i < this . lines . length ; ++ i ) {
var line = this $1 . lines [ i ] ;
var span = getMarkedSpanFor ( line . markedSpans , this $1 ) ;
if ( cm && ! this $1 . collapsed ) { regLineChange ( cm , lineNo ( line ) , "text" ) ; }
else if ( cm ) {
if ( span . to != null ) { max = lineNo ( line ) ; }
if ( span . from != null ) { min = lineNo ( line ) ; }
}
line . markedSpans = removeMarkedSpan ( line . markedSpans , span ) ;
if ( span . from == null && this $1 . collapsed && ! lineIsHidden ( this $1 . doc , line ) && cm )
{ updateLineHeight ( line , textHeight ( cm . display ) ) ; }
}
if ( cm && this . collapsed && ! cm . options . lineWrapping ) { for ( var i$1 = 0 ; i$1 < this . lines . length ; ++ i$1 ) {
var visual = visualLine ( this $1 . lines [ i$1 ] ) , len = lineLength ( visual ) ;
if ( len > cm . display . maxLineLength ) {
cm . display . maxLine = visual ;
cm . display . maxLineLength = len ;
cm . display . maxLineChanged = true ;
}
} }
if ( min != null && cm && this . collapsed ) { regChange ( cm , min , max + 1 ) ; }
this . lines . length = 0 ;
this . explicitlyCleared = true ;
if ( this . atomic && this . doc . cantEdit ) {
this . doc . cantEdit = false ;
if ( cm ) { reCheckSelection ( cm . doc ) ; }
}
if ( cm ) { signalLater ( cm , "markerCleared" , cm , this , min , max ) ; }
if ( withOp ) { endOperation ( cm ) ; }
if ( this . parent ) { this . parent . clear ( ) ; }
} ;
// Find the position of the marker in the document. Returns a {from,
// to} object by default. Side can be passed to get a specific side
// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
// Pos objects returned contain a line object, rather than a line
// number (used to prevent looking up the same line twice).
TextMarker . prototype . find = function ( side , lineObj ) {
var this $1 = this ;
if ( side == null && this . type == "bookmark" ) { side = 1 ; }
var from , to ;
for ( var i = 0 ; i < this . lines . length ; ++ i ) {
var line = this $1 . lines [ i ] ;
var span = getMarkedSpanFor ( line . markedSpans , this $1 ) ;
if ( span . from != null ) {
from = Pos ( lineObj ? line : lineNo ( line ) , span . from ) ;
if ( side == - 1 ) { return from }
}
if ( span . to != null ) {
to = Pos ( lineObj ? line : lineNo ( line ) , span . to ) ;
if ( side == 1 ) { return to }
}
}
return from && { from : from , to : to }
} ;
// Signals that the marker's widget changed, and surrounding layout
// should be recomputed.
TextMarker . prototype . changed = function ( ) {
var this $1 = this ;
var pos = this . find ( - 1 , true ) , widget = this , cm = this . doc . cm ;
if ( ! pos || ! cm ) { return }
runInOp ( cm , function ( ) {
var line = pos . line , lineN = lineNo ( pos . line ) ;
var view = findViewForLine ( cm , lineN ) ;
if ( view ) {
clearLineMeasurementCacheFor ( view ) ;
cm . curOp . selectionChanged = cm . curOp . forceUpdate = true ;
}
cm . curOp . updateMaxLine = true ;
if ( ! lineIsHidden ( widget . doc , line ) && widget . height != null ) {
var oldHeight = widget . height ;
widget . height = null ;
var dHeight = widgetHeight ( widget ) - oldHeight ;
if ( dHeight )
{ updateLineHeight ( line , line . height + dHeight ) ; }
}
signalLater ( cm , "markerChanged" , cm , this $1 ) ;
} ) ;
} ;
TextMarker . prototype . attachLine = function ( line ) {
if ( ! this . lines . length && this . doc . cm ) {
var op = this . doc . cm . curOp ;
if ( ! op . maybeHiddenMarkers || indexOf ( op . maybeHiddenMarkers , this ) == - 1 )
{ ( op . maybeUnhiddenMarkers || ( op . maybeUnhiddenMarkers = [ ] ) ) . push ( this ) ; }
}
this . lines . push ( line ) ;
} ;
TextMarker . prototype . detachLine = function ( line ) {
this . lines . splice ( indexOf ( this . lines , line ) , 1 ) ;
if ( ! this . lines . length && this . doc . cm ) {
var op = this . doc . cm . curOp ; ( op . maybeHiddenMarkers || ( op . maybeHiddenMarkers = [ ] ) ) . push ( this ) ;
}
} ;
eventMixin ( TextMarker ) ;
// Create a marker, wire it up to the right lines, and
function markText ( doc , from , to , options , type ) {
// Shared markers (across linked documents) are handled separately
// (markTextShared will call out to this again, once per
// document).
if ( options && options . shared ) { return markTextShared ( doc , from , to , options , type ) }
// Ensure we are in an operation.
if ( doc . cm && ! doc . cm . curOp ) { return operation ( doc . cm , markText ) ( doc , from , to , options , type ) }
var marker = new TextMarker ( doc , type ) , diff = cmp ( from , to ) ;
if ( options ) { copyObj ( options , marker , false ) ; }
// Don't connect empty markers unless clearWhenEmpty is false
if ( diff > 0 || diff == 0 && marker . clearWhenEmpty !== false )
{ return marker }
if ( marker . replacedWith ) {
// Showing up as a widget implies collapsed (widget replaces text)
marker . collapsed = true ;
marker . widgetNode = eltP ( "span" , [ marker . replacedWith ] , "CodeMirror-widget" ) ;
if ( ! options . handleMouseEvents ) { marker . widgetNode . setAttribute ( "cm-ignore-events" , "true" ) ; }
if ( options . insertLeft ) { marker . widgetNode . insertLeft = true ; }
}
if ( marker . collapsed ) {
if ( conflictingCollapsedRange ( doc , from . line , from , to , marker ) ||
from . line != to . line && conflictingCollapsedRange ( doc , to . line , from , to , marker ) )
{ throw new Error ( "Inserting collapsed marker partially overlapping an existing one" ) }
seeCollapsedSpans ( ) ;
}
if ( marker . addToHistory )
{ addChangeToHistory ( doc , { from : from , to : to , origin : "markText" } , doc . sel , NaN ) ; }
var curLine = from . line , cm = doc . cm , updateMaxLine ;
doc . iter ( curLine , to . line + 1 , function ( line ) {
if ( cm && marker . collapsed && ! cm . options . lineWrapping && visualLine ( line ) == cm . display . maxLine )
{ updateMaxLine = true ; }
if ( marker . collapsed && curLine != from . line ) { updateLineHeight ( line , 0 ) ; }
addMarkedSpan ( line , new MarkedSpan ( marker ,
curLine == from . line ? from . ch : null ,
curLine == to . line ? to . ch : null ) ) ;
++ curLine ;
} ) ;
// lineIsHidden depends on the presence of the spans, so needs a second pass
if ( marker . collapsed ) { doc . iter ( from . line , to . line + 1 , function ( line ) {
if ( lineIsHidden ( doc , line ) ) { updateLineHeight ( line , 0 ) ; }
} ) ; }
if ( marker . clearOnEnter ) { on ( marker , "beforeCursorEnter" , function ( ) { return marker . clear ( ) ; } ) ; }
if ( marker . readOnly ) {
seeReadOnlySpans ( ) ;
if ( doc . history . done . length || doc . history . undone . length )
{ doc . clearHistory ( ) ; }
}
if ( marker . collapsed ) {
marker . id = ++ nextMarkerId ;
marker . atomic = true ;
}
if ( cm ) {
// Sync editor state
if ( updateMaxLine ) { cm . curOp . updateMaxLine = true ; }
if ( marker . collapsed )
{ regChange ( cm , from . line , to . line + 1 ) ; }
else if ( marker . className || marker . title || marker . startStyle || marker . endStyle || marker . css )
{ for ( var i = from . line ; i <= to . line ; i ++ ) { regLineChange ( cm , i , "text" ) ; } }
if ( marker . atomic ) { reCheckSelection ( cm . doc ) ; }
signalLater ( cm , "markerAdded" , cm , marker ) ;
}
return marker
}
// SHARED TEXTMARKERS
// A shared marker spans multiple linked documents. It is
// implemented as a meta-marker-object controlling multiple normal
// markers.
var SharedTextMarker = function ( markers , primary ) {
var this $1 = this ;
this . markers = markers ;
this . primary = primary ;
for ( var i = 0 ; i < markers . length ; ++ i )
{ markers [ i ] . parent = this $1 ; }
} ;
SharedTextMarker . prototype . clear = function ( ) {
var this $1 = this ;
if ( this . explicitlyCleared ) { return }
this . explicitlyCleared = true ;
for ( var i = 0 ; i < this . markers . length ; ++ i )
{ this $1 . markers [ i ] . clear ( ) ; }
signalLater ( this , "clear" ) ;
} ;
SharedTextMarker . prototype . find = function ( side , lineObj ) {
return this . primary . find ( side , lineObj )
} ;
eventMixin ( SharedTextMarker ) ;
function markTextShared ( doc , from , to , options , type ) {
options = copyObj ( options ) ;
options . shared = false ;
var markers = [ markText ( doc , from , to , options , type ) ] , primary = markers [ 0 ] ;
var widget = options . widgetNode ;
linkedDocs ( doc , function ( doc ) {
if ( widget ) { options . widgetNode = widget . cloneNode ( true ) ; }
markers . push ( markText ( doc , clipPos ( doc , from ) , clipPos ( doc , to ) , options , type ) ) ;
for ( var i = 0 ; i < doc . linked . length ; ++ i )
{ if ( doc . linked [ i ] . isParent ) { return } }
primary = lst ( markers ) ;
} ) ;
return new SharedTextMarker ( markers , primary )
}
function findSharedMarkers ( doc ) {
return doc . findMarks ( Pos ( doc . first , 0 ) , doc . clipPos ( Pos ( doc . lastLine ( ) ) ) , function ( m ) { return m . parent ; } )
}
function copySharedMarkers ( doc , markers ) {
for ( var i = 0 ; i < markers . length ; i ++ ) {
var marker = markers [ i ] , pos = marker . find ( ) ;
var mFrom = doc . clipPos ( pos . from ) , mTo = doc . clipPos ( pos . to ) ;
if ( cmp ( mFrom , mTo ) ) {
var subMark = markText ( doc , mFrom , mTo , marker . primary , marker . primary . type ) ;
marker . markers . push ( subMark ) ;
subMark . parent = marker ;
}
}
}
function detachSharedMarkers ( markers ) {
var loop = function ( i ) {
var marker = markers [ i ] , linked = [ marker . primary . doc ] ;
linkedDocs ( marker . primary . doc , function ( d ) { return linked . push ( d ) ; } ) ;
for ( var j = 0 ; j < marker . markers . length ; j ++ ) {
var subMarker = marker . markers [ j ] ;
if ( indexOf ( linked , subMarker . doc ) == - 1 ) {
subMarker . parent = null ;
marker . markers . splice ( j -- , 1 ) ;
}
}
} ;
for ( var i = 0 ; i < markers . length ; i ++ ) loop ( i ) ;
}
var nextDocId = 0 ;
var Doc = function ( text , mode , firstLine , lineSep , direction ) {
if ( ! ( this instanceof Doc ) ) { return new Doc ( text , mode , firstLine , lineSep , direction ) }
if ( firstLine == null ) { firstLine = 0 ; }
BranchChunk . call ( this , [ new LeafChunk ( [ new Line ( "" , null ) ] ) ] ) ;
this . first = firstLine ;
this . scrollTop = this . scrollLeft = 0 ;
this . cantEdit = false ;
this . cleanGeneration = 1 ;
this . frontier = firstLine ;
var start = Pos ( firstLine , 0 ) ;
this . sel = simpleSelection ( start ) ;
this . history = new History ( null ) ;
this . id = ++ nextDocId ;
this . modeOption = mode ;
this . lineSep = lineSep ;
this . direction = ( direction == "rtl" ) ? "rtl" : "ltr" ;
this . extend = false ;
if ( typeof text == "string" ) { text = this . splitLines ( text ) ; }
updateDoc ( this , { from : start , to : start , text : text } ) ;
setSelection ( this , simpleSelection ( start ) , sel _dontScroll ) ;
} ;
Doc . prototype = createObj ( BranchChunk . prototype , {
constructor : Doc ,
// Iterate over the document. Supports two forms -- with only one
// argument, it calls that for each line in the document. With
// three, it iterates over the range given by the first two (with
// the second being non-inclusive).
iter : function ( from , to , op ) {
if ( op ) { this . iterN ( from - this . first , to - from , op ) ; }
else { this . iterN ( this . first , this . first + this . size , from ) ; }
} ,
// Non-public interface for adding and removing lines.
insert : function ( at , lines ) {
var height = 0 ;
for ( var i = 0 ; i < lines . length ; ++ i ) { height += lines [ i ] . height ; }
this . insertInner ( at - this . first , lines , height ) ;
} ,
remove : function ( at , n ) { this . removeInner ( at - this . first , n ) ; } ,
// From here, the methods are part of the public interface. Most
// are also available from CodeMirror (editor) instances.
getValue : function ( lineSep ) {
var lines = getLines ( this , this . first , this . first + this . size ) ;
if ( lineSep === false ) { return lines }
return lines . join ( lineSep || this . lineSeparator ( ) )
} ,
setValue : docMethodOp ( function ( code ) {
var top = Pos ( this . first , 0 ) , last = this . first + this . size - 1 ;
makeChange ( this , { from : top , to : Pos ( last , getLine ( this , last ) . text . length ) ,
text : this . splitLines ( code ) , origin : "setValue" , full : true } , true ) ;
if ( this . cm ) { scrollToCoords ( this . cm , 0 , 0 ) ; }
setSelection ( this , simpleSelection ( top ) , sel _dontScroll ) ;
} ) ,
replaceRange : function ( code , from , to , origin ) {
from = clipPos ( this , from ) ;
to = to ? clipPos ( this , to ) : from ;
replaceRange ( this , code , from , to , origin ) ;
} ,
getRange : function ( from , to , lineSep ) {
var lines = getBetween ( this , clipPos ( this , from ) , clipPos ( this , to ) ) ;
if ( lineSep === false ) { return lines }
return lines . join ( lineSep || this . lineSeparator ( ) )
} ,
getLine : function ( line ) { var l = this . getLineHandle ( line ) ; return l && l . text } ,
getLineHandle : function ( line ) { if ( isLine ( this , line ) ) { return getLine ( this , line ) } } ,
getLineNumber : function ( line ) { return lineNo ( line ) } ,
getLineHandleVisualStart : function ( line ) {
if ( typeof line == "number" ) { line = getLine ( this , line ) ; }
return visualLine ( line )
} ,
lineCount : function ( ) { return this . size } ,
firstLine : function ( ) { return this . first } ,
lastLine : function ( ) { return this . first + this . size - 1 } ,
clipPos : function ( pos ) { return clipPos ( this , pos ) } ,
getCursor : function ( start ) {
var range$$1 = this . sel . primary ( ) , pos ;
if ( start == null || start == "head" ) { pos = range$$1 . head ; }
else if ( start == "anchor" ) { pos = range$$1 . anchor ; }
else if ( start == "end" || start == "to" || start === false ) { pos = range$$1 . to ( ) ; }
else { pos = range$$1 . from ( ) ; }
return pos
} ,
listSelections : function ( ) { return this . sel . ranges } ,
somethingSelected : function ( ) { return this . sel . somethingSelected ( ) } ,
setCursor : docMethodOp ( function ( line , ch , options ) {
setSimpleSelection ( this , clipPos ( this , typeof line == "number" ? Pos ( line , ch || 0 ) : line ) , null , options ) ;
} ) ,
setSelection : docMethodOp ( function ( anchor , head , options ) {
setSimpleSelection ( this , clipPos ( this , anchor ) , clipPos ( this , head || anchor ) , options ) ;
} ) ,
extendSelection : docMethodOp ( function ( head , other , options ) {
extendSelection ( this , clipPos ( this , head ) , other && clipPos ( this , other ) , options ) ;
} ) ,
extendSelections : docMethodOp ( function ( heads , options ) {
extendSelections ( this , clipPosArray ( this , heads ) , options ) ;
} ) ,
extendSelectionsBy : docMethodOp ( function ( f , options ) {
var heads = map ( this . sel . ranges , f ) ;
extendSelections ( this , clipPosArray ( this , heads ) , options ) ;
} ) ,
setSelections : docMethodOp ( function ( ranges , primary , options ) {
var this $1 = this ;
if ( ! ranges . length ) { return }
var out = [ ] ;
for ( var i = 0 ; i < ranges . length ; i ++ )
{ out [ i ] = new Range ( clipPos ( this $1 , ranges [ i ] . anchor ) ,
clipPos ( this $1 , ranges [ i ] . head ) ) ; }
if ( primary == null ) { primary = Math . min ( ranges . length - 1 , this . sel . primIndex ) ; }
setSelection ( this , normalizeSelection ( out , primary ) , options ) ;
} ) ,
addSelection : docMethodOp ( function ( anchor , head , options ) {
var ranges = this . sel . ranges . slice ( 0 ) ;
ranges . push ( new Range ( clipPos ( this , anchor ) , clipPos ( this , head || anchor ) ) ) ;
setSelection ( this , normalizeSelection ( ranges , ranges . length - 1 ) , options ) ;
} ) ,
getSelection : function ( lineSep ) {
var this $1 = this ;
var ranges = this . sel . ranges , lines ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var sel = getBetween ( this $1 , ranges [ i ] . from ( ) , ranges [ i ] . to ( ) ) ;
lines = lines ? lines . concat ( sel ) : sel ;
}
if ( lineSep === false ) { return lines }
else { return lines . join ( lineSep || this . lineSeparator ( ) ) }
} ,
getSelections : function ( lineSep ) {
var this $1 = this ;
var parts = [ ] , ranges = this . sel . ranges ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var sel = getBetween ( this $1 , ranges [ i ] . from ( ) , ranges [ i ] . to ( ) ) ;
if ( lineSep !== false ) { sel = sel . join ( lineSep || this $1 . lineSeparator ( ) ) ; }
parts [ i ] = sel ;
}
return parts
} ,
replaceSelection : function ( code , collapse , origin ) {
var dup = [ ] ;
for ( var i = 0 ; i < this . sel . ranges . length ; i ++ )
{ dup [ i ] = code ; }
this . replaceSelections ( dup , collapse , origin || "+input" ) ;
} ,
replaceSelections : docMethodOp ( function ( code , collapse , origin ) {
var this $1 = this ;
var changes = [ ] , sel = this . sel ;
for ( var i = 0 ; i < sel . ranges . length ; i ++ ) {
var range$$1 = sel . ranges [ i ] ;
changes [ i ] = { from : range$$1 . from ( ) , to : range$$1 . to ( ) , text : this $1 . splitLines ( code [ i ] ) , origin : origin } ;
}
var newSel = collapse && collapse != "end" && computeReplacedSel ( this , changes , collapse ) ;
for ( var i$1 = changes . length - 1 ; i$1 >= 0 ; i$1 -- )
{ makeChange ( this $1 , changes [ i$1 ] ) ; }
if ( newSel ) { setSelectionReplaceHistory ( this , newSel ) ; }
else if ( this . cm ) { ensureCursorVisible ( this . cm ) ; }
} ) ,
undo : docMethodOp ( function ( ) { makeChangeFromHistory ( this , "undo" ) ; } ) ,
redo : docMethodOp ( function ( ) { makeChangeFromHistory ( this , "redo" ) ; } ) ,
undoSelection : docMethodOp ( function ( ) { makeChangeFromHistory ( this , "undo" , true ) ; } ) ,
redoSelection : docMethodOp ( function ( ) { makeChangeFromHistory ( this , "redo" , true ) ; } ) ,
setExtending : function ( val ) { this . extend = val ; } ,
getExtending : function ( ) { return this . extend } ,
historySize : function ( ) {
var hist = this . history , done = 0 , undone = 0 ;
for ( var i = 0 ; i < hist . done . length ; i ++ ) { if ( ! hist . done [ i ] . ranges ) { ++ done ; } }
for ( var i$1 = 0 ; i$1 < hist . undone . length ; i$1 ++ ) { if ( ! hist . undone [ i$1 ] . ranges ) { ++ undone ; } }
return { undo : done , redo : undone }
} ,
clearHistory : function ( ) { this . history = new History ( this . history . maxGeneration ) ; } ,
markClean : function ( ) {
this . cleanGeneration = this . changeGeneration ( true ) ;
} ,
changeGeneration : function ( forceSplit ) {
if ( forceSplit )
{ this . history . lastOp = this . history . lastSelOp = this . history . lastOrigin = null ; }
return this . history . generation
} ,
isClean : function ( gen ) {
return this . history . generation == ( gen || this . cleanGeneration )
} ,
getHistory : function ( ) {
return { done : copyHistoryArray ( this . history . done ) ,
undone : copyHistoryArray ( this . history . undone ) }
} ,
setHistory : function ( histData ) {
var hist = this . history = new History ( this . history . maxGeneration ) ;
hist . done = copyHistoryArray ( histData . done . slice ( 0 ) , null , true ) ;
hist . undone = copyHistoryArray ( histData . undone . slice ( 0 ) , null , true ) ;
} ,
setGutterMarker : docMethodOp ( function ( line , gutterID , value ) {
return changeLine ( this , line , "gutter" , function ( line ) {
var markers = line . gutterMarkers || ( line . gutterMarkers = { } ) ;
markers [ gutterID ] = value ;
if ( ! value && isEmpty ( markers ) ) { line . gutterMarkers = null ; }
return true
} )
} ) ,
clearGutter : docMethodOp ( function ( gutterID ) {
var this $1 = this ;
this . iter ( function ( line ) {
if ( line . gutterMarkers && line . gutterMarkers [ gutterID ] ) {
changeLine ( this $1 , line , "gutter" , function ( ) {
line . gutterMarkers [ gutterID ] = null ;
if ( isEmpty ( line . gutterMarkers ) ) { line . gutterMarkers = null ; }
return true
} ) ;
}
} ) ;
} ) ,
lineInfo : function ( line ) {
var n ;
if ( typeof line == "number" ) {
if ( ! isLine ( this , line ) ) { return null }
n = line ;
line = getLine ( this , line ) ;
if ( ! line ) { return null }
} else {
n = lineNo ( line ) ;
if ( n == null ) { return null }
}
return { line : n , handle : line , text : line . text , gutterMarkers : line . gutterMarkers ,
textClass : line . textClass , bgClass : line . bgClass , wrapClass : line . wrapClass ,
widgets : line . widgets }
} ,
addLineClass : docMethodOp ( function ( handle , where , cls ) {
return changeLine ( this , handle , where == "gutter" ? "gutter" : "class" , function ( line ) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass" ;
if ( ! line [ prop ] ) { line [ prop ] = cls ; }
else if ( classTest ( cls ) . test ( line [ prop ] ) ) { return false }
else { line [ prop ] += " " + cls ; }
return true
} )
} ) ,
removeLineClass : docMethodOp ( function ( handle , where , cls ) {
return changeLine ( this , handle , where == "gutter" ? "gutter" : "class" , function ( line ) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass" ;
var cur = line [ prop ] ;
if ( ! cur ) { return false }
else if ( cls == null ) { line [ prop ] = null ; }
else {
var found = cur . match ( classTest ( cls ) ) ;
if ( ! found ) { return false }
var end = found . index + found [ 0 ] . length ;
line [ prop ] = cur . slice ( 0 , found . index ) + ( ! found . index || end == cur . length ? "" : " " ) + cur . slice ( end ) || null ;
}
return true
} )
} ) ,
addLineWidget : docMethodOp ( function ( handle , node , options ) {
return addLineWidget ( this , handle , node , options )
} ) ,
removeLineWidget : function ( widget ) { widget . clear ( ) ; } ,
markText : function ( from , to , options ) {
return markText ( this , clipPos ( this , from ) , clipPos ( this , to ) , options , options && options . type || "range" )
} ,
setBookmark : function ( pos , options ) {
var realOpts = { replacedWith : options && ( options . nodeType == null ? options . widget : options ) ,
insertLeft : options && options . insertLeft ,
clearWhenEmpty : false , shared : options && options . shared ,
handleMouseEvents : options && options . handleMouseEvents } ;
pos = clipPos ( this , pos ) ;
return markText ( this , pos , pos , realOpts , "bookmark" )
} ,
findMarksAt : function ( pos ) {
pos = clipPos ( this , pos ) ;
var markers = [ ] , spans = getLine ( this , pos . line ) . markedSpans ;
if ( spans ) { for ( var i = 0 ; i < spans . length ; ++ i ) {
var span = spans [ i ] ;
if ( ( span . from == null || span . from <= pos . ch ) &&
( span . to == null || span . to >= pos . ch ) )
{ markers . push ( span . marker . parent || span . marker ) ; }
} }
return markers
} ,
findMarks : function ( from , to , filter ) {
from = clipPos ( this , from ) ; to = clipPos ( this , to ) ;
var found = [ ] , lineNo$$1 = from . line ;
this . iter ( from . line , to . line + 1 , function ( line ) {
var spans = line . markedSpans ;
if ( spans ) { for ( var i = 0 ; i < spans . length ; i ++ ) {
var span = spans [ i ] ;
if ( ! ( span . to != null && lineNo$$1 == from . line && from . ch >= span . to ||
span . from == null && lineNo$$1 != from . line ||
span . from != null && lineNo$$1 == to . line && span . from >= to . ch ) &&
( ! filter || filter ( span . marker ) ) )
{ found . push ( span . marker . parent || span . marker ) ; }
} }
++ lineNo$$1 ;
} ) ;
return found
} ,
getAllMarks : function ( ) {
var markers = [ ] ;
this . iter ( function ( line ) {
var sps = line . markedSpans ;
if ( sps ) { for ( var i = 0 ; i < sps . length ; ++ i )
{ if ( sps [ i ] . from != null ) { markers . push ( sps [ i ] . marker ) ; } } }
} ) ;
return markers
} ,
posFromIndex : function ( off ) {
var ch , lineNo$$1 = this . first , sepSize = this . lineSeparator ( ) . length ;
this . iter ( function ( line ) {
var sz = line . text . length + sepSize ;
if ( sz > off ) { ch = off ; return true }
off -= sz ;
++ lineNo$$1 ;
} ) ;
return clipPos ( this , Pos ( lineNo$$1 , ch ) )
} ,
indexFromPos : function ( coords ) {
coords = clipPos ( this , coords ) ;
var index = coords . ch ;
if ( coords . line < this . first || coords . ch < 0 ) { return 0 }
var sepSize = this . lineSeparator ( ) . length ;
this . iter ( this . first , coords . line , function ( line ) { // iter aborts when callback returns a truthy value
index += line . text . length + sepSize ;
} ) ;
return index
} ,
copy : function ( copyHistory ) {
var doc = new Doc ( getLines ( this , this . first , this . first + this . size ) ,
this . modeOption , this . first , this . lineSep , this . direction ) ;
doc . scrollTop = this . scrollTop ; doc . scrollLeft = this . scrollLeft ;
doc . sel = this . sel ;
doc . extend = false ;
if ( copyHistory ) {
doc . history . undoDepth = this . history . undoDepth ;
doc . setHistory ( this . getHistory ( ) ) ;
}
return doc
} ,
linkedDoc : function ( options ) {
if ( ! options ) { options = { } ; }
var from = this . first , to = this . first + this . size ;
if ( options . from != null && options . from > from ) { from = options . from ; }
if ( options . to != null && options . to < to ) { to = options . to ; }
var copy = new Doc ( getLines ( this , from , to ) , options . mode || this . modeOption , from , this . lineSep , this . direction ) ;
if ( options . sharedHist ) { copy . history = this . history
; } ( this . linked || ( this . linked = [ ] ) ) . push ( { doc : copy , sharedHist : options . sharedHist } ) ;
copy . linked = [ { doc : this , isParent : true , sharedHist : options . sharedHist } ] ;
copySharedMarkers ( copy , findSharedMarkers ( this ) ) ;
return copy
} ,
unlinkDoc : function ( other ) {
var this $1 = this ;
if ( other instanceof CodeMirror$1 ) { other = other . doc ; }
if ( this . linked ) { for ( var i = 0 ; i < this . linked . length ; ++ i ) {
var link = this $1 . linked [ i ] ;
if ( link . doc != other ) { continue }
this $1 . linked . splice ( i , 1 ) ;
other . unlinkDoc ( this $1 ) ;
detachSharedMarkers ( findSharedMarkers ( this $1 ) ) ;
break
} }
// If the histories were shared, split them again
if ( other . history == this . history ) {
var splitIds = [ other . id ] ;
linkedDocs ( other , function ( doc ) { return splitIds . push ( doc . id ) ; } , true ) ;
other . history = new History ( null ) ;
other . history . done = copyHistoryArray ( this . history . done , splitIds ) ;
other . history . undone = copyHistoryArray ( this . history . undone , splitIds ) ;
}
} ,
iterLinkedDocs : function ( f ) { linkedDocs ( this , f ) ; } ,
getMode : function ( ) { return this . mode } ,
getEditor : function ( ) { return this . cm } ,
splitLines : function ( str ) {
if ( this . lineSep ) { return str . split ( this . lineSep ) }
return splitLinesAuto ( str )
} ,
lineSeparator : function ( ) { return this . lineSep || "\n" } ,
setDirection : docMethodOp ( function ( dir ) {
if ( dir != "rtl" ) { dir = "ltr" ; }
if ( dir == this . direction ) { return }
this . direction = dir ;
this . iter ( function ( line ) { return line . order = null ; } ) ;
if ( this . cm ) { directionChanged ( this . cm ) ; }
} )
} ) ;
// Public alias.
Doc . prototype . eachLine = Doc . prototype . iter ;
// Kludge to work around strange IE behavior where it'll sometimes
// re-fire a series of drag-related events right after the drop (#1551)
var lastDrop = 0 ;
function onDrop ( e ) {
var cm = this ;
clearDragCursor ( cm ) ;
if ( signalDOMEvent ( cm , e ) || eventInWidget ( cm . display , e ) )
{ return }
e _preventDefault ( e ) ;
if ( ie ) { lastDrop = + new Date ; }
var pos = posFromMouse ( cm , e , true ) , files = e . dataTransfer . files ;
if ( ! pos || cm . isReadOnly ( ) ) { return }
// Might be a file drop, in which case we simply extract the text
// and insert it.
if ( files && files . length && window . FileReader && window . File ) {
var n = files . length , text = Array ( n ) , read = 0 ;
var loadFile = function ( file , i ) {
if ( cm . options . allowDropFileTypes &&
indexOf ( cm . options . allowDropFileTypes , file . type ) == - 1 )
{ return }
var reader = new FileReader ;
reader . onload = operation ( cm , function ( ) {
var content = reader . result ;
if ( /[\x00-\x08\x0e-\x1f]{2}/ . test ( content ) ) { content = "" ; }
text [ i ] = content ;
if ( ++ read == n ) {
pos = clipPos ( cm . doc , pos ) ;
var change = { from : pos , to : pos ,
text : cm . doc . splitLines ( text . join ( cm . doc . lineSeparator ( ) ) ) ,
origin : "paste" } ;
makeChange ( cm . doc , change ) ;
setSelectionReplaceHistory ( cm . doc , simpleSelection ( pos , changeEnd ( change ) ) ) ;
}
} ) ;
reader . readAsText ( file ) ;
} ;
for ( var i = 0 ; i < n ; ++ i ) { loadFile ( files [ i ] , i ) ; }
} else { // Normal drop
// Don't do a replace if the drop happened inside of the selected text.
if ( cm . state . draggingText && cm . doc . sel . contains ( pos ) > - 1 ) {
cm . state . draggingText ( e ) ;
// Ensure the editor is re-focused
setTimeout ( function ( ) { return cm . display . input . focus ( ) ; } , 20 ) ;
return
}
try {
var text$1 = e . dataTransfer . getData ( "Text" ) ;
if ( text$1 ) {
var selected ;
if ( cm . state . draggingText && ! cm . state . draggingText . copy )
{ selected = cm . listSelections ( ) ; }
setSelectionNoUndo ( cm . doc , simpleSelection ( pos , pos ) ) ;
if ( selected ) { for ( var i$1 = 0 ; i$1 < selected . length ; ++ i$1 )
{ replaceRange ( cm . doc , "" , selected [ i$1 ] . anchor , selected [ i$1 ] . head , "drag" ) ; } }
cm . replaceSelection ( text$1 , "around" , "paste" ) ;
cm . display . input . focus ( ) ;
}
}
catch ( e ) { }
}
}
function onDragStart ( cm , e ) {
if ( ie && ( ! cm . state . draggingText || + new Date - lastDrop < 100 ) ) { e _stop ( e ) ; return }
if ( signalDOMEvent ( cm , e ) || eventInWidget ( cm . display , e ) ) { return }
e . dataTransfer . setData ( "Text" , cm . getSelection ( ) ) ;
e . dataTransfer . effectAllowed = "copyMove" ;
// Use dummy image instead of default browsers image.
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
if ( e . dataTransfer . setDragImage && ! safari ) {
var img = elt ( "img" , null , null , "position: fixed; left: 0; top: 0;" ) ;
img . src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" ;
if ( presto ) {
img . width = img . height = 1 ;
cm . display . wrapper . appendChild ( img ) ;
// Force a relayout, or Opera won't use our image for some obscure reason
img . _top = img . offsetTop ;
}
e . dataTransfer . setDragImage ( img , 0 , 0 ) ;
if ( presto ) { img . parentNode . removeChild ( img ) ; }
}
}
function onDragOver ( cm , e ) {
var pos = posFromMouse ( cm , e ) ;
if ( ! pos ) { return }
var frag = document . createDocumentFragment ( ) ;
drawSelectionCursor ( cm , pos , frag ) ;
if ( ! cm . display . dragCursor ) {
cm . display . dragCursor = elt ( "div" , null , "CodeMirror-cursors CodeMirror-dragcursors" ) ;
cm . display . lineSpace . insertBefore ( cm . display . dragCursor , cm . display . cursorDiv ) ;
}
removeChildrenAndAdd ( cm . display . dragCursor , frag ) ;
}
function clearDragCursor ( cm ) {
if ( cm . display . dragCursor ) {
cm . display . lineSpace . removeChild ( cm . display . dragCursor ) ;
cm . display . dragCursor = null ;
}
}
// These must be handled carefully, because naively registering a
// handler for each editor will cause the editors to never be
// garbage collected.
function forEachCodeMirror ( f ) {
if ( ! document . body . getElementsByClassName ) { return }
var byClass = document . body . getElementsByClassName ( "CodeMirror" ) ;
for ( var i = 0 ; i < byClass . length ; i ++ ) {
var cm = byClass [ i ] . CodeMirror ;
if ( cm ) { f ( cm ) ; }
}
}
var globalsRegistered = false ;
function ensureGlobalHandlers ( ) {
if ( globalsRegistered ) { return }
registerGlobalHandlers ( ) ;
globalsRegistered = true ;
}
function registerGlobalHandlers ( ) {
// When the window resizes, we need to refresh active editors.
var resizeTimer ;
on ( window , "resize" , function ( ) {
if ( resizeTimer == null ) { resizeTimer = setTimeout ( function ( ) {
resizeTimer = null ;
forEachCodeMirror ( onResize ) ;
} , 100 ) ; }
} ) ;
// When the window loses focus, we want to show the editor as blurred
on ( window , "blur" , function ( ) { return forEachCodeMirror ( onBlur ) ; } ) ;
}
// Called when the window resizes
function onResize ( cm ) {
var d = cm . display ;
if ( d . lastWrapHeight == d . wrapper . clientHeight && d . lastWrapWidth == d . wrapper . clientWidth )
{ return }
// Might be a text scaling operation, clear size caches.
d . cachedCharWidth = d . cachedTextHeight = d . cachedPaddingH = null ;
d . scrollbarsClipped = false ;
cm . setSize ( ) ;
}
var keyNames = {
3 : "Enter" , 8 : "Backspace" , 9 : "Tab" , 13 : "Enter" , 16 : "Shift" , 17 : "Ctrl" , 18 : "Alt" ,
19 : "Pause" , 20 : "CapsLock" , 27 : "Esc" , 32 : "Space" , 33 : "PageUp" , 34 : "PageDown" , 35 : "End" ,
36 : "Home" , 37 : "Left" , 38 : "Up" , 39 : "Right" , 40 : "Down" , 44 : "PrintScrn" , 45 : "Insert" ,
46 : "Delete" , 59 : ";" , 61 : "=" , 91 : "Mod" , 92 : "Mod" , 93 : "Mod" ,
106 : "*" , 107 : "=" , 109 : "-" , 110 : "." , 111 : "/" , 127 : "Delete" ,
173 : "-" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" ,
221 : "]" , 222 : "'" , 63232 : "Up" , 63233 : "Down" , 63234 : "Left" , 63235 : "Right" , 63272 : "Delete" ,
63273 : "Home" , 63275 : "End" , 63276 : "PageUp" , 63277 : "PageDown" , 63302 : "Insert"
} ;
// Number keys
for ( var i = 0 ; i < 10 ; i ++ ) { keyNames [ i + 48 ] = keyNames [ i + 96 ] = String ( i ) ; }
// Alphabetic keys
for ( var i$1 = 65 ; i$1 <= 90 ; i$1 ++ ) { keyNames [ i$1 ] = String . fromCharCode ( i$1 ) ; }
// Function keys
for ( var i$2 = 1 ; i$2 <= 12 ; i$2 ++ ) { keyNames [ i$2 + 111 ] = keyNames [ i$2 + 63235 ] = "F" + i$2 ; }
var keyMap = { } ;
keyMap . basic = {
"Left" : "goCharLeft" , "Right" : "goCharRight" , "Up" : "goLineUp" , "Down" : "goLineDown" ,
"End" : "goLineEnd" , "Home" : "goLineStartSmart" , "PageUp" : "goPageUp" , "PageDown" : "goPageDown" ,
"Delete" : "delCharAfter" , "Backspace" : "delCharBefore" , "Shift-Backspace" : "delCharBefore" ,
"Tab" : "defaultTab" , "Shift-Tab" : "indentAuto" ,
"Enter" : "newlineAndIndent" , "Insert" : "toggleOverwrite" ,
"Esc" : "singleSelection"
} ;
// Note that the save and find-related commands aren't defined by
// default. User code or addons can define them. Unknown commands
// are simply ignored.
keyMap . pcDefault = {
"Ctrl-A" : "selectAll" , "Ctrl-D" : "deleteLine" , "Ctrl-Z" : "undo" , "Shift-Ctrl-Z" : "redo" , "Ctrl-Y" : "redo" ,
"Ctrl-Home" : "goDocStart" , "Ctrl-End" : "goDocEnd" , "Ctrl-Up" : "goLineUp" , "Ctrl-Down" : "goLineDown" ,
"Ctrl-Left" : "goGroupLeft" , "Ctrl-Right" : "goGroupRight" , "Alt-Left" : "goLineStart" , "Alt-Right" : "goLineEnd" ,
"Ctrl-Backspace" : "delGroupBefore" , "Ctrl-Delete" : "delGroupAfter" , "Ctrl-S" : "save" , "Ctrl-F" : "find" ,
"Ctrl-G" : "findNext" , "Shift-Ctrl-G" : "findPrev" , "Shift-Ctrl-F" : "replace" , "Shift-Ctrl-R" : "replaceAll" ,
"Ctrl-[" : "indentLess" , "Ctrl-]" : "indentMore" ,
"Ctrl-U" : "undoSelection" , "Shift-Ctrl-U" : "redoSelection" , "Alt-U" : "redoSelection" ,
fallthrough : "basic"
} ;
// Very basic readline/emacs-style bindings, which are standard on Mac.
keyMap . emacsy = {
"Ctrl-F" : "goCharRight" , "Ctrl-B" : "goCharLeft" , "Ctrl-P" : "goLineUp" , "Ctrl-N" : "goLineDown" ,
"Alt-F" : "goWordRight" , "Alt-B" : "goWordLeft" , "Ctrl-A" : "goLineStart" , "Ctrl-E" : "goLineEnd" ,
"Ctrl-V" : "goPageDown" , "Shift-Ctrl-V" : "goPageUp" , "Ctrl-D" : "delCharAfter" , "Ctrl-H" : "delCharBefore" ,
"Alt-D" : "delWordAfter" , "Alt-Backspace" : "delWordBefore" , "Ctrl-K" : "killLine" , "Ctrl-T" : "transposeChars" ,
"Ctrl-O" : "openLine"
} ;
keyMap . macDefault = {
"Cmd-A" : "selectAll" , "Cmd-D" : "deleteLine" , "Cmd-Z" : "undo" , "Shift-Cmd-Z" : "redo" , "Cmd-Y" : "redo" ,
"Cmd-Home" : "goDocStart" , "Cmd-Up" : "goDocStart" , "Cmd-End" : "goDocEnd" , "Cmd-Down" : "goDocEnd" , "Alt-Left" : "goGroupLeft" ,
"Alt-Right" : "goGroupRight" , "Cmd-Left" : "goLineLeft" , "Cmd-Right" : "goLineRight" , "Alt-Backspace" : "delGroupBefore" ,
"Ctrl-Alt-Backspace" : "delGroupAfter" , "Alt-Delete" : "delGroupAfter" , "Cmd-S" : "save" , "Cmd-F" : "find" ,
"Cmd-G" : "findNext" , "Shift-Cmd-G" : "findPrev" , "Cmd-Alt-F" : "replace" , "Shift-Cmd-Alt-F" : "replaceAll" ,
"Cmd-[" : "indentLess" , "Cmd-]" : "indentMore" , "Cmd-Backspace" : "delWrappedLineLeft" , "Cmd-Delete" : "delWrappedLineRight" ,
"Cmd-U" : "undoSelection" , "Shift-Cmd-U" : "redoSelection" , "Ctrl-Up" : "goDocStart" , "Ctrl-Down" : "goDocEnd" ,
fallthrough : [ "basic" , "emacsy" ]
} ;
keyMap [ "default" ] = mac ? keyMap . macDefault : keyMap . pcDefault ;
// KEYMAP DISPATCH
function normalizeKeyName ( name ) {
var parts = name . split ( /-(?!$)/ ) ;
name = parts [ parts . length - 1 ] ;
var alt , ctrl , shift , cmd ;
for ( var i = 0 ; i < parts . length - 1 ; i ++ ) {
var mod = parts [ i ] ;
if ( /^(cmd|meta|m)$/i . test ( mod ) ) { cmd = true ; }
else if ( /^a(lt)?$/i . test ( mod ) ) { alt = true ; }
else if ( /^(c|ctrl|control)$/i . test ( mod ) ) { ctrl = true ; }
else if ( /^s(hift)?$/i . test ( mod ) ) { shift = true ; }
else { throw new Error ( "Unrecognized modifier name: " + mod ) }
}
if ( alt ) { name = "Alt-" + name ; }
if ( ctrl ) { name = "Ctrl-" + name ; }
if ( cmd ) { name = "Cmd-" + name ; }
if ( shift ) { name = "Shift-" + name ; }
return name
}
// This is a kludge to keep keymaps mostly working as raw objects
// (backwards compatibility) while at the same time support features
// like normalization and multi-stroke key bindings. It compiles a
// new normalized keymap, and then updates the old object to reflect
// this.
function normalizeKeyMap ( keymap ) {
var copy = { } ;
for ( var keyname in keymap ) { if ( keymap . hasOwnProperty ( keyname ) ) {
var value = keymap [ keyname ] ;
if ( /^(name|fallthrough|(de|at)tach)$/ . test ( keyname ) ) { continue }
if ( value == "..." ) { delete keymap [ keyname ] ; continue }
var keys = map ( keyname . split ( " " ) , normalizeKeyName ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var val = ( void 0 ) , name = ( void 0 ) ;
if ( i == keys . length - 1 ) {
name = keys . join ( " " ) ;
val = value ;
} else {
name = keys . slice ( 0 , i + 1 ) . join ( " " ) ;
val = "..." ;
}
var prev = copy [ name ] ;
if ( ! prev ) { copy [ name ] = val ; }
else if ( prev != val ) { throw new Error ( "Inconsistent bindings for " + name ) }
}
delete keymap [ keyname ] ;
} }
for ( var prop in copy ) { keymap [ prop ] = copy [ prop ] ; }
return keymap
}
function lookupKey ( key , map$$1 , handle , context ) {
map$$1 = getKeyMap ( map$$1 ) ;
var found = map$$1 . call ? map$$1 . call ( key , context ) : map$$1 [ key ] ;
if ( found === false ) { return "nothing" }
if ( found === "..." ) { return "multi" }
if ( found != null && handle ( found ) ) { return "handled" }
if ( map$$1 . fallthrough ) {
if ( Object . prototype . toString . call ( map$$1 . fallthrough ) != "[object Array]" )
{ return lookupKey ( key , map$$1 . fallthrough , handle , context ) }
for ( var i = 0 ; i < map$$1 . fallthrough . length ; i ++ ) {
var result = lookupKey ( key , map$$1 . fallthrough [ i ] , handle , context ) ;
if ( result ) { return result }
}
}
}
// Modifier key presses don't count as 'real' key presses for the
// purpose of keymap fallthrough.
function isModifierKey ( value ) {
var name = typeof value == "string" ? value : keyNames [ value . keyCode ] ;
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
}
// Look up the name of a key as indicated by an event object.
function keyName ( event , noShift ) {
if ( presto && event . keyCode == 34 && event [ "char" ] ) { return false }
var base = keyNames [ event . keyCode ] , name = base ;
if ( name == null || event . altGraphKey ) { return false }
if ( event . altKey && base != "Alt" ) { name = "Alt-" + name ; }
if ( ( flipCtrlCmd ? event . metaKey : event . ctrlKey ) && base != "Ctrl" ) { name = "Ctrl-" + name ; }
if ( ( flipCtrlCmd ? event . ctrlKey : event . metaKey ) && base != "Cmd" ) { name = "Cmd-" + name ; }
if ( ! noShift && event . shiftKey && base != "Shift" ) { name = "Shift-" + name ; }
return name
}
function getKeyMap ( val ) {
return typeof val == "string" ? keyMap [ val ] : val
}
// Helper for deleting text near the selection(s), used to implement
// backspace, delete, and similar functionality.
function deleteNearSelection ( cm , compute ) {
var ranges = cm . doc . sel . ranges , kill = [ ] ;
// Build up a set of ranges to kill first, merging overlapping
// ranges.
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var toKill = compute ( ranges [ i ] ) ;
while ( kill . length && cmp ( toKill . from , lst ( kill ) . to ) <= 0 ) {
var replaced = kill . pop ( ) ;
if ( cmp ( replaced . from , toKill . from ) < 0 ) {
toKill . from = replaced . from ;
break
}
}
kill . push ( toKill ) ;
}
// Next, remove those actual ranges.
runInOp ( cm , function ( ) {
for ( var i = kill . length - 1 ; i >= 0 ; i -- )
{ replaceRange ( cm . doc , "" , kill [ i ] . from , kill [ i ] . to , "+delete" ) ; }
ensureCursorVisible ( cm ) ;
} ) ;
}
// Commands are parameter-less actions that can be performed on an
// editor, mostly used for keybindings.
var commands = {
selectAll : selectAll ,
singleSelection : function ( cm ) { return cm . setSelection ( cm . getCursor ( "anchor" ) , cm . getCursor ( "head" ) , sel _dontScroll ) ; } ,
killLine : function ( cm ) { return deleteNearSelection ( cm , function ( range ) {
if ( range . empty ( ) ) {
var len = getLine ( cm . doc , range . head . line ) . text . length ;
if ( range . head . ch == len && range . head . line < cm . lastLine ( ) )
{ return { from : range . head , to : Pos ( range . head . line + 1 , 0 ) } }
else
{ return { from : range . head , to : Pos ( range . head . line , len ) } }
} else {
return { from : range . from ( ) , to : range . to ( ) }
}
} ) ; } ,
deleteLine : function ( cm ) { return deleteNearSelection ( cm , function ( range ) { return ( {
from : Pos ( range . from ( ) . line , 0 ) ,
to : clipPos ( cm . doc , Pos ( range . to ( ) . line + 1 , 0 ) )
} ) ; } ) ; } ,
delLineLeft : function ( cm ) { return deleteNearSelection ( cm , function ( range ) { return ( {
from : Pos ( range . from ( ) . line , 0 ) , to : range . from ( )
} ) ; } ) ; } ,
delWrappedLineLeft : function ( cm ) { return deleteNearSelection ( cm , function ( range ) {
var top = cm . charCoords ( range . head , "div" ) . top + 5 ;
var leftPos = cm . coordsChar ( { left : 0 , top : top } , "div" ) ;
return { from : leftPos , to : range . from ( ) }
} ) ; } ,
delWrappedLineRight : function ( cm ) { return deleteNearSelection ( cm , function ( range ) {
var top = cm . charCoords ( range . head , "div" ) . top + 5 ;
var rightPos = cm . coordsChar ( { left : cm . display . lineDiv . offsetWidth + 100 , top : top } , "div" ) ;
return { from : range . from ( ) , to : rightPos }
} ) ; } ,
undo : function ( cm ) { return cm . undo ( ) ; } ,
redo : function ( cm ) { return cm . redo ( ) ; } ,
undoSelection : function ( cm ) { return cm . undoSelection ( ) ; } ,
redoSelection : function ( cm ) { return cm . redoSelection ( ) ; } ,
goDocStart : function ( cm ) { return cm . extendSelection ( Pos ( cm . firstLine ( ) , 0 ) ) ; } ,
goDocEnd : function ( cm ) { return cm . extendSelection ( Pos ( cm . lastLine ( ) ) ) ; } ,
goLineStart : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) { return lineStart ( cm , range . head . line ) ; } ,
{ origin : "+move" , bias : 1 }
) ; } ,
goLineStartSmart : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) { return lineStartSmart ( cm , range . head ) ; } ,
{ origin : "+move" , bias : 1 }
) ; } ,
goLineEnd : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) { return lineEnd ( cm , range . head . line ) ; } ,
{ origin : "+move" , bias : - 1 }
) ; } ,
goLineRight : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) {
var top = cm . charCoords ( range . head , "div" ) . top + 5 ;
return cm . coordsChar ( { left : cm . display . lineDiv . offsetWidth + 100 , top : top } , "div" )
} , sel _move ) ; } ,
goLineLeft : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) {
var top = cm . charCoords ( range . head , "div" ) . top + 5 ;
return cm . coordsChar ( { left : 0 , top : top } , "div" )
} , sel _move ) ; } ,
goLineLeftSmart : function ( cm ) { return cm . extendSelectionsBy ( function ( range ) {
var top = cm . charCoords ( range . head , "div" ) . top + 5 ;
var pos = cm . coordsChar ( { left : 0 , top : top } , "div" ) ;
if ( pos . ch < cm . getLine ( pos . line ) . search ( /\S/ ) ) { return lineStartSmart ( cm , range . head ) }
return pos
} , sel _move ) ; } ,
goLineUp : function ( cm ) { return cm . moveV ( - 1 , "line" ) ; } ,
goLineDown : function ( cm ) { return cm . moveV ( 1 , "line" ) ; } ,
goPageUp : function ( cm ) { return cm . moveV ( - 1 , "page" ) ; } ,
goPageDown : function ( cm ) { return cm . moveV ( 1 , "page" ) ; } ,
goCharLeft : function ( cm ) { return cm . moveH ( - 1 , "char" ) ; } ,
goCharRight : function ( cm ) { return cm . moveH ( 1 , "char" ) ; } ,
goColumnLeft : function ( cm ) { return cm . moveH ( - 1 , "column" ) ; } ,
goColumnRight : function ( cm ) { return cm . moveH ( 1 , "column" ) ; } ,
goWordLeft : function ( cm ) { return cm . moveH ( - 1 , "word" ) ; } ,
goGroupRight : function ( cm ) { return cm . moveH ( 1 , "group" ) ; } ,
goGroupLeft : function ( cm ) { return cm . moveH ( - 1 , "group" ) ; } ,
goWordRight : function ( cm ) { return cm . moveH ( 1 , "word" ) ; } ,
delCharBefore : function ( cm ) { return cm . deleteH ( - 1 , "char" ) ; } ,
delCharAfter : function ( cm ) { return cm . deleteH ( 1 , "char" ) ; } ,
delWordBefore : function ( cm ) { return cm . deleteH ( - 1 , "word" ) ; } ,
delWordAfter : function ( cm ) { return cm . deleteH ( 1 , "word" ) ; } ,
delGroupBefore : function ( cm ) { return cm . deleteH ( - 1 , "group" ) ; } ,
delGroupAfter : function ( cm ) { return cm . deleteH ( 1 , "group" ) ; } ,
indentAuto : function ( cm ) { return cm . indentSelection ( "smart" ) ; } ,
indentMore : function ( cm ) { return cm . indentSelection ( "add" ) ; } ,
indentLess : function ( cm ) { return cm . indentSelection ( "subtract" ) ; } ,
insertTab : function ( cm ) { return cm . replaceSelection ( "\t" ) ; } ,
insertSoftTab : function ( cm ) {
var spaces = [ ] , ranges = cm . listSelections ( ) , tabSize = cm . options . tabSize ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var pos = ranges [ i ] . from ( ) ;
var col = countColumn ( cm . getLine ( pos . line ) , pos . ch , tabSize ) ;
spaces . push ( spaceStr ( tabSize - col % tabSize ) ) ;
}
cm . replaceSelections ( spaces ) ;
} ,
defaultTab : function ( cm ) {
if ( cm . somethingSelected ( ) ) { cm . indentSelection ( "add" ) ; }
else { cm . execCommand ( "insertTab" ) ; }
} ,
// Swap the two chars left and right of each selection's head.
// Move cursor behind the two swapped characters afterwards.
//
// Doesn't consider line feeds a character.
// Doesn't scan more than one line above to find a character.
// Doesn't do anything on an empty line.
// Doesn't do anything with non-empty selections.
transposeChars : function ( cm ) { return runInOp ( cm , function ( ) {
var ranges = cm . listSelections ( ) , newSel = [ ] ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
if ( ! ranges [ i ] . empty ( ) ) { continue }
var cur = ranges [ i ] . head , line = getLine ( cm . doc , cur . line ) . text ;
if ( line ) {
if ( cur . ch == line . length ) { cur = new Pos ( cur . line , cur . ch - 1 ) ; }
if ( cur . ch > 0 ) {
cur = new Pos ( cur . line , cur . ch + 1 ) ;
cm . replaceRange ( line . charAt ( cur . ch - 1 ) + line . charAt ( cur . ch - 2 ) ,
Pos ( cur . line , cur . ch - 2 ) , cur , "+transpose" ) ;
} else if ( cur . line > cm . doc . first ) {
var prev = getLine ( cm . doc , cur . line - 1 ) . text ;
if ( prev ) {
cur = new Pos ( cur . line , 1 ) ;
cm . replaceRange ( line . charAt ( 0 ) + cm . doc . lineSeparator ( ) +
prev . charAt ( prev . length - 1 ) ,
Pos ( cur . line - 1 , prev . length - 1 ) , cur , "+transpose" ) ;
}
}
}
newSel . push ( new Range ( cur , cur ) ) ;
}
cm . setSelections ( newSel ) ;
} ) ; } ,
newlineAndIndent : function ( cm ) { return runInOp ( cm , function ( ) {
var sels = cm . listSelections ( ) ;
for ( var i = sels . length - 1 ; i >= 0 ; i -- )
{ cm . replaceRange ( cm . doc . lineSeparator ( ) , sels [ i ] . anchor , sels [ i ] . head , "+input" ) ; }
sels = cm . listSelections ( ) ;
for ( var i$1 = 0 ; i$1 < sels . length ; i$1 ++ )
{ cm . indentLine ( sels [ i$1 ] . from ( ) . line , null , true ) ; }
ensureCursorVisible ( cm ) ;
} ) ; } ,
openLine : function ( cm ) { return cm . replaceSelection ( "\n" , "start" ) ; } ,
toggleOverwrite : function ( cm ) { return cm . toggleOverwrite ( ) ; }
} ;
function lineStart ( cm , lineN ) {
var line = getLine ( cm . doc , lineN ) ;
var visual = visualLine ( line ) ;
if ( visual != line ) { lineN = lineNo ( visual ) ; }
return endOfLine ( true , cm , visual , lineN , 1 )
}
function lineEnd ( cm , lineN ) {
var line = getLine ( cm . doc , lineN ) ;
var visual = visualLineEnd ( line ) ;
if ( visual != line ) { lineN = lineNo ( visual ) ; }
return endOfLine ( true , cm , line , lineN , - 1 )
}
function lineStartSmart ( cm , pos ) {
var start = lineStart ( cm , pos . line ) ;
var line = getLine ( cm . doc , start . line ) ;
var order = getOrder ( line , cm . doc . direction ) ;
if ( ! order || order [ 0 ] . level == 0 ) {
var firstNonWS = Math . max ( 0 , line . text . search ( /\S/ ) ) ;
var inWS = pos . line == start . line && pos . ch <= firstNonWS && pos . ch ;
return Pos ( start . line , inWS ? 0 : firstNonWS , start . sticky )
}
return start
}
// Run a handler that was bound to a key.
function doHandleBinding ( cm , bound , dropShift ) {
if ( typeof bound == "string" ) {
bound = commands [ bound ] ;
if ( ! bound ) { return false }
}
// Ensure previous input has been read, so that the handler sees a
// consistent view of the document
cm . display . input . ensurePolled ( ) ;
var prevShift = cm . display . shift , done = false ;
try {
if ( cm . isReadOnly ( ) ) { cm . state . suppressEdits = true ; }
if ( dropShift ) { cm . display . shift = false ; }
done = bound ( cm ) != Pass ;
} finally {
cm . display . shift = prevShift ;
cm . state . suppressEdits = false ;
}
return done
}
function lookupKeyForEditor ( cm , name , handle ) {
for ( var i = 0 ; i < cm . state . keyMaps . length ; i ++ ) {
var result = lookupKey ( name , cm . state . keyMaps [ i ] , handle , cm ) ;
if ( result ) { return result }
}
return ( cm . options . extraKeys && lookupKey ( name , cm . options . extraKeys , handle , cm ) )
|| lookupKey ( name , cm . options . keyMap , handle , cm )
}
var stopSeq = new Delayed ;
function dispatchKey ( cm , name , e , handle ) {
var seq = cm . state . keySeq ;
if ( seq ) {
if ( isModifierKey ( name ) ) { return "handled" }
stopSeq . set ( 50 , function ( ) {
if ( cm . state . keySeq == seq ) {
cm . state . keySeq = null ;
cm . display . input . reset ( ) ;
}
} ) ;
name = seq + " " + name ;
}
var result = lookupKeyForEditor ( cm , name , handle ) ;
if ( result == "multi" )
{ cm . state . keySeq = name ; }
if ( result == "handled" )
{ signalLater ( cm , "keyHandled" , cm , name , e ) ; }
if ( result == "handled" || result == "multi" ) {
e _preventDefault ( e ) ;
restartBlink ( cm ) ;
}
if ( seq && ! result && /\'$/ . test ( name ) ) {
e _preventDefault ( e ) ;
return true
}
return ! ! result
}
// Handle a key from the keydown event.
function handleKeyBinding ( cm , e ) {
var name = keyName ( e , true ) ;
if ( ! name ) { return false }
if ( e . shiftKey && ! cm . state . keySeq ) {
// First try to resolve full name (including 'Shift-'). Failing
// that, see if there is a cursor-motion command (starting with
// 'go') bound to the keyname without 'Shift-'.
return dispatchKey ( cm , "Shift-" + name , e , function ( b ) { return doHandleBinding ( cm , b , true ) ; } )
|| dispatchKey ( cm , name , e , function ( b ) {
if ( typeof b == "string" ? /^go[A-Z]/ . test ( b ) : b . motion )
{ return doHandleBinding ( cm , b ) }
} )
} else {
return dispatchKey ( cm , name , e , function ( b ) { return doHandleBinding ( cm , b ) ; } )
}
}
// Handle a key from the keypress event
function handleCharBinding ( cm , e , ch ) {
return dispatchKey ( cm , "'" + ch + "'" , e , function ( b ) { return doHandleBinding ( cm , b , true ) ; } )
}
var lastStoppedKey = null ;
function onKeyDown ( e ) {
var cm = this ;
cm . curOp . focus = activeElt ( ) ;
if ( signalDOMEvent ( cm , e ) ) { return }
// IE does strange things with escape.
if ( ie && ie _version < 11 && e . keyCode == 27 ) { e . returnValue = false ; }
var code = e . keyCode ;
cm . display . shift = code == 16 || e . shiftKey ;
var handled = handleKeyBinding ( cm , e ) ;
if ( presto ) {
lastStoppedKey = handled ? code : null ;
// Opera has no cut event... we try to at least catch the key combo
if ( ! handled && code == 88 && ! hasCopyEvent && ( mac ? e . metaKey : e . ctrlKey ) )
{ cm . replaceSelection ( "" , null , "cut" ) ; }
}
// Turn mouse into crosshair when Alt is held on Mac.
if ( code == 18 && ! /\bCodeMirror-crosshair\b/ . test ( cm . display . lineDiv . className ) )
{ showCrossHair ( cm ) ; }
}
function showCrossHair ( cm ) {
var lineDiv = cm . display . lineDiv ;
addClass ( lineDiv , "CodeMirror-crosshair" ) ;
function up ( e ) {
if ( e . keyCode == 18 || ! e . altKey ) {
rmClass ( lineDiv , "CodeMirror-crosshair" ) ;
off ( document , "keyup" , up ) ;
off ( document , "mouseover" , up ) ;
}
}
on ( document , "keyup" , up ) ;
on ( document , "mouseover" , up ) ;
}
function onKeyUp ( e ) {
if ( e . keyCode == 16 ) { this . doc . sel . shift = false ; }
signalDOMEvent ( this , e ) ;
}
function onKeyPress ( e ) {
var cm = this ;
if ( eventInWidget ( cm . display , e ) || signalDOMEvent ( cm , e ) || e . ctrlKey && ! e . altKey || mac && e . metaKey ) { return }
var keyCode = e . keyCode , charCode = e . charCode ;
if ( presto && keyCode == lastStoppedKey ) { lastStoppedKey = null ; e _preventDefault ( e ) ; return }
if ( ( presto && ( ! e . which || e . which < 10 ) ) && handleKeyBinding ( cm , e ) ) { return }
var ch = String . fromCharCode ( charCode == null ? keyCode : charCode ) ;
// Some browsers fire keypress events for backspace
if ( ch == "\x08" ) { return }
if ( handleCharBinding ( cm , e , ch ) ) { return }
cm . display . input . onKeyPress ( e ) ;
}
// A mouse down can be a single click, double click, triple click,
// start of selection drag, start of text drag, new cursor
// (ctrl-click), rectangle drag (alt-drag), or xwin
// middle-click-paste. Or it might be a click on something we should
// not interfere with, such as a scrollbar or widget.
function onMouseDown ( e ) {
var cm = this , display = cm . display ;
if ( signalDOMEvent ( cm , e ) || display . activeTouch && display . input . supportsTouch ( ) ) { return }
display . input . ensurePolled ( ) ;
display . shift = e . shiftKey ;
if ( eventInWidget ( display , e ) ) {
if ( ! webkit ) {
// Briefly turn off draggability, to allow widgets to do
// normal dragging things.
display . scroller . draggable = false ;
setTimeout ( function ( ) { return display . scroller . draggable = true ; } , 100 ) ;
}
return
}
if ( clickInGutter ( cm , e ) ) { return }
var start = posFromMouse ( cm , e ) ;
window . focus ( ) ;
switch ( e _button ( e ) ) {
case 1 :
// #3261: make sure, that we're not starting a second selection
if ( cm . state . selectingText )
{ cm . state . selectingText ( e ) ; }
else if ( start )
{ leftButtonDown ( cm , e , start ) ; }
else if ( e _target ( e ) == display . scroller )
{ e _preventDefault ( e ) ; }
break
case 2 :
if ( webkit ) { cm . state . lastMiddleDown = + new Date ; }
if ( start ) { extendSelection ( cm . doc , start ) ; }
setTimeout ( function ( ) { return display . input . focus ( ) ; } , 20 ) ;
e _preventDefault ( e ) ;
break
case 3 :
if ( captureRightClick ) { onContextMenu ( cm , e ) ; }
else { delayBlurEvent ( cm ) ; }
break
}
}
var lastClick ;
var lastDoubleClick ;
function leftButtonDown ( cm , e , start ) {
if ( ie ) { setTimeout ( bind ( ensureFocus , cm ) , 0 ) ; }
else { cm . curOp . focus = activeElt ( ) ; }
var now = + new Date , type ;
if ( lastDoubleClick && lastDoubleClick . time > now - 400 && cmp ( lastDoubleClick . pos , start ) == 0 ) {
type = "triple" ;
} else if ( lastClick && lastClick . time > now - 400 && cmp ( lastClick . pos , start ) == 0 ) {
type = "double" ;
lastDoubleClick = { time : now , pos : start } ;
} else {
type = "single" ;
lastClick = { time : now , pos : start } ;
}
var sel = cm . doc . sel , modifier = mac ? e . metaKey : e . ctrlKey , contained ;
if ( cm . options . dragDrop && dragAndDrop && ! cm . isReadOnly ( ) &&
type == "single" && ( contained = sel . contains ( start ) ) > - 1 &&
( cmp ( ( contained = sel . ranges [ contained ] ) . from ( ) , start ) < 0 || start . xRel > 0 ) &&
( cmp ( contained . to ( ) , start ) > 0 || start . xRel < 0 ) )
{ leftButtonStartDrag ( cm , e , start , modifier ) ; }
else
{ leftButtonSelect ( cm , e , start , type , modifier ) ; }
}
// Start a text drag. When it ends, see if any dragging actually
// happen, and treat as a click if it didn't.
function leftButtonStartDrag ( cm , e , start , modifier ) {
var display = cm . display , moved = false ;
var dragEnd = operation ( cm , function ( e ) {
if ( webkit ) { display . scroller . draggable = false ; }
cm . state . draggingText = false ;
off ( document , "mouseup" , dragEnd ) ;
off ( document , "mousemove" , mouseMove ) ;
off ( display . scroller , "dragstart" , dragStart ) ;
off ( display . scroller , "drop" , dragEnd ) ;
if ( ! moved ) {
e _preventDefault ( e ) ;
if ( ! modifier )
{ extendSelection ( cm . doc , start ) ; }
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
if ( webkit || ie && ie _version == 9 )
{ setTimeout ( function ( ) { document . body . focus ( ) ; display . input . focus ( ) ; } , 20 ) ; }
else
{ display . input . focus ( ) ; }
}
} ) ;
var mouseMove = function ( e2 ) {
moved = moved || Math . abs ( e . clientX - e2 . clientX ) + Math . abs ( e . clientY - e2 . clientY ) >= 10 ;
} ;
var dragStart = function ( ) { return moved = true ; } ;
// Let the drag handler handle this.
if ( webkit ) { display . scroller . draggable = true ; }
cm . state . draggingText = dragEnd ;
dragEnd . copy = mac ? e . altKey : e . ctrlKey ;
// IE's approach to draggable
if ( display . scroller . dragDrop ) { display . scroller . dragDrop ( ) ; }
on ( document , "mouseup" , dragEnd ) ;
on ( document , "mousemove" , mouseMove ) ;
on ( display . scroller , "dragstart" , dragStart ) ;
on ( display . scroller , "drop" , dragEnd ) ;
delayBlurEvent ( cm ) ;
setTimeout ( function ( ) { return display . input . focus ( ) ; } , 20 ) ;
}
// Normal selection, as opposed to text dragging.
function leftButtonSelect ( cm , e , start , type , addNew ) {
var display = cm . display , doc = cm . doc ;
e _preventDefault ( e ) ;
var ourRange , ourIndex , startSel = doc . sel , ranges = startSel . ranges ;
if ( addNew && ! e . shiftKey ) {
ourIndex = doc . sel . contains ( start ) ;
if ( ourIndex > - 1 )
{ ourRange = ranges [ ourIndex ] ; }
else
{ ourRange = new Range ( start , start ) ; }
} else {
ourRange = doc . sel . primary ( ) ;
ourIndex = doc . sel . primIndex ;
}
if ( chromeOS ? e . shiftKey && e . metaKey : e . altKey ) {
type = "rect" ;
if ( ! addNew ) { ourRange = new Range ( start , start ) ; }
start = posFromMouse ( cm , e , true , true ) ;
ourIndex = - 1 ;
} else if ( type == "double" ) {
var word = cm . findWordAt ( start ) ;
if ( cm . display . shift || doc . extend )
{ ourRange = extendRange ( doc , ourRange , word . anchor , word . head ) ; }
else
{ ourRange = word ; }
} else if ( type == "triple" ) {
var line = new Range ( Pos ( start . line , 0 ) , clipPos ( doc , Pos ( start . line + 1 , 0 ) ) ) ;
if ( cm . display . shift || doc . extend )
{ ourRange = extendRange ( doc , ourRange , line . anchor , line . head ) ; }
else
{ ourRange = line ; }
} else {
ourRange = extendRange ( doc , ourRange , start ) ;
}
if ( ! addNew ) {
ourIndex = 0 ;
setSelection ( doc , new Selection ( [ ourRange ] , 0 ) , sel _mouse ) ;
startSel = doc . sel ;
} else if ( ourIndex == - 1 ) {
ourIndex = ranges . length ;
setSelection ( doc , normalizeSelection ( ranges . concat ( [ ourRange ] ) , ourIndex ) ,
{ scroll : false , origin : "*mouse" } ) ;
} else if ( ranges . length > 1 && ranges [ ourIndex ] . empty ( ) && type == "single" && ! e . shiftKey ) {
setSelection ( doc , normalizeSelection ( ranges . slice ( 0 , ourIndex ) . concat ( ranges . slice ( ourIndex + 1 ) ) , 0 ) ,
{ scroll : false , origin : "*mouse" } ) ;
startSel = doc . sel ;
} else {
replaceOneSelection ( doc , ourIndex , ourRange , sel _mouse ) ;
}
var lastPos = start ;
function extendTo ( pos ) {
if ( cmp ( lastPos , pos ) == 0 ) { return }
lastPos = pos ;
if ( type == "rect" ) {
var ranges = [ ] , tabSize = cm . options . tabSize ;
var startCol = countColumn ( getLine ( doc , start . line ) . text , start . ch , tabSize ) ;
var posCol = countColumn ( getLine ( doc , pos . line ) . text , pos . ch , tabSize ) ;
var left = Math . min ( startCol , posCol ) , right = Math . max ( startCol , posCol ) ;
for ( var line = Math . min ( start . line , pos . line ) , end = Math . min ( cm . lastLine ( ) , Math . max ( start . line , pos . line ) ) ;
line <= end ; line ++ ) {
var text = getLine ( doc , line ) . text , leftPos = findColumn ( text , left , tabSize ) ;
if ( left == right )
{ ranges . push ( new Range ( Pos ( line , leftPos ) , Pos ( line , leftPos ) ) ) ; }
else if ( text . length > leftPos )
{ ranges . push ( new Range ( Pos ( line , leftPos ) , Pos ( line , findColumn ( text , right , tabSize ) ) ) ) ; }
}
if ( ! ranges . length ) { ranges . push ( new Range ( start , start ) ) ; }
setSelection ( doc , normalizeSelection ( startSel . ranges . slice ( 0 , ourIndex ) . concat ( ranges ) , ourIndex ) ,
{ origin : "*mouse" , scroll : false } ) ;
cm . scrollIntoView ( pos ) ;
} else {
var oldRange = ourRange ;
var anchor = oldRange . anchor , head = pos ;
if ( type != "single" ) {
var range$$1 ;
if ( type == "double" )
{ range$$1 = cm . findWordAt ( pos ) ; }
else
{ range$$1 = new Range ( Pos ( pos . line , 0 ) , clipPos ( doc , Pos ( pos . line + 1 , 0 ) ) ) ; }
if ( cmp ( range$$1 . anchor , anchor ) > 0 ) {
head = range$$1 . head ;
anchor = minPos ( oldRange . from ( ) , range$$1 . anchor ) ;
} else {
head = range$$1 . anchor ;
anchor = maxPos ( oldRange . to ( ) , range$$1 . head ) ;
}
}
var ranges$1 = startSel . ranges . slice ( 0 ) ;
ranges$1 [ ourIndex ] = new Range ( clipPos ( doc , anchor ) , head ) ;
setSelection ( doc , normalizeSelection ( ranges$1 , ourIndex ) , sel _mouse ) ;
}
}
var editorSize = display . wrapper . getBoundingClientRect ( ) ;
// Used to ensure timeout re-tries don't fire when another extend
// happened in the meantime (clearTimeout isn't reliable -- at
// least on Chrome, the timeouts still happen even when cleared,
// if the clear happens after their scheduled firing time).
var counter = 0 ;
function extend ( e ) {
var curCount = ++ counter ;
var cur = posFromMouse ( cm , e , true , type == "rect" ) ;
if ( ! cur ) { return }
if ( cmp ( cur , lastPos ) != 0 ) {
cm . curOp . focus = activeElt ( ) ;
extendTo ( cur ) ;
var visible = visibleLines ( display , doc ) ;
if ( cur . line >= visible . to || cur . line < visible . from )
{ setTimeout ( operation ( cm , function ( ) { if ( counter == curCount ) { extend ( e ) ; } } ) , 150 ) ; }
} else {
var outside = e . clientY < editorSize . top ? - 20 : e . clientY > editorSize . bottom ? 20 : 0 ;
if ( outside ) { setTimeout ( operation ( cm , function ( ) {
if ( counter != curCount ) { return }
display . scroller . scrollTop += outside ;
extend ( e ) ;
} ) , 50 ) ; }
}
}
function done ( e ) {
cm . state . selectingText = false ;
counter = Infinity ;
e _preventDefault ( e ) ;
display . input . focus ( ) ;
off ( document , "mousemove" , move ) ;
off ( document , "mouseup" , up ) ;
doc . history . lastSelOrigin = null ;
}
var move = operation ( cm , function ( e ) {
if ( ! e _button ( e ) ) { done ( e ) ; }
else { extend ( e ) ; }
} ) ;
var up = operation ( cm , done ) ;
cm . state . selectingText = up ;
on ( document , "mousemove" , move ) ;
on ( document , "mouseup" , up ) ;
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent ( cm , e , type , prevent ) {
var mX , mY ;
try { mX = e . clientX ; mY = e . clientY ; }
catch ( e ) { return false }
if ( mX >= Math . floor ( cm . display . gutters . getBoundingClientRect ( ) . right ) ) { return false }
if ( prevent ) { e _preventDefault ( e ) ; }
var display = cm . display ;
var lineBox = display . lineDiv . getBoundingClientRect ( ) ;
if ( mY > lineBox . bottom || ! hasHandler ( cm , type ) ) { return e _defaultPrevented ( e ) }
mY -= lineBox . top - display . viewOffset ;
for ( var i = 0 ; i < cm . options . gutters . length ; ++ i ) {
var g = display . gutters . childNodes [ i ] ;
if ( g && g . getBoundingClientRect ( ) . right >= mX ) {
var line = lineAtHeight ( cm . doc , mY ) ;
var gutter = cm . options . gutters [ i ] ;
signal ( cm , type , cm , line , gutter , e ) ;
return e _defaultPrevented ( e )
}
}
}
function clickInGutter ( cm , e ) {
return gutterEvent ( cm , e , "gutterClick" , true )
}
// CONTEXT MENU HANDLING
// To make the context menu work, we need to briefly unhide the
// textarea (making it as unobtrusive as possible) to let the
// right-click take effect on it.
function onContextMenu ( cm , e ) {
if ( eventInWidget ( cm . display , e ) || contextMenuInGutter ( cm , e ) ) { return }
if ( signalDOMEvent ( cm , e , "contextmenu" ) ) { return }
cm . display . input . onContextMenu ( e ) ;
}
function contextMenuInGutter ( cm , e ) {
if ( ! hasHandler ( cm , "gutterContextMenu" ) ) { return false }
return gutterEvent ( cm , e , "gutterContextMenu" , false )
}
function themeChanged ( cm ) {
cm . display . wrapper . className = cm . display . wrapper . className . replace ( /\s*cm-s-\S+/g , "" ) +
cm . options . theme . replace ( /(^|\s)\s*/g , " cm-s-" ) ;
clearCaches ( cm ) ;
}
var Init = { toString : function ( ) { return "CodeMirror.Init" } } ;
var defaults = { } ;
var optionHandlers = { } ;
function defineOptions ( CodeMirror ) {
var optionHandlers = CodeMirror . optionHandlers ;
function option ( name , deflt , handle , notOnInit ) {
CodeMirror . defaults [ name ] = deflt ;
if ( handle ) { optionHandlers [ name ] =
notOnInit ? function ( cm , val , old ) { if ( old != Init ) { handle ( cm , val , old ) ; } } : handle ; }
}
CodeMirror . defineOption = option ;
// Passed to option handlers when there is no old value.
CodeMirror . Init = Init ;
// These two are, on init, called from the constructor because they
// have to be initialized before the editor can start at all.
option ( "value" , "" , function ( cm , val ) { return cm . setValue ( val ) ; } , true ) ;
option ( "mode" , null , function ( cm , val ) {
cm . doc . modeOption = val ;
loadMode ( cm ) ;
} , true ) ;
option ( "indentUnit" , 2 , loadMode , true ) ;
option ( "indentWithTabs" , false ) ;
option ( "smartIndent" , true ) ;
option ( "tabSize" , 4 , function ( cm ) {
resetModeState ( cm ) ;
clearCaches ( cm ) ;
regChange ( cm ) ;
} , true ) ;
option ( "lineSeparator" , null , function ( cm , val ) {
cm . doc . lineSep = val ;
if ( ! val ) { return }
var newBreaks = [ ] , lineNo = cm . doc . first ;
cm . doc . iter ( function ( line ) {
for ( var pos = 0 ; ; ) {
var found = line . text . indexOf ( val , pos ) ;
if ( found == - 1 ) { break }
pos = found + val . length ;
newBreaks . push ( Pos ( lineNo , found ) ) ;
}
lineNo ++ ;
} ) ;
for ( var i = newBreaks . length - 1 ; i >= 0 ; i -- )
{ replaceRange ( cm . doc , val , newBreaks [ i ] , Pos ( newBreaks [ i ] . line , newBreaks [ i ] . ch + val . length ) ) ; }
} ) ;
option ( "specialChars" , /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g , function ( cm , val , old ) {
cm . state . specialChars = new RegExp ( val . source + ( val . test ( "\t" ) ? "" : "|\t" ) , "g" ) ;
if ( old != Init ) { cm . refresh ( ) ; }
} ) ;
option ( "specialCharPlaceholder" , defaultSpecialCharPlaceholder , function ( cm ) { return cm . refresh ( ) ; } , true ) ;
option ( "electricChars" , true ) ;
option ( "inputStyle" , mobile ? "contenteditable" : "textarea" , function ( ) {
throw new Error ( "inputStyle can not (yet) be changed in a running editor" ) // FIXME
} , true ) ;
option ( "spellcheck" , false , function ( cm , val ) { return cm . getInputField ( ) . spellcheck = val ; } , true ) ;
option ( "rtlMoveVisually" , ! windows ) ;
option ( "wholeLineUpdateBefore" , true ) ;
option ( "theme" , "default" , function ( cm ) {
themeChanged ( cm ) ;
guttersChanged ( cm ) ;
} , true ) ;
option ( "keyMap" , "default" , function ( cm , val , old ) {
var next = getKeyMap ( val ) ;
var prev = old != Init && getKeyMap ( old ) ;
if ( prev && prev . detach ) { prev . detach ( cm , next ) ; }
if ( next . attach ) { next . attach ( cm , prev || null ) ; }
} ) ;
option ( "extraKeys" , null ) ;
option ( "lineWrapping" , false , wrappingChanged , true ) ;
option ( "gutters" , [ ] , function ( cm ) {
setGuttersForLineNumbers ( cm . options ) ;
guttersChanged ( cm ) ;
} , true ) ;
option ( "fixedGutter" , true , function ( cm , val ) {
cm . display . gutters . style . left = val ? compensateForHScroll ( cm . display ) + "px" : "0" ;
cm . refresh ( ) ;
} , true ) ;
option ( "coverGutterNextToScrollbar" , false , function ( cm ) { return updateScrollbars ( cm ) ; } , true ) ;
option ( "scrollbarStyle" , "native" , function ( cm ) {
initScrollbars ( cm ) ;
updateScrollbars ( cm ) ;
cm . display . scrollbars . setScrollTop ( cm . doc . scrollTop ) ;
cm . display . scrollbars . setScrollLeft ( cm . doc . scrollLeft ) ;
} , true ) ;
option ( "lineNumbers" , false , function ( cm ) {
setGuttersForLineNumbers ( cm . options ) ;
guttersChanged ( cm ) ;
} , true ) ;
option ( "firstLineNumber" , 1 , guttersChanged , true ) ;
option ( "lineNumberFormatter" , function ( integer ) { return integer ; } , guttersChanged , true ) ;
option ( "showCursorWhenSelecting" , false , updateSelection , true ) ;
option ( "resetSelectionOnContextMenu" , true ) ;
option ( "lineWiseCopyCut" , true ) ;
option ( "readOnly" , false , function ( cm , val ) {
if ( val == "nocursor" ) {
onBlur ( cm ) ;
cm . display . input . blur ( ) ;
cm . display . disabled = true ;
} else {
cm . display . disabled = false ;
}
cm . display . input . readOnlyChanged ( val ) ;
} ) ;
option ( "disableInput" , false , function ( cm , val ) { if ( ! val ) { cm . display . input . reset ( ) ; } } , true ) ;
option ( "dragDrop" , true , dragDropChanged ) ;
option ( "allowDropFileTypes" , null ) ;
option ( "cursorBlinkRate" , 530 ) ;
option ( "cursorScrollMargin" , 0 ) ;
option ( "cursorHeight" , 1 , updateSelection , true ) ;
option ( "singleCursorHeightPerLine" , true , updateSelection , true ) ;
option ( "workTime" , 100 ) ;
option ( "workDelay" , 100 ) ;
option ( "flattenSpans" , true , resetModeState , true ) ;
option ( "addModeClass" , false , resetModeState , true ) ;
option ( "pollInterval" , 100 ) ;
option ( "undoDepth" , 200 , function ( cm , val ) { return cm . doc . history . undoDepth = val ; } ) ;
option ( "historyEventDelay" , 1250 ) ;
option ( "viewportMargin" , 10 , function ( cm ) { return cm . refresh ( ) ; } , true ) ;
option ( "maxHighlightLength" , 10000 , resetModeState , true ) ;
option ( "moveInputWithCursor" , true , function ( cm , val ) {
if ( ! val ) { cm . display . input . resetPosition ( ) ; }
} ) ;
option ( "tabindex" , null , function ( cm , val ) { return cm . display . input . getField ( ) . tabIndex = val || "" ; } ) ;
option ( "autofocus" , null ) ;
option ( "direction" , "ltr" , function ( cm , val ) { return cm . doc . setDirection ( val ) ; } , true ) ;
}
function guttersChanged ( cm ) {
updateGutters ( cm ) ;
regChange ( cm ) ;
alignHorizontally ( cm ) ;
}
function dragDropChanged ( cm , value , old ) {
var wasOn = old && old != Init ;
if ( ! value != ! wasOn ) {
var funcs = cm . display . dragFunctions ;
var toggle = value ? on : off ;
toggle ( cm . display . scroller , "dragstart" , funcs . start ) ;
toggle ( cm . display . scroller , "dragenter" , funcs . enter ) ;
toggle ( cm . display . scroller , "dragover" , funcs . over ) ;
toggle ( cm . display . scroller , "dragleave" , funcs . leave ) ;
toggle ( cm . display . scroller , "drop" , funcs . drop ) ;
}
}
function wrappingChanged ( cm ) {
if ( cm . options . lineWrapping ) {
addClass ( cm . display . wrapper , "CodeMirror-wrap" ) ;
cm . display . sizer . style . minWidth = "" ;
cm . display . sizerWidth = null ;
} else {
rmClass ( cm . display . wrapper , "CodeMirror-wrap" ) ;
findMaxLine ( cm ) ;
}
estimateLineHeights ( cm ) ;
regChange ( cm ) ;
clearCaches ( cm ) ;
setTimeout ( function ( ) { return updateScrollbars ( cm ) ; } , 100 ) ;
}
// A CodeMirror instance represents an editor. This is the object
// that user code is usually dealing with.
function CodeMirror$1 ( place , options ) {
var this $1 = this ;
if ( ! ( this instanceof CodeMirror$1 ) ) { return new CodeMirror$1 ( place , options ) }
this . options = options = options ? copyObj ( options ) : { } ;
// Determine effective options based on given values and defaults.
copyObj ( defaults , options , false ) ;
setGuttersForLineNumbers ( options ) ;
var doc = options . value ;
if ( typeof doc == "string" ) { doc = new Doc ( doc , options . mode , null , options . lineSeparator , options . direction ) ; }
this . doc = doc ;
var input = new CodeMirror$1 . inputStyles [ options . inputStyle ] ( this ) ;
var display = this . display = new Display ( place , doc , input ) ;
display . wrapper . CodeMirror = this ;
updateGutters ( this ) ;
themeChanged ( this ) ;
if ( options . lineWrapping )
{ this . display . wrapper . className += " CodeMirror-wrap" ; }
initScrollbars ( this ) ;
this . state = {
keyMaps : [ ] , // stores maps added by addKeyMap
overlays : [ ] , // highlighting overlays, as added by addOverlay
modeGen : 0 , // bumped when mode/overlay changes, used to invalidate highlighting info
overwrite : false ,
delayingBlurEvent : false ,
focused : false ,
suppressEdits : false , // used to disable editing during key handlers when in readOnly mode
pasteIncoming : false , cutIncoming : false , // help recognize paste/cut edits in input.poll
selectingText : false ,
draggingText : false ,
highlight : new Delayed ( ) , // stores highlight worker timeout
keySeq : null , // Unfinished key sequence
specialChars : null
} ;
if ( options . autofocus && ! mobile ) { display . input . focus ( ) ; }
// Override magic textarea content restore that IE sometimes does
// on our hidden textarea on reload
if ( ie && ie _version < 11 ) { setTimeout ( function ( ) { return this $1 . display . input . reset ( true ) ; } , 20 ) ; }
registerEventHandlers ( this ) ;
ensureGlobalHandlers ( ) ;
startOperation ( this ) ;
this . curOp . forceUpdate = true ;
attachDoc ( this , doc ) ;
if ( ( options . autofocus && ! mobile ) || this . hasFocus ( ) )
{ setTimeout ( bind ( onFocus , this ) , 20 ) ; }
else
{ onBlur ( this ) ; }
for ( var opt in optionHandlers ) { if ( optionHandlers . hasOwnProperty ( opt ) )
{ optionHandlers [ opt ] ( this $1 , options [ opt ] , Init ) ; } }
maybeUpdateLineNumberWidth ( this ) ;
if ( options . finishInit ) { options . finishInit ( this ) ; }
for ( var i = 0 ; i < initHooks . length ; ++ i ) { initHooks [ i ] ( this $1 ) ; }
endOperation ( this ) ;
// Suppress optimizelegibility in Webkit, since it breaks text
// measuring on line wrapping boundaries.
if ( webkit && options . lineWrapping &&
getComputedStyle ( display . lineDiv ) . textRendering == "optimizelegibility" )
{ display . lineDiv . style . textRendering = "auto" ; }
}
// The default configuration options.
CodeMirror$1 . defaults = defaults ;
// Functions to run when options are changed.
CodeMirror$1 . optionHandlers = optionHandlers ;
// Attach the necessary event handlers when initializing the editor
function registerEventHandlers ( cm ) {
var d = cm . display ;
on ( d . scroller , "mousedown" , operation ( cm , onMouseDown ) ) ;
// Older IE's will not fire a second mousedown for a double click
if ( ie && ie _version < 11 )
{ on ( d . scroller , "dblclick" , operation ( cm , function ( e ) {
if ( signalDOMEvent ( cm , e ) ) { return }
var pos = posFromMouse ( cm , e ) ;
if ( ! pos || clickInGutter ( cm , e ) || eventInWidget ( cm . display , e ) ) { return }
e _preventDefault ( e ) ;
var word = cm . findWordAt ( pos ) ;
extendSelection ( cm . doc , word . anchor , word . head ) ;
} ) ) ; }
else
{ on ( d . scroller , "dblclick" , function ( e ) { return signalDOMEvent ( cm , e ) || e _preventDefault ( e ) ; } ) ; }
// Some browsers fire contextmenu *after* opening the menu, at
// which point we can't mess with it anymore. Context menu is
// handled in onMouseDown for these browsers.
if ( ! captureRightClick ) { on ( d . scroller , "contextmenu" , function ( e ) { return onContextMenu ( cm , e ) ; } ) ; }
// Used to suppress mouse event handling when a touch happens
var touchFinished , prevTouch = { end : 0 } ;
function finishTouch ( ) {
if ( d . activeTouch ) {
touchFinished = setTimeout ( function ( ) { return d . activeTouch = null ; } , 1000 ) ;
prevTouch = d . activeTouch ;
prevTouch . end = + new Date ;
}
}
function isMouseLikeTouchEvent ( e ) {
if ( e . touches . length != 1 ) { return false }
var touch = e . touches [ 0 ] ;
return touch . radiusX <= 1 && touch . radiusY <= 1
}
function farAway ( touch , other ) {
if ( other . left == null ) { return true }
var dx = other . left - touch . left , dy = other . top - touch . top ;
return dx * dx + dy * dy > 20 * 20
}
on ( d . scroller , "touchstart" , function ( e ) {
if ( ! signalDOMEvent ( cm , e ) && ! isMouseLikeTouchEvent ( e ) ) {
d . input . ensurePolled ( ) ;
clearTimeout ( touchFinished ) ;
var now = + new Date ;
d . activeTouch = { start : now , moved : false ,
prev : now - prevTouch . end <= 300 ? prevTouch : null } ;
if ( e . touches . length == 1 ) {
d . activeTouch . left = e . touches [ 0 ] . pageX ;
d . activeTouch . top = e . touches [ 0 ] . pageY ;
}
}
} ) ;
on ( d . scroller , "touchmove" , function ( ) {
if ( d . activeTouch ) { d . activeTouch . moved = true ; }
} ) ;
on ( d . scroller , "touchend" , function ( e ) {
var touch = d . activeTouch ;
if ( touch && ! eventInWidget ( d , e ) && touch . left != null &&
! touch . moved && new Date - touch . start < 300 ) {
var pos = cm . coordsChar ( d . activeTouch , "page" ) , range ;
if ( ! touch . prev || farAway ( touch , touch . prev ) ) // Single tap
{ range = new Range ( pos , pos ) ; }
else if ( ! touch . prev . prev || farAway ( touch , touch . prev . prev ) ) // Double tap
{ range = cm . findWordAt ( pos ) ; }
else // Triple tap
{ range = new Range ( Pos ( pos . line , 0 ) , clipPos ( cm . doc , Pos ( pos . line + 1 , 0 ) ) ) ; }
cm . setSelection ( range . anchor , range . head ) ;
cm . focus ( ) ;
e _preventDefault ( e ) ;
}
finishTouch ( ) ;
} ) ;
on ( d . scroller , "touchcancel" , finishTouch ) ;
// Sync scrolling between fake scrollbars and real scrollable
// area, ensure viewport is updated when scrolling.
on ( d . scroller , "scroll" , function ( ) {
if ( d . scroller . clientHeight ) {
updateScrollTop ( cm , d . scroller . scrollTop ) ;
setScrollLeft ( cm , d . scroller . scrollLeft , true ) ;
signal ( cm , "scroll" , cm ) ;
}
} ) ;
// Listen to wheel events in order to try and update the viewport on time.
on ( d . scroller , "mousewheel" , function ( e ) { return onScrollWheel ( cm , e ) ; } ) ;
on ( d . scroller , "DOMMouseScroll" , function ( e ) { return onScrollWheel ( cm , e ) ; } ) ;
// Prevent wrapper from ever scrolling
on ( d . wrapper , "scroll" , function ( ) { return d . wrapper . scrollTop = d . wrapper . scrollLeft = 0 ; } ) ;
d . dragFunctions = {
enter : function ( e ) { if ( ! signalDOMEvent ( cm , e ) ) { e _stop ( e ) ; } } ,
over : function ( e ) { if ( ! signalDOMEvent ( cm , e ) ) { onDragOver ( cm , e ) ; e _stop ( e ) ; } } ,
start : function ( e ) { return onDragStart ( cm , e ) ; } ,
drop : operation ( cm , onDrop ) ,
leave : function ( e ) { if ( ! signalDOMEvent ( cm , e ) ) { clearDragCursor ( cm ) ; } }
} ;
var inp = d . input . getField ( ) ;
on ( inp , "keyup" , function ( e ) { return onKeyUp . call ( cm , e ) ; } ) ;
on ( inp , "keydown" , operation ( cm , onKeyDown ) ) ;
on ( inp , "keypress" , operation ( cm , onKeyPress ) ) ;
on ( inp , "focus" , function ( e ) { return onFocus ( cm , e ) ; } ) ;
on ( inp , "blur" , function ( e ) { return onBlur ( cm , e ) ; } ) ;
}
var initHooks = [ ] ;
CodeMirror$1 . defineInitHook = function ( f ) { return initHooks . push ( f ) ; } ;
// Indent the given line. The how parameter can be "smart",
// "add"/null, "subtract", or "prev". When aggressive is false
// (typically set to true for forced single-line indents), empty
// lines are not indented, and places where the mode returns Pass
// are left alone.
function indentLine ( cm , n , how , aggressive ) {
var doc = cm . doc , state ;
if ( how == null ) { how = "add" ; }
if ( how == "smart" ) {
// Fall back to "prev" when the mode doesn't have an indentation
// method.
if ( ! doc . mode . indent ) { how = "prev" ; }
else { state = getStateBefore ( cm , n ) ; }
}
var tabSize = cm . options . tabSize ;
var line = getLine ( doc , n ) , curSpace = countColumn ( line . text , null , tabSize ) ;
if ( line . stateAfter ) { line . stateAfter = null ; }
var curSpaceString = line . text . match ( /^\s*/ ) [ 0 ] , indentation ;
if ( ! aggressive && ! /\S/ . test ( line . text ) ) {
indentation = 0 ;
how = "not" ;
} else if ( how == "smart" ) {
indentation = doc . mode . indent ( state , line . text . slice ( curSpaceString . length ) , line . text ) ;
if ( indentation == Pass || indentation > 150 ) {
if ( ! aggressive ) { return }
how = "prev" ;
}
}
if ( how == "prev" ) {
if ( n > doc . first ) { indentation = countColumn ( getLine ( doc , n - 1 ) . text , null , tabSize ) ; }
else { indentation = 0 ; }
} else if ( how == "add" ) {
indentation = curSpace + cm . options . indentUnit ;
} else if ( how == "subtract" ) {
indentation = curSpace - cm . options . indentUnit ;
} else if ( typeof how == "number" ) {
indentation = curSpace + how ;
}
indentation = Math . max ( 0 , indentation ) ;
var indentString = "" , pos = 0 ;
if ( cm . options . indentWithTabs )
{ for ( var i = Math . floor ( indentation / tabSize ) ; i ; -- i ) { pos += tabSize ; indentString += "\t" ; } }
if ( pos < indentation ) { indentString += spaceStr ( indentation - pos ) ; }
if ( indentString != curSpaceString ) {
replaceRange ( doc , indentString , Pos ( n , 0 ) , Pos ( n , curSpaceString . length ) , "+input" ) ;
line . stateAfter = null ;
return true
} else {
// Ensure that, if the cursor was in the whitespace at the start
// of the line, it is moved to the end of that space.
for ( var i$1 = 0 ; i$1 < doc . sel . ranges . length ; i$1 ++ ) {
var range = doc . sel . ranges [ i$1 ] ;
if ( range . head . line == n && range . head . ch < curSpaceString . length ) {
var pos$1 = Pos ( n , curSpaceString . length ) ;
replaceOneSelection ( doc , i$1 , new Range ( pos$1 , pos$1 ) ) ;
break
}
}
}
}
// This will be set to a {lineWise: bool, text: [string]} object, so
// that, when pasting, we know what kind of selections the copied
// text was made out of.
var lastCopied = null ;
function setLastCopied ( newLastCopied ) {
lastCopied = newLastCopied ;
}
function applyTextInput ( cm , inserted , deleted , sel , origin ) {
var doc = cm . doc ;
cm . display . shift = false ;
if ( ! sel ) { sel = doc . sel ; }
var paste = cm . state . pasteIncoming || origin == "paste" ;
var textLines = splitLinesAuto ( inserted ) , multiPaste = null ;
// When pasing N lines into N selections, insert one line per selection
if ( paste && sel . ranges . length > 1 ) {
if ( lastCopied && lastCopied . text . join ( "\n" ) == inserted ) {
if ( sel . ranges . length % lastCopied . text . length == 0 ) {
multiPaste = [ ] ;
for ( var i = 0 ; i < lastCopied . text . length ; i ++ )
{ multiPaste . push ( doc . splitLines ( lastCopied . text [ i ] ) ) ; }
}
} else if ( textLines . length == sel . ranges . length ) {
multiPaste = map ( textLines , function ( l ) { return [ l ] ; } ) ;
}
}
var updateInput ;
// Normal behavior is to insert the new text into every selection
for ( var i$1 = sel . ranges . length - 1 ; i$1 >= 0 ; i$1 -- ) {
var range$$1 = sel . ranges [ i$1 ] ;
var from = range$$1 . from ( ) , to = range$$1 . to ( ) ;
if ( range$$1 . empty ( ) ) {
if ( deleted && deleted > 0 ) // Handle deletion
{ from = Pos ( from . line , from . ch - deleted ) ; }
else if ( cm . state . overwrite && ! paste ) // Handle overwrite
{ to = Pos ( to . line , Math . min ( getLine ( doc , to . line ) . text . length , to . ch + lst ( textLines ) . length ) ) ; }
else if ( lastCopied && lastCopied . lineWise && lastCopied . text . join ( "\n" ) == inserted )
{ from = to = Pos ( from . line , 0 ) ; }
}
updateInput = cm . curOp . updateInput ;
var changeEvent = { from : from , to : to , text : multiPaste ? multiPaste [ i$1 % multiPaste . length ] : textLines ,
origin : origin || ( paste ? "paste" : cm . state . cutIncoming ? "cut" : "+input" ) } ;
makeChange ( cm . doc , changeEvent ) ;
signalLater ( cm , "inputRead" , cm , changeEvent ) ;
}
if ( inserted && ! paste )
{ triggerElectric ( cm , inserted ) ; }
ensureCursorVisible ( cm ) ;
cm . curOp . updateInput = updateInput ;
cm . curOp . typing = true ;
cm . state . pasteIncoming = cm . state . cutIncoming = false ;
}
function handlePaste ( e , cm ) {
var pasted = e . clipboardData && e . clipboardData . getData ( "Text" ) ;
if ( pasted ) {
e . preventDefault ( ) ;
if ( ! cm . isReadOnly ( ) && ! cm . options . disableInput )
{ runInOp ( cm , function ( ) { return applyTextInput ( cm , pasted , 0 , null , "paste" ) ; } ) ; }
return true
}
}
function triggerElectric ( cm , inserted ) {
// When an 'electric' character is inserted, immediately trigger a reindent
if ( ! cm . options . electricChars || ! cm . options . smartIndent ) { return }
var sel = cm . doc . sel ;
for ( var i = sel . ranges . length - 1 ; i >= 0 ; i -- ) {
var range$$1 = sel . ranges [ i ] ;
if ( range$$1 . head . ch > 100 || ( i && sel . ranges [ i - 1 ] . head . line == range$$1 . head . line ) ) { continue }
var mode = cm . getModeAt ( range$$1 . head ) ;
var indented = false ;
if ( mode . electricChars ) {
for ( var j = 0 ; j < mode . electricChars . length ; j ++ )
{ if ( inserted . indexOf ( mode . electricChars . charAt ( j ) ) > - 1 ) {
indented = indentLine ( cm , range$$1 . head . line , "smart" ) ;
break
} }
} else if ( mode . electricInput ) {
if ( mode . electricInput . test ( getLine ( cm . doc , range$$1 . head . line ) . text . slice ( 0 , range$$1 . head . ch ) ) )
{ indented = indentLine ( cm , range$$1 . head . line , "smart" ) ; }
}
if ( indented ) { signalLater ( cm , "electricInput" , cm , range$$1 . head . line ) ; }
}
}
function copyableRanges ( cm ) {
var text = [ ] , ranges = [ ] ;
for ( var i = 0 ; i < cm . doc . sel . ranges . length ; i ++ ) {
var line = cm . doc . sel . ranges [ i ] . head . line ;
var lineRange = { anchor : Pos ( line , 0 ) , head : Pos ( line + 1 , 0 ) } ;
ranges . push ( lineRange ) ;
text . push ( cm . getRange ( lineRange . anchor , lineRange . head ) ) ;
}
return { text : text , ranges : ranges }
}
function disableBrowserMagic ( field , spellcheck ) {
field . setAttribute ( "autocorrect" , "off" ) ;
field . setAttribute ( "autocapitalize" , "off" ) ;
field . setAttribute ( "spellcheck" , ! ! spellcheck ) ;
}
function hiddenTextarea ( ) {
var te = elt ( "textarea" , null , null , "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none" ) ;
var div = elt ( "div" , [ te ] , null , "overflow: hidden; position: relative; width: 3px; height: 0px;" ) ;
// The textarea is kept positioned near the cursor to prevent the
// fact that it'll be scrolled into view on input from scrolling
// our fake cursor out of view. On webkit, when wrap=off, paste is
// very slow. So make the area wide instead.
if ( webkit ) { te . style . width = "1000px" ; }
else { te . setAttribute ( "wrap" , "off" ) ; }
// If border: 0; -- iOS fails to open keyboard (issue #1287)
if ( ios ) { te . style . border = "1px solid black" ; }
disableBrowserMagic ( te ) ;
return div
}
// The publicly visible API. Note that methodOp(f) means
// 'wrap f in an operation, performed on its `this` parameter'.
// This is not the complete set of editor methods. Most of the
// methods defined on the Doc type are also injected into
// CodeMirror.prototype, for backwards compatibility and
// convenience.
var addEditorMethods = function ( CodeMirror ) {
var optionHandlers = CodeMirror . optionHandlers ;
var helpers = CodeMirror . helpers = { } ;
CodeMirror . prototype = {
constructor : CodeMirror ,
focus : function ( ) { window . focus ( ) ; this . display . input . focus ( ) ; } ,
setOption : function ( option , value ) {
var options = this . options , old = options [ option ] ;
if ( options [ option ] == value && option != "mode" ) { return }
options [ option ] = value ;
if ( optionHandlers . hasOwnProperty ( option ) )
{ operation ( this , optionHandlers [ option ] ) ( this , value , old ) ; }
signal ( this , "optionChange" , this , option ) ;
} ,
getOption : function ( option ) { return this . options [ option ] } ,
getDoc : function ( ) { return this . doc } ,
addKeyMap : function ( map$$1 , bottom ) {
this . state . keyMaps [ bottom ? "push" : "unshift" ] ( getKeyMap ( map$$1 ) ) ;
} ,
removeKeyMap : function ( map$$1 ) {
var maps = this . state . keyMaps ;
for ( var i = 0 ; i < maps . length ; ++ i )
{ if ( maps [ i ] == map$$1 || maps [ i ] . name == map$$1 ) {
maps . splice ( i , 1 ) ;
return true
} }
} ,
addOverlay : methodOp ( function ( spec , options ) {
var mode = spec . token ? spec : CodeMirror . getMode ( this . options , spec ) ;
if ( mode . startState ) { throw new Error ( "Overlays may not be stateful." ) }
insertSorted ( this . state . overlays ,
{ mode : mode , modeSpec : spec , opaque : options && options . opaque ,
priority : ( options && options . priority ) || 0 } ,
function ( overlay ) { return overlay . priority ; } ) ;
this . state . modeGen ++ ;
regChange ( this ) ;
} ) ,
removeOverlay : methodOp ( function ( spec ) {
var this $1 = this ;
var overlays = this . state . overlays ;
for ( var i = 0 ; i < overlays . length ; ++ i ) {
var cur = overlays [ i ] . modeSpec ;
if ( cur == spec || typeof spec == "string" && cur . name == spec ) {
overlays . splice ( i , 1 ) ;
this $1 . state . modeGen ++ ;
regChange ( this $1 ) ;
return
}
}
} ) ,
indentLine : methodOp ( function ( n , dir , aggressive ) {
if ( typeof dir != "string" && typeof dir != "number" ) {
if ( dir == null ) { dir = this . options . smartIndent ? "smart" : "prev" ; }
else { dir = dir ? "add" : "subtract" ; }
}
if ( isLine ( this . doc , n ) ) { indentLine ( this , n , dir , aggressive ) ; }
} ) ,
indentSelection : methodOp ( function ( how ) {
var this $1 = this ;
var ranges = this . doc . sel . ranges , end = - 1 ;
for ( var i = 0 ; i < ranges . length ; i ++ ) {
var range$$1 = ranges [ i ] ;
if ( ! range$$1 . empty ( ) ) {
var from = range$$1 . from ( ) , to = range$$1 . to ( ) ;
var start = Math . max ( end , from . line ) ;
end = Math . min ( this $1 . lastLine ( ) , to . line - ( to . ch ? 0 : 1 ) ) + 1 ;
for ( var j = start ; j < end ; ++ j )
{ indentLine ( this $1 , j , how ) ; }
var newRanges = this $1 . doc . sel . ranges ;
if ( from . ch == 0 && ranges . length == newRanges . length && newRanges [ i ] . from ( ) . ch > 0 )
{ replaceOneSelection ( this $1 . doc , i , new Range ( from , newRanges [ i ] . to ( ) ) , sel _dontScroll ) ; }
} else if ( range$$1 . head . line > end ) {
indentLine ( this $1 , range$$1 . head . line , how , true ) ;
end = range$$1 . head . line ;
if ( i == this $1 . doc . sel . primIndex ) { ensureCursorVisible ( this $1 ) ; }
}
}
} ) ,
// Fetch the parser token for a given character. Useful for hacks
// that want to inspect the mode state (say, for completion).
getTokenAt : function ( pos , precise ) {
return takeToken ( this , pos , precise )
} ,
getLineTokens : function ( line , precise ) {
return takeToken ( this , Pos ( line ) , precise , true )
} ,
getTokenTypeAt : function ( pos ) {
pos = clipPos ( this . doc , pos ) ;
var styles = getLineStyles ( this , getLine ( this . doc , pos . line ) ) ;
var before = 0 , after = ( styles . length - 1 ) / 2 , ch = pos . ch ;
var type ;
if ( ch == 0 ) { type = styles [ 2 ] ; }
else { for ( ; ; ) {
var mid = ( before + after ) >> 1 ;
if ( ( mid ? styles [ mid * 2 - 1 ] : 0 ) >= ch ) { after = mid ; }
else if ( styles [ mid * 2 + 1 ] < ch ) { before = mid + 1 ; }
else { type = styles [ mid * 2 + 2 ] ; break }
} }
var cut = type ? type . indexOf ( "overlay " ) : - 1 ;
return cut < 0 ? type : cut == 0 ? null : type . slice ( 0 , cut - 1 )
} ,
getModeAt : function ( pos ) {
var mode = this . doc . mode ;
if ( ! mode . innerMode ) { return mode }
return CodeMirror . innerMode ( mode , this . getTokenAt ( pos ) . state ) . mode
} ,
getHelper : function ( pos , type ) {
return this . getHelpers ( pos , type ) [ 0 ]
} ,
getHelpers : function ( pos , type ) {
var this $1 = this ;
var found = [ ] ;
if ( ! helpers . hasOwnProperty ( type ) ) { return found }
var help = helpers [ type ] , mode = this . getModeAt ( pos ) ;
if ( typeof mode [ type ] == "string" ) {
if ( help [ mode [ type ] ] ) { found . push ( help [ mode [ type ] ] ) ; }
} else if ( mode [ type ] ) {
for ( var i = 0 ; i < mode [ type ] . length ; i ++ ) {
var val = help [ mode [ type ] [ i ] ] ;
if ( val ) { found . push ( val ) ; }
}
} else if ( mode . helperType && help [ mode . helperType ] ) {
found . push ( help [ mode . helperType ] ) ;
} else if ( help [ mode . name ] ) {
found . push ( help [ mode . name ] ) ;
}
for ( var i$1 = 0 ; i$1 < help . _global . length ; i$1 ++ ) {
var cur = help . _global [ i$1 ] ;
if ( cur . pred ( mode , this $1 ) && indexOf ( found , cur . val ) == - 1 )
{ found . push ( cur . val ) ; }
}
return found
} ,
getStateAfter : function ( line , precise ) {
var doc = this . doc ;
line = clipLine ( doc , line == null ? doc . first + doc . size - 1 : line ) ;
return getStateBefore ( this , line + 1 , precise )
} ,
cursorCoords : function ( start , mode ) {
var pos , range$$1 = this . doc . sel . primary ( ) ;
if ( start == null ) { pos = range$$1 . head ; }
else if ( typeof start == "object" ) { pos = clipPos ( this . doc , start ) ; }
else { pos = start ? range$$1 . from ( ) : range$$1 . to ( ) ; }
return cursorCoords ( this , pos , mode || "page" )
} ,
charCoords : function ( pos , mode ) {
return charCoords ( this , clipPos ( this . doc , pos ) , mode || "page" )
} ,
coordsChar : function ( coords , mode ) {
coords = fromCoordSystem ( this , coords , mode || "page" ) ;
return coordsChar ( this , coords . left , coords . top )
} ,
lineAtHeight : function ( height , mode ) {
height = fromCoordSystem ( this , { top : height , left : 0 } , mode || "page" ) . top ;
return lineAtHeight ( this . doc , height + this . display . viewOffset )
} ,
heightAtLine : function ( line , mode , includeWidgets ) {
var end = false , lineObj ;
if ( typeof line == "number" ) {
var last = this . doc . first + this . doc . size - 1 ;
if ( line < this . doc . first ) { line = this . doc . first ; }
else if ( line > last ) { line = last ; end = true ; }
lineObj = getLine ( this . doc , line ) ;
} else {
lineObj = line ;
}
return intoCoordSystem ( this , lineObj , { top : 0 , left : 0 } , mode || "page" , includeWidgets || end ) . top +
( end ? this . doc . height - heightAtLine ( lineObj ) : 0 )
} ,
defaultTextHeight : function ( ) { return textHeight ( this . display ) } ,
defaultCharWidth : function ( ) { return charWidth ( this . display ) } ,
getViewport : function ( ) { return { from : this . display . viewFrom , to : this . display . viewTo } } ,
addWidget : function ( pos , node , scroll , vert , horiz ) {
var display = this . display ;
pos = cursorCoords ( this , clipPos ( this . doc , pos ) ) ;
var top = pos . bottom , left = pos . left ;
node . style . position = "absolute" ;
node . setAttribute ( "cm-ignore-events" , "true" ) ;
this . display . input . setUneditable ( node ) ;
display . sizer . appendChild ( node ) ;
if ( vert == "over" ) {
top = pos . top ;
} else if ( vert == "above" || vert == "near" ) {
var vspace = Math . max ( display . wrapper . clientHeight , this . doc . height ) ,
hspace = Math . max ( display . sizer . clientWidth , display . lineSpace . clientWidth ) ;
// Default to positioning above (if specified and possible); otherwise default to positioning below
if ( ( vert == 'above' || pos . bottom + node . offsetHeight > vspace ) && pos . top > node . offsetHeight )
{ top = pos . top - node . offsetHeight ; }
else if ( pos . bottom + node . offsetHeight <= vspace )
{ top = pos . bottom ; }
if ( left + node . offsetWidth > hspace )
{ left = hspace - node . offsetWidth ; }
}
node . style . top = top + "px" ;
node . style . left = node . style . right = "" ;
if ( horiz == "right" ) {
left = display . sizer . clientWidth - node . offsetWidth ;
node . style . right = "0px" ;
} else {
if ( horiz == "left" ) { left = 0 ; }
else if ( horiz == "middle" ) { left = ( display . sizer . clientWidth - node . offsetWidth ) / 2 ; }
node . style . left = left + "px" ;
}
if ( scroll )
{ scrollIntoView ( this , { left : left , top : top , right : left + node . offsetWidth , bottom : top + node . offsetHeight } ) ; }
} ,
triggerOnKeyDown : methodOp ( onKeyDown ) ,
triggerOnKeyPress : methodOp ( onKeyPress ) ,
triggerOnKeyUp : onKeyUp ,
execCommand : function ( cmd ) {
if ( commands . hasOwnProperty ( cmd ) )
{ return commands [ cmd ] . call ( null , this ) }
} ,
triggerElectric : methodOp ( function ( text ) { triggerElectric ( this , text ) ; } ) ,
findPosH : function ( from , amount , unit , visually ) {
var this $1 = this ;
var dir = 1 ;
if ( amount < 0 ) { dir = - 1 ; amount = - amount ; }
var cur = clipPos ( this . doc , from ) ;
for ( var i = 0 ; i < amount ; ++ i ) {
cur = findPosH ( this $1 . doc , cur , dir , unit , visually ) ;
if ( cur . hitSide ) { break }
}
return cur
} ,
moveH : methodOp ( function ( dir , unit ) {
var this $1 = this ;
this . extendSelectionsBy ( function ( range$$1 ) {
if ( this $1 . display . shift || this $1 . doc . extend || range$$1 . empty ( ) )
{ return findPosH ( this $1 . doc , range$$1 . head , dir , unit , this $1 . options . rtlMoveVisually ) }
else
{ return dir < 0 ? range$$1 . from ( ) : range$$1 . to ( ) }
} , sel _move ) ;
} ) ,
deleteH : methodOp ( function ( dir , unit ) {
var sel = this . doc . sel , doc = this . doc ;
if ( sel . somethingSelected ( ) )
{ doc . replaceSelection ( "" , null , "+delete" ) ; }
else
{ deleteNearSelection ( this , function ( range$$1 ) {
var other = findPosH ( doc , range$$1 . head , dir , unit , false ) ;
return dir < 0 ? { from : other , to : range$$1 . head } : { from : range$$1 . head , to : other }
} ) ; }
} ) ,
findPosV : function ( from , amount , unit , goalColumn ) {
var this $1 = this ;
var dir = 1 , x = goalColumn ;
if ( amount < 0 ) { dir = - 1 ; amount = - amount ; }
var cur = clipPos ( this . doc , from ) ;
for ( var i = 0 ; i < amount ; ++ i ) {
var coords = cursorCoords ( this $1 , cur , "div" ) ;
if ( x == null ) { x = coords . left ; }
else { coords . left = x ; }
cur = findPosV ( this $1 , coords , dir , unit ) ;
if ( cur . hitSide ) { break }
}
return cur
} ,
moveV : methodOp ( function ( dir , unit ) {
var this $1 = this ;
var doc = this . doc , goals = [ ] ;
var collapse = ! this . display . shift && ! doc . extend && doc . sel . somethingSelected ( ) ;
doc . extendSelectionsBy ( function ( range$$1 ) {
if ( collapse )
{ return dir < 0 ? range$$1 . from ( ) : range$$1 . to ( ) }
var headPos = cursorCoords ( this $1 , range$$1 . head , "div" ) ;
if ( range$$1 . goalColumn != null ) { headPos . left = range$$1 . goalColumn ; }
goals . push ( headPos . left ) ;
var pos = findPosV ( this $1 , headPos , dir , unit ) ;
if ( unit == "page" && range$$1 == doc . sel . primary ( ) )
{ addToScrollTop ( this $1 , charCoords ( this $1 , pos , "div" ) . top - headPos . top ) ; }
return pos
} , sel _move ) ;
if ( goals . length ) { for ( var i = 0 ; i < doc . sel . ranges . length ; i ++ )
{ doc . sel . ranges [ i ] . goalColumn = goals [ i ] ; } }
} ) ,
// Find the word at the given position (as returned by coordsChar).
findWordAt : function ( pos ) {
var doc = this . doc , line = getLine ( doc , pos . line ) . text ;
var start = pos . ch , end = pos . ch ;
if ( line ) {
var helper = this . getHelper ( pos , "wordChars" ) ;
if ( ( pos . sticky == "before" || end == line . length ) && start ) { -- start ; } else { ++ end ; }
var startChar = line . charAt ( start ) ;
var check = isWordChar ( startChar , helper )
? function ( ch ) { return isWordChar ( ch , helper ) ; }
: /\s/ . test ( startChar ) ? function ( ch ) { return /\s/ . test ( ch ) ; }
: function ( ch ) { return ( ! /\s/ . test ( ch ) && ! isWordChar ( ch ) ) ; } ;
while ( start > 0 && check ( line . charAt ( start - 1 ) ) ) { -- start ; }
while ( end < line . length && check ( line . charAt ( end ) ) ) { ++ end ; }
}
return new Range ( Pos ( pos . line , start ) , Pos ( pos . line , end ) )
} ,
toggleOverwrite : function ( value ) {
if ( value != null && value == this . state . overwrite ) { return }
if ( this . state . overwrite = ! this . state . overwrite )
{ addClass ( this . display . cursorDiv , "CodeMirror-overwrite" ) ; }
else
{ rmClass ( this . display . cursorDiv , "CodeMirror-overwrite" ) ; }
signal ( this , "overwriteToggle" , this , this . state . overwrite ) ;
} ,
hasFocus : function ( ) { return this . display . input . getField ( ) == activeElt ( ) } ,
isReadOnly : function ( ) { return ! ! ( this . options . readOnly || this . doc . cantEdit ) } ,
scrollTo : methodOp ( function ( x , y ) { scrollToCoords ( this , x , y ) ; } ) ,
getScrollInfo : function ( ) {
var scroller = this . display . scroller ;
return { left : scroller . scrollLeft , top : scroller . scrollTop ,
height : scroller . scrollHeight - scrollGap ( this ) - this . display . barHeight ,
width : scroller . scrollWidth - scrollGap ( this ) - this . display . barWidth ,
clientHeight : displayHeight ( this ) , clientWidth : displayWidth ( this ) }
} ,
scrollIntoView : methodOp ( function ( range$$1 , margin ) {
if ( range$$1 == null ) {
range$$1 = { from : this . doc . sel . primary ( ) . head , to : null } ;
if ( margin == null ) { margin = this . options . cursorScrollMargin ; }
} else if ( typeof range$$1 == "number" ) {
range$$1 = { from : Pos ( range$$1 , 0 ) , to : null } ;
} else if ( range$$1 . from == null ) {
range$$1 = { from : range$$1 , to : null } ;
}
if ( ! range$$1 . to ) { range$$1 . to = range$$1 . from ; }
range$$1 . margin = margin || 0 ;
if ( range$$1 . from . line != null ) {
scrollToRange ( this , range$$1 ) ;
} else {
scrollToCoordsRange ( this , range$$1 . from , range$$1 . to , range$$1 . margin ) ;
}
} ) ,
setSize : methodOp ( function ( width , height ) {
var this $1 = this ;
var interpret = function ( val ) { return typeof val == "number" || /^\d+$/ . test ( String ( val ) ) ? val + "px" : val ; } ;
if ( width != null ) { this . display . wrapper . style . width = interpret ( width ) ; }
if ( height != null ) { this . display . wrapper . style . height = interpret ( height ) ; }
if ( this . options . lineWrapping ) { clearLineMeasurementCache ( this ) ; }
var lineNo$$1 = this . display . viewFrom ;
this . doc . iter ( lineNo$$1 , this . display . viewTo , function ( line ) {
if ( line . widgets ) { for ( var i = 0 ; i < line . widgets . length ; i ++ )
{ if ( line . widgets [ i ] . noHScroll ) { regLineChange ( this $1 , lineNo$$1 , "widget" ) ; break } } }
++ lineNo$$1 ;
} ) ;
this . curOp . forceUpdate = true ;
signal ( this , "refresh" , this ) ;
} ) ,
operation : function ( f ) { return runInOp ( this , f ) } ,
refresh : methodOp ( function ( ) {
var oldHeight = this . display . cachedTextHeight ;
regChange ( this ) ;
this . curOp . forceUpdate = true ;
clearCaches ( this ) ;
scrollToCoords ( this , this . doc . scrollLeft , this . doc . scrollTop ) ;
updateGutterSpace ( this ) ;
if ( oldHeight == null || Math . abs ( oldHeight - textHeight ( this . display ) ) > . 5 )
{ estimateLineHeights ( this ) ; }
signal ( this , "refresh" , this ) ;
} ) ,
swapDoc : methodOp ( function ( doc ) {
var old = this . doc ;
old . cm = null ;
attachDoc ( this , doc ) ;
clearCaches ( this ) ;
this . display . input . reset ( ) ;
scrollToCoords ( this , doc . scrollLeft , doc . scrollTop ) ;
this . curOp . forceScroll = true ;
signalLater ( this , "swapDoc" , this , old ) ;
return old
} ) ,
getInputField : function ( ) { return this . display . input . getField ( ) } ,
getWrapperElement : function ( ) { return this . display . wrapper } ,
getScrollerElement : function ( ) { return this . display . scroller } ,
getGutterElement : function ( ) { return this . display . gutters }
} ;
eventMixin ( CodeMirror ) ;
CodeMirror . registerHelper = function ( type , name , value ) {
if ( ! helpers . hasOwnProperty ( type ) ) { helpers [ type ] = CodeMirror [ type ] = { _global : [ ] } ; }
helpers [ type ] [ name ] = value ;
} ;
CodeMirror . registerGlobalHelper = function ( type , name , predicate , value ) {
CodeMirror . registerHelper ( type , name , value ) ;
helpers [ type ] . _global . push ( { pred : predicate , val : value } ) ;
} ;
} ;
// Used for horizontal relative motion. Dir is -1 or 1 (left or
// right), unit can be "char", "column" (like char, but doesn't
// cross line boundaries), "word" (across next word), or "group" (to
// the start of next group of word or non-word-non-whitespace
// chars). The visually param controls whether, in right-to-left
// text, direction 1 means to move towards the next index in the
// string, or towards the character to the right of the current
// position. The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosH ( doc , pos , dir , unit , visually ) {
var oldPos = pos ;
var origDir = dir ;
var lineObj = getLine ( doc , pos . line ) ;
function findNextLine ( ) {
var l = pos . line + dir ;
if ( l < doc . first || l >= doc . first + doc . size ) { return false }
pos = new Pos ( l , pos . ch , pos . sticky ) ;
return lineObj = getLine ( doc , l )
}
function moveOnce ( boundToLine ) {
var next ;
if ( visually ) {
next = moveVisually ( doc . cm , lineObj , pos , dir ) ;
} else {
next = moveLogically ( lineObj , pos , dir ) ;
}
if ( next == null ) {
if ( ! boundToLine && findNextLine ( ) )
{ pos = endOfLine ( visually , doc . cm , lineObj , pos . line , dir ) ; }
else
{ return false }
} else {
pos = next ;
}
return true
}
if ( unit == "char" ) {
moveOnce ( ) ;
} else if ( unit == "column" ) {
moveOnce ( true ) ;
} else if ( unit == "word" || unit == "group" ) {
var sawType = null , group = unit == "group" ;
var helper = doc . cm && doc . cm . getHelper ( pos , "wordChars" ) ;
for ( var first = true ; ; first = false ) {
if ( dir < 0 && ! moveOnce ( ! first ) ) { break }
var cur = lineObj . text . charAt ( pos . ch ) || "\n" ;
var type = isWordChar ( cur , helper ) ? "w"
: group && cur == "\n" ? "n"
: ! group || /\s/ . test ( cur ) ? null
: "p" ;
if ( group && ! first && ! type ) { type = "s" ; }
if ( sawType && sawType != type ) {
if ( dir < 0 ) { dir = 1 ; moveOnce ( ) ; pos . sticky = "after" ; }
break
}
if ( type ) { sawType = type ; }
if ( dir > 0 && ! moveOnce ( ! first ) ) { break }
}
}
var result = skipAtomic ( doc , pos , oldPos , origDir , true ) ;
if ( equalCursorPos ( oldPos , result ) ) { result . hitSide = true ; }
return result
}
// For relative vertical movement. Dir may be -1 or 1. Unit can be
// "page" or "line". The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosV ( cm , pos , dir , unit ) {
var doc = cm . doc , x = pos . left , y ;
if ( unit == "page" ) {
var pageSize = Math . min ( cm . display . wrapper . clientHeight , window . innerHeight || document . documentElement . clientHeight ) ;
var moveAmount = Math . max ( pageSize - . 5 * textHeight ( cm . display ) , 3 ) ;
y = ( dir > 0 ? pos . bottom : pos . top ) + dir * moveAmount ;
} else if ( unit == "line" ) {
y = dir > 0 ? pos . bottom + 3 : pos . top - 3 ;
}
var target ;
for ( ; ; ) {
target = coordsChar ( cm , x , y ) ;
if ( ! target . outside ) { break }
if ( dir < 0 ? y <= 0 : y >= doc . height ) { target . hitSide = true ; break }
y += dir * 5 ;
}
return target
}
// CONTENTEDITABLE INPUT STYLE
var ContentEditableInput = function ( cm ) {
this . cm = cm ;
this . lastAnchorNode = this . lastAnchorOffset = this . lastFocusNode = this . lastFocusOffset = null ;
this . polling = new Delayed ( ) ;
this . composing = null ;
this . gracePeriod = false ;
this . readDOMTimeout = null ;
} ;
ContentEditableInput . prototype . init = function ( display ) {
var this $1 = this ;
var input = this , cm = input . cm ;
var div = input . div = display . lineDiv ;
disableBrowserMagic ( div , cm . options . spellcheck ) ;
on ( div , "paste" , function ( e ) {
if ( signalDOMEvent ( cm , e ) || handlePaste ( e , cm ) ) { return }
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
if ( ie _version <= 11 ) { setTimeout ( operation ( cm , function ( ) { return this $1 . updateFromDOM ( ) ; } ) , 20 ) ; }
} ) ;
on ( div , "compositionstart" , function ( e ) {
this $1 . composing = { data : e . data , done : false } ;
} ) ;
on ( div , "compositionupdate" , function ( e ) {
if ( ! this $1 . composing ) { this $1 . composing = { data : e . data , done : false } ; }
} ) ;
on ( div , "compositionend" , function ( e ) {
if ( this $1 . composing ) {
if ( e . data != this $1 . composing . data ) { this $1 . readFromDOMSoon ( ) ; }
this $1 . composing . done = true ;
}
} ) ;
on ( div , "touchstart" , function ( ) { return input . forceCompositionEnd ( ) ; } ) ;
on ( div , "input" , function ( ) {
if ( ! this $1 . composing ) { this $1 . readFromDOMSoon ( ) ; }
} ) ;
function onCopyCut ( e ) {
if ( signalDOMEvent ( cm , e ) ) { return }
if ( cm . somethingSelected ( ) ) {
setLastCopied ( { lineWise : false , text : cm . getSelections ( ) } ) ;
if ( e . type == "cut" ) { cm . replaceSelection ( "" , null , "cut" ) ; }
} else if ( ! cm . options . lineWiseCopyCut ) {
return
} else {
var ranges = copyableRanges ( cm ) ;
setLastCopied ( { lineWise : true , text : ranges . text } ) ;
if ( e . type == "cut" ) {
cm . operation ( function ( ) {
cm . setSelections ( ranges . ranges , 0 , sel _dontScroll ) ;
cm . replaceSelection ( "" , null , "cut" ) ;
} ) ;
}
}
if ( e . clipboardData ) {
e . clipboardData . clearData ( ) ;
var content = lastCopied . text . join ( "\n" ) ;
// iOS exposes the clipboard API, but seems to discard content inserted into it
e . clipboardData . setData ( "Text" , content ) ;
if ( e . clipboardData . getData ( "Text" ) == content ) {
e . preventDefault ( ) ;
return
}
}
// Old-fashioned briefly-focus-a-textarea hack
var kludge = hiddenTextarea ( ) , te = kludge . firstChild ;
cm . display . lineSpace . insertBefore ( kludge , cm . display . lineSpace . firstChild ) ;
te . value = lastCopied . text . join ( "\n" ) ;
var hadFocus = document . activeElement ;
selectInput ( te ) ;
setTimeout ( function ( ) {
cm . display . lineSpace . removeChild ( kludge ) ;
hadFocus . focus ( ) ;
if ( hadFocus == div ) { input . showPrimarySelection ( ) ; }
} , 50 ) ;
}
on ( div , "copy" , onCopyCut ) ;
on ( div , "cut" , onCopyCut ) ;
} ;
ContentEditableInput . prototype . prepareSelection = function ( ) {
var result = prepareSelection ( this . cm , false ) ;
result . focus = this . cm . state . focused ;
return result
} ;
ContentEditableInput . prototype . showSelection = function ( info , takeFocus ) {
if ( ! info || ! this . cm . display . view . length ) { return }
if ( info . focus || takeFocus ) { this . showPrimarySelection ( ) ; }
this . showMultipleSelections ( info ) ;
} ;
ContentEditableInput . prototype . showPrimarySelection = function ( ) {
var sel = window . getSelection ( ) , cm = this . cm , prim = cm . doc . sel . primary ( ) ;
var from = prim . from ( ) , to = prim . to ( ) ;
if ( cm . display . viewTo == cm . display . viewFrom || from . line >= cm . display . viewTo || to . line < cm . display . viewFrom ) {
sel . removeAllRanges ( ) ;
return
}
var curAnchor = domToPos ( cm , sel . anchorNode , sel . anchorOffset ) ;
var curFocus = domToPos ( cm , sel . focusNode , sel . focusOffset ) ;
if ( curAnchor && ! curAnchor . bad && curFocus && ! curFocus . bad &&
cmp ( minPos ( curAnchor , curFocus ) , from ) == 0 &&
cmp ( maxPos ( curAnchor , curFocus ) , to ) == 0 )
{ return }
var view = cm . display . view ;
var start = ( from . line >= cm . display . viewFrom && posToDOM ( cm , from ) ) ||
{ node : view [ 0 ] . measure . map [ 2 ] , offset : 0 } ;
var end = to . line < cm . display . viewTo && posToDOM ( cm , to ) ;
if ( ! end ) {
var measure = view [ view . length - 1 ] . measure ;
var map$$1 = measure . maps ? measure . maps [ measure . maps . length - 1 ] : measure . map ;
end = { node : map$$1 [ map$$1 . length - 1 ] , offset : map$$1 [ map$$1 . length - 2 ] - map$$1 [ map$$1 . length - 3 ] } ;
}
if ( ! start || ! end ) {
sel . removeAllRanges ( ) ;
return
}
var old = sel . rangeCount && sel . getRangeAt ( 0 ) , rng ;
try { rng = range ( start . node , start . offset , end . offset , end . node ) ; }
catch ( e ) { } // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if ( rng ) {
if ( ! gecko && cm . state . focused ) {
sel . collapse ( start . node , start . offset ) ;
if ( ! rng . collapsed ) {
sel . removeAllRanges ( ) ;
sel . addRange ( rng ) ;
}
} else {
sel . removeAllRanges ( ) ;
sel . addRange ( rng ) ;
}
if ( old && sel . anchorNode == null ) { sel . addRange ( old ) ; }
else if ( gecko ) { this . startGracePeriod ( ) ; }
}
this . rememberSelection ( ) ;
} ;
ContentEditableInput . prototype . startGracePeriod = function ( ) {
var this $1 = this ;
clearTimeout ( this . gracePeriod ) ;
this . gracePeriod = setTimeout ( function ( ) {
this $1 . gracePeriod = false ;
if ( this $1 . selectionChanged ( ) )
{ this $1 . cm . operation ( function ( ) { return this $1 . cm . curOp . selectionChanged = true ; } ) ; }
} , 20 ) ;
} ;
ContentEditableInput . prototype . showMultipleSelections = function ( info ) {
removeChildrenAndAdd ( this . cm . display . cursorDiv , info . cursors ) ;
removeChildrenAndAdd ( this . cm . display . selectionDiv , info . selection ) ;
} ;
ContentEditableInput . prototype . rememberSelection = function ( ) {
var sel = window . getSelection ( ) ;
this . lastAnchorNode = sel . anchorNode ; this . lastAnchorOffset = sel . anchorOffset ;
this . lastFocusNode = sel . focusNode ; this . lastFocusOffset = sel . focusOffset ;
} ;
ContentEditableInput . prototype . selectionInEditor = function ( ) {
var sel = window . getSelection ( ) ;
if ( ! sel . rangeCount ) { return false }
var node = sel . getRangeAt ( 0 ) . commonAncestorContainer ;
return contains ( this . div , node )
} ;
ContentEditableInput . prototype . focus = function ( ) {
if ( this . cm . options . readOnly != "nocursor" ) {
if ( ! this . selectionInEditor ( ) )
{ this . showSelection ( this . prepareSelection ( ) , true ) ; }
this . div . focus ( ) ;
}
} ;
ContentEditableInput . prototype . blur = function ( ) { this . div . blur ( ) ; } ;
ContentEditableInput . prototype . getField = function ( ) { return this . div } ;
ContentEditableInput . prototype . supportsTouch = function ( ) { return true } ;
ContentEditableInput . prototype . receivedFocus = function ( ) {
var input = this ;
if ( this . selectionInEditor ( ) )
{ this . pollSelection ( ) ; }
else
{ runInOp ( this . cm , function ( ) { return input . cm . curOp . selectionChanged = true ; } ) ; }
function poll ( ) {
if ( input . cm . state . focused ) {
input . pollSelection ( ) ;
input . polling . set ( input . cm . options . pollInterval , poll ) ;
}
}
this . polling . set ( this . cm . options . pollInterval , poll ) ;
} ;
ContentEditableInput . prototype . selectionChanged = function ( ) {
var sel = window . getSelection ( ) ;
return sel . anchorNode != this . lastAnchorNode || sel . anchorOffset != this . lastAnchorOffset ||
sel . focusNode != this . lastFocusNode || sel . focusOffset != this . lastFocusOffset
} ;
ContentEditableInput . prototype . pollSelection = function ( ) {
if ( this . readDOMTimeout != null || this . gracePeriod || ! this . selectionChanged ( ) ) { return }
var sel = window . getSelection ( ) , cm = this . cm ;
// On Android Chrome (version 56, at least), backspacing into an
// uneditable block element will put the cursor in that element,
// and then, because it's not editable, hide the virtual keyboard.
// Because Android doesn't allow us to actually detect backspace
// presses in a sane way, this code checks for when that happens
// and simulates a backspace press in this case.
if ( android && chrome && this . cm . options . gutters . length && isInGutter ( sel . anchorNode ) ) {
this . cm . triggerOnKeyDown ( { type : "keydown" , keyCode : 8 , preventDefault : Math . abs } ) ;
this . blur ( ) ;
this . focus ( ) ;
return
}
if ( this . composing ) { return }
this . rememberSelection ( ) ;
var anchor = domToPos ( cm , sel . anchorNode , sel . anchorOffset ) ;
var head = domToPos ( cm , sel . focusNode , sel . focusOffset ) ;
if ( anchor && head ) { runInOp ( cm , function ( ) {
setSelection ( cm . doc , simpleSelection ( anchor , head ) , sel _dontScroll ) ;
if ( anchor . bad || head . bad ) { cm . curOp . selectionChanged = true ; }
} ) ; }
} ;
ContentEditableInput . prototype . pollContent = function ( ) {
if ( this . readDOMTimeout != null ) {
clearTimeout ( this . readDOMTimeout ) ;
this . readDOMTimeout = null ;
}
var cm = this . cm , display = cm . display , sel = cm . doc . sel . primary ( ) ;
var from = sel . from ( ) , to = sel . to ( ) ;
if ( from . ch == 0 && from . line > cm . firstLine ( ) )
{ from = Pos ( from . line - 1 , getLine ( cm . doc , from . line - 1 ) . length ) ; }
if ( to . ch == getLine ( cm . doc , to . line ) . text . length && to . line < cm . lastLine ( ) )
{ to = Pos ( to . line + 1 , 0 ) ; }
if ( from . line < display . viewFrom || to . line > display . viewTo - 1 ) { return false }
var fromIndex , fromLine , fromNode ;
if ( from . line == display . viewFrom || ( fromIndex = findViewIndex ( cm , from . line ) ) == 0 ) {
fromLine = lineNo ( display . view [ 0 ] . line ) ;
fromNode = display . view [ 0 ] . node ;
} else {
fromLine = lineNo ( display . view [ fromIndex ] . line ) ;
fromNode = display . view [ fromIndex - 1 ] . node . nextSibling ;
}
var toIndex = findViewIndex ( cm , to . line ) ;
var toLine , toNode ;
if ( toIndex == display . view . length - 1 ) {
toLine = display . viewTo - 1 ;
toNode = display . lineDiv . lastChild ;
} else {
toLine = lineNo ( display . view [ toIndex + 1 ] . line ) - 1 ;
toNode = display . view [ toIndex + 1 ] . node . previousSibling ;
}
if ( ! fromNode ) { return false }
var newText = cm . doc . splitLines ( domTextBetween ( cm , fromNode , toNode , fromLine , toLine ) ) ;
var oldText = getBetween ( cm . doc , Pos ( fromLine , 0 ) , Pos ( toLine , getLine ( cm . doc , toLine ) . text . length ) ) ;
while ( newText . length > 1 && oldText . length > 1 ) {
if ( lst ( newText ) == lst ( oldText ) ) { newText . pop ( ) ; oldText . pop ( ) ; toLine -- ; }
else if ( newText [ 0 ] == oldText [ 0 ] ) { newText . shift ( ) ; oldText . shift ( ) ; fromLine ++ ; }
else { break }
}
var cutFront = 0 , cutEnd = 0 ;
var newTop = newText [ 0 ] , oldTop = oldText [ 0 ] , maxCutFront = Math . min ( newTop . length , oldTop . length ) ;
while ( cutFront < maxCutFront && newTop . charCodeAt ( cutFront ) == oldTop . charCodeAt ( cutFront ) )
{ ++ cutFront ; }
var newBot = lst ( newText ) , oldBot = lst ( oldText ) ;
var maxCutEnd = Math . min ( newBot . length - ( newText . length == 1 ? cutFront : 0 ) ,
oldBot . length - ( oldText . length == 1 ? cutFront : 0 ) ) ;
while ( cutEnd < maxCutEnd &&
newBot . charCodeAt ( newBot . length - cutEnd - 1 ) == oldBot . charCodeAt ( oldBot . length - cutEnd - 1 ) )
{ ++ cutEnd ; }
// Try to move start of change to start of selection if ambiguous
if ( newText . length == 1 && oldText . length == 1 && fromLine == from . line ) {
while ( cutFront && cutFront > from . ch &&
newBot . charCodeAt ( newBot . length - cutEnd - 1 ) == oldBot . charCodeAt ( oldBot . length - cutEnd - 1 ) ) {
cutFront -- ;
cutEnd ++ ;
}
}
newText [ newText . length - 1 ] = newBot . slice ( 0 , newBot . length - cutEnd ) . replace ( /^\u200b+/ , "" ) ;
newText [ 0 ] = newText [ 0 ] . slice ( cutFront ) . replace ( /\u200b+$/ , "" ) ;
var chFrom = Pos ( fromLine , cutFront ) ;
var chTo = Pos ( toLine , oldText . length ? lst ( oldText ) . length - cutEnd : 0 ) ;
if ( newText . length > 1 || newText [ 0 ] || cmp ( chFrom , chTo ) ) {
replaceRange ( cm . doc , newText , chFrom , chTo , "+input" ) ;
return true
}
} ;
ContentEditableInput . prototype . ensurePolled = function ( ) {
this . forceCompositionEnd ( ) ;
} ;
ContentEditableInput . prototype . reset = function ( ) {
this . forceCompositionEnd ( ) ;
} ;
ContentEditableInput . prototype . forceCompositionEnd = function ( ) {
if ( ! this . composing ) { return }
clearTimeout ( this . readDOMTimeout ) ;
this . composing = null ;
this . updateFromDOM ( ) ;
this . div . blur ( ) ;
this . div . focus ( ) ;
} ;
ContentEditableInput . prototype . readFromDOMSoon = function ( ) {
var this $1 = this ;
if ( this . readDOMTimeout != null ) { return }
this . readDOMTimeout = setTimeout ( function ( ) {
this $1 . readDOMTimeout = null ;
if ( this $1 . composing ) {
if ( this $1 . composing . done ) { this $1 . composing = null ; }
else { return }
}
this $1 . updateFromDOM ( ) ;
} , 80 ) ;
} ;
ContentEditableInput . prototype . updateFromDOM = function ( ) {
var this $1 = this ;
if ( this . cm . isReadOnly ( ) || ! this . pollContent ( ) )
{ runInOp ( this . cm , function ( ) { return regChange ( this $1 . cm ) ; } ) ; }
} ;
ContentEditableInput . prototype . setUneditable = function ( node ) {
node . contentEditable = "false" ;
} ;
ContentEditableInput . prototype . onKeyPress = function ( e ) {
if ( e . charCode == 0 ) { return }
e . preventDefault ( ) ;
if ( ! this . cm . isReadOnly ( ) )
{ operation ( this . cm , applyTextInput ) ( this . cm , String . fromCharCode ( e . charCode == null ? e . keyCode : e . charCode ) , 0 ) ; }
} ;
ContentEditableInput . prototype . readOnlyChanged = function ( val ) {
this . div . contentEditable = String ( val != "nocursor" ) ;
} ;
ContentEditableInput . prototype . onContextMenu = function ( ) { } ;
ContentEditableInput . prototype . resetPosition = function ( ) { } ;
ContentEditableInput . prototype . needsContentAttribute = true ;
function posToDOM ( cm , pos ) {
var view = findViewForLine ( cm , pos . line ) ;
if ( ! view || view . hidden ) { return null }
var line = getLine ( cm . doc , pos . line ) ;
var info = mapFromLineView ( view , line , pos . line ) ;
var order = getOrder ( line , cm . doc . direction ) , side = "left" ;
if ( order ) {
var partPos = getBidiPartAt ( order , pos . ch ) ;
side = partPos % 2 ? "right" : "left" ;
}
var result = nodeAndOffsetInLineMap ( info . map , pos . ch , side ) ;
result . offset = result . collapse == "right" ? result . end : result . start ;
return result
}
function isInGutter ( node ) {
for ( var scan = node ; scan ; scan = scan . parentNode )
{ if ( /CodeMirror-gutter-wrapper/ . test ( scan . className ) ) { return true } }
return false
}
function badPos ( pos , bad ) { if ( bad ) { pos . bad = true ; } return pos }
function domTextBetween ( cm , from , to , fromLine , toLine ) {
var text = "" , closing = false , lineSep = cm . doc . lineSeparator ( ) ;
function recognizeMarker ( id ) { return function ( marker ) { return marker . id == id ; } }
function close ( ) {
if ( closing ) {
text += lineSep ;
closing = false ;
}
}
function addText ( str ) {
if ( str ) {
close ( ) ;
text += str ;
}
}
function walk ( node ) {
if ( node . nodeType == 1 ) {
var cmText = node . getAttribute ( "cm-text" ) ;
if ( cmText != null ) {
addText ( cmText || node . textContent . replace ( /\u200b/g , "" ) ) ;
return
}
var markerID = node . getAttribute ( "cm-marker" ) , range$$1 ;
if ( markerID ) {
var found = cm . findMarks ( Pos ( fromLine , 0 ) , Pos ( toLine + 1 , 0 ) , recognizeMarker ( + markerID ) ) ;
if ( found . length && ( range$$1 = found [ 0 ] . find ( ) ) )
{ addText ( getBetween ( cm . doc , range$$1 . from , range$$1 . to ) . join ( lineSep ) ) ; }
return
}
if ( node . getAttribute ( "contenteditable" ) == "false" ) { return }
var isBlock = /^(pre|div|p)$/i . test ( node . nodeName ) ;
if ( isBlock ) { close ( ) ; }
for ( var i = 0 ; i < node . childNodes . length ; i ++ )
{ walk ( node . childNodes [ i ] ) ; }
if ( isBlock ) { closing = true ; }
} else if ( node . nodeType == 3 ) {
addText ( node . nodeValue ) ;
}
}
for ( ; ; ) {
walk ( from ) ;
if ( from == to ) { break }
from = from . nextSibling ;
}
return text
}
function domToPos ( cm , node , offset ) {
var lineNode ;
if ( node == cm . display . lineDiv ) {
lineNode = cm . display . lineDiv . childNodes [ offset ] ;
if ( ! lineNode ) { return badPos ( cm . clipPos ( Pos ( cm . display . viewTo - 1 ) ) , true ) }
node = null ; offset = 0 ;
} else {
for ( lineNode = node ; ; lineNode = lineNode . parentNode ) {
if ( ! lineNode || lineNode == cm . display . lineDiv ) { return null }
if ( lineNode . parentNode && lineNode . parentNode == cm . display . lineDiv ) { break }
}
}
for ( var i = 0 ; i < cm . display . view . length ; i ++ ) {
var lineView = cm . display . view [ i ] ;
if ( lineView . node == lineNode )
{ return locateNodeInLineView ( lineView , node , offset ) }
}
}
function locateNodeInLineView ( lineView , node , offset ) {
var wrapper = lineView . text . firstChild , bad = false ;
if ( ! node || ! contains ( wrapper , node ) ) { return badPos ( Pos ( lineNo ( lineView . line ) , 0 ) , true ) }
if ( node == wrapper ) {
bad = true ;
node = wrapper . childNodes [ offset ] ;
offset = 0 ;
if ( ! node ) {
var line = lineView . rest ? lst ( lineView . rest ) : lineView . line ;
return badPos ( Pos ( lineNo ( line ) , line . text . length ) , bad )
}
}
var textNode = node . nodeType == 3 ? node : null , topNode = node ;
if ( ! textNode && node . childNodes . length == 1 && node . firstChild . nodeType == 3 ) {
textNode = node . firstChild ;
if ( offset ) { offset = textNode . nodeValue . length ; }
}
while ( topNode . parentNode != wrapper ) { topNode = topNode . parentNode ; }
var measure = lineView . measure , maps = measure . maps ;
function find ( textNode , topNode , offset ) {
for ( var i = - 1 ; i < ( maps ? maps . length : 0 ) ; i ++ ) {
var map$$1 = i < 0 ? measure . map : maps [ i ] ;
for ( var j = 0 ; j < map$$1 . length ; j += 3 ) {
var curNode = map$$1 [ j + 2 ] ;
if ( curNode == textNode || curNode == topNode ) {
var line = lineNo ( i < 0 ? lineView . line : lineView . rest [ i ] ) ;
var ch = map$$1 [ j ] + offset ;
if ( offset < 0 || curNode != textNode ) { ch = map$$1 [ j + ( offset ? 1 : 0 ) ] ; }
return Pos ( line , ch )
}
}
}
}
var found = find ( textNode , topNode , offset ) ;
if ( found ) { return badPos ( found , bad ) }
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
for ( var after = topNode . nextSibling , dist = textNode ? textNode . nodeValue . length - offset : 0 ; after ; after = after . nextSibling ) {
found = find ( after , after . firstChild , 0 ) ;
if ( found )
{ return badPos ( Pos ( found . line , found . ch - dist ) , bad ) }
else
{ dist += after . textContent . length ; }
}
for ( var before = topNode . previousSibling , dist$1 = offset ; before ; before = before . previousSibling ) {
found = find ( before , before . firstChild , - 1 ) ;
if ( found )
{ return badPos ( Pos ( found . line , found . ch + dist$1 ) , bad ) }
else
{ dist$1 += before . textContent . length ; }
}
}
// TEXTAREA INPUT STYLE
var TextareaInput = function ( cm ) {
this . cm = cm ;
// See input.poll and input.reset
this . prevInput = "" ;
// Flag that indicates whether we expect input to appear real soon
// now (after some event like 'keypress' or 'input') and are
// polling intensively.
this . pollingFast = false ;
// Self-resetting timeout for the poller
this . polling = new Delayed ( ) ;
// Tracks when input.reset has punted to just putting a short
// string into the textarea instead of the full selection.
this . inaccurateSelection = false ;
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
this . hasSelection = false ;
this . composing = null ;
} ;
TextareaInput . prototype . init = function ( display ) {
var this $1 = this ;
var input = this , cm = this . cm ;
// Wraps and hides input textarea
var div = this . wrapper = hiddenTextarea ( ) ;
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
var te = this . textarea = div . firstChild ;
display . wrapper . insertBefore ( div , display . wrapper . firstChild ) ;
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
if ( ios ) { te . style . width = "0px" ; }
on ( te , "input" , function ( ) {
if ( ie && ie _version >= 9 && this $1 . hasSelection ) { this $1 . hasSelection = null ; }
input . poll ( ) ;
} ) ;
on ( te , "paste" , function ( e ) {
if ( signalDOMEvent ( cm , e ) || handlePaste ( e , cm ) ) { return }
cm . state . pasteIncoming = true ;
input . fastPoll ( ) ;
} ) ;
function prepareCopyCut ( e ) {
if ( signalDOMEvent ( cm , e ) ) { return }
if ( cm . somethingSelected ( ) ) {
setLastCopied ( { lineWise : false , text : cm . getSelections ( ) } ) ;
if ( input . inaccurateSelection ) {
input . prevInput = "" ;
input . inaccurateSelection = false ;
te . value = lastCopied . text . join ( "\n" ) ;
selectInput ( te ) ;
}
} else if ( ! cm . options . lineWiseCopyCut ) {
return
} else {
var ranges = copyableRanges ( cm ) ;
setLastCopied ( { lineWise : true , text : ranges . text } ) ;
if ( e . type == "cut" ) {
cm . setSelections ( ranges . ranges , null , sel _dontScroll ) ;
} else {
input . prevInput = "" ;
te . value = ranges . text . join ( "\n" ) ;
selectInput ( te ) ;
}
}
if ( e . type == "cut" ) { cm . state . cutIncoming = true ; }
}
on ( te , "cut" , prepareCopyCut ) ;
on ( te , "copy" , prepareCopyCut ) ;
on ( display . scroller , "paste" , function ( e ) {
if ( eventInWidget ( display , e ) || signalDOMEvent ( cm , e ) ) { return }
cm . state . pasteIncoming = true ;
input . focus ( ) ;
} ) ;
// Prevent normal selection in the editor (we handle our own)
on ( display . lineSpace , "selectstart" , function ( e ) {
if ( ! eventInWidget ( display , e ) ) { e _preventDefault ( e ) ; }
} ) ;
on ( te , "compositionstart" , function ( ) {
var start = cm . getCursor ( "from" ) ;
if ( input . composing ) { input . composing . range . clear ( ) ; }
input . composing = {
start : start ,
range : cm . markText ( start , cm . getCursor ( "to" ) , { className : "CodeMirror-composing" } )
} ;
} ) ;
on ( te , "compositionend" , function ( ) {
if ( input . composing ) {
input . poll ( ) ;
input . composing . range . clear ( ) ;
input . composing = null ;
}
} ) ;
} ;
TextareaInput . prototype . prepareSelection = function ( ) {
// Redraw the selection and/or cursor
var cm = this . cm , display = cm . display , doc = cm . doc ;
var result = prepareSelection ( cm ) ;
// Move the hidden textarea near the cursor to prevent scrolling artifacts
if ( cm . options . moveInputWithCursor ) {
var headPos = cursorCoords ( cm , doc . sel . primary ( ) . head , "div" ) ;
var wrapOff = display . wrapper . getBoundingClientRect ( ) , lineOff = display . lineDiv . getBoundingClientRect ( ) ;
result . teTop = Math . max ( 0 , Math . min ( display . wrapper . clientHeight - 10 ,
headPos . top + lineOff . top - wrapOff . top ) ) ;
result . teLeft = Math . max ( 0 , Math . min ( display . wrapper . clientWidth - 10 ,
headPos . left + lineOff . left - wrapOff . left ) ) ;
}
return result
} ;
TextareaInput . prototype . showSelection = function ( drawn ) {
var cm = this . cm , display = cm . display ;
removeChildrenAndAdd ( display . cursorDiv , drawn . cursors ) ;
removeChildrenAndAdd ( display . selectionDiv , drawn . selection ) ;
if ( drawn . teTop != null ) {
this . wrapper . style . top = drawn . teTop + "px" ;
this . wrapper . style . left = drawn . teLeft + "px" ;
}
} ;
// Reset the input to correspond to the selection (or to be empty,
// when not typing and nothing is selected)
TextareaInput . prototype . reset = function ( typing ) {
if ( this . contextMenuPending || this . composing ) { return }
var minimal , selected , cm = this . cm , doc = cm . doc ;
if ( cm . somethingSelected ( ) ) {
this . prevInput = "" ;
var range$$1 = doc . sel . primary ( ) ;
minimal = hasCopyEvent &&
( range$$1 . to ( ) . line - range$$1 . from ( ) . line > 100 || ( selected = cm . getSelection ( ) ) . length > 1000 ) ;
var content = minimal ? "-" : selected || cm . getSelection ( ) ;
this . textarea . value = content ;
if ( cm . state . focused ) { selectInput ( this . textarea ) ; }
if ( ie && ie _version >= 9 ) { this . hasSelection = content ; }
} else if ( ! typing ) {
this . prevInput = this . textarea . value = "" ;
if ( ie && ie _version >= 9 ) { this . hasSelection = null ; }
}
this . inaccurateSelection = minimal ;
} ;
TextareaInput . prototype . getField = function ( ) { return this . textarea } ;
TextareaInput . prototype . supportsTouch = function ( ) { return false } ;
TextareaInput . prototype . focus = function ( ) {
if ( this . cm . options . readOnly != "nocursor" && ( ! mobile || activeElt ( ) != this . textarea ) ) {
try { this . textarea . focus ( ) ; }
catch ( e ) { } // IE8 will throw if the textarea is display: none or not in DOM
}
} ;
TextareaInput . prototype . blur = function ( ) { this . textarea . blur ( ) ; } ;
TextareaInput . prototype . resetPosition = function ( ) {
this . wrapper . style . top = this . wrapper . style . left = 0 ;
} ;
TextareaInput . prototype . receivedFocus = function ( ) { this . slowPoll ( ) ; } ;
// Poll for input changes, using the normal rate of polling. This
// runs as long as the editor is focused.
TextareaInput . prototype . slowPoll = function ( ) {
var this $1 = this ;
if ( this . pollingFast ) { return }
this . polling . set ( this . cm . options . pollInterval , function ( ) {
this $1 . poll ( ) ;
if ( this $1 . cm . state . focused ) { this $1 . slowPoll ( ) ; }
} ) ;
} ;
// When an event has just come in that is likely to add or change
// something in the input textarea, we poll faster, to ensure that
// the change appears on the screen quickly.
TextareaInput . prototype . fastPoll = function ( ) {
var missed = false , input = this ;
input . pollingFast = true ;
function p ( ) {
var changed = input . poll ( ) ;
if ( ! changed && ! missed ) { missed = true ; input . polling . set ( 60 , p ) ; }
else { input . pollingFast = false ; input . slowPoll ( ) ; }
}
input . polling . set ( 20 , p ) ;
} ;
// Read input from the textarea, and update the document to match.
// When something is selected, it is present in the textarea, and
// selected (unless it is huge, in which case a placeholder is
// used). When nothing is selected, the cursor sits after previously
// seen text (can be empty), which is stored in prevInput (we must
// not reset the textarea when typing, because that breaks IME).
TextareaInput . prototype . poll = function ( ) {
var this $1 = this ;
var cm = this . cm , input = this . textarea , prevInput = this . prevInput ;
// Since this is called a *lot*, try to bail out as cheaply as
// possible when it is clear that nothing happened. hasSelection
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if ( this . contextMenuPending || ! cm . state . focused ||
( hasSelection ( input ) && ! prevInput && ! this . composing ) ||
cm . isReadOnly ( ) || cm . options . disableInput || cm . state . keySeq )
{ return false }
var text = input . value ;
// If nothing changed, bail.
if ( text == prevInput && ! cm . somethingSelected ( ) ) { return false }
// Work around nonsensical selection resetting in IE9/10, and
// inexplicable appearance of private area unicode characters on
// some key combos in Mac (#2689).
if ( ie && ie _version >= 9 && this . hasSelection === text ||
mac && /[\uf700-\uf7ff]/ . test ( text ) ) {
cm . display . input . reset ( ) ;
return false
}
if ( cm . doc . sel == cm . display . selForContextMenu ) {
var first = text . charCodeAt ( 0 ) ;
if ( first == 0x200b && ! prevInput ) { prevInput = "\u200b" ; }
if ( first == 0x21da ) { this . reset ( ) ; return this . cm . execCommand ( "undo" ) }
}
// Find the part of the input that is actually new
var same = 0 , l = Math . min ( prevInput . length , text . length ) ;
while ( same < l && prevInput . charCodeAt ( same ) == text . charCodeAt ( same ) ) { ++ same ; }
runInOp ( cm , function ( ) {
applyTextInput ( cm , text . slice ( same ) , prevInput . length - same ,
null , this $1 . composing ? "*compose" : null ) ;
// Don't leave long text in the textarea, since it makes further polling slow
if ( text . length > 1000 || text . indexOf ( "\n" ) > - 1 ) { input . value = this $1 . prevInput = "" ; }
else { this $1 . prevInput = text ; }
if ( this $1 . composing ) {
this $1 . composing . range . clear ( ) ;
this $1 . composing . range = cm . markText ( this $1 . composing . start , cm . getCursor ( "to" ) ,
{ className : "CodeMirror-composing" } ) ;
}
} ) ;
return true
} ;
TextareaInput . prototype . ensurePolled = function ( ) {
if ( this . pollingFast && this . poll ( ) ) { this . pollingFast = false ; }
} ;
TextareaInput . prototype . onKeyPress = function ( ) {
if ( ie && ie _version >= 9 ) { this . hasSelection = null ; }
this . fastPoll ( ) ;
} ;
TextareaInput . prototype . onContextMenu = function ( e ) {
var input = this , cm = input . cm , display = cm . display , te = input . textarea ;
var pos = posFromMouse ( cm , e ) , scrollPos = display . scroller . scrollTop ;
if ( ! pos || presto ) { return } // Opera is difficult.
// Reset the current text selection only if the click is done outside of the selection
// and 'resetSelectionOnContextMenu' option is true.
var reset = cm . options . resetSelectionOnContextMenu ;
if ( reset && cm . doc . sel . contains ( pos ) == - 1 )
{ operation ( cm , setSelection ) ( cm . doc , simpleSelection ( pos ) , sel _dontScroll ) ; }
var oldCSS = te . style . cssText , oldWrapperCSS = input . wrapper . style . cssText ;
input . wrapper . style . cssText = "position: absolute" ;
var wrapperBox = input . wrapper . getBoundingClientRect ( ) ;
te . style . cssText = "position: absolute; width: 30px; height: 30px;\n top: " + ( e . clientY - wrapperBox . top - 5 ) + "px; left: " + ( e . clientX - wrapperBox . left - 5 ) + "px;\n z-index: 1000; background: " + ( ie ? "rgba(255, 255, 255, .05)" : "transparent" ) + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" ;
var oldScrollY ;
if ( webkit ) { oldScrollY = window . scrollY ; } // Work around Chrome issue (#2712)
display . input . focus ( ) ;
if ( webkit ) { window . scrollTo ( null , oldScrollY ) ; }
display . input . reset ( ) ;
// Adds "Select all" to context menu in FF
if ( ! cm . somethingSelected ( ) ) { te . value = input . prevInput = " " ; }
input . contextMenuPending = true ;
display . selForContextMenu = cm . doc . sel ;
clearTimeout ( display . detectingSelectAll ) ;
// Select-all will be greyed out if there's nothing to select, so
// this adds a zero-width space so that we can later check whether
// it got selected.
function prepareSelectAllHack ( ) {
if ( te . selectionStart != null ) {
var selected = cm . somethingSelected ( ) ;
var extval = "\u200b" + ( selected ? te . value : "" ) ;
te . value = "\u21da" ; // Used to catch context-menu undo
te . value = extval ;
input . prevInput = selected ? "" : "\u200b" ;
te . selectionStart = 1 ; te . selectionEnd = extval . length ;
// Re-set this, in case some other handler touched the
// selection in the meantime.
display . selForContextMenu = cm . doc . sel ;
}
}
function rehide ( ) {
input . contextMenuPending = false ;
input . wrapper . style . cssText = oldWrapperCSS ;
te . style . cssText = oldCSS ;
if ( ie && ie _version < 9 ) { display . scrollbars . setScrollTop ( display . scroller . scrollTop = scrollPos ) ; }
// Try to detect the user choosing select-all
if ( te . selectionStart != null ) {
if ( ! ie || ( ie && ie _version < 9 ) ) { prepareSelectAllHack ( ) ; }
var i = 0 , poll = function ( ) {
if ( display . selForContextMenu == cm . doc . sel && te . selectionStart == 0 &&
te . selectionEnd > 0 && input . prevInput == "\u200b" ) {
operation ( cm , selectAll ) ( cm ) ;
} else if ( i ++ < 10 ) {
display . detectingSelectAll = setTimeout ( poll , 500 ) ;
} else {
display . selForContextMenu = null ;
display . input . reset ( ) ;
}
} ;
display . detectingSelectAll = setTimeout ( poll , 200 ) ;
}
}
if ( ie && ie _version >= 9 ) { prepareSelectAllHack ( ) ; }
if ( captureRightClick ) {
e _stop ( e ) ;
var mouseup = function ( ) {
off ( window , "mouseup" , mouseup ) ;
setTimeout ( rehide , 20 ) ;
} ;
on ( window , "mouseup" , mouseup ) ;
} else {
setTimeout ( rehide , 50 ) ;
}
} ;
TextareaInput . prototype . readOnlyChanged = function ( val ) {
if ( ! val ) { this . reset ( ) ; }
} ;
TextareaInput . prototype . setUneditable = function ( ) { } ;
TextareaInput . prototype . needsContentAttribute = false ;
function fromTextArea ( textarea , options ) {
options = options ? copyObj ( options ) : { } ;
options . value = textarea . value ;
if ( ! options . tabindex && textarea . tabIndex )
{ options . tabindex = textarea . tabIndex ; }
if ( ! options . placeholder && textarea . placeholder )
{ options . placeholder = textarea . placeholder ; }
// Set autofocus to true if this textarea is focused, or if it has
// autofocus and no other element is focused.
if ( options . autofocus == null ) {
var hasFocus = activeElt ( ) ;
options . autofocus = hasFocus == textarea ||
textarea . getAttribute ( "autofocus" ) != null && hasFocus == document . body ;
}
function save ( ) { textarea . value = cm . getValue ( ) ; }
var realSubmit ;
if ( textarea . form ) {
on ( textarea . form , "submit" , save ) ;
// Deplorable hack to make the submit method do the right thing.
if ( ! options . leaveSubmitMethodAlone ) {
var form = textarea . form ;
realSubmit = form . submit ;
try {
var wrappedSubmit = form . submit = function ( ) {
save ( ) ;
form . submit = realSubmit ;
form . submit ( ) ;
form . submit = wrappedSubmit ;
} ;
} catch ( e ) { }
}
}
options . finishInit = function ( cm ) {
cm . save = save ;
cm . getTextArea = function ( ) { return textarea ; } ;
cm . toTextArea = function ( ) {
cm . toTextArea = isNaN ; // Prevent this from being ran twice
save ( ) ;
textarea . parentNode . removeChild ( cm . getWrapperElement ( ) ) ;
textarea . style . display = "" ;
if ( textarea . form ) {
off ( textarea . form , "submit" , save ) ;
if ( typeof textarea . form . submit == "function" )
{ textarea . form . submit = realSubmit ; }
}
} ;
} ;
textarea . style . display = "none" ;
var cm = CodeMirror$1 ( function ( node ) { return textarea . parentNode . insertBefore ( node , textarea . nextSibling ) ; } ,
options ) ;
return cm
}
function addLegacyProps ( CodeMirror ) {
CodeMirror . off = off ;
CodeMirror . on = on ;
CodeMirror . wheelEventPixels = wheelEventPixels ;
CodeMirror . Doc = Doc ;
CodeMirror . splitLines = splitLinesAuto ;
CodeMirror . countColumn = countColumn ;
CodeMirror . findColumn = findColumn ;
CodeMirror . isWordChar = isWordCharBasic ;
CodeMirror . Pass = Pass ;
CodeMirror . signal = signal ;
CodeMirror . Line = Line ;
CodeMirror . changeEnd = changeEnd ;
CodeMirror . scrollbarModel = scrollbarModel ;
CodeMirror . Pos = Pos ;
CodeMirror . cmpPos = cmp ;
CodeMirror . modes = modes ;
CodeMirror . mimeModes = mimeModes ;
CodeMirror . resolveMode = resolveMode ;
CodeMirror . getMode = getMode ;
CodeMirror . modeExtensions = modeExtensions ;
CodeMirror . extendMode = extendMode ;
CodeMirror . copyState = copyState ;
CodeMirror . startState = startState ;
CodeMirror . innerMode = innerMode ;
CodeMirror . commands = commands ;
CodeMirror . keyMap = keyMap ;
CodeMirror . keyName = keyName ;
CodeMirror . isModifierKey = isModifierKey ;
CodeMirror . lookupKey = lookupKey ;
CodeMirror . normalizeKeyMap = normalizeKeyMap ;
CodeMirror . StringStream = StringStream ;
CodeMirror . SharedTextMarker = SharedTextMarker ;
CodeMirror . TextMarker = TextMarker ;
CodeMirror . LineWidget = LineWidget ;
CodeMirror . e _preventDefault = e _preventDefault ;
CodeMirror . e _stopPropagation = e _stopPropagation ;
CodeMirror . e _stop = e _stop ;
CodeMirror . addClass = addClass ;
CodeMirror . contains = contains ;
CodeMirror . rmClass = rmClass ;
CodeMirror . keyNames = keyNames ;
}
// EDITOR CONSTRUCTOR
defineOptions ( CodeMirror$1 ) ;
addEditorMethods ( CodeMirror$1 ) ;
// Set up methods on CodeMirror's prototype to redirect to the editor's document.
var dontDelegate = "iter insert remove copy getEditor constructor" . split ( " " ) ;
for ( var prop in Doc . prototype ) { if ( Doc . prototype . hasOwnProperty ( prop ) && indexOf ( dontDelegate , prop ) < 0 )
{ CodeMirror$1 . prototype [ prop ] = ( function ( method ) {
return function ( ) { return method . apply ( this . doc , arguments ) }
} ) ( Doc . prototype [ prop ] ) ; } }
eventMixin ( Doc ) ;
// INPUT HANDLING
CodeMirror$1 . inputStyles = { "textarea" : TextareaInput , "contenteditable" : ContentEditableInput } ;
// MODE DEFINITION AND QUERYING
// Extra arguments are stored as the mode's dependencies, which is
// used by (legacy) mechanisms like loadmode.js to automatically
// load a mode. (Preferred mechanism is the require/define calls.)
CodeMirror$1 . defineMode = function ( name /*, mode, …*/ ) {
if ( ! CodeMirror$1 . defaults . mode && name != "null" ) { CodeMirror$1 . defaults . mode = name ; }
defineMode . apply ( this , arguments ) ;
} ;
CodeMirror$1 . defineMIME = defineMIME ;
// Minimal default mode.
CodeMirror$1 . defineMode ( "null" , function ( ) { return ( { token : function ( stream ) { return stream . skipToEnd ( ) ; } } ) ; } ) ;
CodeMirror$1 . defineMIME ( "text/plain" , "null" ) ;
// EXTENSIONS
CodeMirror$1 . defineExtension = function ( name , func ) {
CodeMirror$1 . prototype [ name ] = func ;
} ;
CodeMirror$1 . defineDocExtension = function ( name , func ) {
Doc . prototype [ name ] = func ;
} ;
CodeMirror$1 . fromTextArea = fromTextArea ;
addLegacyProps ( CodeMirror$1 ) ;
CodeMirror$1 . version = "5.26.0" ;
return CodeMirror$1 ;
} ) ) ) ;
} , { } ] , 11 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) , require ( "../markdown/markdown" ) , require ( "../../addon/mode/overlay" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" , "../markdown/markdown" , "../../addon/mode/overlay" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
var urlRE = /^((?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i
CodeMirror . defineMode ( "gfm" , function ( config , modeConfig ) {
var codeDepth = 0 ;
function blankLine ( state ) {
state . code = false ;
return null ;
}
var gfmOverlay = {
startState : function ( ) {
return {
code : false ,
codeBlock : false ,
ateSpace : false
} ;
} ,
copyState : function ( s ) {
return {
code : s . code ,
codeBlock : s . codeBlock ,
ateSpace : s . ateSpace
} ;
} ,
token : function ( stream , state ) {
state . combineTokens = null ;
// Hack to prevent formatting override inside code blocks (block and inline)
if ( state . codeBlock ) {
if ( stream . match ( /^```+/ ) ) {
state . codeBlock = false ;
return null ;
}
stream . skipToEnd ( ) ;
return null ;
}
if ( stream . sol ( ) ) {
state . code = false ;
}
if ( stream . sol ( ) && stream . match ( /^```+/ ) ) {
stream . skipToEnd ( ) ;
state . codeBlock = true ;
return null ;
}
// If this block is changed, it may need to be updated in Markdown mode
if ( stream . peek ( ) === '`' ) {
stream . next ( ) ;
var before = stream . pos ;
stream . eatWhile ( '`' ) ;
var difference = 1 + stream . pos - before ;
if ( ! state . code ) {
codeDepth = difference ;
state . code = true ;
} else {
if ( difference === codeDepth ) { // Must be exact
state . code = false ;
}
}
return null ;
} else if ( state . code ) {
stream . next ( ) ;
return null ;
}
// Check if space. If so, links can be formatted later on
if ( stream . eatSpace ( ) ) {
state . ateSpace = true ;
return null ;
}
if ( stream . sol ( ) || state . ateSpace ) {
state . ateSpace = false ;
if ( modeConfig . gitHubSpice !== false ) {
if ( stream . match ( /^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/ ) ) {
// User/Project@SHA
// User@SHA
// SHA
state . combineTokens = true ;
return "link" ;
} else if ( stream . match ( /^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/ ) ) {
// User/Project#Num
// User#Num
// #Num
state . combineTokens = true ;
return "link" ;
}
}
}
if ( stream . match ( urlRE ) &&
stream . string . slice ( stream . start - 2 , stream . start ) != "](" &&
( stream . start == 0 || /\W/ . test ( stream . string . charAt ( stream . start - 1 ) ) ) ) {
// URLs
// Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
// And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
// And then limited url schemes to the CommonMark list, so foo:bar isn't matched as a URL
state . combineTokens = true ;
return "link" ;
}
stream . next ( ) ;
return null ;
} ,
blankLine : blankLine
} ;
var markdownConfig = {
taskLists : true ,
fencedCodeBlocks : '```' ,
strikethrough : true
} ;
for ( var attr in modeConfig ) {
markdownConfig [ attr ] = modeConfig [ attr ] ;
}
markdownConfig . name = "markdown" ;
return CodeMirror . overlayMode ( CodeMirror . getMode ( config , markdownConfig ) , gfmOverlay ) ;
} , "markdown" ) ;
CodeMirror . defineMIME ( "text/x-gfm" , "gfm" ) ;
} ) ;
} , { "../../addon/mode/overlay" : 8 , "../../lib/codemirror" : 10 , "../markdown/markdown" : 12 } ] , 12 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) , require ( "../xml/xml" ) , require ( "../meta" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" , "../xml/xml" , "../meta" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
CodeMirror . defineMode ( "markdown" , function ( cmCfg , modeCfg ) {
var htmlMode = CodeMirror . getMode ( cmCfg , "text/html" ) ;
var htmlModeMissing = htmlMode . name == "null"
function getMode ( name ) {
if ( CodeMirror . findModeByName ) {
var found = CodeMirror . findModeByName ( name ) ;
if ( found ) name = found . mime || found . mimes [ 0 ] ;
}
var mode = CodeMirror . getMode ( cmCfg , name ) ;
return mode . name == "null" ? null : mode ;
}
// Should characters that affect highlighting be highlighted separate?
// Does not include characters that will be output (such as `1.` and `-` for lists)
if ( modeCfg . highlightFormatting === undefined )
modeCfg . highlightFormatting = false ;
// Maximum number of nested blockquotes. Set to 0 for infinite nesting.
// Excess `>` will emit `error` token.
if ( modeCfg . maxBlockquoteDepth === undefined )
modeCfg . maxBlockquoteDepth = 0 ;
// Use `fencedCodeBlocks` to configure fenced code blocks. false to
// disable, string to specify a precise regexp that the fence should
// match, and true to allow three or more backticks or tildes (as
// per CommonMark).
// Turn on task lists? ("- [ ] " and "- [x] ")
if ( modeCfg . taskLists === undefined ) modeCfg . taskLists = false ;
// Turn on strikethrough syntax
if ( modeCfg . strikethrough === undefined )
modeCfg . strikethrough = false ;
// Allow token types to be overridden by user-provided token types.
if ( modeCfg . tokenTypeOverrides === undefined )
modeCfg . tokenTypeOverrides = { } ;
var tokenTypes = {
header : "header" ,
code : "comment" ,
quote : "quote" ,
list1 : "variable-2" ,
list2 : "variable-3" ,
list3 : "keyword" ,
hr : "hr" ,
image : "image" ,
imageAltText : "image-alt-text" ,
imageMarker : "image-marker" ,
formatting : "formatting" ,
linkInline : "link" ,
linkEmail : "link" ,
linkText : "link" ,
linkHref : "string" ,
em : "em" ,
strong : "strong" ,
strikethrough : "strikethrough"
} ;
for ( var tokenType in tokenTypes ) {
if ( tokenTypes . hasOwnProperty ( tokenType ) && modeCfg . tokenTypeOverrides [ tokenType ] ) {
tokenTypes [ tokenType ] = modeCfg . tokenTypeOverrides [ tokenType ] ;
}
}
var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
, listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE
, atxHeaderRE = modeCfg . allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
, setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/
, fencedCodeRE = new RegExp ( "^(" + ( modeCfg . fencedCodeBlocks === true ? "~~~+|```+" : modeCfg . fencedCodeBlocks ) +
")[ \\t]*([\\w+#\-]*)" )
, punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/
function switchInline ( stream , state , f ) {
state . f = state . inline = f ;
return f ( stream , state ) ;
}
function switchBlock ( stream , state , f ) {
state . f = state . block = f ;
return f ( stream , state ) ;
}
function lineIsEmpty ( line ) {
return ! line || ! /\S/ . test ( line . string )
}
// Blocks
function blankLine ( state ) {
// Reset linkTitle state
state . linkTitle = false ;
// Reset EM state
state . em = false ;
// Reset STRONG state
state . strong = false ;
// Reset strikethrough state
state . strikethrough = false ;
// Reset state.quote
state . quote = 0 ;
// Reset state.indentedCode
state . indentedCode = false ;
if ( state . f == htmlBlock ) {
state . f = inlineNormal ;
state . block = blockNormal ;
}
// Reset state.trailingSpace
state . trailingSpace = 0 ;
state . trailingSpaceNewLine = false ;
// Mark this line as blank
state . prevLine = state . thisLine
state . thisLine = null
return null ;
}
function blockNormal ( stream , state ) {
var sol = stream . sol ( ) ;
var prevLineIsList = state . list !== false ,
prevLineIsIndentedCode = state . indentedCode ;
state . indentedCode = false ;
if ( prevLineIsList ) {
if ( state . indentationDiff >= 0 ) { // Continued list
if ( state . indentationDiff < 4 ) { // Only adjust indentation if *not* a code block
state . indentation -= state . indentationDiff ;
}
state . list = null ;
} else if ( state . indentation > 0 ) {
state . list = null ;
} else { // No longer a list
state . list = false ;
}
}
var match = null ;
if ( state . indentationDiff >= 4 ) {
stream . skipToEnd ( ) ;
if ( prevLineIsIndentedCode || lineIsEmpty ( state . prevLine ) ) {
state . indentation -= 4 ;
state . indentedCode = true ;
return tokenTypes . code ;
} else {
return null ;
}
} else if ( stream . eatSpace ( ) ) {
return null ;
} else if ( ( match = stream . match ( atxHeaderRE ) ) && match [ 1 ] . length <= 6 ) {
state . header = match [ 1 ] . length ;
if ( modeCfg . highlightFormatting ) state . formatting = "header" ;
state . f = state . inline ;
return getType ( state ) ;
} else if ( ! lineIsEmpty ( state . prevLine ) && ! state . quote && ! prevLineIsList &&
! prevLineIsIndentedCode && ( match = stream . match ( setextHeaderRE ) ) ) {
state . header = match [ 0 ] . charAt ( 0 ) == '=' ? 1 : 2 ;
if ( modeCfg . highlightFormatting ) state . formatting = "header" ;
state . f = state . inline ;
return getType ( state ) ;
} else if ( stream . eat ( '>' ) ) {
state . quote = sol ? 1 : state . quote + 1 ;
if ( modeCfg . highlightFormatting ) state . formatting = "quote" ;
stream . eatSpace ( ) ;
return getType ( state ) ;
} else if ( stream . peek ( ) === '[' ) {
return switchInline ( stream , state , footnoteLink ) ;
} else if ( stream . match ( hrRE , true ) ) {
state . hr = true ;
return tokenTypes . hr ;
} else if ( match = stream . match ( listRE ) ) {
var listType = match [ 1 ] ? "ol" : "ul" ;
state . indentation = stream . column ( ) + stream . current ( ) . length ;
state . list = true ;
// While this list item's marker's indentation
// is less than the deepest list item's content's indentation,
// pop the deepest list item indentation off the stack.
while ( state . listStack && stream . column ( ) < state . listStack [ state . listStack . length - 1 ] ) {
state . listStack . pop ( ) ;
}
// Add this list item's content's indentation to the stack
state . listStack . push ( state . indentation ) ;
if ( modeCfg . taskLists && stream . match ( taskListRE , false ) ) {
state . taskList = true ;
}
state . f = state . inline ;
if ( modeCfg . highlightFormatting ) state . formatting = [ "list" , "list-" + listType ] ;
return getType ( state ) ;
} else if ( modeCfg . fencedCodeBlocks && ( match = stream . match ( fencedCodeRE , true ) ) ) {
state . fencedChars = match [ 1 ]
// try switching mode
state . localMode = getMode ( match [ 2 ] ) ;
if ( state . localMode ) state . localState = CodeMirror . startState ( state . localMode ) ;
state . f = state . block = local ;
if ( modeCfg . highlightFormatting ) state . formatting = "code-block" ;
state . code = - 1
return getType ( state ) ;
}
return switchInline ( stream , state , state . inline ) ;
}
function htmlBlock ( stream , state ) {
var style = htmlMode . token ( stream , state . htmlState ) ;
if ( ! htmlModeMissing ) {
var inner = CodeMirror . innerMode ( htmlMode , state . htmlState )
if ( ( inner . mode . name == "xml" && inner . state . tagStart === null &&
( ! inner . state . context && inner . state . tokenize . isInText ) ) ||
( state . md _inside && stream . current ( ) . indexOf ( ">" ) > - 1 ) ) {
state . f = inlineNormal ;
state . block = blockNormal ;
state . htmlState = null ;
}
}
return style ;
}
function local ( stream , state ) {
if ( state . fencedChars && stream . match ( state . fencedChars ) ) {
if ( modeCfg . highlightFormatting ) state . formatting = "code-block" ;
var returnType = getType ( state )
state . localMode = state . localState = null ;
state . block = blockNormal ;
state . f = inlineNormal ;
state . fencedChars = null ;
state . code = 0
return returnType ;
} else if ( state . fencedChars && stream . skipTo ( state . fencedChars ) ) {
return "comment"
} else if ( state . localMode ) {
return state . localMode . token ( stream , state . localState ) ;
} else {
stream . skipToEnd ( ) ;
return tokenTypes . code ;
}
}
// Inline
function getType ( state ) {
var styles = [ ] ;
if ( state . formatting ) {
styles . push ( tokenTypes . formatting ) ;
if ( typeof state . formatting === "string" ) state . formatting = [ state . formatting ] ;
for ( var i = 0 ; i < state . formatting . length ; i ++ ) {
styles . push ( tokenTypes . formatting + "-" + state . formatting [ i ] ) ;
if ( state . formatting [ i ] === "header" ) {
styles . push ( tokenTypes . formatting + "-" + state . formatting [ i ] + "-" + state . header ) ;
}
// Add `formatting-quote` and `formatting-quote-#` for blockquotes
// Add `error` instead if the maximum blockquote nesting depth is passed
if ( state . formatting [ i ] === "quote" ) {
if ( ! modeCfg . maxBlockquoteDepth || modeCfg . maxBlockquoteDepth >= state . quote ) {
styles . push ( tokenTypes . formatting + "-" + state . formatting [ i ] + "-" + state . quote ) ;
} else {
styles . push ( "error" ) ;
}
}
}
}
if ( state . taskOpen ) {
styles . push ( "meta" ) ;
return styles . length ? styles . join ( ' ' ) : null ;
}
if ( state . taskClosed ) {
styles . push ( "property" ) ;
return styles . length ? styles . join ( ' ' ) : null ;
}
if ( state . linkHref ) {
styles . push ( tokenTypes . linkHref , "url" ) ;
} else { // Only apply inline styles to non-url text
if ( state . strong ) { styles . push ( tokenTypes . strong ) ; }
if ( state . em ) { styles . push ( tokenTypes . em ) ; }
if ( state . strikethrough ) { styles . push ( tokenTypes . strikethrough ) ; }
if ( state . linkText ) { styles . push ( tokenTypes . linkText ) ; }
if ( state . code ) { styles . push ( tokenTypes . code ) ; }
if ( state . image ) { styles . push ( tokenTypes . image ) ; }
if ( state . imageAltText ) { styles . push ( tokenTypes . imageAltText , "link" ) ; }
if ( state . imageMarker ) { styles . push ( tokenTypes . imageMarker ) ; }
}
if ( state . header ) { styles . push ( tokenTypes . header , tokenTypes . header + "-" + state . header ) ; }
if ( state . quote ) {
styles . push ( tokenTypes . quote ) ;
// Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
if ( ! modeCfg . maxBlockquoteDepth || modeCfg . maxBlockquoteDepth >= state . quote ) {
styles . push ( tokenTypes . quote + "-" + state . quote ) ;
} else {
styles . push ( tokenTypes . quote + "-" + modeCfg . maxBlockquoteDepth ) ;
}
}
if ( state . list !== false ) {
var listMod = ( state . listStack . length - 1 ) % 3 ;
if ( ! listMod ) {
styles . push ( tokenTypes . list1 ) ;
} else if ( listMod === 1 ) {
styles . push ( tokenTypes . list2 ) ;
} else {
styles . push ( tokenTypes . list3 ) ;
}
}
if ( state . trailingSpaceNewLine ) {
styles . push ( "trailing-space-new-line" ) ;
} else if ( state . trailingSpace ) {
styles . push ( "trailing-space-" + ( state . trailingSpace % 2 ? "a" : "b" ) ) ;
}
return styles . length ? styles . join ( ' ' ) : null ;
}
function handleText ( stream , state ) {
if ( stream . match ( textRE , true ) ) {
return getType ( state ) ;
}
return undefined ;
}
function inlineNormal ( stream , state ) {
var style = state . text ( stream , state ) ;
if ( typeof style !== 'undefined' )
return style ;
if ( state . list ) { // List marker (*, +, -, 1., etc)
state . list = null ;
return getType ( state ) ;
}
if ( state . taskList ) {
var taskOpen = stream . match ( taskListRE , true ) [ 1 ] !== "x" ;
if ( taskOpen ) state . taskOpen = true ;
else state . taskClosed = true ;
if ( modeCfg . highlightFormatting ) state . formatting = "task" ;
state . taskList = false ;
return getType ( state ) ;
}
state . taskOpen = false ;
state . taskClosed = false ;
if ( state . header && stream . match ( /^#+$/ , true ) ) {
if ( modeCfg . highlightFormatting ) state . formatting = "header" ;
return getType ( state ) ;
}
var ch = stream . next ( ) ;
// Matches link titles present on next line
if ( state . linkTitle ) {
state . linkTitle = false ;
var matchCh = ch ;
if ( ch === '(' ) {
matchCh = ')' ;
}
matchCh = ( matchCh + '' ) . replace ( /([.?*+^\[\]\\(){}|-])/g , "\\$1" ) ;
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh ;
if ( stream . match ( new RegExp ( regex ) , true ) ) {
return tokenTypes . linkHref ;
}
}
// If this block is changed, it may need to be updated in GFM mode
if ( ch === '`' ) {
var previousFormatting = state . formatting ;
if ( modeCfg . highlightFormatting ) state . formatting = "code" ;
stream . eatWhile ( '`' ) ;
var count = stream . current ( ) . length
if ( state . code == 0 ) {
state . code = count
return getType ( state )
} else if ( count == state . code ) { // Must be exact
var t = getType ( state )
state . code = 0
return t
} else {
state . formatting = previousFormatting
return getType ( state )
}
} else if ( state . code ) {
return getType ( state ) ;
}
if ( ch === '\\' ) {
stream . next ( ) ;
if ( modeCfg . highlightFormatting ) {
var type = getType ( state ) ;
var formattingEscape = tokenTypes . formatting + "-escape" ;
return type ? type + " " + formattingEscape : formattingEscape ;
}
}
if ( ch === '!' && stream . match ( /\[[^\]]*\] ?(?:\(|\[)/ , false ) ) {
state . imageMarker = true ;
state . image = true ;
if ( modeCfg . highlightFormatting ) state . formatting = "image" ;
return getType ( state ) ;
}
if ( ch === '[' && state . imageMarker && stream . match ( /[^\]]*\](\(.*?\)| ?\[.*?\])/ , false ) ) {
state . imageMarker = false ;
state . imageAltText = true
if ( modeCfg . highlightFormatting ) state . formatting = "image" ;
return getType ( state ) ;
}
if ( ch === ']' && state . imageAltText ) {
if ( modeCfg . highlightFormatting ) state . formatting = "image" ;
var type = getType ( state ) ;
state . imageAltText = false ;
state . image = false ;
state . inline = state . f = linkHref ;
return type ;
}
if ( ch === '[' && ! state . image ) {
state . linkText = true ;
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
return getType ( state ) ;
}
if ( ch === ']' && state . linkText ) {
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
var type = getType ( state ) ;
state . linkText = false ;
state . inline = state . f = stream . match ( /\(.*?\)| ?\[.*?\]/ , false ) ? linkHref : inlineNormal
return type ;
}
if ( ch === '<' && stream . match ( /^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/ , false ) ) {
state . f = state . inline = linkInline ;
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
var type = getType ( state ) ;
if ( type ) {
type += " " ;
} else {
type = "" ;
}
return type + tokenTypes . linkInline ;
}
if ( ch === '<' && stream . match ( /^[^> \\]+@(?:[^\\>]|\\.)+>/ , false ) ) {
state . f = state . inline = linkInline ;
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
var type = getType ( state ) ;
if ( type ) {
type += " " ;
} else {
type = "" ;
}
return type + tokenTypes . linkEmail ;
}
if ( ch === '<' && stream . match ( /^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i , false ) ) {
var end = stream . string . indexOf ( ">" , stream . pos ) ;
if ( end != - 1 ) {
var atts = stream . string . substring ( stream . start , end ) ;
if ( /markdown\s*=\s*('|"){0,1}1('|"){0,1}/ . test ( atts ) ) state . md _inside = true ;
}
stream . backUp ( 1 ) ;
state . htmlState = CodeMirror . startState ( htmlMode ) ;
return switchBlock ( stream , state , htmlBlock ) ;
}
if ( ch === '<' && stream . match ( /^\/\w*?>/ ) ) {
state . md _inside = false ;
return "tag" ;
} else if ( ch === "*" || ch === "_" ) {
var len = 1 , before = stream . pos == 1 ? " " : stream . string . charAt ( stream . pos - 2 )
while ( len < 3 && stream . eat ( ch ) ) len ++
var after = stream . peek ( ) || " "
// See http://spec.commonmark.org/0.27/#emphasis-and-strong-emphasis
var leftFlanking = ! /\s/ . test ( after ) && ( ! punctuation . test ( after ) || /\s/ . test ( before ) || punctuation . test ( before ) )
var rightFlanking = ! /\s/ . test ( before ) && ( ! punctuation . test ( before ) || /\s/ . test ( after ) || punctuation . test ( after ) )
var setEm = null , setStrong = null
if ( len % 2 ) { // Em
if ( ! state . em && leftFlanking && ( ch === "*" || ! rightFlanking || punctuation . test ( before ) ) )
setEm = true
else if ( state . em == ch && rightFlanking && ( ch === "*" || ! leftFlanking || punctuation . test ( after ) ) )
setEm = false
}
if ( len > 1 ) { // Strong
if ( ! state . strong && leftFlanking && ( ch === "*" || ! rightFlanking || punctuation . test ( before ) ) )
setStrong = true
else if ( state . strong == ch && rightFlanking && ( ch === "*" || ! leftFlanking || punctuation . test ( after ) ) )
setStrong = false
}
if ( setStrong != null || setEm != null ) {
if ( modeCfg . highlightFormatting ) state . formatting = setEm == null ? "strong" : setStrong == null ? "em" : "strong em"
if ( setEm === true ) state . em = ch
if ( setStrong === true ) state . strong = ch
var t = getType ( state )
if ( setEm === false ) state . em = false
if ( setStrong === false ) state . strong = false
return t
}
} else if ( ch === ' ' ) {
if ( stream . eat ( '*' ) || stream . eat ( '_' ) ) { // Probably surrounded by spaces
if ( stream . peek ( ) === ' ' ) { // Surrounded by spaces, ignore
return getType ( state ) ;
} else { // Not surrounded by spaces, back up pointer
stream . backUp ( 1 ) ;
}
}
}
if ( modeCfg . strikethrough ) {
if ( ch === '~' && stream . eatWhile ( ch ) ) {
if ( state . strikethrough ) { // Remove strikethrough
if ( modeCfg . highlightFormatting ) state . formatting = "strikethrough" ;
var t = getType ( state ) ;
state . strikethrough = false ;
return t ;
} else if ( stream . match ( /^[^\s]/ , false ) ) { // Add strikethrough
state . strikethrough = true ;
if ( modeCfg . highlightFormatting ) state . formatting = "strikethrough" ;
return getType ( state ) ;
}
} else if ( ch === ' ' ) {
if ( stream . match ( /^~~/ , true ) ) { // Probably surrounded by space
if ( stream . peek ( ) === ' ' ) { // Surrounded by spaces, ignore
return getType ( state ) ;
} else { // Not surrounded by spaces, back up pointer
stream . backUp ( 2 ) ;
}
}
}
}
if ( ch === ' ' ) {
if ( stream . match ( / +$/ , false ) ) {
state . trailingSpace ++ ;
} else if ( state . trailingSpace ) {
state . trailingSpaceNewLine = true ;
}
}
return getType ( state ) ;
}
function linkInline ( stream , state ) {
var ch = stream . next ( ) ;
if ( ch === ">" ) {
state . f = state . inline = inlineNormal ;
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
var type = getType ( state ) ;
if ( type ) {
type += " " ;
} else {
type = "" ;
}
return type + tokenTypes . linkInline ;
}
stream . match ( /^[^>]+/ , true ) ;
return tokenTypes . linkInline ;
}
function linkHref ( stream , state ) {
// Check if space, and return NULL if so (to avoid marking the space)
if ( stream . eatSpace ( ) ) {
return null ;
}
var ch = stream . next ( ) ;
if ( ch === '(' || ch === '[' ) {
state . f = state . inline = getLinkHrefInside ( ch === "(" ? ")" : "]" ) ;
if ( modeCfg . highlightFormatting ) state . formatting = "link-string" ;
state . linkHref = true ;
return getType ( state ) ;
}
return 'error' ;
}
var linkRE = {
")" : /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/ ,
"]" : /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\]]|\\.)*\])*?(?=\])/
}
function getLinkHrefInside ( endChar ) {
return function ( stream , state ) {
var ch = stream . next ( ) ;
if ( ch === endChar ) {
state . f = state . inline = inlineNormal ;
if ( modeCfg . highlightFormatting ) state . formatting = "link-string" ;
var returnState = getType ( state ) ;
state . linkHref = false ;
return returnState ;
}
stream . match ( linkRE [ endChar ] )
state . linkHref = true ;
return getType ( state ) ;
} ;
}
function footnoteLink ( stream , state ) {
if ( stream . match ( /^([^\]\\]|\\.)*\]:/ , false ) ) {
state . f = footnoteLinkInside ;
stream . next ( ) ; // Consume [
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
state . linkText = true ;
return getType ( state ) ;
}
return switchInline ( stream , state , inlineNormal ) ;
}
function footnoteLinkInside ( stream , state ) {
if ( stream . match ( /^\]:/ , true ) ) {
state . f = state . inline = footnoteUrl ;
if ( modeCfg . highlightFormatting ) state . formatting = "link" ;
var returnType = getType ( state ) ;
state . linkText = false ;
return returnType ;
}
stream . match ( /^([^\]\\]|\\.)+/ , true ) ;
return tokenTypes . linkText ;
}
function footnoteUrl ( stream , state ) {
// Check if space, and return NULL if so (to avoid marking the space)
if ( stream . eatSpace ( ) ) {
return null ;
}
// Match URL
stream . match ( /^[^\s]+/ , true ) ;
// Check for link title
if ( stream . peek ( ) === undefined ) { // End of line, set flag to check next line
state . linkTitle = true ;
} else { // More content on line, check if link title
stream . match ( /^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/ , true ) ;
}
state . f = state . inline = inlineNormal ;
return tokenTypes . linkHref + " url" ;
}
var mode = {
startState : function ( ) {
return {
f : blockNormal ,
prevLine : null ,
thisLine : null ,
block : blockNormal ,
htmlState : null ,
indentation : 0 ,
inline : inlineNormal ,
text : handleText ,
formatting : false ,
linkText : false ,
linkHref : false ,
linkTitle : false ,
code : 0 ,
em : false ,
strong : false ,
header : 0 ,
hr : false ,
taskList : false ,
list : false ,
listStack : [ ] ,
quote : 0 ,
trailingSpace : 0 ,
trailingSpaceNewLine : false ,
strikethrough : false ,
fencedChars : null
} ;
} ,
copyState : function ( s ) {
return {
f : s . f ,
prevLine : s . prevLine ,
thisLine : s . thisLine ,
block : s . block ,
htmlState : s . htmlState && CodeMirror . copyState ( htmlMode , s . htmlState ) ,
indentation : s . indentation ,
localMode : s . localMode ,
localState : s . localMode ? CodeMirror . copyState ( s . localMode , s . localState ) : null ,
inline : s . inline ,
text : s . text ,
formatting : false ,
linkText : s . linkText ,
linkTitle : s . linkTitle ,
code : s . code ,
em : s . em ,
strong : s . strong ,
strikethrough : s . strikethrough ,
header : s . header ,
hr : s . hr ,
taskList : s . taskList ,
list : s . list ,
listStack : s . listStack . slice ( 0 ) ,
quote : s . quote ,
indentedCode : s . indentedCode ,
trailingSpace : s . trailingSpace ,
trailingSpaceNewLine : s . trailingSpaceNewLine ,
md _inside : s . md _inside ,
fencedChars : s . fencedChars
} ;
} ,
token : function ( stream , state ) {
// Reset state.formatting
state . formatting = false ;
if ( stream != state . thisLine ) {
var forceBlankLine = state . header || state . hr ;
// Reset state.header and state.hr
state . header = 0 ;
state . hr = false ;
if ( stream . match ( /^\s*$/ , true ) || forceBlankLine ) {
blankLine ( state ) ;
if ( ! forceBlankLine ) return null
state . prevLine = null
}
state . prevLine = state . thisLine
state . thisLine = stream
// Reset state.taskList
state . taskList = false ;
// Reset state.trailingSpace
state . trailingSpace = 0 ;
state . trailingSpaceNewLine = false ;
state . f = state . block ;
var indentation = stream . match ( /^\s*/ , true ) [ 0 ] . replace ( /\t/g , ' ' ) . length ;
state . indentationDiff = Math . min ( indentation - state . indentation , 4 ) ;
state . indentation = state . indentation + state . indentationDiff ;
if ( indentation > 0 ) return null ;
}
return state . f ( stream , state ) ;
} ,
innerMode : function ( state ) {
if ( state . block == htmlBlock ) return { state : state . htmlState , mode : htmlMode } ;
if ( state . localState ) return { state : state . localState , mode : state . localMode } ;
return { state : state , mode : mode } ;
} ,
blankLine : blankLine ,
getType : getType ,
closeBrackets : "()[]{}''\"\"``" ,
fold : "markdown"
} ;
return mode ;
} , "xml" ) ;
CodeMirror . defineMIME ( "text/x-markdown" , "markdown" ) ;
} ) ;
} , { "../../lib/codemirror" : 10 , "../meta" : 13 , "../xml/xml" : 14 } ] , 13 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
CodeMirror . modeInfo = [
{ name : "APL" , mime : "text/apl" , mode : "apl" , ext : [ "dyalog" , "apl" ] } ,
{ name : "PGP" , mimes : [ "application/pgp" , "application/pgp-keys" , "application/pgp-signature" ] , mode : "asciiarmor" , ext : [ "pgp" ] } ,
{ name : "ASN.1" , mime : "text/x-ttcn-asn" , mode : "asn.1" , ext : [ "asn" , "asn1" ] } ,
{ name : "Asterisk" , mime : "text/x-asterisk" , mode : "asterisk" , file : /^extensions\.conf$/i } ,
{ name : "Brainfuck" , mime : "text/x-brainfuck" , mode : "brainfuck" , ext : [ "b" , "bf" ] } ,
{ name : "C" , mime : "text/x-csrc" , mode : "clike" , ext : [ "c" , "h" ] } ,
{ name : "C++" , mime : "text/x-c++src" , mode : "clike" , ext : [ "cpp" , "c++" , "cc" , "cxx" , "hpp" , "h++" , "hh" , "hxx" ] , alias : [ "cpp" ] } ,
{ name : "Cobol" , mime : "text/x-cobol" , mode : "cobol" , ext : [ "cob" , "cpy" ] } ,
{ name : "C#" , mime : "text/x-csharp" , mode : "clike" , ext : [ "cs" ] , alias : [ "csharp" ] } ,
{ name : "Clojure" , mime : "text/x-clojure" , mode : "clojure" , ext : [ "clj" , "cljc" , "cljx" ] } ,
{ name : "ClojureScript" , mime : "text/x-clojurescript" , mode : "clojure" , ext : [ "cljs" ] } ,
{ name : "Closure Stylesheets (GSS)" , mime : "text/x-gss" , mode : "css" , ext : [ "gss" ] } ,
{ name : "CMake" , mime : "text/x-cmake" , mode : "cmake" , ext : [ "cmake" , "cmake.in" ] , file : /^CMakeLists.txt$/ } ,
{ name : "CoffeeScript" , mime : "text/x-coffeescript" , mode : "coffeescript" , ext : [ "coffee" ] , alias : [ "coffee" , "coffee-script" ] } ,
{ name : "Common Lisp" , mime : "text/x-common-lisp" , mode : "commonlisp" , ext : [ "cl" , "lisp" , "el" ] , alias : [ "lisp" ] } ,
{ name : "Cypher" , mime : "application/x-cypher-query" , mode : "cypher" , ext : [ "cyp" , "cypher" ] } ,
{ name : "Cython" , mime : "text/x-cython" , mode : "python" , ext : [ "pyx" , "pxd" , "pxi" ] } ,
{ name : "Crystal" , mime : "text/x-crystal" , mode : "crystal" , ext : [ "cr" ] } ,
{ name : "CSS" , mime : "text/css" , mode : "css" , ext : [ "css" ] } ,
{ name : "CQL" , mime : "text/x-cassandra" , mode : "sql" , ext : [ "cql" ] } ,
{ name : "D" , mime : "text/x-d" , mode : "d" , ext : [ "d" ] } ,
{ name : "Dart" , mimes : [ "application/dart" , "text/x-dart" ] , mode : "dart" , ext : [ "dart" ] } ,
{ name : "diff" , mime : "text/x-diff" , mode : "diff" , ext : [ "diff" , "patch" ] } ,
{ name : "Django" , mime : "text/x-django" , mode : "django" } ,
{ name : "Dockerfile" , mime : "text/x-dockerfile" , mode : "dockerfile" , file : /^Dockerfile$/ } ,
{ name : "DTD" , mime : "application/xml-dtd" , mode : "dtd" , ext : [ "dtd" ] } ,
{ name : "Dylan" , mime : "text/x-dylan" , mode : "dylan" , ext : [ "dylan" , "dyl" , "intr" ] } ,
{ name : "EBNF" , mime : "text/x-ebnf" , mode : "ebnf" } ,
{ name : "ECL" , mime : "text/x-ecl" , mode : "ecl" , ext : [ "ecl" ] } ,
{ name : "edn" , mime : "application/edn" , mode : "clojure" , ext : [ "edn" ] } ,
{ name : "Eiffel" , mime : "text/x-eiffel" , mode : "eiffel" , ext : [ "e" ] } ,
{ name : "Elm" , mime : "text/x-elm" , mode : "elm" , ext : [ "elm" ] } ,
{ name : "Embedded Javascript" , mime : "application/x-ejs" , mode : "htmlembedded" , ext : [ "ejs" ] } ,
{ name : "Embedded Ruby" , mime : "application/x-erb" , mode : "htmlembedded" , ext : [ "erb" ] } ,
{ name : "Erlang" , mime : "text/x-erlang" , mode : "erlang" , ext : [ "erl" ] } ,
{ name : "Factor" , mime : "text/x-factor" , mode : "factor" , ext : [ "factor" ] } ,
{ name : "FCL" , mime : "text/x-fcl" , mode : "fcl" } ,
{ name : "Forth" , mime : "text/x-forth" , mode : "forth" , ext : [ "forth" , "fth" , "4th" ] } ,
{ name : "Fortran" , mime : "text/x-fortran" , mode : "fortran" , ext : [ "f" , "for" , "f77" , "f90" ] } ,
{ name : "F#" , mime : "text/x-fsharp" , mode : "mllike" , ext : [ "fs" ] , alias : [ "fsharp" ] } ,
{ name : "Gas" , mime : "text/x-gas" , mode : "gas" , ext : [ "s" ] } ,
{ name : "Gherkin" , mime : "text/x-feature" , mode : "gherkin" , ext : [ "feature" ] } ,
{ name : "GitHub Flavored Markdown" , mime : "text/x-gfm" , mode : "gfm" , file : /^(readme|contributing|history).md$/i } ,
{ name : "Go" , mime : "text/x-go" , mode : "go" , ext : [ "go" ] } ,
{ name : "Groovy" , mime : "text/x-groovy" , mode : "groovy" , ext : [ "groovy" , "gradle" ] , file : /^Jenkinsfile$/ } ,
{ name : "HAML" , mime : "text/x-haml" , mode : "haml" , ext : [ "haml" ] } ,
{ name : "Haskell" , mime : "text/x-haskell" , mode : "haskell" , ext : [ "hs" ] } ,
{ name : "Haskell (Literate)" , mime : "text/x-literate-haskell" , mode : "haskell-literate" , ext : [ "lhs" ] } ,
{ name : "Haxe" , mime : "text/x-haxe" , mode : "haxe" , ext : [ "hx" ] } ,
{ name : "HXML" , mime : "text/x-hxml" , mode : "haxe" , ext : [ "hxml" ] } ,
{ name : "ASP.NET" , mime : "application/x-aspx" , mode : "htmlembedded" , ext : [ "aspx" ] , alias : [ "asp" , "aspx" ] } ,
{ name : "HTML" , mime : "text/html" , mode : "htmlmixed" , ext : [ "html" , "htm" ] , alias : [ "xhtml" ] } ,
{ name : "HTTP" , mime : "message/http" , mode : "http" } ,
{ name : "IDL" , mime : "text/x-idl" , mode : "idl" , ext : [ "pro" ] } ,
{ name : "Pug" , mime : "text/x-pug" , mode : "pug" , ext : [ "jade" , "pug" ] , alias : [ "jade" ] } ,
{ name : "Java" , mime : "text/x-java" , mode : "clike" , ext : [ "java" ] } ,
{ name : "Java Server Pages" , mime : "application/x-jsp" , mode : "htmlembedded" , ext : [ "jsp" ] , alias : [ "jsp" ] } ,
{ name : "JavaScript" , mimes : [ "text/javascript" , "text/ecmascript" , "application/javascript" , "application/x-javascript" , "application/ecmascript" ] ,
mode : "javascript" , ext : [ "js" ] , alias : [ "ecmascript" , "js" , "node" ] } ,
{ name : "JSON" , mimes : [ "application/json" , "application/x-json" ] , mode : "javascript" , ext : [ "json" , "map" ] , alias : [ "json5" ] } ,
{ name : "JSON-LD" , mime : "application/ld+json" , mode : "javascript" , ext : [ "jsonld" ] , alias : [ "jsonld" ] } ,
{ name : "JSX" , mime : "text/jsx" , mode : "jsx" , ext : [ "jsx" ] } ,
{ name : "Jinja2" , mime : "null" , mode : "jinja2" } ,
{ name : "Julia" , mime : "text/x-julia" , mode : "julia" , ext : [ "jl" ] } ,
{ name : "Kotlin" , mime : "text/x-kotlin" , mode : "clike" , ext : [ "kt" ] } ,
{ name : "LESS" , mime : "text/x-less" , mode : "css" , ext : [ "less" ] } ,
{ name : "LiveScript" , mime : "text/x-livescript" , mode : "livescript" , ext : [ "ls" ] , alias : [ "ls" ] } ,
{ name : "Lua" , mime : "text/x-lua" , mode : "lua" , ext : [ "lua" ] } ,
{ name : "Markdown" , mime : "text/x-markdown" , mode : "markdown" , ext : [ "markdown" , "md" , "mkd" ] } ,
{ name : "mIRC" , mime : "text/mirc" , mode : "mirc" } ,
{ name : "MariaDB SQL" , mime : "text/x-mariadb" , mode : "sql" } ,
{ name : "Mathematica" , mime : "text/x-mathematica" , mode : "mathematica" , ext : [ "m" , "nb" ] } ,
{ name : "Modelica" , mime : "text/x-modelica" , mode : "modelica" , ext : [ "mo" ] } ,
{ name : "MUMPS" , mime : "text/x-mumps" , mode : "mumps" , ext : [ "mps" ] } ,
{ name : "MS SQL" , mime : "text/x-mssql" , mode : "sql" } ,
{ name : "mbox" , mime : "application/mbox" , mode : "mbox" , ext : [ "mbox" ] } ,
{ name : "MySQL" , mime : "text/x-mysql" , mode : "sql" } ,
{ name : "Nginx" , mime : "text/x-nginx-conf" , mode : "nginx" , file : /nginx.*\.conf$/i } ,
{ name : "NSIS" , mime : "text/x-nsis" , mode : "nsis" , ext : [ "nsh" , "nsi" ] } ,
{ name : "NTriples" , mime : "text/n-triples" , mode : "ntriples" , ext : [ "nt" ] } ,
{ name : "Objective C" , mime : "text/x-objectivec" , mode : "clike" , ext : [ "m" , "mm" ] , alias : [ "objective-c" , "objc" ] } ,
{ name : "OCaml" , mime : "text/x-ocaml" , mode : "mllike" , ext : [ "ml" , "mli" , "mll" , "mly" ] } ,
{ name : "Octave" , mime : "text/x-octave" , mode : "octave" , ext : [ "m" ] } ,
{ name : "Oz" , mime : "text/x-oz" , mode : "oz" , ext : [ "oz" ] } ,
{ name : "Pascal" , mime : "text/x-pascal" , mode : "pascal" , ext : [ "p" , "pas" ] } ,
{ name : "PEG.js" , mime : "null" , mode : "pegjs" , ext : [ "jsonld" ] } ,
{ name : "Perl" , mime : "text/x-perl" , mode : "perl" , ext : [ "pl" , "pm" ] } ,
{ name : "PHP" , mime : "application/x-httpd-php" , mode : "php" , ext : [ "php" , "php3" , "php4" , "php5" , "phtml" ] } ,
{ name : "Pig" , mime : "text/x-pig" , mode : "pig" , ext : [ "pig" ] } ,
{ name : "Plain Text" , mime : "text/plain" , mode : "null" , ext : [ "txt" , "text" , "conf" , "def" , "list" , "log" ] } ,
{ name : "PLSQL" , mime : "text/x-plsql" , mode : "sql" , ext : [ "pls" ] } ,
{ name : "PowerShell" , mime : "application/x-powershell" , mode : "powershell" , ext : [ "ps1" , "psd1" , "psm1" ] } ,
{ name : "Properties files" , mime : "text/x-properties" , mode : "properties" , ext : [ "properties" , "ini" , "in" ] , alias : [ "ini" , "properties" ] } ,
{ name : "ProtoBuf" , mime : "text/x-protobuf" , mode : "protobuf" , ext : [ "proto" ] } ,
{ name : "Python" , mime : "text/x-python" , mode : "python" , ext : [ "BUILD" , "bzl" , "py" , "pyw" ] , file : /^(BUCK|BUILD)$/ } ,
{ name : "Puppet" , mime : "text/x-puppet" , mode : "puppet" , ext : [ "pp" ] } ,
{ name : "Q" , mime : "text/x-q" , mode : "q" , ext : [ "q" ] } ,
{ name : "R" , mime : "text/x-rsrc" , mode : "r" , ext : [ "r" , "R" ] , alias : [ "rscript" ] } ,
{ name : "reStructuredText" , mime : "text/x-rst" , mode : "rst" , ext : [ "rst" ] , alias : [ "rst" ] } ,
{ name : "RPM Changes" , mime : "text/x-rpm-changes" , mode : "rpm" } ,
{ name : "RPM Spec" , mime : "text/x-rpm-spec" , mode : "rpm" , ext : [ "spec" ] } ,
{ name : "Ruby" , mime : "text/x-ruby" , mode : "ruby" , ext : [ "rb" ] , alias : [ "jruby" , "macruby" , "rake" , "rb" , "rbx" ] } ,
{ name : "Rust" , mime : "text/x-rustsrc" , mode : "rust" , ext : [ "rs" ] } ,
{ name : "SAS" , mime : "text/x-sas" , mode : "sas" , ext : [ "sas" ] } ,
{ name : "Sass" , mime : "text/x-sass" , mode : "sass" , ext : [ "sass" ] } ,
{ name : "Scala" , mime : "text/x-scala" , mode : "clike" , ext : [ "scala" ] } ,
{ name : "Scheme" , mime : "text/x-scheme" , mode : "scheme" , ext : [ "scm" , "ss" ] } ,
{ name : "SCSS" , mime : "text/x-scss" , mode : "css" , ext : [ "scss" ] } ,
{ name : "Shell" , mime : "text/x-sh" , mode : "shell" , ext : [ "sh" , "ksh" , "bash" ] , alias : [ "bash" , "sh" , "zsh" ] , file : /^PKGBUILD$/ } ,
{ name : "Sieve" , mime : "application/sieve" , mode : "sieve" , ext : [ "siv" , "sieve" ] } ,
{ name : "Slim" , mimes : [ "text/x-slim" , "application/x-slim" ] , mode : "slim" , ext : [ "slim" ] } ,
{ name : "Smalltalk" , mime : "text/x-stsrc" , mode : "smalltalk" , ext : [ "st" ] } ,
{ name : "Smarty" , mime : "text/x-smarty" , mode : "smarty" , ext : [ "tpl" ] } ,
{ name : "Solr" , mime : "text/x-solr" , mode : "solr" } ,
{ name : "Soy" , mime : "text/x-soy" , mode : "soy" , ext : [ "soy" ] , alias : [ "closure template" ] } ,
{ name : "SPARQL" , mime : "application/sparql-query" , mode : "sparql" , ext : [ "rq" , "sparql" ] , alias : [ "sparul" ] } ,
{ name : "Spreadsheet" , mime : "text/x-spreadsheet" , mode : "spreadsheet" , alias : [ "excel" , "formula" ] } ,
{ name : "SQL" , mime : "text/x-sql" , mode : "sql" , ext : [ "sql" ] } ,
{ name : "SQLite" , mime : "text/x-sqlite" , mode : "sql" } ,
{ name : "Squirrel" , mime : "text/x-squirrel" , mode : "clike" , ext : [ "nut" ] } ,
{ name : "Stylus" , mime : "text/x-styl" , mode : "stylus" , ext : [ "styl" ] } ,
{ name : "Swift" , mime : "text/x-swift" , mode : "swift" , ext : [ "swift" ] } ,
{ name : "sTeX" , mime : "text/x-stex" , mode : "stex" } ,
{ name : "LaTeX" , mime : "text/x-latex" , mode : "stex" , ext : [ "text" , "ltx" ] , alias : [ "tex" ] } ,
{ name : "SystemVerilog" , mime : "text/x-systemverilog" , mode : "verilog" , ext : [ "v" ] } ,
{ name : "Tcl" , mime : "text/x-tcl" , mode : "tcl" , ext : [ "tcl" ] } ,
{ name : "Textile" , mime : "text/x-textile" , mode : "textile" , ext : [ "textile" ] } ,
{ name : "TiddlyWiki " , mime : "text/x-tiddlywiki" , mode : "tiddlywiki" } ,
{ name : "Tiki wiki" , mime : "text/tiki" , mode : "tiki" } ,
{ name : "TOML" , mime : "text/x-toml" , mode : "toml" , ext : [ "toml" ] } ,
{ name : "Tornado" , mime : "text/x-tornado" , mode : "tornado" } ,
{ name : "troff" , mime : "text/troff" , mode : "troff" , ext : [ "1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" ] } ,
{ name : "TTCN" , mime : "text/x-ttcn" , mode : "ttcn" , ext : [ "ttcn" , "ttcn3" , "ttcnpp" ] } ,
{ name : "TTCN_CFG" , mime : "text/x-ttcn-cfg" , mode : "ttcn-cfg" , ext : [ "cfg" ] } ,
{ name : "Turtle" , mime : "text/turtle" , mode : "turtle" , ext : [ "ttl" ] } ,
{ name : "TypeScript" , mime : "application/typescript" , mode : "javascript" , ext : [ "ts" ] , alias : [ "ts" ] } ,
{ name : "TypeScript-JSX" , mime : "text/typescript-jsx" , mode : "jsx" , ext : [ "tsx" ] , alias : [ "tsx" ] } ,
{ name : "Twig" , mime : "text/x-twig" , mode : "twig" } ,
{ name : "Web IDL" , mime : "text/x-webidl" , mode : "webidl" , ext : [ "webidl" ] } ,
{ name : "VB.NET" , mime : "text/x-vb" , mode : "vb" , ext : [ "vb" ] } ,
{ name : "VBScript" , mime : "text/vbscript" , mode : "vbscript" , ext : [ "vbs" ] } ,
{ name : "Velocity" , mime : "text/velocity" , mode : "velocity" , ext : [ "vtl" ] } ,
{ name : "Verilog" , mime : "text/x-verilog" , mode : "verilog" , ext : [ "v" ] } ,
{ name : "VHDL" , mime : "text/x-vhdl" , mode : "vhdl" , ext : [ "vhd" , "vhdl" ] } ,
{ name : "Vue.js Component" , mimes : [ "script/x-vue" , "text/x-vue" ] , mode : "vue" , ext : [ "vue" ] } ,
{ name : "XML" , mimes : [ "application/xml" , "text/xml" ] , mode : "xml" , ext : [ "xml" , "xsl" , "xsd" , "svg" ] , alias : [ "rss" , "wsdl" , "xsd" ] } ,
{ name : "XQuery" , mime : "application/xquery" , mode : "xquery" , ext : [ "xy" , "xquery" ] } ,
{ name : "Yacas" , mime : "text/x-yacas" , mode : "yacas" , ext : [ "ys" ] } ,
{ name : "YAML" , mimes : [ "text/x-yaml" , "text/yaml" ] , mode : "yaml" , ext : [ "yaml" , "yml" ] , alias : [ "yml" ] } ,
{ name : "Z80" , mime : "text/x-z80" , mode : "z80" , ext : [ "z80" ] } ,
{ name : "mscgen" , mime : "text/x-mscgen" , mode : "mscgen" , ext : [ "mscgen" , "mscin" , "msc" ] } ,
{ name : "xu" , mime : "text/x-xu" , mode : "mscgen" , ext : [ "xu" ] } ,
{ name : "msgenny" , mime : "text/x-msgenny" , mode : "mscgen" , ext : [ "msgenny" ] }
] ;
// Ensure all modes have a mime property for backwards compatibility
for ( var i = 0 ; i < CodeMirror . modeInfo . length ; i ++ ) {
var info = CodeMirror . modeInfo [ i ] ;
if ( info . mimes ) info . mime = info . mimes [ 0 ] ;
}
CodeMirror . findModeByMIME = function ( mime ) {
mime = mime . toLowerCase ( ) ;
for ( var i = 0 ; i < CodeMirror . modeInfo . length ; i ++ ) {
var info = CodeMirror . modeInfo [ i ] ;
if ( info . mime == mime ) return info ;
if ( info . mimes ) for ( var j = 0 ; j < info . mimes . length ; j ++ )
if ( info . mimes [ j ] == mime ) return info ;
}
if ( /\+xml$/ . test ( mime ) ) return CodeMirror . findModeByMIME ( "application/xml" )
if ( /\+json$/ . test ( mime ) ) return CodeMirror . findModeByMIME ( "application/json" )
} ;
CodeMirror . findModeByExtension = function ( ext ) {
for ( var i = 0 ; i < CodeMirror . modeInfo . length ; i ++ ) {
var info = CodeMirror . modeInfo [ i ] ;
if ( info . ext ) for ( var j = 0 ; j < info . ext . length ; j ++ )
if ( info . ext [ j ] == ext ) return info ;
}
} ;
CodeMirror . findModeByFileName = function ( filename ) {
for ( var i = 0 ; i < CodeMirror . modeInfo . length ; i ++ ) {
var info = CodeMirror . modeInfo [ i ] ;
if ( info . file && info . file . test ( filename ) ) return info ;
}
var dot = filename . lastIndexOf ( "." ) ;
var ext = dot > - 1 && filename . substring ( dot + 1 , filename . length ) ;
if ( ext ) return CodeMirror . findModeByExtension ( ext ) ;
} ;
CodeMirror . findModeByName = function ( name ) {
name = name . toLowerCase ( ) ;
for ( var i = 0 ; i < CodeMirror . modeInfo . length ; i ++ ) {
var info = CodeMirror . modeInfo [ i ] ;
if ( info . name . toLowerCase ( ) == name ) return info ;
if ( info . alias ) for ( var j = 0 ; j < info . alias . length ; j ++ )
if ( info . alias [ j ] . toLowerCase ( ) == name ) return info ;
}
} ;
} ) ;
} , { "../lib/codemirror" : 10 } ] , 14 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
( function ( mod ) {
if ( typeof exports == "object" && typeof module == "object" ) // CommonJS
mod ( require ( "../../lib/codemirror" ) ) ;
else if ( typeof define == "function" && define . amd ) // AMD
define ( [ "../../lib/codemirror" ] , mod ) ;
else // Plain browser env
mod ( CodeMirror ) ;
} ) ( function ( CodeMirror ) {
"use strict" ;
var htmlConfig = {
autoSelfClosers : { 'area' : true , 'base' : true , 'br' : true , 'col' : true , 'command' : true ,
'embed' : true , 'frame' : true , 'hr' : true , 'img' : true , 'input' : true ,
'keygen' : true , 'link' : true , 'meta' : true , 'param' : true , 'source' : true ,
'track' : true , 'wbr' : true , 'menuitem' : true } ,
implicitlyClosed : { 'dd' : true , 'li' : true , 'optgroup' : true , 'option' : true , 'p' : true ,
'rp' : true , 'rt' : true , 'tbody' : true , 'td' : true , 'tfoot' : true ,
'th' : true , 'tr' : true } ,
contextGrabbers : {
'dd' : { 'dd' : true , 'dt' : true } ,
'dt' : { 'dd' : true , 'dt' : true } ,
'li' : { 'li' : true } ,
'option' : { 'option' : true , 'optgroup' : true } ,
'optgroup' : { 'optgroup' : true } ,
'p' : { 'address' : true , 'article' : true , 'aside' : true , 'blockquote' : true , 'dir' : true ,
'div' : true , 'dl' : true , 'fieldset' : true , 'footer' : true , 'form' : true ,
'h1' : true , 'h2' : true , 'h3' : true , 'h4' : true , 'h5' : true , 'h6' : true ,
'header' : true , 'hgroup' : true , 'hr' : true , 'menu' : true , 'nav' : true , 'ol' : true ,
'p' : true , 'pre' : true , 'section' : true , 'table' : true , 'ul' : true } ,
'rp' : { 'rp' : true , 'rt' : true } ,
'rt' : { 'rp' : true , 'rt' : true } ,
'tbody' : { 'tbody' : true , 'tfoot' : true } ,
'td' : { 'td' : true , 'th' : true } ,
'tfoot' : { 'tbody' : true } ,
'th' : { 'td' : true , 'th' : true } ,
'thead' : { 'tbody' : true , 'tfoot' : true } ,
'tr' : { 'tr' : true }
} ,
doNotIndent : { "pre" : true } ,
allowUnquoted : true ,
allowMissing : true ,
caseFold : true
}
var xmlConfig = {
autoSelfClosers : { } ,
implicitlyClosed : { } ,
contextGrabbers : { } ,
doNotIndent : { } ,
allowUnquoted : false ,
allowMissing : false ,
caseFold : false
}
CodeMirror . defineMode ( "xml" , function ( editorConf , config _ ) {
var indentUnit = editorConf . indentUnit
var config = { }
var defaults = config _ . htmlMode ? htmlConfig : xmlConfig
for ( var prop in defaults ) config [ prop ] = defaults [ prop ]
for ( var prop in config _ ) config [ prop ] = config _ [ prop ]
// Return variables for tokenizers
var type , setStyle ;
function inText ( stream , state ) {
function chain ( parser ) {
state . tokenize = parser ;
return parser ( stream , state ) ;
}
var ch = stream . next ( ) ;
if ( ch == "<" ) {
if ( stream . eat ( "!" ) ) {
if ( stream . eat ( "[" ) ) {
if ( stream . match ( "CDATA[" ) ) return chain ( inBlock ( "atom" , "]]>" ) ) ;
else return null ;
} else if ( stream . match ( "--" ) ) {
return chain ( inBlock ( "comment" , "-->" ) ) ;
} else if ( stream . match ( "DOCTYPE" , true , true ) ) {
stream . eatWhile ( /[\w\._\-]/ ) ;
return chain ( doctype ( 1 ) ) ;
} else {
return null ;
}
} else if ( stream . eat ( "?" ) ) {
stream . eatWhile ( /[\w\._\-]/ ) ;
state . tokenize = inBlock ( "meta" , "?>" ) ;
return "meta" ;
} else {
type = stream . eat ( "/" ) ? "closeTag" : "openTag" ;
state . tokenize = inTag ;
return "tag bracket" ;
}
} else if ( ch == "&" ) {
var ok ;
if ( stream . eat ( "#" ) ) {
if ( stream . eat ( "x" ) ) {
ok = stream . eatWhile ( /[a-fA-F\d]/ ) && stream . eat ( ";" ) ;
} else {
ok = stream . eatWhile ( /[\d]/ ) && stream . eat ( ";" ) ;
}
} else {
ok = stream . eatWhile ( /[\w\.\-:]/ ) && stream . eat ( ";" ) ;
}
return ok ? "atom" : "error" ;
} else {
stream . eatWhile ( /[^&<]/ ) ;
return null ;
}
}
inText . isInText = true ;
function inTag ( stream , state ) {
var ch = stream . next ( ) ;
if ( ch == ">" || ( ch == "/" && stream . eat ( ">" ) ) ) {
state . tokenize = inText ;
type = ch == ">" ? "endTag" : "selfcloseTag" ;
return "tag bracket" ;
} else if ( ch == "=" ) {
type = "equals" ;
return null ;
} else if ( ch == "<" ) {
state . tokenize = inText ;
state . state = baseState ;
state . tagName = state . tagStart = null ;
var next = state . tokenize ( stream , state ) ;
return next ? next + " tag error" : "tag error" ;
} else if ( /[\'\"]/ . test ( ch ) ) {
state . tokenize = inAttribute ( ch ) ;
state . stringStartCol = stream . column ( ) ;
return state . tokenize ( stream , state ) ;
} else {
stream . match ( /^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/ ) ;
return "word" ;
}
}
function inAttribute ( quote ) {
var closure = function ( stream , state ) {
while ( ! stream . eol ( ) ) {
if ( stream . next ( ) == quote ) {
state . tokenize = inTag ;
break ;
}
}
return "string" ;
} ;
closure . isInAttribute = true ;
return closure ;
}
function inBlock ( style , terminator ) {
return function ( stream , state ) {
while ( ! stream . eol ( ) ) {
if ( stream . match ( terminator ) ) {
state . tokenize = inText ;
break ;
}
stream . next ( ) ;
}
return style ;
} ;
}
function doctype ( depth ) {
return function ( stream , state ) {
var ch ;
while ( ( ch = stream . next ( ) ) != null ) {
if ( ch == "<" ) {
state . tokenize = doctype ( depth + 1 ) ;
return state . tokenize ( stream , state ) ;
} else if ( ch == ">" ) {
if ( depth == 1 ) {
state . tokenize = inText ;
break ;
} else {
state . tokenize = doctype ( depth - 1 ) ;
return state . tokenize ( stream , state ) ;
}
}
}
return "meta" ;
} ;
}
function Context ( state , tagName , startOfLine ) {
this . prev = state . context ;
this . tagName = tagName ;
this . indent = state . indented ;
this . startOfLine = startOfLine ;
if ( config . doNotIndent . hasOwnProperty ( tagName ) || ( state . context && state . context . noIndent ) )
this . noIndent = true ;
}
function popContext ( state ) {
if ( state . context ) state . context = state . context . prev ;
}
function maybePopContext ( state , nextTagName ) {
var parentTagName ;
while ( true ) {
if ( ! state . context ) {
return ;
}
parentTagName = state . context . tagName ;
if ( ! config . contextGrabbers . hasOwnProperty ( parentTagName ) ||
! config . contextGrabbers [ parentTagName ] . hasOwnProperty ( nextTagName ) ) {
return ;
}
popContext ( state ) ;
}
}
function baseState ( type , stream , state ) {
if ( type == "openTag" ) {
state . tagStart = stream . column ( ) ;
return tagNameState ;
} else if ( type == "closeTag" ) {
return closeTagNameState ;
} else {
return baseState ;
}
}
function tagNameState ( type , stream , state ) {
if ( type == "word" ) {
state . tagName = stream . current ( ) ;
setStyle = "tag" ;
return attrState ;
} else {
setStyle = "error" ;
return tagNameState ;
}
}
function closeTagNameState ( type , stream , state ) {
if ( type == "word" ) {
var tagName = stream . current ( ) ;
if ( state . context && state . context . tagName != tagName &&
config . implicitlyClosed . hasOwnProperty ( state . context . tagName ) )
popContext ( state ) ;
if ( ( state . context && state . context . tagName == tagName ) || config . matchClosing === false ) {
setStyle = "tag" ;
return closeState ;
} else {
setStyle = "tag error" ;
return closeStateErr ;
}
} else {
setStyle = "error" ;
return closeStateErr ;
}
}
function closeState ( type , _stream , state ) {
if ( type != "endTag" ) {
setStyle = "error" ;
return closeState ;
}
popContext ( state ) ;
return baseState ;
}
function closeStateErr ( type , stream , state ) {
setStyle = "error" ;
return closeState ( type , stream , state ) ;
}
function attrState ( type , _stream , state ) {
if ( type == "word" ) {
setStyle = "attribute" ;
return attrEqState ;
} else if ( type == "endTag" || type == "selfcloseTag" ) {
var tagName = state . tagName , tagStart = state . tagStart ;
state . tagName = state . tagStart = null ;
if ( type == "selfcloseTag" ||
config . autoSelfClosers . hasOwnProperty ( tagName ) ) {
maybePopContext ( state , tagName ) ;
} else {
maybePopContext ( state , tagName ) ;
state . context = new Context ( state , tagName , tagStart == state . indented ) ;
}
return baseState ;
}
setStyle = "error" ;
return attrState ;
}
function attrEqState ( type , stream , state ) {
if ( type == "equals" ) return attrValueState ;
if ( ! config . allowMissing ) setStyle = "error" ;
return attrState ( type , stream , state ) ;
}
function attrValueState ( type , stream , state ) {
if ( type == "string" ) return attrContinuedState ;
if ( type == "word" && config . allowUnquoted ) { setStyle = "string" ; return attrState ; }
setStyle = "error" ;
return attrState ( type , stream , state ) ;
}
function attrContinuedState ( type , stream , state ) {
if ( type == "string" ) return attrContinuedState ;
return attrState ( type , stream , state ) ;
}
return {
startState : function ( baseIndent ) {
var state = { tokenize : inText ,
state : baseState ,
indented : baseIndent || 0 ,
tagName : null , tagStart : null ,
context : null }
if ( baseIndent != null ) state . baseIndent = baseIndent
return state
} ,
token : function ( stream , state ) {
if ( ! state . tagName && stream . sol ( ) )
state . indented = stream . indentation ( ) ;
if ( stream . eatSpace ( ) ) return null ;
type = null ;
var style = state . tokenize ( stream , state ) ;
if ( ( style || type ) && style != "comment" ) {
setStyle = null ;
state . state = state . state ( type || style , stream , state ) ;
if ( setStyle )
style = setStyle == "error" ? style + " error" : setStyle ;
}
return style ;
} ,
indent : function ( state , textAfter , fullLine ) {
var context = state . context ;
// Indent multi-line strings (e.g. css).
if ( state . tokenize . isInAttribute ) {
if ( state . tagStart == state . indented )
return state . stringStartCol + 1 ;
else
return state . indented + indentUnit ;
}
if ( context && context . noIndent ) return CodeMirror . Pass ;
if ( state . tokenize != inTag && state . tokenize != inText )
return fullLine ? fullLine . match ( /^(\s*)/ ) [ 0 ] . length : 0 ;
// Indent the starts of attribute names.
if ( state . tagName ) {
if ( config . multilineTagIndentPastTag !== false )
return state . tagStart + state . tagName . length + 2 ;
else
return state . tagStart + indentUnit * ( config . multilineTagIndentFactor || 1 ) ;
}
if ( config . alignCDATA && /<!\[CDATA\[/ . test ( textAfter ) ) return 0 ;
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/ . exec ( textAfter ) ;
if ( tagAfter && tagAfter [ 1 ] ) { // Closing tag spotted
while ( context ) {
if ( context . tagName == tagAfter [ 2 ] ) {
context = context . prev ;
break ;
} else if ( config . implicitlyClosed . hasOwnProperty ( context . tagName ) ) {
context = context . prev ;
} else {
break ;
}
}
} else if ( tagAfter ) { // Opening tag spotted
while ( context ) {
var grabbers = config . contextGrabbers [ context . tagName ] ;
if ( grabbers && grabbers . hasOwnProperty ( tagAfter [ 2 ] ) )
context = context . prev ;
else
break ;
}
}
while ( context && context . prev && ! context . startOfLine )
context = context . prev ;
if ( context ) return context . indent + indentUnit ;
else return state . baseIndent || 0 ;
} ,
electricInput : /<\/[\s\w:]+>$/ ,
blockCommentStart : "<!--" ,
blockCommentEnd : "-->" ,
configuration : config . htmlMode ? "html" : "xml" ,
helperType : config . htmlMode ? "html" : "xml" ,
skipAttribute : function ( state ) {
if ( state . state == attrValueState )
state . state = attrState
}
} ;
} ) ;
CodeMirror . defineMIME ( "text/xml" , "xml" ) ;
CodeMirror . defineMIME ( "application/xml" , "xml" ) ;
if ( ! CodeMirror . mimeModes . hasOwnProperty ( "text/html" ) )
CodeMirror . defineMIME ( "text/html" , { name : "xml" , htmlMode : true } ) ;
} ) ;
} , { "../../lib/codemirror" : 10 } ] , 15 : [ function ( require , module , exports ) {
exports . read = function ( buffer , offset , isLE , mLen , nBytes ) {
var e , m
var eLen = nBytes * 8 - mLen - 1
var eMax = ( 1 << eLen ) - 1
var eBias = eMax >> 1
var nBits = - 7
var i = isLE ? ( nBytes - 1 ) : 0
var d = isLE ? - 1 : 1
var s = buffer [ offset + i ]
i += d
e = s & ( ( 1 << ( - nBits ) ) - 1 )
s >>= ( - nBits )
nBits += eLen
for ( ; nBits > 0 ; e = e * 256 + buffer [ offset + i ] , i += d , nBits -= 8 ) { }
m = e & ( ( 1 << ( - nBits ) ) - 1 )
e >>= ( - nBits )
nBits += mLen
for ( ; nBits > 0 ; m = m * 256 + buffer [ offset + i ] , i += d , nBits -= 8 ) { }
if ( e === 0 ) {
e = 1 - eBias
} else if ( e === eMax ) {
return m ? NaN : ( ( s ? - 1 : 1 ) * Infinity )
} else {
m = m + Math . pow ( 2 , mLen )
e = e - eBias
}
return ( s ? - 1 : 1 ) * m * Math . pow ( 2 , e - mLen )
}
exports . write = function ( buffer , value , offset , isLE , mLen , nBytes ) {
var e , m , c
var eLen = nBytes * 8 - mLen - 1
var eMax = ( 1 << eLen ) - 1
var eBias = eMax >> 1
var rt = ( mLen === 23 ? Math . pow ( 2 , - 24 ) - Math . pow ( 2 , - 77 ) : 0 )
var i = isLE ? 0 : ( nBytes - 1 )
var d = isLE ? 1 : - 1
var s = value < 0 || ( value === 0 && 1 / value < 0 ) ? 1 : 0
value = Math . abs ( value )
if ( isNaN ( value ) || value === Infinity ) {
m = isNaN ( value ) ? 1 : 0
e = eMax
} else {
e = Math . floor ( Math . log ( value ) / Math . LN2 )
if ( value * ( c = Math . pow ( 2 , - e ) ) < 1 ) {
e --
c *= 2
}
if ( e + eBias >= 1 ) {
value += rt / c
} else {
value += rt * Math . pow ( 2 , 1 - eBias )
}
if ( value * c >= 2 ) {
e ++
c /= 2
}
if ( e + eBias >= eMax ) {
m = 0
e = eMax
} else if ( e + eBias >= 1 ) {
m = ( value * c - 1 ) * Math . pow ( 2 , mLen )
e = e + eBias
} else {
m = value * Math . pow ( 2 , eBias - 1 ) * Math . pow ( 2 , mLen )
e = 0
}
}
for ( ; mLen >= 8 ; buffer [ offset + i ] = m & 0xff , i += d , m /= 256 , mLen -= 8 ) { }
e = ( e << mLen ) | m
eLen += mLen
for ( ; eLen > 0 ; buffer [ offset + i ] = e & 0xff , i += d , e /= 256 , eLen -= 8 ) { }
buffer [ offset + i - d ] |= s * 128
}
} , { } ] , 16 : [ function ( require , module , exports ) {
( function ( global ) {
/ * *
* marked - a markdown parser
* Copyright ( c ) 2011 - 2014 , Christopher Jeffrey . ( MIT Licensed )
* https : //github.com/chjj/marked
* /
; ( function ( ) {
/ * *
* Block - Level Grammar
* /
var block = {
newline : /^\n+/ ,
code : /^( {4}[^\n]+\n*)+/ ,
fences : noop ,
hr : /^( *[-*_]){3,} *(?:\n+|$)/ ,
heading : /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/ ,
nptable : noop ,
lheading : /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/ ,
blockquote : /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/ ,
list : /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/ ,
html : /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/ ,
def : /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/ ,
table : noop ,
paragraph : /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/ ,
text : /^[^\n]+/
} ;
block . bullet = /(?:[*+-]|\d+\.)/ ;
block . item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/ ;
block . item = replace ( block . item , 'gm' )
( /bull/g , block . bullet )
( ) ;
block . list = replace ( block . list )
( /bull/g , block . bullet )
( 'hr' , '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))' )
( 'def' , '\\n+(?=' + block . def . source + ')' )
( ) ;
block . blockquote = replace ( block . blockquote )
( 'def' , block . def )
( ) ;
block . _tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b' ;
block . html = replace ( block . html )
( 'comment' , /<!--[\s\S]*?-->/ )
( 'closed' , /<(tag)[\s\S]+?<\/\1>/ )
( 'closing' , /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/ )
( /tag/g , block . _tag )
( ) ;
block . paragraph = replace ( block . paragraph )
( 'hr' , block . hr )
( 'heading' , block . heading )
( 'lheading' , block . lheading )
( 'blockquote' , block . blockquote )
( 'tag' , '<' + block . _tag )
( 'def' , block . def )
( ) ;
/ * *
* Normal Block Grammar
* /
block . normal = merge ( { } , block ) ;
/ * *
* GFM Block Grammar
* /
block . gfm = merge ( { } , block . normal , {
fences : /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/ ,
paragraph : /^/ ,
heading : /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
} ) ;
block . gfm . paragraph = replace ( block . paragraph )
( '(?!' , '(?!'
+ block . gfm . fences . source . replace ( '\\1' , '\\2' ) + '|'
+ block . list . source . replace ( '\\1' , '\\3' ) + '|' )
( ) ;
/ * *
* GFM + Tables Block Grammar
* /
block . tables = merge ( { } , block . gfm , {
nptable : /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/ ,
table : /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
} ) ;
/ * *
* Block Lexer
* /
function Lexer ( options ) {
this . tokens = [ ] ;
this . tokens . links = { } ;
this . options = options || marked . defaults ;
this . rules = block . normal ;
if ( this . options . gfm ) {
if ( this . options . tables ) {
this . rules = block . tables ;
} else {
this . rules = block . gfm ;
}
}
}
/ * *
* Expose Block Rules
* /
Lexer . rules = block ;
/ * *
* Static Lex Method
* /
Lexer . lex = function ( src , options ) {
var lexer = new Lexer ( options ) ;
return lexer . lex ( src ) ;
} ;
/ * *
* Preprocessing
* /
Lexer . prototype . lex = function ( src ) {
src = src
. replace ( /\r\n|\r/g , '\n' )
. replace ( /\t/g , ' ' )
. replace ( /\u00a0/g , ' ' )
. replace ( /\u2424/g , '\n' ) ;
return this . token ( src , true ) ;
} ;
/ * *
* Lexing
* /
Lexer . prototype . token = function ( src , top , bq ) {
var src = src . replace ( /^ +$/gm , '' )
, next
, loose
, cap
, bull
, b
, item
, space
, i
, l ;
while ( src ) {
// newline
if ( cap = this . rules . newline . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
if ( cap [ 0 ] . length > 1 ) {
this . tokens . push ( {
type : 'space'
} ) ;
}
}
// code
if ( cap = this . rules . code . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
cap = cap [ 0 ] . replace ( /^ {4}/gm , '' ) ;
this . tokens . push ( {
type : 'code' ,
text : ! this . options . pedantic
? cap . replace ( /\n+$/ , '' )
: cap
} ) ;
continue ;
}
// fences (gfm)
if ( cap = this . rules . fences . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'code' ,
lang : cap [ 2 ] ,
text : cap [ 3 ] || ''
} ) ;
continue ;
}
// heading
if ( cap = this . rules . heading . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'heading' ,
depth : cap [ 1 ] . length ,
text : cap [ 2 ]
} ) ;
continue ;
}
// table no leading pipe (gfm)
if ( top && ( cap = this . rules . nptable . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
item = {
type : 'table' ,
header : cap [ 1 ] . replace ( /^ *| *\| *$/g , '' ) . split ( / *\| */ ) ,
align : cap [ 2 ] . replace ( /^ *|\| *$/g , '' ) . split ( / *\| */ ) ,
cells : cap [ 3 ] . replace ( /\n$/ , '' ) . split ( '\n' )
} ;
for ( i = 0 ; i < item . align . length ; i ++ ) {
if ( /^ *-+: *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'right' ;
} else if ( /^ *:-+: *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'center' ;
} else if ( /^ *:-+ *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'left' ;
} else {
item . align [ i ] = null ;
}
}
for ( i = 0 ; i < item . cells . length ; i ++ ) {
item . cells [ i ] = item . cells [ i ] . split ( / *\| */ ) ;
}
this . tokens . push ( item ) ;
continue ;
}
// lheading
if ( cap = this . rules . lheading . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'heading' ,
depth : cap [ 2 ] === '=' ? 1 : 2 ,
text : cap [ 1 ]
} ) ;
continue ;
}
// hr
if ( cap = this . rules . hr . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'hr'
} ) ;
continue ;
}
// blockquote
if ( cap = this . rules . blockquote . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'blockquote_start'
} ) ;
cap = cap [ 0 ] . replace ( /^ *> ?/gm , '' ) ;
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
this . token ( cap , top , true ) ;
this . tokens . push ( {
type : 'blockquote_end'
} ) ;
continue ;
}
// list
if ( cap = this . rules . list . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
bull = cap [ 2 ] ;
this . tokens . push ( {
type : 'list_start' ,
ordered : bull . length > 1
} ) ;
// Get each top-level item.
cap = cap [ 0 ] . match ( this . rules . item ) ;
next = false ;
l = cap . length ;
i = 0 ;
for ( ; i < l ; i ++ ) {
item = cap [ i ] ;
// Remove the list item's bullet
// so it is seen as the next token.
space = item . length ;
item = item . replace ( /^ *([*+-]|\d+\.) +/ , '' ) ;
// Outdent whatever the
// list item contains. Hacky.
if ( ~ item . indexOf ( '\n ' ) ) {
space -= item . length ;
item = ! this . options . pedantic
? item . replace ( new RegExp ( '^ {1,' + space + '}' , 'gm' ) , '' )
: item . replace ( /^ {1,4}/gm , '' ) ;
}
// Determine whether the next list item belongs here.
// Backpedal if it does not belong in this list.
if ( this . options . smartLists && i !== l - 1 ) {
b = block . bullet . exec ( cap [ i + 1 ] ) [ 0 ] ;
if ( bull !== b && ! ( bull . length > 1 && b . length > 1 ) ) {
src = cap . slice ( i + 1 ) . join ( '\n' ) + src ;
i = l - 1 ;
}
}
// Determine whether item is loose or not.
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
// for discount behavior.
loose = next || /\n\n(?!\s*$)/ . test ( item ) ;
if ( i !== l - 1 ) {
next = item . charAt ( item . length - 1 ) === '\n' ;
if ( ! loose ) loose = next ;
}
this . tokens . push ( {
type : loose
? 'loose_item_start'
: 'list_item_start'
} ) ;
// Recurse.
this . token ( item , false , bq ) ;
this . tokens . push ( {
type : 'list_item_end'
} ) ;
}
this . tokens . push ( {
type : 'list_end'
} ) ;
continue ;
}
// html
if ( cap = this . rules . html . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : this . options . sanitize
? 'paragraph'
: 'html' ,
pre : ! this . options . sanitizer
&& ( cap [ 1 ] === 'pre' || cap [ 1 ] === 'script' || cap [ 1 ] === 'style' ) ,
text : cap [ 0 ]
} ) ;
continue ;
}
// def
if ( ( ! bq && top ) && ( cap = this . rules . def . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . links [ cap [ 1 ] . toLowerCase ( ) ] = {
href : cap [ 2 ] ,
title : cap [ 3 ]
} ;
continue ;
}
// table (gfm)
if ( top && ( cap = this . rules . table . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
item = {
type : 'table' ,
header : cap [ 1 ] . replace ( /^ *| *\| *$/g , '' ) . split ( / *\| */ ) ,
align : cap [ 2 ] . replace ( /^ *|\| *$/g , '' ) . split ( / *\| */ ) ,
cells : cap [ 3 ] . replace ( /(?: *\| *)?\n$/ , '' ) . split ( '\n' )
} ;
for ( i = 0 ; i < item . align . length ; i ++ ) {
if ( /^ *-+: *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'right' ;
} else if ( /^ *:-+: *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'center' ;
} else if ( /^ *:-+ *$/ . test ( item . align [ i ] ) ) {
item . align [ i ] = 'left' ;
} else {
item . align [ i ] = null ;
}
}
for ( i = 0 ; i < item . cells . length ; i ++ ) {
item . cells [ i ] = item . cells [ i ]
. replace ( /^ *\| *| *\| *$/g , '' )
. split ( / *\| */ ) ;
}
this . tokens . push ( item ) ;
continue ;
}
// top-level paragraph
if ( top && ( cap = this . rules . paragraph . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'paragraph' ,
text : cap [ 1 ] . charAt ( cap [ 1 ] . length - 1 ) === '\n'
? cap [ 1 ] . slice ( 0 , - 1 )
: cap [ 1 ]
} ) ;
continue ;
}
// text
if ( cap = this . rules . text . exec ( src ) ) {
// Top-level should never reach here.
src = src . substring ( cap [ 0 ] . length ) ;
this . tokens . push ( {
type : 'text' ,
text : cap [ 0 ]
} ) ;
continue ;
}
if ( src ) {
throw new
Error ( 'Infinite loop on byte: ' + src . charCodeAt ( 0 ) ) ;
}
}
return this . tokens ;
} ;
/ * *
* Inline - Level Grammar
* /
var inline = {
escape : /^\\([\\`*{}\[\]()#+\-.!_>])/ ,
autolink : /^<([^ >]+(@|:\/)[^ >]+)>/ ,
url : noop ,
tag : /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/ ,
link : /^!?\[(inside)\]\(href\)/ ,
reflink : /^!?\[(inside)\]\s*\[([^\]]*)\]/ ,
nolink : /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/ ,
strong : /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/ ,
em : /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/ ,
code : /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/ ,
br : /^ {2,}\n(?!\s*$)/ ,
del : noop ,
text : /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
} ;
inline . _inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/ ;
inline . _href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/ ;
inline . link = replace ( inline . link )
( 'inside' , inline . _inside )
( 'href' , inline . _href )
( ) ;
inline . reflink = replace ( inline . reflink )
( 'inside' , inline . _inside )
( ) ;
/ * *
* Normal Inline Grammar
* /
inline . normal = merge ( { } , inline ) ;
/ * *
* Pedantic Inline Grammar
* /
inline . pedantic = merge ( { } , inline . normal , {
strong : /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/ ,
em : /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
} ) ;
/ * *
* GFM Inline Grammar
* /
inline . gfm = merge ( { } , inline . normal , {
escape : replace ( inline . escape ) ( '])' , '~|])' ) ( ) ,
url : /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/ ,
del : /^~~(?=\S)([\s\S]*?\S)~~/ ,
text : replace ( inline . text )
( ']|' , '~]|' )
( '|' , '|https?://|' )
( )
} ) ;
/ * *
* GFM + Line Breaks Inline Grammar
* /
inline . breaks = merge ( { } , inline . gfm , {
br : replace ( inline . br ) ( '{2,}' , '*' ) ( ) ,
text : replace ( inline . gfm . text ) ( '{2,}' , '*' ) ( )
} ) ;
/ * *
* Inline Lexer & Compiler
* /
function InlineLexer ( links , options ) {
this . options = options || marked . defaults ;
this . links = links ;
this . rules = inline . normal ;
this . renderer = this . options . renderer || new Renderer ;
this . renderer . options = this . options ;
if ( ! this . links ) {
throw new
Error ( 'Tokens array requires a `links` property.' ) ;
}
if ( this . options . gfm ) {
if ( this . options . breaks ) {
this . rules = inline . breaks ;
} else {
this . rules = inline . gfm ;
}
} else if ( this . options . pedantic ) {
this . rules = inline . pedantic ;
}
}
/ * *
* Expose Inline Rules
* /
InlineLexer . rules = inline ;
/ * *
* Static Lexing / Compiling Method
* /
InlineLexer . output = function ( src , links , options ) {
var inline = new InlineLexer ( links , options ) ;
return inline . output ( src ) ;
} ;
/ * *
* Lexing / Compiling
* /
InlineLexer . prototype . output = function ( src ) {
var out = ''
, link
, text
, href
, cap ;
while ( src ) {
// escape
if ( cap = this . rules . escape . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += cap [ 1 ] ;
continue ;
}
// autolink
if ( cap = this . rules . autolink . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
if ( cap [ 2 ] === '@' ) {
text = cap [ 1 ] . charAt ( 6 ) === ':'
? this . mangle ( cap [ 1 ] . substring ( 7 ) )
: this . mangle ( cap [ 1 ] ) ;
href = this . mangle ( 'mailto:' ) + text ;
} else {
text = escape ( cap [ 1 ] ) ;
href = text ;
}
out += this . renderer . link ( href , null , text ) ;
continue ;
}
// url (gfm)
if ( ! this . inLink && ( cap = this . rules . url . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
text = escape ( cap [ 1 ] ) ;
href = text ;
out += this . renderer . link ( href , null , text ) ;
continue ;
}
// tag
if ( cap = this . rules . tag . exec ( src ) ) {
if ( ! this . inLink && /^<a /i . test ( cap [ 0 ] ) ) {
this . inLink = true ;
} else if ( this . inLink && /^<\/a>/i . test ( cap [ 0 ] ) ) {
this . inLink = false ;
}
src = src . substring ( cap [ 0 ] . length ) ;
out += this . options . sanitize
? this . options . sanitizer
? this . options . sanitizer ( cap [ 0 ] )
: escape ( cap [ 0 ] )
: cap [ 0 ]
continue ;
}
// link
if ( cap = this . rules . link . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
this . inLink = true ;
out += this . outputLink ( cap , {
href : cap [ 2 ] ,
title : cap [ 3 ]
} ) ;
this . inLink = false ;
continue ;
}
// reflink, nolink
if ( ( cap = this . rules . reflink . exec ( src ) )
|| ( cap = this . rules . nolink . exec ( src ) ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
link = ( cap [ 2 ] || cap [ 1 ] ) . replace ( /\s+/g , ' ' ) ;
link = this . links [ link . toLowerCase ( ) ] ;
if ( ! link || ! link . href ) {
out += cap [ 0 ] . charAt ( 0 ) ;
src = cap [ 0 ] . substring ( 1 ) + src ;
continue ;
}
this . inLink = true ;
out += this . outputLink ( cap , link ) ;
this . inLink = false ;
continue ;
}
// strong
if ( cap = this . rules . strong . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . strong ( this . output ( cap [ 2 ] || cap [ 1 ] ) ) ;
continue ;
}
// em
if ( cap = this . rules . em . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . em ( this . output ( cap [ 2 ] || cap [ 1 ] ) ) ;
continue ;
}
// code
if ( cap = this . rules . code . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . codespan ( escape ( cap [ 2 ] , true ) ) ;
continue ;
}
// br
if ( cap = this . rules . br . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . br ( ) ;
continue ;
}
// del (gfm)
if ( cap = this . rules . del . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . del ( this . output ( cap [ 1 ] ) ) ;
continue ;
}
// text
if ( cap = this . rules . text . exec ( src ) ) {
src = src . substring ( cap [ 0 ] . length ) ;
out += this . renderer . text ( escape ( this . smartypants ( cap [ 0 ] ) ) ) ;
continue ;
}
if ( src ) {
throw new
Error ( 'Infinite loop on byte: ' + src . charCodeAt ( 0 ) ) ;
}
}
return out ;
} ;
/ * *
* Compile Link
* /
InlineLexer . prototype . outputLink = function ( cap , link ) {
var href = escape ( link . href )
, title = link . title ? escape ( link . title ) : null ;
return cap [ 0 ] . charAt ( 0 ) !== '!'
? this . renderer . link ( href , title , this . output ( cap [ 1 ] ) )
: this . renderer . image ( href , title , escape ( cap [ 1 ] ) ) ;
} ;
/ * *
* Smartypants Transformations
* /
InlineLexer . prototype . smartypants = function ( text ) {
if ( ! this . options . smartypants ) return text ;
return text
// em-dashes
. replace ( /---/g , '\u2014' )
// en-dashes
. replace ( /--/g , '\u2013' )
// opening singles
. replace ( /(^|[-\u2014/(\[{"\s])'/g , '$1\u2018' )
// closing singles & apostrophes
. replace ( /'/g , '\u2019' )
// opening doubles
. replace ( /(^|[-\u2014/(\[{\u2018\s])"/g , '$1\u201c' )
// closing doubles
. replace ( /"/g , '\u201d' )
// ellipses
. replace ( /\.{3}/g , '\u2026' ) ;
} ;
/ * *
* Mangle Links
* /
InlineLexer . prototype . mangle = function ( text ) {
if ( ! this . options . mangle ) return text ;
var out = ''
, l = text . length
, i = 0
, ch ;
for ( ; i < l ; i ++ ) {
ch = text . charCodeAt ( i ) ;
if ( Math . random ( ) > 0.5 ) {
ch = 'x' + ch . toString ( 16 ) ;
}
out += '&#' + ch + ';' ;
}
return out ;
} ;
/ * *
* Renderer
* /
function Renderer ( options ) {
this . options = options || { } ;
}
Renderer . prototype . code = function ( code , lang , escaped ) {
if ( this . options . highlight ) {
var out = this . options . highlight ( code , lang ) ;
if ( out != null && out !== code ) {
escaped = true ;
code = out ;
}
}
if ( ! lang ) {
return '<pre><code>'
+ ( escaped ? code : escape ( code , true ) )
+ '\n</code></pre>' ;
}
return '<pre><code class="'
+ this . options . langPrefix
+ escape ( lang , true )
+ '">'
+ ( escaped ? code : escape ( code , true ) )
+ '\n</code></pre>\n' ;
} ;
Renderer . prototype . blockquote = function ( quote ) {
return '<blockquote>\n' + quote + '</blockquote>\n' ;
} ;
Renderer . prototype . html = function ( html ) {
return html ;
} ;
Renderer . prototype . heading = function ( text , level , raw ) {
return '<h'
+ level
+ ' id="'
+ this . options . headerPrefix
+ raw . toLowerCase ( ) . replace ( /[^\w]+/g , '-' )
+ '">'
+ text
+ '</h'
+ level
+ '>\n' ;
} ;
Renderer . prototype . hr = function ( ) {
return this . options . xhtml ? '<hr/>\n' : '<hr>\n' ;
} ;
Renderer . prototype . list = function ( body , ordered ) {
var type = ordered ? 'ol' : 'ul' ;
return '<' + type + '>\n' + body + '</' + type + '>\n' ;
} ;
Renderer . prototype . listitem = function ( text ) {
return '<li>' + text + '</li>\n' ;
} ;
Renderer . prototype . paragraph = function ( text ) {
return '<p>' + text + '</p>\n' ;
} ;
Renderer . prototype . table = function ( header , body ) {
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n' ;
} ;
Renderer . prototype . tablerow = function ( content ) {
return '<tr>\n' + content + '</tr>\n' ;
} ;
Renderer . prototype . tablecell = function ( content , flags ) {
var type = flags . header ? 'th' : 'td' ;
var tag = flags . align
? '<' + type + ' style="text-align:' + flags . align + '">'
: '<' + type + '>' ;
return tag + content + '</' + type + '>\n' ;
} ;
// span level renderer
Renderer . prototype . strong = function ( text ) {
return '<strong>' + text + '</strong>' ;
} ;
Renderer . prototype . em = function ( text ) {
return '<em>' + text + '</em>' ;
} ;
Renderer . prototype . codespan = function ( text ) {
return '<code>' + text + '</code>' ;
} ;
Renderer . prototype . br = function ( ) {
return this . options . xhtml ? '<br/>' : '<br>' ;
} ;
Renderer . prototype . del = function ( text ) {
return '<del>' + text + '</del>' ;
} ;
Renderer . prototype . link = function ( href , title , text ) {
if ( this . options . sanitize ) {
try {
var prot = decodeURIComponent ( unescape ( href ) )
. replace ( /[^\w:]/g , '' )
. toLowerCase ( ) ;
} catch ( e ) {
return '' ;
}
if ( prot . indexOf ( 'javascript:' ) === 0 || prot . indexOf ( 'vbscript:' ) === 0 ) {
return '' ;
}
}
var out = '<a href="' + href + '"' ;
if ( title ) {
out += ' title="' + title + '"' ;
}
out += '>' + text + '</a>' ;
return out ;
} ;
Renderer . prototype . image = function ( href , title , text ) {
var out = '<img src="' + href + '" alt="' + text + '"' ;
if ( title ) {
out += ' title="' + title + '"' ;
}
out += this . options . xhtml ? '/>' : '>' ;
return out ;
} ;
Renderer . prototype . text = function ( text ) {
return text ;
} ;
/ * *
* Parsing & Compiling
* /
function Parser ( options ) {
this . tokens = [ ] ;
this . token = null ;
this . options = options || marked . defaults ;
this . options . renderer = this . options . renderer || new Renderer ;
this . renderer = this . options . renderer ;
this . renderer . options = this . options ;
}
/ * *
* Static Parse Method
* /
Parser . parse = function ( src , options , renderer ) {
var parser = new Parser ( options , renderer ) ;
return parser . parse ( src ) ;
} ;
/ * *
* Parse Loop
* /
Parser . prototype . parse = function ( src ) {
this . inline = new InlineLexer ( src . links , this . options , this . renderer ) ;
this . tokens = src . reverse ( ) ;
var out = '' ;
while ( this . next ( ) ) {
out += this . tok ( ) ;
}
return out ;
} ;
/ * *
* Next Token
* /
Parser . prototype . next = function ( ) {
return this . token = this . tokens . pop ( ) ;
} ;
/ * *
* Preview Next Token
* /
Parser . prototype . peek = function ( ) {
return this . tokens [ this . tokens . length - 1 ] || 0 ;
} ;
/ * *
* Parse Text Tokens
* /
Parser . prototype . parseText = function ( ) {
var body = this . token . text ;
while ( this . peek ( ) . type === 'text' ) {
body += '\n' + this . next ( ) . text ;
}
return this . inline . output ( body ) ;
} ;
/ * *
* Parse Current Token
* /
Parser . prototype . tok = function ( ) {
switch ( this . token . type ) {
case 'space' : {
return '' ;
}
case 'hr' : {
return this . renderer . hr ( ) ;
}
case 'heading' : {
return this . renderer . heading (
this . inline . output ( this . token . text ) ,
this . token . depth ,
this . token . text ) ;
}
case 'code' : {
return this . renderer . code ( this . token . text ,
this . token . lang ,
this . token . escaped ) ;
}
case 'table' : {
var header = ''
, body = ''
, i
, row
, cell
, flags
, j ;
// header
cell = '' ;
for ( i = 0 ; i < this . token . header . length ; i ++ ) {
flags = { header : true , align : this . token . align [ i ] } ;
cell += this . renderer . tablecell (
this . inline . output ( this . token . header [ i ] ) ,
{ header : true , align : this . token . align [ i ] }
) ;
}
header += this . renderer . tablerow ( cell ) ;
for ( i = 0 ; i < this . token . cells . length ; i ++ ) {
row = this . token . cells [ i ] ;
cell = '' ;
for ( j = 0 ; j < row . length ; j ++ ) {
cell += this . renderer . tablecell (
this . inline . output ( row [ j ] ) ,
{ header : false , align : this . token . align [ j ] }
) ;
}
body += this . renderer . tablerow ( cell ) ;
}
return this . renderer . table ( header , body ) ;
}
case 'blockquote_start' : {
var body = '' ;
while ( this . next ( ) . type !== 'blockquote_end' ) {
body += this . tok ( ) ;
}
return this . renderer . blockquote ( body ) ;
}
case 'list_start' : {
var body = ''
, ordered = this . token . ordered ;
while ( this . next ( ) . type !== 'list_end' ) {
body += this . tok ( ) ;
}
return this . renderer . list ( body , ordered ) ;
}
case 'list_item_start' : {
var body = '' ;
while ( this . next ( ) . type !== 'list_item_end' ) {
body += this . token . type === 'text'
? this . parseText ( )
: this . tok ( ) ;
}
return this . renderer . listitem ( body ) ;
}
case 'loose_item_start' : {
var body = '' ;
while ( this . next ( ) . type !== 'list_item_end' ) {
body += this . tok ( ) ;
}
return this . renderer . listitem ( body ) ;
}
case 'html' : {
var html = ! this . token . pre && ! this . options . pedantic
? this . inline . output ( this . token . text )
: this . token . text ;
return this . renderer . html ( html ) ;
}
case 'paragraph' : {
return this . renderer . paragraph ( this . inline . output ( this . token . text ) ) ;
}
case 'text' : {
return this . renderer . paragraph ( this . parseText ( ) ) ;
}
}
} ;
/ * *
* Helpers
* /
function escape ( html , encode ) {
return html
. replace ( ! encode ? /&(?!#?\w+;)/g : /&/g , '&' )
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /"/g , '"' )
. replace ( /'/g , ''' ) ;
}
function unescape ( html ) {
// explicitly match decimal, hex, and named HTML entities
return html . replace ( /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g , function ( _ , n ) {
n = n . toLowerCase ( ) ;
if ( n === 'colon' ) return ':' ;
if ( n . charAt ( 0 ) === '#' ) {
return n . charAt ( 1 ) === 'x'
? String . fromCharCode ( parseInt ( n . substring ( 2 ) , 16 ) )
: String . fromCharCode ( + n . substring ( 1 ) ) ;
}
return '' ;
} ) ;
}
function replace ( regex , opt ) {
regex = regex . source ;
opt = opt || '' ;
return function self ( name , val ) {
if ( ! name ) return new RegExp ( regex , opt ) ;
val = val . source || val ;
val = val . replace ( /(^|[^\[])\^/g , '$1' ) ;
regex = regex . replace ( name , val ) ;
return self ;
} ;
}
function noop ( ) { }
noop . exec = noop ;
function merge ( obj ) {
var i = 1
, target
, key ;
for ( ; i < arguments . length ; i ++ ) {
target = arguments [ i ] ;
for ( key in target ) {
if ( Object . prototype . hasOwnProperty . call ( target , key ) ) {
obj [ key ] = target [ key ] ;
}
}
}
return obj ;
}
/ * *
* Marked
* /
function marked ( src , opt , callback ) {
if ( callback || typeof opt === 'function' ) {
if ( ! callback ) {
callback = opt ;
opt = null ;
}
opt = merge ( { } , marked . defaults , opt || { } ) ;
var highlight = opt . highlight
, tokens
, pending
, i = 0 ;
try {
tokens = Lexer . lex ( src , opt )
} catch ( e ) {
return callback ( e ) ;
}
pending = tokens . length ;
var done = function ( err ) {
if ( err ) {
opt . highlight = highlight ;
return callback ( err ) ;
}
var out ;
try {
out = Parser . parse ( tokens , opt ) ;
} catch ( e ) {
err = e ;
}
opt . highlight = highlight ;
return err
? callback ( err )
: callback ( null , out ) ;
} ;
if ( ! highlight || highlight . length < 3 ) {
return done ( ) ;
}
delete opt . highlight ;
if ( ! pending ) return done ( ) ;
for ( ; i < tokens . length ; i ++ ) {
( function ( token ) {
if ( token . type !== 'code' ) {
return -- pending || done ( ) ;
}
return highlight ( token . text , token . lang , function ( err , code ) {
if ( err ) return done ( err ) ;
if ( code == null || code === token . text ) {
return -- pending || done ( ) ;
}
token . text = code ;
token . escaped = true ;
-- pending || done ( ) ;
} ) ;
} ) ( tokens [ i ] ) ;
}
return ;
}
try {
if ( opt ) opt = merge ( { } , marked . defaults , opt ) ;
return Parser . parse ( Lexer . lex ( src , opt ) , opt ) ;
} catch ( e ) {
e . message += '\nPlease report this to https://github.com/chjj/marked.' ;
if ( ( opt || marked . defaults ) . silent ) {
return '<p>An error occured:</p><pre>'
+ escape ( e . message + '' , true )
+ '</pre>' ;
}
throw e ;
}
}
/ * *
* Options
* /
marked . options =
marked . setOptions = function ( opt ) {
merge ( marked . defaults , opt ) ;
return marked ;
} ;
marked . defaults = {
gfm : true ,
tables : true ,
breaks : false ,
pedantic : false ,
sanitize : false ,
sanitizer : null ,
mangle : true ,
smartLists : false ,
silent : false ,
highlight : null ,
langPrefix : 'lang-' ,
smartypants : false ,
headerPrefix : '' ,
renderer : new Renderer ,
xhtml : false
} ;
/ * *
* Expose
* /
marked . Parser = Parser ;
marked . parser = Parser . parse ;
marked . Renderer = Renderer ;
marked . Lexer = Lexer ;
marked . lexer = Lexer . lex ;
marked . InlineLexer = InlineLexer ;
marked . inlineLexer = InlineLexer . output ;
marked . parse = marked ;
if ( typeof module !== 'undefined' && typeof exports === 'object' ) {
module . exports = marked ;
} else if ( typeof define === 'function' && define . amd ) {
define ( function ( ) { return marked ; } ) ;
} else {
this . marked = marked ;
}
} ) . call ( function ( ) {
return this || ( typeof window !== 'undefined' ? window : global ) ;
} ( ) ) ;
} ) . call ( this , typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : { } )
} , { } ] , 17 : [ function ( require , module , exports ) {
( function ( Buffer , _ _dirname ) {
/* globals chrome: false */
/* globals __dirname: false */
/* globals require: false */
/* globals Buffer: false */
/* globals module: false */
/ * *
* Typo is a JavaScript implementation of a spellchecker using hunspell - style
* dictionaries .
* /
var Typo ;
( function ( ) {
"use strict" ;
/ * *
* Typo constructor .
*
* @ param { String } [ dictionary ] The locale code of the dictionary being used . e . g . ,
* "en_US" . This is only used to auto - load dictionaries .
* @ param { String } [ affData ] The data from the dictionary ' s . aff file . If omitted
* and Typo . js is being used in a Chrome extension , the . aff
* file will be loaded automatically from
* lib / typo / dictionaries / [ dictionary ] / [ dictionary ] . aff
* In other environments , it will be loaded from
* [ settings . dictionaryPath ] / dictionaries / [ dictionary ] / [ dictionary ] . aff
* @ param { String } [ wordsData ] The data from the dictionary ' s . dic file . If omitted
* and Typo . js is being used in a Chrome extension , the . dic
* file will be loaded automatically from
* lib / typo / dictionaries / [ dictionary ] / [ dictionary ] . dic
* In other environments , it will be loaded from
* [ settings . dictionaryPath ] / dictionaries / [ dictionary ] / [ dictionary ] . dic
* @ param { Object } [ settings ] Constructor settings . Available properties are :
* { String } [ dictionaryPath ] : path to load dictionary from in non - chrome
* environment .
* { Object } [ flags ] : flag information .
* { Boolean } [ asyncLoad ] : If true , affData and wordsData will be loaded
* asynchronously .
* { Function } [ loadedCallback ] : Called when both affData and wordsData
* have been loaded . Only used if asyncLoad is set to true . The parameter
* is the instantiated Typo object .
*
* @ returns { Typo } A Typo object .
* /
Typo = function ( dictionary , affData , wordsData , settings ) {
settings = settings || { } ;
this . dictionary = null ;
this . rules = { } ;
this . dictionaryTable = { } ;
this . compoundRules = [ ] ;
this . compoundRuleCodes = { } ;
this . replacementTable = [ ] ;
this . flags = settings . flags || { } ;
this . memoized = { } ;
this . loaded = false ;
var self = this ;
var path ;
// Loop-control variables.
var i , j , _len , _jlen ;
if ( dictionary ) {
self . dictionary = dictionary ;
// If the data is preloaded, just setup the Typo object.
if ( affData && wordsData ) {
setup ( ) ;
}
// Loading data for Chrome extentions.
else if ( typeof window !== 'undefined' && 'chrome' in window && 'extension' in window . chrome && 'getURL' in window . chrome . extension ) {
if ( settings . dictionaryPath ) {
path = settings . dictionaryPath ;
}
else {
path = "typo/dictionaries" ;
}
if ( ! affData ) readDataFile ( chrome . extension . getURL ( path + "/" + dictionary + "/" + dictionary + ".aff" ) , setAffData ) ;
if ( ! wordsData ) readDataFile ( chrome . extension . getURL ( path + "/" + dictionary + "/" + dictionary + ".dic" ) , setWordsData ) ;
}
else {
if ( settings . dictionaryPath ) {
path = settings . dictionaryPath ;
}
else if ( typeof _ _dirname !== 'undefined' ) {
path = _ _dirname + '/dictionaries' ;
}
else {
path = './dictionaries' ;
}
if ( ! affData ) readDataFile ( path + "/" + dictionary + "/" + dictionary + ".aff" , setAffData ) ;
if ( ! wordsData ) readDataFile ( path + "/" + dictionary + "/" + dictionary + ".dic" , setWordsData ) ;
}
}
function readDataFile ( url , setFunc ) {
var response = self . _readFile ( url , null , settings . asyncLoad ) ;
if ( settings . asyncLoad ) {
response . then ( function ( data ) {
setFunc ( data ) ;
} ) ;
}
else {
setFunc ( response ) ;
}
}
function setAffData ( data ) {
affData = data ;
if ( wordsData ) {
setup ( ) ;
}
}
function setWordsData ( data ) {
wordsData = data ;
if ( affData ) {
setup ( ) ;
}
}
function setup ( ) {
self . rules = self . _parseAFF ( affData ) ;
// Save the rule codes that are used in compound rules.
self . compoundRuleCodes = { } ;
for ( i = 0 , _len = self . compoundRules . length ; i < _len ; i ++ ) {
var rule = self . compoundRules [ i ] ;
for ( j = 0 , _jlen = rule . length ; j < _jlen ; j ++ ) {
self . compoundRuleCodes [ rule [ j ] ] = [ ] ;
}
}
// If we add this ONLYINCOMPOUND flag to self.compoundRuleCodes, then _parseDIC
// will do the work of saving the list of words that are compound-only.
if ( "ONLYINCOMPOUND" in self . flags ) {
self . compoundRuleCodes [ self . flags . ONLYINCOMPOUND ] = [ ] ;
}
self . dictionaryTable = self . _parseDIC ( wordsData ) ;
// Get rid of any codes from the compound rule codes that are never used
// (or that were special regex characters). Not especially necessary...
for ( i in self . compoundRuleCodes ) {
if ( self . compoundRuleCodes [ i ] . length === 0 ) {
delete self . compoundRuleCodes [ i ] ;
}
}
// Build the full regular expressions for each compound rule.
// I have a feeling (but no confirmation yet) that this method of
// testing for compound words is probably slow.
for ( i = 0 , _len = self . compoundRules . length ; i < _len ; i ++ ) {
var ruleText = self . compoundRules [ i ] ;
var expressionText = "" ;
for ( j = 0 , _jlen = ruleText . length ; j < _jlen ; j ++ ) {
var character = ruleText [ j ] ;
if ( character in self . compoundRuleCodes ) {
expressionText += "(" + self . compoundRuleCodes [ character ] . join ( "|" ) + ")" ;
}
else {
expressionText += character ;
}
}
self . compoundRules [ i ] = new RegExp ( expressionText , "i" ) ;
}
self . loaded = true ;
if ( settings . asyncLoad && settings . loadedCallback ) {
settings . loadedCallback ( self ) ;
}
}
return this ;
} ;
Typo . prototype = {
/ * *
* Loads a Typo instance from a hash of all of the Typo properties .
*
* @ param object obj A hash of Typo properties , probably gotten from a JSON . parse ( JSON . stringify ( typo _instance ) ) .
* /
load : function ( obj ) {
for ( var i in obj ) {
if ( obj . hasOwnProperty ( i ) ) {
this [ i ] = obj [ i ] ;
}
}
return this ;
} ,
/ * *
* Read the contents of a file .
*
* @ param { String } path The path ( relative ) to the file .
* @ param { String } [ charset = "ISO8859-1" ] The expected charset of the file
* @ param { Boolean } async If true , the file will be read asynchronously . For node . js this does nothing , all
* files are read synchronously .
* @ returns { String } The file data if async is false , otherwise a promise object . If running node . js , the data is
* always returned .
* /
_readFile : function ( path , charset , async ) {
charset = charset || "utf8" ;
if ( typeof XMLHttpRequest !== 'undefined' ) {
var promise ;
var req = new XMLHttpRequest ( ) ;
req . open ( "GET" , path , async ) ;
if ( async ) {
promise = new Promise ( function ( resolve , reject ) {
req . onload = function ( ) {
if ( req . status === 200 ) {
resolve ( req . responseText ) ;
}
else {
reject ( req . statusText ) ;
}
} ;
req . onerror = function ( ) {
reject ( req . statusText ) ;
}
} ) ;
}
if ( req . overrideMimeType )
req . overrideMimeType ( "text/plain; charset=" + charset ) ;
req . send ( null ) ;
return async ? promise : req . responseText ;
}
else if ( typeof require !== 'undefined' ) {
// Node.js
var fs = require ( "fs" ) ;
try {
if ( fs . existsSync ( path ) ) {
var stats = fs . statSync ( path ) ;
var fileDescriptor = fs . openSync ( path , 'r' ) ;
var buffer = new Buffer ( stats . size ) ;
fs . readSync ( fileDescriptor , buffer , 0 , buffer . length , null ) ;
return buffer . toString ( charset , 0 , buffer . length ) ;
}
else {
console . log ( "Path " + path + " does not exist." ) ;
}
} catch ( e ) {
console . log ( e ) ;
return '' ;
}
}
} ,
/ * *
* Parse the rules out from a . aff file .
*
* @ param { String } data The contents of the affix file .
* @ returns object The rules from the file .
* /
_parseAFF : function ( data ) {
var rules = { } ;
var line , subline , numEntries , lineParts ;
var i , j , _len , _jlen ;
// Remove comment lines
data = this . _removeAffixComments ( data ) ;
var lines = data . split ( "\n" ) ;
for ( i = 0 , _len = lines . length ; i < _len ; i ++ ) {
line = lines [ i ] ;
var definitionParts = line . split ( /\s+/ ) ;
var ruleType = definitionParts [ 0 ] ;
if ( ruleType == "PFX" || ruleType == "SFX" ) {
var ruleCode = definitionParts [ 1 ] ;
var combineable = definitionParts [ 2 ] ;
numEntries = parseInt ( definitionParts [ 3 ] , 10 ) ;
var entries = [ ] ;
for ( j = i + 1 , _jlen = i + 1 + numEntries ; j < _jlen ; j ++ ) {
subline = lines [ j ] ;
lineParts = subline . split ( /\s+/ ) ;
var charactersToRemove = lineParts [ 2 ] ;
var additionParts = lineParts [ 3 ] . split ( "/" ) ;
var charactersToAdd = additionParts [ 0 ] ;
if ( charactersToAdd === "0" ) charactersToAdd = "" ;
var continuationClasses = this . parseRuleCodes ( additionParts [ 1 ] ) ;
var regexToMatch = lineParts [ 4 ] ;
var entry = { } ;
entry . add = charactersToAdd ;
if ( continuationClasses . length > 0 ) entry . continuationClasses = continuationClasses ;
if ( regexToMatch !== "." ) {
if ( ruleType === "SFX" ) {
entry . match = new RegExp ( regexToMatch + "$" ) ;
}
else {
entry . match = new RegExp ( "^" + regexToMatch ) ;
}
}
if ( charactersToRemove != "0" ) {
if ( ruleType === "SFX" ) {
entry . remove = new RegExp ( charactersToRemove + "$" ) ;
}
else {
entry . remove = charactersToRemove ;
}
}
entries . push ( entry ) ;
}
rules [ ruleCode ] = { "type" : ruleType , "combineable" : ( combineable == "Y" ) , "entries" : entries } ;
i += numEntries ;
}
else if ( ruleType === "COMPOUNDRULE" ) {
numEntries = parseInt ( definitionParts [ 1 ] , 10 ) ;
for ( j = i + 1 , _jlen = i + 1 + numEntries ; j < _jlen ; j ++ ) {
line = lines [ j ] ;
lineParts = line . split ( /\s+/ ) ;
this . compoundRules . push ( lineParts [ 1 ] ) ;
}
i += numEntries ;
}
else if ( ruleType === "REP" ) {
lineParts = line . split ( /\s+/ ) ;
if ( lineParts . length === 3 ) {
this . replacementTable . push ( [ lineParts [ 1 ] , lineParts [ 2 ] ] ) ;
}
}
else {
// ONLYINCOMPOUND
// COMPOUNDMIN
// FLAG
// KEEPCASE
// NEEDAFFIX
this . flags [ ruleType ] = definitionParts [ 1 ] ;
}
}
return rules ;
} ,
/ * *
* Removes comment lines and then cleans up blank lines and trailing whitespace .
*
* @ param { String } data The data from an affix file .
* @ return { String } The cleaned - up data .
* /
_removeAffixComments : function ( data ) {
// Remove comments
// This used to remove any string starting with '#' up to the end of the line,
// but some COMPOUNDRULE definitions include '#' as part of the rule.
// I haven't seen any affix files that use comments on the same line as real data,
// so I don't think this will break anything.
data = data . replace ( /^\s*#.*$/mg , "" ) ;
// Trim each line
data = data . replace ( /^\s\s*/m , '' ) . replace ( /\s\s*$/m , '' ) ;
// Remove blank lines.
data = data . replace ( /\n{2,}/g , "\n" ) ;
// Trim the entire string
data = data . replace ( /^\s\s*/ , '' ) . replace ( /\s\s*$/ , '' ) ;
return data ;
} ,
/ * *
* Parses the words out from the . dic file .
*
* @ param { String } data The data from the dictionary file .
* @ returns object The lookup table containing all of the words and
* word forms from the dictionary .
* /
_parseDIC : function ( data ) {
data = this . _removeDicComments ( data ) ;
var lines = data . split ( "\n" ) ;
var dictionaryTable = { } ;
function addWord ( word , rules ) {
// Some dictionaries will list the same word multiple times with different rule sets.
if ( ! dictionaryTable . hasOwnProperty ( word ) ) {
dictionaryTable [ word ] = null ;
}
if ( rules . length > 0 ) {
if ( dictionaryTable [ word ] === null ) {
dictionaryTable [ word ] = [ ] ;
}
dictionaryTable [ word ] . push ( rules ) ;
}
}
// The first line is the number of words in the dictionary.
for ( var i = 1 , _len = lines . length ; i < _len ; i ++ ) {
var line = lines [ i ] ;
var parts = line . split ( "/" , 2 ) ;
var word = parts [ 0 ] ;
// Now for each affix rule, generate that form of the word.
if ( parts . length > 1 ) {
var ruleCodesArray = this . parseRuleCodes ( parts [ 1 ] ) ;
// Save the ruleCodes for compound word situations.
if ( ! ( "NEEDAFFIX" in this . flags ) || ruleCodesArray . indexOf ( this . flags . NEEDAFFIX ) == - 1 ) {
addWord ( word , ruleCodesArray ) ;
}
for ( var j = 0 , _jlen = ruleCodesArray . length ; j < _jlen ; j ++ ) {
var code = ruleCodesArray [ j ] ;
var rule = this . rules [ code ] ;
if ( rule ) {
var newWords = this . _applyRule ( word , rule ) ;
for ( var ii = 0 , _iilen = newWords . length ; ii < _iilen ; ii ++ ) {
var newWord = newWords [ ii ] ;
addWord ( newWord , [ ] ) ;
if ( rule . combineable ) {
for ( var k = j + 1 ; k < _jlen ; k ++ ) {
var combineCode = ruleCodesArray [ k ] ;
var combineRule = this . rules [ combineCode ] ;
if ( combineRule ) {
if ( combineRule . combineable && ( rule . type != combineRule . type ) ) {
var otherNewWords = this . _applyRule ( newWord , combineRule ) ;
for ( var iii = 0 , _iiilen = otherNewWords . length ; iii < _iiilen ; iii ++ ) {
var otherNewWord = otherNewWords [ iii ] ;
addWord ( otherNewWord , [ ] ) ;
}
}
}
}
}
}
}
if ( code in this . compoundRuleCodes ) {
this . compoundRuleCodes [ code ] . push ( word ) ;
}
}
}
else {
addWord ( word . trim ( ) , [ ] ) ;
}
}
return dictionaryTable ;
} ,
/ * *
* Removes comment lines and then cleans up blank lines and trailing whitespace .
*
* @ param { String } data The data from a . dic file .
* @ return { String } The cleaned - up data .
* /
_removeDicComments : function ( data ) {
// I can't find any official documentation on it, but at least the de_DE
// dictionary uses tab-indented lines as comments.
// Remove comments
data = data . replace ( /^\t.*$/mg , "" ) ;
return data ;
} ,
parseRuleCodes : function ( textCodes ) {
if ( ! textCodes ) {
return [ ] ;
}
else if ( ! ( "FLAG" in this . flags ) ) {
return textCodes . split ( "" ) ;
}
else if ( this . flags . FLAG === "long" ) {
var flags = [ ] ;
for ( var i = 0 , _len = textCodes . length ; i < _len ; i += 2 ) {
flags . push ( textCodes . substr ( i , 2 ) ) ;
}
return flags ;
}
else if ( this . flags . FLAG === "num" ) {
return textCodes . split ( "," ) ;
}
} ,
/ * *
* Applies an affix rule to a word .
*
* @ param { String } word The base word .
* @ param { Object } rule The affix rule .
* @ returns { String [ ] } The new words generated by the rule .
* /
_applyRule : function ( word , rule ) {
var entries = rule . entries ;
var newWords = [ ] ;
for ( var i = 0 , _len = entries . length ; i < _len ; i ++ ) {
var entry = entries [ i ] ;
if ( ! entry . match || word . match ( entry . match ) ) {
var newWord = word ;
if ( entry . remove ) {
newWord = newWord . replace ( entry . remove , "" ) ;
}
if ( rule . type === "SFX" ) {
newWord = newWord + entry . add ;
}
else {
newWord = entry . add + newWord ;
}
newWords . push ( newWord ) ;
if ( "continuationClasses" in entry ) {
for ( var j = 0 , _jlen = entry . continuationClasses . length ; j < _jlen ; j ++ ) {
var continuationRule = this . rules [ entry . continuationClasses [ j ] ] ;
if ( continuationRule ) {
newWords = newWords . concat ( this . _applyRule ( newWord , continuationRule ) ) ;
}
/ *
else {
// This shouldn't happen, but it does, at least in the de_DE dictionary.
// I think the author mistakenly supplied lower-case rule codes instead
// of upper-case.
}
* /
}
}
}
}
return newWords ;
} ,
/ * *
* Checks whether a word or a capitalization variant exists in the current dictionary .
* The word is trimmed and several variations of capitalizations are checked .
* If you want to check a word without any changes made to it , call checkExact ( )
*
* @ see http : //blog.stevenlevithan.com/archives/faster-trim-javascript re:trimming function
*
* @ param { String } aWord The word to check .
* @ returns { Boolean }
* /
check : function ( aWord ) {
if ( ! this . loaded ) {
throw "Dictionary not loaded." ;
}
// Remove leading and trailing whitespace
var trimmedWord = aWord . replace ( /^\s\s*/ , '' ) . replace ( /\s\s*$/ , '' ) ;
if ( this . checkExact ( trimmedWord ) ) {
return true ;
}
// The exact word is not in the dictionary.
if ( trimmedWord . toUpperCase ( ) === trimmedWord ) {
// The word was supplied in all uppercase.
// Check for a capitalized form of the word.
var capitalizedWord = trimmedWord [ 0 ] + trimmedWord . substring ( 1 ) . toLowerCase ( ) ;
if ( this . hasFlag ( capitalizedWord , "KEEPCASE" ) ) {
// Capitalization variants are not allowed for this word.
return false ;
}
if ( this . checkExact ( capitalizedWord ) ) {
return true ;
}
}
var lowercaseWord = trimmedWord . toLowerCase ( ) ;
if ( lowercaseWord !== trimmedWord ) {
if ( this . hasFlag ( lowercaseWord , "KEEPCASE" ) ) {
// Capitalization variants are not allowed for this word.
return false ;
}
// Check for a lowercase form
if ( this . checkExact ( lowercaseWord ) ) {
return true ;
}
}
return false ;
} ,
/ * *
* Checks whether a word exists in the current dictionary .
*
* @ param { String } word The word to check .
* @ returns { Boolean }
* /
checkExact : function ( word ) {
if ( ! this . loaded ) {
throw "Dictionary not loaded." ;
}
var ruleCodes = this . dictionaryTable [ word ] ;
var i , _len ;
if ( typeof ruleCodes === 'undefined' ) {
// Check if this might be a compound word.
if ( "COMPOUNDMIN" in this . flags && word . length >= this . flags . COMPOUNDMIN ) {
for ( i = 0 , _len = this . compoundRules . length ; i < _len ; i ++ ) {
if ( word . match ( this . compoundRules [ i ] ) ) {
return true ;
}
}
}
}
else if ( ruleCodes === null ) {
// a null (but not undefined) value for an entry in the dictionary table
// means that the word is in the dictionary but has no flags.
return true ;
}
else if ( typeof ruleCodes === 'object' ) { // this.dictionary['hasOwnProperty'] will be a function.
for ( i = 0 , _len = ruleCodes . length ; i < _len ; i ++ ) {
if ( ! this . hasFlag ( word , "ONLYINCOMPOUND" , ruleCodes [ i ] ) ) {
return true ;
}
}
}
return false ;
} ,
/ * *
* Looks up whether a given word is flagged with a given flag .
*
* @ param { String } word The word in question .
* @ param { String } flag The flag in question .
* @ return { Boolean }
* /
hasFlag : function ( word , flag , wordFlags ) {
if ( ! this . loaded ) {
throw "Dictionary not loaded." ;
}
if ( flag in this . flags ) {
if ( typeof wordFlags === 'undefined' ) {
wordFlags = Array . prototype . concat . apply ( [ ] , this . dictionaryTable [ word ] ) ;
}
if ( wordFlags && wordFlags . indexOf ( this . flags [ flag ] ) !== - 1 ) {
return true ;
}
}
return false ;
} ,
/ * *
* Returns a list of suggestions for a misspelled word .
*
* @ see http : //www.norvig.com/spell-correct.html for the basis of this suggestor.
* This suggestor is primitive , but it works .
*
* @ param { String } word The misspelling .
* @ param { Number } [ limit = 5 ] The maximum number of suggestions to return .
* @ returns { String [ ] } The array of suggestions .
* /
alphabet : "" ,
suggest : function ( word , limit ) {
if ( ! this . loaded ) {
throw "Dictionary not loaded." ;
}
limit = limit || 5 ;
if ( this . memoized . hasOwnProperty ( word ) ) {
var memoizedLimit = this . memoized [ word ] [ 'limit' ] ;
// Only return the cached list if it's big enough or if there weren't enough suggestions
// to fill a smaller limit.
if ( limit <= memoizedLimit || this . memoized [ word ] [ 'suggestions' ] . length < memoizedLimit ) {
return this . memoized [ word ] [ 'suggestions' ] . slice ( 0 , limit ) ;
}
}
if ( this . check ( word ) ) return [ ] ;
// Check the replacement table.
for ( var i = 0 , _len = this . replacementTable . length ; i < _len ; i ++ ) {
var replacementEntry = this . replacementTable [ i ] ;
if ( word . indexOf ( replacementEntry [ 0 ] ) !== - 1 ) {
var correctedWord = word . replace ( replacementEntry [ 0 ] , replacementEntry [ 1 ] ) ;
if ( this . check ( correctedWord ) ) {
return [ correctedWord ] ;
}
}
}
var self = this ;
self . alphabet = "abcdefghijklmnopqrstuvwxyz" ;
/ *
if ( ! self . alphabet ) {
// Use the alphabet as implicitly defined by the words in the dictionary.
var alphaHash = { } ;
for ( var i in self . dictionaryTable ) {
for ( var j = 0 , _len = i . length ; j < _len ; j ++ ) {
alphaHash [ i [ j ] ] = true ;
}
}
for ( var i in alphaHash ) {
self . alphabet += i ;
}
var alphaArray = self . alphabet . split ( "" ) ;
alphaArray . sort ( ) ;
self . alphabet = alphaArray . join ( "" ) ;
}
* /
function edits1 ( words ) {
var rv = [ ] ;
var ii , i , j , _iilen , _len , _jlen ;
for ( ii = 0 , _iilen = words . length ; ii < _iilen ; ii ++ ) {
var word = words [ ii ] ;
for ( i = 0 , _len = word . length + 1 ; i < _len ; i ++ ) {
var s = [ word . substring ( 0 , i ) , word . substring ( i ) ] ;
if ( s [ 1 ] ) {
rv . push ( s [ 0 ] + s [ 1 ] . substring ( 1 ) ) ;
}
// Eliminate transpositions of identical letters
if ( s [ 1 ] . length > 1 && s [ 1 ] [ 1 ] !== s [ 1 ] [ 0 ] ) {
rv . push ( s [ 0 ] + s [ 1 ] [ 1 ] + s [ 1 ] [ 0 ] + s [ 1 ] . substring ( 2 ) ) ;
}
if ( s [ 1 ] ) {
for ( j = 0 , _jlen = self . alphabet . length ; j < _jlen ; j ++ ) {
// Eliminate replacement of a letter by itself
if ( self . alphabet [ j ] != s [ 1 ] . substring ( 0 , 1 ) ) {
rv . push ( s [ 0 ] + self . alphabet [ j ] + s [ 1 ] . substring ( 1 ) ) ;
}
}
}
if ( s [ 1 ] ) {
for ( j = 0 , _jlen = self . alphabet . length ; j < _jlen ; j ++ ) {
rv . push ( s [ 0 ] + self . alphabet [ j ] + s [ 1 ] ) ;
}
}
}
}
return rv ;
}
function known ( words ) {
var rv = [ ] ;
for ( var i = 0 , _len = words . length ; i < _len ; i ++ ) {
if ( self . check ( words [ i ] ) ) {
rv . push ( words [ i ] ) ;
}
}
return rv ;
}
function correct ( word ) {
// Get the edit-distance-1 and edit-distance-2 forms of this word.
var ed1 = edits1 ( [ word ] ) ;
var ed2 = edits1 ( ed1 ) ;
var corrections = known ( ed1 . concat ( ed2 ) ) ;
var i , _len ;
// Sort the edits based on how many different ways they were created.
var weighted _corrections = { } ;
for ( i = 0 , _len = corrections . length ; i < _len ; i ++ ) {
if ( ! ( corrections [ i ] in weighted _corrections ) ) {
weighted _corrections [ corrections [ i ] ] = 1 ;
}
else {
weighted _corrections [ corrections [ i ] ] += 1 ;
}
}
var sorted _corrections = [ ] ;
for ( i in weighted _corrections ) {
if ( weighted _corrections . hasOwnProperty ( i ) ) {
sorted _corrections . push ( [ i , weighted _corrections [ i ] ] ) ;
}
}
function sorter ( a , b ) {
if ( a [ 1 ] < b [ 1 ] ) {
return - 1 ;
}
return 1 ;
}
sorted _corrections . sort ( sorter ) . reverse ( ) ;
var rv = [ ] ;
var capitalization _scheme = "lowercase" ;
if ( word . toUpperCase ( ) === word ) {
capitalization _scheme = "uppercase" ;
}
else if ( word . substr ( 0 , 1 ) . toUpperCase ( ) + word . substr ( 1 ) . toLowerCase ( ) === word ) {
capitalization _scheme = "capitalized" ;
}
for ( i = 0 , _len = Math . min ( limit , sorted _corrections . length ) ; i < _len ; i ++ ) {
if ( "uppercase" === capitalization _scheme ) {
sorted _corrections [ i ] [ 0 ] = sorted _corrections [ i ] [ 0 ] . toUpperCase ( ) ;
}
else if ( "capitalized" === capitalization _scheme ) {
sorted _corrections [ i ] [ 0 ] = sorted _corrections [ i ] [ 0 ] . substr ( 0 , 1 ) . toUpperCase ( ) + sorted _corrections [ i ] [ 0 ] . substr ( 1 ) ;
}
if ( ! self . hasFlag ( sorted _corrections [ i ] [ 0 ] , "NOSUGGEST" ) ) {
rv . push ( sorted _corrections [ i ] [ 0 ] ) ;
}
}
return rv ;
}
this . memoized [ word ] = {
'suggestions' : correct ( word ) ,
'limit' : limit
} ;
return this . memoized [ word ] [ 'suggestions' ] ;
}
} ;
} ) ( ) ;
// Support for use as a node.js module.
if ( typeof module !== 'undefined' ) {
module . exports = Typo ;
}
} ) . call ( this , require ( "buffer" ) . Buffer , "/node_modules/typo-js" )
} , { "buffer" : 3 , "fs" : 2 } ] , 18 : [ function ( require , module , exports ) {
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
var CodeMirror = require ( "codemirror" ) ;
CodeMirror . commands . tabAndIndentMarkdownList = function ( cm ) {
var ranges = cm . listSelections ( ) ;
var pos = ranges [ 0 ] . head ;
var eolState = cm . getStateAfter ( pos . line ) ;
var inList = eolState . list !== false ;
if ( inList ) {
cm . execCommand ( "indentMore" ) ;
return ;
}
if ( cm . options . indentWithTabs ) {
cm . execCommand ( "insertTab" ) ;
}
else {
var spaces = Array ( cm . options . tabSize + 1 ) . join ( " " ) ;
cm . replaceSelection ( spaces ) ;
}
} ;
CodeMirror . commands . shiftTabAndUnindentMarkdownList = function ( cm ) {
var ranges = cm . listSelections ( ) ;
var pos = ranges [ 0 ] . head ;
var eolState = cm . getStateAfter ( pos . line ) ;
var inList = eolState . list !== false ;
if ( inList ) {
cm . execCommand ( "indentLess" ) ;
return ;
}
if ( cm . options . indentWithTabs ) {
cm . execCommand ( "insertTab" ) ;
}
else {
var spaces = Array ( cm . options . tabSize + 1 ) . join ( " " ) ;
cm . replaceSelection ( spaces ) ;
}
} ;
} , { "codemirror" : 10 } ] , 19 : [ function ( require , module , exports ) {
/*global require,module*/
"use strict" ;
var CodeMirror = require ( "codemirror" ) ;
require ( "codemirror/addon/edit/continuelist.js" ) ;
require ( "./codemirror/tablist" ) ;
require ( "codemirror/addon/display/fullscreen.js" ) ;
require ( "codemirror/mode/markdown/markdown.js" ) ;
require ( "codemirror/addon/mode/overlay.js" ) ;
require ( "codemirror/addon/display/placeholder.js" ) ;
require ( "codemirror/addon/selection/mark-selection.js" ) ;
require ( "codemirror/mode/gfm/gfm.js" ) ;
require ( "codemirror/mode/xml/xml.js" ) ;
var CodeMirrorSpellChecker = require ( "codemirror-spell-checker" ) ;
var marked = require ( "marked" ) ;
// Some variables
var isMac = /Mac/ . test ( navigator . platform ) ;
// Mapping of actions that can be bound to keyboard shortcuts or toolbar buttons
var bindings = {
"toggleBold" : toggleBold ,
"toggleItalic" : toggleItalic ,
"drawLink" : drawLink ,
"toggleHeadingSmaller" : toggleHeadingSmaller ,
"toggleHeadingBigger" : toggleHeadingBigger ,
"drawImage" : drawImage ,
"toggleBlockquote" : toggleBlockquote ,
"toggleOrderedList" : toggleOrderedList ,
"toggleUnorderedList" : toggleUnorderedList ,
"toggleCodeBlock" : toggleCodeBlock ,
"togglePreview" : togglePreview ,
"toggleStrikethrough" : toggleStrikethrough ,
"toggleHeading1" : toggleHeading1 ,
"toggleHeading2" : toggleHeading2 ,
"toggleHeading3" : toggleHeading3 ,
"cleanBlock" : cleanBlock ,
"drawTable" : drawTable ,
"drawHorizontalRule" : drawHorizontalRule ,
"undo" : undo ,
"redo" : redo ,
"toggleSideBySide" : toggleSideBySide ,
"toggleFullScreen" : toggleFullScreen
} ;
var shortcuts = {
"toggleBold" : "Cmd-B" ,
"toggleItalic" : "Cmd-I" ,
"drawLink" : "Cmd-K" ,
"toggleHeadingSmaller" : "Cmd-H" ,
"toggleHeadingBigger" : "Shift-Cmd-H" ,
"cleanBlock" : "Cmd-E" ,
"drawImage" : "Cmd-Alt-I" ,
"toggleBlockquote" : "Cmd-'" ,
"toggleOrderedList" : "Cmd-Alt-L" ,
"toggleUnorderedList" : "Cmd-L" ,
"toggleCodeBlock" : "Cmd-Alt-C" ,
"togglePreview" : "Cmd-P" ,
"toggleSideBySide" : "F9" ,
"toggleFullScreen" : "F11"
} ;
var getBindingName = function ( f ) {
for ( var key in bindings ) {
if ( bindings [ key ] === f ) {
return key ;
}
}
return null ;
} ;
var isMobile = function ( ) {
var check = false ;
( function ( a ) {
if ( /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i . test ( a ) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i . test ( a . substr ( 0 , 4 ) ) ) check = true ;
} ) ( navigator . userAgent || navigator . vendor || window . opera ) ;
return check ;
} ;
/ * *
* Fix shortcut . Mac use Command , others use Ctrl .
* /
function fixShortcut ( name ) {
if ( isMac ) {
name = name . replace ( "Ctrl" , "Cmd" ) ;
} else {
name = name . replace ( "Cmd" , "Ctrl" ) ;
}
return name ;
}
/ * *
* Create icon element for toolbar .
* /
function createIcon ( options , enableTooltips , shortcuts ) {
options = options || { } ;
var el = document . createElement ( "a" ) ;
enableTooltips = ( enableTooltips == undefined ) ? true : enableTooltips ;
if ( options . title && enableTooltips ) {
el . title = createTootlip ( options . title , options . action , shortcuts ) ;
if ( isMac ) {
el . title = el . title . replace ( "Ctrl" , "⌘" ) ;
el . title = el . title . replace ( "Alt" , "⌥" ) ;
}
}
el . tabIndex = - 1 ;
el . className = options . className ;
return el ;
}
function createSep ( ) {
var el = document . createElement ( "i" ) ;
el . className = "separator" ;
el . innerHTML = "|" ;
return el ;
}
function createTootlip ( title , action , shortcuts ) {
var actionName ;
var tooltip = title ;
if ( action ) {
actionName = getBindingName ( action ) ;
if ( shortcuts [ actionName ] ) {
tooltip += " (" + fixShortcut ( shortcuts [ actionName ] ) + ")" ;
}
}
return tooltip ;
}
/ * *
* The state of CodeMirror at the given position .
* /
function getState ( cm , pos ) {
pos = pos || cm . getCursor ( "start" ) ;
var stat = cm . getTokenAt ( pos ) ;
if ( ! stat . type ) return { } ;
var types = stat . type . split ( " " ) ;
var ret = { } ,
data , text ;
for ( var i = 0 ; i < types . length ; i ++ ) {
data = types [ i ] ;
if ( data === "strong" ) {
ret . bold = true ;
} else if ( data === "variable-2" ) {
text = cm . getLine ( pos . line ) ;
if ( /^\s*\d+\.\s/ . test ( text ) ) {
ret [ "ordered-list" ] = true ;
} else {
ret [ "unordered-list" ] = true ;
}
} else if ( data === "atom" ) {
ret . quote = true ;
} else if ( data === "em" ) {
ret . italic = true ;
} else if ( data === "quote" ) {
ret . quote = true ;
} else if ( data === "strikethrough" ) {
ret . strikethrough = true ;
} else if ( data === "comment" ) {
ret . code = true ;
} else if ( data === "link" ) {
ret . link = true ;
} else if ( data === "tag" ) {
ret . image = true ;
} else if ( data . match ( /^header(\-[1-6])?$/ ) ) {
ret [ data . replace ( "header" , "heading" ) ] = true ;
}
}
return ret ;
}
// Saved overflow setting
var saved _overflow = "" ;
/ * *
* Toggle full screen of the editor .
* /
function toggleFullScreen ( editor ) {
// Set fullscreen
var cm = editor . codemirror ;
cm . setOption ( "fullScreen" , ! cm . getOption ( "fullScreen" ) ) ;
// Prevent scrolling on body during fullscreen active
if ( cm . getOption ( "fullScreen" ) ) {
saved _overflow = document . body . style . overflow ;
document . body . style . overflow = "hidden" ;
} else {
document . body . style . overflow = saved _overflow ;
}
// Update toolbar class
var wrap = cm . getWrapperElement ( ) ;
if ( ! /fullscreen/ . test ( wrap . previousSibling . className ) ) {
wrap . previousSibling . className += " fullscreen" ;
} else {
wrap . previousSibling . className = wrap . previousSibling . className . replace ( /\s*fullscreen\b/ , "" ) ;
}
// Update toolbar button
var toolbarButton = editor . toolbarElements . fullscreen ;
if ( ! /active/ . test ( toolbarButton . className ) ) {
toolbarButton . className += " active" ;
} else {
toolbarButton . className = toolbarButton . className . replace ( /\s*active\s*/g , "" ) ;
}
// Hide side by side if needed
var sidebyside = cm . getWrapperElement ( ) . nextSibling ;
if ( /editor-preview-active-side/ . test ( sidebyside . className ) )
toggleSideBySide ( editor ) ;
}
/ * *
* Action for toggling bold .
* /
function toggleBold ( editor ) {
_toggleBlock ( editor , "bold" , editor . options . blockStyles . bold ) ;
}
/ * *
* Action for toggling italic .
* /
function toggleItalic ( editor ) {
_toggleBlock ( editor , "italic" , editor . options . blockStyles . italic ) ;
}
/ * *
* Action for toggling strikethrough .
* /
function toggleStrikethrough ( editor ) {
_toggleBlock ( editor , "strikethrough" , "~~" ) ;
}
/ * *
* Action for toggling code block .
* /
function toggleCodeBlock ( editor ) {
var fenceCharsToInsert = editor . options . blockStyles . code ;
function fencing _line ( line ) {
/* return true, if this is a ``` or ~~~ line */
if ( typeof line !== "object" ) {
throw "fencing_line() takes a 'line' object (not a line number, or line text). Got: " + typeof line + ": " + line ;
}
return line . styles && line . styles [ 2 ] && line . styles [ 2 ] . indexOf ( "formatting-code-block" ) !== - 1 ;
}
function token _state ( token ) {
// base goes an extra level deep when mode backdrops are used, e.g. spellchecker on
return token . state . base . base || token . state . base ;
}
function code _type ( cm , line _num , line , firstTok , lastTok ) {
/ *
* Return "single" , "indented" , "fenced" or false
*
* cm and line _num are required . Others are optional for efficiency
* To check in the middle of a line , pass in firstTok yourself .
* /
line = line || cm . getLineHandle ( line _num ) ;
firstTok = firstTok || cm . getTokenAt ( {
line : line _num ,
ch : 1
} ) ;
lastTok = lastTok || ( ! ! line . text && cm . getTokenAt ( {
line : line _num ,
ch : line . text . length - 1
} ) ) ;
var types = firstTok . type ? firstTok . type . split ( " " ) : [ ] ;
if ( lastTok && token _state ( lastTok ) . indentedCode ) {
// have to check last char, since first chars of first line aren"t marked as indented
return "indented" ;
} else if ( types . indexOf ( "comment" ) === - 1 ) {
// has to be after "indented" check, since first chars of first indented line aren"t marked as such
return false ;
} else if ( token _state ( firstTok ) . fencedChars || token _state ( lastTok ) . fencedChars || fencing _line ( line ) ) {
return "fenced" ;
} else {
return "single" ;
}
}
function insertFencingAtSelection ( cm , cur _start , cur _end , fenceCharsToInsert ) {
var start _line _sel = cur _start . line + 1 ,
end _line _sel = cur _end . line + 1 ,
sel _multi = cur _start . line !== cur _end . line ,
repl _start = fenceCharsToInsert + "\n" ,
repl _end = "\n" + fenceCharsToInsert ;
if ( sel _multi ) {
end _line _sel ++ ;
}
// handle last char including \n or not
if ( sel _multi && cur _end . ch === 0 ) {
repl _end = fenceCharsToInsert + "\n" ;
end _line _sel -- ;
}
_replaceSelection ( cm , false , [ repl _start , repl _end ] ) ;
cm . setSelection ( {
line : start _line _sel ,
ch : 0
} , {
line : end _line _sel ,
ch : 0
} ) ;
}
var cm = editor . codemirror ,
cur _start = cm . getCursor ( "start" ) ,
cur _end = cm . getCursor ( "end" ) ,
tok = cm . getTokenAt ( {
line : cur _start . line ,
ch : cur _start . ch || 1
} ) , // avoid ch 0 which is a cursor pos but not token
line = cm . getLineHandle ( cur _start . line ) ,
is _code = code _type ( cm , cur _start . line , line , tok ) ;
var block _start , block _end , lineCount ;
if ( is _code === "single" ) {
// similar to some SimpleMDE _toggleBlock logic
var start = line . text . slice ( 0 , cur _start . ch ) . replace ( "`" , "" ) ,
end = line . text . slice ( cur _start . ch ) . replace ( "`" , "" ) ;
cm . replaceRange ( start + end , {
line : cur _start . line ,
ch : 0
} , {
line : cur _start . line ,
ch : 99999999999999
} ) ;
cur _start . ch -- ;
if ( cur _start !== cur _end ) {
cur _end . ch -- ;
}
cm . setSelection ( cur _start , cur _end ) ;
cm . focus ( ) ;
} else if ( is _code === "fenced" ) {
if ( cur _start . line !== cur _end . line || cur _start . ch !== cur _end . ch ) {
// use selection
// find the fenced line so we know what type it is (tilde, backticks, number of them)
for ( block _start = cur _start . line ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
var fencedTok = cm . getTokenAt ( {
line : block _start ,
ch : 1
} ) ;
var fence _chars = token _state ( fencedTok ) . fencedChars ;
var start _text , start _line ;
var end _text , end _line ;
// check for selection going up against fenced lines, in which case we don't want to add more fencing
if ( fencing _line ( cm . getLineHandle ( cur _start . line ) ) ) {
start _text = "" ;
start _line = cur _start . line ;
} else if ( fencing _line ( cm . getLineHandle ( cur _start . line - 1 ) ) ) {
start _text = "" ;
start _line = cur _start . line - 1 ;
} else {
start _text = fence _chars + "\n" ;
start _line = cur _start . line ;
}
if ( fencing _line ( cm . getLineHandle ( cur _end . line ) ) ) {
end _text = "" ;
end _line = cur _end . line ;
if ( cur _end . ch === 0 ) {
end _line += 1 ;
}
} else if ( cur _end . ch !== 0 && fencing _line ( cm . getLineHandle ( cur _end . line + 1 ) ) ) {
end _text = "" ;
end _line = cur _end . line + 1 ;
} else {
end _text = fence _chars + "\n" ;
end _line = cur _end . line + 1 ;
}
if ( cur _end . ch === 0 ) {
// full last line selected, putting cursor at beginning of next
end _line -= 1 ;
}
cm . operation ( function ( ) {
// end line first, so that line numbers don't change
cm . replaceRange ( end _text , {
line : end _line ,
ch : 0
} , {
line : end _line + ( end _text ? 0 : 1 ) ,
ch : 0
} ) ;
cm . replaceRange ( start _text , {
line : start _line ,
ch : 0
} , {
line : start _line + ( start _text ? 0 : 1 ) ,
ch : 0
} ) ;
} ) ;
cm . setSelection ( {
line : start _line + ( start _text ? 1 : 0 ) ,
ch : 0
} , {
line : end _line + ( start _text ? 1 : - 1 ) ,
ch : 0
} ) ;
cm . focus ( ) ;
} else {
// no selection, search for ends of this fenced block
var search _from = cur _start . line ;
if ( fencing _line ( cm . getLineHandle ( cur _start . line ) ) ) { // gets a little tricky if cursor is right on a fenced line
if ( code _type ( cm , cur _start . line + 1 ) === "fenced" ) {
block _start = cur _start . line ;
search _from = cur _start . line + 1 ; // for searching for "end"
} else {
block _end = cur _start . line ;
search _from = cur _start . line - 1 ; // for searching for "start"
}
}
if ( block _start === undefined ) {
for ( block _start = search _from ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
}
if ( block _end === undefined ) {
lineCount = cm . lineCount ( ) ;
for ( block _end = search _from ; block _end < lineCount ; block _end ++ ) {
line = cm . getLineHandle ( block _end ) ;
if ( fencing _line ( line ) ) {
break ;
}
}
}
cm . operation ( function ( ) {
cm . replaceRange ( "" , {
line : block _start ,
ch : 0
} , {
line : block _start + 1 ,
ch : 0
} ) ;
cm . replaceRange ( "" , {
line : block _end - 1 ,
ch : 0
} , {
line : block _end ,
ch : 0
} ) ;
} ) ;
cm . focus ( ) ;
}
} else if ( is _code === "indented" ) {
if ( cur _start . line !== cur _end . line || cur _start . ch !== cur _end . ch ) {
// use selection
block _start = cur _start . line ;
block _end = cur _end . line ;
if ( cur _end . ch === 0 ) {
block _end -- ;
}
} else {
// no selection, search for ends of this indented block
for ( block _start = cur _start . line ; block _start >= 0 ; block _start -- ) {
line = cm . getLineHandle ( block _start ) ;
if ( line . text . match ( /^\s*$/ ) ) {
// empty or all whitespace - keep going
continue ;
} else {
if ( code _type ( cm , block _start , line ) !== "indented" ) {
block _start += 1 ;
break ;
}
}
}
lineCount = cm . lineCount ( ) ;
for ( block _end = cur _start . line ; block _end < lineCount ; block _end ++ ) {
line = cm . getLineHandle ( block _end ) ;
if ( line . text . match ( /^\s*$/ ) ) {
// empty or all whitespace - keep going
continue ;
} else {
if ( code _type ( cm , block _end , line ) !== "indented" ) {
block _end -= 1 ;
break ;
}
}
}
}
// if we are going to un-indent based on a selected set of lines, and the next line is indented too, we need to
// insert a blank line so that the next line(s) continue to be indented code
var next _line = cm . getLineHandle ( block _end + 1 ) ,
next _line _last _tok = next _line && cm . getTokenAt ( {
line : block _end + 1 ,
ch : next _line . text . length - 1
} ) ,
next _line _indented = next _line _last _tok && token _state ( next _line _last _tok ) . indentedCode ;
if ( next _line _indented ) {
cm . replaceRange ( "\n" , {
line : block _end + 1 ,
ch : 0
} ) ;
}
for ( var i = block _start ; i <= block _end ; i ++ ) {
cm . indentLine ( i , "subtract" ) ; // TODO: this doesn't get tracked in the history, so can't be undone :(
}
cm . focus ( ) ;
} else {
// insert code formatting
var no _sel _and _starting _of _line = ( cur _start . line === cur _end . line && cur _start . ch === cur _end . ch && cur _start . ch === 0 ) ;
var sel _multi = cur _start . line !== cur _end . line ;
if ( no _sel _and _starting _of _line || sel _multi ) {
insertFencingAtSelection ( cm , cur _start , cur _end , fenceCharsToInsert ) ;
} else {
_replaceSelection ( cm , false , [ "`" , "`" ] ) ;
}
}
}
/ * *
* Action for toggling blockquote .
* /
function toggleBlockquote ( editor ) {
var cm = editor . codemirror ;
_toggleLine ( cm , "quote" ) ;
}
/ * *
* Action for toggling heading size : normal - > h1 - > h2 - > h3 - > h4 - > h5 - > h6 - > normal
* /
function toggleHeadingSmaller ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , "smaller" ) ;
}
/ * *
* Action for toggling heading size : normal - > h6 - > h5 - > h4 - > h3 - > h2 - > h1 - > normal
* /
function toggleHeadingBigger ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , "bigger" ) ;
}
/ * *
* Action for toggling heading size 1
* /
function toggleHeading1 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 1 ) ;
}
/ * *
* Action for toggling heading size 2
* /
function toggleHeading2 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 2 ) ;
}
/ * *
* Action for toggling heading size 3
* /
function toggleHeading3 ( editor ) {
var cm = editor . codemirror ;
_toggleHeading ( cm , undefined , 3 ) ;
}
/ * *
* Action for toggling ul .
* /
function toggleUnorderedList ( editor ) {
var cm = editor . codemirror ;
_toggleLine ( cm , "unordered-list" ) ;
}
/ * *
* Action for toggling ol .
* /
function toggleOrderedList ( editor ) {
var cm = editor . codemirror ;
_toggleLine ( cm , "ordered-list" ) ;
}
/ * *
* Action for clean block ( remove headline , list , blockquote code , markers )
* /
function cleanBlock ( editor ) {
var cm = editor . codemirror ;
_cleanBlock ( cm ) ;
}
/ * *
* Action for drawing a link .
* /
function drawLink ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var options = editor . options ;
var url = "http://" ;
if ( options . promptURLs ) {
url = prompt ( options . promptTexts . link ) ;
if ( ! url ) {
return false ;
}
}
_replaceSelection ( cm , stat . link , options . insertTexts . link , url ) ;
}
/ * *
* Action for drawing an img .
* /
function drawImage ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var options = editor . options ;
var url = "http://" ;
if ( options . imageURLFn ) {
url = options . imageURLFn ( ) ;
} else if ( options . promptURLs ) {
url = prompt ( options . promptTexts . image ) ;
}
if ( ! url ) {
return false ;
}
_replaceSelection ( cm , stat . image , options . insertTexts . image , url ) ;
}
/ * *
* Action for drawing a table .
* /
function drawTable ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var options = editor . options ;
_replaceSelection ( cm , stat . table , options . insertTexts . table ) ;
}
/ * *
* Action for drawing a horizontal rule .
* /
function drawHorizontalRule ( editor ) {
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var options = editor . options ;
_replaceSelection ( cm , stat . image , options . insertTexts . horizontalRule ) ;
}
/ * *
* Undo action .
* /
function undo ( editor ) {
var cm = editor . codemirror ;
cm . undo ( ) ;
cm . focus ( ) ;
}
/ * *
* Redo action .
* /
function redo ( editor ) {
var cm = editor . codemirror ;
cm . redo ( ) ;
cm . focus ( ) ;
}
/ * *
* Toggle side by side preview
* /
function toggleSideBySide ( editor ) {
var cm = editor . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
var toolbarButton = editor . toolbarElements [ "side-by-side" ] ;
var useSideBySideListener = false ;
if ( /editor-preview-active-side/ . test ( preview . className ) ) {
preview . className = preview . className . replace (
/\s*editor-preview-active-side\s*/g , ""
) ;
toolbarButton . className = toolbarButton . className . replace ( /\s*active\s*/g , "" ) ;
wrapper . className = wrapper . className . replace ( /\s*CodeMirror-sided\s*/g , " " ) ;
} else {
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
setTimeout ( function ( ) {
if ( ! cm . getOption ( "fullScreen" ) )
toggleFullScreen ( editor ) ;
preview . className += " editor-preview-active-side" ;
} , 1 ) ;
toolbarButton . className += " active" ;
wrapper . className += " CodeMirror-sided" ;
useSideBySideListener = true ;
}
// Hide normal preview if active
var previewNormal = wrapper . lastChild ;
if ( /editor-preview-active/ . test ( previewNormal . className ) ) {
previewNormal . className = previewNormal . className . replace (
/\s*editor-preview-active\s*/g , ""
) ;
var toolbar = editor . toolbarElements . preview ;
var toolbar _div = wrapper . previousSibling ;
toolbar . className = toolbar . className . replace ( /\s*active\s*/g , "" ) ;
toolbar _div . className = toolbar _div . className . replace ( /\s*disabled-for-preview*/g , "" ) ;
}
var sideBySideRenderingFunction = function ( ) {
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
} ;
if ( ! cm . sideBySideRenderingFunction ) {
cm . sideBySideRenderingFunction = sideBySideRenderingFunction ;
}
if ( useSideBySideListener ) {
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
cm . on ( "update" , cm . sideBySideRenderingFunction ) ;
} else {
cm . off ( "update" , cm . sideBySideRenderingFunction ) ;
}
// Refresh to fix selection being off (#309)
cm . refresh ( ) ;
}
/ * *
* Preview action .
* /
function togglePreview ( editor ) {
var cm = editor . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var toolbar _div = wrapper . previousSibling ;
var toolbar = editor . options . toolbar ? editor . toolbarElements . preview : false ;
var preview = wrapper . lastChild ;
if ( ! preview || ! /editor-preview/ . test ( preview . className ) ) {
preview = document . createElement ( "div" ) ;
preview . className = "editor-preview" ;
wrapper . appendChild ( preview ) ;
}
if ( /editor-preview-active/ . test ( preview . className ) ) {
preview . className = preview . className . replace (
/\s*editor-preview-active\s*/g , ""
) ;
if ( toolbar ) {
toolbar . className = toolbar . className . replace ( /\s*active\s*/g , "" ) ;
toolbar _div . className = toolbar _div . className . replace ( /\s*disabled-for-preview*/g , "" ) ;
}
} else {
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
setTimeout ( function ( ) {
preview . className += " editor-preview-active" ;
} , 1 ) ;
if ( toolbar ) {
toolbar . className += " active" ;
toolbar _div . className += " disabled-for-preview" ;
}
}
preview . innerHTML = editor . options . previewRender ( editor . value ( ) , preview ) ;
// Turn off side by side if needed
var sidebyside = cm . getWrapperElement ( ) . nextSibling ;
if ( /editor-preview-active-side/ . test ( sidebyside . className ) )
toggleSideBySide ( editor ) ;
}
function _replaceSelection ( cm , active , startEnd , url ) {
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
var text ;
var start = startEnd [ 0 ] ;
var end = startEnd [ 1 ] ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
if ( url ) {
end = end . replace ( "#url#" , url ) ;
}
if ( active ) {
text = cm . getLine ( startPoint . line ) ;
start = text . slice ( 0 , startPoint . ch ) ;
end = text . slice ( startPoint . ch ) ;
cm . replaceRange ( start + end , {
line : startPoint . line ,
ch : 0
} ) ;
} else {
text = cm . getSelection ( ) ;
cm . replaceSelection ( start + text + end ) ;
startPoint . ch += start . length ;
if ( startPoint !== endPoint ) {
endPoint . ch += start . length ;
}
}
cm . setSelection ( startPoint , endPoint ) ;
cm . focus ( ) ;
}
function _toggleHeading ( cm , direction , size ) {
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
for ( var i = startPoint . line ; i <= endPoint . line ; i ++ ) {
( function ( i ) {
var text = cm . getLine ( i ) ;
var currHeadingLevel = text . search ( /[^#]/ ) ;
if ( direction !== undefined ) {
if ( currHeadingLevel <= 0 ) {
if ( direction == "bigger" ) {
text = "###### " + text ;
} else {
text = "# " + text ;
}
} else if ( currHeadingLevel == 6 && direction == "smaller" ) {
text = text . substr ( 7 ) ;
} else if ( currHeadingLevel == 1 && direction == "bigger" ) {
text = text . substr ( 2 ) ;
} else {
if ( direction == "bigger" ) {
text = text . substr ( 1 ) ;
} else {
text = "#" + text ;
}
}
} else {
if ( size == 1 ) {
if ( currHeadingLevel <= 0 ) {
text = "# " + text ;
} else if ( currHeadingLevel == size ) {
text = text . substr ( currHeadingLevel + 1 ) ;
} else {
text = "# " + text . substr ( currHeadingLevel + 1 ) ;
}
} else if ( size == 2 ) {
if ( currHeadingLevel <= 0 ) {
text = "## " + text ;
} else if ( currHeadingLevel == size ) {
text = text . substr ( currHeadingLevel + 1 ) ;
} else {
text = "## " + text . substr ( currHeadingLevel + 1 ) ;
}
} else {
if ( currHeadingLevel <= 0 ) {
text = "### " + text ;
} else if ( currHeadingLevel == size ) {
text = text . substr ( currHeadingLevel + 1 ) ;
} else {
text = "### " + text . substr ( currHeadingLevel + 1 ) ;
}
}
}
cm . replaceRange ( text , {
line : i ,
ch : 0
} , {
line : i ,
ch : 99999999999999
} ) ;
} ) ( i ) ;
}
cm . focus ( ) ;
}
function _toggleLine ( cm , name ) {
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
var stat = getState ( cm ) ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
var repl = {
"quote" : /^(\s*)\>\s+/ ,
"unordered-list" : /^(\s*)(\*|\-|\+)\s+/ ,
"ordered-list" : /^(\s*)\d+\.\s+/
} ;
var map = {
"quote" : "> " ,
"unordered-list" : "* " ,
"ordered-list" : "1. "
} ;
for ( var i = startPoint . line ; i <= endPoint . line ; i ++ ) {
( function ( i ) {
var text = cm . getLine ( i ) ;
if ( stat [ name ] ) {
text = text . replace ( repl [ name ] , "$1" ) ;
} else {
text = map [ name ] + text ;
}
cm . replaceRange ( text , {
line : i ,
ch : 0
} , {
line : i ,
ch : 99999999999999
} ) ;
} ) ( i ) ;
}
cm . focus ( ) ;
}
function _toggleBlock ( editor , type , start _chars , end _chars ) {
if ( /editor-preview-active/ . test ( editor . codemirror . getWrapperElement ( ) . lastChild . className ) )
return ;
end _chars = ( typeof end _chars === "undefined" ) ? start _chars : end _chars ;
var cm = editor . codemirror ;
var stat = getState ( cm ) ;
var text ;
var start = start _chars ;
var end = end _chars ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
if ( stat [ type ] ) {
text = cm . getLine ( startPoint . line ) ;
start = text . slice ( 0 , startPoint . ch ) ;
end = text . slice ( startPoint . ch ) ;
if ( type == "bold" ) {
start = start . replace ( /(\*\*|__)(?![\s\S]*(\*\*|__))/ , "" ) ;
end = end . replace ( /(\*\*|__)/ , "" ) ;
} else if ( type == "italic" ) {
start = start . replace ( /(\*|_)(?![\s\S]*(\*|_))/ , "" ) ;
end = end . replace ( /(\*|_)/ , "" ) ;
} else if ( type == "strikethrough" ) {
start = start . replace ( /(\*\*|~~)(?![\s\S]*(\*\*|~~))/ , "" ) ;
end = end . replace ( /(\*\*|~~)/ , "" ) ;
}
cm . replaceRange ( start + end , {
line : startPoint . line ,
ch : 0
} , {
line : startPoint . line ,
ch : 99999999999999
} ) ;
if ( type == "bold" || type == "strikethrough" ) {
startPoint . ch -= 2 ;
if ( startPoint !== endPoint ) {
endPoint . ch -= 2 ;
}
} else if ( type == "italic" ) {
startPoint . ch -= 1 ;
if ( startPoint !== endPoint ) {
endPoint . ch -= 1 ;
}
}
} else {
text = cm . getSelection ( ) ;
if ( type == "bold" ) {
text = text . split ( "**" ) . join ( "" ) ;
text = text . split ( "__" ) . join ( "" ) ;
} else if ( type == "italic" ) {
text = text . split ( "*" ) . join ( "" ) ;
text = text . split ( "_" ) . join ( "" ) ;
} else if ( type == "strikethrough" ) {
text = text . split ( "~~" ) . join ( "" ) ;
}
cm . replaceSelection ( start + text + end ) ;
startPoint . ch += start _chars . length ;
endPoint . ch = startPoint . ch + text . length ;
}
cm . setSelection ( startPoint , endPoint ) ;
cm . focus ( ) ;
}
function _cleanBlock ( cm ) {
if ( /editor-preview-active/ . test ( cm . getWrapperElement ( ) . lastChild . className ) )
return ;
var startPoint = cm . getCursor ( "start" ) ;
var endPoint = cm . getCursor ( "end" ) ;
var text ;
for ( var line = startPoint . line ; line <= endPoint . line ; line ++ ) {
text = cm . getLine ( line ) ;
text = text . replace ( /^[ ]*([# ]+|\*|\-|[> ]+|[0-9]+(.|\)))[ ]*/ , "" ) ;
cm . replaceRange ( text , {
line : line ,
ch : 0
} , {
line : line ,
ch : 99999999999999
} ) ;
}
}
// Merge the properties of one object into another.
function _mergeProperties ( target , source ) {
for ( var property in source ) {
if ( source . hasOwnProperty ( property ) ) {
if ( source [ property ] instanceof Array ) {
target [ property ] = source [ property ] . concat ( target [ property ] instanceof Array ? target [ property ] : [ ] ) ;
} else if (
source [ property ] !== null &&
typeof source [ property ] === "object" &&
source [ property ] . constructor === Object
) {
target [ property ] = _mergeProperties ( target [ property ] || { } , source [ property ] ) ;
} else {
target [ property ] = source [ property ] ;
}
}
}
return target ;
}
// Merge an arbitrary number of objects into one.
function extend ( target ) {
for ( var i = 1 ; i < arguments . length ; i ++ ) {
target = _mergeProperties ( target , arguments [ i ] ) ;
}
return target ;
}
/* The right word count in respect for CJK. */
function wordCount ( data ) {
var pattern = /[a-zA-Z0-9_\u0392-\u03c9\u0410-\u04F9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g ;
var m = data . match ( pattern ) ;
var count = 0 ;
if ( m === null ) return count ;
for ( var i = 0 ; i < m . length ; i ++ ) {
if ( m [ i ] . charCodeAt ( 0 ) >= 0x4E00 ) {
count += m [ i ] . length ;
} else {
count += 1 ;
}
}
return count ;
}
var toolbarBuiltInButtons = {
"bold" : {
name : "bold" ,
action : toggleBold ,
className : "fa fa-bold" ,
title : "Bold" ,
default : true
} ,
"italic" : {
name : "italic" ,
action : toggleItalic ,
className : "fa fa-italic" ,
title : "Italic" ,
default : true
} ,
"strikethrough" : {
name : "strikethrough" ,
action : toggleStrikethrough ,
className : "fa fa-strikethrough" ,
title : "Strikethrough"
} ,
"heading" : {
name : "heading" ,
action : toggleHeadingSmaller ,
className : "fa fa-header" ,
title : "Heading" ,
default : true
} ,
"heading-smaller" : {
name : "heading-smaller" ,
action : toggleHeadingSmaller ,
className : "fa fa-header fa-header-x fa-header-smaller" ,
title : "Smaller Heading"
} ,
"heading-bigger" : {
name : "heading-bigger" ,
action : toggleHeadingBigger ,
className : "fa fa-header fa-header-x fa-header-bigger" ,
title : "Bigger Heading"
} ,
"heading-1" : {
name : "heading-1" ,
action : toggleHeading1 ,
className : "fa fa-header fa-header-x fa-header-1" ,
title : "Big Heading"
} ,
"heading-2" : {
name : "heading-2" ,
action : toggleHeading2 ,
className : "fa fa-header fa-header-x fa-header-2" ,
title : "Medium Heading"
} ,
"heading-3" : {
name : "heading-3" ,
action : toggleHeading3 ,
className : "fa fa-header fa-header-x fa-header-3" ,
title : "Small Heading"
} ,
"separator-1" : {
name : "separator-1"
} ,
"code" : {
name : "code" ,
action : toggleCodeBlock ,
className : "fa fa-code" ,
title : "Code"
} ,
"quote" : {
name : "quote" ,
action : toggleBlockquote ,
className : "fa fa-quote-left" ,
title : "Quote" ,
default : true
} ,
"unordered-list" : {
name : "unordered-list" ,
action : toggleUnorderedList ,
className : "fa fa-list-ul" ,
title : "Generic List" ,
default : true
} ,
"ordered-list" : {
name : "ordered-list" ,
action : toggleOrderedList ,
className : "fa fa-list-ol" ,
title : "Numbered List" ,
default : true
} ,
"clean-block" : {
name : "clean-block" ,
action : cleanBlock ,
className : "fa fa-eraser fa-clean-block" ,
title : "Clean block"
} ,
"separator-2" : {
name : "separator-2"
} ,
"link" : {
name : "link" ,
action : drawLink ,
className : "fa fa-link" ,
title : "Create Link" ,
default : true
} ,
"image" : {
name : "image" ,
action : drawImage ,
className : "fa fa-picture-o" ,
title : "Insert Image" ,
default : true
} ,
"table" : {
name : "table" ,
action : drawTable ,
className : "fa fa-table" ,
title : "Insert Table"
} ,
"horizontal-rule" : {
name : "horizontal-rule" ,
action : drawHorizontalRule ,
className : "fa fa-minus" ,
title : "Insert Horizontal Line"
} ,
"separator-3" : {
name : "separator-3"
} ,
"preview" : {
name : "preview" ,
action : togglePreview ,
className : "fa fa-eye no-disable" ,
title : "Toggle Preview" ,
default : true
} ,
"side-by-side" : {
name : "side-by-side" ,
action : toggleSideBySide ,
className : "fa fa-columns no-disable no-mobile" ,
title : "Toggle Side by Side" ,
default : true
} ,
"fullscreen" : {
name : "fullscreen" ,
action : toggleFullScreen ,
className : "fa fa-arrows-alt no-disable no-mobile" ,
title : "Toggle Fullscreen" ,
default : true
} ,
"separator-4" : {
name : "separator-4"
} ,
"guide" : {
name : "guide" ,
action : "https://simplemde.com/markdown-guide" ,
className : "fa fa-question-circle" ,
title : "Markdown Guide" ,
default : true
} ,
"separator-5" : {
name : "separator-5"
} ,
"undo" : {
name : "undo" ,
action : undo ,
className : "fa fa-undo no-disable" ,
title : "Undo"
} ,
"redo" : {
name : "redo" ,
action : redo ,
className : "fa fa-repeat no-disable" ,
title : "Redo"
}
} ;
var insertTexts = {
link : [ "[" , "](#url#)" ] ,
image : [ "![](" , "#url#)" ] ,
table : [ "" , "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n" ] ,
horizontalRule : [ "" , "\n\n-----\n\n" ]
} ;
var promptTexts = {
link : "URL for the link:" ,
image : "URL of the image:"
} ;
var blockStyles = {
"bold" : "**" ,
"code" : "```" ,
"italic" : "*"
} ;
/ * *
* Interface of SimpleMDE .
* /
function SimpleMDE ( options ) {
// Handle options parameter
options = options || { } ;
// Used later to refer to it"s parent
options . parent = this ;
// Check if Font Awesome needs to be auto downloaded
var autoDownloadFA = true ;
if ( options . autoDownloadFontAwesome === false ) {
autoDownloadFA = false ;
}
if ( options . autoDownloadFontAwesome !== true ) {
var styleSheets = document . styleSheets ;
for ( var i = 0 ; i < styleSheets . length ; i ++ ) {
if ( ! styleSheets [ i ] . href )
continue ;
if ( styleSheets [ i ] . href . indexOf ( "//maxcdn.bootstrapcdn.com/font-awesome/" ) > - 1 ) {
autoDownloadFA = false ;
}
}
}
if ( autoDownloadFA ) {
var link = document . createElement ( "link" ) ;
link . rel = "stylesheet" ;
link . href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" ;
document . getElementsByTagName ( "head" ) [ 0 ] . appendChild ( link ) ;
}
// Find the textarea to use
if ( options . element ) {
this . element = options . element ;
} else if ( options . element === null ) {
// This means that the element option was specified, but no element was found
console . log ( "SimpleMDE: Error. No element was found." ) ;
return ;
}
// Handle toolbar
if ( options . toolbar === undefined ) {
// Initialize
options . toolbar = [ ] ;
// Loop over the built in buttons, to get the preferred order
for ( var key in toolbarBuiltInButtons ) {
if ( toolbarBuiltInButtons . hasOwnProperty ( key ) ) {
if ( key . indexOf ( "separator-" ) != - 1 ) {
options . toolbar . push ( "|" ) ;
}
if ( toolbarBuiltInButtons [ key ] . default === true || ( options . showIcons && options . showIcons . constructor === Array && options . showIcons . indexOf ( key ) != - 1 ) ) {
options . toolbar . push ( key ) ;
}
}
}
}
// Handle status bar
if ( ! options . hasOwnProperty ( "status" ) ) {
options . status = [ "autosave" , "lines" , "words" , "cursor" ] ;
}
// Add default preview rendering function
if ( ! options . previewRender ) {
options . previewRender = function ( plainText ) {
// Note: "this" refers to the options object
return this . parent . markdown ( plainText ) ;
} ;
}
// Set default options for parsing config
options . parsingConfig = extend ( {
highlightFormatting : true // needed for toggleCodeBlock to detect types of code
} , options . parsingConfig || { } ) ;
// Merging the insertTexts, with the given options
options . insertTexts = extend ( { } , insertTexts , options . insertTexts || { } ) ;
// Merging the promptTexts, with the given options
options . promptTexts = promptTexts ;
// Merging the blockStyles, with the given options
options . blockStyles = extend ( { } , blockStyles , options . blockStyles || { } ) ;
// Merging the shortcuts, with the given options
options . shortcuts = extend ( { } , shortcuts , options . shortcuts || { } ) ;
// Change unique_id to uniqueId for backwards compatibility
if ( options . autosave != undefined && options . autosave . unique _id != undefined && options . autosave . unique _id != "" )
options . autosave . uniqueId = options . autosave . unique _id ;
// Update this options
this . options = options ;
// Auto render
this . render ( ) ;
// The codemirror component is only available after rendering
// so, the setter for the initialValue can only run after
// the element has been rendered
if ( options . initialValue && ( ! this . options . autosave || this . options . autosave . foundSavedValue !== true ) ) {
this . value ( options . initialValue ) ;
}
}
/ * *
* Default markdown render .
* /
SimpleMDE . prototype . markdown = function ( text ) {
if ( marked ) {
// Initialize
var markedOptions = { } ;
// Update options
if ( this . options && this . options . renderingConfig && this . options . renderingConfig . singleLineBreaks === false ) {
markedOptions . breaks = false ;
} else {
markedOptions . breaks = true ;
}
if ( this . options && this . options . renderingConfig && this . options . renderingConfig . codeSyntaxHighlighting === true && window . hljs ) {
markedOptions . highlight = function ( code ) {
return window . hljs . highlightAuto ( code ) . value ;
} ;
}
// Set options
marked . setOptions ( markedOptions ) ;
// Return
return marked ( text ) ;
}
} ;
/ * *
* Render editor to the given element .
* /
SimpleMDE . prototype . render = function ( el ) {
if ( ! el ) {
el = this . element || document . getElementsByTagName ( "textarea" ) [ 0 ] ;
}
if ( this . _rendered && this . _rendered === el ) {
// Already rendered.
return ;
}
this . element = el ;
var options = this . options ;
var self = this ;
var keyMaps = { } ;
for ( var key in options . shortcuts ) {
// null stands for "do not bind this command"
if ( options . shortcuts [ key ] !== null && bindings [ key ] !== null ) {
( function ( key ) {
keyMaps [ fixShortcut ( options . shortcuts [ key ] ) ] = function ( ) {
bindings [ key ] ( self ) ;
} ;
} ) ( key ) ;
}
}
keyMaps [ "Enter" ] = "newlineAndIndentContinueMarkdownList" ;
keyMaps [ "Tab" ] = "tabAndIndentMarkdownList" ;
keyMaps [ "Shift-Tab" ] = "shiftTabAndUnindentMarkdownList" ;
keyMaps [ "Esc" ] = function ( cm ) {
if ( cm . getOption ( "fullScreen" ) ) toggleFullScreen ( self ) ;
} ;
document . addEventListener ( "keydown" , function ( e ) {
e = e || window . event ;
if ( e . keyCode == 27 ) {
if ( self . codemirror . getOption ( "fullScreen" ) ) toggleFullScreen ( self ) ;
}
} , false ) ;
var mode , backdrop ;
if ( options . spellChecker !== false ) {
mode = "spell-checker" ;
backdrop = options . parsingConfig ;
backdrop . name = "gfm" ;
backdrop . gitHubSpice = false ;
CodeMirrorSpellChecker ( {
codeMirrorInstance : CodeMirror
} ) ;
} else {
mode = options . parsingConfig ;
mode . name = "gfm" ;
mode . gitHubSpice = false ;
}
this . codemirror = CodeMirror . fromTextArea ( el , {
mode : mode ,
backdrop : backdrop ,
theme : "paper" ,
tabSize : ( options . tabSize != undefined ) ? options . tabSize : 2 ,
indentUnit : ( options . tabSize != undefined ) ? options . tabSize : 2 ,
indentWithTabs : ( options . indentWithTabs === false ) ? false : true ,
lineNumbers : false ,
autofocus : ( options . autofocus === true ) ? true : false ,
extraKeys : keyMaps ,
lineWrapping : ( options . lineWrapping === false ) ? false : true ,
allowDropFileTypes : [ "text/plain" ] ,
placeholder : options . placeholder || el . getAttribute ( "placeholder" ) || "" ,
styleSelectedText : ( options . styleSelectedText != undefined ) ? options . styleSelectedText : true
} ) ;
this . codemirror . changeEnd = CodeMirror . changeEnd ;
if ( options . forceSync === true ) {
var cm = this . codemirror ;
cm . on ( "change" , function ( ) {
cm . save ( ) ;
} ) ;
}
this . gui = { } ;
if ( options . toolbar !== false ) {
this . gui . toolbar = this . createToolbar ( ) ;
}
if ( options . status !== false ) {
this . gui . statusbar = this . createStatusbar ( ) ;
}
if ( options . autosave != undefined && options . autosave . enabled === true ) {
this . autosave ( ) ;
}
this . gui . sideBySide = this . createSideBySide ( ) ;
this . _rendered = this . element ;
// Fixes CodeMirror bug (#344)
var temp _cm = this . codemirror ;
setTimeout ( function ( ) {
temp _cm . refresh ( ) ;
} . bind ( temp _cm ) , 0 ) ;
} ;
// Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem throw QuotaExceededError. We're going to detect this and set a variable accordingly.
function isLocalStorageAvailable ( ) {
if ( typeof localStorage === "object" ) {
try {
localStorage . setItem ( "smde_localStorage" , 1 ) ;
localStorage . removeItem ( "smde_localStorage" ) ;
} catch ( e ) {
return false ;
}
} else {
return false ;
}
return true ;
}
SimpleMDE . prototype . autosave = function ( ) {
if ( isLocalStorageAvailable ( ) ) {
var simplemde = this ;
if ( this . options . autosave . uniqueId == undefined || this . options . autosave . uniqueId == "" ) {
console . log ( "SimpleMDE: You must set a uniqueId to use the autosave feature" ) ;
return ;
}
if ( simplemde . element . form != null && simplemde . element . form != undefined ) {
simplemde . element . form . addEventListener ( "submit" , function ( ) {
localStorage . removeItem ( "smde_" + simplemde . options . autosave . uniqueId ) ;
} ) ;
}
if ( this . options . autosave . loaded !== true ) {
if ( typeof localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) == "string" && localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) != "" ) {
this . codemirror . setValue ( localStorage . getItem ( "smde_" + this . options . autosave . uniqueId ) ) ;
this . options . autosave . foundSavedValue = true ;
}
this . options . autosave . loaded = true ;
}
localStorage . setItem ( "smde_" + this . options . autosave . uniqueId , simplemde . value ( ) ) ;
var el = document . getElementById ( "autosaved" ) ;
if ( el != null && el != undefined && el != "" ) {
var d = new Date ( ) ;
var hh = d . getHours ( ) ;
var m = d . getMinutes ( ) ;
var dd = "am" ;
var h = hh ;
if ( h >= 12 ) {
h = hh - 12 ;
dd = "pm" ;
}
if ( h == 0 ) {
h = 12 ;
}
m = m < 10 ? "0" + m : m ;
el . innerHTML = "Autosaved: " + h + ":" + m + " " + dd ;
}
this . autosaveTimeoutId = setTimeout ( function ( ) {
simplemde . autosave ( ) ;
} , this . options . autosave . delay || 10000 ) ;
} else {
console . log ( "SimpleMDE: localStorage not available, cannot autosave" ) ;
}
} ;
SimpleMDE . prototype . clearAutosavedValue = function ( ) {
if ( isLocalStorageAvailable ( ) ) {
if ( this . options . autosave == undefined || this . options . autosave . uniqueId == undefined || this . options . autosave . uniqueId == "" ) {
console . log ( "SimpleMDE: You must set a uniqueId to clear the autosave value" ) ;
return ;
}
localStorage . removeItem ( "smde_" + this . options . autosave . uniqueId ) ;
} else {
console . log ( "SimpleMDE: localStorage not available, cannot autosave" ) ;
}
} ;
SimpleMDE . prototype . createSideBySide = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
if ( ! preview || ! /editor-preview-side/ . test ( preview . className ) ) {
preview = document . createElement ( "div" ) ;
preview . className = "editor-preview-side" ;
wrapper . parentNode . insertBefore ( preview , wrapper . nextSibling ) ;
}
// Syncs scroll editor -> preview
var cScroll = false ;
var pScroll = false ;
cm . on ( "scroll" , function ( v ) {
if ( cScroll ) {
cScroll = false ;
return ;
}
pScroll = true ;
var height = v . getScrollInfo ( ) . height - v . getScrollInfo ( ) . clientHeight ;
var ratio = parseFloat ( v . getScrollInfo ( ) . top ) / height ;
var move = ( preview . scrollHeight - preview . clientHeight ) * ratio ;
preview . scrollTop = move ;
} ) ;
// Syncs scroll preview -> editor
preview . onscroll = function ( ) {
if ( pScroll ) {
pScroll = false ;
return ;
}
cScroll = true ;
var height = preview . scrollHeight - preview . clientHeight ;
var ratio = parseFloat ( preview . scrollTop ) / height ;
var move = ( cm . getScrollInfo ( ) . height - cm . getScrollInfo ( ) . clientHeight ) * ratio ;
cm . scrollTo ( 0 , move ) ;
} ;
return preview ;
} ;
SimpleMDE . prototype . createToolbar = function ( items ) {
items = items || this . options . toolbar ;
if ( ! items || items . length === 0 ) {
return ;
}
var i ;
for ( i = 0 ; i < items . length ; i ++ ) {
if ( toolbarBuiltInButtons [ items [ i ] ] != undefined ) {
items [ i ] = toolbarBuiltInButtons [ items [ i ] ] ;
}
}
var bar = document . createElement ( "div" ) ;
bar . className = "editor-toolbar" ;
var self = this ;
var toolbarData = { } ;
self . toolbar = items ;
for ( i = 0 ; i < items . length ; i ++ ) {
if ( items [ i ] . name == "guide" && self . options . toolbarGuideIcon === false )
continue ;
if ( self . options . hideIcons && self . options . hideIcons . indexOf ( items [ i ] . name ) != - 1 )
continue ;
// Fullscreen does not work well on mobile devices (even tablets)
// In the future, hopefully this can be resolved
if ( ( items [ i ] . name == "fullscreen" || items [ i ] . name == "side-by-side" ) && isMobile ( ) )
continue ;
// Don't include trailing separators
if ( items [ i ] === "|" ) {
var nonSeparatorIconsFollow = false ;
for ( var x = ( i + 1 ) ; x < items . length ; x ++ ) {
if ( items [ x ] !== "|" && ( ! self . options . hideIcons || self . options . hideIcons . indexOf ( items [ x ] . name ) == - 1 ) ) {
nonSeparatorIconsFollow = true ;
}
}
if ( ! nonSeparatorIconsFollow )
continue ;
}
// Create the icon and append to the toolbar
( function ( item ) {
var el ;
if ( item === "|" ) {
el = createSep ( ) ;
} else {
el = createIcon ( item , self . options . toolbarTips , self . options . shortcuts ) ;
}
// bind events, special for info
if ( item . action ) {
if ( typeof item . action === "function" ) {
el . onclick = function ( e ) {
e . preventDefault ( ) ;
item . action ( self ) ;
} ;
} else if ( typeof item . action === "string" ) {
el . href = item . action ;
el . target = "_blank" ;
}
}
toolbarData [ item . name || item ] = el ;
bar . appendChild ( el ) ;
} ) ( items [ i ] ) ;
}
self . toolbarElements = toolbarData ;
var cm = this . codemirror ;
cm . on ( "cursorActivity" , function ( ) {
var stat = getState ( cm ) ;
for ( var key in toolbarData ) {
( function ( key ) {
var el = toolbarData [ key ] ;
if ( stat [ key ] ) {
el . className += " active" ;
} else if ( key != "fullscreen" && key != "side-by-side" ) {
el . className = el . className . replace ( /\s*active\s*/g , "" ) ;
}
} ) ( key ) ;
}
} ) ;
var cmWrapper = cm . getWrapperElement ( ) ;
cmWrapper . parentNode . insertBefore ( bar , cmWrapper ) ;
return bar ;
} ;
SimpleMDE . prototype . createStatusbar = function ( status ) {
// Initialize
status = status || this . options . status ;
var options = this . options ;
var cm = this . codemirror ;
// Make sure the status variable is valid
if ( ! status || status . length === 0 )
return ;
// Set up the built-in items
var items = [ ] ;
var i , onUpdate , defaultValue ;
for ( i = 0 ; i < status . length ; i ++ ) {
// Reset some values
onUpdate = undefined ;
defaultValue = undefined ;
// Handle if custom or not
if ( typeof status [ i ] === "object" ) {
items . push ( {
className : status [ i ] . className ,
defaultValue : status [ i ] . defaultValue ,
onUpdate : status [ i ] . onUpdate
} ) ;
} else {
var name = status [ i ] ;
if ( name === "words" ) {
defaultValue = function ( el ) {
el . innerHTML = wordCount ( cm . getValue ( ) ) ;
} ;
onUpdate = function ( el ) {
el . innerHTML = wordCount ( cm . getValue ( ) ) ;
} ;
} else if ( name === "lines" ) {
defaultValue = function ( el ) {
el . innerHTML = cm . lineCount ( ) ;
} ;
onUpdate = function ( el ) {
el . innerHTML = cm . lineCount ( ) ;
} ;
} else if ( name === "cursor" ) {
defaultValue = function ( el ) {
el . innerHTML = "0:0" ;
} ;
onUpdate = function ( el ) {
var pos = cm . getCursor ( ) ;
el . innerHTML = pos . line + ":" + pos . ch ;
} ;
} else if ( name === "autosave" ) {
defaultValue = function ( el ) {
if ( options . autosave != undefined && options . autosave . enabled === true ) {
el . setAttribute ( "id" , "autosaved" ) ;
}
} ;
}
items . push ( {
className : name ,
defaultValue : defaultValue ,
onUpdate : onUpdate
} ) ;
}
}
// Create element for the status bar
var bar = document . createElement ( "div" ) ;
bar . className = "editor-statusbar" ;
// Create a new span for each item
for ( i = 0 ; i < items . length ; i ++ ) {
// Store in temporary variable
var item = items [ i ] ;
// Create span element
var el = document . createElement ( "span" ) ;
el . className = item . className ;
// Ensure the defaultValue is a function
if ( typeof item . defaultValue === "function" ) {
item . defaultValue ( el ) ;
}
// Ensure the onUpdate is a function
if ( typeof item . onUpdate === "function" ) {
// Create a closure around the span of the current action, then execute the onUpdate handler
this . codemirror . on ( "update" , ( function ( el , item ) {
return function ( ) {
item . onUpdate ( el ) ;
} ;
} ( el , item ) ) ) ;
}
// Append the item to the status bar
bar . appendChild ( el ) ;
}
// Insert the status bar into the DOM
var cmWrapper = this . codemirror . getWrapperElement ( ) ;
cmWrapper . parentNode . insertBefore ( bar , cmWrapper . nextSibling ) ;
return bar ;
} ;
/ * *
* Get or set the text content .
* /
SimpleMDE . prototype . value = function ( val ) {
if ( val === undefined ) {
return this . codemirror . getValue ( ) ;
} else {
this . codemirror . getDoc ( ) . setValue ( val ) ;
return this ;
}
} ;
/ * *
* Bind static methods for exports .
* /
SimpleMDE . toggleBold = toggleBold ;
SimpleMDE . toggleItalic = toggleItalic ;
SimpleMDE . toggleStrikethrough = toggleStrikethrough ;
SimpleMDE . toggleBlockquote = toggleBlockquote ;
SimpleMDE . toggleHeadingSmaller = toggleHeadingSmaller ;
SimpleMDE . toggleHeadingBigger = toggleHeadingBigger ;
SimpleMDE . toggleHeading1 = toggleHeading1 ;
SimpleMDE . toggleHeading2 = toggleHeading2 ;
SimpleMDE . toggleHeading3 = toggleHeading3 ;
SimpleMDE . toggleCodeBlock = toggleCodeBlock ;
SimpleMDE . toggleUnorderedList = toggleUnorderedList ;
SimpleMDE . toggleOrderedList = toggleOrderedList ;
SimpleMDE . cleanBlock = cleanBlock ;
SimpleMDE . drawLink = drawLink ;
SimpleMDE . drawImage = drawImage ;
SimpleMDE . drawTable = drawTable ;
SimpleMDE . drawHorizontalRule = drawHorizontalRule ;
SimpleMDE . undo = undo ;
SimpleMDE . redo = redo ;
SimpleMDE . togglePreview = togglePreview ;
SimpleMDE . toggleSideBySide = toggleSideBySide ;
SimpleMDE . toggleFullScreen = toggleFullScreen ;
/ * *
* Bind instance methods for exports .
* /
SimpleMDE . prototype . toggleBold = function ( ) {
toggleBold ( this ) ;
} ;
SimpleMDE . prototype . toggleItalic = function ( ) {
toggleItalic ( this ) ;
} ;
SimpleMDE . prototype . toggleStrikethrough = function ( ) {
toggleStrikethrough ( this ) ;
} ;
SimpleMDE . prototype . toggleBlockquote = function ( ) {
toggleBlockquote ( this ) ;
} ;
SimpleMDE . prototype . toggleHeadingSmaller = function ( ) {
toggleHeadingSmaller ( this ) ;
} ;
SimpleMDE . prototype . toggleHeadingBigger = function ( ) {
toggleHeadingBigger ( this ) ;
} ;
SimpleMDE . prototype . toggleHeading1 = function ( ) {
toggleHeading1 ( this ) ;
} ;
SimpleMDE . prototype . toggleHeading2 = function ( ) {
toggleHeading2 ( this ) ;
} ;
SimpleMDE . prototype . toggleHeading3 = function ( ) {
toggleHeading3 ( this ) ;
} ;
SimpleMDE . prototype . toggleCodeBlock = function ( ) {
toggleCodeBlock ( this ) ;
} ;
SimpleMDE . prototype . toggleUnorderedList = function ( ) {
toggleUnorderedList ( this ) ;
} ;
SimpleMDE . prototype . toggleOrderedList = function ( ) {
toggleOrderedList ( this ) ;
} ;
SimpleMDE . prototype . cleanBlock = function ( ) {
cleanBlock ( this ) ;
} ;
SimpleMDE . prototype . drawLink = function ( ) {
drawLink ( this ) ;
} ;
SimpleMDE . prototype . drawImage = function ( ) {
drawImage ( this ) ;
} ;
SimpleMDE . prototype . drawTable = function ( ) {
drawTable ( this ) ;
} ;
SimpleMDE . prototype . drawHorizontalRule = function ( ) {
drawHorizontalRule ( this ) ;
} ;
SimpleMDE . prototype . undo = function ( ) {
undo ( this ) ;
} ;
SimpleMDE . prototype . redo = function ( ) {
redo ( this ) ;
} ;
SimpleMDE . prototype . togglePreview = function ( ) {
togglePreview ( this ) ;
} ;
SimpleMDE . prototype . toggleSideBySide = function ( ) {
toggleSideBySide ( this ) ;
} ;
SimpleMDE . prototype . toggleFullScreen = function ( ) {
toggleFullScreen ( this ) ;
} ;
SimpleMDE . prototype . isPreviewActive = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . lastChild ;
return /editor-preview-active/ . test ( preview . className ) ;
} ;
SimpleMDE . prototype . isSideBySideActive = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
var preview = wrapper . nextSibling ;
return /editor-preview-active-side/ . test ( preview . className ) ;
} ;
SimpleMDE . prototype . isFullscreenActive = function ( ) {
var cm = this . codemirror ;
return cm . getOption ( "fullScreen" ) ;
} ;
SimpleMDE . prototype . getState = function ( ) {
var cm = this . codemirror ;
return getState ( cm ) ;
} ;
SimpleMDE . prototype . toTextArea = function ( ) {
var cm = this . codemirror ;
var wrapper = cm . getWrapperElement ( ) ;
if ( wrapper . parentNode ) {
if ( this . gui . toolbar ) {
wrapper . parentNode . removeChild ( this . gui . toolbar ) ;
}
if ( this . gui . statusbar ) {
wrapper . parentNode . removeChild ( this . gui . statusbar ) ;
}
if ( this . gui . sideBySide ) {
wrapper . parentNode . removeChild ( this . gui . sideBySide ) ;
}
}
cm . toTextArea ( ) ;
if ( this . autosaveTimeoutId ) {
clearTimeout ( this . autosaveTimeoutId ) ;
this . autosaveTimeoutId = undefined ;
this . clearAutosavedValue ( ) ;
}
} ;
module . exports = SimpleMDE ;
} , { "./codemirror/tablist" : 18 , "codemirror" : 10 , "codemirror-spell-checker" : 4 , "codemirror/addon/display/fullscreen.js" : 5 , "codemirror/addon/display/placeholder.js" : 6 , "codemirror/addon/edit/continuelist.js" : 7 , "codemirror/addon/mode/overlay.js" : 8 , "codemirror/addon/selection/mark-selection.js" : 9 , "codemirror/mode/gfm/gfm.js" : 11 , "codemirror/mode/markdown/markdown.js" : 12 , "codemirror/mode/xml/xml.js" : 14 , "marked" : 16 } ] } , { } , [ 19 ] ) ( 19 )
} ) ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYmFzZTY0LWpzL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2Jyb3dzZXItcmVzb2x2ZS9lbXB0eS5qcyIsIm5vZGVfbW9kdWxlcy9idWZmZXIvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci1zcGVsbC1jaGVja2VyL3NyYy9qcy9zcGVsbC1jaGVja2VyLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvYWRkb24vZGlzcGxheS9mdWxsc2NyZWVuLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvYWRkb24vZGlzcGxheS9wbGFjZWhvbGRlci5qcyIsIm5vZGVfbW9kdWxlcy9jb2RlbWlycm9yL2FkZG9uL2VkaXQvY29udGludWVsaXN0LmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvYWRkb24vbW9kZS9vdmVybGF5LmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvYWRkb24vc2VsZWN0aW9uL21hcmstc2VsZWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbGliL2NvZGVtaXJyb3IuanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci9tb2RlL2dmbS9nZm0uanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci9tb2RlL21hcmtkb3duL21hcmtkb3duLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbW9kZS9tZXRhLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbW9kZS94bWwveG1sLmpzIiwibm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvbWFya2VkL2xpYi9tYXJrZWQuanMiLCJub2RlX21vZHVsZXMvdHlwby1qcy90eXBvLmpzIiwic3JjL2pzL2NvZGVtaXJyb3IvdGFibGlzdC5qcyIsInNyYy9qcy9zaW1wbGVtZGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSEE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUF