2014-07-09 12:59:04 -04:00
"no use strict" ;
; ( function ( window ) {
2015-09-07 12:04:05 -04:00
if ( typeof window . window != "undefined" && window . document )
return ;
if ( window . require && window . define )
2014-07-09 12:59:04 -04:00
return ;
window . console = function ( ) {
var msgs = Array . prototype . slice . call ( arguments , 0 ) ;
postMessage ( { type : "log" , data : msgs } ) ;
} ;
window . console . error =
window . console . warn =
window . console . log =
window . console . trace = window . console ;
window . window = window ;
window . ace = window ;
window . onerror = function ( message , file , line , col , err ) {
2015-02-12 05:36:57 -05:00
postMessage ( { type : "error" , data : {
message : message ,
2015-09-07 12:04:05 -04:00
data : err . data ,
2015-02-12 05:36:57 -05:00
file : file ,
line : line ,
col : col ,
stack : err . stack
} } ) ;
2014-07-09 12:59:04 -04:00
} ;
window . normalizeModule = function ( parentId , moduleName ) {
// normalize plugin requires
if ( moduleName . indexOf ( "!" ) !== - 1 ) {
var chunks = moduleName . split ( "!" ) ;
return window . normalizeModule ( parentId , chunks [ 0 ] ) + "!" + window . normalizeModule ( parentId , chunks [ 1 ] ) ;
}
// normalize relative requires
if ( moduleName . charAt ( 0 ) == "." ) {
var base = parentId . split ( "/" ) . slice ( 0 , - 1 ) . join ( "/" ) ;
moduleName = ( base ? base + "/" : "" ) + moduleName ;
2015-09-07 12:04:05 -04:00
while ( moduleName . indexOf ( "." ) !== - 1 && previous != moduleName ) {
2014-07-09 12:59:04 -04:00
var previous = moduleName ;
moduleName = moduleName . replace ( /^\.\// , "" ) . replace ( /\/\.\// , "/" ) . replace ( /[^\/]+\/\.\.\// , "" ) ;
}
}
return moduleName ;
} ;
2015-09-07 12:04:05 -04:00
window . require = function require ( parentId , id ) {
2014-07-09 12:59:04 -04:00
if ( ! id ) {
id = parentId ;
parentId = null ;
}
if ( ! id . charAt )
throw new Error ( "worker.js require() accepts only (parentId, id) as arguments" ) ;
id = window . normalizeModule ( parentId , id ) ;
var module = window . require . modules [ id ] ;
if ( module ) {
if ( ! module . initialized ) {
module . initialized = true ;
module . exports = module . factory ( ) . exports ;
}
return module . exports ;
}
2015-09-07 12:04:05 -04:00
2014-07-09 12:59:04 -04:00
if ( ! window . require . tlns )
return console . log ( "unable to load " + id ) ;
2015-09-07 12:04:05 -04:00
var path = resolveModuleId ( id , window . require . tlns ) ;
if ( path . slice ( - 3 ) != ".js" ) path += ".js" ;
2014-07-09 12:59:04 -04:00
window . require . id = id ;
2015-09-07 12:04:05 -04:00
window . require . modules [ id ] = { } ; // prevent infinite loop on broken modules
2014-07-09 12:59:04 -04:00
importScripts ( path ) ;
return window . require ( parentId , id ) ;
} ;
2015-09-07 12:04:05 -04:00
function resolveModuleId ( id , paths ) {
var testPath = id , tail = "" ;
while ( testPath ) {
var alias = paths [ testPath ] ;
if ( typeof alias == "string" ) {
return alias + tail ;
} else if ( alias ) {
return alias . location . replace ( /\/*$/ , "/" ) + ( tail || alias . main || alias . name ) ;
} else if ( alias === false ) {
return "" ;
}
var i = testPath . lastIndexOf ( "/" ) ;
if ( i === - 1 ) break ;
tail = testPath . substr ( i ) + tail ;
testPath = testPath . slice ( 0 , i ) ;
}
return id ;
}
2014-07-09 12:59:04 -04:00
window . require . modules = { } ;
window . require . tlns = { } ;
window . define = function ( id , deps , factory ) {
if ( arguments . length == 2 ) {
factory = deps ;
if ( typeof id != "string" ) {
deps = id ;
id = window . require . id ;
}
} else if ( arguments . length == 1 ) {
factory = id ;
deps = [ ] ;
id = window . require . id ;
}
2015-02-12 05:36:57 -05:00
if ( typeof factory != "function" ) {
window . require . modules [ id ] = {
exports : factory ,
initialized : true
} ;
return ;
}
2014-07-09 12:59:04 -04:00
if ( ! deps . length )
2015-09-07 12:04:05 -04:00
// If there is no dependencies, we inject "require", "exports" and
// "module" as dependencies, to provide CommonJS compatibility.
deps = [ "require" , "exports" , "module" ] ;
2014-07-09 12:59:04 -04:00
var req = function ( childId ) {
return window . require ( id , childId ) ;
} ;
window . require . modules [ id ] = {
exports : { } ,
factory : function ( ) {
var module = this ;
var returnExports = factory . apply ( this , deps . map ( function ( dep ) {
2015-09-07 12:04:05 -04:00
switch ( dep ) {
// Because "require", "exports" and "module" aren't actual
// dependencies, we must handle them seperately.
case "require" : return req ;
case "exports" : return module . exports ;
case "module" : return module ;
// But for all other dependencies, we can just go ahead and
// require them.
default : return req ( dep ) ;
}
2014-07-09 12:59:04 -04:00
} ) ) ;
if ( returnExports )
module . exports = returnExports ;
return module ;
}
} ;
} ;
window . define . amd = { } ;
2015-09-07 12:04:05 -04:00
require . tlns = { } ;
2014-07-09 12:59:04 -04:00
window . initBaseUrls = function initBaseUrls ( topLevelNamespaces ) {
2015-09-07 12:04:05 -04:00
for ( var i in topLevelNamespaces )
require . tlns [ i ] = topLevelNamespaces [ i ] ;
2014-07-09 12:59:04 -04:00
} ;
window . initSender = function initSender ( ) {
var EventEmitter = window . require ( "ace/lib/event_emitter" ) . EventEmitter ;
var oop = window . require ( "ace/lib/oop" ) ;
var Sender = function ( ) { } ;
( function ( ) {
oop . implement ( this , EventEmitter ) ;
this . callback = function ( data , callbackId ) {
postMessage ( {
type : "call" ,
id : callbackId ,
data : data
} ) ;
} ;
this . emit = function ( name , data ) {
postMessage ( {
type : "event" ,
name : name ,
data : data
} ) ;
} ;
} ) . call ( Sender . prototype ) ;
return new Sender ( ) ;
} ;
var main = window . main = null ;
var sender = window . sender = null ;
window . onmessage = function ( e ) {
var msg = e . data ;
2015-09-07 12:04:05 -04:00
if ( msg . event && sender ) {
sender . _signal ( msg . event , msg . data ) ;
}
else if ( msg . command ) {
2014-07-09 12:59:04 -04:00
if ( main [ msg . command ] )
main [ msg . command ] . apply ( main , msg . args ) ;
2015-09-07 12:04:05 -04:00
else if ( window [ msg . command ] )
window [ msg . command ] . apply ( window , msg . args ) ;
2014-07-09 12:59:04 -04:00
else
throw new Error ( "Unknown command:" + msg . command ) ;
}
2015-09-07 12:04:05 -04:00
else if ( msg . init ) {
window . initBaseUrls ( msg . tlns ) ;
2014-07-09 12:59:04 -04:00
require ( "ace/lib/es5-shim" ) ;
2015-09-07 12:04:05 -04:00
sender = window . sender = window . initSender ( ) ;
2014-07-09 12:59:04 -04:00
var clazz = require ( msg . module ) [ msg . classname ] ;
main = window . main = new clazz ( sender ) ;
}
} ;
} ) ( this ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/lib/oop" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
exports . inherits = function ( ctor , superCtor ) {
ctor . super _ = superCtor ;
ctor . prototype = Object . create ( superCtor . prototype , {
constructor : {
value : ctor ,
enumerable : false ,
writable : true ,
configurable : true
}
} ) ;
} ;
exports . mixin = function ( obj , mixin ) {
for ( var key in mixin ) {
obj [ key ] = mixin [ key ] ;
}
return obj ;
} ;
exports . implement = function ( proto , mixin ) {
exports . mixin ( proto , mixin ) ;
} ;
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/lib/lang" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
exports . last = function ( a ) {
return a [ a . length - 1 ] ;
} ;
exports . stringReverse = function ( string ) {
return string . split ( "" ) . reverse ( ) . join ( "" ) ;
} ;
exports . stringRepeat = function ( string , count ) {
var result = '' ;
while ( count > 0 ) {
if ( count & 1 )
result += string ;
if ( count >>= 1 )
string += string ;
}
return result ;
} ;
var trimBeginRegexp = /^\s\s*/ ;
var trimEndRegexp = /\s\s*$/ ;
exports . stringTrimLeft = function ( string ) {
return string . replace ( trimBeginRegexp , '' ) ;
} ;
exports . stringTrimRight = function ( string ) {
return string . replace ( trimEndRegexp , '' ) ;
} ;
exports . copyObject = function ( obj ) {
var copy = { } ;
for ( var key in obj ) {
copy [ key ] = obj [ key ] ;
}
return copy ;
} ;
exports . copyArray = function ( array ) {
var copy = [ ] ;
for ( var i = 0 , l = array . length ; i < l ; i ++ ) {
if ( array [ i ] && typeof array [ i ] == "object" )
copy [ i ] = this . copyObject ( array [ i ] ) ;
else
copy [ i ] = array [ i ] ;
}
return copy ;
} ;
2015-09-07 12:04:05 -04:00
exports . deepCopy = function deepCopy ( obj ) {
2014-07-09 12:59:04 -04:00
if ( typeof obj !== "object" || ! obj )
return obj ;
2015-09-07 12:04:05 -04:00
var copy ;
if ( Array . isArray ( obj ) ) {
copy = [ ] ;
for ( var key = 0 ; key < obj . length ; key ++ ) {
copy [ key ] = deepCopy ( obj [ key ] ) ;
}
return copy ;
}
2014-07-09 12:59:04 -04:00
var cons = obj . constructor ;
if ( cons === RegExp )
return obj ;
2015-09-07 12:04:05 -04:00
copy = cons ( ) ;
2014-07-09 12:59:04 -04:00
for ( var key in obj ) {
2015-09-07 12:04:05 -04:00
copy [ key ] = deepCopy ( obj [ key ] ) ;
2014-07-09 12:59:04 -04:00
}
return copy ;
} ;
exports . arrayToMap = function ( arr ) {
var map = { } ;
for ( var i = 0 ; i < arr . length ; i ++ ) {
map [ arr [ i ] ] = 1 ;
}
return map ;
} ;
exports . createMap = function ( props ) {
var map = Object . create ( null ) ;
for ( var i in props ) {
map [ i ] = props [ i ] ;
}
return map ;
} ;
exports . arrayRemove = function ( array , value ) {
for ( var i = 0 ; i <= array . length ; i ++ ) {
if ( value === array [ i ] ) {
array . splice ( i , 1 ) ;
}
}
} ;
exports . escapeRegExp = function ( str ) {
return str . replace ( /([.*+?^${}()|[\]\/\\])/g , '\\$1' ) ;
} ;
exports . escapeHTML = function ( str ) {
return str . replace ( /&/g , "&" ) . replace ( /"/g , """ ) . replace ( /'/g , "'" ) . replace ( /</g , "<" ) ;
} ;
exports . getMatchOffsets = function ( string , regExp ) {
var matches = [ ] ;
string . replace ( regExp , function ( str ) {
matches . push ( {
offset : arguments [ arguments . length - 2 ] ,
length : str . length
} ) ;
} ) ;
return matches ;
} ;
exports . deferredCall = function ( fcn ) {
var timer = null ;
var callback = function ( ) {
timer = null ;
fcn ( ) ;
} ;
var deferred = function ( timeout ) {
deferred . cancel ( ) ;
timer = setTimeout ( callback , timeout || 0 ) ;
return deferred ;
} ;
deferred . schedule = deferred ;
deferred . call = function ( ) {
this . cancel ( ) ;
fcn ( ) ;
return deferred ;
} ;
deferred . cancel = function ( ) {
clearTimeout ( timer ) ;
timer = null ;
return deferred ;
} ;
deferred . isPending = function ( ) {
return timer ;
} ;
return deferred ;
} ;
exports . delayedCall = function ( fcn , defaultTimeout ) {
var timer = null ;
var callback = function ( ) {
timer = null ;
fcn ( ) ;
} ;
var _self = function ( timeout ) {
if ( timer == null )
timer = setTimeout ( callback , timeout || defaultTimeout ) ;
} ;
_self . delay = function ( timeout ) {
timer && clearTimeout ( timer ) ;
timer = setTimeout ( callback , timeout || defaultTimeout ) ;
} ;
_self . schedule = _self ;
_self . call = function ( ) {
this . cancel ( ) ;
fcn ( ) ;
} ;
_self . cancel = function ( ) {
timer && clearTimeout ( timer ) ;
timer = null ;
} ;
_self . isPending = function ( ) {
return timer ;
} ;
return _self ;
} ;
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/range" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
var comparePoints = function ( p1 , p2 ) {
return p1 . row - p2 . row || p1 . column - p2 . column ;
} ;
var Range = function ( startRow , startColumn , endRow , endColumn ) {
this . start = {
row : startRow ,
column : startColumn
} ;
this . end = {
row : endRow ,
column : endColumn
} ;
} ;
( function ( ) {
this . isEqual = function ( range ) {
return this . start . row === range . start . row &&
this . end . row === range . end . row &&
this . start . column === range . start . column &&
this . end . column === range . end . column ;
} ;
this . toString = function ( ) {
return ( "Range: [" + this . start . row + "/" + this . start . column +
"] -> [" + this . end . row + "/" + this . end . column + "]" ) ;
} ;
this . contains = function ( row , column ) {
return this . compare ( row , column ) == 0 ;
} ;
this . compareRange = function ( range ) {
var cmp ,
end = range . end ,
start = range . start ;
cmp = this . compare ( end . row , end . column ) ;
if ( cmp == 1 ) {
cmp = this . compare ( start . row , start . column ) ;
if ( cmp == 1 ) {
return 2 ;
} else if ( cmp == 0 ) {
return 1 ;
} else {
return 0 ;
}
} else if ( cmp == - 1 ) {
return - 2 ;
} else {
cmp = this . compare ( start . row , start . column ) ;
if ( cmp == - 1 ) {
return - 1 ;
} else if ( cmp == 1 ) {
return 42 ;
} else {
return 0 ;
}
}
} ;
this . comparePoint = function ( p ) {
return this . compare ( p . row , p . column ) ;
} ;
this . containsRange = function ( range ) {
return this . comparePoint ( range . start ) == 0 && this . comparePoint ( range . end ) == 0 ;
} ;
this . intersects = function ( range ) {
var cmp = this . compareRange ( range ) ;
return ( cmp == - 1 || cmp == 0 || cmp == 1 ) ;
} ;
this . isEnd = function ( row , column ) {
return this . end . row == row && this . end . column == column ;
} ;
this . isStart = function ( row , column ) {
return this . start . row == row && this . start . column == column ;
} ;
this . setStart = function ( row , column ) {
if ( typeof row == "object" ) {
this . start . column = row . column ;
this . start . row = row . row ;
} else {
this . start . row = row ;
this . start . column = column ;
}
} ;
this . setEnd = function ( row , column ) {
if ( typeof row == "object" ) {
this . end . column = row . column ;
this . end . row = row . row ;
} else {
this . end . row = row ;
this . end . column = column ;
}
} ;
this . inside = function ( row , column ) {
if ( this . compare ( row , column ) == 0 ) {
if ( this . isEnd ( row , column ) || this . isStart ( row , column ) ) {
return false ;
} else {
return true ;
}
}
return false ;
} ;
this . insideStart = function ( row , column ) {
if ( this . compare ( row , column ) == 0 ) {
if ( this . isEnd ( row , column ) ) {
return false ;
} else {
return true ;
}
}
return false ;
} ;
this . insideEnd = function ( row , column ) {
if ( this . compare ( row , column ) == 0 ) {
if ( this . isStart ( row , column ) ) {
return false ;
} else {
return true ;
}
}
return false ;
} ;
this . compare = function ( row , column ) {
if ( ! this . isMultiLine ( ) ) {
if ( row === this . start . row ) {
return column < this . start . column ? - 1 : ( column > this . end . column ? 1 : 0 ) ;
} ;
}
if ( row < this . start . row )
return - 1 ;
if ( row > this . end . row )
return 1 ;
if ( this . start . row === row )
return column >= this . start . column ? 0 : - 1 ;
if ( this . end . row === row )
return column <= this . end . column ? 0 : 1 ;
return 0 ;
} ;
this . compareStart = function ( row , column ) {
if ( this . start . row == row && this . start . column == column ) {
return - 1 ;
} else {
return this . compare ( row , column ) ;
}
} ;
this . compareEnd = function ( row , column ) {
if ( this . end . row == row && this . end . column == column ) {
return 1 ;
} else {
return this . compare ( row , column ) ;
}
} ;
this . compareInside = function ( row , column ) {
if ( this . end . row == row && this . end . column == column ) {
return 1 ;
} else if ( this . start . row == row && this . start . column == column ) {
return - 1 ;
} else {
return this . compare ( row , column ) ;
}
} ;
this . clipRows = function ( firstRow , lastRow ) {
if ( this . end . row > lastRow )
var end = { row : lastRow + 1 , column : 0 } ;
else if ( this . end . row < firstRow )
var end = { row : firstRow , column : 0 } ;
if ( this . start . row > lastRow )
var start = { row : lastRow + 1 , column : 0 } ;
else if ( this . start . row < firstRow )
var start = { row : firstRow , column : 0 } ;
return Range . fromPoints ( start || this . start , end || this . end ) ;
} ;
this . extend = function ( row , column ) {
var cmp = this . compare ( row , column ) ;
if ( cmp == 0 )
return this ;
else if ( cmp == - 1 )
var start = { row : row , column : column } ;
else
var end = { row : row , column : column } ;
return Range . fromPoints ( start || this . start , end || this . end ) ;
} ;
this . isEmpty = function ( ) {
return ( this . start . row === this . end . row && this . start . column === this . end . column ) ;
} ;
this . isMultiLine = function ( ) {
return ( this . start . row !== this . end . row ) ;
} ;
this . clone = function ( ) {
return Range . fromPoints ( this . start , this . end ) ;
} ;
this . collapseRows = function ( ) {
if ( this . end . column == 0 )
return new Range ( this . start . row , 0 , Math . max ( this . start . row , this . end . row - 1 ) , 0 )
else
return new Range ( this . start . row , 0 , this . end . row , 0 )
} ;
this . toScreenRange = function ( session ) {
var screenPosStart = session . documentToScreenPosition ( this . start ) ;
var screenPosEnd = session . documentToScreenPosition ( this . end ) ;
return new Range (
screenPosStart . row , screenPosStart . column ,
screenPosEnd . row , screenPosEnd . column
) ;
} ;
this . moveBy = function ( row , column ) {
this . start . row += row ;
this . start . column += column ;
this . end . row += row ;
this . end . column += column ;
} ;
} ) . call ( Range . prototype ) ;
Range . fromPoints = function ( start , end ) {
return new Range ( start . row , start . column , end . row , end . column ) ;
} ;
Range . comparePoints = comparePoints ;
Range . comparePoints = function ( p1 , p2 ) {
return p1 . row - p2 . row || p1 . column - p2 . column ;
} ;
exports . Range = Range ;
} ) ;
2015-09-07 12:04:05 -04:00
ace . define ( "ace/apply_delta" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
"use strict" ;
function throwDeltaError ( delta , errorText ) {
console . log ( "Invalid Delta:" , delta ) ;
throw "Invalid Delta: " + errorText ;
}
function positionInDocument ( docLines , position ) {
return position . row >= 0 && position . row < docLines . length &&
position . column >= 0 && position . column <= docLines [ position . row ] . length ;
}
function validateDelta ( docLines , delta ) {
if ( delta . action != "insert" && delta . action != "remove" )
throwDeltaError ( delta , "delta.action must be 'insert' or 'remove'" ) ;
if ( ! ( delta . lines instanceof Array ) )
throwDeltaError ( delta , "delta.lines must be an Array" ) ;
if ( ! delta . start || ! delta . end )
throwDeltaError ( delta , "delta.start/end must be an present" ) ;
var start = delta . start ;
if ( ! positionInDocument ( docLines , delta . start ) )
throwDeltaError ( delta , "delta.start must be contained in document" ) ;
var end = delta . end ;
if ( delta . action == "remove" && ! positionInDocument ( docLines , end ) )
throwDeltaError ( delta , "delta.end must contained in document for 'remove' actions" ) ;
var numRangeRows = end . row - start . row ;
var numRangeLastLineChars = ( end . column - ( numRangeRows == 0 ? start . column : 0 ) ) ;
if ( numRangeRows != delta . lines . length - 1 || delta . lines [ numRangeRows ] . length != numRangeLastLineChars )
throwDeltaError ( delta , "delta.range must match delta lines" ) ;
}
exports . applyDelta = function ( docLines , delta , doNotValidate ) {
var row = delta . start . row ;
var startColumn = delta . start . column ;
var line = docLines [ row ] || "" ;
switch ( delta . action ) {
case "insert" :
var lines = delta . lines ;
if ( lines . length === 1 ) {
docLines [ row ] = line . substring ( 0 , startColumn ) + delta . lines [ 0 ] + line . substring ( startColumn ) ;
} else {
var args = [ row , 1 ] . concat ( delta . lines ) ;
docLines . splice . apply ( docLines , args ) ;
docLines [ row ] = line . substring ( 0 , startColumn ) + docLines [ row ] ;
docLines [ row + delta . lines . length - 1 ] += line . substring ( startColumn ) ;
}
break ;
case "remove" :
var endColumn = delta . end . column ;
var endRow = delta . end . row ;
if ( row === endRow ) {
docLines [ row ] = line . substring ( 0 , startColumn ) + line . substring ( endColumn ) ;
} else {
docLines . splice (
row , endRow - row + 1 ,
line . substring ( 0 , startColumn ) + docLines [ endRow ] . substring ( endColumn )
) ;
}
break ;
}
}
} ) ;
ace . define ( "ace/lib/event_emitter" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
"use strict" ;
var EventEmitter = { } ;
var stopPropagation = function ( ) { this . propagationStopped = true ; } ;
var preventDefault = function ( ) { this . defaultPrevented = true ; } ;
EventEmitter . _emit =
EventEmitter . _dispatchEvent = function ( eventName , e ) {
this . _eventRegistry || ( this . _eventRegistry = { } ) ;
this . _defaultHandlers || ( this . _defaultHandlers = { } ) ;
var listeners = this . _eventRegistry [ eventName ] || [ ] ;
var defaultHandler = this . _defaultHandlers [ eventName ] ;
if ( ! listeners . length && ! defaultHandler )
return ;
if ( typeof e != "object" || ! e )
e = { } ;
if ( ! e . type )
e . type = eventName ;
if ( ! e . stopPropagation )
e . stopPropagation = stopPropagation ;
if ( ! e . preventDefault )
e . preventDefault = preventDefault ;
listeners = listeners . slice ( ) ;
for ( var i = 0 ; i < listeners . length ; i ++ ) {
listeners [ i ] ( e , this ) ;
if ( e . propagationStopped )
break ;
}
if ( defaultHandler && ! e . defaultPrevented )
return defaultHandler ( e , this ) ;
} ;
EventEmitter . _signal = function ( eventName , e ) {
var listeners = ( this . _eventRegistry || { } ) [ eventName ] ;
if ( ! listeners )
return ;
listeners = listeners . slice ( ) ;
for ( var i = 0 ; i < listeners . length ; i ++ )
listeners [ i ] ( e , this ) ;
} ;
EventEmitter . once = function ( eventName , callback ) {
var _self = this ;
callback && this . addEventListener ( eventName , function newCallback ( ) {
_self . removeEventListener ( eventName , newCallback ) ;
callback . apply ( null , arguments ) ;
} ) ;
} ;
EventEmitter . setDefaultHandler = function ( eventName , callback ) {
var handlers = this . _defaultHandlers
if ( ! handlers )
handlers = this . _defaultHandlers = { _disabled _ : { } } ;
if ( handlers [ eventName ] ) {
var old = handlers [ eventName ] ;
var disabled = handlers . _disabled _ [ eventName ] ;
if ( ! disabled )
handlers . _disabled _ [ eventName ] = disabled = [ ] ;
disabled . push ( old ) ;
var i = disabled . indexOf ( callback ) ;
if ( i != - 1 )
disabled . splice ( i , 1 ) ;
}
handlers [ eventName ] = callback ;
} ;
EventEmitter . removeDefaultHandler = function ( eventName , callback ) {
var handlers = this . _defaultHandlers
if ( ! handlers )
return ;
var disabled = handlers . _disabled _ [ eventName ] ;
if ( handlers [ eventName ] == callback ) {
var old = handlers [ eventName ] ;
if ( disabled )
this . setDefaultHandler ( eventName , disabled . pop ( ) ) ;
} else if ( disabled ) {
var i = disabled . indexOf ( callback ) ;
if ( i != - 1 )
disabled . splice ( i , 1 ) ;
}
} ;
EventEmitter . on =
EventEmitter . addEventListener = function ( eventName , callback , capturing ) {
this . _eventRegistry = this . _eventRegistry || { } ;
var listeners = this . _eventRegistry [ eventName ] ;
if ( ! listeners )
listeners = this . _eventRegistry [ eventName ] = [ ] ;
if ( listeners . indexOf ( callback ) == - 1 )
listeners [ capturing ? "unshift" : "push" ] ( callback ) ;
return callback ;
} ;
EventEmitter . off =
EventEmitter . removeListener =
EventEmitter . removeEventListener = function ( eventName , callback ) {
this . _eventRegistry = this . _eventRegistry || { } ;
var listeners = this . _eventRegistry [ eventName ] ;
if ( ! listeners )
return ;
var index = listeners . indexOf ( callback ) ;
if ( index !== - 1 )
listeners . splice ( index , 1 ) ;
} ;
EventEmitter . removeAllListeners = function ( eventName ) {
if ( this . _eventRegistry ) this . _eventRegistry [ eventName ] = [ ] ;
} ;
exports . EventEmitter = EventEmitter ;
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/anchor" , [ "require" , "exports" , "module" , "ace/lib/oop" , "ace/lib/event_emitter" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
var oop = require ( "./lib/oop" ) ;
var EventEmitter = require ( "./lib/event_emitter" ) . EventEmitter ;
var Anchor = exports . Anchor = function ( doc , row , column ) {
this . $onChange = this . onChange . bind ( this ) ;
this . attach ( doc ) ;
if ( typeof column == "undefined" )
this . setPosition ( row . row , row . column ) ;
else
this . setPosition ( row , column ) ;
} ;
( function ( ) {
oop . implement ( this , EventEmitter ) ;
this . getPosition = function ( ) {
return this . $clipPositionToDocument ( this . row , this . column ) ;
} ;
this . getDocument = function ( ) {
return this . document ;
} ;
this . $insertRight = false ;
2015-09-07 12:04:05 -04:00
this . onChange = function ( delta ) {
if ( delta . start . row == delta . end . row && delta . start . row != this . row )
2014-07-09 12:59:04 -04:00
return ;
2015-09-07 12:04:05 -04:00
if ( delta . start . row > this . row )
2014-07-09 12:59:04 -04:00
return ;
2015-09-07 12:04:05 -04:00
var point = $getTransformedPoint ( delta , { row : this . row , column : this . column } , this . $insertRight ) ;
this . setPosition ( point . row , point . column , true ) ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
function $pointsInOrder ( point1 , point2 , equalPointsInOrder ) {
var bColIsAfter = equalPointsInOrder ? point1 . column <= point2 . column : point1 . column < point2 . column ;
return ( point1 . row < point2 . row ) || ( point1 . row == point2 . row && bColIsAfter ) ;
}
function $getTransformedPoint ( delta , point , moveIfEqual ) {
var deltaIsInsert = delta . action == "insert" ;
var deltaRowShift = ( deltaIsInsert ? 1 : - 1 ) * ( delta . end . row - delta . start . row ) ;
var deltaColShift = ( deltaIsInsert ? 1 : - 1 ) * ( delta . end . column - delta . start . column ) ;
var deltaStart = delta . start ;
var deltaEnd = deltaIsInsert ? deltaStart : delta . end ; // Collapse insert range.
if ( $pointsInOrder ( point , deltaStart , moveIfEqual ) ) {
return {
row : point . row ,
column : point . column
} ;
}
if ( $pointsInOrder ( deltaEnd , point , ! moveIfEqual ) ) {
return {
row : point . row + deltaRowShift ,
column : point . column + ( point . row == deltaEnd . row ? deltaColShift : 0 )
} ;
}
return {
row : deltaStart . row ,
column : deltaStart . column
} ;
}
2014-07-09 12:59:04 -04:00
this . setPosition = function ( row , column , noClip ) {
var pos ;
if ( noClip ) {
pos = {
row : row ,
column : column
} ;
} else {
pos = this . $clipPositionToDocument ( row , column ) ;
}
if ( this . row == pos . row && this . column == pos . column )
return ;
var old = {
row : this . row ,
column : this . column
} ;
this . row = pos . row ;
this . column = pos . column ;
this . _signal ( "change" , {
old : old ,
value : pos
} ) ;
} ;
this . detach = function ( ) {
this . document . removeEventListener ( "change" , this . $onChange ) ;
} ;
this . attach = function ( doc ) {
this . document = doc || this . document ;
this . document . on ( "change" , this . $onChange ) ;
} ;
this . $clipPositionToDocument = function ( row , column ) {
var pos = { } ;
if ( row >= this . document . getLength ( ) ) {
pos . row = Math . max ( 0 , this . document . getLength ( ) - 1 ) ;
pos . column = this . document . getLine ( pos . row ) . length ;
}
else if ( row < 0 ) {
pos . row = 0 ;
pos . column = 0 ;
}
else {
pos . row = row ;
pos . column = Math . min ( this . document . getLine ( pos . row ) . length , Math . max ( 0 , column ) ) ;
}
if ( column < 0 )
pos . column = 0 ;
return pos ;
} ;
} ) . call ( Anchor . prototype ) ;
} ) ;
2015-09-07 12:04:05 -04:00
ace . define ( "ace/document" , [ "require" , "exports" , "module" , "ace/lib/oop" , "ace/apply_delta" , "ace/lib/event_emitter" , "ace/range" , "ace/anchor" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
var oop = require ( "./lib/oop" ) ;
2015-09-07 12:04:05 -04:00
var applyDelta = require ( "./apply_delta" ) . applyDelta ;
2014-07-09 12:59:04 -04:00
var EventEmitter = require ( "./lib/event_emitter" ) . EventEmitter ;
var Range = require ( "./range" ) . Range ;
var Anchor = require ( "./anchor" ) . Anchor ;
2015-09-07 12:04:05 -04:00
var Document = function ( textOrLines ) {
this . $lines = [ "" ] ;
if ( textOrLines . length === 0 ) {
2014-07-09 12:59:04 -04:00
this . $lines = [ "" ] ;
2015-09-07 12:04:05 -04:00
} else if ( Array . isArray ( textOrLines ) ) {
this . insertMergedLines ( { row : 0 , column : 0 } , textOrLines ) ;
2014-07-09 12:59:04 -04:00
} else {
2015-09-07 12:04:05 -04:00
this . insert ( { row : 0 , column : 0 } , textOrLines ) ;
2014-07-09 12:59:04 -04:00
}
} ;
( function ( ) {
oop . implement ( this , EventEmitter ) ;
this . setValue = function ( text ) {
2015-09-07 12:04:05 -04:00
var len = this . getLength ( ) - 1 ;
this . remove ( new Range ( 0 , 0 , len , this . getLine ( len ) . length ) ) ;
this . insert ( { row : 0 , column : 0 } , text ) ;
2014-07-09 12:59:04 -04:00
} ;
this . getValue = function ( ) {
return this . getAllLines ( ) . join ( this . getNewLineCharacter ( ) ) ;
} ;
this . createAnchor = function ( row , column ) {
return new Anchor ( this , row , column ) ;
} ;
2015-09-07 12:04:05 -04:00
if ( "aaa" . split ( /a/ ) . length === 0 ) {
2014-07-09 12:59:04 -04:00
this . $split = function ( text ) {
return text . replace ( /\r\n|\r/g , "\n" ) . split ( "\n" ) ;
} ;
2015-09-07 12:04:05 -04:00
} else {
2014-07-09 12:59:04 -04:00
this . $split = function ( text ) {
return text . split ( /\r\n|\r|\n/ ) ;
} ;
2015-09-07 12:04:05 -04:00
}
2014-07-09 12:59:04 -04:00
this . $detectNewLine = function ( text ) {
var match = text . match ( /^.*?(\r\n|\r|\n)/m ) ;
this . $autoNewLine = match ? match [ 1 ] : "\n" ;
this . _signal ( "changeNewLineMode" ) ;
} ;
this . getNewLineCharacter = function ( ) {
switch ( this . $newLineMode ) {
case "windows" :
return "\r\n" ;
case "unix" :
return "\n" ;
default :
return this . $autoNewLine || "\n" ;
}
} ;
this . $autoNewLine = "" ;
this . $newLineMode = "auto" ;
this . setNewLineMode = function ( newLineMode ) {
if ( this . $newLineMode === newLineMode )
return ;
this . $newLineMode = newLineMode ;
this . _signal ( "changeNewLineMode" ) ;
} ;
this . getNewLineMode = function ( ) {
return this . $newLineMode ;
} ;
this . isNewLine = function ( text ) {
return ( text == "\r\n" || text == "\r" || text == "\n" ) ;
} ;
this . getLine = function ( row ) {
return this . $lines [ row ] || "" ;
} ;
this . getLines = function ( firstRow , lastRow ) {
return this . $lines . slice ( firstRow , lastRow + 1 ) ;
} ;
this . getAllLines = function ( ) {
return this . getLines ( 0 , this . getLength ( ) ) ;
} ;
this . getLength = function ( ) {
return this . $lines . length ;
} ;
this . getTextRange = function ( range ) {
2015-09-07 12:04:05 -04:00
return this . getLinesForRange ( range ) . join ( this . getNewLineCharacter ( ) ) ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . getLinesForRange = function ( range ) {
var lines ;
if ( range . start . row === range . end . row ) {
lines = [ this . getLine ( range . start . row ) . substring ( range . start . column , range . end . column ) ] ;
} else {
lines = this . getLines ( range . start . row , range . end . row ) ;
lines [ 0 ] = ( lines [ 0 ] || "" ) . substring ( range . start . column ) ;
var l = lines . length - 1 ;
if ( range . end . row - range . start . row == l )
lines [ l ] = lines [ l ] . substring ( 0 , range . end . column ) ;
}
return lines ;
} ;
this . insertLines = function ( row , lines ) {
console . warn ( "Use of document.insertLines is deprecated. Use the insertFullLines method instead." ) ;
return this . insertFullLines ( row , lines ) ;
} ;
this . removeLines = function ( firstRow , lastRow ) {
console . warn ( "Use of document.removeLines is deprecated. Use the removeFullLines method instead." ) ;
return this . removeFullLines ( firstRow , lastRow ) ;
} ;
this . insertNewLine = function ( position ) {
console . warn ( "Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead." ) ;
return this . insertMergedLines ( position , [ "" , "" ] ) ;
2014-07-09 12:59:04 -04:00
} ;
this . insert = function ( position , text ) {
if ( this . getLength ( ) <= 1 )
this . $detectNewLine ( text ) ;
2015-09-07 12:04:05 -04:00
return this . insertMergedLines ( position , this . $split ( text ) ) ;
} ;
this . insertInLine = function ( position , text ) {
var start = this . clippedPos ( position . row , position . column ) ;
var end = this . pos ( position . row , position . column + text . length ) ;
this . applyDelta ( {
start : start ,
end : end ,
action : "insert" ,
lines : [ text ]
} , true ) ;
return this . clonePos ( end ) ;
} ;
this . clippedPos = function ( row , column ) {
var length = this . getLength ( ) ;
if ( row === undefined ) {
row = length ;
} else if ( row < 0 ) {
row = 0 ;
} else if ( row >= length ) {
row = length - 1 ;
column = undefined ;
2014-07-09 12:59:04 -04:00
}
2015-09-07 12:04:05 -04:00
var line = this . getLine ( row ) ;
if ( column == undefined )
column = line . length ;
column = Math . min ( Math . max ( column , 0 ) , line . length ) ;
return { row : row , column : column } ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . clonePos = function ( pos ) {
return { row : pos . row , column : pos . column } ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . pos = function ( row , column ) {
return { row : row , column : column } ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . $clipPosition = function ( position ) {
var length = this . getLength ( ) ;
if ( position . row >= length ) {
position . row = Math . max ( 0 , length - 1 ) ;
position . column = this . getLine ( length - 1 ) . length ;
} else {
position . row = Math . max ( 0 , position . row ) ;
position . column = Math . min ( Math . max ( position . column , 0 ) , this . getLine ( position . row ) . length ) ;
}
return position ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . insertFullLines = function ( row , lines ) {
row = Math . min ( Math . max ( row , 0 ) , this . getLength ( ) ) ;
var column = 0 ;
if ( row < this . getLength ( ) ) {
lines = lines . concat ( [ "" ] ) ;
column = 0 ;
} else {
lines = [ "" ] . concat ( lines ) ;
row -- ;
column = this . $lines [ row ] . length ;
}
this . insertMergedLines ( { row : row , column : column } , lines ) ;
} ;
this . insertMergedLines = function ( position , lines ) {
var start = this . clippedPos ( position . row , position . column ) ;
2014-07-09 12:59:04 -04:00
var end = {
2015-09-07 12:04:05 -04:00
row : start . row + lines . length - 1 ,
column : ( lines . length == 1 ? start . column : 0 ) + lines [ lines . length - 1 ] . length
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . applyDelta ( {
start : start ,
end : end ,
action : "insert" ,
lines : lines
} ) ;
return this . clonePos ( end ) ;
2014-07-09 12:59:04 -04:00
} ;
this . remove = function ( range ) {
2015-09-07 12:04:05 -04:00
var start = this . clippedPos ( range . start . row , range . start . column ) ;
var end = this . clippedPos ( range . end . row , range . end . column ) ;
this . applyDelta ( {
start : start ,
end : end ,
action : "remove" ,
lines : this . getLinesForRange ( { start : start , end : end } )
} ) ;
return this . clonePos ( start ) ;
2014-07-09 12:59:04 -04:00
} ;
this . removeInLine = function ( row , startColumn , endColumn ) {
2015-09-07 12:04:05 -04:00
var start = this . clippedPos ( row , startColumn ) ;
var end = this . clippedPos ( row , endColumn ) ;
this . applyDelta ( {
start : start ,
end : end ,
action : "remove" ,
lines : this . getLinesForRange ( { start : start , end : end } )
} , true ) ;
return this . clonePos ( start ) ;
2014-07-09 12:59:04 -04:00
} ;
2015-09-07 12:04:05 -04:00
this . removeFullLines = function ( firstRow , lastRow ) {
firstRow = Math . min ( Math . max ( 0 , firstRow ) , this . getLength ( ) - 1 ) ;
lastRow = Math . min ( Math . max ( 0 , lastRow ) , this . getLength ( ) - 1 ) ;
var deleteFirstNewLine = lastRow == this . getLength ( ) - 1 && firstRow > 0 ;
var deleteLastNewLine = lastRow < this . getLength ( ) - 1 ;
var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ) ;
var startCol = ( deleteFirstNewLine ? this . getLine ( startRow ) . length : 0 ) ;
var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ) ;
var endCol = ( deleteLastNewLine ? 0 : this . getLine ( endRow ) . length ) ;
var range = new Range ( startRow , startCol , endRow , endCol ) ;
var deletedLines = this . $lines . slice ( firstRow , lastRow + 1 ) ;
this . applyDelta ( {
start : range . start ,
end : range . end ,
action : "remove" ,
lines : this . getLinesForRange ( range )
} ) ;
return deletedLines ;
2014-07-09 12:59:04 -04:00
} ;
this . removeNewLine = function ( row ) {
2015-09-07 12:04:05 -04:00
if ( row < this . getLength ( ) - 1 && row >= 0 ) {
this . applyDelta ( {
start : this . pos ( row , this . getLine ( row ) . length ) ,
end : this . pos ( row + 1 , 0 ) ,
action : "remove" ,
lines : [ "" , "" ]
} ) ;
}
2014-07-09 12:59:04 -04:00
} ;
this . replace = function ( range , text ) {
2015-09-07 12:04:05 -04:00
if ( ! range instanceof Range )
2014-07-09 12:59:04 -04:00
range = Range . fromPoints ( range . start , range . end ) ;
2015-09-07 12:04:05 -04:00
if ( text . length === 0 && range . isEmpty ( ) )
2014-07-09 12:59:04 -04:00
return range . start ;
if ( text == this . getTextRange ( range ) )
return range . end ;
this . remove ( range ) ;
2015-09-07 12:04:05 -04:00
var end ;
2014-07-09 12:59:04 -04:00
if ( text ) {
2015-09-07 12:04:05 -04:00
end = this . insert ( range . start , text ) ;
2014-07-09 12:59:04 -04:00
}
else {
end = range . start ;
}
2015-09-07 12:04:05 -04:00
2014-07-09 12:59:04 -04:00
return end ;
} ;
this . applyDeltas = function ( deltas ) {
for ( var i = 0 ; i < deltas . length ; i ++ ) {
2015-09-07 12:04:05 -04:00
this . applyDelta ( deltas [ i ] ) ;
2014-07-09 12:59:04 -04:00
}
} ;
this . revertDeltas = function ( deltas ) {
for ( var i = deltas . length - 1 ; i >= 0 ; i -- ) {
2015-09-07 12:04:05 -04:00
this . revertDelta ( deltas [ i ] ) ;
}
} ;
this . applyDelta = function ( delta , doNotValidate ) {
var isInsert = delta . action == "insert" ;
if ( isInsert ? delta . lines . length <= 1 && ! delta . lines [ 0 ]
: ! Range . comparePoints ( delta . start , delta . end ) ) {
return ;
2014-07-09 12:59:04 -04:00
}
2015-09-07 12:04:05 -04:00
if ( isInsert && delta . lines . length > 20000 )
this . $splitAndapplyLargeDelta ( delta , 20000 ) ;
applyDelta ( this . $lines , delta , doNotValidate ) ;
this . _signal ( "change" , delta ) ;
} ;
this . $splitAndapplyLargeDelta = function ( delta , MAX ) {
var lines = delta . lines ;
var l = lines . length ;
var row = delta . start . row ;
var column = delta . start . column ;
var from = 0 , to = 0 ;
do {
from = to ;
to += MAX - 1 ;
var chunk = lines . slice ( from , to ) ;
if ( to > l ) {
delta . lines = chunk ;
delta . start . row = row + from ;
delta . start . column = column ;
break ;
}
chunk . push ( "" ) ;
this . applyDelta ( {
start : this . pos ( row + from , column ) ,
end : this . pos ( row + to , column = 0 ) ,
action : delta . action ,
lines : chunk
} , true ) ;
} while ( true ) ;
} ;
this . revertDelta = function ( delta ) {
this . applyDelta ( {
start : this . clonePos ( delta . start ) ,
end : this . clonePos ( delta . end ) ,
action : ( delta . action == "insert" ? "remove" : "insert" ) ,
lines : delta . lines . slice ( )
} ) ;
2014-07-09 12:59:04 -04:00
} ;
this . indexToPosition = function ( index , startRow ) {
var lines = this . $lines || this . getAllLines ( ) ;
var newlineLength = this . getNewLineCharacter ( ) . length ;
for ( var i = startRow || 0 , l = lines . length ; i < l ; i ++ ) {
index -= lines [ i ] . length + newlineLength ;
if ( index < 0 )
return { row : i , column : index + lines [ i ] . length + newlineLength } ;
}
return { row : l - 1 , column : lines [ l - 1 ] . length } ;
} ;
this . positionToIndex = function ( pos , startRow ) {
var lines = this . $lines || this . getAllLines ( ) ;
var newlineLength = this . getNewLineCharacter ( ) . length ;
var index = 0 ;
var row = Math . min ( pos . row , lines . length ) ;
for ( var i = startRow || 0 ; i < row ; ++ i )
index += lines [ i ] . length + newlineLength ;
return index + pos . column ;
} ;
} ) . call ( Document . prototype ) ;
exports . Document = Document ;
} ) ;
2015-09-07 12:04:05 -04:00
ace . define ( "ace/worker/mirror" , [ "require" , "exports" , "module" , "ace/range" , "ace/document" , "ace/lib/lang" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
2015-09-07 12:04:05 -04:00
var Range = require ( "../range" ) . Range ;
2014-07-09 12:59:04 -04:00
var Document = require ( "../document" ) . Document ;
var lang = require ( "../lib/lang" ) ;
var Mirror = exports . Mirror = function ( sender ) {
this . sender = sender ;
var doc = this . doc = new Document ( "" ) ;
var deferredUpdate = this . deferredUpdate = lang . delayedCall ( this . onUpdate . bind ( this ) ) ;
var _self = this ;
sender . on ( "change" , function ( e ) {
2015-09-07 12:04:05 -04:00
var data = e . data ;
if ( data [ 0 ] . start ) {
doc . applyDeltas ( data ) ;
} else {
for ( var i = 0 ; i < data . length ; i += 2 ) {
if ( Array . isArray ( data [ i + 1 ] ) ) {
var d = { action : "insert" , start : data [ i ] , lines : data [ i + 1 ] } ;
} else {
var d = { action : "remove" , start : data [ i ] , end : data [ i + 1 ] } ;
}
doc . applyDelta ( d , true ) ;
}
}
2014-07-09 12:59:04 -04:00
if ( _self . $timeout )
return deferredUpdate . schedule ( _self . $timeout ) ;
_self . onUpdate ( ) ;
} ) ;
} ;
( function ( ) {
this . $timeout = 500 ;
this . setTimeout = function ( timeout ) {
this . $timeout = timeout ;
} ;
this . setValue = function ( value ) {
this . doc . setValue ( value ) ;
this . deferredUpdate . schedule ( this . $timeout ) ;
} ;
this . getValue = function ( callbackId ) {
this . sender . callback ( this . doc . getValue ( ) , callbackId ) ;
} ;
this . onUpdate = function ( ) {
} ;
this . isPending = function ( ) {
return this . deferredUpdate . isPending ( ) ;
} ;
} ) . call ( Mirror . prototype ) ;
2014-02-12 05:23:40 -05:00
2014-07-09 12:59:04 -04:00
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/mode/css/csslint" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
var parserlib = { } ;
( function ( ) {
function EventTarget ( ) {
this . _listeners = { } ;
2014-02-12 05:23:40 -05:00
}
EventTarget . prototype = {
constructor : EventTarget ,
addListener : function ( type , listener ) {
if ( ! this . _listeners [ type ] ) {
this . _listeners [ type ] = [ ] ;
}
this . _listeners [ type ] . push ( listener ) ;
} ,
fire : function ( event ) {
if ( typeof event == "string" ) {
event = { type : event } ;
}
if ( typeof event . target != "undefined" ) {
event . target = this ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( typeof event . type == "undefined" ) {
throw new Error ( "Event object missing 'type' property." ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( this . _listeners [ event . type ] ) {
var listeners = this . _listeners [ event . type ] . concat ( ) ;
for ( var i = 0 , len = listeners . length ; i < len ; i ++ ) {
listeners [ i ] . call ( this , event ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
removeListener : function ( type , listener ) {
if ( this . _listeners [ type ] ) {
var listeners = this . _listeners [ type ] ;
for ( var i = 0 , len = listeners . length ; i < len ; i ++ ) {
if ( listeners [ i ] === listener ) {
listeners . splice ( i , 1 ) ;
break ;
}
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
} ;
function StringReader ( text ) {
this . _input = text . replace ( /\n\r?/g , "\n" ) ;
this . _line = 1 ;
this . _col = 1 ;
this . _cursor = 0 ;
}
StringReader . prototype = {
constructor : StringReader ,
getCol : function ( ) {
return this . _col ;
} ,
getLine : function ( ) {
return this . _line ;
} ,
eof : function ( ) {
return ( this . _cursor == this . _input . length ) ;
} ,
peek : function ( count ) {
var c = null ;
count = ( typeof count == "undefined" ? 1 : count ) ;
if ( this . _cursor < this . _input . length ) {
c = this . _input . charAt ( this . _cursor + count - 1 ) ;
}
return c ;
} ,
read : function ( ) {
var c = null ;
if ( this . _cursor < this . _input . length ) {
if ( this . _input . charAt ( this . _cursor ) == "\n" ) {
this . _line ++ ;
this . _col = 1 ;
} else {
this . _col ++ ;
}
c = this . _input . charAt ( this . _cursor ++ ) ;
}
return c ;
} ,
mark : function ( ) {
this . _bookmark = {
cursor : this . _cursor ,
line : this . _line ,
col : this . _col
} ;
} ,
reset : function ( ) {
if ( this . _bookmark ) {
this . _cursor = this . _bookmark . cursor ;
this . _line = this . _bookmark . line ;
this . _col = this . _bookmark . col ;
delete this . _bookmark ;
}
} ,
readTo : function ( pattern ) {
var buffer = "" ,
c ;
while ( buffer . length < pattern . length || buffer . lastIndexOf ( pattern ) != buffer . length - pattern . length ) {
c = this . read ( ) ;
if ( c ) {
buffer += c ;
} else {
throw new Error ( "Expected \"" + pattern + "\" at line " + this . _line + ", col " + this . _col + "." ) ;
}
}
return buffer ;
} ,
readWhile : function ( filter ) {
var buffer = "" ,
c = this . read ( ) ;
while ( c !== null && filter ( c ) ) {
buffer += c ;
c = this . read ( ) ;
}
return buffer ;
} ,
readMatch : function ( matcher ) {
var source = this . _input . substring ( this . _cursor ) ,
value = null ;
if ( typeof matcher == "string" ) {
if ( source . indexOf ( matcher ) === 0 ) {
value = this . readCount ( matcher . length ) ;
}
} else if ( matcher instanceof RegExp ) {
if ( matcher . test ( source ) ) {
value = this . readCount ( RegExp . lastMatch . length ) ;
}
}
return value ;
} ,
readCount : function ( count ) {
var buffer = "" ;
while ( count -- ) {
buffer += this . read ( ) ;
}
return buffer ;
}
} ;
function SyntaxError ( message , line , col ) {
this . col = col ;
this . line = line ;
this . message = message ;
}
SyntaxError . prototype = new Error ( ) ;
function SyntaxUnit ( text , line , col , type ) {
this . col = col ;
this . line = line ;
this . text = text ;
this . type = type ;
}
SyntaxUnit . fromToken = function ( token ) {
return new SyntaxUnit ( token . value , token . startLine , token . startCol ) ;
} ;
SyntaxUnit . prototype = {
constructor : SyntaxUnit ,
valueOf : function ( ) {
2015-02-12 05:36:57 -05:00
return this . text ;
2014-02-12 05:23:40 -05:00
} ,
toString : function ( ) {
return this . text ;
}
} ;
function TokenStreamBase ( input , tokenData ) {
this . _reader = input ? new StringReader ( input . toString ( ) ) : null ;
2014-07-09 12:59:04 -04:00
this . _token = null ;
2014-02-12 05:23:40 -05:00
this . _tokenData = tokenData ;
this . _lt = [ ] ;
this . _ltIndex = 0 ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _ltIndexCache = [ ] ;
}
TokenStreamBase . createTokenData = function ( tokens ) {
var nameMap = [ ] ,
typeMap = { } ,
tokenData = tokens . concat ( [ ] ) ,
i = 0 ,
len = tokenData . length + 1 ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenData . UNKNOWN = - 1 ;
tokenData . unshift ( { name : "EOF" } ) ;
for ( ; i < len ; i ++ ) {
nameMap . push ( tokenData [ i ] . name ) ;
tokenData [ tokenData [ i ] . name ] = i ;
if ( tokenData [ i ] . text ) {
typeMap [ tokenData [ i ] . text ] = i ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenData . name = function ( tt ) {
return nameMap [ tt ] ;
} ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenData . type = function ( c ) {
return typeMap [ c ] ;
} ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return tokenData ;
} ;
TokenStreamBase . prototype = {
2014-07-09 12:59:04 -04:00
constructor : TokenStreamBase ,
2014-02-12 05:23:40 -05:00
match : function ( tokenTypes , channel ) {
if ( ! ( tokenTypes instanceof Array ) ) {
tokenTypes = [ tokenTypes ] ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tt = this . get ( channel ) ,
i = 0 ,
len = tokenTypes . length ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( i < len ) {
if ( tt == tokenTypes [ i ++ ] ) {
return true ;
}
}
this . unget ( ) ;
return false ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
mustMatch : function ( tokenTypes , channel ) {
var token ;
if ( ! ( tokenTypes instanceof Array ) ) {
tokenTypes = [ tokenTypes ] ;
}
2014-07-09 12:59:04 -04:00
if ( ! this . match . apply ( this , arguments ) ) {
2014-02-12 05:23:40 -05:00
token = this . LT ( 1 ) ;
2014-07-09 12:59:04 -04:00
throw new SyntaxError ( "Expected " + this . _tokenData [ tokenTypes [ 0 ] ] . name +
2014-02-12 05:23:40 -05:00
" at line " + token . startLine + ", col " + token . startCol + "." , token . startLine , token . startCol ) ;
}
} ,
advance : function ( tokenTypes , channel ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( this . LA ( 0 ) !== 0 && ! this . match ( tokenTypes , channel ) ) {
this . get ( ) ;
}
2014-07-09 12:59:04 -04:00
return this . LA ( 0 ) ;
2014-02-12 05:23:40 -05:00
} ,
get : function ( channel ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenInfo = this . _tokenData ,
reader = this . _reader ,
value ,
i = 0 ,
len = tokenInfo . length ,
found = false ,
token ,
info ;
2014-07-09 12:59:04 -04:00
if ( this . _lt . length && this . _ltIndex >= 0 && this . _ltIndex < this . _lt . length ) {
2014-02-12 05:23:40 -05:00
i ++ ;
this . _token = this . _lt [ this . _ltIndex ++ ] ;
info = tokenInfo [ this . _token . type ] ;
while ( ( info . channel !== undefined && channel !== info . channel ) &&
this . _ltIndex < this . _lt . length ) {
this . _token = this . _lt [ this . _ltIndex ++ ] ;
info = tokenInfo [ this . _token . type ] ;
i ++ ;
}
if ( ( info . channel === undefined || channel === info . channel ) &&
this . _ltIndex <= this . _lt . length ) {
this . _ltIndexCache . push ( i ) ;
return this . _token . type ;
}
}
token = this . _getToken ( ) ;
if ( token . type > - 1 && ! tokenInfo [ token . type ] . hide ) {
token . channel = tokenInfo [ token . type ] . channel ;
this . _token = token ;
this . _lt . push ( token ) ;
2014-07-09 12:59:04 -04:00
this . _ltIndexCache . push ( this . _lt . length - this . _ltIndex + i ) ;
2014-02-12 05:23:40 -05:00
if ( this . _lt . length > 5 ) {
2014-07-09 12:59:04 -04:00
this . _lt . shift ( ) ;
2014-02-12 05:23:40 -05:00
}
if ( this . _ltIndexCache . length > 5 ) {
this . _ltIndexCache . shift ( ) ;
}
this . _ltIndex = this . _lt . length ;
}
info = tokenInfo [ token . type ] ;
2014-07-09 12:59:04 -04:00
if ( info &&
( info . hide ||
2014-02-12 05:23:40 -05:00
( info . channel !== undefined && channel !== info . channel ) ) ) {
return this . get ( channel ) ;
} else {
return token . type ;
}
} ,
LA : function ( index ) {
var total = index ,
tt ;
if ( index > 0 ) {
if ( index > 5 ) {
throw new Error ( "Too much lookahead." ) ;
}
while ( total ) {
2014-07-09 12:59:04 -04:00
tt = this . get ( ) ;
total -- ;
2014-02-12 05:23:40 -05:00
}
while ( total < index ) {
this . unget ( ) ;
total ++ ;
}
} else if ( index < 0 ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( this . _lt [ this . _ltIndex + index ] ) {
tt = this . _lt [ this . _ltIndex + index ] . type ;
} else {
throw new Error ( "Too much lookbehind." ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} else {
tt = this . _token . type ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return tt ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
LT : function ( index ) {
this . LA ( index ) ;
2014-07-09 12:59:04 -04:00
return this . _lt [ this . _ltIndex + index - 1 ] ;
2014-02-12 05:23:40 -05:00
} ,
peek : function ( ) {
return this . LA ( 1 ) ;
} ,
token : function ( ) {
return this . _token ;
} ,
tokenName : function ( tokenType ) {
if ( tokenType < 0 || tokenType > this . _tokenData . length ) {
return "UNKNOWN_TOKEN" ;
} else {
return this . _tokenData [ tokenType ] . name ;
}
} ,
tokenType : function ( tokenName ) {
return this . _tokenData [ tokenName ] || - 1 ;
} ,
unget : function ( ) {
if ( this . _ltIndexCache . length ) {
this . _ltIndex -= this . _ltIndexCache . pop ( ) ; //--;
this . _token = this . _lt [ this . _ltIndex - 1 ] ;
} else {
throw new Error ( "Too much lookahead." ) ;
}
}
} ;
parserlib . util = {
StringReader : StringReader ,
SyntaxError : SyntaxError ,
SyntaxUnit : SyntaxUnit ,
EventTarget : EventTarget ,
TokenStreamBase : TokenStreamBase
} ;
} ) ( ) ;
( function ( ) {
var EventTarget = parserlib . util . EventTarget ,
TokenStreamBase = parserlib . util . TokenStreamBase ,
StringReader = parserlib . util . StringReader ,
SyntaxError = parserlib . util . SyntaxError ,
SyntaxUnit = parserlib . util . SyntaxUnit ;
var Colors = {
aliceblue : "#f0f8ff" ,
antiquewhite : "#faebd7" ,
aqua : "#00ffff" ,
aquamarine : "#7fffd4" ,
azure : "#f0ffff" ,
beige : "#f5f5dc" ,
bisque : "#ffe4c4" ,
black : "#000000" ,
blanchedalmond : "#ffebcd" ,
blue : "#0000ff" ,
blueviolet : "#8a2be2" ,
brown : "#a52a2a" ,
burlywood : "#deb887" ,
cadetblue : "#5f9ea0" ,
chartreuse : "#7fff00" ,
chocolate : "#d2691e" ,
coral : "#ff7f50" ,
cornflowerblue : "#6495ed" ,
cornsilk : "#fff8dc" ,
crimson : "#dc143c" ,
cyan : "#00ffff" ,
darkblue : "#00008b" ,
darkcyan : "#008b8b" ,
darkgoldenrod : "#b8860b" ,
darkgray : "#a9a9a9" ,
2014-07-09 12:59:04 -04:00
darkgrey : "#a9a9a9" ,
2014-02-12 05:23:40 -05:00
darkgreen : "#006400" ,
darkkhaki : "#bdb76b" ,
darkmagenta : "#8b008b" ,
darkolivegreen : "#556b2f" ,
darkorange : "#ff8c00" ,
darkorchid : "#9932cc" ,
darkred : "#8b0000" ,
darksalmon : "#e9967a" ,
darkseagreen : "#8fbc8f" ,
darkslateblue : "#483d8b" ,
darkslategray : "#2f4f4f" ,
2014-07-09 12:59:04 -04:00
darkslategrey : "#2f4f4f" ,
2014-02-12 05:23:40 -05:00
darkturquoise : "#00ced1" ,
darkviolet : "#9400d3" ,
deeppink : "#ff1493" ,
deepskyblue : "#00bfff" ,
dimgray : "#696969" ,
2014-07-09 12:59:04 -04:00
dimgrey : "#696969" ,
2014-02-12 05:23:40 -05:00
dodgerblue : "#1e90ff" ,
firebrick : "#b22222" ,
floralwhite : "#fffaf0" ,
forestgreen : "#228b22" ,
fuchsia : "#ff00ff" ,
gainsboro : "#dcdcdc" ,
ghostwhite : "#f8f8ff" ,
gold : "#ffd700" ,
goldenrod : "#daa520" ,
gray : "#808080" ,
2014-07-09 12:59:04 -04:00
grey : "#808080" ,
2014-02-12 05:23:40 -05:00
green : "#008000" ,
greenyellow : "#adff2f" ,
honeydew : "#f0fff0" ,
hotpink : "#ff69b4" ,
indianred : "#cd5c5c" ,
indigo : "#4b0082" ,
ivory : "#fffff0" ,
khaki : "#f0e68c" ,
lavender : "#e6e6fa" ,
lavenderblush : "#fff0f5" ,
lawngreen : "#7cfc00" ,
lemonchiffon : "#fffacd" ,
lightblue : "#add8e6" ,
lightcoral : "#f08080" ,
lightcyan : "#e0ffff" ,
lightgoldenrodyellow : "#fafad2" ,
lightgray : "#d3d3d3" ,
2014-07-09 12:59:04 -04:00
lightgrey : "#d3d3d3" ,
2014-02-12 05:23:40 -05:00
lightgreen : "#90ee90" ,
lightpink : "#ffb6c1" ,
lightsalmon : "#ffa07a" ,
lightseagreen : "#20b2aa" ,
lightskyblue : "#87cefa" ,
lightslategray : "#778899" ,
2014-07-09 12:59:04 -04:00
lightslategrey : "#778899" ,
2014-02-12 05:23:40 -05:00
lightsteelblue : "#b0c4de" ,
lightyellow : "#ffffe0" ,
lime : "#00ff00" ,
limegreen : "#32cd32" ,
linen : "#faf0e6" ,
magenta : "#ff00ff" ,
maroon : "#800000" ,
mediumaquamarine : "#66cdaa" ,
mediumblue : "#0000cd" ,
mediumorchid : "#ba55d3" ,
mediumpurple : "#9370d8" ,
mediumseagreen : "#3cb371" ,
mediumslateblue : "#7b68ee" ,
mediumspringgreen : "#00fa9a" ,
mediumturquoise : "#48d1cc" ,
mediumvioletred : "#c71585" ,
midnightblue : "#191970" ,
mintcream : "#f5fffa" ,
mistyrose : "#ffe4e1" ,
moccasin : "#ffe4b5" ,
navajowhite : "#ffdead" ,
navy : "#000080" ,
oldlace : "#fdf5e6" ,
olive : "#808000" ,
olivedrab : "#6b8e23" ,
orange : "#ffa500" ,
orangered : "#ff4500" ,
orchid : "#da70d6" ,
palegoldenrod : "#eee8aa" ,
palegreen : "#98fb98" ,
paleturquoise : "#afeeee" ,
palevioletred : "#d87093" ,
papayawhip : "#ffefd5" ,
peachpuff : "#ffdab9" ,
peru : "#cd853f" ,
pink : "#ffc0cb" ,
plum : "#dda0dd" ,
powderblue : "#b0e0e6" ,
purple : "#800080" ,
red : "#ff0000" ,
rosybrown : "#bc8f8f" ,
royalblue : "#4169e1" ,
saddlebrown : "#8b4513" ,
salmon : "#fa8072" ,
sandybrown : "#f4a460" ,
seagreen : "#2e8b57" ,
seashell : "#fff5ee" ,
sienna : "#a0522d" ,
silver : "#c0c0c0" ,
skyblue : "#87ceeb" ,
slateblue : "#6a5acd" ,
slategray : "#708090" ,
2014-07-09 12:59:04 -04:00
slategrey : "#708090" ,
2014-02-12 05:23:40 -05:00
snow : "#fffafa" ,
springgreen : "#00ff7f" ,
steelblue : "#4682b4" ,
tan : "#d2b48c" ,
teal : "#008080" ,
thistle : "#d8bfd8" ,
tomato : "#ff6347" ,
turquoise : "#40e0d0" ,
violet : "#ee82ee" ,
wheat : "#f5deb3" ,
white : "#ffffff" ,
whitesmoke : "#f5f5f5" ,
yellow : "#ffff00" ,
yellowgreen : "#9acd32" ,
activeBorder : "Active window border." ,
activecaption : "Active window caption." ,
appworkspace : "Background color of multiple document interface." ,
background : "Desktop background." ,
buttonface : "The face background color for 3-D elements that appear 3-D due to one layer of surrounding border." ,
buttonhighlight : "The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border." ,
buttonshadow : "The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border." ,
buttontext : "Text on push buttons." ,
captiontext : "Text in caption, size box, and scrollbar arrow box." ,
graytext : "Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color." ,
2014-07-09 12:59:04 -04:00
greytext : "Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color." ,
2014-02-12 05:23:40 -05:00
highlight : "Item(s) selected in a control." ,
highlighttext : "Text of item(s) selected in a control." ,
inactiveborder : "Inactive window border." ,
inactivecaption : "Inactive window caption." ,
inactivecaptiontext : "Color of text in an inactive caption." ,
infobackground : "Background color for tooltip controls." ,
infotext : "Text color for tooltip controls." ,
menu : "Menu background." ,
menutext : "Text in menus." ,
scrollbar : "Scroll bar gray area." ,
threeddarkshadow : "The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border." ,
threedface : "The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border." ,
threedhighlight : "The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border." ,
threedlightshadow : "The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border." ,
threedshadow : "The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border." ,
window : "Window background." ,
windowframe : "Window frame." ,
windowtext : "Text in windows."
} ;
function Combinator ( text , line , col ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , text , line , col , Parser . COMBINATOR _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . type = "unknown" ;
if ( /^\s+$/ . test ( text ) ) {
this . type = "descendant" ;
} else if ( text == ">" ) {
this . type = "child" ;
} else if ( text == "+" ) {
this . type = "adjacent-sibling" ;
} else if ( text == "~" ) {
this . type = "sibling" ;
}
}
Combinator . prototype = new SyntaxUnit ( ) ;
Combinator . prototype . constructor = Combinator ;
function MediaFeature ( name , value ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , "(" + name + ( value !== null ? ":" + value : "" ) + ")" , name . startLine , name . startCol , Parser . MEDIA _FEATURE _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . name = name ;
this . value = value ;
}
MediaFeature . prototype = new SyntaxUnit ( ) ;
MediaFeature . prototype . constructor = MediaFeature ;
function MediaQuery ( modifier , mediaType , features , line , col ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , ( modifier ? modifier + " " : "" ) + ( mediaType ? mediaType : "" ) + ( mediaType && features . length > 0 ? " and " : "" ) + features . join ( " and " ) , line , col , Parser . MEDIA _QUERY _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . modifier = modifier ;
2014-07-09 12:59:04 -04:00
this . mediaType = mediaType ;
2014-02-12 05:23:40 -05:00
this . features = features ;
}
MediaQuery . prototype = new SyntaxUnit ( ) ;
MediaQuery . prototype . constructor = MediaQuery ;
function Parser ( options ) {
EventTarget . call ( this ) ;
this . options = options || { } ;
this . _tokenStream = null ;
}
Parser . DEFAULT _TYPE = 0 ;
Parser . COMBINATOR _TYPE = 1 ;
Parser . MEDIA _FEATURE _TYPE = 2 ;
Parser . MEDIA _QUERY _TYPE = 3 ;
Parser . PROPERTY _NAME _TYPE = 4 ;
Parser . PROPERTY _VALUE _TYPE = 5 ;
Parser . PROPERTY _VALUE _PART _TYPE = 6 ;
Parser . SELECTOR _TYPE = 7 ;
Parser . SELECTOR _PART _TYPE = 8 ;
Parser . SELECTOR _SUB _PART _TYPE = 9 ;
Parser . prototype = function ( ) {
var proto = new EventTarget ( ) , //new prototype
prop ,
additions = {
constructor : Parser ,
DEFAULT _TYPE : 0 ,
COMBINATOR _TYPE : 1 ,
MEDIA _FEATURE _TYPE : 2 ,
MEDIA _QUERY _TYPE : 3 ,
PROPERTY _NAME _TYPE : 4 ,
PROPERTY _VALUE _TYPE : 5 ,
PROPERTY _VALUE _PART _TYPE : 6 ,
SELECTOR _TYPE : 7 ,
SELECTOR _PART _TYPE : 8 ,
2014-07-09 12:59:04 -04:00
SELECTOR _SUB _PART _TYPE : 9 ,
2014-02-12 05:23:40 -05:00
_stylesheet : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
charset = null ,
count ,
token ,
tt ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( "startstylesheet" ) ;
this . _charset ( ) ;
2014-07-09 12:59:04 -04:00
this . _skipCruft ( ) ;
2014-02-12 05:23:40 -05:00
while ( tokenStream . peek ( ) == Tokens . IMPORT _SYM ) {
this . _import ( ) ;
this . _skipCruft ( ) ;
}
while ( tokenStream . peek ( ) == Tokens . NAMESPACE _SYM ) {
this . _namespace ( ) ;
this . _skipCruft ( ) ;
}
tt = tokenStream . peek ( ) ;
while ( tt > Tokens . EOF ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
try {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
switch ( tt ) {
case Tokens . MEDIA _SYM :
this . _media ( ) ;
this . _skipCruft ( ) ;
break ;
case Tokens . PAGE _SYM :
2014-07-09 12:59:04 -04:00
this . _page ( ) ;
2014-02-12 05:23:40 -05:00
this . _skipCruft ( ) ;
2014-07-09 12:59:04 -04:00
break ;
2014-02-12 05:23:40 -05:00
case Tokens . FONT _FACE _SYM :
2014-07-09 12:59:04 -04:00
this . _font _face ( ) ;
2014-02-12 05:23:40 -05:00
this . _skipCruft ( ) ;
2014-07-09 12:59:04 -04:00
break ;
2014-02-12 05:23:40 -05:00
case Tokens . KEYFRAMES _SYM :
2014-07-09 12:59:04 -04:00
this . _keyframes ( ) ;
this . _skipCruft ( ) ;
break ;
case Tokens . VIEWPORT _SYM :
this . _viewport ( ) ;
2014-02-12 05:23:40 -05:00
this . _skipCruft ( ) ;
2014-07-09 12:59:04 -04:00
break ;
2014-02-12 05:23:40 -05:00
case Tokens . UNKNOWN _SYM : //unknown @ rule
tokenStream . get ( ) ;
if ( ! this . options . strict ) {
this . fire ( {
type : "error" ,
error : null ,
message : "Unknown @ rule: " + tokenStream . LT ( 0 ) . value + "." ,
line : tokenStream . LT ( 0 ) . startLine ,
col : tokenStream . LT ( 0 ) . startCol
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
count = 0 ;
while ( tokenStream . advance ( [ Tokens . LBRACE , Tokens . RBRACE ] ) == Tokens . LBRACE ) {
count ++ ; //keep track of nesting depth
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( count ) {
tokenStream . advance ( [ Tokens . RBRACE ] ) ;
count -- ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} else {
throw new SyntaxError ( "Unknown @ rule." , tokenStream . LT ( 0 ) . startLine , tokenStream . LT ( 0 ) . startCol ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
break ;
case Tokens . S :
this . _readWhitespace ( ) ;
break ;
2014-07-09 12:59:04 -04:00
default :
2014-02-12 05:23:40 -05:00
if ( ! this . _ruleset ( ) ) {
switch ( tt ) {
case Tokens . CHARSET _SYM :
token = tokenStream . LT ( 1 ) ;
this . _charset ( false ) ;
throw new SyntaxError ( "@charset not allowed here." , token . startLine , token . startCol ) ;
case Tokens . IMPORT _SYM :
token = tokenStream . LT ( 1 ) ;
this . _import ( false ) ;
throw new SyntaxError ( "@import not allowed here." , token . startLine , token . startCol ) ;
case Tokens . NAMESPACE _SYM :
token = tokenStream . LT ( 1 ) ;
this . _namespace ( false ) ;
throw new SyntaxError ( "@namespace not allowed here." , token . startLine , token . startCol ) ;
default :
tokenStream . get ( ) ; //get the last token
this . _unexpectedToken ( tokenStream . token ( ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
}
}
} catch ( ex ) {
if ( ex instanceof SyntaxError && ! this . options . strict ) {
this . fire ( {
type : "error" ,
error : ex ,
message : ex . message ,
line : ex . line ,
col : ex . col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
} else {
throw ex ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tt = tokenStream . peek ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tt != Tokens . EOF ) {
this . _unexpectedToken ( tokenStream . token ( ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( "endstylesheet" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_charset : function ( emit ) {
var tokenStream = this . _tokenStream ,
charset ,
token ,
line ,
col ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . CHARSET _SYM ) ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
tokenStream . mustMatch ( Tokens . STRING ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
token = tokenStream . token ( ) ;
charset = token . value ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
tokenStream . mustMatch ( Tokens . SEMICOLON ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( emit !== false ) {
2014-07-09 12:59:04 -04:00
this . fire ( {
2014-02-12 05:23:40 -05:00
type : "charset" ,
charset : charset ,
line : line ,
col : col
} ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_import : function ( emit ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
tt ,
uri ,
importToken ,
mediaList = [ ] ;
tokenStream . mustMatch ( Tokens . IMPORT _SYM ) ;
importToken = tokenStream . token ( ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( [ Tokens . STRING , Tokens . URI ] ) ;
2015-02-12 05:36:57 -05:00
uri = tokenStream . token ( ) . value . replace ( /^(?:url\()?["']?([^"']+?)["']?\)?$/ , "$1" ) ;
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
mediaList = this . _media _query _list ( ) ;
tokenStream . mustMatch ( Tokens . SEMICOLON ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( emit !== false ) {
this . fire ( {
type : "import" ,
uri : uri ,
media : mediaList ,
line : importToken . startLine ,
col : importToken . startCol
} ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_namespace : function ( emit ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
line ,
col ,
prefix ,
uri ;
tokenStream . mustMatch ( Tokens . NAMESPACE _SYM ) ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
this . _readWhitespace ( ) ;
if ( tokenStream . match ( Tokens . IDENT ) ) {
prefix = tokenStream . token ( ) . value ;
this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( [ Tokens . STRING , Tokens . URI ] ) ;
2014-07-09 12:59:04 -04:00
uri = tokenStream . token ( ) . value . replace ( /(?:url\()?["']([^"']+)["']\)?/ , "$1" ) ;
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
tokenStream . mustMatch ( Tokens . SEMICOLON ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( emit !== false ) {
this . fire ( {
type : "namespace" ,
prefix : prefix ,
uri : uri ,
line : line ,
col : col
} ) ;
}
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_media : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ,
mediaList ; // = [];
tokenStream . mustMatch ( Tokens . MEDIA _SYM ) ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
this . _readWhitespace ( ) ;
2014-02-12 05:23:40 -05:00
mediaList = this . _media _query _list ( ) ;
tokenStream . mustMatch ( Tokens . LBRACE ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startmedia" ,
media : mediaList ,
line : line ,
col : col
} ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( true ) {
if ( tokenStream . peek ( ) == Tokens . PAGE _SYM ) {
this . _page ( ) ;
2015-02-12 05:36:57 -05:00
} else if ( tokenStream . peek ( ) == Tokens . FONT _FACE _SYM ) {
2014-07-09 12:59:04 -04:00
this . _font _face ( ) ;
2015-02-12 05:36:57 -05:00
} else if ( tokenStream . peek ( ) == Tokens . VIEWPORT _SYM ) {
this . _viewport ( ) ;
2014-02-12 05:23:40 -05:00
} else if ( ! this . _ruleset ( ) ) {
break ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . RBRACE ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endmedia" ,
media : mediaList ,
line : line ,
col : col
} ) ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_media _query _list : function ( ) {
var tokenStream = this . _tokenStream ,
mediaList = [ ] ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . peek ( ) == Tokens . IDENT || tokenStream . peek ( ) == Tokens . LPAREN ) {
mediaList . push ( this . _media _query ( ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( tokenStream . match ( Tokens . COMMA ) ) {
this . _readWhitespace ( ) ;
mediaList . push ( this . _media _query ( ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return mediaList ;
} ,
_media _query : function ( ) {
var tokenStream = this . _tokenStream ,
type = null ,
ident = null ,
token = null ,
expressions = [ ] ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . IDENT ) ) {
ident = tokenStream . token ( ) . value . toLowerCase ( ) ;
if ( ident != "only" && ident != "not" ) {
tokenStream . unget ( ) ;
ident = null ;
} else {
token = tokenStream . token ( ) ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . peek ( ) == Tokens . IDENT ) {
type = this . _media _type ( ) ;
if ( token === null ) {
token = tokenStream . token ( ) ;
}
} else if ( tokenStream . peek ( ) == Tokens . LPAREN ) {
if ( token === null ) {
token = tokenStream . LT ( 1 ) ;
}
expressions . push ( this . _media _expression ( ) ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
if ( type === null && expressions . length === 0 ) {
return null ;
2014-07-09 12:59:04 -04:00
} else {
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
while ( tokenStream . match ( Tokens . IDENT ) ) {
if ( tokenStream . token ( ) . value . toLowerCase ( ) != "and" ) {
this . _unexpectedToken ( tokenStream . token ( ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
expressions . push ( this . _media _expression ( ) ) ;
}
}
return new MediaQuery ( ident , type , expressions , token . startLine , token . startCol ) ;
} ,
_media _type : function ( ) {
2014-07-09 12:59:04 -04:00
return this . _media _feature ( ) ;
2014-02-12 05:23:40 -05:00
} ,
_media _expression : function ( ) {
var tokenStream = this . _tokenStream ,
feature = null ,
token ,
expression = null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . LPAREN ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
feature = this . _media _feature ( ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . COLON ) ) {
this . _readWhitespace ( ) ;
token = tokenStream . LT ( 1 ) ;
expression = this . _expression ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . RPAREN ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
return new MediaFeature ( feature , ( expression ? new SyntaxUnit ( expression , token . startLine , token . startCol ) : null ) ) ;
2014-02-12 05:23:40 -05:00
} ,
_media _feature : function ( ) {
var tokenStream = this . _tokenStream ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . IDENT ) ;
2014-07-09 12:59:04 -04:00
return SyntaxUnit . fromToken ( tokenStream . token ( ) ) ;
2014-02-12 05:23:40 -05:00
} ,
_page : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ,
identifier = null ,
pseudoPage = null ;
tokenStream . mustMatch ( Tokens . PAGE _SYM ) ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . IDENT ) ) {
identifier = tokenStream . token ( ) . value ;
if ( identifier . toLowerCase ( ) === "auto" ) {
this . _unexpectedToken ( tokenStream . token ( ) ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
if ( tokenStream . peek ( ) == Tokens . COLON ) {
pseudoPage = this . _pseudo _page ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startpage" ,
id : identifier ,
pseudo : pseudoPage ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
this . _readDeclarations ( true , true ) ;
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endpage" ,
id : identifier ,
pseudo : pseudoPage ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
} ,
_margin : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ,
marginSym = this . _margin _sym ( ) ;
if ( marginSym ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startpagemargin" ,
margin : marginSym ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
this . _readDeclarations ( true ) ;
this . fire ( {
type : "endpagemargin" ,
margin : marginSym ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
return true ;
} else {
return false ;
}
} ,
_margin _sym : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( [ Tokens . TOPLEFTCORNER _SYM , Tokens . TOPLEFT _SYM ,
Tokens . TOPCENTER _SYM , Tokens . TOPRIGHT _SYM , Tokens . TOPRIGHTCORNER _SYM ,
2014-07-09 12:59:04 -04:00
Tokens . BOTTOMLEFTCORNER _SYM , Tokens . BOTTOMLEFT _SYM ,
2014-02-12 05:23:40 -05:00
Tokens . BOTTOMCENTER _SYM , Tokens . BOTTOMRIGHT _SYM ,
2014-07-09 12:59:04 -04:00
Tokens . BOTTOMRIGHTCORNER _SYM , Tokens . LEFTTOP _SYM ,
2014-02-12 05:23:40 -05:00
Tokens . LEFTMIDDLE _SYM , Tokens . LEFTBOTTOM _SYM , Tokens . RIGHTTOP _SYM ,
Tokens . RIGHTMIDDLE _SYM , Tokens . RIGHTBOTTOM _SYM ] ) )
{
2014-07-09 12:59:04 -04:00
return SyntaxUnit . fromToken ( tokenStream . token ( ) ) ;
2014-02-12 05:23:40 -05:00
} else {
return null ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_pseudo _page : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . COLON ) ;
tokenStream . mustMatch ( Tokens . IDENT ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return tokenStream . token ( ) . value ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_font _face : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ;
tokenStream . mustMatch ( Tokens . FONT _FACE _SYM ) ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
this . fire ( {
type : "startfontface" ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
this . _readDeclarations ( true ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endfontface" ,
line : line ,
col : col
2014-07-09 12:59:04 -04:00
} ) ;
} ,
_viewport : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ;
tokenStream . mustMatch ( Tokens . VIEWPORT _SYM ) ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
this . _readWhitespace ( ) ;
this . fire ( {
type : "startviewport" ,
line : line ,
col : col
} ) ;
this . _readDeclarations ( true ) ;
this . fire ( {
type : "endviewport" ,
line : line ,
col : col
} ) ;
2014-02-12 05:23:40 -05:00
} ,
_operator : function ( inFunction ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
token = null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( [ Tokens . SLASH , Tokens . COMMA ] ) ||
( inFunction && tokenStream . match ( [ Tokens . PLUS , Tokens . STAR , Tokens . MINUS ] ) ) ) {
token = tokenStream . token ( ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return token ? PropertyValuePart . fromToken ( token ) : null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_combinator : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
value = null ,
token ;
2014-07-09 12:59:04 -04:00
if ( tokenStream . match ( [ Tokens . PLUS , Tokens . GREATER , Tokens . TILDE ] ) ) {
2014-02-12 05:23:40 -05:00
token = tokenStream . token ( ) ;
value = new Combinator ( token . value , token . startLine , token . startCol ) ;
this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return value ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_unary _operator : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( [ Tokens . MINUS , Tokens . PLUS ] ) ) {
return tokenStream . token ( ) . value ;
} else {
return null ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_property : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
value = null ,
hack = null ,
tokenValue ,
token ,
line ,
col ;
if ( tokenStream . peek ( ) == Tokens . STAR && this . options . starHack ) {
tokenStream . get ( ) ;
token = tokenStream . token ( ) ;
hack = token . value ;
line = token . startLine ;
col = token . startCol ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . IDENT ) ) {
token = tokenStream . token ( ) ;
tokenValue = token . value ;
if ( tokenValue . charAt ( 0 ) == "_" && this . options . underscoreHack ) {
hack = "_" ;
tokenValue = tokenValue . substring ( 1 ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
value = new PropertyName ( tokenValue , hack , ( line || token . startLine ) , ( col || token . startCol ) ) ;
this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return value ;
} ,
_ruleset : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
tt ,
selectors ;
try {
selectors = this . _selectors _group ( ) ;
} catch ( ex ) {
if ( ex instanceof SyntaxError && ! this . options . strict ) {
this . fire ( {
type : "error" ,
error : ex ,
message : ex . message ,
line : ex . line ,
col : ex . col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
tt = tokenStream . advance ( [ Tokens . RBRACE ] ) ;
if ( tt == Tokens . RBRACE ) {
} else {
throw ex ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} else {
throw ex ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return true ;
}
2014-07-09 12:59:04 -04:00
if ( selectors ) {
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startrule" ,
selectors : selectors ,
line : selectors [ 0 ] . line ,
col : selectors [ 0 ] . col
2014-07-09 12:59:04 -04:00
} ) ;
this . _readDeclarations ( true ) ;
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endrule" ,
selectors : selectors ,
line : selectors [ 0 ] . line ,
col : selectors [ 0 ] . col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return selectors ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_selectors _group : function ( ) {
var tokenStream = this . _tokenStream ,
selectors = [ ] ,
selector ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
selector = this . _selector ( ) ;
if ( selector !== null ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
selectors . push ( selector ) ;
while ( tokenStream . match ( Tokens . COMMA ) ) {
this . _readWhitespace ( ) ;
selector = this . _selector ( ) ;
if ( selector !== null ) {
selectors . push ( selector ) ;
} else {
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
}
}
}
return selectors . length ? selectors : null ;
} ,
_selector : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
selector = [ ] ,
nextSelector = null ,
combinator = null ,
ws = null ;
nextSelector = this . _simple _selector _sequence ( ) ;
if ( nextSelector === null ) {
return null ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
selector . push ( nextSelector ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
do {
combinator = this . _combinator ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( combinator !== null ) {
selector . push ( combinator ) ;
nextSelector = this . _simple _selector _sequence ( ) ;
if ( nextSelector === null ) {
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
} else {
selector . push ( nextSelector ) ;
}
} else {
2014-07-09 12:59:04 -04:00
if ( this . _readWhitespace ( ) ) {
2014-02-12 05:23:40 -05:00
ws = new Combinator ( tokenStream . token ( ) . value , tokenStream . token ( ) . startLine , tokenStream . token ( ) . startCol ) ;
combinator = this . _combinator ( ) ;
nextSelector = this . _simple _selector _sequence ( ) ;
2014-07-09 12:59:04 -04:00
if ( nextSelector === null ) {
2014-02-12 05:23:40 -05:00
if ( combinator !== null ) {
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
}
} else {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( combinator !== null ) {
selector . push ( combinator ) ;
} else {
selector . push ( ws ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
selector . push ( nextSelector ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} else {
break ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
} while ( true ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return new Selector ( selector , selector [ 0 ] . line , selector [ 0 ] . col ) ;
} ,
_simple _selector _sequence : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
elementName = null ,
modifiers = [ ] ,
selectorText = "" ,
components = [
function ( ) {
return tokenStream . match ( Tokens . HASH ) ?
new SelectorSubPart ( tokenStream . token ( ) . value , "id" , tokenStream . token ( ) . startLine , tokenStream . token ( ) . startCol ) :
null ;
} ,
this . _class ,
this . _attrib ,
this . _pseudo ,
this . _negation
] ,
i = 0 ,
len = components . length ,
component = null ,
found = false ,
line ,
col ;
line = tokenStream . LT ( 1 ) . startLine ;
col = tokenStream . LT ( 1 ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
elementName = this . _type _selector ( ) ;
if ( ! elementName ) {
elementName = this . _universal ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( elementName !== null ) {
selectorText += elementName ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
2014-07-09 12:59:04 -04:00
while ( true ) {
2014-02-12 05:23:40 -05:00
if ( tokenStream . peek ( ) === Tokens . S ) {
break ;
}
while ( i < len && component === null ) {
component = components [ i ++ ] . call ( this ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( component === null ) {
if ( selectorText === "" ) {
return null ;
} else {
break ;
}
} else {
i = 0 ;
modifiers . push ( component ) ;
2014-07-09 12:59:04 -04:00
selectorText += component . toString ( ) ;
2014-02-12 05:23:40 -05:00
component = null ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return selectorText !== "" ?
new SelectorPart ( elementName , modifiers , selectorText , line , col ) :
null ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_type _selector : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
ns = this . _namespace _prefix ( ) ,
elementName = this . _element _name ( ) ;
2014-07-09 12:59:04 -04:00
if ( ! elementName ) {
2014-02-12 05:23:40 -05:00
if ( ns ) {
tokenStream . unget ( ) ;
if ( ns . length > 1 ) {
tokenStream . unget ( ) ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return null ;
2014-07-09 12:59:04 -04:00
} else {
2014-02-12 05:23:40 -05:00
if ( ns ) {
elementName . text = ns + elementName . text ;
elementName . col -= ns . length ;
}
return elementName ;
}
} ,
_class : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
token ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . DOT ) ) {
2014-07-09 12:59:04 -04:00
tokenStream . mustMatch ( Tokens . IDENT ) ;
2014-02-12 05:23:40 -05:00
token = tokenStream . token ( ) ;
2014-07-09 12:59:04 -04:00
return new SelectorSubPart ( "." + token . value , "class" , token . startLine , token . startCol - 1 ) ;
2014-02-12 05:23:40 -05:00
} else {
return null ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
_element _name : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
token ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . IDENT ) ) {
token = tokenStream . token ( ) ;
2014-07-09 12:59:04 -04:00
return new SelectorSubPart ( token . value , "elementName" , token . startLine , token . startCol ) ;
2014-02-12 05:23:40 -05:00
} else {
return null ;
}
} ,
_namespace _prefix : function ( ) {
var tokenStream = this . _tokenStream ,
value = "" ;
if ( tokenStream . LA ( 1 ) === Tokens . PIPE || tokenStream . LA ( 2 ) === Tokens . PIPE ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( [ Tokens . IDENT , Tokens . STAR ] ) ) {
value += tokenStream . token ( ) . value ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . PIPE ) ;
value += "|" ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
return value . length ? value : null ;
2014-02-12 05:23:40 -05:00
} ,
_universal : function ( ) {
var tokenStream = this . _tokenStream ,
value = "" ,
ns ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
ns = this . _namespace _prefix ( ) ;
if ( ns ) {
value += ns ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . STAR ) ) {
value += "*" ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return value . length ? value : null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
_attrib : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
value = null ,
ns ,
token ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . LBRACKET ) ) {
token = tokenStream . token ( ) ;
value = token . value ;
value += this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
ns = this . _namespace _prefix ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ns ) {
value += ns ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . IDENT ) ;
2014-07-09 12:59:04 -04:00
value += tokenStream . token ( ) . value ;
2014-02-12 05:23:40 -05:00
value += this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( [ Tokens . PREFIXMATCH , Tokens . SUFFIXMATCH , Tokens . SUBSTRINGMATCH ,
Tokens . EQUALS , Tokens . INCLUDES , Tokens . DASHMATCH ] ) ) {
2014-07-09 12:59:04 -04:00
value += tokenStream . token ( ) . value ;
2014-02-12 05:23:40 -05:00
value += this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( [ Tokens . IDENT , Tokens . STRING ] ) ;
2014-07-09 12:59:04 -04:00
value += tokenStream . token ( ) . value ;
2014-02-12 05:23:40 -05:00
value += this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . RBRACKET ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return new SelectorSubPart ( value + "]" , "attribute" , token . startLine , token . startCol ) ;
} else {
return null ;
}
} ,
_pseudo : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
pseudo = null ,
colons = ":" ,
line ,
col ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . COLON ) ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . COLON ) ) {
colons += ":" ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . IDENT ) ) {
pseudo = tokenStream . token ( ) . value ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol - colons . length ;
} else if ( tokenStream . peek ( ) == Tokens . FUNCTION ) {
line = tokenStream . LT ( 1 ) . startLine ;
col = tokenStream . LT ( 1 ) . startCol - colons . length ;
pseudo = this . _functional _pseudo ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( pseudo ) {
pseudo = new SelectorSubPart ( colons + pseudo , "pseudo" , line , col ) ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return pseudo ;
} ,
_functional _pseudo : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
value = null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . FUNCTION ) ) {
value = tokenStream . token ( ) . value ;
value += this . _readWhitespace ( ) ;
value += this . _expression ( ) ;
tokenStream . mustMatch ( Tokens . RPAREN ) ;
value += ")" ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return value ;
} ,
_expression : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
value = "" ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( tokenStream . match ( [ Tokens . PLUS , Tokens . MINUS , Tokens . DIMENSION ,
Tokens . NUMBER , Tokens . STRING , Tokens . IDENT , Tokens . LENGTH ,
Tokens . FREQ , Tokens . ANGLE , Tokens . TIME ,
Tokens . RESOLUTION , Tokens . SLASH ] ) ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
value += tokenStream . token ( ) . value ;
2014-07-09 12:59:04 -04:00
value += this . _readWhitespace ( ) ;
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return value . length ? value : null ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_negation : function ( ) {
var tokenStream = this . _tokenStream ,
line ,
col ,
value = "" ,
arg ,
subpart = null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . NOT ) ) {
value = tokenStream . token ( ) . value ;
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
value += this . _readWhitespace ( ) ;
arg = this . _negation _arg ( ) ;
value += arg ;
value += this . _readWhitespace ( ) ;
tokenStream . match ( Tokens . RPAREN ) ;
value += tokenStream . token ( ) . value ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
subpart = new SelectorSubPart ( value , "not" , line , col ) ;
subpart . args . push ( arg ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return subpart ;
} ,
2014-07-09 12:59:04 -04:00
_negation _arg : function ( ) {
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
args = [
this . _type _selector ,
this . _universal ,
function ( ) {
return tokenStream . match ( Tokens . HASH ) ?
new SelectorSubPart ( tokenStream . token ( ) . value , "id" , tokenStream . token ( ) . startLine , tokenStream . token ( ) . startCol ) :
2014-07-09 12:59:04 -04:00
null ;
2014-02-12 05:23:40 -05:00
} ,
this . _class ,
this . _attrib ,
2014-07-09 12:59:04 -04:00
this . _pseudo
2014-02-12 05:23:40 -05:00
] ,
arg = null ,
i = 0 ,
len = args . length ,
elementName ,
line ,
col ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
line = tokenStream . LT ( 1 ) . startLine ;
col = tokenStream . LT ( 1 ) . startCol ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( i < len && arg === null ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
arg = args [ i ] . call ( this ) ;
i ++ ;
}
if ( arg === null ) {
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
}
if ( arg . type == "elementName" ) {
part = new SelectorPart ( arg , [ ] , arg . toString ( ) , line , col ) ;
} else {
part = new SelectorPart ( null , [ arg ] , arg . toString ( ) , line , col ) ;
}
2014-07-09 12:59:04 -04:00
return part ;
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_declaration : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
property = null ,
expr = null ,
prio = null ,
error = null ,
invalid = null ,
propertyName = "" ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
property = this . _property ( ) ;
if ( property !== null ) {
tokenStream . mustMatch ( Tokens . COLON ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
expr = this . _expr ( ) ;
if ( ! expr || expr . length === 0 ) {
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
prio = this . _prio ( ) ;
propertyName = property . toString ( ) ;
if ( this . options . starHack && property . hack == "*" ||
this . options . underscoreHack && property . hack == "_" ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
propertyName = property . text ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
try {
this . _validateProperty ( propertyName , expr ) ;
} catch ( ex ) {
invalid = ex ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "property" ,
property : property ,
value : expr ,
important : prio ,
line : property . line ,
col : property . col ,
invalid : invalid
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
return true ;
} else {
return false ;
}
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_prio : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
result = tokenStream . match ( Tokens . IMPORTANT _SYM ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
return result ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_expr : function ( inFunction ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
values = [ ] ,
value = null ,
operator = null ;
2014-07-09 12:59:04 -04:00
2015-02-12 05:36:57 -05:00
value = this . _term ( inFunction ) ;
2014-02-12 05:23:40 -05:00
if ( value !== null ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
values . push ( value ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
do {
operator = this . _operator ( inFunction ) ;
if ( operator ) {
values . push ( operator ) ;
} / * else {
values . push ( new PropertyValue ( valueParts , valueParts [ 0 ] . line , valueParts [ 0 ] . col ) ) ;
valueParts = [ ] ;
} * /
2014-07-09 12:59:04 -04:00
2015-02-12 05:36:57 -05:00
value = this . _term ( inFunction ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( value === null ) {
break ;
} else {
values . push ( value ) ;
}
} while ( true ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return values . length > 0 ? new PropertyValue ( values , values [ 0 ] . line , values [ 0 ] . col ) : null ;
} ,
2014-07-09 12:59:04 -04:00
2015-02-12 05:36:57 -05:00
_term : function ( inFunction ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
unary = null ,
value = null ,
2015-02-12 05:36:57 -05:00
endChar = null ,
2014-02-12 05:23:40 -05:00
token ,
line ,
col ;
unary = this . _unary _operator ( ) ;
if ( unary !== null ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
if ( tokenStream . peek ( ) == Tokens . IE _FUNCTION && this . options . ieFilters ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
value = this . _ie _function ( ) ;
if ( unary === null ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
}
2015-02-12 05:36:57 -05:00
} else if ( inFunction && tokenStream . match ( [ Tokens . LPAREN , Tokens . LBRACE , Tokens . LBRACKET ] ) ) {
token = tokenStream . token ( ) ;
endChar = token . endChar ;
value = token . value + this . _expr ( inFunction ) . text ;
if ( unary === null ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
}
tokenStream . mustMatch ( Tokens . type ( endChar ) ) ;
value += endChar ;
this . _readWhitespace ( ) ;
2014-02-12 05:23:40 -05:00
} else if ( tokenStream . match ( [ Tokens . NUMBER , Tokens . PERCENTAGE , Tokens . LENGTH ,
Tokens . ANGLE , Tokens . TIME ,
Tokens . FREQ , Tokens . STRING , Tokens . IDENT , Tokens . URI , Tokens . UNICODE _RANGE ] ) ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
value = tokenStream . token ( ) . value ;
if ( unary === null ) {
line = tokenStream . token ( ) . startLine ;
col = tokenStream . token ( ) . startCol ;
}
this . _readWhitespace ( ) ;
} else {
token = this . _hexcolor ( ) ;
if ( token === null ) {
if ( unary === null ) {
line = tokenStream . LT ( 1 ) . startLine ;
col = tokenStream . LT ( 1 ) . startCol ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
if ( value === null ) {
if ( tokenStream . LA ( 3 ) == Tokens . EQUALS && this . options . ieFilters ) {
value = this . _ie _function ( ) ;
} else {
value = this . _function ( ) ;
}
}
} else {
value = token . value ;
if ( unary === null ) {
line = token . startLine ;
col = token . startCol ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return value !== null ?
new PropertyValuePart ( unary !== null ? unary + value : value , line , col ) :
null ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_function : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
functionText = null ,
expr = null ,
lt ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . FUNCTION ) ) {
functionText = tokenStream . token ( ) . value ;
this . _readWhitespace ( ) ;
expr = this . _expr ( true ) ;
functionText += expr ;
if ( this . options . ieFilters && tokenStream . peek ( ) == Tokens . EQUALS ) {
do {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( this . _readWhitespace ( ) ) {
functionText += tokenStream . token ( ) . value ;
}
if ( tokenStream . LA ( 0 ) == Tokens . COMMA ) {
functionText += tokenStream . token ( ) . value ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . match ( Tokens . IDENT ) ;
functionText += tokenStream . token ( ) . value ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . match ( Tokens . EQUALS ) ;
functionText += tokenStream . token ( ) . value ;
lt = tokenStream . peek ( ) ;
while ( lt != Tokens . COMMA && lt != Tokens . S && lt != Tokens . RPAREN ) {
tokenStream . get ( ) ;
functionText += tokenStream . token ( ) . value ;
lt = tokenStream . peek ( ) ;
}
} while ( tokenStream . match ( [ Tokens . COMMA , Tokens . S ] ) ) ;
}
2014-07-09 12:59:04 -04:00
tokenStream . match ( Tokens . RPAREN ) ;
2014-02-12 05:23:40 -05:00
functionText += ")" ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return functionText ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_ie _function : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
functionText = null ,
expr = null ,
lt ;
if ( tokenStream . match ( [ Tokens . IE _FUNCTION , Tokens . FUNCTION ] ) ) {
functionText = tokenStream . token ( ) . value ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
do {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( this . _readWhitespace ( ) ) {
functionText += tokenStream . token ( ) . value ;
}
if ( tokenStream . LA ( 0 ) == Tokens . COMMA ) {
functionText += tokenStream . token ( ) . value ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . match ( Tokens . IDENT ) ;
functionText += tokenStream . token ( ) . value ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . match ( Tokens . EQUALS ) ;
functionText += tokenStream . token ( ) . value ;
lt = tokenStream . peek ( ) ;
while ( lt != Tokens . COMMA && lt != Tokens . S && lt != Tokens . RPAREN ) {
tokenStream . get ( ) ;
functionText += tokenStream . token ( ) . value ;
lt = tokenStream . peek ( ) ;
}
2014-07-09 12:59:04 -04:00
} while ( tokenStream . match ( [ Tokens . COMMA , Tokens . S ] ) ) ;
tokenStream . match ( Tokens . RPAREN ) ;
2014-02-12 05:23:40 -05:00
functionText += ")" ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return functionText ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
_hexcolor : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
token = null ,
color ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . HASH ) ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
token = tokenStream . token ( ) ;
color = token . value ;
if ( ! /#[a-f0-9]{3,6}/i . test ( color ) ) {
throw new SyntaxError ( "Expected a hex color but found '" + color + "' at line " + token . startLine + ", col " + token . startCol + "." , token . startLine , token . startCol ) ;
}
this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return token ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_keyframes : function ( ) {
var tokenStream = this . _tokenStream ,
token ,
tt ,
name ,
2014-07-09 12:59:04 -04:00
prefix = "" ;
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . KEYFRAMES _SYM ) ;
token = tokenStream . token ( ) ;
if ( /^@\-([^\-]+)\-/ . test ( token . value ) ) {
prefix = RegExp . $1 ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
name = this . _keyframe _name ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
tokenStream . mustMatch ( Tokens . LBRACE ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startkeyframes" ,
name : name ,
prefix : prefix ,
line : token . startLine ,
col : token . startCol
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
tt = tokenStream . peek ( ) ;
while ( tt == Tokens . IDENT || tt == Tokens . PERCENTAGE ) {
this . _keyframe _rule ( ) ;
this . _readWhitespace ( ) ;
tt = tokenStream . peek ( ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endkeyframes" ,
name : name ,
prefix : prefix ,
line : token . startLine ,
col : token . startCol
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
tokenStream . mustMatch ( Tokens . RBRACE ) ;
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_keyframe _name : function ( ) {
var tokenStream = this . _tokenStream ,
token ;
tokenStream . mustMatch ( [ Tokens . IDENT , Tokens . STRING ] ) ;
2014-07-09 12:59:04 -04:00
return SyntaxUnit . fromToken ( tokenStream . token ( ) ) ;
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_keyframe _rule : function ( ) {
var tokenStream = this . _tokenStream ,
token ,
keyList = this . _key _list ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "startkeyframerule" ,
keys : keyList ,
line : keyList [ 0 ] . line ,
col : keyList [ 0 ] . col
2014-07-09 12:59:04 -04:00
} ) ;
this . _readDeclarations ( true ) ;
2014-02-12 05:23:40 -05:00
this . fire ( {
type : "endkeyframerule" ,
keys : keyList ,
line : keyList [ 0 ] . line ,
col : keyList [ 0 ] . col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_key _list : function ( ) {
var tokenStream = this . _tokenStream ,
token ,
key ,
keyList = [ ] ;
keyList . push ( this . _key ( ) ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( tokenStream . match ( Tokens . COMMA ) ) {
this . _readWhitespace ( ) ;
keyList . push ( this . _key ( ) ) ;
this . _readWhitespace ( ) ;
}
return keyList ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
_key : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
token ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . PERCENTAGE ) ) {
return SyntaxUnit . fromToken ( tokenStream . token ( ) ) ;
} else if ( tokenStream . match ( Tokens . IDENT ) ) {
2014-07-09 12:59:04 -04:00
token = tokenStream . token ( ) ;
2014-02-12 05:23:40 -05:00
if ( /from|to/i . test ( token . value ) ) {
return SyntaxUnit . fromToken ( token ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . unget ( ) ;
}
this . _unexpectedToken ( tokenStream . LT ( 1 ) ) ;
} ,
_skipCruft : function ( ) {
while ( this . _tokenStream . match ( [ Tokens . S , Tokens . CDO , Tokens . CDC ] ) ) {
}
} ,
_readDeclarations : function ( checkStart , readMargins ) {
var tokenStream = this . _tokenStream ,
tt ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( checkStart ) {
2014-07-09 12:59:04 -04:00
tokenStream . mustMatch ( Tokens . LBRACE ) ;
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _readWhitespace ( ) ;
try {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( true ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( tokenStream . match ( Tokens . SEMICOLON ) || ( readMargins && this . _margin ( ) ) ) {
} else if ( this . _declaration ( ) ) {
if ( ! tokenStream . match ( Tokens . SEMICOLON ) ) {
break ;
}
} else {
break ;
}
this . _readWhitespace ( ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
tokenStream . mustMatch ( Tokens . RBRACE ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} catch ( ex ) {
if ( ex instanceof SyntaxError && ! this . options . strict ) {
this . fire ( {
type : "error" ,
error : ex ,
message : ex . message ,
line : ex . line ,
col : ex . col
2014-07-09 12:59:04 -04:00
} ) ;
2014-02-12 05:23:40 -05:00
tt = tokenStream . advance ( [ Tokens . SEMICOLON , Tokens . RBRACE ] ) ;
if ( tt == Tokens . SEMICOLON ) {
2014-07-09 12:59:04 -04:00
this . _readDeclarations ( false , readMargins ) ;
2014-02-12 05:23:40 -05:00
} else if ( tt != Tokens . RBRACE ) {
throw ex ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} else {
throw ex ;
}
2014-07-09 12:59:04 -04:00
}
} ,
2014-02-12 05:23:40 -05:00
_readWhitespace : function ( ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var tokenStream = this . _tokenStream ,
ws = "" ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( tokenStream . match ( Tokens . S ) ) {
ws += tokenStream . token ( ) . value ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return ws ;
} ,
_unexpectedToken : function ( token ) {
throw new SyntaxError ( "Unexpected token '" + token . value + "' at line " + token . startLine + ", col " + token . startCol + "." , token . startLine , token . startCol ) ;
} ,
_verifyEnd : function ( ) {
if ( this . _tokenStream . LA ( 1 ) != Tokens . EOF ) {
this . _unexpectedToken ( this . _tokenStream . LT ( 1 ) ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
_validateProperty : function ( property , value ) {
Validation . validate ( property , value ) ;
} ,
2014-07-09 12:59:04 -04:00
parse : function ( input ) {
2014-02-12 05:23:40 -05:00
this . _tokenStream = new TokenStream ( input , Tokens ) ;
this . _stylesheet ( ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
parseStyleSheet : function ( input ) {
return this . parse ( input ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
parseMediaQuery : function ( input ) {
this . _tokenStream = new TokenStream ( input , Tokens ) ;
var result = this . _media _query ( ) ;
this . _verifyEnd ( ) ;
2014-07-09 12:59:04 -04:00
return result ;
2014-02-12 05:23:40 -05:00
} ,
parsePropertyValue : function ( input ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _tokenStream = new TokenStream ( input , Tokens ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var result = this . _expr ( ) ;
this . _readWhitespace ( ) ;
this . _verifyEnd ( ) ;
return result ;
} ,
parseRule : function ( input ) {
this . _tokenStream = new TokenStream ( input , Tokens ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var result = this . _ruleset ( ) ;
this . _readWhitespace ( ) ;
this . _verifyEnd ( ) ;
2014-07-09 12:59:04 -04:00
return result ;
2014-02-12 05:23:40 -05:00
} ,
parseSelector : function ( input ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
this . _tokenStream = new TokenStream ( input , Tokens ) ;
this . _readWhitespace ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var result = this . _selector ( ) ;
this . _readWhitespace ( ) ;
this . _verifyEnd ( ) ;
return result ;
} ,
parseStyleAttribute : function ( input ) {
input += "}" ; // for error recovery in _readDeclarations()
this . _tokenStream = new TokenStream ( input , Tokens ) ;
this . _readDeclarations ( ) ;
}
} ;
for ( prop in additions ) {
if ( additions . hasOwnProperty ( prop ) ) {
proto [ prop ] = additions [ prop ] ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
return proto ;
} ( ) ;
var Properties = {
2014-07-09 12:59:04 -04:00
"align-items" : "flex-start | flex-end | center | baseline | stretch" ,
"align-content" : "flex-start | flex-end | center | space-between | space-around | stretch" ,
"align-self" : "auto | flex-start | flex-end | center | baseline | stretch" ,
"-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch" ,
"-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch" ,
"-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch" ,
2014-02-12 05:23:40 -05:00
"alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>" ,
"alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical" ,
"animation" : 1 ,
"animation-delay" : { multi : "<time>" , comma : true } ,
"animation-direction" : { multi : "normal | alternate" , comma : true } ,
"animation-duration" : { multi : "<time>" , comma : true } ,
2015-02-12 05:36:57 -05:00
"animation-fill-mode" : { multi : "none | forwards | backwards | both" , comma : true } ,
2014-02-12 05:23:40 -05:00
"animation-iteration-count" : { multi : "<number> | infinite" , comma : true } ,
"animation-name" : { multi : "none | <ident>" , comma : true } ,
"animation-play-state" : { multi : "running | paused" , comma : true } ,
"animation-timing-function" : 1 ,
"-moz-animation-delay" : { multi : "<time>" , comma : true } ,
"-moz-animation-direction" : { multi : "normal | alternate" , comma : true } ,
"-moz-animation-duration" : { multi : "<time>" , comma : true } ,
"-moz-animation-iteration-count" : { multi : "<number> | infinite" , comma : true } ,
"-moz-animation-name" : { multi : "none | <ident>" , comma : true } ,
"-moz-animation-play-state" : { multi : "running | paused" , comma : true } ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"-ms-animation-delay" : { multi : "<time>" , comma : true } ,
"-ms-animation-direction" : { multi : "normal | alternate" , comma : true } ,
"-ms-animation-duration" : { multi : "<time>" , comma : true } ,
"-ms-animation-iteration-count" : { multi : "<number> | infinite" , comma : true } ,
"-ms-animation-name" : { multi : "none | <ident>" , comma : true } ,
"-ms-animation-play-state" : { multi : "running | paused" , comma : true } ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"-webkit-animation-delay" : { multi : "<time>" , comma : true } ,
"-webkit-animation-direction" : { multi : "normal | alternate" , comma : true } ,
"-webkit-animation-duration" : { multi : "<time>" , comma : true } ,
2015-02-12 05:36:57 -05:00
"-webkit-animation-fill-mode" : { multi : "none | forwards | backwards | both" , comma : true } ,
2014-02-12 05:23:40 -05:00
"-webkit-animation-iteration-count" : { multi : "<number> | infinite" , comma : true } ,
"-webkit-animation-name" : { multi : "none | <ident>" , comma : true } ,
"-webkit-animation-play-state" : { multi : "running | paused" , comma : true } ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"-o-animation-delay" : { multi : "<time>" , comma : true } ,
"-o-animation-direction" : { multi : "normal | alternate" , comma : true } ,
"-o-animation-duration" : { multi : "<time>" , comma : true } ,
"-o-animation-iteration-count" : { multi : "<number> | infinite" , comma : true } ,
"-o-animation-name" : { multi : "none | <ident>" , comma : true } ,
2014-07-09 12:59:04 -04:00
"-o-animation-play-state" : { multi : "running | paused" , comma : true } ,
2014-02-12 05:23:40 -05:00
"appearance" : "icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit" ,
"azimuth" : function ( expression ) {
var simple = "<angle> | leftwards | rightwards | inherit" ,
direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side" ,
behind = false ,
valid = false ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! ValidationTypes . isAny ( expression , simple ) ) {
if ( ValidationTypes . isAny ( expression , "behind" ) ) {
behind = true ;
valid = true ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isAny ( expression , direction ) ) {
valid = true ;
if ( ! behind ) {
ValidationTypes . isAny ( expression , "behind" ) ;
}
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
if ( valid ) {
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
throw new ValidationError ( "Expected (<'azimuth'>) but found '" + part + "'." , part . line , part . col ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
"backface-visibility" : "visible | hidden" ,
"background" : 1 ,
"background-attachment" : { multi : "<attachment>" , comma : true } ,
"background-clip" : { multi : "<box>" , comma : true } ,
"background-color" : "<color> | inherit" ,
"background-image" : { multi : "<bg-image>" , comma : true } ,
"background-origin" : { multi : "<box>" , comma : true } ,
"background-position" : { multi : "<bg-position>" , comma : true } ,
"background-repeat" : { multi : "<repeat-style>" } ,
"background-size" : { multi : "<bg-size>" , comma : true } ,
"baseline-shift" : "baseline | sub | super | <percentage> | <length>" ,
"behavior" : 1 ,
"binding" : 1 ,
"bleed" : "<length>" ,
"bookmark-label" : "<content> | <attr> | <string>" ,
"bookmark-level" : "none | <integer>" ,
"bookmark-state" : "open | closed" ,
"bookmark-target" : "none | <uri> | <attr>" ,
"border" : "<border-width> || <border-style> || <color>" ,
"border-bottom" : "<border-width> || <border-style> || <color>" ,
2014-07-09 12:59:04 -04:00
"border-bottom-color" : "<color> | inherit" ,
2014-02-12 05:23:40 -05:00
"border-bottom-left-radius" : "<x-one-radius>" ,
"border-bottom-right-radius" : "<x-one-radius>" ,
"border-bottom-style" : "<border-style>" ,
"border-bottom-width" : "<border-width>" ,
"border-collapse" : "collapse | separate | inherit" ,
"border-color" : { multi : "<color> | inherit" , max : 4 } ,
"border-image" : 1 ,
"border-image-outset" : { multi : "<length> | <number>" , max : 4 } ,
"border-image-repeat" : { multi : "stretch | repeat | round" , max : 2 } ,
"border-image-slice" : function ( expression ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var valid = false ,
numeric = "<number> | <percentage>" ,
fill = false ,
count = 0 ,
max = 4 ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isAny ( expression , "fill" ) ) {
fill = true ;
valid = true ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( expression . hasNext ( ) && count < max ) {
valid = ValidationTypes . isAny ( expression , numeric ) ;
if ( ! valid ) {
break ;
}
count ++ ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! fill ) {
ValidationTypes . isAny ( expression , "fill" ) ;
} else {
valid = true ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
if ( valid ) {
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
throw new ValidationError ( "Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'." , part . line , part . col ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
"border-image-source" : "<image> | none" ,
"border-image-width" : { multi : "<length> | <percentage> | <number> | auto" , max : 4 } ,
"border-left" : "<border-width> || <border-style> || <color>" ,
"border-left-color" : "<color> | inherit" ,
"border-left-style" : "<border-style>" ,
"border-left-width" : "<border-width>" ,
"border-radius" : function ( expression ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var valid = false ,
2014-07-09 12:59:04 -04:00
simple = "<length> | <percentage> | inherit" ,
2014-02-12 05:23:40 -05:00
slash = false ,
fill = false ,
count = 0 ,
max = 8 ,
part ;
while ( expression . hasNext ( ) && count < max ) {
2014-07-09 12:59:04 -04:00
valid = ValidationTypes . isAny ( expression , simple ) ;
2014-02-12 05:23:40 -05:00
if ( ! valid ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . peek ( ) == "/" && count > 0 && ! slash ) {
slash = true ;
max = count + 5 ;
expression . next ( ) ;
} else {
break ;
}
}
count ++ ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
if ( valid ) {
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
throw new ValidationError ( "Expected (<'border-radius'>) but found '" + part + "'." , part . line , part . col ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
"border-right" : "<border-width> || <border-style> || <color>" ,
"border-right-color" : "<color> | inherit" ,
"border-right-style" : "<border-style>" ,
"border-right-width" : "<border-width>" ,
"border-spacing" : { multi : "<length> | inherit" , max : 2 } ,
"border-style" : { multi : "<border-style>" , max : 4 } ,
"border-top" : "<border-width> || <border-style> || <color>" ,
"border-top-color" : "<color> | inherit" ,
"border-top-left-radius" : "<x-one-radius>" ,
"border-top-right-radius" : "<x-one-radius>" ,
"border-top-style" : "<border-style>" ,
"border-top-width" : "<border-width>" ,
"border-width" : { multi : "<border-width>" , max : 4 } ,
2014-07-09 12:59:04 -04:00
"bottom" : "<margin-width> | inherit" ,
"-moz-box-align" : "start | end | center | baseline | stretch" ,
"-moz-box-decoration-break" : "slice |clone" ,
"-moz-box-direction" : "normal | reverse | inherit" ,
"-moz-box-flex" : "<number>" ,
"-moz-box-flex-group" : "<integer>" ,
"-moz-box-lines" : "single | multiple" ,
"-moz-box-ordinal-group" : "<integer>" ,
"-moz-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit" ,
"-moz-box-pack" : "start | end | center | justify" ,
"-webkit-box-align" : "start | end | center | baseline | stretch" ,
"-webkit-box-decoration-break" : "slice |clone" ,
"-webkit-box-direction" : "normal | reverse | inherit" ,
"-webkit-box-flex" : "<number>" ,
"-webkit-box-flex-group" : "<integer>" ,
"-webkit-box-lines" : "single | multiple" ,
"-webkit-box-ordinal-group" : "<integer>" ,
"-webkit-box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit" ,
"-webkit-box-pack" : "start | end | center | justify" ,
2014-02-12 05:23:40 -05:00
"box-shadow" : function ( expression ) {
var result = false ,
part ;
if ( ! ValidationTypes . isAny ( expression , "none" ) ) {
2014-07-09 12:59:04 -04:00
Validation . multiProperty ( "<shadow>" , expression , true , Infinity ) ;
2014-02-12 05:23:40 -05:00
} else {
if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
} ,
"box-sizing" : "content-box | border-box | inherit" ,
"break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column" ,
"break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column" ,
"break-inside" : "auto | avoid | avoid-page | avoid-column" ,
"caption-side" : "top | bottom | inherit" ,
"clear" : "none | right | left | both | inherit" ,
"clip" : 1 ,
"color" : "<color> | inherit" ,
"color-profile" : 1 ,
"column-count" : "<integer> | auto" , //http://www.w3.org/TR/css3-multicol/
"column-fill" : "auto | balance" ,
"column-gap" : "<length> | normal" ,
"column-rule" : "<border-width> || <border-style> || <color>" ,
"column-rule-color" : "<color>" ,
"column-rule-style" : "<border-style>" ,
"column-rule-width" : "<border-width>" ,
"column-span" : "none | all" ,
"column-width" : "<length> | auto" ,
"columns" : 1 ,
"content" : 1 ,
"counter-increment" : 1 ,
"counter-reset" : 1 ,
"crop" : "<shape> | auto" ,
"cue" : "cue-after | cue-before | inherit" ,
"cue-after" : 1 ,
"cue-before" : 1 ,
"cursor" : 1 ,
"direction" : "ltr | rtl | inherit" ,
2014-07-09 12:59:04 -04:00
"display" : "inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex" ,
2014-02-12 05:23:40 -05:00
"dominant-baseline" : 1 ,
"drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>" ,
"drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical" ,
"drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>" ,
"drop-initial-before-align" : "caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical" ,
"drop-initial-size" : "auto | line | <length> | <percentage>" ,
"drop-initial-value" : "initial | <integer>" ,
"elevation" : "<angle> | below | level | above | higher | lower | inherit" ,
"empty-cells" : "show | hide | inherit" ,
"filter" : 1 ,
"fit" : "fill | hidden | meet | slice" ,
"fit-position" : 1 ,
2015-02-12 05:36:57 -05:00
"flex" : "<flex>" ,
2014-07-09 12:59:04 -04:00
"flex-basis" : "<width>" ,
"flex-direction" : "row | row-reverse | column | column-reverse" ,
"flex-flow" : "<flex-direction> || <flex-wrap>" ,
"flex-grow" : "<number>" ,
"flex-shrink" : "<number>" ,
"flex-wrap" : "nowrap | wrap | wrap-reverse" ,
2015-02-12 05:36:57 -05:00
"-webkit-flex" : "<flex>" ,
2014-07-09 12:59:04 -04:00
"-webkit-flex-basis" : "<width>" ,
"-webkit-flex-direction" : "row | row-reverse | column | column-reverse" ,
"-webkit-flex-flow" : "<flex-direction> || <flex-wrap>" ,
"-webkit-flex-grow" : "<number>" ,
"-webkit-flex-shrink" : "<number>" ,
"-webkit-flex-wrap" : "nowrap | wrap | wrap-reverse" ,
2015-02-12 05:36:57 -05:00
"-ms-flex" : "<flex>" ,
2014-07-09 12:59:04 -04:00
"-ms-flex-align" : "start | end | center | stretch | baseline" ,
2015-02-12 05:36:57 -05:00
"-ms-flex-direction" : "row | row-reverse | column | column-reverse | inherit" ,
2014-07-09 12:59:04 -04:00
"-ms-flex-order" : "<number>" ,
"-ms-flex-pack" : "start | end | center | justify" ,
"-ms-flex-wrap" : "nowrap | wrap | wrap-reverse" ,
"float" : "left | right | none | inherit" ,
2014-02-12 05:23:40 -05:00
"float-offset" : 1 ,
"font" : 1 ,
"font-family" : 1 ,
"font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit" ,
"font-size-adjust" : "<number> | none | inherit" ,
"font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit" ,
"font-style" : "normal | italic | oblique | inherit" ,
"font-variant" : "normal | small-caps | inherit" ,
"font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit" ,
"grid-cell-stacking" : "columns | rows | layer" ,
"grid-column" : 1 ,
"grid-columns" : 1 ,
"grid-column-align" : "start | end | center | stretch" ,
"grid-column-sizing" : 1 ,
"grid-column-span" : "<integer>" ,
"grid-flow" : "none | rows | columns" ,
"grid-layer" : "<integer>" ,
"grid-row" : 1 ,
"grid-rows" : 1 ,
"grid-row-align" : "start | end | center | stretch" ,
"grid-row-span" : "<integer>" ,
"grid-row-sizing" : 1 ,
"hanging-punctuation" : 1 ,
2015-02-12 05:36:57 -05:00
"height" : "<margin-width> | <content-sizing> | inherit" ,
2014-02-12 05:23:40 -05:00
"hyphenate-after" : "<integer> | auto" ,
"hyphenate-before" : "<integer> | auto" ,
"hyphenate-character" : "<string> | auto" ,
"hyphenate-lines" : "no-limit | <integer>" ,
"hyphenate-resource" : 1 ,
"hyphens" : "none | manual | auto" ,
"icon" : 1 ,
"image-orientation" : "angle | auto" ,
"image-rendering" : 1 ,
"image-resolution" : 1 ,
"inline-box-align" : "initial | last | <integer>" ,
2014-07-09 12:59:04 -04:00
"justify-content" : "flex-start | flex-end | center | space-between | space-around" ,
"-webkit-justify-content" : "flex-start | flex-end | center | space-between | space-around" ,
2014-02-12 05:23:40 -05:00
"left" : "<margin-width> | inherit" ,
"letter-spacing" : "<length> | normal | inherit" ,
"line-height" : "<number> | <length> | <percentage> | normal | inherit" ,
"line-break" : "auto | loose | normal | strict" ,
"line-stacking" : 1 ,
"line-stacking-ruby" : "exclude-ruby | include-ruby" ,
"line-stacking-shift" : "consider-shifts | disregard-shifts" ,
"line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height" ,
"list-style" : 1 ,
"list-style-image" : "<uri> | none | inherit" ,
"list-style-position" : "inside | outside | inherit" ,
"list-style-type" : "disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit" ,
"margin" : { multi : "<margin-width> | inherit" , max : 4 } ,
"margin-bottom" : "<margin-width> | inherit" ,
"margin-left" : "<margin-width> | inherit" ,
"margin-right" : "<margin-width> | inherit" ,
"margin-top" : "<margin-width> | inherit" ,
"mark" : 1 ,
"mark-after" : 1 ,
"mark-before" : 1 ,
"marks" : 1 ,
"marquee-direction" : 1 ,
"marquee-play-count" : 1 ,
"marquee-speed" : 1 ,
"marquee-style" : 1 ,
2015-02-12 05:36:57 -05:00
"max-height" : "<length> | <percentage> | <content-sizing> | none | inherit" ,
"max-width" : "<length> | <percentage> | <content-sizing> | none | inherit" ,
"min-height" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit" ,
"min-width" : "<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit" ,
2014-02-12 05:23:40 -05:00
"move-to" : 1 ,
"nav-down" : 1 ,
"nav-index" : 1 ,
"nav-left" : 1 ,
"nav-right" : 1 ,
"nav-up" : 1 ,
"opacity" : "<number> | inherit" ,
2014-07-09 12:59:04 -04:00
"order" : "<integer>" ,
"-webkit-order" : "<integer>" ,
2014-02-12 05:23:40 -05:00
"orphans" : "<integer> | inherit" ,
"outline" : 1 ,
"outline-color" : "<color> | invert | inherit" ,
"outline-offset" : 1 ,
"outline-style" : "<border-style> | inherit" ,
"outline-width" : "<border-width> | inherit" ,
"overflow" : "visible | hidden | scroll | auto | inherit" ,
"overflow-style" : 1 ,
2014-07-09 12:59:04 -04:00
"overflow-wrap" : "normal | break-word" ,
2014-02-12 05:23:40 -05:00
"overflow-x" : 1 ,
"overflow-y" : 1 ,
"padding" : { multi : "<padding-width> | inherit" , max : 4 } ,
"padding-bottom" : "<padding-width> | inherit" ,
"padding-left" : "<padding-width> | inherit" ,
"padding-right" : "<padding-width> | inherit" ,
"padding-top" : "<padding-width> | inherit" ,
"page" : 1 ,
"page-break-after" : "auto | always | avoid | left | right | inherit" ,
"page-break-before" : "auto | always | avoid | left | right | inherit" ,
"page-break-inside" : "auto | avoid | inherit" ,
"page-policy" : 1 ,
"pause" : 1 ,
"pause-after" : 1 ,
"pause-before" : 1 ,
"perspective" : 1 ,
"perspective-origin" : 1 ,
"phonemes" : 1 ,
"pitch" : 1 ,
"pitch-range" : 1 ,
"play-during" : 1 ,
"pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit" ,
"position" : "static | relative | absolute | fixed | inherit" ,
"presentation-level" : 1 ,
"punctuation-trim" : 1 ,
"quotes" : 1 ,
"rendering-intent" : 1 ,
"resize" : 1 ,
"rest" : 1 ,
"rest-after" : 1 ,
"rest-before" : 1 ,
"richness" : 1 ,
"right" : "<margin-width> | inherit" ,
"rotation" : 1 ,
"rotation-point" : 1 ,
"ruby-align" : 1 ,
"ruby-overhang" : 1 ,
"ruby-position" : 1 ,
"ruby-span" : 1 ,
"size" : 1 ,
"speak" : "normal | none | spell-out | inherit" ,
"speak-header" : "once | always | inherit" ,
"speak-numeral" : "digits | continuous | inherit" ,
"speak-punctuation" : "code | none | inherit" ,
"speech-rate" : 1 ,
"src" : 1 ,
"stress" : 1 ,
"string-set" : 1 ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"table-layout" : "auto | fixed | inherit" ,
"tab-size" : "<integer> | <length>" ,
"target" : 1 ,
"target-name" : 1 ,
"target-new" : 1 ,
"target-position" : 1 ,
"text-align" : "left | right | center | justify | inherit" ,
"text-align-last" : 1 ,
"text-decoration" : 1 ,
"text-emphasis" : 1 ,
"text-height" : 1 ,
"text-indent" : "<length> | <percentage> | inherit" ,
"text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida" ,
"text-outline" : 1 ,
"text-overflow" : 1 ,
"text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit" ,
"text-shadow" : 1 ,
"text-transform" : "capitalize | uppercase | lowercase | none | inherit" ,
"text-wrap" : "normal | none | avoid" ,
"top" : "<margin-width> | inherit" ,
2014-07-09 12:59:04 -04:00
"-ms-touch-action" : "auto | none | pan-x | pan-y" ,
"touch-action" : "auto | none | pan-x | pan-y" ,
2014-02-12 05:23:40 -05:00
"transform" : 1 ,
"transform-origin" : 1 ,
"transform-style" : 1 ,
"transition" : 1 ,
"transition-delay" : 1 ,
"transition-duration" : 1 ,
"transition-property" : 1 ,
"transition-timing-function" : 1 ,
2014-07-09 12:59:04 -04:00
"unicode-bidi" : "normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit" ,
2014-02-12 05:23:40 -05:00
"user-modify" : "read-only | read-write | write-only | inherit" ,
"user-select" : "none | text | toggle | element | elements | all | inherit" ,
"vertical-align" : "auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>" ,
"visibility" : "visible | hidden | collapse | inherit" ,
"voice-balance" : 1 ,
"voice-duration" : 1 ,
"voice-family" : 1 ,
"voice-pitch" : 1 ,
"voice-pitch-range" : 1 ,
"voice-rate" : 1 ,
"voice-stress" : 1 ,
"voice-volume" : 1 ,
"volume" : 1 ,
"white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap" , //http://perishablepress.com/wrapping-content/
"white-space-collapse" : 1 ,
"widows" : "<integer> | inherit" ,
2015-02-12 05:36:57 -05:00
"width" : "<length> | <percentage> | <content-sizing> | auto | inherit" ,
2014-02-12 05:23:40 -05:00
"word-break" : "normal | keep-all | break-all" ,
"word-spacing" : "<length> | normal | inherit" ,
2014-07-09 12:59:04 -04:00
"word-wrap" : "normal | break-word" ,
"writing-mode" : "horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit" ,
2014-02-12 05:23:40 -05:00
"z-index" : "<integer> | auto | inherit" ,
"zoom" : "<number> | <percentage> | normal"
} ;
function PropertyName ( text , hack , line , col ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , text , line , col , Parser . PROPERTY _NAME _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . hack = hack ;
}
PropertyName . prototype = new SyntaxUnit ( ) ;
PropertyName . prototype . constructor = PropertyName ;
PropertyName . prototype . toString = function ( ) {
return ( this . hack ? this . hack : "" ) + this . text ;
} ;
function PropertyValue ( parts , line , col ) {
SyntaxUnit . call ( this , parts . join ( " " ) , line , col , Parser . PROPERTY _VALUE _TYPE ) ;
this . parts = parts ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
}
PropertyValue . prototype = new SyntaxUnit ( ) ;
PropertyValue . prototype . constructor = PropertyValue ;
function PropertyValueIterator ( value ) {
this . _i = 0 ;
this . _parts = value . parts ;
this . _marks = [ ] ;
this . value = value ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
PropertyValueIterator . prototype . count = function ( ) {
return this . _parts . length ;
} ;
PropertyValueIterator . prototype . isFirst = function ( ) {
return this . _i === 0 ;
} ;
PropertyValueIterator . prototype . hasNext = function ( ) {
return ( this . _i < this . _parts . length ) ;
} ;
PropertyValueIterator . prototype . mark = function ( ) {
this . _marks . push ( this . _i ) ;
} ;
PropertyValueIterator . prototype . peek = function ( count ) {
return this . hasNext ( ) ? this . _parts [ this . _i + ( count || 0 ) ] : null ;
} ;
PropertyValueIterator . prototype . next = function ( ) {
return this . hasNext ( ) ? this . _parts [ this . _i ++ ] : null ;
} ;
PropertyValueIterator . prototype . previous = function ( ) {
return this . _i > 0 ? this . _parts [ -- this . _i ] : null ;
} ;
PropertyValueIterator . prototype . restore = function ( ) {
if ( this . _marks . length ) {
this . _i = this . _marks . pop ( ) ;
}
} ;
function PropertyValuePart ( text , line , col ) {
SyntaxUnit . call ( this , text , line , col , Parser . PROPERTY _VALUE _PART _TYPE ) ;
this . type = "unknown" ;
var temp ;
if ( /^([+\-]?[\d\.]+)([a-z]+)$/i . test ( text ) ) { //dimension
this . type = "dimension" ;
this . value = + RegExp . $1 ;
this . units = RegExp . $2 ;
switch ( this . units . toLowerCase ( ) ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "em" :
case "rem" :
case "ex" :
case "px" :
case "cm" :
case "mm" :
case "in" :
case "pt" :
case "pc" :
case "ch" :
2014-07-09 12:59:04 -04:00
case "vh" :
case "vw" :
2015-02-12 05:36:57 -05:00
case "vmax" :
case "vmin" :
2014-02-12 05:23:40 -05:00
this . type = "length" ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "deg" :
case "rad" :
case "grad" :
this . type = "angle" ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "ms" :
case "s" :
this . type = "time" ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "hz" :
case "khz" :
this . type = "frequency" ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "dpi" :
case "dpcm" :
this . type = "resolution" ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} else if ( /^([+\-]?[\d\.]+)%$/i . test ( text ) ) { //percentage
this . type = "percentage" ;
this . value = + RegExp . $1 ;
} else if ( /^([+\-]?\d+)$/i . test ( text ) ) { //integer
this . type = "integer" ;
this . value = + RegExp . $1 ;
} else if ( /^([+\-]?[\d\.]+)$/i . test ( text ) ) { //number
this . type = "number" ;
this . value = + RegExp . $1 ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} else if ( /^#([a-f0-9]{3,6})/i . test ( text ) ) { //hexcolor
this . type = "color" ;
temp = RegExp . $1 ;
if ( temp . length == 3 ) {
this . red = parseInt ( temp . charAt ( 0 ) + temp . charAt ( 0 ) , 16 ) ;
this . green = parseInt ( temp . charAt ( 1 ) + temp . charAt ( 1 ) , 16 ) ;
2014-07-09 12:59:04 -04:00
this . blue = parseInt ( temp . charAt ( 2 ) + temp . charAt ( 2 ) , 16 ) ;
2014-02-12 05:23:40 -05:00
} else {
this . red = parseInt ( temp . substring ( 0 , 2 ) , 16 ) ;
this . green = parseInt ( temp . substring ( 2 , 4 ) , 16 ) ;
2014-07-09 12:59:04 -04:00
this . blue = parseInt ( temp . substring ( 4 , 6 ) , 16 ) ;
2014-02-12 05:23:40 -05:00
}
} else if ( /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i . test ( text ) ) { //rgb() color with absolute numbers
this . type = "color" ;
this . red = + RegExp . $1 ;
this . green = + RegExp . $2 ;
this . blue = + RegExp . $3 ;
} else if ( /^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i . test ( text ) ) { //rgb() color with percentages
this . type = "color" ;
this . red = + RegExp . $1 * 255 / 100 ;
this . green = + RegExp . $2 * 255 / 100 ;
this . blue = + RegExp . $3 * 255 / 100 ;
} else if ( /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i . test ( text ) ) { //rgba() color with absolute numbers
this . type = "color" ;
this . red = + RegExp . $1 ;
this . green = + RegExp . $2 ;
this . blue = + RegExp . $3 ;
this . alpha = + RegExp . $4 ;
} else if ( /^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i . test ( text ) ) { //rgba() color with percentages
this . type = "color" ;
this . red = + RegExp . $1 * 255 / 100 ;
this . green = + RegExp . $2 * 255 / 100 ;
this . blue = + RegExp . $3 * 255 / 100 ;
2014-07-09 12:59:04 -04:00
this . alpha = + RegExp . $4 ;
2014-02-12 05:23:40 -05:00
} else if ( /^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i . test ( text ) ) { //hsl()
this . type = "color" ;
this . hue = + RegExp . $1 ;
this . saturation = + RegExp . $2 / 100 ;
2014-07-09 12:59:04 -04:00
this . lightness = + RegExp . $3 / 100 ;
2014-02-12 05:23:40 -05:00
} else if ( /^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i . test ( text ) ) { //hsla() color with percentages
this . type = "color" ;
this . hue = + RegExp . $1 ;
this . saturation = + RegExp . $2 / 100 ;
2014-07-09 12:59:04 -04:00
this . lightness = + RegExp . $3 / 100 ;
this . alpha = + RegExp . $4 ;
2014-02-12 05:23:40 -05:00
} else if ( /^url\(["']?([^\)"']+)["']?\)/i . test ( text ) ) { //URI
this . type = "uri" ;
this . uri = RegExp . $1 ;
} else if ( /^([^\(]+)\(/i . test ( text ) ) {
this . type = "function" ;
this . name = RegExp . $1 ;
this . value = text ;
} else if ( /^["'][^"']*["']/ . test ( text ) ) { //string
this . type = "string" ;
this . value = eval ( text ) ;
} else if ( Colors [ text . toLowerCase ( ) ] ) { //named color
this . type = "color" ;
temp = Colors [ text . toLowerCase ( ) ] . substring ( 1 ) ;
this . red = parseInt ( temp . substring ( 0 , 2 ) , 16 ) ;
this . green = parseInt ( temp . substring ( 2 , 4 ) , 16 ) ;
2014-07-09 12:59:04 -04:00
this . blue = parseInt ( temp . substring ( 4 , 6 ) , 16 ) ;
2014-02-12 05:23:40 -05:00
} else if ( /^[\,\/]$/ . test ( text ) ) {
this . type = "operator" ;
this . value = text ;
2015-02-12 05:36:57 -05:00
} else if ( /^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i . test ( text ) ) {
2014-02-12 05:23:40 -05:00
this . type = "identifier" ;
this . value = text ;
}
}
PropertyValuePart . prototype = new SyntaxUnit ( ) ;
PropertyValuePart . prototype . constructor = PropertyValuePart ;
PropertyValuePart . fromToken = function ( token ) {
return new PropertyValuePart ( token . value , token . startLine , token . startCol ) ;
} ;
var Pseudos = {
":first-letter" : 1 ,
":first-line" : 1 ,
":before" : 1 ,
":after" : 1
} ;
Pseudos . ELEMENT = 1 ;
Pseudos . CLASS = 2 ;
Pseudos . isElement = function ( pseudo ) {
return pseudo . indexOf ( "::" ) === 0 || Pseudos [ pseudo . toLowerCase ( ) ] == Pseudos . ELEMENT ;
} ;
function Selector ( parts , line , col ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
SyntaxUnit . call ( this , parts . join ( " " ) , line , col , Parser . SELECTOR _TYPE ) ;
this . parts = parts ;
this . specificity = Specificity . calculate ( this ) ;
}
Selector . prototype = new SyntaxUnit ( ) ;
Selector . prototype . constructor = Selector ;
function SelectorPart ( elementName , modifiers , text , line , col ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , text , line , col , Parser . SELECTOR _PART _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . elementName = elementName ;
this . modifiers = modifiers ;
}
SelectorPart . prototype = new SyntaxUnit ( ) ;
SelectorPart . prototype . constructor = SelectorPart ;
function SelectorSubPart ( text , type , line , col ) {
2014-07-09 12:59:04 -04:00
SyntaxUnit . call ( this , text , line , col , Parser . SELECTOR _SUB _PART _TYPE ) ;
2014-02-12 05:23:40 -05:00
this . type = type ;
this . args = [ ] ;
}
SelectorSubPart . prototype = new SyntaxUnit ( ) ;
SelectorSubPart . prototype . constructor = SelectorSubPart ;
function Specificity ( a , b , c , d ) {
this . a = a ;
this . b = b ;
this . c = c ;
this . d = d ;
}
Specificity . prototype = {
constructor : Specificity ,
compare : function ( other ) {
var comps = [ "a" , "b" , "c" , "d" ] ,
i , len ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = comps . length ; i < len ; i ++ ) {
if ( this [ comps [ i ] ] < other [ comps [ i ] ] ) {
return - 1 ;
} else if ( this [ comps [ i ] ] > other [ comps [ i ] ] ) {
return 1 ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return 0 ;
} ,
valueOf : function ( ) {
return ( this . a * 1000 ) + ( this . b * 100 ) + ( this . c * 10 ) + this . d ;
} ,
toString : function ( ) {
return this . a + "," + this . b + "," + this . c + "," + this . d ;
}
} ;
Specificity . calculate = function ( selector ) {
var i , len ,
part ,
b = 0 , c = 0 , d = 0 ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
function updateValues ( part ) {
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
var i , j , len , num ,
elementName = part . elementName ? part . elementName . text : "" ,
modifier ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( elementName && elementName . charAt ( elementName . length - 1 ) != "*" ) {
d ++ ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = part . modifiers . length ; i < len ; i ++ ) {
modifier = part . modifiers [ i ] ;
switch ( modifier . type ) {
case "class" :
case "attribute" :
c ++ ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "id" :
b ++ ;
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "pseudo" :
if ( Pseudos . isElement ( modifier . text ) ) {
d ++ ;
} else {
c ++ ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
break ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
case "not" :
for ( j = 0 , num = modifier . args . length ; j < num ; j ++ ) {
updateValues ( modifier . args [ j ] ) ;
}
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = selector . parts . length ; i < len ; i ++ ) {
part = selector . parts [ i ] ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( part instanceof SelectorPart ) {
2014-07-09 12:59:04 -04:00
updateValues ( part ) ;
2014-02-12 05:23:40 -05:00
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return new Specificity ( 0 , b , c , d ) ;
} ;
var h = /^[0-9a-fA-F]$/ ,
nonascii = /^[\u0080-\uFFFF]$/ ,
nl = /\n|\r\n|\r|\f/ ;
function isHexDigit ( c ) {
return c !== null && h . test ( c ) ;
}
function isDigit ( c ) {
return c !== null && /\d/ . test ( c ) ;
}
function isWhitespace ( c ) {
return c !== null && /\s/ . test ( c ) ;
}
function isNewLine ( c ) {
return c !== null && nl . test ( c ) ;
}
function isNameStart ( c ) {
return c !== null && ( /[a-z_\u0080-\uFFFF\\]/i . test ( c ) ) ;
}
function isNameChar ( c ) {
return c !== null && ( isNameStart ( c ) || /[0-9\-\\]/ . test ( c ) ) ;
}
function isIdentStart ( c ) {
return c !== null && ( isNameStart ( c ) || /\-\\/ . test ( c ) ) ;
}
function mix ( receiver , supplier ) {
for ( var prop in supplier ) {
if ( supplier . hasOwnProperty ( prop ) ) {
receiver [ prop ] = supplier [ prop ] ;
}
}
return receiver ;
}
function TokenStream ( input ) {
TokenStreamBase . call ( this , input , Tokens ) ;
}
TokenStream . prototype = mix ( new TokenStreamBase ( ) , {
_getToken : function ( channel ) {
var c ,
reader = this . _reader ,
token = null ,
startLine = reader . getLine ( ) ,
startCol = reader . getCol ( ) ;
c = reader . read ( ) ;
while ( c ) {
switch ( c ) {
case "/" :
if ( reader . peek ( ) == "*" ) {
token = this . commentToken ( c , startLine , startCol ) ;
} else {
token = this . charToken ( c , startLine , startCol ) ;
}
break ;
case "|" :
case "~" :
case "^" :
case "$" :
case "*" :
if ( reader . peek ( ) == "=" ) {
token = this . comparisonToken ( c , startLine , startCol ) ;
} else {
token = this . charToken ( c , startLine , startCol ) ;
}
break ;
case "\"" :
case "'" :
token = this . stringToken ( c , startLine , startCol ) ;
break ;
case "#" :
if ( isNameChar ( reader . peek ( ) ) ) {
token = this . hashToken ( c , startLine , startCol ) ;
} else {
token = this . charToken ( c , startLine , startCol ) ;
}
break ;
case "." :
if ( isDigit ( reader . peek ( ) ) ) {
token = this . numberToken ( c , startLine , startCol ) ;
} else {
token = this . charToken ( c , startLine , startCol ) ;
}
break ;
case "-" :
if ( reader . peek ( ) == "-" ) { //could be closing HTML-style comment
token = this . htmlCommentEndToken ( c , startLine , startCol ) ;
} else if ( isNameStart ( reader . peek ( ) ) ) {
token = this . identOrFunctionToken ( c , startLine , startCol ) ;
} else {
token = this . charToken ( c , startLine , startCol ) ;
}
break ;
case "!" :
token = this . importantToken ( c , startLine , startCol ) ;
break ;
case "@" :
token = this . atRuleToken ( c , startLine , startCol ) ;
break ;
case ":" :
token = this . notToken ( c , startLine , startCol ) ;
break ;
case "<" :
token = this . htmlCommentStartToken ( c , startLine , startCol ) ;
break ;
case "U" :
case "u" :
if ( reader . peek ( ) == "+" ) {
token = this . unicodeRangeToken ( c , startLine , startCol ) ;
break ;
}
default :
if ( isDigit ( c ) ) {
token = this . numberToken ( c , startLine , startCol ) ;
} else
if ( isWhitespace ( c ) ) {
token = this . whitespaceToken ( c , startLine , startCol ) ;
} else
if ( isIdentStart ( c ) ) {
token = this . identOrFunctionToken ( c , startLine , startCol ) ;
} else
{
token = this . charToken ( c , startLine , startCol ) ;
}
}
break ;
}
if ( ! token && c === null ) {
token = this . createToken ( Tokens . EOF , null , startLine , startCol ) ;
}
return token ;
} ,
createToken : function ( tt , value , startLine , startCol , options ) {
var reader = this . _reader ;
options = options || { } ;
return {
value : value ,
type : tt ,
channel : options . channel ,
2015-02-12 05:36:57 -05:00
endChar : options . endChar ,
2014-02-12 05:23:40 -05:00
hide : options . hide || false ,
startLine : startLine ,
startCol : startCol ,
endLine : reader . getLine ( ) ,
endCol : reader . getCol ( )
} ;
} ,
atRuleToken : function ( first , startLine , startCol ) {
var rule = first ,
reader = this . _reader ,
tt = Tokens . CHAR ,
valid = false ,
ident ,
c ;
reader . mark ( ) ;
ident = this . readName ( ) ;
rule = first + ident ;
tt = Tokens . type ( rule . toLowerCase ( ) ) ;
if ( tt == Tokens . CHAR || tt == Tokens . UNKNOWN ) {
if ( rule . length > 1 ) {
2014-07-09 12:59:04 -04:00
tt = Tokens . UNKNOWN _SYM ;
2014-02-12 05:23:40 -05:00
} else {
tt = Tokens . CHAR ;
rule = first ;
reader . reset ( ) ;
}
}
return this . createToken ( tt , rule , startLine , startCol ) ;
} ,
charToken : function ( c , startLine , startCol ) {
var tt = Tokens . type ( c ) ;
2015-02-12 05:36:57 -05:00
var opts = { } ;
2014-02-12 05:23:40 -05:00
if ( tt == - 1 ) {
tt = Tokens . CHAR ;
2015-02-12 05:36:57 -05:00
} else {
opts . endChar = Tokens [ tt ] . endChar ;
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
return this . createToken ( tt , c , startLine , startCol , opts ) ;
2014-02-12 05:23:40 -05:00
} ,
commentToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
comment = this . readComment ( first ) ;
return this . createToken ( Tokens . COMMENT , comment , startLine , startCol ) ;
} ,
comparisonToken : function ( c , startLine , startCol ) {
var reader = this . _reader ,
comparison = c + reader . read ( ) ,
tt = Tokens . type ( comparison ) || Tokens . CHAR ;
return this . createToken ( tt , comparison , startLine , startCol ) ;
} ,
hashToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
name = this . readName ( first ) ;
return this . createToken ( Tokens . HASH , name , startLine , startCol ) ;
} ,
htmlCommentStartToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
text = first ;
reader . mark ( ) ;
text += reader . readCount ( 3 ) ;
if ( text == "<!--" ) {
return this . createToken ( Tokens . CDO , text , startLine , startCol ) ;
} else {
reader . reset ( ) ;
return this . charToken ( first , startLine , startCol ) ;
}
} ,
htmlCommentEndToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
text = first ;
reader . mark ( ) ;
text += reader . readCount ( 2 ) ;
if ( text == "-->" ) {
return this . createToken ( Tokens . CDC , text , startLine , startCol ) ;
} else {
reader . reset ( ) ;
return this . charToken ( first , startLine , startCol ) ;
}
} ,
identOrFunctionToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
ident = this . readName ( first ) ,
tt = Tokens . IDENT ;
if ( reader . peek ( ) == "(" ) {
ident += reader . read ( ) ;
if ( ident . toLowerCase ( ) == "url(" ) {
tt = Tokens . URI ;
ident = this . readURI ( ident ) ;
if ( ident . toLowerCase ( ) == "url(" ) {
tt = Tokens . FUNCTION ;
}
} else {
tt = Tokens . FUNCTION ;
}
} else if ( reader . peek ( ) == ":" ) { //might be an IE function
if ( ident . toLowerCase ( ) == "progid" ) {
ident += reader . readTo ( "(" ) ;
tt = Tokens . IE _FUNCTION ;
}
}
return this . createToken ( tt , ident , startLine , startCol ) ;
} ,
importantToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
important = first ,
tt = Tokens . CHAR ,
temp ,
c ;
reader . mark ( ) ;
c = reader . read ( ) ;
while ( c ) {
if ( c == "/" ) {
if ( reader . peek ( ) != "*" ) {
break ;
} else {
temp = this . readComment ( c ) ;
if ( temp === "" ) { //broken!
break ;
}
}
} else if ( isWhitespace ( c ) ) {
important += c + this . readWhitespace ( ) ;
} else if ( /i/i . test ( c ) ) {
temp = reader . readCount ( 8 ) ;
if ( /mportant/i . test ( temp ) ) {
important += c + temp ;
tt = Tokens . IMPORTANT _SYM ;
}
break ; //we're done
} else {
break ;
}
c = reader . read ( ) ;
}
if ( tt == Tokens . CHAR ) {
reader . reset ( ) ;
return this . charToken ( first , startLine , startCol ) ;
} else {
return this . createToken ( tt , important , startLine , startCol ) ;
}
} ,
notToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
text = first ;
reader . mark ( ) ;
text += reader . readCount ( 4 ) ;
if ( text . toLowerCase ( ) == ":not(" ) {
return this . createToken ( Tokens . NOT , text , startLine , startCol ) ;
} else {
reader . reset ( ) ;
return this . charToken ( first , startLine , startCol ) ;
}
} ,
numberToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
value = this . readNumber ( first ) ,
ident ,
tt = Tokens . NUMBER ,
c = reader . peek ( ) ;
if ( isIdentStart ( c ) ) {
ident = this . readName ( reader . read ( ) ) ;
value += ident ;
2015-02-12 05:36:57 -05:00
if ( /^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i . test ( ident ) ) {
2014-02-12 05:23:40 -05:00
tt = Tokens . LENGTH ;
} else if ( /^deg|^rad$|^grad$/i . test ( ident ) ) {
tt = Tokens . ANGLE ;
} else if ( /^ms$|^s$/i . test ( ident ) ) {
tt = Tokens . TIME ;
} else if ( /^hz$|^khz$/i . test ( ident ) ) {
tt = Tokens . FREQ ;
} else if ( /^dpi$|^dpcm$/i . test ( ident ) ) {
tt = Tokens . RESOLUTION ;
} else {
tt = Tokens . DIMENSION ;
}
} else if ( c == "%" ) {
value += reader . read ( ) ;
tt = Tokens . PERCENTAGE ;
}
return this . createToken ( tt , value , startLine , startCol ) ;
} ,
stringToken : function ( first , startLine , startCol ) {
var delim = first ,
string = first ,
reader = this . _reader ,
prev = first ,
tt = Tokens . STRING ,
c = reader . read ( ) ;
while ( c ) {
string += c ;
if ( c == delim && prev != "\\" ) {
break ;
}
if ( isNewLine ( reader . peek ( ) ) && c != "\\" ) {
tt = Tokens . INVALID ;
break ;
}
prev = c ;
c = reader . read ( ) ;
}
if ( c === null ) {
tt = Tokens . INVALID ;
}
return this . createToken ( tt , string , startLine , startCol ) ;
} ,
unicodeRangeToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
value = first ,
temp ,
tt = Tokens . CHAR ;
if ( reader . peek ( ) == "+" ) {
reader . mark ( ) ;
value += reader . read ( ) ;
value += this . readUnicodeRangePart ( true ) ;
if ( value . length == 2 ) {
reader . reset ( ) ;
} else {
tt = Tokens . UNICODE _RANGE ;
if ( value . indexOf ( "?" ) == - 1 ) {
if ( reader . peek ( ) == "-" ) {
reader . mark ( ) ;
temp = reader . read ( ) ;
temp += this . readUnicodeRangePart ( false ) ;
if ( temp . length == 1 ) {
reader . reset ( ) ;
} else {
value += temp ;
}
}
}
}
}
return this . createToken ( tt , value , startLine , startCol ) ;
} ,
whitespaceToken : function ( first , startLine , startCol ) {
var reader = this . _reader ,
value = first + this . readWhitespace ( ) ;
return this . createToken ( Tokens . S , value , startLine , startCol ) ;
} ,
readUnicodeRangePart : function ( allowQuestionMark ) {
var reader = this . _reader ,
part = "" ,
c = reader . peek ( ) ;
while ( isHexDigit ( c ) && part . length < 6 ) {
reader . read ( ) ;
part += c ;
c = reader . peek ( ) ;
}
if ( allowQuestionMark ) {
while ( c == "?" && part . length < 6 ) {
reader . read ( ) ;
part += c ;
c = reader . peek ( ) ;
}
}
return part ;
} ,
readWhitespace : function ( ) {
var reader = this . _reader ,
whitespace = "" ,
c = reader . peek ( ) ;
while ( isWhitespace ( c ) ) {
reader . read ( ) ;
whitespace += c ;
c = reader . peek ( ) ;
}
return whitespace ;
} ,
readNumber : function ( first ) {
var reader = this . _reader ,
number = first ,
hasDot = ( first == "." ) ,
c = reader . peek ( ) ;
while ( c ) {
if ( isDigit ( c ) ) {
number += reader . read ( ) ;
} else if ( c == "." ) {
if ( hasDot ) {
break ;
} else {
hasDot = true ;
number += reader . read ( ) ;
}
} else {
break ;
}
c = reader . peek ( ) ;
}
return number ;
} ,
readString : function ( ) {
var reader = this . _reader ,
delim = reader . read ( ) ,
string = delim ,
prev = delim ,
c = reader . peek ( ) ;
while ( c ) {
c = reader . read ( ) ;
string += c ;
if ( c == delim && prev != "\\" ) {
break ;
}
if ( isNewLine ( reader . peek ( ) ) && c != "\\" ) {
string = "" ;
break ;
}
prev = c ;
c = reader . peek ( ) ;
}
if ( c === null ) {
string = "" ;
}
return string ;
} ,
readURI : function ( first ) {
var reader = this . _reader ,
uri = first ,
inner = "" ,
c = reader . peek ( ) ;
reader . mark ( ) ;
while ( c && isWhitespace ( c ) ) {
reader . read ( ) ;
c = reader . peek ( ) ;
}
if ( c == "'" || c == "\"" ) {
inner = this . readString ( ) ;
} else {
inner = this . readURL ( ) ;
}
c = reader . peek ( ) ;
while ( c && isWhitespace ( c ) ) {
reader . read ( ) ;
c = reader . peek ( ) ;
}
if ( inner === "" || c != ")" ) {
uri = first ;
reader . reset ( ) ;
} else {
uri += inner + reader . read ( ) ;
}
return uri ;
} ,
readURL : function ( ) {
var reader = this . _reader ,
url = "" ,
c = reader . peek ( ) ;
while ( /^[!#$%&\\*-~]$/ . test ( c ) ) {
url += reader . read ( ) ;
c = reader . peek ( ) ;
}
return url ;
} ,
readName : function ( first ) {
var reader = this . _reader ,
ident = first || "" ,
c = reader . peek ( ) ;
while ( true ) {
if ( c == "\\" ) {
ident += this . readEscape ( reader . read ( ) ) ;
c = reader . peek ( ) ;
} else if ( c && isNameChar ( c ) ) {
ident += reader . read ( ) ;
c = reader . peek ( ) ;
} else {
break ;
}
}
return ident ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
readEscape : function ( first ) {
var reader = this . _reader ,
cssEscape = first || "" ,
i = 0 ,
2014-07-09 12:59:04 -04:00
c = reader . peek ( ) ;
2014-02-12 05:23:40 -05:00
if ( isHexDigit ( c ) ) {
do {
cssEscape += reader . read ( ) ;
c = reader . peek ( ) ;
} while ( c && isHexDigit ( c ) && ++ i < 6 ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( cssEscape . length == 3 && /\s/ . test ( c ) ||
cssEscape . length == 7 || cssEscape . length == 1 ) {
reader . read ( ) ;
} else {
c = "" ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return cssEscape + c ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
readComment : function ( first ) {
var reader = this . _reader ,
comment = first || "" ,
c = reader . read ( ) ;
if ( c == "*" ) {
while ( c ) {
comment += c ;
if ( comment . length > 2 && c == "*" && reader . peek ( ) == "/" ) {
comment += reader . read ( ) ;
break ;
}
c = reader . read ( ) ;
}
return comment ;
} else {
return "" ;
}
}
} ) ;
var Tokens = [
{ name : "CDO" } ,
{ name : "CDC" } ,
{ name : "S" , whitespace : true /*, channel: "ws"*/ } ,
{ name : "COMMENT" , comment : true , hide : true , channel : "comment" } ,
{ name : "INCLUDES" , text : "~=" } ,
{ name : "DASHMATCH" , text : "|=" } ,
{ name : "PREFIXMATCH" , text : "^=" } ,
{ name : "SUFFIXMATCH" , text : "$=" } ,
{ name : "SUBSTRINGMATCH" , text : "*=" } ,
2014-07-09 12:59:04 -04:00
{ name : "STRING" } ,
2014-02-12 05:23:40 -05:00
{ name : "IDENT" } ,
{ name : "HASH" } ,
{ name : "IMPORT_SYM" , text : "@import" } ,
{ name : "PAGE_SYM" , text : "@page" } ,
{ name : "MEDIA_SYM" , text : "@media" } ,
{ name : "FONT_FACE_SYM" , text : "@font-face" } ,
{ name : "CHARSET_SYM" , text : "@charset" } ,
{ name : "NAMESPACE_SYM" , text : "@namespace" } ,
2014-07-09 12:59:04 -04:00
{ name : "VIEWPORT_SYM" , text : [ "@viewport" , "@-ms-viewport" ] } ,
2014-02-12 05:23:40 -05:00
{ name : "UNKNOWN_SYM" } ,
{ name : "KEYFRAMES_SYM" , text : [ "@keyframes" , "@-webkit-keyframes" , "@-moz-keyframes" , "@-o-keyframes" ] } ,
{ name : "IMPORTANT_SYM" } ,
{ name : "LENGTH" } ,
{ name : "ANGLE" } ,
{ name : "TIME" } ,
{ name : "FREQ" } ,
{ name : "DIMENSION" } ,
{ name : "PERCENTAGE" } ,
{ name : "NUMBER" } ,
{ name : "URI" } ,
{ name : "FUNCTION" } ,
{ name : "UNICODE_RANGE" } ,
{ name : "INVALID" } ,
{ name : "PLUS" , text : "+" } ,
{ name : "GREATER" , text : ">" } ,
{ name : "COMMA" , text : "," } ,
{ name : "TILDE" , text : "~" } ,
2014-07-09 12:59:04 -04:00
{ name : "NOT" } ,
2014-02-12 05:23:40 -05:00
{ name : "TOPLEFTCORNER_SYM" , text : "@top-left-corner" } ,
{ name : "TOPLEFT_SYM" , text : "@top-left" } ,
{ name : "TOPCENTER_SYM" , text : "@top-center" } ,
{ name : "TOPRIGHT_SYM" , text : "@top-right" } ,
{ name : "TOPRIGHTCORNER_SYM" , text : "@top-right-corner" } ,
{ name : "BOTTOMLEFTCORNER_SYM" , text : "@bottom-left-corner" } ,
{ name : "BOTTOMLEFT_SYM" , text : "@bottom-left" } ,
{ name : "BOTTOMCENTER_SYM" , text : "@bottom-center" } ,
{ name : "BOTTOMRIGHT_SYM" , text : "@bottom-right" } ,
{ name : "BOTTOMRIGHTCORNER_SYM" , text : "@bottom-right-corner" } ,
{ name : "LEFTTOP_SYM" , text : "@left-top" } ,
{ name : "LEFTMIDDLE_SYM" , text : "@left-middle" } ,
{ name : "LEFTBOTTOM_SYM" , text : "@left-bottom" } ,
{ name : "RIGHTTOP_SYM" , text : "@right-top" } ,
{ name : "RIGHTMIDDLE_SYM" , text : "@right-middle" } ,
{ name : "RIGHTBOTTOM_SYM" , text : "@right-bottom" } ,
{ name : "RESOLUTION" , state : "media" } ,
{ name : "IE_FUNCTION" } ,
{ name : "CHAR" } ,
{
name : "PIPE" ,
text : "|"
} ,
{
name : "SLASH" ,
text : "/"
} ,
{
name : "MINUS" ,
text : "-"
} ,
{
name : "STAR" ,
text : "*"
} ,
{
name : "LBRACE" ,
2015-02-12 05:36:57 -05:00
endChar : "}" ,
2014-02-12 05:23:40 -05:00
text : "{"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "RBRACE" ,
text : "}"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "LBRACKET" ,
2015-02-12 05:36:57 -05:00
endChar : "]" ,
2014-02-12 05:23:40 -05:00
text : "["
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "RBRACKET" ,
text : "]"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "EQUALS" ,
text : "="
} ,
{
name : "COLON" ,
text : ":"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "SEMICOLON" ,
text : ";"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "LPAREN" ,
2015-02-12 05:36:57 -05:00
endChar : ")" ,
2014-02-12 05:23:40 -05:00
text : "("
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "RPAREN" ,
text : ")"
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
{
name : "DOT" ,
text : "."
}
] ;
( function ( ) {
var nameMap = [ ] ,
typeMap = { } ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
Tokens . UNKNOWN = - 1 ;
Tokens . unshift ( { name : "EOF" } ) ;
for ( var i = 0 , len = Tokens . length ; i < len ; i ++ ) {
nameMap . push ( Tokens [ i ] . name ) ;
Tokens [ Tokens [ i ] . name ] = i ;
if ( Tokens [ i ] . text ) {
if ( Tokens [ i ] . text instanceof Array ) {
for ( var j = 0 ; j < Tokens [ i ] . text . length ; j ++ ) {
typeMap [ Tokens [ i ] . text [ j ] ] = i ;
}
} else {
typeMap [ Tokens [ i ] . text ] = i ;
}
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
Tokens . name = function ( tt ) {
return nameMap [ tt ] ;
} ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
Tokens . type = function ( c ) {
return typeMap [ c ] || - 1 ;
} ;
} ) ( ) ;
var Validation = {
validate : function ( property , value ) {
var name = property . toString ( ) . toLowerCase ( ) ,
parts = value . parts ,
expression = new PropertyValueIterator ( value ) ,
spec = Properties [ name ] ,
part ,
2014-07-09 12:59:04 -04:00
valid ,
2014-02-12 05:23:40 -05:00
j , count ,
msg ,
types ,
last ,
literals ,
max , multi , group ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! spec ) {
if ( name . indexOf ( "-" ) !== 0 ) { //vendor prefixed are ok
throw new ValidationError ( "Unknown property '" + property + "'." , property . line , property . col ) ;
}
} else if ( typeof spec != "number" ) {
if ( typeof spec == "string" ) {
if ( spec . indexOf ( "||" ) > - 1 ) {
this . groupProperty ( spec , expression ) ;
} else {
this . singleProperty ( spec , expression , 1 ) ;
}
} else if ( spec . multi ) {
this . multiProperty ( spec . multi , expression , spec . comma , spec . max || Infinity ) ;
} else if ( typeof spec == "function" ) {
spec ( expression ) ;
}
}
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
singleProperty : function ( types , expression , max , partial ) {
var result = false ,
value = expression . value ,
count = 0 ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( expression . hasNext ( ) && count < max ) {
result = ValidationTypes . isAny ( expression , types ) ;
if ( ! result ) {
break ;
}
count ++ ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! result ) {
if ( expression . hasNext ( ) && ! expression . isFirst ( ) ) {
part = expression . peek ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
throw new ValidationError ( "Expected (" + types + ") but found '" + value + "'." , value . line , value . col ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} else if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
2014-07-09 12:59:04 -04:00
}
} ,
2014-02-12 05:23:40 -05:00
multiProperty : function ( types , expression , comma , max ) {
var result = false ,
value = expression . value ,
count = 0 ,
sep = false ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( expression . hasNext ( ) && ! result && count < max ) {
if ( ValidationTypes . isAny ( expression , types ) ) {
count ++ ;
if ( ! expression . hasNext ( ) ) {
result = true ;
} else if ( comma ) {
if ( expression . peek ( ) == "," ) {
part = expression . next ( ) ;
} else {
break ;
}
}
} else {
break ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! result ) {
if ( expression . hasNext ( ) && ! expression . isFirst ( ) ) {
part = expression . peek ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
part = expression . previous ( ) ;
if ( comma && part == "," ) {
2014-07-09 12:59:04 -04:00
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
2014-02-12 05:23:40 -05:00
} else {
throw new ValidationError ( "Expected (" + types + ") but found '" + value + "'." , value . line , value . col ) ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} else if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
groupProperty : function ( types , expression , comma ) {
var result = false ,
value = expression . value ,
typeCount = types . split ( "||" ) . length ,
groups = { count : 0 } ,
partial = false ,
name ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
while ( expression . hasNext ( ) && ! result ) {
name = ValidationTypes . isAnyOfGroup ( expression , types ) ;
if ( name ) {
if ( groups [ name ] ) {
break ;
} else {
groups [ name ] = 1 ;
groups . count ++ ;
partial = true ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( groups . count == typeCount || ! expression . hasNext ( ) ) {
result = true ;
}
}
} else {
break ;
}
}
2014-07-09 12:59:04 -04:00
if ( ! result ) {
2014-02-12 05:23:40 -05:00
if ( partial && expression . hasNext ( ) ) {
part = expression . peek ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
} else {
throw new ValidationError ( "Expected (" + types + ") but found '" + value + "'." , value . line , value . col ) ;
}
} else if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
throw new ValidationError ( "Expected end of value but found '" + part + "'." , part . line , part . col ) ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ;
function ValidationError ( message , line , col ) {
this . col = col ;
this . line = line ;
this . message = message ;
}
ValidationError . prototype = new Error ( ) ;
var ValidationTypes = {
isLiteral : function ( part , literals ) {
var text = part . text . toString ( ) . toLowerCase ( ) ,
args = literals . split ( " | " ) ,
i , len , found = false ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = args . length ; i < len && ! found ; i ++ ) {
if ( text == args [ i ] . toLowerCase ( ) ) {
found = true ;
}
}
2014-07-09 12:59:04 -04:00
return found ;
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
isSimple : function ( type ) {
return ! ! this . simple [ type ] ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
isComplex : function ( type ) {
return ! ! this . complex [ type ] ;
} ,
isAny : function ( expression , types ) {
var args = types . split ( " | " ) ,
i , len , found = false ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = args . length ; i < len && ! found && expression . hasNext ( ) ; i ++ ) {
found = this . isType ( expression , args [ i ] ) ;
}
2014-07-09 12:59:04 -04:00
return found ;
2014-02-12 05:23:40 -05:00
} ,
isAnyOfGroup : function ( expression , types ) {
var args = types . split ( " || " ) ,
i , len , found = false ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = args . length ; i < len && ! found ; i ++ ) {
found = this . isType ( expression , args [ i ] ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return found ? args [ i - 1 ] : false ;
} ,
isType : function ( expression , type ) {
var part = expression . peek ( ) ,
result = false ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( type . charAt ( 0 ) != "<" ) {
result = this . isLiteral ( part , type ) ;
if ( result ) {
expression . next ( ) ;
}
} else if ( this . simple [ type ] ) {
result = this . simple [ type ] ( part ) ;
if ( result ) {
expression . next ( ) ;
}
} else {
result = this . complex [ type ] ( expression ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return result ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
simple : {
"<absolute-size>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "xx-small | x-small | small | medium | large | x-large | xx-large" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<attachment>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "scroll | fixed | local" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<attr>" : function ( part ) {
return part . type == "function" && part . name == "attr" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<bg-image>" : function ( part ) {
return this [ "<image>" ] ( part ) || this [ "<gradient>" ] ( part ) || part == "none" ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
"<gradient>" : function ( part ) {
return part . type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i . test ( part ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<box>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "padding-box | border-box | content-box" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<content>" : function ( part ) {
return part . type == "function" && part . name == "content" ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
"<relative-size>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "smaller | larger" ) ;
} ,
"<ident>" : function ( part ) {
return part . type == "identifier" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<length>" : function ( part ) {
if ( part . type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?calc/i . test ( part ) ) {
return true ;
} else {
return part . type == "length" || part . type == "number" || part . type == "integer" || part == "0" ;
}
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<color>" : function ( part ) {
return part . type == "color" || part == "transparent" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<number>" : function ( part ) {
return part . type == "number" || this [ "<integer>" ] ( part ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<integer>" : function ( part ) {
return part . type == "integer" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<line>" : function ( part ) {
return part . type == "integer" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<angle>" : function ( part ) {
return part . type == "angle" ;
2014-07-09 12:59:04 -04:00
} ,
2014-02-12 05:23:40 -05:00
"<uri>" : function ( part ) {
return part . type == "uri" ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<image>" : function ( part ) {
return this [ "<uri>" ] ( part ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<percentage>" : function ( part ) {
return part . type == "percentage" || part == "0" ;
} ,
"<border-width>" : function ( part ) {
return this [ "<length>" ] ( part ) || ValidationTypes . isLiteral ( part , "thin | medium | thick" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<border-style>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset" ) ;
} ,
2014-07-09 12:59:04 -04:00
2015-02-12 05:36:57 -05:00
"<content-sizing>" : function ( part ) { // http://www.w3.org/TR/css3-sizing/#width-height-keywords
return ValidationTypes . isLiteral ( part , "fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content" ) ;
} ,
2014-02-12 05:23:40 -05:00
"<margin-width>" : function ( part ) {
return this [ "<length>" ] ( part ) || this [ "<percentage>" ] ( part ) || ValidationTypes . isLiteral ( part , "auto" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<padding-width>" : function ( part ) {
return this [ "<length>" ] ( part ) || this [ "<percentage>" ] ( part ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<shape>" : function ( part ) {
return part . type == "function" && ( part . name == "rect" || part . name == "inset-rect" ) ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<time>" : function ( part ) {
return part . type == "time" ;
2015-02-12 05:36:57 -05:00
} ,
"<flex-grow>" : function ( part ) {
return this [ "<number>" ] ( part ) ;
} ,
"<flex-shrink>" : function ( part ) {
return this [ "<number>" ] ( part ) ;
} ,
"<width>" : function ( part ) {
return this [ "<margin-width>" ] ( part ) ;
} ,
"<flex-basis>" : function ( part ) {
return this [ "<width>" ] ( part ) ;
} ,
"<flex-direction>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "row | row-reverse | column | column-reverse" ) ;
} ,
"<flex-wrap>" : function ( part ) {
return ValidationTypes . isLiteral ( part , "nowrap | wrap | wrap-reverse" ) ;
2014-02-12 05:23:40 -05:00
}
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
complex : {
"<bg-position>" : function ( expression ) {
var types = this ,
result = false ,
numeric = "<percentage> | <length>" ,
xDir = "left | right" ,
yDir = "top | bottom" ,
count = 0 ,
hasNext = function ( ) {
return expression . hasNext ( ) && expression . peek ( ) != "," ;
} ;
while ( expression . peek ( count ) && expression . peek ( count ) != "," ) {
count ++ ;
}
if ( count < 3 ) {
if ( ValidationTypes . isAny ( expression , xDir + " | center | " + numeric ) ) {
result = true ;
ValidationTypes . isAny ( expression , yDir + " | center | " + numeric ) ;
} else if ( ValidationTypes . isAny ( expression , yDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , xDir + " | center" ) ;
}
} else {
if ( ValidationTypes . isAny ( expression , xDir ) ) {
if ( ValidationTypes . isAny ( expression , yDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , numeric ) ;
} else if ( ValidationTypes . isAny ( expression , numeric ) ) {
if ( ValidationTypes . isAny ( expression , yDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , numeric ) ;
} else if ( ValidationTypes . isAny ( expression , "center" ) ) {
result = true ;
}
}
} else if ( ValidationTypes . isAny ( expression , yDir ) ) {
if ( ValidationTypes . isAny ( expression , xDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , numeric ) ;
} else if ( ValidationTypes . isAny ( expression , numeric ) ) {
if ( ValidationTypes . isAny ( expression , xDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , numeric ) ;
} else if ( ValidationTypes . isAny ( expression , "center" ) ) {
result = true ;
}
}
} else if ( ValidationTypes . isAny ( expression , "center" ) ) {
if ( ValidationTypes . isAny ( expression , xDir + " | " + yDir ) ) {
result = true ;
ValidationTypes . isAny ( expression , numeric ) ;
}
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return result ;
} ,
"<bg-size>" : function ( expression ) {
var types = this ,
result = false ,
numeric = "<percentage> | <length> | auto" ,
part ,
2014-07-09 12:59:04 -04:00
i , len ;
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isAny ( expression , "cover | contain" ) ) {
result = true ;
} else if ( ValidationTypes . isAny ( expression , numeric ) ) {
2014-07-09 12:59:04 -04:00
result = true ;
2014-02-12 05:23:40 -05:00
ValidationTypes . isAny ( expression , numeric ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return result ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<repeat-style>" : function ( expression ) {
var result = false ,
values = "repeat | space | round | no-repeat" ,
part ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . hasNext ( ) ) {
part = expression . next ( ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isLiteral ( part , "repeat-x | repeat-y" ) ) {
2014-07-09 12:59:04 -04:00
result = true ;
2014-02-12 05:23:40 -05:00
} else if ( ValidationTypes . isLiteral ( part , values ) ) {
result = true ;
if ( expression . hasNext ( ) && ValidationTypes . isLiteral ( expression . peek ( ) , values ) ) {
expression . next ( ) ;
}
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return result ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<shadow>" : function ( expression ) {
var result = false ,
count = 0 ,
inset = false ,
color = false ,
part ;
2014-07-09 12:59:04 -04:00
if ( expression . hasNext ( ) ) {
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isAny ( expression , "inset" ) ) {
inset = true ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ValidationTypes . isAny ( expression , "<color>" ) ) {
color = true ;
2014-07-09 12:59:04 -04:00
}
2014-02-12 05:23:40 -05:00
while ( ValidationTypes . isAny ( expression , "<length>" ) && count < 4 ) {
count ++ ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( expression . hasNext ( ) ) {
if ( ! color ) {
ValidationTypes . isAny ( expression , "<color>" ) ;
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
if ( ! inset ) {
ValidationTypes . isAny ( expression , "inset" ) ;
}
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
result = ( count >= 2 && count <= 4 ) ;
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
}
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
return result ;
} ,
2014-07-09 12:59:04 -04:00
2014-02-12 05:23:40 -05:00
"<x-one-radius>" : function ( expression ) {
var result = false ,
2014-07-09 12:59:04 -04:00
simple = "<length> | <percentage> | inherit" ;
if ( ValidationTypes . isAny ( expression , simple ) ) {
2014-02-12 05:23:40 -05:00
result = true ;
2014-07-09 12:59:04 -04:00
ValidationTypes . isAny ( expression , simple ) ;
}
2015-02-12 05:36:57 -05:00
return result ;
} ,
"<flex>" : function ( expression ) {
var part ,
result = false ;
if ( ValidationTypes . isAny ( expression , "none | inherit" ) ) {
result = true ;
} else {
if ( ValidationTypes . isType ( expression , "<flex-grow>" ) ) {
if ( expression . peek ( ) ) {
if ( ValidationTypes . isType ( expression , "<flex-shrink>" ) ) {
if ( expression . peek ( ) ) {
result = ValidationTypes . isType ( expression , "<flex-basis>" ) ;
} else {
result = true ;
}
} else if ( ValidationTypes . isType ( expression , "<flex-basis>" ) ) {
result = expression . peek ( ) === null ;
}
} else {
result = true ;
}
} else if ( ValidationTypes . isType ( expression , "<flex-basis>" ) ) {
result = true ;
}
}
if ( ! result ) {
part = expression . peek ( ) ;
throw new ValidationError ( "Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '" + expression . value . text + "'." , part . line , part . col ) ;
}
2014-02-12 05:23:40 -05:00
return result ;
}
}
} ;
parserlib . css = {
Colors : Colors ,
Combinator : Combinator ,
Parser : Parser ,
PropertyName : PropertyName ,
PropertyValue : PropertyValue ,
PropertyValuePart : PropertyValuePart ,
MediaFeature : MediaFeature ,
MediaQuery : MediaQuery ,
Selector : Selector ,
SelectorPart : SelectorPart ,
SelectorSubPart : SelectorSubPart ,
Specificity : Specificity ,
TokenStream : TokenStream ,
Tokens : Tokens ,
ValidationError : ValidationError
} ;
} ) ( ) ;
2014-07-09 12:59:04 -04:00
( function ( ) {
for ( var prop in parserlib ) {
exports [ prop ] = parserlib [ prop ] ;
}
} ) ( ) ;
2015-02-12 05:36:57 -05:00
function objectToString ( o ) {
return Object . prototype . toString . call ( o ) ;
}
var util = {
isArray : function ( ar ) {
return Array . isArray ( ar ) || ( typeof ar === 'object' && objectToString ( ar ) === '[object Array]' ) ;
} ,
isDate : function ( d ) {
return typeof d === 'object' && objectToString ( d ) === '[object Date]' ;
} ,
isRegExp : function ( re ) {
return typeof re === 'object' && objectToString ( re ) === '[object RegExp]' ;
} ,
getRegExpFlags : function ( re ) {
var flags = '' ;
re . global && ( flags += 'g' ) ;
re . ignoreCase && ( flags += 'i' ) ;
re . multiline && ( flags += 'm' ) ;
return flags ;
}
} ;
if ( typeof module === 'object' )
module . exports = clone ;
function clone ( parent , circular , depth , prototype ) {
var allParents = [ ] ;
var allChildren = [ ] ;
var useBuffer = typeof Buffer != 'undefined' ;
if ( typeof circular == 'undefined' )
circular = true ;
if ( typeof depth == 'undefined' )
depth = Infinity ;
function _clone ( parent , depth ) {
if ( parent === null )
return null ;
if ( depth == 0 )
return parent ;
var child ;
if ( typeof parent != 'object' ) {
return parent ;
}
if ( util . isArray ( parent ) ) {
child = [ ] ;
} else if ( util . isRegExp ( parent ) ) {
child = new RegExp ( parent . source , util . getRegExpFlags ( parent ) ) ;
if ( parent . lastIndex ) child . lastIndex = parent . lastIndex ;
} else if ( util . isDate ( parent ) ) {
child = new Date ( parent . getTime ( ) ) ;
} else if ( useBuffer && Buffer . isBuffer ( parent ) ) {
child = new Buffer ( parent . length ) ;
parent . copy ( child ) ;
return child ;
} else {
if ( typeof prototype == 'undefined' ) child = Object . create ( Object . getPrototypeOf ( parent ) ) ;
else child = Object . create ( prototype ) ;
}
if ( circular ) {
var index = allParents . indexOf ( parent ) ;
if ( index != - 1 ) {
return allChildren [ index ] ;
}
allParents . push ( parent ) ;
allChildren . push ( child ) ;
}
for ( var i in parent ) {
child [ i ] = _clone ( parent [ i ] , depth - 1 ) ;
}
return child ;
}
return _clone ( parent , depth ) ;
}
clone . clonePrototype = function ( parent ) {
if ( parent === null )
return null ;
var c = function ( ) { } ;
c . prototype = parent ;
return new c ( ) ;
} ;
2014-02-12 05:23:40 -05:00
var CSSLint = ( function ( ) {
var rules = [ ] ,
formatters = [ ] ,
embeddedRuleset = /\/\*csslint([^\*]*)\*\// ,
api = new parserlib . util . EventTarget ( ) ;
2014-07-09 12:59:04 -04:00
api . version = "@VERSION@" ;
2014-02-12 05:23:40 -05:00
api . addRule = function ( rule ) {
rules . push ( rule ) ;
rules [ rule . id ] = rule ;
} ;
api . clearRules = function ( ) {
rules = [ ] ;
} ;
api . getRules = function ( ) {
return [ ] . concat ( rules ) . sort ( function ( a , b ) {
return a . id > b . id ? 1 : 0 ;
} ) ;
} ;
api . getRuleset = function ( ) {
var ruleset = { } ,
i = 0 ,
len = rules . length ;
while ( i < len ) {
ruleset [ rules [ i ++ ] . id ] = 1 ; //by default, everything is a warning
}
return ruleset ;
} ;
function applyEmbeddedRuleset ( text , ruleset ) {
var valueMap ,
embedded = text && text . match ( embeddedRuleset ) ,
rules = embedded && embedded [ 1 ] ;
if ( rules ) {
valueMap = {
"true" : 2 , // true is error
"" : 1 , // blank is warning
"false" : 0 , // false is ignore
"2" : 2 , // explicit error
"1" : 1 , // explicit warning
"0" : 0 // explicit ignore
} ;
rules . toLowerCase ( ) . split ( "," ) . forEach ( function ( rule ) {
var pair = rule . split ( ":" ) ,
property = pair [ 0 ] || "" ,
value = pair [ 1 ] || "" ;
ruleset [ property . trim ( ) ] = valueMap [ value . trim ( ) ] ;
} ) ;
}
return ruleset ;
}
api . addFormatter = function ( formatter ) {
formatters [ formatter . id ] = formatter ;
} ;
api . getFormatter = function ( formatId ) {
return formatters [ formatId ] ;
} ;
api . format = function ( results , filename , formatId , options ) {
var formatter = this . getFormatter ( formatId ) ,
result = null ;
if ( formatter ) {
result = formatter . startFormat ( ) ;
result += formatter . formatResults ( results , filename , options || { } ) ;
result += formatter . endFormat ( ) ;
}
return result ;
} ;
api . hasFormat = function ( formatId ) {
return formatters . hasOwnProperty ( formatId ) ;
} ;
api . verify = function ( text , ruleset ) {
2015-02-12 05:36:57 -05:00
var i = 0 ,
2014-02-12 05:23:40 -05:00
reporter ,
lines ,
report ,
parser = new parserlib . css . Parser ( { starHack : true , ieFilters : true ,
underscoreHack : true , strict : false } ) ;
2015-02-12 05:36:57 -05:00
lines = text . replace ( /\n\r?/g , "$split$" ) . split ( "$split$" ) ;
2014-02-12 05:23:40 -05:00
if ( ! ruleset ) {
ruleset = this . getRuleset ( ) ;
}
if ( embeddedRuleset . test ( text ) ) {
2015-02-12 05:36:57 -05:00
ruleset = clone ( ruleset ) ;
2014-02-12 05:23:40 -05:00
ruleset = applyEmbeddedRuleset ( text , ruleset ) ;
}
reporter = new Reporter ( lines , ruleset ) ;
ruleset . errors = 2 ; //always report parsing errors as errors
for ( i in ruleset ) {
if ( ruleset . hasOwnProperty ( i ) && ruleset [ i ] ) {
if ( rules [ i ] ) {
rules [ i ] . init ( parser , reporter ) ;
}
}
}
try {
parser . parse ( text ) ;
} catch ( ex ) {
reporter . error ( "Fatal error, cannot continue: " + ex . message , ex . line , ex . col , { } ) ;
}
report = {
messages : reporter . messages ,
stats : reporter . stats ,
ruleset : reporter . ruleset
} ;
report . messages . sort ( function ( a , b ) {
if ( a . rollup && ! b . rollup ) {
return 1 ;
} else if ( ! a . rollup && b . rollup ) {
return - 1 ;
} else {
return a . line - b . line ;
}
} ) ;
return report ;
} ;
return api ;
} ) ( ) ;
function Reporter ( lines , ruleset ) {
this . messages = [ ] ;
this . stats = [ ] ;
this . lines = lines ;
this . ruleset = ruleset ;
}
Reporter . prototype = {
constructor : Reporter ,
error : function ( message , line , col , rule ) {
this . messages . push ( {
type : "error" ,
line : line ,
col : col ,
message : message ,
evidence : this . lines [ line - 1 ] ,
rule : rule || { }
} ) ;
} ,
warn : function ( message , line , col , rule ) {
this . report ( message , line , col , rule ) ;
} ,
report : function ( message , line , col , rule ) {
this . messages . push ( {
2015-02-12 05:36:57 -05:00
type : this . ruleset [ rule . id ] === 2 ? "error" : "warning" ,
2014-02-12 05:23:40 -05:00
line : line ,
col : col ,
message : message ,
evidence : this . lines [ line - 1 ] ,
rule : rule
} ) ;
} ,
info : function ( message , line , col , rule ) {
this . messages . push ( {
type : "info" ,
line : line ,
col : col ,
message : message ,
evidence : this . lines [ line - 1 ] ,
rule : rule
} ) ;
} ,
rollupError : function ( message , rule ) {
this . messages . push ( {
type : "error" ,
rollup : true ,
message : message ,
rule : rule
} ) ;
} ,
rollupWarn : function ( message , rule ) {
this . messages . push ( {
type : "warning" ,
rollup : true ,
message : message ,
rule : rule
} ) ;
} ,
stat : function ( name , value ) {
this . stats [ name ] = value ;
}
} ;
CSSLint . _Reporter = Reporter ;
CSSLint . Util = {
mix : function ( receiver , supplier ) {
var prop ;
for ( prop in supplier ) {
if ( supplier . hasOwnProperty ( prop ) ) {
receiver [ prop ] = supplier [ prop ] ;
}
}
return prop ;
} ,
indexOf : function ( values , value ) {
if ( values . indexOf ) {
return values . indexOf ( value ) ;
} else {
for ( var i = 0 , len = values . length ; i < len ; i ++ ) {
if ( values [ i ] === value ) {
return i ;
}
}
return - 1 ;
}
} ,
forEach : function ( values , func ) {
if ( values . forEach ) {
return values . forEach ( func ) ;
} else {
for ( var i = 0 , len = values . length ; i < len ; i ++ ) {
func ( values [ i ] , i , values ) ;
}
}
}
} ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "adjoining-classes" ,
name : "Disallow adjoining classes" ,
desc : "Don't use adjoining classes." ,
browsers : "IE6" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
modifier ,
classCount ,
i , j , k ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
for ( j = 0 ; j < selector . parts . length ; j ++ ) {
part = selector . parts [ j ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
classCount = 0 ;
for ( k = 0 ; k < part . modifiers . length ; k ++ ) {
modifier = part . modifiers [ k ] ;
2015-02-12 05:36:57 -05:00
if ( modifier . type === "class" ) {
2014-02-12 05:23:40 -05:00
classCount ++ ;
}
if ( classCount > 1 ) {
reporter . report ( "Don't use adjoining classes." , part . line , part . col , rule ) ;
}
}
}
}
}
} ) ;
}
} ) ;
CSSLint . addRule ( {
id : "box-model" ,
name : "Beware of broken box size" ,
desc : "Don't use width or height when using padding or border." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
widthProperties = {
border : 1 ,
"border-left" : 1 ,
"border-right" : 1 ,
padding : 1 ,
"padding-left" : 1 ,
"padding-right" : 1
} ,
heightProperties = {
border : 1 ,
"border-bottom" : 1 ,
"border-top" : 1 ,
padding : 1 ,
"padding-bottom" : 1 ,
"padding-top" : 1
} ,
properties ,
boxSizing = false ;
function startRule ( ) {
properties = { } ;
boxSizing = false ;
}
function endRule ( ) {
var prop , value ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( ! boxSizing ) {
if ( properties . height ) {
for ( prop in heightProperties ) {
if ( heightProperties . hasOwnProperty ( prop ) && properties [ prop ] ) {
value = properties [ prop ] . value ;
2015-02-12 05:36:57 -05:00
if ( ! ( prop === "padding" && value . parts . length === 2 && value . parts [ 0 ] . value === 0 ) ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Using height with " + prop + " can sometimes make elements larger than you expect." , properties [ prop ] . line , properties [ prop ] . col , rule ) ;
}
}
}
}
if ( properties . width ) {
for ( prop in widthProperties ) {
if ( widthProperties . hasOwnProperty ( prop ) && properties [ prop ] ) {
value = properties [ prop ] . value ;
2015-02-12 05:36:57 -05:00
if ( ! ( prop === "padding" && value . parts . length === 2 && value . parts [ 1 ] . value === 0 ) ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Using width with " + prop + " can sometimes make elements larger than you expect." , properties [ prop ] . line , properties [ prop ] . col , rule ) ;
}
}
}
2015-02-12 05:36:57 -05:00
}
}
2014-02-12 05:23:40 -05:00
}
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startkeyframerule" , startRule ) ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "property" , function ( event ) {
var name = event . property . text . toLowerCase ( ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( heightProperties [ name ] || widthProperties [ name ] ) {
2015-02-12 05:36:57 -05:00
if ( ! /^0\S*$/ . test ( event . value ) && ! ( name === "border" && event . value . toString ( ) === "none" ) ) {
2014-02-12 05:23:40 -05:00
properties [ name ] = { line : event . property . line , col : event . property . col , value : event . value } ;
}
} else {
if ( /^(width|height)/i . test ( name ) && /^(length|percentage)/ . test ( event . value . parts [ 0 ] . type ) ) {
properties [ name ] = 1 ;
2015-02-12 05:36:57 -05:00
} else if ( name === "box-sizing" ) {
2014-02-12 05:23:40 -05:00
boxSizing = true ;
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
} ) ;
parser . addListener ( "endrule" , endRule ) ;
parser . addListener ( "endfontface" , endRule ) ;
parser . addListener ( "endpage" , endRule ) ;
parser . addListener ( "endpagemargin" , endRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endkeyframerule" , endRule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "box-sizing" ,
name : "Disallow use of box-sizing" ,
desc : "The box-sizing properties isn't supported in IE6 and IE7." ,
browsers : "IE6, IE7" ,
tags : [ "Compatibility" ] ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "property" , function ( event ) {
var name = event . property . text . toLowerCase ( ) ;
2015-02-12 05:36:57 -05:00
if ( name === "box-sizing" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "The box-sizing property isn't supported in IE6 and IE7." , event . line , event . col , rule ) ;
}
2015-02-12 05:36:57 -05:00
} ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "bulletproof-font-face" ,
name : "Use the bulletproof @font-face syntax" ,
desc : "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
fontFaceRule = false ,
firstSrc = true ,
ruleFailed = false ,
line , col ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startfontface" , function ( ) {
2014-02-12 05:23:40 -05:00
fontFaceRule = true ;
} ) ;
parser . addListener ( "property" , function ( event ) {
if ( ! fontFaceRule ) {
return ;
}
var propertyName = event . property . toString ( ) . toLowerCase ( ) ,
value = event . value . toString ( ) ;
line = event . line ;
col = event . col ;
2015-02-12 05:36:57 -05:00
if ( propertyName === "src" ) {
2014-02-12 05:23:40 -05:00
var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i ;
if ( ! value . match ( regex ) && firstSrc ) {
ruleFailed = true ;
firstSrc = false ;
} else if ( value . match ( regex ) && ! firstSrc ) {
ruleFailed = false ;
}
}
} ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endfontface" , function ( ) {
2014-02-12 05:23:40 -05:00
fontFaceRule = false ;
if ( ruleFailed ) {
reporter . report ( "@font-face declaration doesn't follow the fontspring bulletproof syntax." , line , col , rule ) ;
}
} ) ;
}
2015-02-12 05:36:57 -05:00
} ) ;
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "compatible-vendor-prefixes" ,
name : "Require compatible vendor prefixes" ,
desc : "Include all compatible vendor prefixes to reach a wider range of users." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
compatiblePrefixes ,
properties ,
prop ,
variations ,
prefixed ,
i ,
len ,
inKeyFrame = false ,
arrayPush = Array . prototype . push ,
applyTo = [ ] ;
compatiblePrefixes = {
"animation" : "webkit moz" ,
"animation-delay" : "webkit moz" ,
"animation-direction" : "webkit moz" ,
"animation-duration" : "webkit moz" ,
"animation-fill-mode" : "webkit moz" ,
"animation-iteration-count" : "webkit moz" ,
"animation-name" : "webkit moz" ,
"animation-play-state" : "webkit moz" ,
"animation-timing-function" : "webkit moz" ,
"appearance" : "webkit moz" ,
"border-end" : "webkit moz" ,
"border-end-color" : "webkit moz" ,
"border-end-style" : "webkit moz" ,
"border-end-width" : "webkit moz" ,
"border-image" : "webkit moz o" ,
"border-radius" : "webkit" ,
"border-start" : "webkit moz" ,
"border-start-color" : "webkit moz" ,
"border-start-style" : "webkit moz" ,
"border-start-width" : "webkit moz" ,
"box-align" : "webkit moz ms" ,
"box-direction" : "webkit moz ms" ,
"box-flex" : "webkit moz ms" ,
"box-lines" : "webkit ms" ,
"box-ordinal-group" : "webkit moz ms" ,
"box-orient" : "webkit moz ms" ,
"box-pack" : "webkit moz ms" ,
"box-sizing" : "webkit moz" ,
"box-shadow" : "webkit moz" ,
"column-count" : "webkit moz ms" ,
"column-gap" : "webkit moz ms" ,
"column-rule" : "webkit moz ms" ,
"column-rule-color" : "webkit moz ms" ,
"column-rule-style" : "webkit moz ms" ,
"column-rule-width" : "webkit moz ms" ,
"column-width" : "webkit moz ms" ,
"hyphens" : "epub moz" ,
"line-break" : "webkit ms" ,
"margin-end" : "webkit moz" ,
"margin-start" : "webkit moz" ,
"marquee-speed" : "webkit wap" ,
"marquee-style" : "webkit wap" ,
"padding-end" : "webkit moz" ,
"padding-start" : "webkit moz" ,
"tab-size" : "moz o" ,
"text-size-adjust" : "webkit ms" ,
"transform" : "webkit moz ms o" ,
"transform-origin" : "webkit moz ms o" ,
"transition" : "webkit moz o" ,
"transition-delay" : "webkit moz o" ,
"transition-duration" : "webkit moz o" ,
"transition-property" : "webkit moz o" ,
"transition-timing-function" : "webkit moz o" ,
"user-modify" : "webkit moz" ,
"user-select" : "webkit moz ms" ,
"word-break" : "epub ms" ,
"writing-mode" : "epub ms"
} ;
for ( prop in compatiblePrefixes ) {
if ( compatiblePrefixes . hasOwnProperty ( prop ) ) {
variations = [ ] ;
2015-02-12 05:36:57 -05:00
prefixed = compatiblePrefixes [ prop ] . split ( " " ) ;
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = prefixed . length ; i < len ; i ++ ) {
2015-02-12 05:36:57 -05:00
variations . push ( "-" + prefixed [ i ] + "-" + prop ) ;
2014-02-12 05:23:40 -05:00
}
compatiblePrefixes [ prop ] = variations ;
arrayPush . apply ( applyTo , variations ) ;
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , function ( ) {
properties = [ ] ;
} ) ;
parser . addListener ( "startkeyframes" , function ( event ) {
inKeyFrame = event . prefix || true ;
} ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endkeyframes" , function ( ) {
2014-02-12 05:23:40 -05:00
inKeyFrame = false ;
} ) ;
parser . addListener ( "property" , function ( event ) {
var name = event . property ;
if ( CSSLint . Util . indexOf ( applyTo , name . text ) > - 1 ) {
2015-02-12 05:36:57 -05:00
if ( ! inKeyFrame || typeof inKeyFrame !== "string" ||
2014-02-12 05:23:40 -05:00
name . text . indexOf ( "-" + inKeyFrame + "-" ) !== 0 ) {
properties . push ( name ) ;
}
}
} ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endrule" , function ( ) {
2014-02-12 05:23:40 -05:00
if ( ! properties . length ) {
return ;
}
var propertyGroups = { } ,
i ,
len ,
name ,
prop ,
variations ,
value ,
full ,
actual ,
item ,
propertiesSpecified ;
for ( i = 0 , len = properties . length ; i < len ; i ++ ) {
name = properties [ i ] ;
for ( prop in compatiblePrefixes ) {
if ( compatiblePrefixes . hasOwnProperty ( prop ) ) {
variations = compatiblePrefixes [ prop ] ;
if ( CSSLint . Util . indexOf ( variations , name . text ) > - 1 ) {
if ( ! propertyGroups [ prop ] ) {
propertyGroups [ prop ] = {
full : variations . slice ( 0 ) ,
actual : [ ] ,
actualNodes : [ ]
} ;
}
if ( CSSLint . Util . indexOf ( propertyGroups [ prop ] . actual , name . text ) === - 1 ) {
propertyGroups [ prop ] . actual . push ( name . text ) ;
propertyGroups [ prop ] . actualNodes . push ( name ) ;
}
}
}
}
}
for ( prop in propertyGroups ) {
if ( propertyGroups . hasOwnProperty ( prop ) ) {
value = propertyGroups [ prop ] ;
full = value . full ;
actual = value . actual ;
if ( full . length > actual . length ) {
for ( i = 0 , len = full . length ; i < len ; i ++ ) {
item = full [ i ] ;
if ( CSSLint . Util . indexOf ( actual , item ) === - 1 ) {
2015-02-12 05:36:57 -05:00
propertiesSpecified = ( actual . length === 1 ) ? actual [ 0 ] : ( actual . length === 2 ) ? actual . join ( " and " ) : actual . join ( ", " ) ;
reporter . report ( "The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well." , value . actualNodes [ 0 ] . line , value . actualNodes [ 0 ] . col , rule ) ;
2014-02-12 05:23:40 -05:00
}
}
}
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "display-property-grouping" ,
name : "Require properties appropriate for display" ,
desc : "Certain properties shouldn't be used with certain display property values." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
var propertiesToCheck = {
display : 1 ,
"float" : "none" ,
height : 1 ,
width : 1 ,
margin : 1 ,
"margin-left" : 1 ,
"margin-right" : 1 ,
"margin-bottom" : 1 ,
"margin-top" : 1 ,
padding : 1 ,
"padding-left" : 1 ,
"padding-right" : 1 ,
"padding-bottom" : 1 ,
"padding-top" : 1 ,
"vertical-align" : 1
} ,
properties ;
function reportProperty ( name , display , msg ) {
if ( properties [ name ] ) {
2015-02-12 05:36:57 -05:00
if ( typeof propertiesToCheck [ name ] !== "string" || properties [ name ] . value . toLowerCase ( ) !== propertiesToCheck [ name ] ) {
2014-02-12 05:23:40 -05:00
reporter . report ( msg || name + " can't be used with display: " + display + "." , properties [ name ] . line , properties [ name ] . col , rule ) ;
}
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
function startRule ( ) {
properties = { } ;
}
function endRule ( ) {
var display = properties . display ? properties . display . value : null ;
if ( display ) {
switch ( display ) {
case "inline" :
reportProperty ( "height" , display ) ;
reportProperty ( "width" , display ) ;
reportProperty ( "margin" , display ) ;
reportProperty ( "margin-top" , display ) ;
2015-02-12 05:36:57 -05:00
reportProperty ( "margin-bottom" , display ) ;
2014-02-12 05:23:40 -05:00
reportProperty ( "float" , display , "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug)." ) ;
break ;
case "block" :
reportProperty ( "vertical-align" , display ) ;
break ;
case "inline-block" :
reportProperty ( "float" , display ) ;
break ;
default :
if ( display . indexOf ( "table-" ) === 0 ) {
reportProperty ( "margin" , display ) ;
reportProperty ( "margin-left" , display ) ;
reportProperty ( "margin-right" , display ) ;
reportProperty ( "margin-top" , display ) ;
reportProperty ( "margin-bottom" , display ) ;
reportProperty ( "float" , display ) ;
}
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
}
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startkeyframerule" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "property" , function ( event ) {
var name = event . property . text . toLowerCase ( ) ;
if ( propertiesToCheck [ name ] ) {
2015-02-12 05:36:57 -05:00
properties [ name ] = { value : event . value . text , line : event . property . line , col : event . property . col } ;
2014-02-12 05:23:40 -05:00
}
} ) ;
parser . addListener ( "endrule" , endRule ) ;
parser . addListener ( "endfontface" , endRule ) ;
parser . addListener ( "endkeyframerule" , endRule ) ;
parser . addListener ( "endpagemargin" , endRule ) ;
parser . addListener ( "endpage" , endRule ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "duplicate-background-images" ,
name : "Disallow duplicate background images" ,
desc : "Every background-image should be unique. Use a common class for e.g. sprites." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
stack = { } ;
parser . addListener ( "property" , function ( event ) {
var name = event . property . text ,
value = event . value ,
i , len ;
if ( name . match ( /background/i ) ) {
for ( i = 0 , len = value . parts . length ; i < len ; i ++ ) {
2015-02-12 05:36:57 -05:00
if ( value . parts [ i ] . type === "uri" ) {
if ( typeof stack [ value . parts [ i ] . uri ] === "undefined" ) {
2014-02-12 05:23:40 -05:00
stack [ value . parts [ i ] . uri ] = event ;
}
else {
reporter . report ( "Background image '" + value . parts [ i ] . uri + "' was used multiple times, first declared at line " + stack [ value . parts [ i ] . uri ] . line + ", col " + stack [ value . parts [ i ] . uri ] . col + "." , event . line , event . col , rule ) ;
}
}
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "duplicate-properties" ,
name : "Disallow duplicate properties" ,
desc : "Duplicate properties must appear one after the other." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
properties ,
2015-02-12 05:36:57 -05:00
lastProperty ;
function startRule ( ) {
properties = { } ;
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startkeyframerule" , startRule ) ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "property" , function ( event ) {
var property = event . property ,
name = property . text . toLowerCase ( ) ;
2015-02-12 05:36:57 -05:00
if ( properties [ name ] && ( lastProperty !== name || properties [ name ] === event . value . text ) ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Duplicate property '" + event . property + "' found." , event . line , event . col , rule ) ;
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
properties [ name ] = event . value . text ;
lastProperty = name ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "empty-rules" ,
name : "Disallow empty rules" ,
desc : "Rules without any properties specified should be removed." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
count = 0 ;
parser . addListener ( "startrule" , function ( ) {
count = 0 ;
} ) ;
parser . addListener ( "property" , function ( ) {
count ++ ;
} ) ;
parser . addListener ( "endrule" , function ( event ) {
var selectors = event . selectors ;
if ( count === 0 ) {
reporter . report ( "Rule is empty." , selectors [ 0 ] . line , selectors [ 0 ] . col , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "errors" ,
name : "Parsing Errors" ,
desc : "This rule looks for recoverable syntax errors." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "error" , function ( event ) {
reporter . error ( event . message , event . line , event . col , rule ) ;
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "fallback-colors" ,
name : "Require fallback colors" ,
desc : "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color." ,
browsers : "IE6,IE7,IE8" ,
init : function ( parser , reporter ) {
var rule = this ,
lastProperty ,
propertiesToCheck = {
color : 1 ,
background : 1 ,
"border-color" : 1 ,
"border-top-color" : 1 ,
"border-right-color" : 1 ,
"border-bottom-color" : 1 ,
"border-left-color" : 1 ,
border : 1 ,
"border-top" : 1 ,
"border-right" : 1 ,
"border-bottom" : 1 ,
"border-left" : 1 ,
"background-color" : 1
} ,
properties ;
2015-02-12 05:36:57 -05:00
function startRule ( ) {
properties = { } ;
lastProperty = null ;
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startkeyframerule" , startRule ) ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "property" , function ( event ) {
var property = event . property ,
name = property . text . toLowerCase ( ) ,
parts = event . value . parts ,
2015-02-12 05:36:57 -05:00
i = 0 ,
2014-02-12 05:23:40 -05:00
colorType = "" ,
2015-02-12 05:36:57 -05:00
len = parts . length ;
2014-02-12 05:23:40 -05:00
if ( propertiesToCheck [ name ] ) {
while ( i < len ) {
2015-02-12 05:36:57 -05:00
if ( parts [ i ] . type === "color" ) {
2014-02-12 05:23:40 -05:00
if ( "alpha" in parts [ i ] || "hue" in parts [ i ] ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( /([^\)]+)\(/ . test ( parts [ i ] ) ) {
colorType = RegExp . $1 . toUpperCase ( ) ;
}
2015-02-12 05:36:57 -05:00
if ( ! lastProperty || ( lastProperty . property . text . toLowerCase ( ) !== name || lastProperty . colorType !== "compat" ) ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + "." , event . line , event . col , rule ) ;
}
} else {
event . colorType = "compat" ;
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
i ++ ;
}
}
lastProperty = event ;
2015-02-12 05:36:57 -05:00
} ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "floats" ,
name : "Disallow too many floats" ,
desc : "This rule tests if the float property is used too many times" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
var count = 0 ;
parser . addListener ( "property" , function ( event ) {
2015-02-12 05:36:57 -05:00
if ( event . property . text . toLowerCase ( ) === "float" &&
event . value . text . toLowerCase ( ) !== "none" ) {
2014-02-12 05:23:40 -05:00
count ++ ;
}
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
reporter . stat ( "floats" , count ) ;
if ( count >= 10 ) {
reporter . rollupWarn ( "Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead." , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "font-faces" ,
name : "Don't use too many web fonts" ,
desc : "Too many different web fonts in the same stylesheet." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
count = 0 ;
parser . addListener ( "startfontface" , function ( ) {
count ++ ;
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
if ( count > 5 ) {
reporter . rollupWarn ( "Too many @font-face declarations (" + count + ")." , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "font-sizes" ,
name : "Disallow too many font sizes" ,
desc : "Checks the number of font-size declarations." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
count = 0 ;
parser . addListener ( "property" , function ( event ) {
2015-02-12 05:36:57 -05:00
if ( event . property . toString ( ) === "font-size" ) {
2014-02-12 05:23:40 -05:00
count ++ ;
}
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
reporter . stat ( "font-sizes" , count ) ;
if ( count >= 10 ) {
reporter . rollupWarn ( "Too many font-size declarations (" + count + "), abstraction needed." , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "gradients" ,
name : "Require all gradient definitions" ,
desc : "When using a vendor-prefixed gradient, make sure to use them all." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
gradients ;
parser . addListener ( "startrule" , function ( ) {
gradients = {
moz : 0 ,
webkit : 0 ,
oldWebkit : 0 ,
o : 0
} ;
} ) ;
parser . addListener ( "property" , function ( event ) {
if ( /\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i . test ( event . value ) ) {
gradients [ RegExp . $1 ] = 1 ;
} else if ( /\-webkit\-gradient/i . test ( event . value ) ) {
gradients . oldWebkit = 1 ;
}
} ) ;
parser . addListener ( "endrule" , function ( event ) {
var missing = [ ] ;
if ( ! gradients . moz ) {
missing . push ( "Firefox 3.6+" ) ;
}
if ( ! gradients . webkit ) {
missing . push ( "Webkit (Safari 5+, Chrome)" ) ;
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( ! gradients . oldWebkit ) {
missing . push ( "Old Webkit (Safari 4+, Chrome)" ) ;
}
if ( ! gradients . o ) {
missing . push ( "Opera 11.1+" ) ;
}
2015-02-12 05:36:57 -05:00
if ( missing . length && missing . length < 4 ) {
reporter . report ( "Missing vendor-prefixed CSS gradients for " + missing . join ( ", " ) + "." , event . selectors [ 0 ] . line , event . selectors [ 0 ] . col , rule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "ids" ,
name : "Disallow IDs in selectors" ,
desc : "Selectors should not contain IDs." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
modifier ,
idCount ,
i , j , k ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
idCount = 0 ;
for ( j = 0 ; j < selector . parts . length ; j ++ ) {
part = selector . parts [ j ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
for ( k = 0 ; k < part . modifiers . length ; k ++ ) {
modifier = part . modifiers [ k ] ;
2015-02-12 05:36:57 -05:00
if ( modifier . type === "id" ) {
2014-02-12 05:23:40 -05:00
idCount ++ ;
}
}
}
}
2015-02-12 05:36:57 -05:00
if ( idCount === 1 ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Don't use IDs in selectors." , selector . line , selector . col , rule ) ;
} else if ( idCount > 1 ) {
reporter . report ( idCount + " IDs in the selector, really?" , selector . line , selector . col , rule ) ;
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "import" ,
name : "Disallow @import" ,
desc : "Don't use @import, use <link> instead." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "import" , function ( event ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "@import prevents parallel downloads, use <link> instead." , event . line , event . col , rule ) ;
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "important" ,
name : "Disallow !important" ,
desc : "Be careful when using !important declaration" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
count = 0 ;
parser . addListener ( "property" , function ( event ) {
if ( event . important === true ) {
count ++ ;
reporter . report ( "Use of !important" , event . line , event . col , rule ) ;
}
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
reporter . stat ( "important" , count ) ;
if ( count >= 10 ) {
reporter . rollupWarn ( "Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues." , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "known-properties" ,
name : "Require use of known properties" ,
desc : "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "property" , function ( event ) {
if ( event . invalid ) {
reporter . report ( event . invalid . message , event . line , event . col , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
CSSLint . addRule ( {
id : "order-alphabetical" ,
name : "Alphabetical order" ,
desc : "Assure properties are in alphabetical order" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
properties ;
var startRule = function ( ) {
properties = [ ] ;
} ;
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
parser . addListener ( "startkeyframerule" , startRule ) ;
parser . addListener ( "property" , function ( event ) {
var name = event . property . text ,
lowerCasePrefixLessName = name . toLowerCase ( ) . replace ( /^-.*?-/ , "" ) ;
properties . push ( lowerCasePrefixLessName ) ;
} ) ;
parser . addListener ( "endrule" , function ( event ) {
var currentProperties = properties . join ( "," ) ,
expectedProperties = properties . sort ( ) . join ( "," ) ;
if ( currentProperties !== expectedProperties ) {
reporter . report ( "Rule doesn't have all its properties in alphabetical ordered." , event . line , event . col , rule ) ;
}
} ) ;
}
} ) ;
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "outline-none" ,
name : "Disallow outline: none" ,
desc : "Use of outline: none or outline: 0 should be limited to :focus rules." ,
browsers : "All" ,
tags : [ "Accessibility" ] ,
init : function ( parser , reporter ) {
var rule = this ,
lastRule ;
function startRule ( event ) {
if ( event . selectors ) {
lastRule = {
line : event . line ,
col : event . col ,
selectors : event . selectors ,
propCount : 0 ,
outline : false
} ;
} else {
lastRule = null ;
}
}
2015-02-12 05:36:57 -05:00
function endRule ( ) {
2014-02-12 05:23:40 -05:00
if ( lastRule ) {
if ( lastRule . outline ) {
2015-02-12 05:36:57 -05:00
if ( lastRule . selectors . toString ( ) . toLowerCase ( ) . indexOf ( ":focus" ) === - 1 ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Outlines should only be modified using :focus." , lastRule . line , lastRule . col , rule ) ;
2015-02-12 05:36:57 -05:00
} else if ( lastRule . propCount === 1 ) {
reporter . report ( "Outlines shouldn't be hidden unless other visual changes are made." , lastRule . line , lastRule . col , rule ) ;
2014-02-12 05:23:40 -05:00
}
}
}
}
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startkeyframerule" , startRule ) ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "property" , function ( event ) {
var name = event . property . text . toLowerCase ( ) ,
2015-02-12 05:36:57 -05:00
value = event . value ;
2014-02-12 05:23:40 -05:00
if ( lastRule ) {
lastRule . propCount ++ ;
2015-02-12 05:36:57 -05:00
if ( name === "outline" && ( value . toString ( ) === "none" || value . toString ( ) === "0" ) ) {
2014-02-12 05:23:40 -05:00
lastRule . outline = true ;
2015-02-12 05:36:57 -05:00
}
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "endrule" , endRule ) ;
parser . addListener ( "endfontface" , endRule ) ;
parser . addListener ( "endpage" , endRule ) ;
parser . addListener ( "endpagemargin" , endRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endkeyframerule" , endRule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "overqualified-elements" ,
name : "Disallow overqualified elements" ,
desc : "Don't use classes or IDs with elements (a.foo or a#foo)." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
classes = { } ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
modifier ,
i , j , k ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
for ( j = 0 ; j < selector . parts . length ; j ++ ) {
part = selector . parts [ j ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
for ( k = 0 ; k < part . modifiers . length ; k ++ ) {
modifier = part . modifiers [ k ] ;
2015-02-12 05:36:57 -05:00
if ( part . elementName && modifier . type === "id" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Element (" + part + ") is overqualified, just use " + modifier + " without element name." , part . line , part . col , rule ) ;
2015-02-12 05:36:57 -05:00
} else if ( modifier . type === "class" ) {
2014-02-12 05:23:40 -05:00
if ( ! classes [ modifier ] ) {
classes [ modifier ] = [ ] ;
}
classes [ modifier ] . push ( { modifier : modifier , part : part } ) ;
}
}
}
}
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
parser . addListener ( "endstylesheet" , function ( ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
var prop ;
for ( prop in classes ) {
if ( classes . hasOwnProperty ( prop ) ) {
2015-02-12 05:36:57 -05:00
if ( classes [ prop ] . length === 1 && classes [ prop ] [ 0 ] . part . elementName ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Element (" + classes [ prop ] [ 0 ] . part + ") is overqualified, just use " + classes [ prop ] [ 0 ] . modifier + " without element name." , classes [ prop ] [ 0 ] . part . line , classes [ prop ] [ 0 ] . part . col , rule ) ;
}
}
2015-02-12 05:36:57 -05:00
}
2014-02-12 05:23:40 -05:00
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "qualified-headings" ,
name : "Disallow qualified headings" ,
desc : "Headings should not be qualified (namespaced)." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
i , j ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
for ( j = 0 ; j < selector . parts . length ; j ++ ) {
part = selector . parts [ j ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
if ( part . elementName && /h[1-6]/ . test ( part . elementName . toString ( ) ) && j > 0 ) {
reporter . report ( "Heading (" + part . elementName + ") should not be qualified." , part . line , part . col , rule ) ;
}
}
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "regex-selectors" ,
name : "Disallow selectors that look like regexs" ,
desc : "Selectors that look like regular expressions are slow and should be avoided." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
modifier ,
i , j , k ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
for ( j = 0 ; j < selector . parts . length ; j ++ ) {
part = selector . parts [ j ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
for ( k = 0 ; k < part . modifiers . length ; k ++ ) {
modifier = part . modifiers [ k ] ;
2015-02-12 05:36:57 -05:00
if ( modifier . type === "attribute" ) {
2014-02-12 05:23:40 -05:00
if ( /([\~\|\^\$\*]=)/ . test ( modifier ) ) {
reporter . report ( "Attribute selectors with " + RegExp . $1 + " are slow!" , modifier . line , modifier . col , rule ) ;
}
}
}
}
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "rules-count" ,
name : "Rules Count" ,
desc : "Track how many rules there are." ,
browsers : "All" ,
init : function ( parser , reporter ) {
2015-02-12 05:36:57 -05:00
var count = 0 ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , function ( ) {
count ++ ;
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
reporter . stat ( "rule-count" , count ) ;
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "selector-max-approaching" ,
name : "Warn when approaching the 4095 selector limit for IE" ,
desc : "Will warn when selector count is >= 3800 selectors." ,
browsers : "IE" ,
init : function ( parser , reporter ) {
var rule = this , count = 0 ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startrule" , function ( event ) {
2014-02-12 05:23:40 -05:00
count += event . selectors . length ;
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
if ( count >= 3800 ) {
2015-02-12 05:36:57 -05:00
reporter . report ( "You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring." , 0 , 0 , rule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "selector-max" ,
name : "Error when past the 4095 selector limit for IE" ,
desc : "Will error when selector count is > 4095." ,
browsers : "IE" ,
init : function ( parser , reporter ) {
var rule = this , count = 0 ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startrule" , function ( event ) {
2014-02-12 05:23:40 -05:00
count += event . selectors . length ;
} ) ;
parser . addListener ( "endstylesheet" , function ( ) {
if ( count > 4095 ) {
2015-02-12 05:36:57 -05:00
reporter . report ( "You have " + count + " selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring." , 0 , 0 , rule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
CSSLint . addRule ( {
id : "selector-newline" ,
name : "Disallow new-line characters in selectors" ,
desc : "New-line characters in selectors are usually a forgotten comma and not a descendant combinator." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
function startRule ( event ) {
var i , len , selector , p , n , pLen , part , part2 , type , currentLine , nextLine ,
selectors = event . selectors ;
for ( i = 0 , len = selectors . length ; i < len ; i ++ ) {
selector = selectors [ i ] ;
for ( p = 0 , pLen = selector . parts . length ; p < pLen ; p ++ ) {
for ( n = p + 1 ; n < pLen ; n ++ ) {
part = selector . parts [ p ] ;
part2 = selector . parts [ n ] ;
type = part . type ;
currentLine = part . line ;
nextLine = part2 . line ;
if ( type === "descendant" && nextLine > currentLine ) {
reporter . report ( "newline character found in selector (forgot a comma?)" , currentLine , selectors [ i ] . parts [ 0 ] . col , rule ) ;
}
}
}
}
}
parser . addListener ( "startrule" , startRule ) ;
}
} ) ;
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "shorthand" ,
name : "Require shorthand properties" ,
desc : "Use shorthand properties where possible." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
prop , i , len ,
propertiesToCheck = { } ,
properties ,
mapping = {
"margin" : [
"margin-top" ,
"margin-bottom" ,
"margin-left" ,
"margin-right"
] ,
"padding" : [
"padding-top" ,
"padding-bottom" ,
"padding-left" ,
"padding-right"
2015-02-12 05:36:57 -05:00
]
2014-02-12 05:23:40 -05:00
} ;
for ( prop in mapping ) {
if ( mapping . hasOwnProperty ( prop ) ) {
for ( i = 0 , len = mapping [ prop ] . length ; i < len ; i ++ ) {
propertiesToCheck [ mapping [ prop ] [ i ] ] = prop ;
}
}
}
2015-02-12 05:36:57 -05:00
function startRule ( ) {
2014-02-12 05:23:40 -05:00
properties = { } ;
}
function endRule ( event ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
var prop , i , len , total ;
for ( prop in mapping ) {
if ( mapping . hasOwnProperty ( prop ) ) {
total = 0 ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
for ( i = 0 , len = mapping [ prop ] . length ; i < len ; i ++ ) {
total += properties [ mapping [ prop ] [ i ] ] ? 1 : 0 ;
}
2015-02-12 05:36:57 -05:00
if ( total === mapping [ prop ] . length ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "The properties " + mapping [ prop ] . join ( ", " ) + " can be replaced by " + prop + "." , event . line , event . col , rule ) ;
}
}
}
2015-02-12 05:36:57 -05:00
}
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "property" , function ( event ) {
2015-02-12 05:36:57 -05:00
var name = event . property . toString ( ) . toLowerCase ( ) ;
2014-02-12 05:23:40 -05:00
if ( propertiesToCheck [ name ] ) {
properties [ name ] = 1 ;
}
} ) ;
parser . addListener ( "endrule" , endRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endfontface" , endRule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "star-property-hack" ,
name : "Disallow properties with a star prefix" ,
desc : "Checks for the star property hack (targets IE6/7)" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "property" , function ( event ) {
var property = event . property ;
2015-02-12 05:36:57 -05:00
if ( property . hack === "*" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Property with star prefix found." , event . property . line , event . property . col , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "text-indent" ,
name : "Disallow negative text-indent" ,
desc : "Checks for text indent less than -99px" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
textIndent ,
direction ;
2015-02-12 05:36:57 -05:00
function startRule ( ) {
2014-02-12 05:23:40 -05:00
textIndent = false ;
direction = "inherit" ;
}
2015-02-12 05:36:57 -05:00
function endRule ( ) {
if ( textIndent && direction !== "ltr" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr." , textIndent . line , textIndent . col , rule ) ;
}
}
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "property" , function ( event ) {
var name = event . property . toString ( ) . toLowerCase ( ) ,
value = event . value ;
2015-02-12 05:36:57 -05:00
if ( name === "text-indent" && value . parts [ 0 ] . value < - 99 ) {
2014-02-12 05:23:40 -05:00
textIndent = event . property ;
2015-02-12 05:36:57 -05:00
} else if ( name === "direction" && value . toString ( ) === "ltr" ) {
2014-02-12 05:23:40 -05:00
direction = "ltr" ;
}
} ) ;
parser . addListener ( "endrule" , endRule ) ;
parser . addListener ( "endfontface" , endRule ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "underscore-property-hack" ,
name : "Disallow properties with an underscore prefix" ,
desc : "Checks for the underscore property hack (targets IE6)" ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "property" , function ( event ) {
var property = event . property ;
2015-02-12 05:36:57 -05:00
if ( property . hack === "_" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Property with underscore prefix found." , event . property . line , event . property . col , rule ) ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "unique-headings" ,
name : "Headings should only be defined once" ,
desc : "Headings should be defined only once." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
2015-02-12 05:36:57 -05:00
var headings = {
2014-02-12 05:23:40 -05:00
h1 : 0 ,
h2 : 0 ,
h3 : 0 ,
h4 : 0 ,
h5 : 0 ,
h6 : 0
} ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
pseudo ,
i , j ;
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
part = selector . parts [ selector . parts . length - 1 ] ;
if ( part . elementName && /(h[1-6])/i . test ( part . elementName . toString ( ) ) ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
for ( j = 0 ; j < part . modifiers . length ; j ++ ) {
2015-02-12 05:36:57 -05:00
if ( part . modifiers [ j ] . type === "pseudo" ) {
2014-02-12 05:23:40 -05:00
pseudo = true ;
break ;
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( ! pseudo ) {
headings [ RegExp . $1 ] ++ ;
if ( headings [ RegExp . $1 ] > 1 ) {
reporter . report ( "Heading (" + part . elementName + ") has already been defined." , part . line , part . col , rule ) ;
}
}
}
}
} ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endstylesheet" , function ( ) {
2014-02-12 05:23:40 -05:00
var prop ,
messages = [ ] ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
for ( prop in headings ) {
if ( headings . hasOwnProperty ( prop ) ) {
if ( headings [ prop ] > 1 ) {
messages . push ( headings [ prop ] + " " + prop + "s" ) ;
}
}
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
if ( messages . length ) {
reporter . rollupWarn ( "You have " + messages . join ( ", " ) + " defined in this stylesheet." , rule ) ;
}
2015-02-12 05:36:57 -05:00
} ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "universal-selector" ,
name : "Disallow universal selector" ,
desc : "The universal selector (*) is known to be slow." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
var selectors = event . selectors ,
selector ,
part ,
2015-02-12 05:36:57 -05:00
i ;
2014-02-12 05:23:40 -05:00
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
part = selector . parts [ selector . parts . length - 1 ] ;
2015-02-12 05:36:57 -05:00
if ( part . elementName === "*" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( rule . desc , part . line , part . col , rule ) ;
}
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "unqualified-attributes" ,
name : "Disallow unqualified attribute selectors" ,
desc : "Unqualified attribute selectors are known to be slow." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "startrule" , function ( event ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
var selectors = event . selectors ,
selector ,
part ,
modifier ,
2015-02-12 05:36:57 -05:00
i , k ;
2014-02-12 05:23:40 -05:00
for ( i = 0 ; i < selectors . length ; i ++ ) {
selector = selectors [ i ] ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
part = selector . parts [ selector . parts . length - 1 ] ;
2015-02-12 05:36:57 -05:00
if ( part . type === parser . SELECTOR _PART _TYPE ) {
2014-02-12 05:23:40 -05:00
for ( k = 0 ; k < part . modifiers . length ; k ++ ) {
modifier = part . modifiers [ k ] ;
2015-02-12 05:36:57 -05:00
if ( modifier . type === "attribute" && ( ! part . elementName || part . elementName === "*" ) ) {
reporter . report ( rule . desc , part . line , part . col , rule ) ;
2014-02-12 05:23:40 -05:00
}
}
}
2015-02-12 05:36:57 -05:00
}
2014-02-12 05:23:40 -05:00
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "vendor-prefix" ,
name : "Require standard property with vendor prefix" ,
desc : "When using a vendor-prefixed property, make sure to include the standard one." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ,
properties ,
num ,
propertiesToCheck = {
"-webkit-border-radius" : "border-radius" ,
"-webkit-border-top-left-radius" : "border-top-left-radius" ,
"-webkit-border-top-right-radius" : "border-top-right-radius" ,
"-webkit-border-bottom-left-radius" : "border-bottom-left-radius" ,
"-webkit-border-bottom-right-radius" : "border-bottom-right-radius" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-o-border-radius" : "border-radius" ,
"-o-border-top-left-radius" : "border-top-left-radius" ,
"-o-border-top-right-radius" : "border-top-right-radius" ,
"-o-border-bottom-left-radius" : "border-bottom-left-radius" ,
"-o-border-bottom-right-radius" : "border-bottom-right-radius" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-border-radius" : "border-radius" ,
"-moz-border-radius-topleft" : "border-top-left-radius" ,
"-moz-border-radius-topright" : "border-top-right-radius" ,
"-moz-border-radius-bottomleft" : "border-bottom-left-radius" ,
2015-02-12 05:36:57 -05:00
"-moz-border-radius-bottomright" : "border-bottom-right-radius" ,
2014-02-12 05:23:40 -05:00
"-moz-column-count" : "column-count" ,
"-webkit-column-count" : "column-count" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-gap" : "column-gap" ,
"-webkit-column-gap" : "column-gap" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-rule" : "column-rule" ,
"-webkit-column-rule" : "column-rule" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-rule-style" : "column-rule-style" ,
"-webkit-column-rule-style" : "column-rule-style" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-rule-color" : "column-rule-color" ,
"-webkit-column-rule-color" : "column-rule-color" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-rule-width" : "column-rule-width" ,
"-webkit-column-rule-width" : "column-rule-width" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-column-width" : "column-width" ,
"-webkit-column-width" : "column-width" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-webkit-column-span" : "column-span" ,
"-webkit-columns" : "columns" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-box-shadow" : "box-shadow" ,
"-webkit-box-shadow" : "box-shadow" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-transform" : "transform" ,
"-webkit-transform" : "transform" ,
"-o-transform" : "transform" ,
"-ms-transform" : "transform" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-transform-origin" : "transform-origin" ,
"-webkit-transform-origin" : "transform-origin" ,
"-o-transform-origin" : "transform-origin" ,
"-ms-transform-origin" : "transform-origin" ,
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
"-moz-box-sizing" : "box-sizing" ,
2015-02-12 05:36:57 -05:00
"-webkit-box-sizing" : "box-sizing"
2014-02-12 05:23:40 -05:00
} ;
function startRule ( ) {
properties = { } ;
2015-02-12 05:36:57 -05:00
num = 1 ;
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
function endRule ( ) {
2014-02-12 05:23:40 -05:00
var prop ,
2015-02-12 05:36:57 -05:00
i ,
len ,
2014-02-12 05:23:40 -05:00
needed ,
actual ,
needsStandard = [ ] ;
for ( prop in properties ) {
if ( propertiesToCheck [ prop ] ) {
needsStandard . push ( { actual : prop , needed : propertiesToCheck [ prop ] } ) ;
}
}
for ( i = 0 , len = needsStandard . length ; i < len ; i ++ ) {
needed = needsStandard [ i ] . needed ;
actual = needsStandard [ i ] . actual ;
2015-02-12 05:36:57 -05:00
if ( ! properties [ needed ] ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Missing standard property '" + needed + "' to go along with '" + actual + "'." , properties [ actual ] [ 0 ] . name . line , properties [ actual ] [ 0 ] . name . col , rule ) ;
} else {
if ( properties [ needed ] [ 0 ] . pos < properties [ actual ] [ 0 ] . pos ) {
reporter . report ( "Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'." , properties [ actual ] [ 0 ] . name . line , properties [ actual ] [ 0 ] . name . col , rule ) ;
}
}
}
2015-02-12 05:36:57 -05:00
}
2014-02-12 05:23:40 -05:00
parser . addListener ( "startrule" , startRule ) ;
parser . addListener ( "startfontface" , startRule ) ;
parser . addListener ( "startpage" , startRule ) ;
parser . addListener ( "startpagemargin" , startRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "startkeyframerule" , startRule ) ;
2014-02-12 05:23:40 -05:00
parser . addListener ( "property" , function ( event ) {
var name = event . property . text . toLowerCase ( ) ;
if ( ! properties [ name ] ) {
properties [ name ] = [ ] ;
}
properties [ name ] . push ( { name : event . property , value : event . value , pos : num ++ } ) ;
} ) ;
parser . addListener ( "endrule" , endRule ) ;
parser . addListener ( "endfontface" , endRule ) ;
parser . addListener ( "endpage" , endRule ) ;
parser . addListener ( "endpagemargin" , endRule ) ;
2015-02-12 05:36:57 -05:00
parser . addListener ( "endkeyframerule" , endRule ) ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addRule ( {
id : "zero-units" ,
name : "Disallow units for 0 values" ,
desc : "You don't need to specify units when a value is 0." ,
browsers : "All" ,
init : function ( parser , reporter ) {
var rule = this ;
parser . addListener ( "property" , function ( event ) {
var parts = event . value . parts ,
2015-02-12 05:36:57 -05:00
i = 0 ,
2014-02-12 05:23:40 -05:00
len = parts . length ;
while ( i < len ) {
2015-02-12 05:36:57 -05:00
if ( ( parts [ i ] . units || parts [ i ] . type === "percentage" ) && parts [ i ] . value === 0 && parts [ i ] . type !== "time" ) {
2014-02-12 05:23:40 -05:00
reporter . report ( "Values of 0 shouldn't have units specified." , parts [ i ] . line , parts [ i ] . col , rule ) ;
}
i ++ ;
}
} ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
( function ( ) {
var xmlEscape = function ( str ) {
if ( ! str || str . constructor !== String ) {
return "" ;
}
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
return str . replace ( /[\"&><]/g , function ( match ) {
switch ( match ) {
case "\"" :
return """ ;
case "&" :
return "&" ;
case "<" :
return "<" ;
case ">" :
2015-02-12 05:36:57 -05:00
return ">" ;
2014-02-12 05:23:40 -05:00
}
} ) ;
} ;
CSSLint . addFormatter ( {
id : "checkstyle-xml" ,
name : "Checkstyle XML format" ,
startFormat : function ( ) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>" ;
} ,
endFormat : function ( ) {
return "</checkstyle>" ;
} ,
readError : function ( filename , message ) {
return "<file name=\"" + xmlEscape ( filename ) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape ( message ) + "\"></error></file>" ;
} ,
2015-02-12 05:36:57 -05:00
formatResults : function ( results , filename /*, options*/ ) {
2014-02-12 05:23:40 -05:00
var messages = results . messages ,
output = [ ] ;
var generateSource = function ( rule ) {
2015-02-12 05:36:57 -05:00
if ( ! rule || ! ( "name" in rule ) ) {
2014-02-12 05:23:40 -05:00
return "" ;
}
2015-02-12 05:36:57 -05:00
return "net.csslint." + rule . name . replace ( /\s/g , "" ) ;
2014-02-12 05:23:40 -05:00
} ;
if ( messages . length > 0 ) {
output . push ( "<file name=\"" + filename + "\">" ) ;
2015-02-12 05:36:57 -05:00
CSSLint . Util . forEach ( messages , function ( message ) {
2014-02-12 05:23:40 -05:00
if ( ! message . rollup ) {
2015-02-12 05:36:57 -05:00
output . push ( "<error line=\"" + message . line + "\" column=\"" + message . col + "\" severity=\"" + message . type + "\"" +
2014-02-12 05:23:40 -05:00
" message=\"" + xmlEscape ( message . message ) + "\" source=\"" + generateSource ( message . rule ) + "\"/>" ) ;
}
} ) ;
output . push ( "</file>" ) ;
}
return output . join ( "" ) ;
}
} ) ;
} ( ) ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addFormatter ( {
id : "compact" ,
name : "Compact, 'porcelain' format" ,
startFormat : function ( ) {
return "" ;
} ,
endFormat : function ( ) {
return "" ;
} ,
formatResults : function ( results , filename , options ) {
var messages = results . messages ,
output = "" ;
options = options || { } ;
var capitalize = function ( str ) {
return str . charAt ( 0 ) . toUpperCase ( ) + str . slice ( 1 ) ;
} ;
if ( messages . length === 0 ) {
2015-02-12 05:36:57 -05:00
return options . quiet ? "" : filename + ": Lint Free!" ;
2014-02-12 05:23:40 -05:00
}
2015-02-12 05:36:57 -05:00
CSSLint . Util . forEach ( messages , function ( message ) {
2014-02-12 05:23:40 -05:00
if ( message . rollup ) {
output += filename + ": " + capitalize ( message . type ) + " - " + message . message + "\n" ;
} else {
2015-02-12 05:36:57 -05:00
output += filename + ": " + "line " + message . line +
2014-07-09 12:59:04 -04:00
", col " + message . col + ", " + capitalize ( message . type ) + " - " + message . message + " (" + message . rule . id + ")\n" ;
2014-02-12 05:23:40 -05:00
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
return output ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addFormatter ( {
id : "csslint-xml" ,
name : "CSSLint XML format" ,
startFormat : function ( ) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><csslint>" ;
} ,
endFormat : function ( ) {
return "</csslint>" ;
} ,
2015-02-12 05:36:57 -05:00
formatResults : function ( results , filename /*, options*/ ) {
2014-02-12 05:23:40 -05:00
var messages = results . messages ,
output = [ ] ;
var escapeSpecialCharacters = function ( str ) {
if ( ! str || str . constructor !== String ) {
return "" ;
}
return str . replace ( /\"/g , "'" ) . replace ( /&/g , "&" ) . replace ( /</g , "<" ) . replace ( />/g , ">" ) ;
} ;
if ( messages . length > 0 ) {
output . push ( "<file name=\"" + filename + "\">" ) ;
2015-02-12 05:36:57 -05:00
CSSLint . Util . forEach ( messages , function ( message ) {
2014-02-12 05:23:40 -05:00
if ( message . rollup ) {
output . push ( "<issue severity=\"" + message . type + "\" reason=\"" + escapeSpecialCharacters ( message . message ) + "\" evidence=\"" + escapeSpecialCharacters ( message . evidence ) + "\"/>" ) ;
} else {
output . push ( "<issue line=\"" + message . line + "\" char=\"" + message . col + "\" severity=\"" + message . type + "\"" +
" reason=\"" + escapeSpecialCharacters ( message . message ) + "\" evidence=\"" + escapeSpecialCharacters ( message . evidence ) + "\"/>" ) ;
}
} ) ;
output . push ( "</file>" ) ;
}
return output . join ( "" ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addFormatter ( {
id : "junit-xml" ,
name : "JUNIT XML format" ,
startFormat : function ( ) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><testsuites>" ;
} ,
endFormat : function ( ) {
return "</testsuites>" ;
} ,
2015-02-12 05:36:57 -05:00
formatResults : function ( results , filename /*, options*/ ) {
2014-02-12 05:23:40 -05:00
var messages = results . messages ,
output = [ ] ,
tests = {
2015-02-12 05:36:57 -05:00
"error" : 0 ,
"failure" : 0
2014-02-12 05:23:40 -05:00
} ;
var generateSource = function ( rule ) {
2015-02-12 05:36:57 -05:00
if ( ! rule || ! ( "name" in rule ) ) {
2014-02-12 05:23:40 -05:00
return "" ;
}
2015-02-12 05:36:57 -05:00
return "net.csslint." + rule . name . replace ( /\s/g , "" ) ;
2014-02-12 05:23:40 -05:00
} ;
var escapeSpecialCharacters = function ( str ) {
if ( ! str || str . constructor !== String ) {
return "" ;
}
return str . replace ( /\"/g , "'" ) . replace ( /</g , "<" ) . replace ( />/g , ">" ) ;
} ;
if ( messages . length > 0 ) {
2015-02-12 05:36:57 -05:00
messages . forEach ( function ( message ) {
var type = message . type === "warning" ? "error" : message . type ;
2014-02-12 05:23:40 -05:00
if ( ! message . rollup ) {
output . push ( "<testcase time=\"0\" name=\"" + generateSource ( message . rule ) + "\">" ) ;
2015-02-12 05:36:57 -05:00
output . push ( "<" + type + " message=\"" + escapeSpecialCharacters ( message . message ) + "\"><![CDATA[" + message . line + ":" + message . col + ":" + escapeSpecialCharacters ( message . evidence ) + "]]></" + type + ">" ) ;
2014-02-12 05:23:40 -05:00
output . push ( "</testcase>" ) ;
tests [ type ] += 1 ;
}
} ) ;
output . unshift ( "<testsuite time=\"0\" tests=\"" + messages . length + "\" skipped=\"0\" errors=\"" + tests . error + "\" failures=\"" + tests . failure + "\" package=\"net.csslint\" name=\"" + filename + "\">" ) ;
output . push ( "</testsuite>" ) ;
}
return output . join ( "" ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addFormatter ( {
id : "lint-xml" ,
name : "Lint XML format" ,
startFormat : function ( ) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><lint>" ;
} ,
endFormat : function ( ) {
return "</lint>" ;
} ,
2015-02-12 05:36:57 -05:00
formatResults : function ( results , filename /*, options*/ ) {
2014-02-12 05:23:40 -05:00
var messages = results . messages ,
output = [ ] ;
var escapeSpecialCharacters = function ( str ) {
if ( ! str || str . constructor !== String ) {
return "" ;
}
return str . replace ( /\"/g , "'" ) . replace ( /&/g , "&" ) . replace ( /</g , "<" ) . replace ( />/g , ">" ) ;
} ;
if ( messages . length > 0 ) {
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
output . push ( "<file name=\"" + filename + "\">" ) ;
2015-02-12 05:36:57 -05:00
CSSLint . Util . forEach ( messages , function ( message ) {
2014-02-12 05:23:40 -05:00
if ( message . rollup ) {
output . push ( "<issue severity=\"" + message . type + "\" reason=\"" + escapeSpecialCharacters ( message . message ) + "\" evidence=\"" + escapeSpecialCharacters ( message . evidence ) + "\"/>" ) ;
} else {
output . push ( "<issue line=\"" + message . line + "\" char=\"" + message . col + "\" severity=\"" + message . type + "\"" +
" reason=\"" + escapeSpecialCharacters ( message . message ) + "\" evidence=\"" + escapeSpecialCharacters ( message . evidence ) + "\"/>" ) ;
}
} ) ;
output . push ( "</file>" ) ;
}
return output . join ( "" ) ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
CSSLint . addFormatter ( {
id : "text" ,
name : "Plain Text" ,
startFormat : function ( ) {
return "" ;
} ,
endFormat : function ( ) {
return "" ;
} ,
formatResults : function ( results , filename , options ) {
var messages = results . messages ,
output = "" ;
options = options || { } ;
if ( messages . length === 0 ) {
return options . quiet ? "" : "\n\ncsslint: No errors in " + filename + "." ;
}
2015-02-12 05:36:57 -05:00
output = "\n\ncsslint: There " ;
if ( messages . length === 1 ) {
output += "is 1 problem" ;
} else {
output += "are " + messages . length + " problems" ;
}
output += " in " + filename + "." ;
2014-02-12 05:23:40 -05:00
var pos = filename . lastIndexOf ( "/" ) ,
shortFilename = filename ;
if ( pos === - 1 ) {
2015-02-12 05:36:57 -05:00
pos = filename . lastIndexOf ( "\\" ) ;
2014-02-12 05:23:40 -05:00
}
if ( pos > - 1 ) {
shortFilename = filename . substring ( pos + 1 ) ;
}
CSSLint . Util . forEach ( messages , function ( message , i ) {
output = output + "\n\n" + shortFilename ;
if ( message . rollup ) {
output += "\n" + ( i + 1 ) + ": " + message . type ;
output += "\n" + message . message ;
} else {
output += "\n" + ( i + 1 ) + ": " + message . type + " at line " + message . line + ", col " + message . col ;
output += "\n" + message . message ;
output += "\n" + message . evidence ;
}
} ) ;
2015-02-12 05:36:57 -05:00
2014-02-12 05:23:40 -05:00
return output ;
}
} ) ;
2015-02-12 05:36:57 -05:00
module . exports . CSSLint = CSSLint ;
2014-02-12 05:23:40 -05:00
2014-07-09 12:59:04 -04:00
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/mode/css_worker" , [ "require" , "exports" , "module" , "ace/lib/oop" , "ace/lib/lang" , "ace/worker/mirror" , "ace/mode/css/csslint" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
"use strict" ;
var oop = require ( "../lib/oop" ) ;
var lang = require ( "../lib/lang" ) ;
var Mirror = require ( "../worker/mirror" ) . Mirror ;
var CSSLint = require ( "./css/csslint" ) . CSSLint ;
var Worker = exports . Worker = function ( sender ) {
Mirror . call ( this , sender ) ;
this . setTimeout ( 400 ) ;
this . ruleset = null ;
2015-02-12 05:36:57 -05:00
this . setDisabledRules ( "ids|order-alphabetical" ) ;
this . setInfoRules (
"adjoining-classes|qualified-headings|zero-units|gradients|" +
"import|outline-none|vendor-prefix"
) ;
2014-07-09 12:59:04 -04:00
} ;
oop . inherits ( Worker , Mirror ) ;
( function ( ) {
this . setInfoRules = function ( ruleNames ) {
if ( typeof ruleNames == "string" )
ruleNames = ruleNames . split ( "|" ) ;
this . infoRules = lang . arrayToMap ( ruleNames ) ;
this . doc . getValue ( ) && this . deferredUpdate . schedule ( 100 ) ;
} ;
this . setDisabledRules = function ( ruleNames ) {
if ( ! ruleNames ) {
this . ruleset = null ;
} else {
if ( typeof ruleNames == "string" )
ruleNames = ruleNames . split ( "|" ) ;
var all = { } ;
CSSLint . getRules ( ) . forEach ( function ( x ) {
all [ x . id ] = true ;
} ) ;
ruleNames . forEach ( function ( x ) {
delete all [ x ] ;
} ) ;
this . ruleset = all ;
}
this . doc . getValue ( ) && this . deferredUpdate . schedule ( 100 ) ;
} ;
this . onUpdate = function ( ) {
var value = this . doc . getValue ( ) ;
if ( ! value )
2015-09-07 12:04:05 -04:00
return this . sender . emit ( "annotate" , [ ] ) ;
2014-07-09 12:59:04 -04:00
var infoRules = this . infoRules ;
var result = CSSLint . verify ( value , this . ruleset ) ;
2015-09-07 12:04:05 -04:00
this . sender . emit ( "annotate" , result . messages . map ( function ( msg ) {
2014-07-09 12:59:04 -04:00
return {
row : msg . line - 1 ,
column : msg . col - 1 ,
text : msg . message ,
type : infoRules [ msg . rule . id ] ? "info" : msg . type ,
rule : msg . rule . name
}
} ) ) ;
} ;
} ) . call ( Worker . prototype ) ;
} ) ;
2014-07-16 06:07:18 -04:00
ace . define ( "ace/lib/es5-shim" , [ "require" , "exports" , "module" ] , function ( require , exports , module ) {
2014-07-09 12:59:04 -04:00
function Empty ( ) { }
if ( ! Function . prototype . bind ) {
Function . prototype . bind = function bind ( that ) { // .length is 1
var target = this ;
if ( typeof target != "function" ) {
throw new TypeError ( "Function.prototype.bind called on incompatible " + target ) ;
}
var args = slice . call ( arguments , 1 ) ; // for normal call
var bound = function ( ) {
if ( this instanceof bound ) {
var result = target . apply (
this ,
args . concat ( slice . call ( arguments ) )
) ;
if ( Object ( result ) === result ) {
return result ;
}
return this ;
} else {
return target . apply (
that ,
args . concat ( slice . call ( arguments ) )
) ;
}
} ;
if ( target . prototype ) {
Empty . prototype = target . prototype ;
bound . prototype = new Empty ( ) ;
Empty . prototype = null ;
}
return bound ;
} ;
}
var call = Function . prototype . call ;
var prototypeOfArray = Array . prototype ;
var prototypeOfObject = Object . prototype ;
var slice = prototypeOfArray . slice ;
var _toString = call . bind ( prototypeOfObject . toString ) ;
var owns = call . bind ( prototypeOfObject . hasOwnProperty ) ;
var defineGetter ;
var defineSetter ;
var lookupGetter ;
var lookupSetter ;
var supportsAccessors ;
if ( ( supportsAccessors = owns ( prototypeOfObject , "__defineGetter__" ) ) ) {
defineGetter = call . bind ( prototypeOfObject . _ _defineGetter _ _ ) ;
defineSetter = call . bind ( prototypeOfObject . _ _defineSetter _ _ ) ;
lookupGetter = call . bind ( prototypeOfObject . _ _lookupGetter _ _ ) ;
lookupSetter = call . bind ( prototypeOfObject . _ _lookupSetter _ _ ) ;
}
if ( [ 1 , 2 ] . splice ( 0 ) . length != 2 ) {
if ( function ( ) { // test IE < 9 to splice bug - see issue #138
function makeArray ( l ) {
var a = new Array ( l + 2 ) ;
a [ 0 ] = a [ 1 ] = 0 ;
return a ;
}
var array = [ ] , lengthBefore ;
array . splice . apply ( array , makeArray ( 20 ) ) ;
array . splice . apply ( array , makeArray ( 26 ) ) ;
lengthBefore = array . length ; //46
array . splice ( 5 , 0 , "XXX" ) ; // add one element
lengthBefore + 1 == array . length
if ( lengthBefore + 1 == array . length ) {
return true ; // has right splice implementation without bugs
}
} ( ) ) { //IE 6/7
var array _splice = Array . prototype . splice ;
Array . prototype . splice = function ( start , deleteCount ) {
if ( ! arguments . length ) {
return [ ] ;
} else {
return array _splice . apply ( this , [
start === void 0 ? 0 : start ,
deleteCount === void 0 ? ( this . length - start ) : deleteCount
] . concat ( slice . call ( arguments , 2 ) ) )
}
} ;
} else { //IE8
Array . prototype . splice = function ( pos , removeCount ) {
var length = this . length ;
if ( pos > 0 ) {
if ( pos > length )
pos = length ;
} else if ( pos == void 0 ) {
pos = 0 ;
} else if ( pos < 0 ) {
pos = Math . max ( length + pos , 0 ) ;
}
if ( ! ( pos + removeCount < length ) )
removeCount = length - pos ;
var removed = this . slice ( pos , pos + removeCount ) ;
var insert = slice . call ( arguments , 2 ) ;
var add = insert . length ;
if ( pos === length ) {
if ( add ) {
this . push . apply ( this , insert ) ;
}
} else {
var remove = Math . min ( removeCount , length - pos ) ;
var tailOldPos = pos + remove ;
var tailNewPos = tailOldPos + add - remove ;
var tailCount = length - tailOldPos ;
var lengthAfterRemove = length - remove ;
if ( tailNewPos < tailOldPos ) { // case A
for ( var i = 0 ; i < tailCount ; ++ i ) {
this [ tailNewPos + i ] = this [ tailOldPos + i ] ;
}
} else if ( tailNewPos > tailOldPos ) { // case B
for ( i = tailCount ; i -- ; ) {
this [ tailNewPos + i ] = this [ tailOldPos + i ] ;
}
} // else, add == remove (nothing to do)
if ( add && pos === lengthAfterRemove ) {
this . length = lengthAfterRemove ; // truncate array
this . push . apply ( this , insert ) ;
} else {
this . length = lengthAfterRemove + add ; // reserves space
for ( i = 0 ; i < add ; ++ i ) {
this [ pos + i ] = insert [ i ] ;
}
}
}
return removed ;
} ;
}
}
if ( ! Array . isArray ) {
Array . isArray = function isArray ( obj ) {
return _toString ( obj ) == "[object Array]" ;
} ;
}
var boxedString = Object ( "a" ) ,
splitString = boxedString [ 0 ] != "a" || ! ( 0 in boxedString ) ;
if ( ! Array . prototype . forEach ) {
Array . prototype . forEach = function forEach ( fun /*, thisp*/ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
thisp = arguments [ 1 ] ,
i = - 1 ,
length = self . length >>> 0 ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( ) ; // TODO message
}
while ( ++ i < length ) {
if ( i in self ) {
fun . call ( thisp , self [ i ] , i , object ) ;
}
}
} ;
}
if ( ! Array . prototype . map ) {
Array . prototype . map = function map ( fun /*, thisp*/ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ,
result = Array ( length ) ,
thisp = arguments [ 1 ] ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
for ( var i = 0 ; i < length ; i ++ ) {
if ( i in self )
result [ i ] = fun . call ( thisp , self [ i ] , i , object ) ;
}
return result ;
} ;
}
if ( ! Array . prototype . filter ) {
Array . prototype . filter = function filter ( fun /*, thisp */ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ,
result = [ ] ,
value ,
thisp = arguments [ 1 ] ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
for ( var i = 0 ; i < length ; i ++ ) {
if ( i in self ) {
value = self [ i ] ;
if ( fun . call ( thisp , value , i , object ) ) {
result . push ( value ) ;
}
}
}
return result ;
} ;
}
if ( ! Array . prototype . every ) {
Array . prototype . every = function every ( fun /*, thisp */ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ,
thisp = arguments [ 1 ] ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
for ( var i = 0 ; i < length ; i ++ ) {
if ( i in self && ! fun . call ( thisp , self [ i ] , i , object ) ) {
return false ;
}
}
return true ;
} ;
}
if ( ! Array . prototype . some ) {
Array . prototype . some = function some ( fun /*, thisp */ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ,
thisp = arguments [ 1 ] ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
for ( var i = 0 ; i < length ; i ++ ) {
if ( i in self && fun . call ( thisp , self [ i ] , i , object ) ) {
return true ;
}
}
return false ;
} ;
}
if ( ! Array . prototype . reduce ) {
Array . prototype . reduce = function reduce ( fun /*, initial*/ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
if ( ! length && arguments . length == 1 ) {
throw new TypeError ( "reduce of empty array with no initial value" ) ;
}
var i = 0 ;
var result ;
if ( arguments . length >= 2 ) {
result = arguments [ 1 ] ;
} else {
do {
if ( i in self ) {
result = self [ i ++ ] ;
break ;
}
if ( ++ i >= length ) {
throw new TypeError ( "reduce of empty array with no initial value" ) ;
}
} while ( true ) ;
}
for ( ; i < length ; i ++ ) {
if ( i in self ) {
result = fun . call ( void 0 , result , self [ i ] , i , object ) ;
}
}
return result ;
} ;
}
if ( ! Array . prototype . reduceRight ) {
Array . prototype . reduceRight = function reduceRight ( fun /*, initial*/ ) {
var object = toObject ( this ) ,
self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
object ,
length = self . length >>> 0 ;
if ( _toString ( fun ) != "[object Function]" ) {
throw new TypeError ( fun + " is not a function" ) ;
}
if ( ! length && arguments . length == 1 ) {
throw new TypeError ( "reduceRight of empty array with no initial value" ) ;
}
var result , i = length - 1 ;
if ( arguments . length >= 2 ) {
result = arguments [ 1 ] ;
} else {
do {
if ( i in self ) {
result = self [ i -- ] ;
break ;
}
if ( -- i < 0 ) {
throw new TypeError ( "reduceRight of empty array with no initial value" ) ;
}
} while ( true ) ;
}
do {
if ( i in this ) {
result = fun . call ( void 0 , result , self [ i ] , i , object ) ;
}
} while ( i -- ) ;
return result ;
} ;
}
if ( ! Array . prototype . indexOf || ( [ 0 , 1 ] . indexOf ( 1 , 2 ) != - 1 ) ) {
Array . prototype . indexOf = function indexOf ( sought /*, fromIndex */ ) {
var self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
toObject ( this ) ,
length = self . length >>> 0 ;
if ( ! length ) {
return - 1 ;
}
var i = 0 ;
if ( arguments . length > 1 ) {
i = toInteger ( arguments [ 1 ] ) ;
}
i = i >= 0 ? i : Math . max ( 0 , length + i ) ;
for ( ; i < length ; i ++ ) {
if ( i in self && self [ i ] === sought ) {
return i ;
}
}
return - 1 ;
} ;
}
if ( ! Array . prototype . lastIndexOf || ( [ 0 , 1 ] . lastIndexOf ( 0 , - 3 ) != - 1 ) ) {
Array . prototype . lastIndexOf = function lastIndexOf ( sought /*, fromIndex */ ) {
var self = splitString && _toString ( this ) == "[object String]" ?
this . split ( "" ) :
toObject ( this ) ,
length = self . length >>> 0 ;
if ( ! length ) {
return - 1 ;
}
var i = length - 1 ;
if ( arguments . length > 1 ) {
i = Math . min ( i , toInteger ( arguments [ 1 ] ) ) ;
}
i = i >= 0 ? i : length - Math . abs ( i ) ;
for ( ; i >= 0 ; i -- ) {
if ( i in self && sought === self [ i ] ) {
return i ;
}
}
return - 1 ;
} ;
}
if ( ! Object . getPrototypeOf ) {
Object . getPrototypeOf = function getPrototypeOf ( object ) {
return object . _ _proto _ _ || (
object . constructor ?
object . constructor . prototype :
prototypeOfObject
) ;
} ;
}
if ( ! Object . getOwnPropertyDescriptor ) {
var ERR _NON _OBJECT = "Object.getOwnPropertyDescriptor called on a " +
"non-object: " ;
Object . getOwnPropertyDescriptor = function getOwnPropertyDescriptor ( object , property ) {
if ( ( typeof object != "object" && typeof object != "function" ) || object === null )
throw new TypeError ( ERR _NON _OBJECT + object ) ;
if ( ! owns ( object , property ) )
return ;
var descriptor , getter , setter ;
descriptor = { enumerable : true , configurable : true } ;
if ( supportsAccessors ) {
var prototype = object . _ _proto _ _ ;
object . _ _proto _ _ = prototypeOfObject ;
var getter = lookupGetter ( object , property ) ;
var setter = lookupSetter ( object , property ) ;
object . _ _proto _ _ = prototype ;
if ( getter || setter ) {
if ( getter ) descriptor . get = getter ;
if ( setter ) descriptor . set = setter ;
return descriptor ;
}
}
descriptor . value = object [ property ] ;
return descriptor ;
} ;
}
if ( ! Object . getOwnPropertyNames ) {
Object . getOwnPropertyNames = function getOwnPropertyNames ( object ) {
return Object . keys ( object ) ;
} ;
}
if ( ! Object . create ) {
var createEmpty ;
if ( Object . prototype . _ _proto _ _ === null ) {
createEmpty = function ( ) {
return { "__proto__" : null } ;
} ;
} else {
createEmpty = function ( ) {
var empty = { } ;
for ( var i in empty )
empty [ i ] = null ;
empty . constructor =
empty . hasOwnProperty =
empty . propertyIsEnumerable =
empty . isPrototypeOf =
empty . toLocaleString =
empty . toString =
empty . valueOf =
empty . _ _proto _ _ = null ;
return empty ;
}
}
Object . create = function create ( prototype , properties ) {
var object ;
if ( prototype === null ) {
object = createEmpty ( ) ;
} else {
if ( typeof prototype != "object" )
throw new TypeError ( "typeof prototype[" + ( typeof prototype ) + "] != 'object'" ) ;
var Type = function ( ) { } ;
Type . prototype = prototype ;
object = new Type ( ) ;
object . _ _proto _ _ = prototype ;
}
if ( properties !== void 0 )
Object . defineProperties ( object , properties ) ;
return object ;
} ;
}
function doesDefinePropertyWork ( object ) {
try {
Object . defineProperty ( object , "sentinel" , { } ) ;
return "sentinel" in object ;
} catch ( exception ) {
}
}
if ( Object . defineProperty ) {
var definePropertyWorksOnObject = doesDefinePropertyWork ( { } ) ;
var definePropertyWorksOnDom = typeof document == "undefined" ||
doesDefinePropertyWork ( document . createElement ( "div" ) ) ;
if ( ! definePropertyWorksOnObject || ! definePropertyWorksOnDom ) {
var definePropertyFallback = Object . defineProperty ;
}
}
if ( ! Object . defineProperty || definePropertyFallback ) {
var ERR _NON _OBJECT _DESCRIPTOR = "Property description must be an object: " ;
var ERR _NON _OBJECT _TARGET = "Object.defineProperty called on non-object: "
var ERR _ACCESSORS _NOT _SUPPORTED = "getters & setters can not be defined " +
"on this javascript engine" ;
Object . defineProperty = function defineProperty ( object , property , descriptor ) {
if ( ( typeof object != "object" && typeof object != "function" ) || object === null )
throw new TypeError ( ERR _NON _OBJECT _TARGET + object ) ;
if ( ( typeof descriptor != "object" && typeof descriptor != "function" ) || descriptor === null )
throw new TypeError ( ERR _NON _OBJECT _DESCRIPTOR + descriptor ) ;
if ( definePropertyFallback ) {
try {
return definePropertyFallback . call ( Object , object , property , descriptor ) ;
} catch ( exception ) {
}
}
if ( owns ( descriptor , "value" ) ) {
if ( supportsAccessors && ( lookupGetter ( object , property ) ||
lookupSetter ( object , property ) ) )
{
var prototype = object . _ _proto _ _ ;
object . _ _proto _ _ = prototypeOfObject ;
delete object [ property ] ;
object [ property ] = descriptor . value ;
object . _ _proto _ _ = prototype ;
} else {
object [ property ] = descriptor . value ;
}
} else {
if ( ! supportsAccessors )
throw new TypeError ( ERR _ACCESSORS _NOT _SUPPORTED ) ;
if ( owns ( descriptor , "get" ) )
defineGetter ( object , property , descriptor . get ) ;
if ( owns ( descriptor , "set" ) )
defineSetter ( object , property , descriptor . set ) ;
}
return object ;
} ;
}
if ( ! Object . defineProperties ) {
Object . defineProperties = function defineProperties ( object , properties ) {
for ( var property in properties ) {
if ( owns ( properties , property ) )
Object . defineProperty ( object , property , properties [ property ] ) ;
}
return object ;
} ;
}
if ( ! Object . seal ) {
Object . seal = function seal ( object ) {
return object ;
} ;
}
if ( ! Object . freeze ) {
Object . freeze = function freeze ( object ) {
return object ;
} ;
}
try {
Object . freeze ( function ( ) { } ) ;
} catch ( exception ) {
Object . freeze = ( function freeze ( freezeObject ) {
return function freeze ( object ) {
if ( typeof object == "function" ) {
return object ;
} else {
return freezeObject ( object ) ;
}
} ;
} ) ( Object . freeze ) ;
}
if ( ! Object . preventExtensions ) {
Object . preventExtensions = function preventExtensions ( object ) {
return object ;
} ;
}
if ( ! Object . isSealed ) {
Object . isSealed = function isSealed ( object ) {
return false ;
} ;
}
if ( ! Object . isFrozen ) {
Object . isFrozen = function isFrozen ( object ) {
return false ;
} ;
}
if ( ! Object . isExtensible ) {
Object . isExtensible = function isExtensible ( object ) {
if ( Object ( object ) === object ) {
throw new TypeError ( ) ; // TODO message
}
var name = '' ;
while ( owns ( object , name ) ) {
name += '?' ;
}
object [ name ] = true ;
var returnValue = owns ( object , name ) ;
delete object [ name ] ;
return returnValue ;
} ;
}
if ( ! Object . keys ) {
var hasDontEnumBug = true ,
dontEnums = [
"toString" ,
"toLocaleString" ,
"valueOf" ,
"hasOwnProperty" ,
"isPrototypeOf" ,
"propertyIsEnumerable" ,
"constructor"
] ,
dontEnumsLength = dontEnums . length ;
for ( var key in { "toString" : null } ) {
hasDontEnumBug = false ;
}
Object . keys = function keys ( object ) {
if (
( typeof object != "object" && typeof object != "function" ) ||
object === null
) {
throw new TypeError ( "Object.keys called on a non-object" ) ;
}
var keys = [ ] ;
for ( var name in object ) {
if ( owns ( object , name ) ) {
keys . push ( name ) ;
}
}
if ( hasDontEnumBug ) {
for ( var i = 0 , ii = dontEnumsLength ; i < ii ; i ++ ) {
var dontEnum = dontEnums [ i ] ;
if ( owns ( object , dontEnum ) ) {
keys . push ( dontEnum ) ;
}
}
}
return keys ;
} ;
}
if ( ! Date . now ) {
Date . now = function now ( ) {
return new Date ( ) . getTime ( ) ;
} ;
}
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF" ;
if ( ! String . prototype . trim || ws . trim ( ) ) {
ws = "[" + ws + "]" ;
var trimBeginRegexp = new RegExp ( "^" + ws + ws + "*" ) ,
trimEndRegexp = new RegExp ( ws + ws + "*$" ) ;
String . prototype . trim = function trim ( ) {
return String ( this ) . replace ( trimBeginRegexp , "" ) . replace ( trimEndRegexp , "" ) ;
} ;
}
function toInteger ( n ) {
n = + n ;
if ( n !== n ) { // isNaN
n = 0 ;
} else if ( n !== 0 && n !== ( 1 / 0 ) && n !== - ( 1 / 0 ) ) {
n = ( n > 0 || - 1 ) * Math . floor ( Math . abs ( n ) ) ;
}
return n ;
}
function isPrimitive ( input ) {
var type = typeof input ;
return (
input === null ||
type === "undefined" ||
type === "boolean" ||
type === "number" ||
type === "string"
) ;
}
function toPrimitive ( input ) {
var val , valueOf , toString ;
if ( isPrimitive ( input ) ) {
return input ;
}
valueOf = input . valueOf ;
if ( typeof valueOf === "function" ) {
val = valueOf . call ( input ) ;
if ( isPrimitive ( val ) ) {
return val ;
}
}
toString = input . toString ;
if ( typeof toString === "function" ) {
val = toString . call ( input ) ;
if ( isPrimitive ( val ) ) {
return val ;
}
}
throw new TypeError ( ) ;
}
var toObject = function ( o ) {
if ( o == null ) { // this matches both null and undefined
throw new TypeError ( "can't convert " + o + " to object" ) ;
}
return Object ( o ) ;
} ;
} ) ;