3
if (typeof window.window != "undefined" && window.document) {
9
var msgs = Array.prototype.slice.call(arguments, 0);
10
postMessage({type: "log", data: msgs});
13
var msgs = Array.prototype.slice.call(arguments, 0);
14
postMessage({type: "log", data: msgs});
17
window.window = window;
20
window.normalizeModule = function(parentId, moduleName) {
21
// normalize plugin requires
22
if (moduleName.indexOf("!") !== -1) {
23
var chunks = moduleName.split("!");
24
return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]);
26
// normalize relative requires
27
if (moduleName.charAt(0) == ".") {
28
var base = parentId.split("/").slice(0, -1).join("/");
29
moduleName = base + "/" + moduleName;
31
while(moduleName.indexOf(".") !== -1 && previous != moduleName) {
32
var previous = moduleName;
33
moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
40
window.require = function(parentId, id) {
42
throw new Error("worker.js require() accepts only (parentId, id) as arguments");
44
id = normalizeModule(parentId, id);
46
var module = require.modules[id];
48
if (!module.initialized) {
49
module.initialized = true;
50
module.exports = module.factory().exports;
52
return module.exports;
55
var chunks = id.split("/");
56
chunks[0] = require.tlns[chunks[0]] || chunks[0];
57
var path = chunks.join("/") + ".js";
61
return require(parentId, id);
67
window.define = function(id, deps, factory) {
68
if (arguments.length == 2) {
70
if (typeof id != "string") {
74
} else if (arguments.length == 1) {
79
if (id.indexOf("text!") === 0)
82
var req = function(deps, factory) {
83
return require(id, deps, factory);
86
require.modules[id] = {
91
var returnExports = factory(req, module.exports, module);
93
module.exports = returnExports;
99
window.initBaseUrls = function initBaseUrls(topLevelNamespaces) {
100
require.tlns = topLevelNamespaces;
103
window.initSender = function initSender() {
105
var EventEmitter = require(null, "ace/lib/event_emitter").EventEmitter;
106
var oop = require(null, "ace/lib/oop");
108
var Sender = function() {};
112
oop.implement(this, EventEmitter);
114
this.callback = function(data, callbackId) {
122
this.emit = function(name, data) {
130
}).call(Sender.prototype);
136
window.sender = null;
138
window.onmessage = function(e) {
141
if (main[msg.command])
142
main[msg.command].apply(main, msg.args);
144
throw new Error("Unknown command:" + msg.command);
147
initBaseUrls(msg.tlns);
148
require(null, "ace/lib/fixoldbrowsers");
149
sender = initSender();
150
var clazz = require(null, msg.module)[msg.classname];
151
main = new clazz(sender);
153
else if (msg.event && sender) {
154
sender._emit(msg.event, msg.data);
157
})(this);// vim:set ts=4 sts=4 sw=4 st:
159
define('ace/lib/fixoldbrowsers', ['require', 'exports', 'module' , 'ace/lib/regexp', 'ace/lib/es5-shim'], function(require, exports, module) {
163
require("./es5-shim");
167
define('ace/lib/regexp', ['require', 'exports', 'module' ], function(require, exports, module) {
170
exec: RegExp.prototype.exec,
171
test: RegExp.prototype.test,
172
match: String.prototype.match,
173
replace: String.prototype.replace,
174
split: String.prototype.split
176
compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
177
compliantLastIndexIncrement = function () {
179
real.test.call(x, "");
183
if (compliantLastIndexIncrement && compliantExecNpcg)
185
RegExp.prototype.exec = function (str) {
186
var match = real.exec.apply(this, arguments),
188
if ( typeof(str) == 'string' && match) {
189
if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
190
r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
191
real.replace.call(str.slice(match.index), r2, function () {
192
for (var i = 1; i < arguments.length - 2; i++) {
193
if (arguments[i] === undefined)
194
match[i] = undefined;
198
if (this._xregexp && this._xregexp.captureNames) {
199
for (var i = 1; i < match.length; i++) {
200
name = this._xregexp.captureNames[i - 1];
202
match[name] = match[i];
205
if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
210
if (!compliantLastIndexIncrement) {
211
RegExp.prototype.test = function (str) {
212
var match = real.exec.call(this, str);
213
if (match && this.global && !match[0].length && (this.lastIndex > match.index))
219
function getNativeFlags (regex) {
220
return (regex.global ? "g" : "") +
221
(regex.ignoreCase ? "i" : "") +
222
(regex.multiline ? "m" : "") +
223
(regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
224
(regex.sticky ? "y" : "");
227
function indexOf (array, item, from) {
228
if (Array.prototype.indexOf) // Use the native array method if available
229
return array.indexOf(item, from);
230
for (var i = from || 0; i < array.length; i++) {
231
if (array[i] === item)
239
define('ace/lib/es5-shim', ['require', 'exports', 'module' ], function(require, exports, module) {
243
if (!Function.prototype.bind) {
244
Function.prototype.bind = function bind(that) { // .length is 1
246
if (typeof target != "function") {
247
throw new TypeError("Function.prototype.bind called on incompatible " + target);
249
var args = slice.call(arguments, 1); // for normal call
250
var bound = function () {
252
if (this instanceof bound) {
254
var result = target.apply(
256
args.concat(slice.call(arguments))
258
if (Object(result) === result) {
266
args.concat(slice.call(arguments))
272
if(target.prototype) {
273
Empty.prototype = target.prototype;
274
bound.prototype = new Empty();
275
Empty.prototype = null;
280
var call = Function.prototype.call;
281
var prototypeOfArray = Array.prototype;
282
var prototypeOfObject = Object.prototype;
283
var slice = prototypeOfArray.slice;
284
var _toString = call.bind(prototypeOfObject.toString);
285
var owns = call.bind(prototypeOfObject.hasOwnProperty);
290
var supportsAccessors;
291
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
292
defineGetter = call.bind(prototypeOfObject.__defineGetter__);
293
defineSetter = call.bind(prototypeOfObject.__defineSetter__);
294
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
295
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
297
if ([1,2].splice(0).length != 2) {
298
if(function() { // test IE < 9 to splice bug - see issue #138
299
function makeArray(l) {
300
var a = new Array(l+2);
304
var array = [], lengthBefore;
306
array.splice.apply(array, makeArray(20));
307
array.splice.apply(array, makeArray(26));
309
lengthBefore = array.length; //46
310
array.splice(5, 0, "XXX"); // add one element
312
lengthBefore + 1 == array.length
314
if (lengthBefore + 1 == array.length) {
315
return true;// has right splice implementation without bugs
318
var array_splice = Array.prototype.splice;
319
Array.prototype.splice = function(start, deleteCount) {
320
if (!arguments.length) {
323
return array_splice.apply(this, [
324
start === void 0 ? 0 : start,
325
deleteCount === void 0 ? (this.length - start) : deleteCount
326
].concat(slice.call(arguments, 2)))
330
Array.prototype.splice = function(pos, removeCount){
331
var length = this.length;
335
} else if (pos == void 0) {
337
} else if (pos < 0) {
338
pos = Math.max(length + pos, 0);
341
if (!(pos+removeCount < length))
342
removeCount = length - pos;
344
var removed = this.slice(pos, pos+removeCount);
345
var insert = slice.call(arguments, 2);
346
var add = insert.length;
347
if (pos === length) {
349
this.push.apply(this, insert);
352
var remove = Math.min(removeCount, length - pos);
353
var tailOldPos = pos + remove;
354
var tailNewPos = tailOldPos + add - remove;
355
var tailCount = length - tailOldPos;
356
var lengthAfterRemove = length - remove;
358
if (tailNewPos < tailOldPos) { // case A
359
for (var i = 0; i < tailCount; ++i) {
360
this[tailNewPos+i] = this[tailOldPos+i];
362
} else if (tailNewPos > tailOldPos) { // case B
363
for (i = tailCount; i--; ) {
364
this[tailNewPos+i] = this[tailOldPos+i];
366
} // else, add == remove (nothing to do)
368
if (add && pos === lengthAfterRemove) {
369
this.length = lengthAfterRemove; // truncate array
370
this.push.apply(this, insert);
372
this.length = lengthAfterRemove + add; // reserves space
373
for (i = 0; i < add; ++i) {
374
this[pos+i] = insert[i];
382
if (!Array.isArray) {
383
Array.isArray = function isArray(obj) {
384
return _toString(obj) == "[object Array]";
387
var boxedString = Object("a"),
388
splitString = boxedString[0] != "a" || !(0 in boxedString);
390
if (!Array.prototype.forEach) {
391
Array.prototype.forEach = function forEach(fun /*, thisp*/) {
392
var object = toObject(this),
393
self = splitString && _toString(this) == "[object String]" ?
396
thisp = arguments[1],
398
length = self.length >>> 0;
399
if (_toString(fun) != "[object Function]") {
400
throw new TypeError(); // TODO message
403
while (++i < length) {
405
fun.call(thisp, self[i], i, object);
410
if (!Array.prototype.map) {
411
Array.prototype.map = function map(fun /*, thisp*/) {
412
var object = toObject(this),
413
self = splitString && _toString(this) == "[object String]" ?
416
length = self.length >>> 0,
417
result = Array(length),
418
thisp = arguments[1];
419
if (_toString(fun) != "[object Function]") {
420
throw new TypeError(fun + " is not a function");
423
for (var i = 0; i < length; i++) {
425
result[i] = fun.call(thisp, self[i], i, object);
430
if (!Array.prototype.filter) {
431
Array.prototype.filter = function filter(fun /*, thisp */) {
432
var object = toObject(this),
433
self = splitString && _toString(this) == "[object String]" ?
436
length = self.length >>> 0,
439
thisp = arguments[1];
440
if (_toString(fun) != "[object Function]") {
441
throw new TypeError(fun + " is not a function");
444
for (var i = 0; i < length; i++) {
447
if (fun.call(thisp, value, i, object)) {
455
if (!Array.prototype.every) {
456
Array.prototype.every = function every(fun /*, thisp */) {
457
var object = toObject(this),
458
self = splitString && _toString(this) == "[object String]" ?
461
length = self.length >>> 0,
462
thisp = arguments[1];
463
if (_toString(fun) != "[object Function]") {
464
throw new TypeError(fun + " is not a function");
467
for (var i = 0; i < length; i++) {
468
if (i in self && !fun.call(thisp, self[i], i, object)) {
475
if (!Array.prototype.some) {
476
Array.prototype.some = function some(fun /*, thisp */) {
477
var object = toObject(this),
478
self = splitString && _toString(this) == "[object String]" ?
481
length = self.length >>> 0,
482
thisp = arguments[1];
483
if (_toString(fun) != "[object Function]") {
484
throw new TypeError(fun + " is not a function");
487
for (var i = 0; i < length; i++) {
488
if (i in self && fun.call(thisp, self[i], i, object)) {
495
if (!Array.prototype.reduce) {
496
Array.prototype.reduce = function reduce(fun /*, initial*/) {
497
var object = toObject(this),
498
self = splitString && _toString(this) == "[object String]" ?
501
length = self.length >>> 0;
502
if (_toString(fun) != "[object Function]") {
503
throw new TypeError(fun + " is not a function");
505
if (!length && arguments.length == 1) {
506
throw new TypeError("reduce of empty array with no initial value");
511
if (arguments.length >= 2) {
512
result = arguments[1];
520
throw new TypeError("reduce of empty array with no initial value");
525
for (; i < length; i++) {
527
result = fun.call(void 0, result, self[i], i, object);
534
if (!Array.prototype.reduceRight) {
535
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
536
var object = toObject(this),
537
self = splitString && _toString(this) == "[object String]" ?
540
length = self.length >>> 0;
541
if (_toString(fun) != "[object Function]") {
542
throw new TypeError(fun + " is not a function");
544
if (!length && arguments.length == 1) {
545
throw new TypeError("reduceRight of empty array with no initial value");
548
var result, i = length - 1;
549
if (arguments.length >= 2) {
550
result = arguments[1];
558
throw new TypeError("reduceRight of empty array with no initial value");
565
result = fun.call(void 0, result, self[i], i, object);
572
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
573
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
574
var self = splitString && _toString(this) == "[object String]" ?
577
length = self.length >>> 0;
584
if (arguments.length > 1) {
585
i = toInteger(arguments[1]);
587
i = i >= 0 ? i : Math.max(0, length + i);
588
for (; i < length; i++) {
589
if (i in self && self[i] === sought) {
596
if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
597
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
598
var self = splitString && _toString(this) == "[object String]" ?
601
length = self.length >>> 0;
607
if (arguments.length > 1) {
608
i = Math.min(i, toInteger(arguments[1]));
610
i = i >= 0 ? i : length - Math.abs(i);
611
for (; i >= 0; i--) {
612
if (i in self && sought === self[i]) {
619
if (!Object.getPrototypeOf) {
620
Object.getPrototypeOf = function getPrototypeOf(object) {
621
return object.__proto__ || (
623
object.constructor.prototype :
628
if (!Object.getOwnPropertyDescriptor) {
629
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
631
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
632
if ((typeof object != "object" && typeof object != "function") || object === null)
633
throw new TypeError(ERR_NON_OBJECT + object);
634
if (!owns(object, property))
637
var descriptor, getter, setter;
638
descriptor = { enumerable: true, configurable: true };
639
if (supportsAccessors) {
640
var prototype = object.__proto__;
641
object.__proto__ = prototypeOfObject;
643
var getter = lookupGetter(object, property);
644
var setter = lookupSetter(object, property);
645
object.__proto__ = prototype;
647
if (getter || setter) {
648
if (getter) descriptor.get = getter;
649
if (setter) descriptor.set = setter;
653
descriptor.value = object[property];
657
if (!Object.getOwnPropertyNames) {
658
Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
659
return Object.keys(object);
662
if (!Object.create) {
664
if (Object.prototype.__proto__ === null) {
665
createEmpty = function () {
666
return { "__proto__": null };
669
createEmpty = function () {
674
empty.hasOwnProperty =
675
empty.propertyIsEnumerable =
676
empty.isPrototypeOf =
677
empty.toLocaleString =
680
empty.__proto__ = null;
685
Object.create = function create(prototype, properties) {
687
if (prototype === null) {
688
object = createEmpty();
690
if (typeof prototype != "object")
691
throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
692
var Type = function () {};
693
Type.prototype = prototype;
695
object.__proto__ = prototype;
697
if (properties !== void 0)
698
Object.defineProperties(object, properties);
703
function doesDefinePropertyWork(object) {
705
Object.defineProperty(object, "sentinel", {});
706
return "sentinel" in object;
707
} catch (exception) {
710
if (Object.defineProperty) {
711
var definePropertyWorksOnObject = doesDefinePropertyWork({});
712
var definePropertyWorksOnDom = typeof document == "undefined" ||
713
doesDefinePropertyWork(document.createElement("div"));
714
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
715
var definePropertyFallback = Object.defineProperty;
719
if (!Object.defineProperty || definePropertyFallback) {
720
var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
721
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
722
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
723
"on this javascript engine";
725
Object.defineProperty = function defineProperty(object, property, descriptor) {
726
if ((typeof object != "object" && typeof object != "function") || object === null)
727
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
728
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
729
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
730
if (definePropertyFallback) {
732
return definePropertyFallback.call(Object, object, property, descriptor);
733
} catch (exception) {
736
if (owns(descriptor, "value")) {
738
if (supportsAccessors && (lookupGetter(object, property) ||
739
lookupSetter(object, property)))
741
var prototype = object.__proto__;
742
object.__proto__ = prototypeOfObject;
743
delete object[property];
744
object[property] = descriptor.value;
745
object.__proto__ = prototype;
747
object[property] = descriptor.value;
750
if (!supportsAccessors)
751
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
752
if (owns(descriptor, "get"))
753
defineGetter(object, property, descriptor.get);
754
if (owns(descriptor, "set"))
755
defineSetter(object, property, descriptor.set);
761
if (!Object.defineProperties) {
762
Object.defineProperties = function defineProperties(object, properties) {
763
for (var property in properties) {
764
if (owns(properties, property))
765
Object.defineProperty(object, property, properties[property]);
771
Object.seal = function seal(object) {
775
if (!Object.freeze) {
776
Object.freeze = function freeze(object) {
781
Object.freeze(function () {});
782
} catch (exception) {
783
Object.freeze = (function freeze(freezeObject) {
784
return function freeze(object) {
785
if (typeof object == "function") {
788
return freezeObject(object);
793
if (!Object.preventExtensions) {
794
Object.preventExtensions = function preventExtensions(object) {
798
if (!Object.isSealed) {
799
Object.isSealed = function isSealed(object) {
803
if (!Object.isFrozen) {
804
Object.isFrozen = function isFrozen(object) {
808
if (!Object.isExtensible) {
809
Object.isExtensible = function isExtensible(object) {
810
if (Object(object) === object) {
811
throw new TypeError(); // TODO message
814
while (owns(object, name)) {
818
var returnValue = owns(object, name);
824
var hasDontEnumBug = true,
831
"propertyIsEnumerable",
834
dontEnumsLength = dontEnums.length;
836
for (var key in {"toString": null}) {
837
hasDontEnumBug = false;
840
Object.keys = function keys(object) {
843
(typeof object != "object" && typeof object != "function") ||
846
throw new TypeError("Object.keys called on a non-object");
850
for (var name in object) {
851
if (owns(object, name)) {
856
if (hasDontEnumBug) {
857
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
858
var dontEnum = dontEnums[i];
859
if (owns(object, dontEnum)) {
869
Date.now = function now() {
870
return new Date().getTime();
873
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
874
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
876
if (!String.prototype.trim || ws.trim()) {
878
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
879
trimEndRegexp = new RegExp(ws + ws + "*$");
880
String.prototype.trim = function trim() {
881
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
885
function toInteger(n) {
887
if (n !== n) { // isNaN
889
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
890
n = (n > 0 || -1) * Math.floor(Math.abs(n));
895
function isPrimitive(input) {
896
var type = typeof input;
899
type === "undefined" ||
900
type === "boolean" ||
906
function toPrimitive(input) {
907
var val, valueOf, toString;
908
if (isPrimitive(input)) {
911
valueOf = input.valueOf;
912
if (typeof valueOf === "function") {
913
val = valueOf.call(input);
914
if (isPrimitive(val)) {
918
toString = input.toString;
919
if (typeof toString === "function") {
920
val = toString.call(input);
921
if (isPrimitive(val)) {
925
throw new TypeError();
927
var toObject = function (o) {
928
if (o == null) { // this matches both null and undefined
929
throw new TypeError("can't convert "+o+" to object");
936
define('ace/lib/event_emitter', ['require', 'exports', 'module' ], function(require, exports, module) {
939
var EventEmitter = {};
940
var stopPropagation = function() { this.propagationStopped = true; };
941
var preventDefault = function() { this.defaultPrevented = true; };
944
EventEmitter._dispatchEvent = function(eventName, e) {
945
this._eventRegistry || (this._eventRegistry = {});
946
this._defaultHandlers || (this._defaultHandlers = {});
948
var listeners = this._eventRegistry[eventName] || [];
949
var defaultHandler = this._defaultHandlers[eventName];
950
if (!listeners.length && !defaultHandler)
953
if (typeof e != "object" || !e)
958
if (!e.stopPropagation)
959
e.stopPropagation = stopPropagation;
960
if (!e.preventDefault)
961
e.preventDefault = preventDefault;
965
for (var i=0; i<listeners.length; i++) {
967
if (e.propagationStopped)
971
if (defaultHandler && !e.defaultPrevented)
972
return defaultHandler(e);
976
EventEmitter._signal = function(eventName, e) {
977
var listeners = (this._eventRegistry || {})[eventName];
981
for (var i=0; i<listeners.length; i++)
985
EventEmitter.once = function(eventName, callback) {
987
var newCallback = function() {
988
fun && fun.apply(null, arguments);
989
_self.removeEventListener(event, newCallback);
991
this.addEventListener(event, newCallback);
995
EventEmitter.setDefaultHandler = function(eventName, callback) {
996
this._defaultHandlers = this._defaultHandlers || {};
998
if (this._defaultHandlers[eventName])
999
throw new Error("The default handler for '" + eventName + "' is already set");
1001
this._defaultHandlers[eventName] = callback;
1005
EventEmitter.addEventListener = function(eventName, callback, capturing) {
1006
this._eventRegistry = this._eventRegistry || {};
1008
var listeners = this._eventRegistry[eventName];
1010
listeners = this._eventRegistry[eventName] = [];
1012
if (listeners.indexOf(callback) == -1)
1013
listeners[capturing ? "unshift" : "push"](callback);
1017
EventEmitter.removeListener =
1018
EventEmitter.removeEventListener = function(eventName, callback) {
1019
this._eventRegistry = this._eventRegistry || {};
1021
var listeners = this._eventRegistry[eventName];
1025
var index = listeners.indexOf(callback);
1027
listeners.splice(index, 1);
1030
EventEmitter.removeAllListeners = function(eventName) {
1031
if (this._eventRegistry) this._eventRegistry[eventName] = [];
1034
exports.EventEmitter = EventEmitter;
1038
define('ace/lib/oop', ['require', 'exports', 'module' ], function(require, exports, module) {
1041
exports.inherits = (function() {
1042
var tempCtor = function() {};
1043
return function(ctor, superCtor) {
1044
tempCtor.prototype = superCtor.prototype;
1045
ctor.super_ = superCtor.prototype;
1046
ctor.prototype = new tempCtor();
1047
ctor.prototype.constructor = ctor;
1051
exports.mixin = function(obj, mixin) {
1052
for (var key in mixin) {
1053
obj[key] = mixin[key];
1057
exports.implement = function(proto, mixin) {
1058
exports.mixin(proto, mixin);
1063
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) {
1066
var oop = require("../lib/oop");
1067
var lang = require("../lib/lang");
1068
var Mirror = require("../worker/mirror").Mirror;
1069
var CSSLint = require("./css/csslint").CSSLint;
1071
var Worker = exports.Worker = function(sender) {
1072
Mirror.call(this, sender);
1073
this.setTimeout(400);
1074
this.ruleset = null;
1075
this.setDisabledRules("ids");
1076
this.setInfoRules("adjoining-classes|qualified-headings|zero-units|gradients|import|outline-none");
1079
oop.inherits(Worker, Mirror);
1082
this.setInfoRules = function(ruleNames) {
1083
if (typeof ruleNames == "string")
1084
ruleNames = ruleNames.split("|");
1085
this.infoRules = lang.arrayToMap(ruleNames);
1086
this.doc.getValue() && this.deferredUpdate.schedule(100);
1089
this.setDisabledRules = function(ruleNames) {
1091
this.ruleset = null;
1093
if (typeof ruleNames == "string")
1094
ruleNames = ruleNames.split("|");
1097
CSSLint.getRules().forEach(function(x){
1100
ruleNames.forEach(function(x) {
1106
this.doc.getValue() && this.deferredUpdate.schedule(100);
1109
this.onUpdate = function() {
1110
var value = this.doc.getValue();
1111
var infoRules = this.infoRules;
1113
var result = CSSLint.verify(value, this.ruleset);
1114
this.sender.emit("csslint", result.messages.map(function(msg) {
1117
column: msg.col - 1,
1119
type: infoRules[msg.rule.id] ? "info" : msg.type
1124
}).call(Worker.prototype);
1128
define('ace/lib/lang', ['require', 'exports', 'module' ], function(require, exports, module) {
1131
exports.stringReverse = function(string) {
1132
return string.split("").reverse().join("");
1135
exports.stringRepeat = function (string, count) {
1147
var trimBeginRegexp = /^\s\s*/;
1148
var trimEndRegexp = /\s\s*$/;
1150
exports.stringTrimLeft = function (string) {
1151
return string.replace(trimBeginRegexp, '');
1154
exports.stringTrimRight = function (string) {
1155
return string.replace(trimEndRegexp, '');
1158
exports.copyObject = function(obj) {
1160
for (var key in obj) {
1161
copy[key] = obj[key];
1166
exports.copyArray = function(array){
1168
for (var i=0, l=array.length; i<l; i++) {
1169
if (array[i] && typeof array[i] == "object")
1170
copy[i] = this.copyObject( array[i] );
1177
exports.deepCopy = function (obj) {
1178
if (typeof obj != "object") {
1182
var copy = obj.constructor();
1183
for (var key in obj) {
1184
if (typeof obj[key] == "object") {
1185
copy[key] = this.deepCopy(obj[key]);
1187
copy[key] = obj[key];
1193
exports.arrayToMap = function(arr) {
1195
for (var i=0; i<arr.length; i++) {
1202
exports.createMap = function(props) {
1203
var map = Object.create(null);
1204
for (var i in props) {
1209
exports.arrayRemove = function(array, value) {
1210
for (var i = 0; i <= array.length; i++) {
1211
if (value === array[i]) {
1217
exports.escapeRegExp = function(str) {
1218
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
1221
exports.escapeHTML = function(str) {
1222
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<");
1225
exports.getMatchOffsets = function(string, regExp) {
1228
string.replace(regExp, function(str) {
1230
offset: arguments[arguments.length-2],
1237
exports.deferredCall = function(fcn) {
1240
var callback = function() {
1245
var deferred = function(timeout) {
1247
timer = setTimeout(callback, timeout || 0);
1251
deferred.schedule = deferred;
1253
deferred.call = function() {
1259
deferred.cancel = function() {
1260
clearTimeout(timer);
1269
exports.delayedCall = function(fcn, defaultTimeout) {
1271
var callback = function() {
1276
var _self = function(timeout) {
1277
timer && clearTimeout(timer);
1278
timer = setTimeout(callback, timeout || defaultTimeout);
1281
_self.delay = _self;
1282
_self.schedule = function(timeout) {
1284
timer = setTimeout(callback, timeout || 0);
1287
_self.call = function() {
1292
_self.cancel = function() {
1293
timer && clearTimeout(timer);
1297
_self.isPending = function() {
1304
define('ace/worker/mirror', ['require', 'exports', 'module' , 'ace/document', 'ace/lib/lang'], function(require, exports, module) {
1307
var Document = require("../document").Document;
1308
var lang = require("../lib/lang");
1310
var Mirror = exports.Mirror = function(sender) {
1311
this.sender = sender;
1312
var doc = this.doc = new Document("");
1314
var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));
1317
sender.on("change", function(e) {
1318
doc.applyDeltas([e.data]);
1319
deferredUpdate.schedule(_self.$timeout);
1325
this.$timeout = 500;
1327
this.setTimeout = function(timeout) {
1328
this.$timeout = timeout;
1331
this.setValue = function(value) {
1332
this.doc.setValue(value);
1333
this.deferredUpdate.schedule(this.$timeout);
1336
this.getValue = function(callbackId) {
1337
this.sender.callback(this.doc.getValue(), callbackId);
1340
this.onUpdate = function() {
1343
}).call(Mirror.prototype);
1347
define('ace/document', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/range', 'ace/anchor'], function(require, exports, module) {
1350
var oop = require("./lib/oop");
1351
var EventEmitter = require("./lib/event_emitter").EventEmitter;
1352
var Range = require("./range").Range;
1353
var Anchor = require("./anchor").Anchor;
1355
var Document = function(text) {
1357
if (text.length == 0) {
1359
} else if (Array.isArray(text)) {
1360
this.insertLines(0, text);
1362
this.insert({row: 0, column:0}, text);
1368
oop.implement(this, EventEmitter);
1369
this.setValue = function(text) {
1370
var len = this.getLength();
1371
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
1372
this.insert({row: 0, column:0}, text);
1374
this.getValue = function() {
1375
return this.getAllLines().join(this.getNewLineCharacter());
1377
this.createAnchor = function(row, column) {
1378
return new Anchor(this, row, column);
1380
if ("aaa".split(/a/).length == 0)
1381
this.$split = function(text) {
1382
return text.replace(/\r\n|\r/g, "\n").split("\n");
1385
this.$split = function(text) {
1386
return text.split(/\r\n|\r|\n/);
1391
this.$detectNewLine = function(text) {
1392
var match = text.match(/^.*?(\r\n|\r|\n)/m);
1394
this.$autoNewLine = match[1];
1396
this.$autoNewLine = "\n";
1399
this.getNewLineCharacter = function() {
1400
switch (this.$newLineMode) {
1408
return this.$autoNewLine;
1412
this.$autoNewLine = "\n";
1413
this.$newLineMode = "auto";
1414
this.setNewLineMode = function(newLineMode) {
1415
if (this.$newLineMode === newLineMode)
1418
this.$newLineMode = newLineMode;
1420
this.getNewLineMode = function() {
1421
return this.$newLineMode;
1423
this.isNewLine = function(text) {
1424
return (text == "\r\n" || text == "\r" || text == "\n");
1426
this.getLine = function(row) {
1427
return this.$lines[row] || "";
1429
this.getLines = function(firstRow, lastRow) {
1430
return this.$lines.slice(firstRow, lastRow + 1);
1432
this.getAllLines = function() {
1433
return this.getLines(0, this.getLength());
1435
this.getLength = function() {
1436
return this.$lines.length;
1438
this.getTextRange = function(range) {
1439
if (range.start.row == range.end.row) {
1440
return this.$lines[range.start.row].substring(range.start.column,
1444
var lines = this.getLines(range.start.row+1, range.end.row-1);
1445
lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
1446
lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
1447
return lines.join(this.getNewLineCharacter());
1451
this.$clipPosition = function(position) {
1452
var length = this.getLength();
1453
if (position.row >= length) {
1454
position.row = Math.max(0, length - 1);
1455
position.column = this.getLine(length-1).length;
1459
this.insert = function(position, text) {
1460
if (!text || text.length === 0)
1463
position = this.$clipPosition(position);
1464
if (this.getLength() <= 1)
1465
this.$detectNewLine(text);
1467
var lines = this.$split(text);
1468
var firstLine = lines.splice(0, 1)[0];
1469
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
1471
position = this.insertInLine(position, firstLine);
1472
if (lastLine !== null) {
1473
position = this.insertNewLine(position); // terminate first line
1474
position = this.insertLines(position.row, lines);
1475
position = this.insertInLine(position, lastLine || "");
1479
this.insertLines = function(row, lines) {
1480
if (lines.length == 0)
1481
return {row: row, column: 0};
1482
if (lines.length > 0xFFFF) {
1483
var end = this.insertLines(row, lines.slice(0xFFFF));
1484
lines = lines.slice(0, 0xFFFF);
1487
var args = [row, 0];
1488
args.push.apply(args, lines);
1489
this.$lines.splice.apply(this.$lines, args);
1491
var range = new Range(row, 0, row + lines.length, 0);
1493
action: "insertLines",
1497
this._emit("change", { data: delta });
1498
return end || range.end;
1500
this.insertNewLine = function(position) {
1501
position = this.$clipPosition(position);
1502
var line = this.$lines[position.row] || "";
1504
this.$lines[position.row] = line.substring(0, position.column);
1505
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
1508
row : position.row + 1,
1513
action: "insertText",
1514
range: Range.fromPoints(position, end),
1515
text: this.getNewLineCharacter()
1517
this._emit("change", { data: delta });
1521
this.insertInLine = function(position, text) {
1522
if (text.length == 0)
1525
var line = this.$lines[position.row] || "";
1527
this.$lines[position.row] = line.substring(0, position.column) + text
1528
+ line.substring(position.column);
1532
column : position.column + text.length
1536
action: "insertText",
1537
range: Range.fromPoints(position, end),
1540
this._emit("change", { data: delta });
1544
this.remove = function(range) {
1545
range.start = this.$clipPosition(range.start);
1546
range.end = this.$clipPosition(range.end);
1548
if (range.isEmpty())
1551
var firstRow = range.start.row;
1552
var lastRow = range.end.row;
1554
if (range.isMultiLine()) {
1555
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
1556
var lastFullRow = lastRow - 1;
1558
if (range.end.column > 0)
1559
this.removeInLine(lastRow, 0, range.end.column);
1561
if (lastFullRow >= firstFullRow)
1562
this.removeLines(firstFullRow, lastFullRow);
1564
if (firstFullRow != firstRow) {
1565
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
1566
this.removeNewLine(range.start.row);
1570
this.removeInLine(firstRow, range.start.column, range.end.column);
1574
this.removeInLine = function(row, startColumn, endColumn) {
1575
if (startColumn == endColumn)
1578
var range = new Range(row, startColumn, row, endColumn);
1579
var line = this.getLine(row);
1580
var removed = line.substring(startColumn, endColumn);
1581
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
1582
this.$lines.splice(row, 1, newLine);
1585
action: "removeText",
1589
this._emit("change", { data: delta });
1592
this.removeLines = function(firstRow, lastRow) {
1593
var range = new Range(firstRow, 0, lastRow + 1, 0);
1594
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
1597
action: "removeLines",
1599
nl: this.getNewLineCharacter(),
1602
this._emit("change", { data: delta });
1605
this.removeNewLine = function(row) {
1606
var firstLine = this.getLine(row);
1607
var secondLine = this.getLine(row+1);
1609
var range = new Range(row, firstLine.length, row+1, 0);
1610
var line = firstLine + secondLine;
1612
this.$lines.splice(row, 2, line);
1615
action: "removeText",
1617
text: this.getNewLineCharacter()
1619
this._emit("change", { data: delta });
1621
this.replace = function(range, text) {
1622
if (text.length == 0 && range.isEmpty())
1624
if (text == this.getTextRange(range))
1629
var end = this.insert(range.start, text);
1637
this.applyDeltas = function(deltas) {
1638
for (var i=0; i<deltas.length; i++) {
1639
var delta = deltas[i];
1640
var range = Range.fromPoints(delta.range.start, delta.range.end);
1642
if (delta.action == "insertLines")
1643
this.insertLines(range.start.row, delta.lines);
1644
else if (delta.action == "insertText")
1645
this.insert(range.start, delta.text);
1646
else if (delta.action == "removeLines")
1647
this.removeLines(range.start.row, range.end.row - 1);
1648
else if (delta.action == "removeText")
1652
this.revertDeltas = function(deltas) {
1653
for (var i=deltas.length-1; i>=0; i--) {
1654
var delta = deltas[i];
1656
var range = Range.fromPoints(delta.range.start, delta.range.end);
1658
if (delta.action == "insertLines")
1659
this.removeLines(range.start.row, range.end.row - 1);
1660
else if (delta.action == "insertText")
1662
else if (delta.action == "removeLines")
1663
this.insertLines(range.start.row, delta.lines);
1664
else if (delta.action == "removeText")
1665
this.insert(range.start, delta.text);
1668
this.indexToPosition = function(index, startRow) {
1669
var lines = this.$lines || this.getAllLines();
1670
var newlineLength = this.getNewLineCharacter().length;
1671
for (var i = startRow || 0, l = lines.length; i < l; i++) {
1672
index -= lines[i].length + newlineLength;
1674
return {row: i, column: index + lines[i].length + newlineLength};
1676
return {row: l-1, column: lines[l-1].length};
1678
this.positionToIndex = function(pos, startRow) {
1679
var lines = this.$lines || this.getAllLines();
1680
var newlineLength = this.getNewLineCharacter().length;
1682
var row = Math.min(pos.row, lines.length);
1683
for (var i = startRow || 0; i < row; ++i)
1684
index += lines[i].length;
1686
return index + newlineLength * i + pos.column;
1689
}).call(Document.prototype);
1691
exports.Document = Document;
1694
define('ace/range', ['require', 'exports', 'module' ], function(require, exports, module) {
1696
var comparePoints = function(p1, p2) {
1697
return p1.row - p2.row || p1.column - p2.column;
1699
var Range = function(startRow, startColumn, endRow, endColumn) {
1712
this.isEqual = function(range) {
1713
return this.start.row === range.start.row &&
1714
this.end.row === range.end.row &&
1715
this.start.column === range.start.column &&
1716
this.end.column === range.end.column;
1718
this.toString = function() {
1719
return ("Range: [" + this.start.row + "/" + this.start.column +
1720
"] -> [" + this.end.row + "/" + this.end.column + "]");
1723
this.contains = function(row, column) {
1724
return this.compare(row, column) == 0;
1726
this.compareRange = function(range) {
1729
start = range.start;
1731
cmp = this.compare(end.row, end.column);
1733
cmp = this.compare(start.row, start.column);
1736
} else if (cmp == 0) {
1741
} else if (cmp == -1) {
1744
cmp = this.compare(start.row, start.column);
1747
} else if (cmp == 1) {
1754
this.comparePoint = function(p) {
1755
return this.compare(p.row, p.column);
1757
this.containsRange = function(range) {
1758
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
1760
this.intersects = function(range) {
1761
var cmp = this.compareRange(range);
1762
return (cmp == -1 || cmp == 0 || cmp == 1);
1764
this.isEnd = function(row, column) {
1765
return this.end.row == row && this.end.column == column;
1767
this.isStart = function(row, column) {
1768
return this.start.row == row && this.start.column == column;
1770
this.setStart = function(row, column) {
1771
if (typeof row == "object") {
1772
this.start.column = row.column;
1773
this.start.row = row.row;
1775
this.start.row = row;
1776
this.start.column = column;
1779
this.setEnd = function(row, column) {
1780
if (typeof row == "object") {
1781
this.end.column = row.column;
1782
this.end.row = row.row;
1785
this.end.column = column;
1788
this.inside = function(row, column) {
1789
if (this.compare(row, column) == 0) {
1790
if (this.isEnd(row, column) || this.isStart(row, column)) {
1798
this.insideStart = function(row, column) {
1799
if (this.compare(row, column) == 0) {
1800
if (this.isEnd(row, column)) {
1808
this.insideEnd = function(row, column) {
1809
if (this.compare(row, column) == 0) {
1810
if (this.isStart(row, column)) {
1818
this.compare = function(row, column) {
1819
if (!this.isMultiLine()) {
1820
if (row === this.start.row) {
1821
return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
1825
if (row < this.start.row)
1828
if (row > this.end.row)
1831
if (this.start.row === row)
1832
return column >= this.start.column ? 0 : -1;
1834
if (this.end.row === row)
1835
return column <= this.end.column ? 0 : 1;
1839
this.compareStart = function(row, column) {
1840
if (this.start.row == row && this.start.column == column) {
1843
return this.compare(row, column);
1846
this.compareEnd = function(row, column) {
1847
if (this.end.row == row && this.end.column == column) {
1850
return this.compare(row, column);
1853
this.compareInside = function(row, column) {
1854
if (this.end.row == row && this.end.column == column) {
1856
} else if (this.start.row == row && this.start.column == column) {
1859
return this.compare(row, column);
1862
this.clipRows = function(firstRow, lastRow) {
1863
if (this.end.row > lastRow)
1864
var end = {row: lastRow + 1, column: 0};
1865
else if (this.end.row < firstRow)
1866
var end = {row: firstRow, column: 0};
1868
if (this.start.row > lastRow)
1869
var start = {row: lastRow + 1, column: 0};
1870
else if (this.start.row < firstRow)
1871
var start = {row: firstRow, column: 0};
1873
return Range.fromPoints(start || this.start, end || this.end);
1875
this.extend = function(row, column) {
1876
var cmp = this.compare(row, column);
1881
var start = {row: row, column: column};
1883
var end = {row: row, column: column};
1885
return Range.fromPoints(start || this.start, end || this.end);
1888
this.isEmpty = function() {
1889
return (this.start.row === this.end.row && this.start.column === this.end.column);
1891
this.isMultiLine = function() {
1892
return (this.start.row !== this.end.row);
1894
this.clone = function() {
1895
return Range.fromPoints(this.start, this.end);
1897
this.collapseRows = function() {
1898
if (this.end.column == 0)
1899
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
1901
return new Range(this.start.row, 0, this.end.row, 0)
1903
this.toScreenRange = function(session) {
1904
var screenPosStart = session.documentToScreenPosition(this.start);
1905
var screenPosEnd = session.documentToScreenPosition(this.end);
1908
screenPosStart.row, screenPosStart.column,
1909
screenPosEnd.row, screenPosEnd.column
1912
this.moveBy = function(row, column) {
1913
this.start.row += row;
1914
this.start.column += column;
1915
this.end.row += row;
1916
this.end.column += column;
1919
}).call(Range.prototype);
1920
Range.fromPoints = function(start, end) {
1921
return new Range(start.row, start.column, end.row, end.column);
1923
Range.comparePoints = comparePoints;
1925
exports.Range = Range;
1928
define('ace/anchor', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/event_emitter'], function(require, exports, module) {
1931
var oop = require("./lib/oop");
1932
var EventEmitter = require("./lib/event_emitter").EventEmitter;
1934
var Anchor = exports.Anchor = function(doc, row, column) {
1935
this.document = doc;
1937
if (typeof column == "undefined")
1938
this.setPosition(row.row, row.column);
1940
this.setPosition(row, column);
1942
this.$onChange = this.onChange.bind(this);
1943
doc.on("change", this.$onChange);
1948
oop.implement(this, EventEmitter);
1950
this.getPosition = function() {
1951
return this.$clipPositionToDocument(this.row, this.column);
1954
this.getDocument = function() {
1955
return this.document;
1958
this.onChange = function(e) {
1960
var range = delta.range;
1962
if (range.start.row == range.end.row && range.start.row != this.row)
1965
if (range.start.row > this.row)
1968
if (range.start.row == this.row && range.start.column > this.column)
1972
var column = this.column;
1974
if (delta.action === "insertText") {
1975
if (range.start.row === row && range.start.column <= column) {
1976
if (range.start.row === range.end.row) {
1977
column += range.end.column - range.start.column;
1980
column -= range.start.column;
1981
row += range.end.row - range.start.row;
1984
else if (range.start.row !== range.end.row && range.start.row < row) {
1985
row += range.end.row - range.start.row;
1987
} else if (delta.action === "insertLines") {
1988
if (range.start.row <= row) {
1989
row += range.end.row - range.start.row;
1992
else if (delta.action == "removeText") {
1993
if (range.start.row == row && range.start.column < column) {
1994
if (range.end.column >= column)
1995
column = range.start.column;
1997
column = Math.max(0, column - (range.end.column - range.start.column));
1999
} else if (range.start.row !== range.end.row && range.start.row < row) {
2000
if (range.end.row == row) {
2001
column = Math.max(0, column - range.end.column) + range.start.column;
2003
row -= (range.end.row - range.start.row);
2005
else if (range.end.row == row) {
2006
row -= range.end.row - range.start.row;
2007
column = Math.max(0, column - range.end.column) + range.start.column;
2009
} else if (delta.action == "removeLines") {
2010
if (range.start.row <= row) {
2011
if (range.end.row <= row)
2012
row -= range.end.row - range.start.row;
2014
row = range.start.row;
2020
this.setPosition(row, column, true);
2023
this.setPosition = function(row, column, noClip) {
2032
pos = this.$clipPositionToDocument(row, column);
2035
if (this.row == pos.row && this.column == pos.column)
2044
this.column = pos.column;
2045
this._emit("change", {
2051
this.detach = function() {
2052
this.document.removeEventListener("change", this.$onChange);
2054
this.$clipPositionToDocument = function(row, column) {
2057
if (row >= this.document.getLength()) {
2058
pos.row = Math.max(0, this.document.getLength() - 1);
2059
pos.column = this.document.getLine(pos.row).length;
2067
pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
2076
}).call(Anchor.prototype);
2079
define('ace/mode/css/csslint', ['require', 'exports', 'module' ], function(require, exports, module) {
2082
function EventTarget(){
2083
this._listeners = {};
2086
EventTarget.prototype = {
2087
constructor: EventTarget,
2088
addListener: function(type, listener){
2089
if (!this._listeners[type]){
2090
this._listeners[type] = [];
2093
this._listeners[type].push(listener);
2095
fire: function(event){
2096
if (typeof event == "string"){
2097
event = { type: event };
2099
if (typeof event.target != "undefined"){
2100
event.target = this;
2103
if (typeof event.type == "undefined"){
2104
throw new Error("Event object missing 'type' property.");
2107
if (this._listeners[event.type]){
2108
var listeners = this._listeners[event.type].concat();
2109
for (var i=0, len=listeners.length; i < len; i++){
2110
listeners[i].call(this, event);
2114
removeListener: function(type, listener){
2115
if (this._listeners[type]){
2116
var listeners = this._listeners[type];
2117
for (var i=0, len=listeners.length; i < len; i++){
2118
if (listeners[i] === listener){
2119
listeners.splice(i, 1);
2128
function StringReader(text){
2129
this._input = text.replace(/\n\r?/g, "\n");
2135
StringReader.prototype = {
2136
constructor: StringReader,
2140
getLine: function(){
2144
return (this._cursor == this._input.length);
2146
peek: function(count){
2148
count = (typeof count == "undefined" ? 1 : count);
2149
if (this._cursor < this._input.length){
2150
c = this._input.charAt(this._cursor + count - 1);
2157
if (this._cursor < this._input.length){
2158
if (this._input.charAt(this._cursor) == "\n"){
2164
c = this._input.charAt(this._cursor++);
2171
cursor: this._cursor,
2178
if (this._bookmark){
2179
this._cursor = this._bookmark.cursor;
2180
this._line = this._bookmark.line;
2181
this._col = this._bookmark.col;
2182
delete this._bookmark;
2185
readTo: function(pattern){
2189
while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){
2194
throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + ".");
2201
readWhile: function(filter){
2206
while(c !== null && filter(c)){
2214
readMatch: function(matcher){
2216
var source = this._input.substring(this._cursor),
2218
if (typeof matcher == "string"){
2219
if (source.indexOf(matcher) === 0){
2220
value = this.readCount(matcher.length);
2222
} else if (matcher instanceof RegExp){
2223
if (matcher.test(source)){
2224
value = this.readCount(RegExp.lastMatch.length);
2230
readCount: function(count){
2234
buffer += this.read();
2241
function SyntaxError(message, line, col){
2244
this.message = message;
2247
SyntaxError.prototype = new Error();
2248
function SyntaxUnit(text, line, col, type){
2254
SyntaxUnit.fromToken = function(token){
2255
return new SyntaxUnit(token.value, token.startLine, token.startCol);
2258
SyntaxUnit.prototype = {
2259
constructor: SyntaxUnit,
2260
valueOf: function(){
2261
return this.toString();
2263
toString: function(){
2268
function TokenStreamBase(input, tokenData){
2269
this._reader = input ? new StringReader(input.toString()) : null;
2271
this._tokenData = tokenData;
2275
this._ltIndexCache = [];
2277
TokenStreamBase.createTokenData = function(tokens){
2281
tokenData = tokens.concat([]),
2283
len = tokenData.length+1;
2285
tokenData.UNKNOWN = -1;
2286
tokenData.unshift({name:"EOF"});
2288
for (; i < len; i++){
2289
nameMap.push(tokenData[i].name);
2290
tokenData[tokenData[i].name] = i;
2291
if (tokenData[i].text){
2292
typeMap[tokenData[i].text] = i;
2296
tokenData.name = function(tt){
2300
tokenData.type = function(c){
2307
TokenStreamBase.prototype = {
2308
constructor: TokenStreamBase,
2309
match: function(tokenTypes, channel){
2310
if (!(tokenTypes instanceof Array)){
2311
tokenTypes = [tokenTypes];
2314
var tt = this.get(channel),
2316
len = tokenTypes.length;
2319
if (tt == tokenTypes[i++]){
2326
mustMatch: function(tokenTypes, channel){
2329
if (!(tokenTypes instanceof Array)){
2330
tokenTypes = [tokenTypes];
2333
if (!this.match.apply(this, arguments)){
2335
throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
2336
" at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
2339
advance: function(tokenTypes, channel){
2341
while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){
2347
get: function(channel){
2349
var tokenInfo = this._tokenData,
2350
reader = this._reader,
2353
len = tokenInfo.length,
2357
if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){
2360
this._token = this._lt[this._ltIndex++];
2361
info = tokenInfo[this._token.type];
2362
while((info.channel !== undefined && channel !== info.channel) &&
2363
this._ltIndex < this._lt.length){
2364
this._token = this._lt[this._ltIndex++];
2365
info = tokenInfo[this._token.type];
2368
if ((info.channel === undefined || channel === info.channel) &&
2369
this._ltIndex <= this._lt.length){
2370
this._ltIndexCache.push(i);
2371
return this._token.type;
2374
token = this._getToken();
2375
if (token.type > -1 && !tokenInfo[token.type].hide){
2376
token.channel = tokenInfo[token.type].channel;
2377
this._token = token;
2378
this._lt.push(token);
2379
this._ltIndexCache.push(this._lt.length - this._ltIndex + i);
2380
if (this._lt.length > 5){
2383
if (this._ltIndexCache.length > 5){
2384
this._ltIndexCache.shift();
2386
this._ltIndex = this._lt.length;
2388
info = tokenInfo[token.type];
2391
(info.channel !== undefined && channel !== info.channel))){
2392
return this.get(channel);
2397
LA: function(index){
2402
throw new Error("Too much lookahead.");
2408
while(total < index){
2412
} else if (index < 0){
2414
if(this._lt[this._ltIndex+index]){
2415
tt = this._lt[this._ltIndex+index].type;
2417
throw new Error("Too much lookbehind.");
2421
tt = this._token.type;
2427
LT: function(index){
2429
return this._lt[this._ltIndex+index-1];
2437
tokenName: function(tokenType){
2438
if (tokenType < 0 || tokenType > this._tokenData.length){
2439
return "UNKNOWN_TOKEN";
2441
return this._tokenData[tokenType].name;
2444
tokenType: function(tokenName){
2445
return this._tokenData[tokenName] || -1;
2448
if (this._ltIndexCache.length){
2449
this._ltIndex -= this._ltIndexCache.pop();//--;
2450
this._token = this._lt[this._ltIndex - 1];
2452
throw new Error("Too much lookahead.");
2462
StringReader: StringReader,
2463
SyntaxError : SyntaxError,
2464
SyntaxUnit : SyntaxUnit,
2465
EventTarget : EventTarget,
2466
TokenStreamBase : TokenStreamBase
2470
var EventTarget = parserlib.util.EventTarget,
2471
TokenStreamBase = parserlib.util.TokenStreamBase,
2472
StringReader = parserlib.util.StringReader,
2473
SyntaxError = parserlib.util.SyntaxError,
2474
SyntaxUnit = parserlib.util.SyntaxUnit;
2478
aliceblue :"#f0f8ff",
2479
antiquewhite :"#faebd7",
2481
aquamarine :"#7fffd4",
2486
blanchedalmond :"#ffebcd",
2488
blueviolet :"#8a2be2",
2490
burlywood :"#deb887",
2491
cadetblue :"#5f9ea0",
2492
chartreuse :"#7fff00",
2493
chocolate :"#d2691e",
2495
cornflowerblue :"#6495ed",
2496
cornsilk :"#fff8dc",
2499
darkblue :"#00008b",
2500
darkcyan :"#008b8b",
2501
darkgoldenrod :"#b8860b",
2502
darkgray :"#a9a9a9",
2503
darkgreen :"#006400",
2504
darkkhaki :"#bdb76b",
2505
darkmagenta :"#8b008b",
2506
darkolivegreen :"#556b2f",
2507
darkorange :"#ff8c00",
2508
darkorchid :"#9932cc",
2510
darksalmon :"#e9967a",
2511
darkseagreen :"#8fbc8f",
2512
darkslateblue :"#483d8b",
2513
darkslategray :"#2f4f4f",
2514
darkturquoise :"#00ced1",
2515
darkviolet :"#9400d3",
2516
deeppink :"#ff1493",
2517
deepskyblue :"#00bfff",
2519
dodgerblue :"#1e90ff",
2520
firebrick :"#b22222",
2521
floralwhite :"#fffaf0",
2522
forestgreen :"#228b22",
2524
gainsboro :"#dcdcdc",
2525
ghostwhite :"#f8f8ff",
2527
goldenrod :"#daa520",
2530
greenyellow :"#adff2f",
2531
honeydew :"#f0fff0",
2533
indianred :"#cd5c5c",
2537
lavender :"#e6e6fa",
2538
lavenderblush :"#fff0f5",
2539
lawngreen :"#7cfc00",
2540
lemonchiffon :"#fffacd",
2541
lightblue :"#add8e6",
2542
lightcoral :"#f08080",
2543
lightcyan :"#e0ffff",
2544
lightgoldenrodyellow :"#fafad2",
2545
lightgray :"#d3d3d3",
2546
lightgreen :"#90ee90",
2547
lightpink :"#ffb6c1",
2548
lightsalmon :"#ffa07a",
2549
lightseagreen :"#20b2aa",
2550
lightskyblue :"#87cefa",
2551
lightslategray :"#778899",
2552
lightsteelblue :"#b0c4de",
2553
lightyellow :"#ffffe0",
2555
limegreen :"#32cd32",
2559
mediumaquamarine:"#66cdaa",
2560
mediumblue :"#0000cd",
2561
mediumorchid :"#ba55d3",
2562
mediumpurple :"#9370d8",
2563
mediumseagreen :"#3cb371",
2564
mediumslateblue :"#7b68ee",
2565
mediumspringgreen :"#00fa9a",
2566
mediumturquoise :"#48d1cc",
2567
mediumvioletred :"#c71585",
2568
midnightblue :"#191970",
2569
mintcream :"#f5fffa",
2570
mistyrose :"#ffe4e1",
2571
moccasin :"#ffe4b5",
2572
navajowhite :"#ffdead",
2576
olivedrab :"#6b8e23",
2578
orangered :"#ff4500",
2580
palegoldenrod :"#eee8aa",
2581
palegreen :"#98fb98",
2582
paleturquoise :"#afeeee",
2583
palevioletred :"#d87093",
2584
papayawhip :"#ffefd5",
2585
peachpuff :"#ffdab9",
2589
powderblue :"#b0e0e6",
2592
rosybrown :"#bc8f8f",
2593
royalblue :"#4169e1",
2594
saddlebrown :"#8b4513",
2596
sandybrown :"#f4a460",
2597
seagreen :"#2e8b57",
2598
seashell :"#fff5ee",
2602
slateblue :"#6a5acd",
2603
slategray :"#708090",
2605
springgreen :"#00ff7f",
2606
steelblue :"#4682b4",
2611
turquoise :"#40e0d0",
2615
whitesmoke :"#f5f5f5",
2617
yellowgreen :"#9acd32"
2619
function Combinator(text, line, col){
2621
SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);
2622
this.type = "unknown";
2623
if (/^\s+$/.test(text)){
2624
this.type = "descendant";
2625
} else if (text == ">"){
2626
this.type = "child";
2627
} else if (text == "+"){
2628
this.type = "adjacent-sibling";
2629
} else if (text == "~"){
2630
this.type = "sibling";
2635
Combinator.prototype = new SyntaxUnit();
2636
Combinator.prototype.constructor = Combinator;
2637
function MediaFeature(name, value){
2639
SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);
2644
MediaFeature.prototype = new SyntaxUnit();
2645
MediaFeature.prototype.constructor = MediaFeature;
2646
function MediaQuery(modifier, mediaType, features, line, col){
2648
SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType + " " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE);
2649
this.modifier = modifier;
2650
this.mediaType = mediaType;
2651
this.features = features;
2655
MediaQuery.prototype = new SyntaxUnit();
2656
MediaQuery.prototype.constructor = MediaQuery;
2657
function Parser(options){
2658
EventTarget.call(this);
2661
this.options = options || {};
2663
this._tokenStream = null;
2665
Parser.DEFAULT_TYPE = 0;
2666
Parser.COMBINATOR_TYPE = 1;
2667
Parser.MEDIA_FEATURE_TYPE = 2;
2668
Parser.MEDIA_QUERY_TYPE = 3;
2669
Parser.PROPERTY_NAME_TYPE = 4;
2670
Parser.PROPERTY_VALUE_TYPE = 5;
2671
Parser.PROPERTY_VALUE_PART_TYPE = 6;
2672
Parser.SELECTOR_TYPE = 7;
2673
Parser.SELECTOR_PART_TYPE = 8;
2674
Parser.SELECTOR_SUB_PART_TYPE = 9;
2676
Parser.prototype = function(){
2678
var proto = new EventTarget(), //new prototype
2681
constructor: Parser,
2683
COMBINATOR_TYPE : 1,
2684
MEDIA_FEATURE_TYPE : 2,
2685
MEDIA_QUERY_TYPE : 3,
2686
PROPERTY_NAME_TYPE : 4,
2687
PROPERTY_VALUE_TYPE : 5,
2688
PROPERTY_VALUE_PART_TYPE : 6,
2690
SELECTOR_PART_TYPE : 8,
2691
SELECTOR_SUB_PART_TYPE : 9,
2693
_stylesheet: function(){
2695
var tokenStream = this._tokenStream,
2701
this.fire("startstylesheet");
2705
while (tokenStream.peek() == Tokens.IMPORT_SYM){
2709
while (tokenStream.peek() == Tokens.NAMESPACE_SYM){
2713
tt = tokenStream.peek();
2714
while(tt > Tokens.EOF){
2719
case Tokens.MEDIA_SYM:
2723
case Tokens.PAGE_SYM:
2727
case Tokens.FONT_FACE_SYM:
2731
case Tokens.KEYFRAMES_SYM:
2735
case Tokens.UNKNOWN_SYM: //unknown @ rule
2737
if (!this.options.strict){
2741
message: "Unknown @ rule: " + tokenStream.LT(0).value + ".",
2742
line: tokenStream.LT(0).startLine,
2743
col: tokenStream.LT(0).startCol
2746
while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){
2747
count++; //keep track of nesting depth
2751
tokenStream.advance([Tokens.RBRACE]);
2756
throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);
2760
this._readWhitespace();
2763
if(!this._ruleset()){
2765
case Tokens.CHARSET_SYM:
2766
token = tokenStream.LT(1);
2767
this._charset(false);
2768
throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol);
2769
case Tokens.IMPORT_SYM:
2770
token = tokenStream.LT(1);
2771
this._import(false);
2772
throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol);
2773
case Tokens.NAMESPACE_SYM:
2774
token = tokenStream.LT(1);
2775
this._namespace(false);
2776
throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol);
2778
tokenStream.get(); //get the last token
2779
this._unexpectedToken(tokenStream.token());
2785
if (ex instanceof SyntaxError && !this.options.strict){
2789
message: ex.message,
2798
tt = tokenStream.peek();
2801
if (tt != Tokens.EOF){
2802
this._unexpectedToken(tokenStream.token());
2805
this.fire("endstylesheet");
2808
_charset: function(emit){
2809
var tokenStream = this._tokenStream,
2815
if (tokenStream.match(Tokens.CHARSET_SYM)){
2816
line = tokenStream.token().startLine;
2817
col = tokenStream.token().startCol;
2819
this._readWhitespace();
2820
tokenStream.mustMatch(Tokens.STRING);
2822
token = tokenStream.token();
2823
charset = token.value;
2825
this._readWhitespace();
2826
tokenStream.mustMatch(Tokens.SEMICOLON);
2828
if (emit !== false){
2839
_import: function(emit){
2841
var tokenStream = this._tokenStream,
2846
tokenStream.mustMatch(Tokens.IMPORT_SYM);
2847
importToken = tokenStream.token();
2848
this._readWhitespace();
2850
tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
2851
uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
2853
this._readWhitespace();
2855
mediaList = this._media_query_list();
2856
tokenStream.mustMatch(Tokens.SEMICOLON);
2857
this._readWhitespace();
2859
if (emit !== false){
2864
line: importToken.startLine,
2865
col: importToken.startCol
2871
_namespace: function(emit){
2873
var tokenStream = this._tokenStream,
2878
tokenStream.mustMatch(Tokens.NAMESPACE_SYM);
2879
line = tokenStream.token().startLine;
2880
col = tokenStream.token().startCol;
2881
this._readWhitespace();
2882
if (tokenStream.match(Tokens.IDENT)){
2883
prefix = tokenStream.token().value;
2884
this._readWhitespace();
2887
tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);
2888
uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1");
2890
this._readWhitespace();
2891
tokenStream.mustMatch(Tokens.SEMICOLON);
2892
this._readWhitespace();
2894
if (emit !== false){
2907
var tokenStream = this._tokenStream,
2911
tokenStream.mustMatch(Tokens.MEDIA_SYM);
2912
line = tokenStream.token().startLine;
2913
col = tokenStream.token().startCol;
2915
this._readWhitespace();
2917
mediaList = this._media_query_list();
2919
tokenStream.mustMatch(Tokens.LBRACE);
2920
this._readWhitespace();
2930
if (tokenStream.peek() == Tokens.PAGE_SYM){
2932
} else if (!this._ruleset()){
2937
tokenStream.mustMatch(Tokens.RBRACE);
2938
this._readWhitespace();
2947
_media_query_list: function(){
2948
var tokenStream = this._tokenStream,
2952
this._readWhitespace();
2954
if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){
2955
mediaList.push(this._media_query());
2958
while(tokenStream.match(Tokens.COMMA)){
2959
this._readWhitespace();
2960
mediaList.push(this._media_query());
2965
_media_query: function(){
2966
var tokenStream = this._tokenStream,
2972
if (tokenStream.match(Tokens.IDENT)){
2973
ident = tokenStream.token().value.toLowerCase();
2974
if (ident != "only" && ident != "not"){
2975
tokenStream.unget();
2978
token = tokenStream.token();
2982
this._readWhitespace();
2984
if (tokenStream.peek() == Tokens.IDENT){
2985
type = this._media_type();
2986
if (token === null){
2987
token = tokenStream.token();
2989
} else if (tokenStream.peek() == Tokens.LPAREN){
2990
if (token === null){
2991
token = tokenStream.LT(1);
2993
expressions.push(this._media_expression());
2996
if (type === null && expressions.length === 0){
2999
this._readWhitespace();
3000
while (tokenStream.match(Tokens.IDENT)){
3001
if (tokenStream.token().value.toLowerCase() != "and"){
3002
this._unexpectedToken(tokenStream.token());
3005
this._readWhitespace();
3006
expressions.push(this._media_expression());
3010
return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);
3012
_media_type: function(){
3013
return this._media_feature();
3015
_media_expression: function(){
3016
var tokenStream = this._tokenStream,
3021
tokenStream.mustMatch(Tokens.LPAREN);
3023
feature = this._media_feature();
3024
this._readWhitespace();
3026
if (tokenStream.match(Tokens.COLON)){
3027
this._readWhitespace();
3028
token = tokenStream.LT(1);
3029
expression = this._expression();
3032
tokenStream.mustMatch(Tokens.RPAREN);
3033
this._readWhitespace();
3035
return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));
3037
_media_feature: function(){
3038
var tokenStream = this._tokenStream;
3040
tokenStream.mustMatch(Tokens.IDENT);
3042
return SyntaxUnit.fromToken(tokenStream.token());
3045
var tokenStream = this._tokenStream,
3050
tokenStream.mustMatch(Tokens.PAGE_SYM);
3051
line = tokenStream.token().startLine;
3052
col = tokenStream.token().startCol;
3054
this._readWhitespace();
3056
if (tokenStream.match(Tokens.IDENT)){
3057
identifier = tokenStream.token().value;
3058
if (identifier.toLowerCase() === "auto"){
3059
this._unexpectedToken(tokenStream.token());
3062
if (tokenStream.peek() == Tokens.COLON){
3063
pseudoPage = this._pseudo_page();
3066
this._readWhitespace();
3076
this._readDeclarations(true, true);
3087
_margin: function(){
3088
var tokenStream = this._tokenStream,
3091
marginSym = this._margin_sym();
3094
line = tokenStream.token().startLine;
3095
col = tokenStream.token().startCol;
3098
type: "startpagemargin",
3104
this._readDeclarations(true);
3107
type: "endpagemargin",
3117
_margin_sym: function(){
3119
var tokenStream = this._tokenStream;
3121
if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
3122
Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
3123
Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
3124
Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
3125
Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
3126
Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
3127
Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))
3129
return SyntaxUnit.fromToken(tokenStream.token());
3136
_pseudo_page: function(){
3138
var tokenStream = this._tokenStream;
3140
tokenStream.mustMatch(Tokens.COLON);
3141
tokenStream.mustMatch(Tokens.IDENT);
3143
return tokenStream.token().value;
3146
_font_face: function(){
3147
var tokenStream = this._tokenStream,
3150
tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
3151
line = tokenStream.token().startLine;
3152
col = tokenStream.token().startCol;
3154
this._readWhitespace();
3157
type: "startfontface",
3162
this._readDeclarations(true);
3165
type: "endfontface",
3171
_operator: function(){
3173
var tokenStream = this._tokenStream,
3176
if (tokenStream.match([Tokens.SLASH, Tokens.COMMA])){
3177
token = tokenStream.token();
3178
this._readWhitespace();
3180
return token ? PropertyValuePart.fromToken(token) : null;
3184
_combinator: function(){
3186
var tokenStream = this._tokenStream,
3190
if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){
3191
token = tokenStream.token();
3192
value = new Combinator(token.value, token.startLine, token.startCol);
3193
this._readWhitespace();
3199
_unary_operator: function(){
3201
var tokenStream = this._tokenStream;
3203
if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){
3204
return tokenStream.token().value;
3210
_property: function(){
3212
var tokenStream = this._tokenStream,
3219
if (tokenStream.peek() == Tokens.STAR && this.options.starHack){
3221
token = tokenStream.token();
3223
line = token.startLine;
3224
col = token.startCol;
3227
if(tokenStream.match(Tokens.IDENT)){
3228
token = tokenStream.token();
3229
tokenValue = token.value;
3230
if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){
3232
tokenValue = tokenValue.substring(1);
3235
value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
3236
this._readWhitespace();
3241
_ruleset: function(){
3243
var tokenStream = this._tokenStream,
3247
selectors = this._selectors_group();
3249
if (ex instanceof SyntaxError && !this.options.strict){
3253
message: ex.message,
3257
tt = tokenStream.advance([Tokens.RBRACE]);
3258
if (tt == Tokens.RBRACE){
3272
selectors: selectors,
3273
line: selectors[0].line,
3274
col: selectors[0].col
3277
this._readDeclarations(true);
3281
selectors: selectors,
3282
line: selectors[0].line,
3283
col: selectors[0].col
3291
_selectors_group: function(){
3292
var tokenStream = this._tokenStream,
3296
selector = this._selector();
3297
if (selector !== null){
3299
selectors.push(selector);
3300
while(tokenStream.match(Tokens.COMMA)){
3301
this._readWhitespace();
3302
selector = this._selector();
3303
if (selector !== null){
3304
selectors.push(selector);
3306
this._unexpectedToken(tokenStream.LT(1));
3311
return selectors.length ? selectors : null;
3313
_selector: function(){
3315
var tokenStream = this._tokenStream,
3317
nextSelector = null,
3320
nextSelector = this._simple_selector_sequence();
3321
if (nextSelector === null){
3325
selector.push(nextSelector);
3328
combinator = this._combinator();
3330
if (combinator !== null){
3331
selector.push(combinator);
3332
nextSelector = this._simple_selector_sequence();
3333
if (nextSelector === null){
3334
this._unexpectedToken(tokenStream.LT(1));
3336
selector.push(nextSelector);
3339
if (this._readWhitespace()){
3340
ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);
3341
combinator = this._combinator();
3342
nextSelector = this._simple_selector_sequence();
3343
if (nextSelector === null){
3344
if (combinator !== null){
3345
this._unexpectedToken(tokenStream.LT(1));
3349
if (combinator !== null){
3350
selector.push(combinator);
3355
selector.push(nextSelector);
3364
return new Selector(selector, selector[0].line, selector[0].col);
3366
_simple_selector_sequence: function(){
3368
var tokenStream = this._tokenStream,
3374
return tokenStream.match(Tokens.HASH) ?
3375
new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
3384
len = components.length,
3389
line = tokenStream.LT(1).startLine;
3390
col = tokenStream.LT(1).startCol;
3392
elementName = this._type_selector();
3394
elementName = this._universal();
3397
if (elementName !== null){
3398
selectorText += elementName;
3402
if (tokenStream.peek() === Tokens.S){
3405
while(i < len && component === null){
3406
component = components[i++].call(this);
3409
if (component === null){
3410
if (selectorText === ""){
3417
modifiers.push(component);
3418
selectorText += component.toString();
3424
return selectorText !== "" ?
3425
new SelectorPart(elementName, modifiers, selectorText, line, col) :
3428
_type_selector: function(){
3430
var tokenStream = this._tokenStream,
3431
ns = this._namespace_prefix(),
3432
elementName = this._element_name();
3436
tokenStream.unget();
3438
tokenStream.unget();
3445
elementName.text = ns + elementName.text;
3446
elementName.col -= ns.length;
3453
var tokenStream = this._tokenStream,
3456
if (tokenStream.match(Tokens.DOT)){
3457
tokenStream.mustMatch(Tokens.IDENT);
3458
token = tokenStream.token();
3459
return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1);
3465
_element_name: function(){
3467
var tokenStream = this._tokenStream,
3470
if (tokenStream.match(Tokens.IDENT)){
3471
token = tokenStream.token();
3472
return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol);
3478
_namespace_prefix: function(){
3479
var tokenStream = this._tokenStream,
3481
if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){
3483
if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){
3484
value += tokenStream.token().value;
3487
tokenStream.mustMatch(Tokens.PIPE);
3492
return value.length ? value : null;
3494
_universal: function(){
3495
var tokenStream = this._tokenStream,
3499
ns = this._namespace_prefix();
3504
if(tokenStream.match(Tokens.STAR)){
3508
return value.length ? value : null;
3511
_attrib: function(){
3513
var tokenStream = this._tokenStream,
3518
if (tokenStream.match(Tokens.LBRACKET)){
3519
token = tokenStream.token();
3520
value = token.value;
3521
value += this._readWhitespace();
3523
ns = this._namespace_prefix();
3529
tokenStream.mustMatch(Tokens.IDENT);
3530
value += tokenStream.token().value;
3531
value += this._readWhitespace();
3533
if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,
3534
Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){
3536
value += tokenStream.token().value;
3537
value += this._readWhitespace();
3539
tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
3540
value += tokenStream.token().value;
3541
value += this._readWhitespace();
3544
tokenStream.mustMatch(Tokens.RBRACKET);
3546
return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol);
3551
_pseudo: function(){
3553
var tokenStream = this._tokenStream,
3559
if (tokenStream.match(Tokens.COLON)){
3561
if (tokenStream.match(Tokens.COLON)){
3565
if (tokenStream.match(Tokens.IDENT)){
3566
pseudo = tokenStream.token().value;
3567
line = tokenStream.token().startLine;
3568
col = tokenStream.token().startCol - colons.length;
3569
} else if (tokenStream.peek() == Tokens.FUNCTION){
3570
line = tokenStream.LT(1).startLine;
3571
col = tokenStream.LT(1).startCol - colons.length;
3572
pseudo = this._functional_pseudo();
3576
pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col);
3582
_functional_pseudo: function(){
3584
var tokenStream = this._tokenStream,
3587
if(tokenStream.match(Tokens.FUNCTION)){
3588
value = tokenStream.token().value;
3589
value += this._readWhitespace();
3590
value += this._expression();
3591
tokenStream.mustMatch(Tokens.RPAREN);
3597
_expression: function(){
3599
var tokenStream = this._tokenStream,
3602
while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,
3603
Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,
3604
Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,
3605
Tokens.RESOLUTION])){
3607
value += tokenStream.token().value;
3608
value += this._readWhitespace();
3611
return value.length ? value : null;
3614
_negation: function(){
3616
var tokenStream = this._tokenStream,
3623
if (tokenStream.match(Tokens.NOT)){
3624
value = tokenStream.token().value;
3625
line = tokenStream.token().startLine;
3626
col = tokenStream.token().startCol;
3627
value += this._readWhitespace();
3628
arg = this._negation_arg();
3630
value += this._readWhitespace();
3631
tokenStream.match(Tokens.RPAREN);
3632
value += tokenStream.token().value;
3634
subpart = new SelectorSubPart(value, "not", line, col);
3635
subpart.args.push(arg);
3640
_negation_arg: function(){
3642
var tokenStream = this._tokenStream,
3644
this._type_selector,
3647
return tokenStream.match(Tokens.HASH) ?
3648
new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) :
3663
line = tokenStream.LT(1).startLine;
3664
col = tokenStream.LT(1).startCol;
3666
while(i < len && arg === null){
3668
arg = args[i].call(this);
3672
this._unexpectedToken(tokenStream.LT(1));
3674
if (arg.type == "elementName"){
3675
part = new SelectorPart(arg, [], arg.toString(), line, col);
3677
part = new SelectorPart(null, [arg], arg.toString(), line, col);
3683
_declaration: function(){
3685
var tokenStream = this._tokenStream,
3693
property = this._property();
3694
if (property !== null){
3696
tokenStream.mustMatch(Tokens.COLON);
3697
this._readWhitespace();
3699
expr = this._expr();
3700
if (!expr || expr.length === 0){
3701
this._unexpectedToken(tokenStream.LT(1));
3704
prio = this._prio();
3705
propertyName = property.toString();
3706
if (this.options.starHack && property.hack == "*" ||
3707
this.options.underscoreHack && property.hack == "_") {
3709
propertyName = property.text;
3713
this._validateProperty(propertyName, expr);
3723
line: property.line,
3736
var tokenStream = this._tokenStream,
3737
result = tokenStream.match(Tokens.IMPORTANT_SYM);
3739
this._readWhitespace();
3745
var tokenStream = this._tokenStream,
3750
value = this._term();
3751
if (value !== null){
3756
operator = this._operator();
3758
values.push(operator);
3760
values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));
3764
value = this._term();
3766
if (value === null){
3774
return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;
3779
var tokenStream = this._tokenStream,
3785
unary = this._unary_operator();
3786
if (unary !== null){
3787
line = tokenStream.token().startLine;
3788
col = tokenStream.token().startCol;
3790
if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){
3792
value = this._ie_function();
3793
if (unary === null){
3794
line = tokenStream.token().startLine;
3795
col = tokenStream.token().startCol;
3797
} else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,
3798
Tokens.ANGLE, Tokens.TIME,
3799
Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){
3801
value = tokenStream.token().value;
3802
if (unary === null){
3803
line = tokenStream.token().startLine;
3804
col = tokenStream.token().startCol;
3806
this._readWhitespace();
3808
token = this._hexcolor();
3809
if (token === null){
3810
if (unary === null){
3811
line = tokenStream.LT(1).startLine;
3812
col = tokenStream.LT(1).startCol;
3814
if (value === null){
3815
if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){
3816
value = this._ie_function();
3818
value = this._function();
3823
value = token.value;
3824
if (unary === null){
3825
line = token.startLine;
3826
col = token.startCol;
3832
return value !== null ?
3833
new PropertyValuePart(unary !== null ? unary + value : value, line, col) :
3838
_function: function(){
3840
var tokenStream = this._tokenStream,
3841
functionText = null,
3845
if (tokenStream.match(Tokens.FUNCTION)){
3846
functionText = tokenStream.token().value;
3847
this._readWhitespace();
3848
expr = this._expr();
3849
functionText += expr;
3850
if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){
3853
if (this._readWhitespace()){
3854
functionText += tokenStream.token().value;
3856
if (tokenStream.LA(0) == Tokens.COMMA){
3857
functionText += tokenStream.token().value;
3860
tokenStream.match(Tokens.IDENT);
3861
functionText += tokenStream.token().value;
3863
tokenStream.match(Tokens.EQUALS);
3864
functionText += tokenStream.token().value;
3865
lt = tokenStream.peek();
3866
while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
3868
functionText += tokenStream.token().value;
3869
lt = tokenStream.peek();
3871
} while(tokenStream.match([Tokens.COMMA, Tokens.S]));
3874
tokenStream.match(Tokens.RPAREN);
3875
functionText += ")";
3876
this._readWhitespace();
3879
return functionText;
3882
_ie_function: function(){
3884
var tokenStream = this._tokenStream,
3885
functionText = null,
3888
if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){
3889
functionText = tokenStream.token().value;
3893
if (this._readWhitespace()){
3894
functionText += tokenStream.token().value;
3896
if (tokenStream.LA(0) == Tokens.COMMA){
3897
functionText += tokenStream.token().value;
3900
tokenStream.match(Tokens.IDENT);
3901
functionText += tokenStream.token().value;
3903
tokenStream.match(Tokens.EQUALS);
3904
functionText += tokenStream.token().value;
3905
lt = tokenStream.peek();
3906
while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){
3908
functionText += tokenStream.token().value;
3909
lt = tokenStream.peek();
3911
} while(tokenStream.match([Tokens.COMMA, Tokens.S]));
3913
tokenStream.match(Tokens.RPAREN);
3914
functionText += ")";
3915
this._readWhitespace();
3918
return functionText;
3921
_hexcolor: function(){
3923
var tokenStream = this._tokenStream,
3927
if(tokenStream.match(Tokens.HASH)){
3929
token = tokenStream.token();
3930
color = token.value;
3931
if (!/#[a-f0-9]{3,6}/i.test(color)){
3932
throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
3934
this._readWhitespace();
3940
_keyframes: function(){
3941
var tokenStream = this._tokenStream,
3947
tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);
3948
token = tokenStream.token();
3949
if (/^@\-([^\-]+)\-/.test(token.value)) {
3953
this._readWhitespace();
3954
name = this._keyframe_name();
3956
this._readWhitespace();
3957
tokenStream.mustMatch(Tokens.LBRACE);
3960
type: "startkeyframes",
3963
line: token.startLine,
3967
this._readWhitespace();
3968
tt = tokenStream.peek();
3969
while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {
3970
this._keyframe_rule();
3971
this._readWhitespace();
3972
tt = tokenStream.peek();
3976
type: "endkeyframes",
3979
line: token.startLine,
3983
this._readWhitespace();
3984
tokenStream.mustMatch(Tokens.RBRACE);
3988
_keyframe_name: function(){
3989
var tokenStream = this._tokenStream,
3992
tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);
3993
return SyntaxUnit.fromToken(tokenStream.token());
3996
_keyframe_rule: function(){
3997
var tokenStream = this._tokenStream,
3999
keyList = this._key_list();
4002
type: "startkeyframerule",
4004
line: keyList[0].line,
4008
this._readDeclarations(true);
4011
type: "endkeyframerule",
4013
line: keyList[0].line,
4019
_key_list: function(){
4020
var tokenStream = this._tokenStream,
4024
keyList.push(this._key());
4026
this._readWhitespace();
4028
while(tokenStream.match(Tokens.COMMA)){
4029
this._readWhitespace();
4030
keyList.push(this._key());
4031
this._readWhitespace();
4039
var tokenStream = this._tokenStream,
4042
if (tokenStream.match(Tokens.PERCENTAGE)){
4043
return SyntaxUnit.fromToken(tokenStream.token());
4044
} else if (tokenStream.match(Tokens.IDENT)){
4045
token = tokenStream.token();
4047
if (/from|to/i.test(token.value)){
4048
return SyntaxUnit.fromToken(token);
4051
tokenStream.unget();
4053
this._unexpectedToken(tokenStream.LT(1));
4055
_skipCruft: function(){
4056
while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){
4059
_readDeclarations: function(checkStart, readMargins){
4060
var tokenStream = this._tokenStream,
4064
this._readWhitespace();
4067
tokenStream.mustMatch(Tokens.LBRACE);
4070
this._readWhitespace();
4076
if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){
4077
} else if (this._declaration()){
4078
if (!tokenStream.match(Tokens.SEMICOLON)){
4084
this._readWhitespace();
4087
tokenStream.mustMatch(Tokens.RBRACE);
4088
this._readWhitespace();
4091
if (ex instanceof SyntaxError && !this.options.strict){
4095
message: ex.message,
4099
tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);
4100
if (tt == Tokens.SEMICOLON){
4101
this._readDeclarations(false, readMargins);
4102
} else if (tt != Tokens.RBRACE){
4112
_readWhitespace: function(){
4114
var tokenStream = this._tokenStream,
4117
while(tokenStream.match(Tokens.S)){
4118
ws += tokenStream.token().value;
4123
_unexpectedToken: function(token){
4124
throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
4126
_verifyEnd: function(){
4127
if (this._tokenStream.LA(1) != Tokens.EOF){
4128
this._unexpectedToken(this._tokenStream.LT(1));
4131
_validateProperty: function(property, value){
4132
Validation.validate(property, value);
4135
parse: function(input){
4136
this._tokenStream = new TokenStream(input, Tokens);
4140
parseStyleSheet: function(input){
4141
return this.parse(input);
4144
parseMediaQuery: function(input){
4145
this._tokenStream = new TokenStream(input, Tokens);
4146
var result = this._media_query();
4150
parsePropertyValue: function(input){
4152
this._tokenStream = new TokenStream(input, Tokens);
4153
this._readWhitespace();
4155
var result = this._expr();
4156
this._readWhitespace();
4160
parseRule: function(input){
4161
this._tokenStream = new TokenStream(input, Tokens);
4162
this._readWhitespace();
4164
var result = this._ruleset();
4165
this._readWhitespace();
4169
parseSelector: function(input){
4171
this._tokenStream = new TokenStream(input, Tokens);
4172
this._readWhitespace();
4174
var result = this._selector();
4175
this._readWhitespace();
4179
parseStyleAttribute: function(input){
4180
input += "}"; // for error recovery in _readDeclarations()
4181
this._tokenStream = new TokenStream(input, Tokens);
4182
this._readDeclarations();
4185
for (prop in additions){
4186
if (additions.hasOwnProperty(prop)){
4187
proto[prop] = additions[prop];
4194
"alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>",
4195
"alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
4197
"animation-delay" : { multi: "<time>", comma: true },
4198
"animation-direction" : { multi: "normal | alternate", comma: true },
4199
"animation-duration" : { multi: "<time>", comma: true },
4200
"animation-iteration-count" : { multi: "<number> | infinite", comma: true },
4201
"animation-name" : { multi: "none | <ident>", comma: true },
4202
"animation-play-state" : { multi: "running | paused", comma: true },
4203
"animation-timing-function" : 1,
4204
"-moz-animation-delay" : { multi: "<time>", comma: true },
4205
"-moz-animation-direction" : { multi: "normal | alternate", comma: true },
4206
"-moz-animation-duration" : { multi: "<time>", comma: true },
4207
"-moz-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
4208
"-moz-animation-name" : { multi: "none | <ident>", comma: true },
4209
"-moz-animation-play-state" : { multi: "running | paused", comma: true },
4211
"-ms-animation-delay" : { multi: "<time>", comma: true },
4212
"-ms-animation-direction" : { multi: "normal | alternate", comma: true },
4213
"-ms-animation-duration" : { multi: "<time>", comma: true },
4214
"-ms-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
4215
"-ms-animation-name" : { multi: "none | <ident>", comma: true },
4216
"-ms-animation-play-state" : { multi: "running | paused", comma: true },
4218
"-webkit-animation-delay" : { multi: "<time>", comma: true },
4219
"-webkit-animation-direction" : { multi: "normal | alternate", comma: true },
4220
"-webkit-animation-duration" : { multi: "<time>", comma: true },
4221
"-webkit-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
4222
"-webkit-animation-name" : { multi: "none | <ident>", comma: true },
4223
"-webkit-animation-play-state" : { multi: "running | paused", comma: true },
4225
"-o-animation-delay" : { multi: "<time>", comma: true },
4226
"-o-animation-direction" : { multi: "normal | alternate", comma: true },
4227
"-o-animation-duration" : { multi: "<time>", comma: true },
4228
"-o-animation-iteration-count" : { multi: "<number> | infinite", comma: true },
4229
"-o-animation-name" : { multi: "none | <ident>", comma: true },
4230
"-o-animation-play-state" : { multi: "running | paused", comma: true },
4232
"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 | inherit",
4233
"azimuth" : function (expression) {
4234
var simple = "<angle> | leftwards | rightwards | inherit",
4235
direction = "left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",
4240
if (!ValidationTypes.isAny(expression, simple)) {
4241
if (ValidationTypes.isAny(expression, "behind")) {
4246
if (ValidationTypes.isAny(expression, direction)) {
4249
ValidationTypes.isAny(expression, "behind");
4254
if (expression.hasNext()) {
4255
part = expression.next();
4257
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
4259
throw new ValidationError("Expected (<'azimuth'>) but found '" + part + "'.", part.line, part.col);
4263
"backface-visibility" : "visible | hidden",
4265
"background-attachment" : { multi: "<attachment>", comma: true },
4266
"background-clip" : { multi: "<box>", comma: true },
4267
"background-color" : "<color> | inherit",
4268
"background-image" : { multi: "<bg-image>", comma: true },
4269
"background-origin" : { multi: "<box>", comma: true },
4270
"background-position" : { multi: "<bg-position>", comma: true },
4271
"background-repeat" : { multi: "<repeat-style>" },
4272
"background-size" : { multi: "<bg-size>", comma: true },
4273
"baseline-shift" : "baseline | sub | super | <percentage> | <length>",
4276
"bleed" : "<length>",
4277
"bookmark-label" : "<content> | <attr> | <string>",
4278
"bookmark-level" : "none | <integer>",
4279
"bookmark-state" : "open | closed",
4280
"bookmark-target" : "none | <uri> | <attr>",
4281
"border" : "<border-width> || <border-style> || <color>",
4282
"border-bottom" : "<border-width> || <border-style> || <color>",
4283
"border-bottom-color" : "<color>",
4284
"border-bottom-left-radius" : "<x-one-radius>",
4285
"border-bottom-right-radius" : "<x-one-radius>",
4286
"border-bottom-style" : "<border-style>",
4287
"border-bottom-width" : "<border-width>",
4288
"border-collapse" : "collapse | separate | inherit",
4289
"border-color" : { multi: "<color> | inherit", max: 4 },
4291
"border-image-outset" : { multi: "<length> | <number>", max: 4 },
4292
"border-image-repeat" : { multi: "stretch | repeat | round", max: 2 },
4293
"border-image-slice" : function(expression) {
4296
numeric = "<number> | <percentage>",
4302
if (ValidationTypes.isAny(expression, "fill")) {
4307
while (expression.hasNext() && count < max) {
4308
valid = ValidationTypes.isAny(expression, numeric);
4317
ValidationTypes.isAny(expression, "fill");
4322
if (expression.hasNext()) {
4323
part = expression.next();
4325
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
4327
throw new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '" + part + "'.", part.line, part.col);
4331
"border-image-source" : "<image> | none",
4332
"border-image-width" : { multi: "<length> | <percentage> | <number> | auto", max: 4 },
4333
"border-left" : "<border-width> || <border-style> || <color>",
4334
"border-left-color" : "<color> | inherit",
4335
"border-left-style" : "<border-style>",
4336
"border-left-width" : "<border-width>",
4337
"border-radius" : function(expression) {
4340
numeric = "<length> | <percentage>",
4347
while (expression.hasNext() && count < max) {
4348
valid = ValidationTypes.isAny(expression, numeric);
4351
if (expression.peek() == "/" && count > 1 && !slash) {
4362
if (expression.hasNext()) {
4363
part = expression.next();
4365
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
4367
throw new ValidationError("Expected (<'border-radius'>) but found '" + part + "'.", part.line, part.col);
4371
"border-right" : "<border-width> || <border-style> || <color>",
4372
"border-right-color" : "<color> | inherit",
4373
"border-right-style" : "<border-style>",
4374
"border-right-width" : "<border-width>",
4375
"border-spacing" : { multi: "<length> | inherit", max: 2 },
4376
"border-style" : { multi: "<border-style>", max: 4 },
4377
"border-top" : "<border-width> || <border-style> || <color>",
4378
"border-top-color" : "<color> | inherit",
4379
"border-top-left-radius" : "<x-one-radius>",
4380
"border-top-right-radius" : "<x-one-radius>",
4381
"border-top-style" : "<border-style>",
4382
"border-top-width" : "<border-width>",
4383
"border-width" : { multi: "<border-width>", max: 4 },
4384
"bottom" : "<margin-width> | inherit",
4385
"box-align" : "start | end | center | baseline | stretch", //http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/
4386
"box-decoration-break" : "slice |clone",
4387
"box-direction" : "normal | reverse | inherit",
4388
"box-flex" : "<number>",
4389
"box-flex-group" : "<integer>",
4390
"box-lines" : "single | multiple",
4391
"box-ordinal-group" : "<integer>",
4392
"box-orient" : "horizontal | vertical | inline-axis | block-axis | inherit",
4393
"box-pack" : "start | end | center | justify",
4394
"box-shadow" : function (expression) {
4398
if (!ValidationTypes.isAny(expression, "none")) {
4399
Validation.multiProperty("<shadow>", expression, true, Infinity);
4401
if (expression.hasNext()) {
4402
part = expression.next();
4403
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
4407
"box-sizing" : "content-box | border-box | inherit",
4408
"break-after" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
4409
"break-before" : "auto | always | avoid | left | right | page | column | avoid-page | avoid-column",
4410
"break-inside" : "auto | avoid | avoid-page | avoid-column",
4411
"caption-side" : "top | bottom | inherit",
4412
"clear" : "none | right | left | both | inherit",
4414
"color" : "<color> | inherit",
4415
"color-profile" : 1,
4416
"column-count" : "<integer> | auto", //http://www.w3.org/TR/css3-multicol/
4417
"column-fill" : "auto | balance",
4418
"column-gap" : "<length> | normal",
4419
"column-rule" : "<border-width> || <border-style> || <color>",
4420
"column-rule-color" : "<color>",
4421
"column-rule-style" : "<border-style>",
4422
"column-rule-width" : "<border-width>",
4423
"column-span" : "none | all",
4424
"column-width" : "<length> | auto",
4427
"counter-increment" : 1,
4428
"counter-reset" : 1,
4429
"crop" : "<shape> | auto",
4430
"cue" : "cue-after | cue-before | inherit",
4434
"direction" : "ltr | rtl | inherit",
4435
"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 | box | inline-box | grid | inline-grid | none | inherit",
4436
"dominant-baseline" : 1,
4437
"drop-initial-after-adjust" : "central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>",
4438
"drop-initial-after-align" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",
4439
"drop-initial-before-adjust" : "before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>",
4440
"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",
4441
"drop-initial-size" : "auto | line | <length> | <percentage>",
4442
"drop-initial-value" : "initial | <integer>",
4443
"elevation" : "<angle> | below | level | above | higher | lower | inherit",
4444
"empty-cells" : "show | hide | inherit",
4446
"fit" : "fill | hidden | meet | slice",
4448
"float" : "left | right | none | inherit",
4452
"font-size" : "<absolute-size> | <relative-size> | <length> | <percentage> | inherit",
4453
"font-size-adjust" : "<number> | none | inherit",
4454
"font-stretch" : "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit",
4455
"font-style" : "normal | italic | oblique | inherit",
4456
"font-variant" : "normal | small-caps | inherit",
4457
"font-weight" : "normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit",
4458
"grid-cell-stacking" : "columns | rows | layer",
4461
"grid-column-align" : "start | end | center | stretch",
4462
"grid-column-sizing" : 1,
4463
"grid-column-span" : "<integer>",
4464
"grid-flow" : "none | rows | columns",
4465
"grid-layer" : "<integer>",
4468
"grid-row-align" : "start | end | center | stretch",
4469
"grid-row-span" : "<integer>",
4470
"grid-row-sizing" : 1,
4471
"hanging-punctuation" : 1,
4472
"height" : "<margin-width> | inherit",
4473
"hyphenate-after" : "<integer> | auto",
4474
"hyphenate-before" : "<integer> | auto",
4475
"hyphenate-character" : "<string> | auto",
4476
"hyphenate-lines" : "no-limit | <integer>",
4477
"hyphenate-resource" : 1,
4478
"hyphens" : "none | manual | auto",
4480
"image-orientation" : "angle | auto",
4481
"image-rendering" : 1,
4482
"image-resolution" : 1,
4483
"inline-box-align" : "initial | last | <integer>",
4484
"left" : "<margin-width> | inherit",
4485
"letter-spacing" : "<length> | normal | inherit",
4486
"line-height" : "<number> | <length> | <percentage> | normal | inherit",
4487
"line-break" : "auto | loose | normal | strict",
4488
"line-stacking" : 1,
4489
"line-stacking-ruby" : "exclude-ruby | include-ruby",
4490
"line-stacking-shift" : "consider-shifts | disregard-shifts",
4491
"line-stacking-strategy" : "inline-line-height | block-line-height | max-height | grid-height",
4493
"list-style-image" : "<uri> | none | inherit",
4494
"list-style-position" : "inside | outside | inherit",
4495
"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",
4496
"margin" : { multi: "<margin-width> | inherit", max: 4 },
4497
"margin-bottom" : "<margin-width> | inherit",
4498
"margin-left" : "<margin-width> | inherit",
4499
"margin-right" : "<margin-width> | inherit",
4500
"margin-top" : "<margin-width> | inherit",
4505
"marquee-direction" : 1,
4506
"marquee-play-count" : 1,
4507
"marquee-speed" : 1,
4508
"marquee-style" : 1,
4509
"max-height" : "<length> | <percentage> | none | inherit",
4510
"max-width" : "<length> | <percentage> | none | inherit",
4511
"min-height" : "<length> | <percentage> | inherit",
4512
"min-width" : "<length> | <percentage> | inherit",
4519
"opacity" : "<number> | inherit",
4520
"orphans" : "<integer> | inherit",
4522
"outline-color" : "<color> | invert | inherit",
4523
"outline-offset" : 1,
4524
"outline-style" : "<border-style> | inherit",
4525
"outline-width" : "<border-width> | inherit",
4526
"overflow" : "visible | hidden | scroll | auto | inherit",
4527
"overflow-style" : 1,
4530
"padding" : { multi: "<padding-width> | inherit", max: 4 },
4531
"padding-bottom" : "<padding-width> | inherit",
4532
"padding-left" : "<padding-width> | inherit",
4533
"padding-right" : "<padding-width> | inherit",
4534
"padding-top" : "<padding-width> | inherit",
4536
"page-break-after" : "auto | always | avoid | left | right | inherit",
4537
"page-break-before" : "auto | always | avoid | left | right | inherit",
4538
"page-break-inside" : "auto | avoid | inherit",
4544
"perspective-origin" : 1,
4549
"pointer-events" : "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",
4550
"position" : "static | relative | absolute | fixed | inherit",
4551
"presentation-level" : 1,
4552
"punctuation-trim" : 1,
4554
"rendering-intent" : 1,
4560
"right" : "<margin-width> | inherit",
4562
"rotation-point" : 1,
4564
"ruby-overhang" : 1,
4565
"ruby-position" : 1,
4568
"speak" : "normal | none | spell-out | inherit",
4569
"speak-header" : "once | always | inherit",
4570
"speak-numeral" : "digits | continuous | inherit",
4571
"speak-punctuation" : "code | none | inherit",
4577
"table-layout" : "auto | fixed | inherit",
4578
"tab-size" : "<integer> | <length>",
4582
"target-position" : 1,
4583
"text-align" : "left | right | center | justify | inherit" ,
4584
"text-align-last" : 1,
4585
"text-decoration" : 1,
4586
"text-emphasis" : 1,
4588
"text-indent" : "<length> | <percentage> | inherit",
4589
"text-justify" : "auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida",
4591
"text-overflow" : 1,
4592
"text-rendering" : "auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit",
4594
"text-transform" : "capitalize | uppercase | lowercase | none | inherit",
4595
"text-wrap" : "normal | none | avoid",
4596
"top" : "<margin-width> | inherit",
4598
"transform-origin" : 1,
4599
"transform-style" : 1,
4601
"transition-delay" : 1,
4602
"transition-duration" : 1,
4603
"transition-property" : 1,
4604
"transition-timing-function" : 1,
4605
"unicode-bidi" : "normal | embed | bidi-override | inherit",
4606
"user-modify" : "read-only | read-write | write-only | inherit",
4607
"user-select" : "none | text | toggle | element | elements | all | inherit",
4608
"vertical-align" : "<percentage> | <length> | baseline | sub | super | top | text-top | middle | bottom | text-bottom | inherit",
4609
"visibility" : "visible | hidden | collapse | inherit",
4610
"voice-balance" : 1,
4611
"voice-duration" : 1,
4614
"voice-pitch-range" : 1,
4619
"white-space" : "normal | pre | nowrap | pre-wrap | pre-line | inherit",
4620
"white-space-collapse" : 1,
4621
"widows" : "<integer> | inherit",
4622
"width" : "<length> | <percentage> | auto | inherit" ,
4623
"word-break" : "normal | keep-all | break-all",
4624
"word-spacing" : "<length> | normal | inherit",
4626
"z-index" : "<integer> | auto | inherit",
4627
"zoom" : "<number> | <percentage> | normal"
4629
function PropertyName(text, hack, line, col){
4631
SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);
4636
PropertyName.prototype = new SyntaxUnit();
4637
PropertyName.prototype.constructor = PropertyName;
4638
PropertyName.prototype.toString = function(){
4639
return (this.hack ? this.hack : "") + this.text;
4641
function PropertyValue(parts, line, col){
4643
SyntaxUnit.call(this, parts.join(" "), line, col, Parser.PROPERTY_VALUE_TYPE);
4648
PropertyValue.prototype = new SyntaxUnit();
4649
PropertyValue.prototype.constructor = PropertyValue;
4650
function PropertyValueIterator(value){
4652
this._parts = value.parts;
4657
PropertyValueIterator.prototype.count = function(){
4658
return this._parts.length;
4660
PropertyValueIterator.prototype.isFirst = function(){
4661
return this._i === 0;
4663
PropertyValueIterator.prototype.hasNext = function(){
4664
return (this._i < this._parts.length);
4666
PropertyValueIterator.prototype.mark = function(){
4667
this._marks.push(this._i);
4669
PropertyValueIterator.prototype.peek = function(count){
4670
return this.hasNext() ? this._parts[this._i + (count || 0)] : null;
4672
PropertyValueIterator.prototype.next = function(){
4673
return this.hasNext() ? this._parts[this._i++] : null;
4675
PropertyValueIterator.prototype.previous = function(){
4676
return this._i > 0 ? this._parts[--this._i] : null;
4678
PropertyValueIterator.prototype.restore = function(){
4679
if (this._marks.length){
4680
this._i = this._marks.pop();
4683
function PropertyValuePart(text, line, col){
4685
SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);
4686
this.type = "unknown";
4689
if (/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){ //dimension
4690
this.type = "dimension";
4691
this.value = +RegExp.$1;
4692
this.units = RegExp.$2;
4693
switch(this.units.toLowerCase()){
4705
this.type = "length";
4711
this.type = "angle";
4721
this.type = "frequency";
4726
this.type = "resolution";
4731
} else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
4732
this.type = "percentage";
4733
this.value = +RegExp.$1;
4734
} else if (/^([+\-]?[\d\.]+)%$/i.test(text)){ //percentage
4735
this.type = "percentage";
4736
this.value = +RegExp.$1;
4737
} else if (/^([+\-]?\d+)$/i.test(text)){ //integer
4738
this.type = "integer";
4739
this.value = +RegExp.$1;
4740
} else if (/^([+\-]?[\d\.]+)$/i.test(text)){ //number
4741
this.type = "number";
4742
this.value = +RegExp.$1;
4744
} else if (/^#([a-f0-9]{3,6})/i.test(text)){ //hexcolor
4745
this.type = "color";
4747
if (temp.length == 3){
4748
this.red = parseInt(temp.charAt(0)+temp.charAt(0),16);
4749
this.green = parseInt(temp.charAt(1)+temp.charAt(1),16);
4750
this.blue = parseInt(temp.charAt(2)+temp.charAt(2),16);
4752
this.red = parseInt(temp.substring(0,2),16);
4753
this.green = parseInt(temp.substring(2,4),16);
4754
this.blue = parseInt(temp.substring(4,6),16);
4756
} else if (/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)){ //rgb() color with absolute numbers
4757
this.type = "color";
4758
this.red = +RegExp.$1;
4759
this.green = +RegExp.$2;
4760
this.blue = +RegExp.$3;
4761
} else if (/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //rgb() color with percentages
4762
this.type = "color";
4763
this.red = +RegExp.$1 * 255 / 100;
4764
this.green = +RegExp.$2 * 255 / 100;
4765
this.blue = +RegExp.$3 * 255 / 100;
4766
} else if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with absolute numbers
4767
this.type = "color";
4768
this.red = +RegExp.$1;
4769
this.green = +RegExp.$2;
4770
this.blue = +RegExp.$3;
4771
this.alpha = +RegExp.$4;
4772
} else if (/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //rgba() color with percentages
4773
this.type = "color";
4774
this.red = +RegExp.$1 * 255 / 100;
4775
this.green = +RegExp.$2 * 255 / 100;
4776
this.blue = +RegExp.$3 * 255 / 100;
4777
this.alpha = +RegExp.$4;
4778
} else if (/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)){ //hsl()
4779
this.type = "color";
4780
this.hue = +RegExp.$1;
4781
this.saturation = +RegExp.$2 / 100;
4782
this.lightness = +RegExp.$3 / 100;
4783
} else if (/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)){ //hsla() color with percentages
4784
this.type = "color";
4785
this.hue = +RegExp.$1;
4786
this.saturation = +RegExp.$2 / 100;
4787
this.lightness = +RegExp.$3 / 100;
4788
this.alpha = +RegExp.$4;
4789
} else if (/^url\(["']?([^\)"']+)["']?\)/i.test(text)){ //URI
4791
this.uri = RegExp.$1;
4792
} else if (/^([^\(]+)\(/i.test(text)){
4793
this.type = "function";
4794
this.name = RegExp.$1;
4796
} else if (/^["'][^"']*["']/.test(text)){ //string
4797
this.type = "string";
4798
this.value = eval(text);
4799
} else if (Colors[text.toLowerCase()]){ //named color
4800
this.type = "color";
4801
temp = Colors[text.toLowerCase()].substring(1);
4802
this.red = parseInt(temp.substring(0,2),16);
4803
this.green = parseInt(temp.substring(2,4),16);
4804
this.blue = parseInt(temp.substring(4,6),16);
4805
} else if (/^[\,\/]$/.test(text)){
4806
this.type = "operator";
4808
} else if (/^[a-z\-\u0080-\uFFFF][a-z0-9\-\u0080-\uFFFF]*$/i.test(text)){
4809
this.type = "identifier";
4815
PropertyValuePart.prototype = new SyntaxUnit();
4816
PropertyValuePart.prototype.constructor = PropertyValuePart;
4817
PropertyValuePart.fromToken = function(token){
4818
return new PropertyValuePart(token.value, token.startLine, token.startCol);
4827
Pseudos.ELEMENT = 1;
4830
Pseudos.isElement = function(pseudo){
4831
return pseudo.indexOf("::") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;
4833
function Selector(parts, line, col){
4835
SyntaxUnit.call(this, parts.join(" "), line, col, Parser.SELECTOR_TYPE);
4837
this.specificity = Specificity.calculate(this);
4841
Selector.prototype = new SyntaxUnit();
4842
Selector.prototype.constructor = Selector;
4843
function SelectorPart(elementName, modifiers, text, line, col){
4845
SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);
4846
this.elementName = elementName;
4847
this.modifiers = modifiers;
4851
SelectorPart.prototype = new SyntaxUnit();
4852
SelectorPart.prototype.constructor = SelectorPart;
4853
function SelectorSubPart(text, type, line, col){
4855
SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);
4861
SelectorSubPart.prototype = new SyntaxUnit();
4862
SelectorSubPart.prototype.constructor = SelectorSubPart;
4863
function Specificity(a, b, c, d){
4870
Specificity.prototype = {
4871
constructor: Specificity,
4872
compare: function(other){
4873
var comps = ["a", "b", "c", "d"],
4876
for (i=0, len=comps.length; i < len; i++){
4877
if (this[comps[i]] < other[comps[i]]){
4879
} else if (this[comps[i]] > other[comps[i]]){
4886
valueOf: function(){
4887
return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;
4889
toString: function(){
4890
return this.a + "," + this.b + "," + this.c + "," + this.d;
4894
Specificity.calculate = function(selector){
4900
function updateValues(part){
4903
elementName = part.elementName ? part.elementName.text : "",
4906
if (elementName && elementName.charAt(elementName.length-1) != "*") {
4910
for (i=0, len=part.modifiers.length; i < len; i++){
4911
modifier = part.modifiers[i];
4912
switch(modifier.type){
4923
if (Pseudos.isElement(modifier.text)){
4931
for (j=0, num=modifier.args.length; j < num; j++){
4932
updateValues(modifier.args[j]);
4938
for (i=0, len=selector.parts.length; i < len; i++){
4939
part = selector.parts[i];
4941
if (part instanceof SelectorPart){
4946
return new Specificity(0, b, c, d);
4949
var h = /^[0-9a-fA-F]$/,
4950
nonascii = /^[\u0080-\uFFFF]$/,
4951
nl = /\n|\r\n|\r|\f/;
4954
function isHexDigit(c){
4955
return c !== null && h.test(c);
4958
function isDigit(c){
4959
return c !== null && /\d/.test(c);
4962
function isWhitespace(c){
4963
return c !== null && /\s/.test(c);
4966
function isNewLine(c){
4967
return c !== null && nl.test(c);
4970
function isNameStart(c){
4971
return c !== null && (/[a-z_\u0080-\uFFFF\\]/i.test(c));
4974
function isNameChar(c){
4975
return c !== null && (isNameStart(c) || /[0-9\-\\]/.test(c));
4978
function isIdentStart(c){
4979
return c !== null && (isNameStart(c) || /\-\\/.test(c));
4982
function mix(receiver, supplier){
4983
for (var prop in supplier){
4984
if (supplier.hasOwnProperty(prop)){
4985
receiver[prop] = supplier[prop];
4990
function TokenStream(input){
4991
TokenStreamBase.call(this, input, Tokens);
4994
TokenStream.prototype = mix(new TokenStreamBase(), {
4995
_getToken: function(channel){
4998
reader = this._reader,
5000
startLine = reader.getLine(),
5001
startCol = reader.getCol();
5010
if(reader.peek() == "*"){
5011
token = this.commentToken(c, startLine, startCol);
5013
token = this.charToken(c, startLine, startCol);
5021
if(reader.peek() == "="){
5022
token = this.comparisonToken(c, startLine, startCol);
5024
token = this.charToken(c, startLine, startCol);
5029
token = this.stringToken(c, startLine, startCol);
5032
if (isNameChar(reader.peek())){
5033
token = this.hashToken(c, startLine, startCol);
5035
token = this.charToken(c, startLine, startCol);
5039
if (isDigit(reader.peek())){
5040
token = this.numberToken(c, startLine, startCol);
5042
token = this.charToken(c, startLine, startCol);
5046
if (reader.peek() == "-"){ //could be closing HTML-style comment
5047
token = this.htmlCommentEndToken(c, startLine, startCol);
5048
} else if (isNameStart(reader.peek())){
5049
token = this.identOrFunctionToken(c, startLine, startCol);
5051
token = this.charToken(c, startLine, startCol);
5055
token = this.importantToken(c, startLine, startCol);
5058
token = this.atRuleToken(c, startLine, startCol);
5061
token = this.notToken(c, startLine, startCol);
5064
token = this.htmlCommentStartToken(c, startLine, startCol);
5068
if (reader.peek() == "+"){
5069
token = this.unicodeRangeToken(c, startLine, startCol);
5074
token = this.numberToken(c, startLine, startCol);
5076
if (isWhitespace(c)){
5077
token = this.whitespaceToken(c, startLine, startCol);
5079
if (isIdentStart(c)){
5080
token = this.identOrFunctionToken(c, startLine, startCol);
5083
token = this.charToken(c, startLine, startCol);
5095
if (!token && c === null){
5096
token = this.createToken(Tokens.EOF,null,startLine,startCol);
5101
createToken: function(tt, value, startLine, startCol, options){
5102
var reader = this._reader;
5103
options = options || {};
5108
channel: options.channel,
5109
hide: options.hide || false,
5110
startLine: startLine,
5112
endLine: reader.getLine(),
5113
endCol: reader.getCol()
5116
atRuleToken: function(first, startLine, startCol){
5118
reader = this._reader,
5124
ident = this.readName();
5125
rule = first + ident;
5126
tt = Tokens.type(rule.toLowerCase());
5127
if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){
5128
if (rule.length > 1){
5129
tt = Tokens.UNKNOWN_SYM;
5137
return this.createToken(tt, rule, startLine, startCol);
5139
charToken: function(c, startLine, startCol){
5140
var tt = Tokens.type(c);
5146
return this.createToken(tt, c, startLine, startCol);
5148
commentToken: function(first, startLine, startCol){
5149
var reader = this._reader,
5150
comment = this.readComment(first);
5152
return this.createToken(Tokens.COMMENT, comment, startLine, startCol);
5154
comparisonToken: function(c, startLine, startCol){
5155
var reader = this._reader,
5156
comparison = c + reader.read(),
5157
tt = Tokens.type(comparison) || Tokens.CHAR;
5159
return this.createToken(tt, comparison, startLine, startCol);
5161
hashToken: function(first, startLine, startCol){
5162
var reader = this._reader,
5163
name = this.readName(first);
5165
return this.createToken(Tokens.HASH, name, startLine, startCol);
5167
htmlCommentStartToken: function(first, startLine, startCol){
5168
var reader = this._reader,
5172
text += reader.readCount(3);
5174
if (text == "<!--"){
5175
return this.createToken(Tokens.CDO, text, startLine, startCol);
5178
return this.charToken(first, startLine, startCol);
5181
htmlCommentEndToken: function(first, startLine, startCol){
5182
var reader = this._reader,
5186
text += reader.readCount(2);
5189
return this.createToken(Tokens.CDC, text, startLine, startCol);
5192
return this.charToken(first, startLine, startCol);
5195
identOrFunctionToken: function(first, startLine, startCol){
5196
var reader = this._reader,
5197
ident = this.readName(first),
5199
if (reader.peek() == "("){
5200
ident += reader.read();
5201
if (ident.toLowerCase() == "url("){
5203
ident = this.readURI(ident);
5204
if (ident.toLowerCase() == "url("){
5205
tt = Tokens.FUNCTION;
5208
tt = Tokens.FUNCTION;
5210
} else if (reader.peek() == ":"){ //might be an IE function
5211
if (ident.toLowerCase() == "progid"){
5212
ident += reader.readTo("(");
5213
tt = Tokens.IE_FUNCTION;
5217
return this.createToken(tt, ident, startLine, startCol);
5219
importantToken: function(first, startLine, startCol){
5220
var reader = this._reader,
5231
if (reader.peek() != "*"){
5234
temp = this.readComment(c);
5235
if (temp === ""){ //broken!
5239
} else if (isWhitespace(c)){
5240
important += c + this.readWhitespace();
5241
} else if (/i/i.test(c)){
5242
temp = reader.readCount(8);
5243
if (/mportant/i.test(temp)){
5244
important += c + temp;
5245
tt = Tokens.IMPORTANT_SYM;
5256
if (tt == Tokens.CHAR){
5258
return this.charToken(first, startLine, startCol);
5260
return this.createToken(tt, important, startLine, startCol);
5265
notToken: function(first, startLine, startCol){
5266
var reader = this._reader,
5270
text += reader.readCount(4);
5272
if (text.toLowerCase() == ":not("){
5273
return this.createToken(Tokens.NOT, text, startLine, startCol);
5276
return this.charToken(first, startLine, startCol);
5279
numberToken: function(first, startLine, startCol){
5280
var reader = this._reader,
5281
value = this.readNumber(first),
5286
if (isIdentStart(c)){
5287
ident = this.readName(reader.read());
5290
if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vm$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){
5292
} else if (/^deg|^rad$|^grad$/i.test(ident)){
5294
} else if (/^ms$|^s$/i.test(ident)){
5296
} else if (/^hz$|^khz$/i.test(ident)){
5298
} else if (/^dpi$|^dpcm$/i.test(ident)){
5299
tt = Tokens.RESOLUTION;
5301
tt = Tokens.DIMENSION;
5304
} else if (c == "%"){
5305
value += reader.read();
5306
tt = Tokens.PERCENTAGE;
5309
return this.createToken(tt, value, startLine, startCol);
5311
stringToken: function(first, startLine, startCol){
5314
reader = this._reader,
5321
if (c == delim && prev != "\\"){
5324
if (isNewLine(reader.peek()) && c != "\\"){
5325
tt = Tokens.INVALID;
5332
tt = Tokens.INVALID;
5335
return this.createToken(tt, string, startLine, startCol);
5338
unicodeRangeToken: function(first, startLine, startCol){
5339
var reader = this._reader,
5343
if (reader.peek() == "+"){
5345
value += reader.read();
5346
value += this.readUnicodeRangePart(true);
5347
if (value.length == 2){
5351
tt = Tokens.UNICODE_RANGE;
5352
if (value.indexOf("?") == -1){
5354
if (reader.peek() == "-"){
5356
temp = reader.read();
5357
temp += this.readUnicodeRangePart(false);
5358
if (temp.length == 1){
5369
return this.createToken(tt, value, startLine, startCol);
5371
whitespaceToken: function(first, startLine, startCol){
5372
var reader = this._reader,
5373
value = first + this.readWhitespace();
5374
return this.createToken(Tokens.S, value, startLine, startCol);
5377
readUnicodeRangePart: function(allowQuestionMark){
5378
var reader = this._reader,
5381
while(isHexDigit(c) && part.length < 6){
5386
if (allowQuestionMark){
5387
while(c == "?" && part.length < 6){
5397
readWhitespace: function(){
5398
var reader = this._reader,
5402
while(isWhitespace(c)){
5410
readNumber: function(first){
5411
var reader = this._reader,
5413
hasDot = (first == "."),
5419
number += reader.read();
5420
} else if (c == "."){
5425
number += reader.read();
5436
readString: function(){
5437
var reader = this._reader,
5438
delim = reader.read(),
5446
if (c == delim && prev != "\\"){
5449
if (isNewLine(reader.peek()) && c != "\\"){
5462
readURI: function(first){
5463
var reader = this._reader,
5469
while(c && isWhitespace(c)){
5473
if (c == "'" || c == "\""){
5474
inner = this.readString();
5476
inner = this.readURL();
5480
while(c && isWhitespace(c)){
5484
if (inner === "" || c != ")"){
5488
uri += inner + reader.read();
5493
readURL: function(){
5494
var reader = this._reader,
5497
while (/^[!#$%&\\*-~]$/.test(c)){
5498
url += reader.read();
5505
readName: function(first){
5506
var reader = this._reader,
5507
ident = first || "",
5512
ident += this.readEscape(reader.read());
5514
} else if(c && isNameChar(c)){
5515
ident += reader.read();
5525
readEscape: function(first){
5526
var reader = this._reader,
5527
cssEscape = first || "",
5533
cssEscape += reader.read();
5535
} while(c && isHexDigit(c) && ++i < 6);
5538
if (cssEscape.length == 3 && /\s/.test(c) ||
5539
cssEscape.length == 7 || cssEscape.length == 1){
5545
return cssEscape + c;
5548
readComment: function(first){
5549
var reader = this._reader,
5550
comment = first || "",
5556
if (comment.length > 2 && c == "*" && reader.peek() == "/"){
5557
comment += reader.read();
5576
{ name: "S", whitespace: true/*, channel: "ws"*/},
5577
{ name: "COMMENT", comment: true, hide: true, channel: "comment" },
5578
{ name: "INCLUDES", text: "~="},
5579
{ name: "DASHMATCH", text: "|="},
5580
{ name: "PREFIXMATCH", text: "^="},
5581
{ name: "SUFFIXMATCH", text: "$="},
5582
{ name: "SUBSTRINGMATCH", text: "*="},
5586
{ name: "IMPORT_SYM", text: "@import"},
5587
{ name: "PAGE_SYM", text: "@page"},
5588
{ name: "MEDIA_SYM", text: "@media"},
5589
{ name: "FONT_FACE_SYM", text: "@font-face"},
5590
{ name: "CHARSET_SYM", text: "@charset"},
5591
{ name: "NAMESPACE_SYM", text: "@namespace"},
5592
{ name: "UNKNOWN_SYM" },
5593
{ name: "KEYFRAMES_SYM", text: [ "@keyframes", "@-webkit-keyframes", "@-moz-keyframes", "@-o-keyframes" ] },
5594
{ name: "IMPORTANT_SYM"},
5599
{ name: "DIMENSION"},
5600
{ name: "PERCENTAGE"},
5603
{ name: "FUNCTION"},
5604
{ name: "UNICODE_RANGE"},
5606
{ name: "PLUS", text: "+" },
5607
{ name: "GREATER", text: ">"},
5608
{ name: "COMMA", text: ","},
5609
{ name: "TILDE", text: "~"},
5611
{ name: "TOPLEFTCORNER_SYM", text: "@top-left-corner"},
5612
{ name: "TOPLEFT_SYM", text: "@top-left"},
5613
{ name: "TOPCENTER_SYM", text: "@top-center"},
5614
{ name: "TOPRIGHT_SYM", text: "@top-right"},
5615
{ name: "TOPRIGHTCORNER_SYM", text: "@top-right-corner"},
5616
{ name: "BOTTOMLEFTCORNER_SYM", text: "@bottom-left-corner"},
5617
{ name: "BOTTOMLEFT_SYM", text: "@bottom-left"},
5618
{ name: "BOTTOMCENTER_SYM", text: "@bottom-center"},
5619
{ name: "BOTTOMRIGHT_SYM", text: "@bottom-right"},
5620
{ name: "BOTTOMRIGHTCORNER_SYM", text: "@bottom-right-corner"},
5621
{ name: "LEFTTOP_SYM", text: "@left-top"},
5622
{ name: "LEFTMIDDLE_SYM", text: "@left-middle"},
5623
{ name: "LEFTBOTTOM_SYM", text: "@left-bottom"},
5624
{ name: "RIGHTTOP_SYM", text: "@right-top"},
5625
{ name: "RIGHTMIDDLE_SYM", text: "@right-middle"},
5626
{ name: "RIGHTBOTTOM_SYM", text: "@right-bottom"},
5627
{ name: "RESOLUTION", state: "media"},
5628
{ name: "IE_FUNCTION" },
5695
Tokens.UNKNOWN = -1;
5696
Tokens.unshift({name:"EOF"});
5697
for (var i=0, len = Tokens.length; i < len; i++){
5698
nameMap.push(Tokens[i].name);
5699
Tokens[Tokens[i].name] = i;
5700
if (Tokens[i].text){
5701
if (Tokens[i].text instanceof Array){
5702
for (var j=0; j < Tokens[i].text.length; j++){
5703
typeMap[Tokens[i].text[j]] = i;
5706
typeMap[Tokens[i].text] = i;
5711
Tokens.name = function(tt){
5715
Tokens.type = function(c){
5716
return typeMap[c] || -1;
5722
validate: function(property, value){
5723
var name = property.toString().toLowerCase(),
5724
parts = value.parts,
5725
expression = new PropertyValueIterator(value),
5726
spec = Properties[name],
5737
if (name.indexOf("-") !== 0){ //vendor prefixed are ok
5738
throw new ValidationError("Unknown property '" + property + "'.", property.line, property.col);
5740
} else if (typeof spec != "number"){
5741
if (typeof spec == "string"){
5742
if (spec.indexOf("||") > -1) {
5743
this.groupProperty(spec, expression);
5745
this.singleProperty(spec, expression, 1);
5748
} else if (spec.multi) {
5749
this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);
5750
} else if (typeof spec == "function") {
5758
singleProperty: function(types, expression, max, partial) {
5761
value = expression.value,
5765
while (expression.hasNext() && count < max) {
5766
result = ValidationTypes.isAny(expression, types);
5774
if (expression.hasNext() && !expression.isFirst()) {
5775
part = expression.peek();
5776
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5778
throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5780
} else if (expression.hasNext()) {
5781
part = expression.next();
5782
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5787
multiProperty: function (types, expression, comma, max) {
5790
value = expression.value,
5795
while(expression.hasNext() && !result && count < max) {
5796
if (ValidationTypes.isAny(expression, types)) {
5798
if (!expression.hasNext()) {
5802
if (expression.peek() == ",") {
5803
part = expression.next();
5815
if (expression.hasNext() && !expression.isFirst()) {
5816
part = expression.peek();
5817
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5819
part = expression.previous();
5820
if (comma && part == ",") {
5821
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5823
throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5827
} else if (expression.hasNext()) {
5828
part = expression.next();
5829
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5834
groupProperty: function (types, expression, comma) {
5837
value = expression.value,
5838
typeCount = types.split("||").length,
5839
groups = { count: 0 },
5844
while(expression.hasNext() && !result) {
5845
name = ValidationTypes.isAnyOfGroup(expression, types);
5854
if (groups.count == typeCount || !expression.hasNext()) {
5864
if (partial && expression.hasNext()) {
5865
part = expression.peek();
5866
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5868
throw new ValidationError("Expected (" + types + ") but found '" + value + "'.", value.line, value.col);
5870
} else if (expression.hasNext()) {
5871
part = expression.next();
5872
throw new ValidationError("Expected end of value but found '" + part + "'.", part.line, part.col);
5879
function ValidationError(message, line, col){
5882
this.message = message;
5885
ValidationError.prototype = new Error();
5886
var ValidationTypes = {
5888
isLiteral: function (part, literals) {
5889
var text = part.text.toString().toLowerCase(),
5890
args = literals.split(" | "),
5891
i, len, found = false;
5893
for (i=0,len=args.length; i < len && !found; i++){
5894
if (text == args[i].toLowerCase()){
5902
isSimple: function(type) {
5903
return !!this.simple[type];
5906
isComplex: function(type) {
5907
return !!this.complex[type];
5909
isAny: function (expression, types) {
5910
var args = types.split(" | "),
5911
i, len, found = false;
5913
for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){
5914
found = this.isType(expression, args[i]);
5919
isAnyOfGroup: function(expression, types) {
5920
var args = types.split(" || "),
5921
i, len, found = false;
5923
for (i=0,len=args.length; i < len && !found; i++){
5924
found = this.isType(expression, args[i]);
5927
return found ? args[i-1] : false;
5929
isType: function (expression, type) {
5930
var part = expression.peek(),
5933
if (type.charAt(0) != "<") {
5934
result = this.isLiteral(part, type);
5938
} else if (this.simple[type]) {
5939
result = this.simple[type](part);
5944
result = this.complex[type](expression);
5954
"<absolute-size>": function(part){
5955
return ValidationTypes.isLiteral(part, "xx-small | x-small | small | medium | large | x-large | xx-large");
5958
"<attachment>": function(part){
5959
return ValidationTypes.isLiteral(part, "scroll | fixed | local");
5962
"<attr>": function(part){
5963
return part.type == "function" && part.name == "attr";
5966
"<bg-image>": function(part){
5967
return this["<image>"](part) || this["<gradient>"](part) || part == "none";
5970
"<gradient>": function(part) {
5971
return part.type == "function" && /^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(part);
5974
"<box>": function(part){
5975
return ValidationTypes.isLiteral(part, "padding-box | border-box | content-box");
5978
"<content>": function(part){
5979
return part.type == "function" && part.name == "content";
5982
"<relative-size>": function(part){
5983
return ValidationTypes.isLiteral(part, "smaller | larger");
5985
"<ident>": function(part){
5986
return part.type == "identifier";
5989
"<length>": function(part){
5990
return part.type == "length" || part.type == "number" || part.type == "integer" || part == "0";
5993
"<color>": function(part){
5994
return part.type == "color" || part == "transparent";
5997
"<number>": function(part){
5998
return part.type == "number" || this["<integer>"](part);
6001
"<integer>": function(part){
6002
return part.type == "integer";
6005
"<line>": function(part){
6006
return part.type == "integer";
6009
"<angle>": function(part){
6010
return part.type == "angle";
6013
"<uri>": function(part){
6014
return part.type == "uri";
6017
"<image>": function(part){
6018
return this["<uri>"](part);
6021
"<percentage>": function(part){
6022
return part.type == "percentage" || part == "0";
6025
"<border-width>": function(part){
6026
return this["<length>"](part) || ValidationTypes.isLiteral(part, "thin | medium | thick");
6029
"<border-style>": function(part){
6030
return ValidationTypes.isLiteral(part, "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset");
6033
"<margin-width>": function(part){
6034
return this["<length>"](part) || this["<percentage>"](part) || ValidationTypes.isLiteral(part, "auto");
6037
"<padding-width>": function(part){
6038
return this["<length>"](part) || this["<percentage>"](part);
6041
"<shape>": function(part){
6042
return part.type == "function" && (part.name == "rect" || part.name == "inset-rect");
6045
"<time>": function(part) {
6046
return part.type == "time";
6052
"<bg-position>": function(expression){
6055
numeric = "<percentage> | <length>",
6056
xDir = "left | center | right",
6057
yDir = "top | center | bottom",
6061
if (ValidationTypes.isAny(expression, "top | bottom")) {
6064
if (ValidationTypes.isAny(expression, numeric)){
6065
if (expression.hasNext()){
6066
result = ValidationTypes.isAny(expression, numeric + " | " + yDir);
6068
} else if (ValidationTypes.isAny(expression, xDir)){
6069
if (expression.hasNext()){
6070
if (ValidationTypes.isAny(expression, yDir)){
6073
ValidationTypes.isAny(expression, numeric);
6075
} else if (ValidationTypes.isAny(expression, numeric)){
6076
if (ValidationTypes.isAny(expression, yDir)){
6077
ValidationTypes.isAny(expression, numeric);
6090
"<bg-size>": function(expression){
6093
numeric = "<percentage> | <length> | auto",
6097
if (ValidationTypes.isAny(expression, "cover | contain")) {
6099
} else if (ValidationTypes.isAny(expression, numeric)) {
6101
ValidationTypes.isAny(expression, numeric);
6107
"<repeat-style>": function(expression){
6109
values = "repeat | space | round | no-repeat",
6112
if (expression.hasNext()){
6113
part = expression.next();
6115
if (ValidationTypes.isLiteral(part, "repeat-x | repeat-y")) {
6117
} else if (ValidationTypes.isLiteral(part, values)) {
6120
if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {
6130
"<shadow>": function(expression) {
6137
if (expression.hasNext()) {
6139
if (ValidationTypes.isAny(expression, "inset")){
6143
if (ValidationTypes.isAny(expression, "<color>")) {
6147
while (ValidationTypes.isAny(expression, "<length>") && count < 4) {
6152
if (expression.hasNext()) {
6154
ValidationTypes.isAny(expression, "<color>");
6158
ValidationTypes.isAny(expression, "inset");
6163
result = (count >= 2 && count <= 4);
6170
"<x-one-radius>": function(expression) {
6173
numeric = "<length> | <percentage>",
6176
if (ValidationTypes.isAny(expression, numeric)){
6179
ValidationTypes.isAny(expression, numeric);
6190
Combinator :Combinator,
6192
PropertyName :PropertyName,
6193
PropertyValue :PropertyValue,
6194
PropertyValuePart :PropertyValuePart,
6195
MediaFeature :MediaFeature,
6196
MediaQuery :MediaQuery,
6198
SelectorPart :SelectorPart,
6199
SelectorSubPart :SelectorSubPart,
6200
Specificity :Specificity,
6201
TokenStream :TokenStream,
6203
ValidationError :ValidationError
6206
var CSSLint = (function(){
6210
api = new parserlib.util.EventTarget();
6212
api.version = "0.9.9";
6213
api.addRule = function(rule){
6215
rules[rule.id] = rule;
6217
api.clearRules = function(){
6220
api.getRules = function(){
6221
return [].concat(rules).sort(function(a,b){
6222
return a.id > b.id ? 1 : 0;
6225
api.getRuleset = function() {
6231
ruleset[rules[i++].id] = 1; //by default, everything is a warning
6236
api.addFormatter = function(formatter) {
6237
formatters[formatter.id] = formatter;
6239
api.getFormatter = function(formatId){
6240
return formatters[formatId];
6242
api.format = function(results, filename, formatId, options) {
6243
var formatter = this.getFormatter(formatId),
6247
result = formatter.startFormat();
6248
result += formatter.formatResults(results, filename, options || {});
6249
result += formatter.endFormat();
6254
api.hasFormat = function(formatId){
6255
return formatters.hasOwnProperty(formatId);
6257
api.verify = function(text, ruleset){
6264
parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,
6265
underscoreHack: true, strict: false });
6266
lines = text.replace(/\n\r?/g, "$split$").split('$split$');
6269
ruleset = this.getRuleset();
6272
reporter = new Reporter(lines, ruleset);
6274
ruleset.errors = 2; //always report parsing errors as errors
6276
if(ruleset.hasOwnProperty(i)){
6278
rules[i].init(parser, reporter);
6285
reporter.error("Fatal error, cannot continue: " + ex.message, ex.line, ex.col, {});
6289
messages : reporter.messages,
6290
stats : reporter.stats
6292
report.messages.sort(function (a, b){
6293
if (a.rollup && !b.rollup){
6295
} else if (!a.rollup && b.rollup){
6298
return a.line - b.line;
6308
function Reporter(lines, ruleset){
6312
this.ruleset = ruleset;
6315
Reporter.prototype = {
6316
constructor: Reporter,
6317
error: function(message, line, col, rule){
6318
this.messages.push({
6323
evidence: this.lines[line-1],
6327
warn: function(message, line, col, rule){
6328
this.report(message, line, col, rule);
6330
report: function(message, line, col, rule){
6331
this.messages.push({
6332
type : this.ruleset[rule.id] == 2 ? "error" : "warning",
6336
evidence: this.lines[line-1],
6340
info: function(message, line, col, rule){
6341
this.messages.push({
6346
evidence: this.lines[line-1],
6350
rollupError: function(message, rule){
6351
this.messages.push({
6358
rollupWarn: function(message, rule){
6359
this.messages.push({
6366
stat: function(name, value){
6367
this.stats[name] = value;
6370
CSSLint._Reporter = Reporter;
6372
mix: function(receiver, supplier){
6375
for (prop in supplier){
6376
if (supplier.hasOwnProperty(prop)){
6377
receiver[prop] = supplier[prop];
6383
indexOf: function(values, value){
6384
if (values.indexOf){
6385
return values.indexOf(value);
6387
for (var i=0, len=values.length; i < len; i++){
6388
if (values[i] === value){
6395
forEach: function(values, func) {
6396
if (values.forEach){
6397
return values.forEach(func);
6399
for (var i=0, len=values.length; i < len; i++){
6400
func(values[i], i, values);
6406
id: "adjoining-classes",
6407
name: "Disallow adjoining classes",
6408
desc: "Don't use adjoining classes.",
6410
init: function(parser, reporter){
6412
parser.addListener("startrule", function(event){
6413
var selectors = event.selectors,
6420
for (i=0; i < selectors.length; i++){
6421
selector = selectors[i];
6422
for (j=0; j < selector.parts.length; j++){
6423
part = selector.parts[j];
6424
if (part.type == parser.SELECTOR_PART_TYPE){
6426
for (k=0; k < part.modifiers.length; k++){
6427
modifier = part.modifiers[k];
6428
if (modifier.type == "class"){
6431
if (classCount > 1){
6432
reporter.report("Don't use adjoining classes.", part.line, part.col, rule);
6444
name: "Beware of broken box size",
6445
desc: "Don't use width or height when using padding or border.",
6447
init: function(parser, reporter){
6457
heightProperties = {
6462
"padding-bottom": 1,
6468
function startRule(){
6477
if (properties.height){
6478
for (prop in heightProperties){
6479
if (heightProperties.hasOwnProperty(prop) && properties[prop]){
6480
value = properties[prop].value;
6481
if (!(prop == "padding" && value.parts.length === 2 && value.parts[0].value === 0)){
6482
reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
6488
if (properties.width){
6489
for (prop in widthProperties){
6490
if (widthProperties.hasOwnProperty(prop) && properties[prop]){
6491
value = properties[prop].value;
6493
if (!(prop == "padding" && value.parts.length === 2 && value.parts[1].value === 0)){
6494
reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
6502
parser.addListener("startrule", startRule);
6503
parser.addListener("startfontface", startRule);
6504
parser.addListener("startpage", startRule);
6505
parser.addListener("startpagemargin", startRule);
6506
parser.addListener("startkeyframerule", startRule);
6508
parser.addListener("property", function(event){
6509
var name = event.property.text.toLowerCase();
6511
if (heightProperties[name] || widthProperties[name]){
6512
if (!/^0\S*$/.test(event.value) && !(name == "border" && event.value == "none")){
6513
properties[name] = { line: event.property.line, col: event.property.col, value: event.value };
6516
if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){
6517
properties[name] = 1;
6518
} else if (name == "box-sizing") {
6525
parser.addListener("endrule", endRule);
6526
parser.addListener("endfontface", endRule);
6527
parser.addListener("endpage", endRule);
6528
parser.addListener("endpagemargin", endRule);
6529
parser.addListener("endkeyframerule", endRule);
6535
name: "Disallow use of box-sizing",
6536
desc: "The box-sizing properties isn't supported in IE6 and IE7.",
6537
browsers: "IE6, IE7",
6538
tags: ["Compatibility"],
6539
init: function(parser, reporter){
6542
parser.addListener("property", function(event){
6543
var name = event.property.text.toLowerCase();
6545
if (name == "box-sizing"){
6546
reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
6553
id: "compatible-vendor-prefixes",
6554
name: "Require compatible vendor prefixes",
6555
desc: "Include all compatible vendor prefixes to reach a wider range of users.",
6557
init: function (parser, reporter) {
6567
arrayPush = Array.prototype.push,
6569
compatiblePrefixes = {
6570
"animation" : "webkit moz",
6571
"animation-delay" : "webkit moz",
6572
"animation-direction" : "webkit moz",
6573
"animation-duration" : "webkit moz",
6574
"animation-fill-mode" : "webkit moz",
6575
"animation-iteration-count" : "webkit moz",
6576
"animation-name" : "webkit moz",
6577
"animation-play-state" : "webkit moz",
6578
"animation-timing-function" : "webkit moz",
6579
"appearance" : "webkit moz",
6580
"border-end" : "webkit moz",
6581
"border-end-color" : "webkit moz",
6582
"border-end-style" : "webkit moz",
6583
"border-end-width" : "webkit moz",
6584
"border-image" : "webkit moz o",
6585
"border-radius" : "webkit moz",
6586
"border-start" : "webkit moz",
6587
"border-start-color" : "webkit moz",
6588
"border-start-style" : "webkit moz",
6589
"border-start-width" : "webkit moz",
6590
"box-align" : "webkit moz ms",
6591
"box-direction" : "webkit moz ms",
6592
"box-flex" : "webkit moz ms",
6593
"box-lines" : "webkit ms",
6594
"box-ordinal-group" : "webkit moz ms",
6595
"box-orient" : "webkit moz ms",
6596
"box-pack" : "webkit moz ms",
6597
"box-sizing" : "webkit moz",
6598
"box-shadow" : "webkit moz",
6599
"column-count" : "webkit moz ms",
6600
"column-gap" : "webkit moz ms",
6601
"column-rule" : "webkit moz ms",
6602
"column-rule-color" : "webkit moz ms",
6603
"column-rule-style" : "webkit moz ms",
6604
"column-rule-width" : "webkit moz ms",
6605
"column-width" : "webkit moz ms",
6606
"hyphens" : "epub moz",
6607
"line-break" : "webkit ms",
6608
"margin-end" : "webkit moz",
6609
"margin-start" : "webkit moz",
6610
"marquee-speed" : "webkit wap",
6611
"marquee-style" : "webkit wap",
6612
"padding-end" : "webkit moz",
6613
"padding-start" : "webkit moz",
6614
"tab-size" : "moz o",
6615
"text-size-adjust" : "webkit ms",
6616
"transform" : "webkit moz ms o",
6617
"transform-origin" : "webkit moz ms o",
6618
"transition" : "webkit moz o",
6619
"transition-delay" : "webkit moz o",
6620
"transition-duration" : "webkit moz o",
6621
"transition-property" : "webkit moz o",
6622
"transition-timing-function" : "webkit moz o",
6623
"user-modify" : "webkit moz",
6624
"user-select" : "webkit moz ms",
6625
"word-break" : "epub ms",
6626
"writing-mode" : "epub ms"
6630
for (prop in compatiblePrefixes) {
6631
if (compatiblePrefixes.hasOwnProperty(prop)) {
6633
prefixed = compatiblePrefixes[prop].split(' ');
6634
for (i = 0, len = prefixed.length; i < len; i++) {
6635
variations.push('-' + prefixed[i] + '-' + prop);
6637
compatiblePrefixes[prop] = variations;
6638
arrayPush.apply(applyTo, variations);
6642
parser.addListener("startrule", function () {
6646
parser.addListener("startkeyframes", function (event) {
6647
inKeyFrame = event.prefix || true;
6650
parser.addListener("endkeyframes", function (event) {
6654
parser.addListener("property", function (event) {
6655
var name = event.property;
6656
if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {
6657
if (!inKeyFrame || typeof inKeyFrame != "string" ||
6658
name.text.indexOf("-" + inKeyFrame + "-") !== 0) {
6659
properties.push(name);
6664
parser.addListener("endrule", function (event) {
6665
if (!properties.length) {
6669
var propertyGroups = {},
6679
propertiesSpecified;
6681
for (i = 0, len = properties.length; i < len; i++) {
6682
name = properties[i];
6684
for (prop in compatiblePrefixes) {
6685
if (compatiblePrefixes.hasOwnProperty(prop)) {
6686
variations = compatiblePrefixes[prop];
6687
if (CSSLint.Util.indexOf(variations, name.text) > -1) {
6688
if (!propertyGroups[prop]) {
6689
propertyGroups[prop] = {
6690
full : variations.slice(0),
6695
if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {
6696
propertyGroups[prop].actual.push(name.text);
6697
propertyGroups[prop].actualNodes.push(name);
6704
for (prop in propertyGroups) {
6705
if (propertyGroups.hasOwnProperty(prop)) {
6706
value = propertyGroups[prop];
6708
actual = value.actual;
6710
if (full.length > actual.length) {
6711
for (i = 0, len = full.length; i < len; i++) {
6713
if (CSSLint.Util.indexOf(actual, item) === -1) {
6714
propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(" and ") : actual.join(", ");
6715
reporter.report("The property " + item + " is compatible with " + propertiesSpecified + " and should be included as well.", value.actualNodes[0].line, value.actualNodes[0].col, rule);
6726
id: "display-property-grouping",
6727
name: "Require properties appropriate for display",
6728
desc: "Certain properties shouldn't be used with certain display property values.",
6730
init: function(parser, reporter){
6733
var propertiesToCheck = {
6746
"padding-bottom": 1,
6752
function reportProperty(name, display, msg){
6753
if (properties[name]){
6754
if (typeof propertiesToCheck[name] != "string" || properties[name].value.toLowerCase() != propertiesToCheck[name]){
6755
reporter.report(msg || name + " can't be used with display: " + display + ".", properties[name].line, properties[name].col, rule);
6760
function startRule(){
6766
var display = properties.display ? properties.display.value : null;
6771
reportProperty("height", display);
6772
reportProperty("width", display);
6773
reportProperty("margin", display);
6774
reportProperty("margin-top", display);
6775
reportProperty("margin-bottom", display);
6776
reportProperty("float", display, "display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");
6780
reportProperty("vertical-align", display);
6783
case "inline-block":
6784
reportProperty("float", display);
6788
if (display.indexOf("table-") === 0){
6789
reportProperty("margin", display);
6790
reportProperty("margin-left", display);
6791
reportProperty("margin-right", display);
6792
reportProperty("margin-top", display);
6793
reportProperty("margin-bottom", display);
6794
reportProperty("float", display);
6801
parser.addListener("startrule", startRule);
6802
parser.addListener("startfontface", startRule);
6803
parser.addListener("startkeyframerule", startRule);
6804
parser.addListener("startpagemargin", startRule);
6805
parser.addListener("startpage", startRule);
6807
parser.addListener("property", function(event){
6808
var name = event.property.text.toLowerCase();
6810
if (propertiesToCheck[name]){
6811
properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };
6815
parser.addListener("endrule", endRule);
6816
parser.addListener("endfontface", endRule);
6817
parser.addListener("endkeyframerule", endRule);
6818
parser.addListener("endpagemargin", endRule);
6819
parser.addListener("endpage", endRule);
6825
id: "duplicate-background-images",
6826
name: "Disallow duplicate background images",
6827
desc: "Every background-image should be unique. Use a common class for e.g. sprites.",
6829
init: function(parser, reporter){
6833
parser.addListener("property", function(event){
6834
var name = event.property.text,
6835
value = event.value,
6838
if (name.match(/background/i)) {
6839
for (i=0, len=value.parts.length; i < len; i++) {
6840
if (value.parts[i].type == 'uri') {
6841
if (typeof stack[value.parts[i].uri] === 'undefined') {
6842
stack[value.parts[i].uri] = event;
6845
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);
6854
id: "duplicate-properties",
6855
name: "Disallow duplicate properties",
6856
desc: "Duplicate properties must appear one after the other.",
6858
init: function(parser, reporter){
6863
function startRule(event){
6867
parser.addListener("startrule", startRule);
6868
parser.addListener("startfontface", startRule);
6869
parser.addListener("startpage", startRule);
6870
parser.addListener("startpagemargin", startRule);
6871
parser.addListener("startkeyframerule", startRule);
6873
parser.addListener("property", function(event){
6874
var property = event.property,
6875
name = property.text.toLowerCase();
6877
if (properties[name] && (lastProperty != name || properties[name] == event.value.text)){
6878
reporter.report("Duplicate property '" + event.property + "' found.", event.line, event.col, rule);
6881
properties[name] = event.value.text;
6882
lastProperty = name;
6892
name: "Disallow empty rules",
6893
desc: "Rules without any properties specified should be removed.",
6895
init: function(parser, reporter){
6899
parser.addListener("startrule", function(){
6903
parser.addListener("property", function(){
6907
parser.addListener("endrule", function(event){
6908
var selectors = event.selectors;
6910
reporter.report("Rule is empty.", selectors[0].line, selectors[0].col, rule);
6918
name: "Parsing Errors",
6919
desc: "This rule looks for recoverable syntax errors.",
6921
init: function(parser, reporter){
6924
parser.addListener("error", function(event){
6925
reporter.error(event.message, event.line, event.col, rule);
6932
id: "fallback-colors",
6933
name: "Require fallback colors",
6934
desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
6935
browsers: "IE6,IE7,IE8",
6936
init: function(parser, reporter){
6939
propertiesToCheck = {
6942
"background-color": 1
6946
function startRule(event){
6948
lastProperty = null;
6951
parser.addListener("startrule", startRule);
6952
parser.addListener("startfontface", startRule);
6953
parser.addListener("startpage", startRule);
6954
parser.addListener("startpagemargin", startRule);
6955
parser.addListener("startkeyframerule", startRule);
6957
parser.addListener("property", function(event){
6958
var property = event.property,
6959
name = property.text.toLowerCase(),
6960
parts = event.value.parts,
6965
if(propertiesToCheck[name]){
6967
if (parts[i].type == "color"){
6968
if ("alpha" in parts[i] || "hue" in parts[i]){
6970
if (/([^\)]+)\(/.test(parts[i])){
6971
colorType = RegExp.$1.toUpperCase();
6974
if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != "compat")){
6975
reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
6978
event.colorType = "compat";
6986
lastProperty = event;
6994
name: "Disallow too many floats",
6995
desc: "This rule tests if the float property is used too many times",
6997
init: function(parser, reporter){
7000
parser.addListener("property", function(event){
7001
if (event.property.text.toLowerCase() == "float" &&
7002
event.value.text.toLowerCase() != "none"){
7006
parser.addListener("endstylesheet", function(){
7007
reporter.stat("floats", count);
7009
reporter.rollupWarn("Too many floats (" + count + "), you're probably using them for layout. Consider using a grid system instead.", rule);
7017
name: "Don't use too many web fonts",
7018
desc: "Too many different web fonts in the same stylesheet.",
7020
init: function(parser, reporter){
7025
parser.addListener("startfontface", function(){
7029
parser.addListener("endstylesheet", function(){
7031
reporter.rollupWarn("Too many @font-face declarations (" + count + ").", rule);
7039
name: "Disallow too many font sizes",
7040
desc: "Checks the number of font-size declarations.",
7042
init: function(parser, reporter){
7045
parser.addListener("property", function(event){
7046
if (event.property == "font-size"){
7050
parser.addListener("endstylesheet", function(){
7051
reporter.stat("font-sizes", count);
7053
reporter.rollupWarn("Too many font-size declarations (" + count + "), abstraction needed.", rule);
7061
name: "Require all gradient definitions",
7062
desc: "When using a vendor-prefixed gradient, make sure to use them all.",
7064
init: function(parser, reporter){
7068
parser.addListener("startrule", function(){
7078
parser.addListener("property", function(event){
7080
if (/\-(moz|ms|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(event.value)){
7081
gradients[RegExp.$1] = 1;
7082
} else if (/\-webkit\-gradient/i.test(event.value)){
7083
gradients.oldWebkit = 1;
7088
parser.addListener("endrule", function(event){
7091
if (!gradients.moz){
7092
missing.push("Firefox 3.6+");
7095
if (!gradients.webkit){
7096
missing.push("Webkit (Safari 5+, Chrome)");
7099
if (!gradients.oldWebkit){
7100
missing.push("Old Webkit (Safari 4+, Chrome)");
7104
missing.push("Internet Explorer 10+");
7108
missing.push("Opera 11.1+");
7111
if (missing.length && missing.length < 5){
7112
reporter.report("Missing vendor-prefixed CSS gradients for " + missing.join(", ") + ".", event.selectors[0].line, event.selectors[0].col, rule);
7122
name: "Disallow IDs in selectors",
7123
desc: "Selectors should not contain IDs.",
7125
init: function(parser, reporter){
7127
parser.addListener("startrule", function(event){
7128
var selectors = event.selectors,
7135
for (i=0; i < selectors.length; i++){
7136
selector = selectors[i];
7139
for (j=0; j < selector.parts.length; j++){
7140
part = selector.parts[j];
7141
if (part.type == parser.SELECTOR_PART_TYPE){
7142
for (k=0; k < part.modifiers.length; k++){
7143
modifier = part.modifiers[k];
7144
if (modifier.type == "id"){
7152
reporter.report("Don't use IDs in selectors.", selector.line, selector.col, rule);
7153
} else if (idCount > 1){
7154
reporter.report(idCount + " IDs in the selector, really?", selector.line, selector.col, rule);
7164
name: "Disallow @import",
7165
desc: "Don't use @import, use <link> instead.",
7167
init: function(parser, reporter){
7170
parser.addListener("import", function(event){
7171
reporter.report("@import prevents parallel downloads, use <link> instead.", event.line, event.col, rule);
7179
name: "Disallow !important",
7180
desc: "Be careful when using !important declaration",
7182
init: function(parser, reporter){
7185
parser.addListener("property", function(event){
7186
if (event.important === true){
7188
reporter.report("Use of !important", event.line, event.col, rule);
7191
parser.addListener("endstylesheet", function(){
7192
reporter.stat("important", count);
7194
reporter.rollupWarn("Too many !important declarations (" + count + "), try to use less than 10 to avoid specificity issues.", rule);
7201
id: "known-properties",
7202
name: "Require use of known properties",
7203
desc: "Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",
7205
init: function(parser, reporter){
7208
parser.addListener("property", function(event){
7209
var name = event.property.text.toLowerCase();
7210
if (event.invalid) {
7211
reporter.report(event.invalid.message, event.line, event.col, rule);
7220
name: "Disallow outline: none",
7221
desc: "Use of outline: none or outline: 0 should be limited to :focus rules.",
7223
tags: ["Accessibility"],
7224
init: function(parser, reporter){
7228
function startRule(event){
7229
if (event.selectors){
7233
selectors: event.selectors,
7242
function endRule(event){
7244
if (lastRule.outline){
7245
if (lastRule.selectors.toString().toLowerCase().indexOf(":focus") == -1){
7246
reporter.report("Outlines should only be modified using :focus.", lastRule.line, lastRule.col, rule);
7247
} else if (lastRule.propCount == 1) {
7248
reporter.report("Outlines shouldn't be hidden unless other visual changes are made.", lastRule.line, lastRule.col, rule);
7254
parser.addListener("startrule", startRule);
7255
parser.addListener("startfontface", startRule);
7256
parser.addListener("startpage", startRule);
7257
parser.addListener("startpagemargin", startRule);
7258
parser.addListener("startkeyframerule", startRule);
7260
parser.addListener("property", function(event){
7261
var name = event.property.text.toLowerCase(),
7262
value = event.value;
7265
lastRule.propCount++;
7266
if (name == "outline" && (value == "none" || value == "0")){
7267
lastRule.outline = true;
7273
parser.addListener("endrule", endRule);
7274
parser.addListener("endfontface", endRule);
7275
parser.addListener("endpage", endRule);
7276
parser.addListener("endpagemargin", endRule);
7277
parser.addListener("endkeyframerule", endRule);
7283
id: "overqualified-elements",
7284
name: "Disallow overqualified elements",
7285
desc: "Don't use classes or IDs with elements (a.foo or a#foo).",
7287
init: function(parser, reporter){
7291
parser.addListener("startrule", function(event){
7292
var selectors = event.selectors,
7298
for (i=0; i < selectors.length; i++){
7299
selector = selectors[i];
7301
for (j=0; j < selector.parts.length; j++){
7302
part = selector.parts[j];
7303
if (part.type == parser.SELECTOR_PART_TYPE){
7304
for (k=0; k < part.modifiers.length; k++){
7305
modifier = part.modifiers[k];
7306
if (part.elementName && modifier.type == "id"){
7307
reporter.report("Element (" + part + ") is overqualified, just use " + modifier + " without element name.", part.line, part.col, rule);
7308
} else if (modifier.type == "class"){
7310
if (!classes[modifier]){
7311
classes[modifier] = [];
7313
classes[modifier].push({ modifier: modifier, part: part });
7321
parser.addListener("endstylesheet", function(){
7324
for (prop in classes){
7325
if (classes.hasOwnProperty(prop)){
7326
if (classes[prop].length == 1 && classes[prop][0].part.elementName){
7327
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);
7336
id: "qualified-headings",
7337
name: "Disallow qualified headings",
7338
desc: "Headings should not be qualified (namespaced).",
7340
init: function(parser, reporter){
7343
parser.addListener("startrule", function(event){
7344
var selectors = event.selectors,
7349
for (i=0; i < selectors.length; i++){
7350
selector = selectors[i];
7352
for (j=0; j < selector.parts.length; j++){
7353
part = selector.parts[j];
7354
if (part.type == parser.SELECTOR_PART_TYPE){
7355
if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){
7356
reporter.report("Heading (" + part.elementName + ") should not be qualified.", part.line, part.col, rule);
7366
id: "regex-selectors",
7367
name: "Disallow selectors that look like regexs",
7368
desc: "Selectors that look like regular expressions are slow and should be avoided.",
7370
init: function(parser, reporter){
7373
parser.addListener("startrule", function(event){
7374
var selectors = event.selectors,
7380
for (i=0; i < selectors.length; i++){
7381
selector = selectors[i];
7382
for (j=0; j < selector.parts.length; j++){
7383
part = selector.parts[j];
7384
if (part.type == parser.SELECTOR_PART_TYPE){
7385
for (k=0; k < part.modifiers.length; k++){
7386
modifier = part.modifiers[k];
7387
if (modifier.type == "attribute"){
7388
if (/([\~\|\^\$\*]=)/.test(modifier)){
7389
reporter.report("Attribute selectors with " + RegExp.$1 + " are slow!", modifier.line, modifier.col, rule);
7403
name: "Rules Count",
7404
desc: "Track how many rules there are.",
7406
init: function(parser, reporter){
7409
parser.addListener("startrule", function(){
7413
parser.addListener("endstylesheet", function(){
7414
reporter.stat("rule-count", count);
7421
name: "Require shorthand properties",
7422
desc: "Use shorthand properties where possible.",
7424
init: function(parser, reporter){
7427
propertiesToCheck = {},
7443
for (prop in mapping){
7444
if (mapping.hasOwnProperty(prop)){
7445
for (i=0, len=mapping[prop].length; i < len; i++){
7446
propertiesToCheck[mapping[prop][i]] = prop;
7451
function startRule(event){
7454
function endRule(event){
7456
var prop, i, len, total;
7457
for (prop in mapping){
7458
if (mapping.hasOwnProperty(prop)){
7461
for (i=0, len=mapping[prop].length; i < len; i++){
7462
total += properties[mapping[prop][i]] ? 1 : 0;
7465
if (total == mapping[prop].length){
7466
reporter.report("The properties " + mapping[prop].join(", ") + " can be replaced by " + prop + ".", event.line, event.col, rule);
7472
parser.addListener("startrule", startRule);
7473
parser.addListener("startfontface", startRule);
7474
parser.addListener("property", function(event){
7475
var name = event.property.toString().toLowerCase(),
7476
value = event.value.parts[0].value;
7478
if (propertiesToCheck[name]){
7479
properties[name] = 1;
7483
parser.addListener("endrule", endRule);
7484
parser.addListener("endfontface", endRule);
7490
id: "star-property-hack",
7491
name: "Disallow properties with a star prefix",
7492
desc: "Checks for the star property hack (targets IE6/7)",
7494
init: function(parser, reporter){
7496
parser.addListener("property", function(event){
7497
var property = event.property;
7499
if (property.hack == "*") {
7500
reporter.report("Property with star prefix found.", event.property.line, event.property.col, rule);
7507
name: "Disallow negative text-indent",
7508
desc: "Checks for text indent less than -99px",
7510
init: function(parser, reporter){
7516
function startRule(event){
7518
direction = "inherit";
7520
function endRule(event){
7521
if (textIndent && direction != "ltr"){
7522
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);
7526
parser.addListener("startrule", startRule);
7527
parser.addListener("startfontface", startRule);
7528
parser.addListener("property", function(event){
7529
var name = event.property.toString().toLowerCase(),
7530
value = event.value;
7532
if (name == "text-indent" && value.parts[0].value < -99){
7533
textIndent = event.property;
7534
} else if (name == "direction" && value == "ltr"){
7539
parser.addListener("endrule", endRule);
7540
parser.addListener("endfontface", endRule);
7546
id: "underscore-property-hack",
7547
name: "Disallow properties with an underscore prefix",
7548
desc: "Checks for the underscore property hack (targets IE6)",
7550
init: function(parser, reporter){
7552
parser.addListener("property", function(event){
7553
var property = event.property;
7555
if (property.hack == "_") {
7556
reporter.report("Property with underscore prefix found.", event.property.line, event.property.col, rule);
7562
id: "unique-headings",
7563
name: "Headings should only be defined once",
7564
desc: "Headings should be defined only once.",
7566
init: function(parser, reporter){
7578
parser.addListener("startrule", function(event){
7579
var selectors = event.selectors,
7585
for (i=0; i < selectors.length; i++){
7586
selector = selectors[i];
7587
part = selector.parts[selector.parts.length-1];
7589
if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){
7591
for (j=0; j < part.modifiers.length; j++){
7592
if (part.modifiers[j].type == "pseudo"){
7599
headings[RegExp.$1]++;
7600
if (headings[RegExp.$1] > 1) {
7601
reporter.report("Heading (" + part.elementName + ") has already been defined.", part.line, part.col, rule);
7608
parser.addListener("endstylesheet", function(event){
7612
for (prop in headings){
7613
if (headings.hasOwnProperty(prop)){
7614
if (headings[prop] > 1){
7615
messages.push(headings[prop] + " " + prop + "s");
7620
if (messages.length){
7621
reporter.rollupWarn("You have " + messages.join(", ") + " defined in this stylesheet.", rule);
7628
id: "universal-selector",
7629
name: "Disallow universal selector",
7630
desc: "The universal selector (*) is known to be slow.",
7632
init: function(parser, reporter){
7635
parser.addListener("startrule", function(event){
7636
var selectors = event.selectors,
7642
for (i=0; i < selectors.length; i++){
7643
selector = selectors[i];
7645
part = selector.parts[selector.parts.length-1];
7646
if (part.elementName == "*"){
7647
reporter.report(rule.desc, part.line, part.col, rule);
7655
id: "unqualified-attributes",
7656
name: "Disallow unqualified attribute selectors",
7657
desc: "Unqualified attribute selectors are known to be slow.",
7659
init: function(parser, reporter){
7662
parser.addListener("startrule", function(event){
7664
var selectors = event.selectors,
7670
for (i=0; i < selectors.length; i++){
7671
selector = selectors[i];
7673
part = selector.parts[selector.parts.length-1];
7674
if (part.type == parser.SELECTOR_PART_TYPE){
7675
for (k=0; k < part.modifiers.length; k++){
7676
modifier = part.modifiers[k];
7677
if (modifier.type == "attribute" && (!part.elementName || part.elementName == "*")){
7678
reporter.report(rule.desc, part.line, part.col, rule);
7689
id: "vendor-prefix",
7690
name: "Require standard property with vendor prefix",
7691
desc: "When using a vendor-prefixed property, make sure to include the standard one.",
7693
init: function(parser, reporter){
7697
propertiesToCheck = {
7698
"-webkit-border-radius": "border-radius",
7699
"-webkit-border-top-left-radius": "border-top-left-radius",
7700
"-webkit-border-top-right-radius": "border-top-right-radius",
7701
"-webkit-border-bottom-left-radius": "border-bottom-left-radius",
7702
"-webkit-border-bottom-right-radius": "border-bottom-right-radius",
7704
"-o-border-radius": "border-radius",
7705
"-o-border-top-left-radius": "border-top-left-radius",
7706
"-o-border-top-right-radius": "border-top-right-radius",
7707
"-o-border-bottom-left-radius": "border-bottom-left-radius",
7708
"-o-border-bottom-right-radius": "border-bottom-right-radius",
7710
"-moz-border-radius": "border-radius",
7711
"-moz-border-radius-topleft": "border-top-left-radius",
7712
"-moz-border-radius-topright": "border-top-right-radius",
7713
"-moz-border-radius-bottomleft": "border-bottom-left-radius",
7714
"-moz-border-radius-bottomright": "border-bottom-right-radius",
7716
"-moz-column-count": "column-count",
7717
"-webkit-column-count": "column-count",
7719
"-moz-column-gap": "column-gap",
7720
"-webkit-column-gap": "column-gap",
7722
"-moz-column-rule": "column-rule",
7723
"-webkit-column-rule": "column-rule",
7725
"-moz-column-rule-style": "column-rule-style",
7726
"-webkit-column-rule-style": "column-rule-style",
7728
"-moz-column-rule-color": "column-rule-color",
7729
"-webkit-column-rule-color": "column-rule-color",
7731
"-moz-column-rule-width": "column-rule-width",
7732
"-webkit-column-rule-width": "column-rule-width",
7734
"-moz-column-width": "column-width",
7735
"-webkit-column-width": "column-width",
7737
"-webkit-column-span": "column-span",
7738
"-webkit-columns": "columns",
7740
"-moz-box-shadow": "box-shadow",
7741
"-webkit-box-shadow": "box-shadow",
7743
"-moz-transform" : "transform",
7744
"-webkit-transform" : "transform",
7745
"-o-transform" : "transform",
7746
"-ms-transform" : "transform",
7748
"-moz-transform-origin" : "transform-origin",
7749
"-webkit-transform-origin" : "transform-origin",
7750
"-o-transform-origin" : "transform-origin",
7751
"-ms-transform-origin" : "transform-origin",
7753
"-moz-box-sizing" : "box-sizing",
7754
"-webkit-box-sizing" : "box-sizing",
7756
"-moz-user-select" : "user-select",
7757
"-khtml-user-select" : "user-select",
7758
"-webkit-user-select" : "user-select"
7760
function startRule(){
7764
function endRule(event){
7772
for (prop in properties){
7773
if (propertiesToCheck[prop]){
7774
needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});
7778
for (i=0, len=needsStandard.length; i < len; i++){
7779
needed = needsStandard[i].needed;
7780
actual = needsStandard[i].actual;
7782
if (!properties[needed]){
7783
reporter.report("Missing standard property '" + needed + "' to go along with '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
7785
if (properties[needed][0].pos < properties[actual][0].pos){
7786
reporter.report("Standard property '" + needed + "' should come after vendor-prefixed property '" + actual + "'.", properties[actual][0].name.line, properties[actual][0].name.col, rule);
7793
parser.addListener("startrule", startRule);
7794
parser.addListener("startfontface", startRule);
7795
parser.addListener("startpage", startRule);
7796
parser.addListener("startpagemargin", startRule);
7797
parser.addListener("startkeyframerule", startRule);
7799
parser.addListener("property", function(event){
7800
var name = event.property.text.toLowerCase();
7802
if (!properties[name]){
7803
properties[name] = [];
7806
properties[name].push({ name: event.property, value : event.value, pos:num++ });
7809
parser.addListener("endrule", endRule);
7810
parser.addListener("endfontface", endRule);
7811
parser.addListener("endpage", endRule);
7812
parser.addListener("endpagemargin", endRule);
7813
parser.addListener("endkeyframerule", endRule);
7819
name: "Disallow units for 0 values",
7820
desc: "You don't need to specify units when a value is 0.",
7822
init: function(parser, reporter){
7824
parser.addListener("property", function(event){
7825
var parts = event.value.parts,
7830
if ((parts[i].units || parts[i].type == "percentage") && parts[i].value === 0 && parts[i].type != "time"){
7831
reporter.report("Values of 0 shouldn't have units specified.", parts[i].line, parts[i].col, rule);
7843
exports.CSSLint = CSSLint;